xref: /linux/drivers/gpu/drm/hisilicon/hibmc/dp/dp_link.c (revision e814f3fd16acfb7f9966773953de8f740a1e3202)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 // Copyright (c) 2024 Hisilicon Limited.
3 
4 #include <linux/delay.h>
5 #include <drm/drm_device.h>
6 #include <drm/drm_print.h>
7 #include "dp_comm.h"
8 #include "dp_reg.h"
9 
10 #define HIBMC_EQ_MAX_RETRY 5
11 
12 static int hibmc_dp_link_training_configure(struct hibmc_dp_dev *dp)
13 {
14 	u8 buf[2];
15 	int ret;
16 
17 	/* DP 2 lane */
18 	hibmc_dp_reg_write_field(dp, HIBMC_DP_PHYIF_CTRL0, HIBMC_DP_CFG_LANE_DATA_EN,
19 				 dp->link.cap.lanes == 0x2 ? 0x3 : 0x1);
20 	hibmc_dp_reg_write_field(dp, HIBMC_DP_DPTX_GCTL0, HIBMC_DP_CFG_PHY_LANE_NUM,
21 				 dp->link.cap.lanes == 0x2 ? 0x1 : 0);
22 
23 	/* enhanced frame */
24 	hibmc_dp_reg_write_field(dp, HIBMC_DP_VIDEO_CTRL, HIBMC_DP_CFG_STREAM_FRAME_MODE, 0x1);
25 
26 	/* set rate and lane count */
27 	buf[0] = dp->link.cap.link_rate;
28 	buf[1] = DP_LANE_COUNT_ENHANCED_FRAME_EN | dp->link.cap.lanes;
29 	ret = drm_dp_dpcd_write(&dp->aux, DP_LINK_BW_SET, buf, sizeof(buf));
30 	if (ret != sizeof(buf)) {
31 		drm_dbg_dp(dp->dev, "dp aux write link rate and lanes failed, ret: %d\n", ret);
32 		return ret >= 0 ? -EIO : ret;
33 	}
34 
35 	/* set 8b/10b and downspread */
36 	buf[0] = DP_SPREAD_AMP_0_5;
37 	buf[1] = DP_SET_ANSI_8B10B;
38 	ret = drm_dp_dpcd_write(&dp->aux, DP_DOWNSPREAD_CTRL, buf, sizeof(buf));
39 	if (ret != sizeof(buf)) {
40 		drm_dbg_dp(dp->dev, "dp aux write 8b/10b and downspread failed, ret: %d\n", ret);
41 		return ret >= 0 ? -EIO : ret;
42 	}
43 
44 	ret = drm_dp_read_dpcd_caps(&dp->aux, dp->dpcd);
45 	if (ret)
46 		drm_err(dp->dev, "dp aux read dpcd failed, ret: %d\n", ret);
47 
48 	return ret;
49 }
50 
51 static int hibmc_dp_link_set_pattern(struct hibmc_dp_dev *dp, int pattern)
52 {
53 	int ret;
54 	u8 val;
55 	u8 buf;
56 
57 	buf = (u8)pattern;
58 	if (pattern != DP_TRAINING_PATTERN_DISABLE && pattern != DP_TRAINING_PATTERN_4) {
59 		buf |= DP_LINK_SCRAMBLING_DISABLE;
60 		hibmc_dp_reg_write_field(dp, HIBMC_DP_PHYIF_CTRL0, HIBMC_DP_CFG_SCRAMBLE_EN, 0x1);
61 	} else {
62 		hibmc_dp_reg_write_field(dp, HIBMC_DP_PHYIF_CTRL0, HIBMC_DP_CFG_SCRAMBLE_EN, 0);
63 	}
64 
65 	switch (pattern) {
66 	case DP_TRAINING_PATTERN_DISABLE:
67 		val = 0;
68 		break;
69 	case DP_TRAINING_PATTERN_1:
70 		val = 1;
71 		break;
72 	case DP_TRAINING_PATTERN_2:
73 		val = 2;
74 		break;
75 	case DP_TRAINING_PATTERN_3:
76 		val = 3;
77 		break;
78 	case DP_TRAINING_PATTERN_4:
79 		val = 4;
80 		break;
81 	default:
82 		return -EINVAL;
83 	}
84 
85 	hibmc_dp_reg_write_field(dp, HIBMC_DP_PHYIF_CTRL0, HIBMC_DP_CFG_PAT_SEL, val);
86 
87 	ret = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_PATTERN_SET, &buf, sizeof(buf));
88 	if (ret != sizeof(buf)) {
89 		drm_dbg_dp(dp->dev, "dp aux write training pattern set failed\n");
90 		return ret >= 0 ? -EIO : ret;
91 	}
92 
93 	return 0;
94 }
95 
96 static int hibmc_dp_link_training_cr_pre(struct hibmc_dp_dev *dp)
97 {
98 	u8 *train_set = dp->link.train_set;
99 	int ret;
100 	u8 i;
101 
102 	ret = hibmc_dp_link_training_configure(dp);
103 	if (ret)
104 		return ret;
105 
106 	ret = hibmc_dp_link_set_pattern(dp, DP_TRAINING_PATTERN_1);
107 	if (ret)
108 		return ret;
109 
110 	for (i = 0; i < dp->link.cap.lanes; i++)
111 		train_set[i] = DP_TRAIN_VOLTAGE_SWING_LEVEL_2;
112 
113 	ret = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, train_set, dp->link.cap.lanes);
114 	if (ret != dp->link.cap.lanes) {
115 		drm_dbg_dp(dp->dev, "dp aux write training lane set failed\n");
116 		return ret >= 0 ? -EIO : ret;
117 	}
118 
119 	return 0;
120 }
121 
122 static bool hibmc_dp_link_get_adjust_train(struct hibmc_dp_dev *dp,
123 					   u8 lane_status[DP_LINK_STATUS_SIZE])
124 {
125 	u8 train_set[HIBMC_DP_LANE_NUM_MAX] = {0};
126 	u8 lane;
127 
128 	for (lane = 0; lane < dp->link.cap.lanes; lane++)
129 		train_set[lane] = drm_dp_get_adjust_request_voltage(lane_status, lane) |
130 				  drm_dp_get_adjust_request_pre_emphasis(lane_status, lane);
131 
132 	if (memcmp(dp->link.train_set, train_set, HIBMC_DP_LANE_NUM_MAX)) {
133 		memcpy(dp->link.train_set, train_set, HIBMC_DP_LANE_NUM_MAX);
134 		return true;
135 	}
136 
137 	return false;
138 }
139 
140 static inline int hibmc_dp_link_reduce_rate(struct hibmc_dp_dev *dp)
141 {
142 	switch (dp->link.cap.link_rate) {
143 	case DP_LINK_BW_2_7:
144 		dp->link.cap.link_rate = DP_LINK_BW_1_62;
145 		return 0;
146 	case DP_LINK_BW_5_4:
147 		dp->link.cap.link_rate = DP_LINK_BW_2_7;
148 		return 0;
149 	case DP_LINK_BW_8_1:
150 		dp->link.cap.link_rate = DP_LINK_BW_5_4;
151 		return 0;
152 	default:
153 		return -EINVAL;
154 	}
155 }
156 
157 static inline int hibmc_dp_link_reduce_lane(struct hibmc_dp_dev *dp)
158 {
159 	switch (dp->link.cap.lanes) {
160 	case 0x2:
161 		dp->link.cap.lanes--;
162 		break;
163 	case 0x1:
164 		drm_err(dp->dev, "dp link training reduce lane failed, already reach minimum\n");
165 		return -EIO;
166 	default:
167 		return -EINVAL;
168 	}
169 
170 	return 0;
171 }
172 
173 static int hibmc_dp_link_training_cr(struct hibmc_dp_dev *dp)
174 {
175 	u8 lane_status[DP_LINK_STATUS_SIZE] = {0};
176 	bool level_changed;
177 	u32 voltage_tries;
178 	u32 cr_tries;
179 	int ret;
180 
181 	/*
182 	 * DP 1.4 spec define 10 for maxtries value, for pre DP 1.4 version set a limit of 80
183 	 * (4 voltage levels x 4 preemphasis levels x 5 identical voltage retries)
184 	 */
185 
186 	voltage_tries = 1;
187 	for (cr_tries = 0; cr_tries < 80; cr_tries++) {
188 		drm_dp_link_train_clock_recovery_delay(&dp->aux, dp->dpcd);
189 
190 		ret = drm_dp_dpcd_read_link_status(&dp->aux, lane_status);
191 		if (ret != DP_LINK_STATUS_SIZE) {
192 			drm_err(dp->dev, "Get lane status failed\n");
193 			return ret;
194 		}
195 
196 		if (drm_dp_clock_recovery_ok(lane_status, dp->link.cap.lanes)) {
197 			drm_dbg_dp(dp->dev, "dp link training cr done\n");
198 			dp->link.status.clock_recovered = true;
199 			return 0;
200 		}
201 
202 		if (voltage_tries == 5) {
203 			drm_dbg_dp(dp->dev, "same voltage tries 5 times\n");
204 			dp->link.status.clock_recovered = false;
205 			return 0;
206 		}
207 
208 		level_changed = hibmc_dp_link_get_adjust_train(dp, lane_status);
209 		ret = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, dp->link.train_set,
210 					dp->link.cap.lanes);
211 		if (ret != dp->link.cap.lanes) {
212 			drm_dbg_dp(dp->dev, "Update link training failed\n");
213 			return ret >= 0 ? -EIO : ret;
214 		}
215 
216 		voltage_tries = level_changed ? 1 : voltage_tries + 1;
217 	}
218 
219 	drm_err(dp->dev, "dp link training clock recovery 80 times failed\n");
220 	dp->link.status.clock_recovered = false;
221 
222 	return 0;
223 }
224 
225 static int hibmc_dp_link_training_channel_eq(struct hibmc_dp_dev *dp)
226 {
227 	u8 lane_status[DP_LINK_STATUS_SIZE] = {0};
228 	u8 eq_tries;
229 	int ret;
230 
231 	ret = hibmc_dp_link_set_pattern(dp, DP_TRAINING_PATTERN_2);
232 	if (ret)
233 		return ret;
234 
235 	for (eq_tries = 0; eq_tries < HIBMC_EQ_MAX_RETRY; eq_tries++) {
236 		drm_dp_link_train_channel_eq_delay(&dp->aux, dp->dpcd);
237 
238 		ret = drm_dp_dpcd_read_link_status(&dp->aux, lane_status);
239 		if (ret != DP_LINK_STATUS_SIZE) {
240 			drm_err(dp->dev, "get lane status failed\n");
241 			break;
242 		}
243 
244 		if (!drm_dp_clock_recovery_ok(lane_status, dp->link.cap.lanes)) {
245 			drm_dbg_dp(dp->dev, "clock recovery check failed\n");
246 			drm_dbg_dp(dp->dev, "cannot continue channel equalization\n");
247 			dp->link.status.clock_recovered = false;
248 			break;
249 		}
250 
251 		if (drm_dp_channel_eq_ok(lane_status, dp->link.cap.lanes)) {
252 			dp->link.status.channel_equalized = true;
253 			drm_dbg_dp(dp->dev, "dp link training eq done\n");
254 			break;
255 		}
256 
257 		hibmc_dp_link_get_adjust_train(dp, lane_status);
258 		ret = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET,
259 					dp->link.train_set, dp->link.cap.lanes);
260 		if (ret != dp->link.cap.lanes) {
261 			drm_dbg_dp(dp->dev, "Update link training failed\n");
262 			ret = (ret >= 0) ? -EIO : ret;
263 			break;
264 		}
265 	}
266 
267 	if (eq_tries == HIBMC_EQ_MAX_RETRY)
268 		drm_err(dp->dev, "channel equalization failed %u times\n", eq_tries);
269 
270 	hibmc_dp_link_set_pattern(dp, DP_TRAINING_PATTERN_DISABLE);
271 
272 	return ret < 0 ? ret : 0;
273 }
274 
275 static int hibmc_dp_link_downgrade_training_cr(struct hibmc_dp_dev *dp)
276 {
277 	if (hibmc_dp_link_reduce_rate(dp))
278 		return hibmc_dp_link_reduce_lane(dp);
279 
280 	return 0;
281 }
282 
283 static int hibmc_dp_link_downgrade_training_eq(struct hibmc_dp_dev *dp)
284 {
285 	if ((dp->link.status.clock_recovered && !dp->link.status.channel_equalized)) {
286 		if (!hibmc_dp_link_reduce_lane(dp))
287 			return 0;
288 	}
289 
290 	return hibmc_dp_link_reduce_rate(dp);
291 }
292 
293 int hibmc_dp_link_training(struct hibmc_dp_dev *dp)
294 {
295 	struct hibmc_dp_link *link = &dp->link;
296 	int ret;
297 
298 	while (true) {
299 		ret = hibmc_dp_link_training_cr_pre(dp);
300 		if (ret)
301 			goto err;
302 
303 		ret = hibmc_dp_link_training_cr(dp);
304 		if (ret)
305 			goto err;
306 
307 		if (!link->status.clock_recovered) {
308 			ret = hibmc_dp_link_downgrade_training_cr(dp);
309 			if (ret)
310 				goto err;
311 			continue;
312 		}
313 
314 		ret = hibmc_dp_link_training_channel_eq(dp);
315 		if (ret)
316 			goto err;
317 
318 		if (!link->status.channel_equalized) {
319 			ret = hibmc_dp_link_downgrade_training_eq(dp);
320 			if (ret)
321 				goto err;
322 			continue;
323 		}
324 
325 		return 0;
326 	}
327 
328 err:
329 	hibmc_dp_link_set_pattern(dp, DP_TRAINING_PATTERN_DISABLE);
330 
331 	return ret;
332 }
333