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
hibmc_dp_aux_reset(struct hibmc_dp_dev * dp)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
hibmc_dp_aux_read_data(struct hibmc_dp_dev * dp,u8 * buf,u8 size)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
hibmc_dp_aux_write_data(struct hibmc_dp_dev * dp,u8 * buf,u8 size)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
hibmc_dp_aux_build_cmd(const struct drm_dp_aux_msg * msg)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 */
hibmc_dp_aux_parse_xfer(struct hibmc_dp_dev * dp,struct drm_dp_aux_msg * msg)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 */
hibmc_dp_aux_xfer(struct drm_dp_aux * aux,struct drm_dp_aux_msg * msg)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
hibmc_dp_aux_init(struct hibmc_dp_dev * dp)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 }
165