xref: /linux/drivers/gpu/drm/hisilicon/hibmc/dp/dp_aux.c (revision 2c1ed907520c50326b8f604907a8478b27881a2e)
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