Skip to content

Commit 057e779

Browse files
Baihan Lilumag
authored andcommitted
drm/hisilicon/hibmc: add dp aux in hibmc drivers
Add dp aux read/write functions. They are basic functions and will be used later. Signed-off-by: Baihan Li <[email protected]> Signed-off-by: Yongbang Shi <[email protected]> Reviewed-by: Dmitry Baryshkov <[email protected]> Reviewed-by: Tian Tao <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected] Signed-off-by: Dmitry Baryshkov <[email protected]>
1 parent f8a2397 commit 057e779

File tree

4 files changed

+235
-1
lines changed

4 files changed

+235
-1
lines changed
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# SPDX-License-Identifier: GPL-2.0-only
2-
hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_vdac.o hibmc_drm_i2c.o
2+
hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_vdac.o hibmc_drm_i2c.o \
3+
dp/dp_aux.o
34

45
obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc-drm.o
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
// Copyright (c) 2024 Hisilicon Limited.
3+
4+
#include <linux/io.h>
5+
#include <linux/iopoll.h>
6+
#include <linux/minmax.h>
7+
#include <drm/drm_device.h>
8+
#include <drm/drm_print.h>
9+
#include "dp_comm.h"
10+
#include "dp_reg.h"
11+
12+
#define HIBMC_AUX_CMD_REQ_LEN GENMASK(7, 4)
13+
#define HIBMC_AUX_CMD_ADDR GENMASK(27, 8)
14+
#define HIBMC_AUX_CMD_I2C_ADDR_ONLY BIT(28)
15+
#define HIBMC_BYTES_IN_U32 4
16+
#define HIBMC_AUX_I2C_WRITE_SUCCESS 0x1
17+
#define HIBMC_DP_MIN_PULSE_NUM 0x9
18+
#define BITS_IN_U8 8
19+
20+
static inline void hibmc_dp_aux_reset(struct hibmc_dp_dev *dp)
21+
{
22+
hibmc_dp_reg_write_field(dp, HIBMC_DP_DPTX_RST_CTRL, HIBMC_DP_CFG_AUX_RST_N, 0x0);
23+
usleep_range(10, 15);
24+
hibmc_dp_reg_write_field(dp, HIBMC_DP_DPTX_RST_CTRL, HIBMC_DP_CFG_AUX_RST_N, 0x1);
25+
}
26+
27+
static void hibmc_dp_aux_read_data(struct hibmc_dp_dev *dp, u8 *buf, u8 size)
28+
{
29+
u32 reg_num;
30+
u32 value;
31+
u32 num;
32+
u8 i, j;
33+
34+
reg_num = DIV_ROUND_UP(size, HIBMC_BYTES_IN_U32);
35+
for (i = 0; i < reg_num; i++) {
36+
/* number of bytes read from a single register */
37+
num = min(size - i * HIBMC_BYTES_IN_U32, HIBMC_BYTES_IN_U32);
38+
value = readl(dp->base + HIBMC_DP_AUX_RD_DATA0 + i * HIBMC_BYTES_IN_U32);
39+
/* convert the 32-bit value of the register to the buffer. */
40+
for (j = 0; j < num; j++)
41+
buf[i * HIBMC_BYTES_IN_U32 + j] = value >> (j * BITS_IN_U8);
42+
}
43+
}
44+
45+
static void hibmc_dp_aux_write_data(struct hibmc_dp_dev *dp, u8 *buf, u8 size)
46+
{
47+
u32 reg_num;
48+
u32 value;
49+
u32 num;
50+
u8 i, j;
51+
52+
reg_num = DIV_ROUND_UP(size, HIBMC_BYTES_IN_U32);
53+
for (i = 0; i < reg_num; i++) {
54+
/* number of bytes written to a single register */
55+
num = min_t(u8, size - i * HIBMC_BYTES_IN_U32, HIBMC_BYTES_IN_U32);
56+
value = 0;
57+
/* obtain the 32-bit value written to a single register. */
58+
for (j = 0; j < num; j++)
59+
value |= buf[i * HIBMC_BYTES_IN_U32 + j] << (j * BITS_IN_U8);
60+
/* writing data to a single register */
61+
writel(value, dp->base + HIBMC_DP_AUX_WR_DATA0 + i * HIBMC_BYTES_IN_U32);
62+
}
63+
}
64+
65+
static u32 hibmc_dp_aux_build_cmd(const struct drm_dp_aux_msg *msg)
66+
{
67+
u32 aux_cmd = msg->request;
68+
69+
if (msg->size)
70+
aux_cmd |= FIELD_PREP(HIBMC_AUX_CMD_REQ_LEN, (msg->size - 1));
71+
else
72+
aux_cmd |= FIELD_PREP(HIBMC_AUX_CMD_I2C_ADDR_ONLY, 1);
73+
74+
aux_cmd |= FIELD_PREP(HIBMC_AUX_CMD_ADDR, msg->address);
75+
76+
return aux_cmd;
77+
}
78+
79+
/* ret >= 0, ret is size; ret < 0, ret is err code */
80+
static int hibmc_dp_aux_parse_xfer(struct hibmc_dp_dev *dp, struct drm_dp_aux_msg *msg)
81+
{
82+
u32 buf_data_cnt;
83+
u32 aux_status;
84+
85+
aux_status = readl(dp->base + HIBMC_DP_AUX_STATUS);
86+
msg->reply = FIELD_GET(HIBMC_DP_CFG_AUX_STATUS, aux_status);
87+
88+
if (aux_status & HIBMC_DP_CFG_AUX_TIMEOUT)
89+
return -ETIMEDOUT;
90+
91+
/* only address */
92+
if (!msg->size)
93+
return 0;
94+
95+
if (msg->reply != DP_AUX_NATIVE_REPLY_ACK)
96+
return -EIO;
97+
98+
buf_data_cnt = FIELD_GET(HIBMC_DP_CFG_AUX_READY_DATA_BYTE, aux_status);
99+
100+
switch (msg->request) {
101+
case DP_AUX_NATIVE_WRITE:
102+
return msg->size;
103+
case DP_AUX_I2C_WRITE | DP_AUX_I2C_MOT:
104+
if (buf_data_cnt == HIBMC_AUX_I2C_WRITE_SUCCESS)
105+
return msg->size;
106+
else
107+
return FIELD_GET(HIBMC_DP_CFG_AUX, aux_status);
108+
case DP_AUX_NATIVE_READ:
109+
case DP_AUX_I2C_READ | DP_AUX_I2C_MOT:
110+
buf_data_cnt--;
111+
if (buf_data_cnt != msg->size) {
112+
/* only the successful part of data is read */
113+
return -EBUSY;
114+
}
115+
116+
/* all data is successfully read */
117+
hibmc_dp_aux_read_data(dp, msg->buffer, msg->size);
118+
return msg->size;
119+
default:
120+
return -EINVAL;
121+
}
122+
}
123+
124+
/* ret >= 0 ,ret is size; ret < 0, ret is err code */
125+
static ssize_t hibmc_dp_aux_xfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
126+
{
127+
struct hibmc_dp_dev *dp = container_of(aux, struct hibmc_dp_dev, aux);
128+
u32 aux_cmd;
129+
int ret;
130+
u32 val; /* val will be assigned at the beginning of readl_poll_timeout function */
131+
132+
writel(0, dp->base + HIBMC_DP_AUX_WR_DATA0);
133+
writel(0, dp->base + HIBMC_DP_AUX_WR_DATA1);
134+
writel(0, dp->base + HIBMC_DP_AUX_WR_DATA2);
135+
writel(0, dp->base + HIBMC_DP_AUX_WR_DATA3);
136+
137+
hibmc_dp_aux_write_data(dp, msg->buffer, msg->size);
138+
139+
aux_cmd = hibmc_dp_aux_build_cmd(msg);
140+
writel(aux_cmd, dp->base + HIBMC_DP_AUX_CMD_ADDR);
141+
142+
/* enable aux transfer */
143+
hibmc_dp_reg_write_field(dp, HIBMC_DP_AUX_REQ, HIBMC_DP_CFG_AUX_REQ, 0x1);
144+
ret = readl_poll_timeout(dp->base + HIBMC_DP_AUX_REQ, val,
145+
!(val & HIBMC_DP_CFG_AUX_REQ), 50, 5000);
146+
if (ret) {
147+
hibmc_dp_aux_reset(dp);
148+
return ret;
149+
}
150+
151+
return hibmc_dp_aux_parse_xfer(dp, msg);
152+
}
153+
154+
void hibmc_dp_aux_init(struct hibmc_dp_dev *dp)
155+
{
156+
hibmc_dp_reg_write_field(dp, HIBMC_DP_AUX_REQ, HIBMC_DP_CFG_AUX_SYNC_LEN_SEL, 0x0);
157+
hibmc_dp_reg_write_field(dp, HIBMC_DP_AUX_REQ, HIBMC_DP_CFG_AUX_TIMER_TIMEOUT, 0x1);
158+
hibmc_dp_reg_write_field(dp, HIBMC_DP_AUX_REQ, HIBMC_DP_CFG_AUX_MIN_PULSE_NUM,
159+
HIBMC_DP_MIN_PULSE_NUM);
160+
161+
dp->aux.transfer = hibmc_dp_aux_xfer;
162+
dp->aux.is_remote = 0;
163+
drm_dp_aux_init(&dp->aux);
164+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/* SPDX-License-Identifier: GPL-2.0-or-later */
2+
/* Copyright (c) 2024 Hisilicon Limited. */
3+
4+
#ifndef DP_COMM_H
5+
#define DP_COMM_H
6+
7+
#include <linux/types.h>
8+
#include <linux/bitops.h>
9+
#include <linux/errno.h>
10+
#include <linux/mutex.h>
11+
#include <linux/kernel.h>
12+
#include <linux/bitfield.h>
13+
#include <linux/io.h>
14+
#include <drm/display/drm_dp_helper.h>
15+
16+
struct hibmc_dp_dev {
17+
struct drm_dp_aux aux;
18+
struct drm_device *dev;
19+
void __iomem *base;
20+
struct mutex lock; /* protects concurrent RW in hibmc_dp_reg_write_field() */
21+
};
22+
23+
#define dp_field_modify(reg_value, mask, val) \
24+
do { \
25+
(reg_value) &= ~(mask); \
26+
(reg_value) |= FIELD_PREP(mask, val); \
27+
} while (0) \
28+
29+
#define hibmc_dp_reg_write_field(dp, offset, mask, val) \
30+
do { \
31+
typeof(dp) _dp = dp; \
32+
typeof(_dp->base) addr = (_dp->base + (offset)); \
33+
mutex_lock(&_dp->lock); \
34+
u32 reg_value = readl(addr); \
35+
dp_field_modify(reg_value, mask, val); \
36+
writel(reg_value, addr); \
37+
mutex_unlock(&_dp->lock); \
38+
} while (0)
39+
40+
void hibmc_dp_aux_init(struct hibmc_dp_dev *dp);
41+
42+
#endif
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/* SPDX-License-Identifier: GPL-2.0-or-later */
2+
/* Copyright (c) 2024 Hisilicon Limited. */
3+
4+
#ifndef DP_REG_H
5+
#define DP_REG_H
6+
7+
#define HIBMC_DP_AUX_CMD_ADDR 0x50
8+
#define HIBMC_DP_AUX_WR_DATA0 0x54
9+
#define HIBMC_DP_AUX_WR_DATA1 0x58
10+
#define HIBMC_DP_AUX_WR_DATA2 0x5c
11+
#define HIBMC_DP_AUX_WR_DATA3 0x60
12+
#define HIBMC_DP_AUX_RD_DATA0 0x64
13+
#define HIBMC_DP_AUX_REQ 0x74
14+
#define HIBMC_DP_AUX_STATUS 0x78
15+
#define HIBMC_DP_DPTX_RST_CTRL 0x700
16+
17+
#define HIBMC_DP_CFG_AUX_SYNC_LEN_SEL BIT(1)
18+
#define HIBMC_DP_CFG_AUX_TIMER_TIMEOUT BIT(2)
19+
#define HIBMC_DP_CFG_AUX_MIN_PULSE_NUM GENMASK(13, 9)
20+
#define HIBMC_DP_CFG_AUX_REQ BIT(0)
21+
#define HIBMC_DP_CFG_AUX_RST_N BIT(4)
22+
#define HIBMC_DP_CFG_AUX_TIMEOUT BIT(0)
23+
#define HIBMC_DP_CFG_AUX_READY_DATA_BYTE GENMASK(16, 12)
24+
#define HIBMC_DP_CFG_AUX GENMASK(24, 17)
25+
#define HIBMC_DP_CFG_AUX_STATUS GENMASK(11, 4)
26+
27+
#endif

0 commit comments

Comments
 (0)