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
hibmc_dp_link_training_configure(struct hibmc_dp_dev * dp)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
hibmc_dp_link_set_pattern(struct hibmc_dp_dev * dp,int pattern)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
hibmc_dp_link_training_cr_pre(struct hibmc_dp_dev * dp)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
hibmc_dp_link_get_adjust_train(struct hibmc_dp_dev * dp,u8 lane_status[DP_LINK_STATUS_SIZE])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
hibmc_dp_link_reduce_rate(struct hibmc_dp_dev * dp)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
hibmc_dp_link_reduce_lane(struct hibmc_dp_dev * dp)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
hibmc_dp_link_training_cr(struct hibmc_dp_dev * dp)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
hibmc_dp_link_training_channel_eq(struct hibmc_dp_dev * dp)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
hibmc_dp_link_downgrade_training_cr(struct hibmc_dp_dev * dp)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
hibmc_dp_link_downgrade_training_eq(struct hibmc_dp_dev * dp)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
hibmc_dp_link_training(struct hibmc_dp_dev * dp)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