1 /*
2 * Copyright 2022 Advanced Micro Devices, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Authors: AMD
23 *
24 */
25
26 /* FILE POLICY AND INTENDED USAGE:
27 * This file implements 8b/10b link training specially modified to support an
28 * embedded retimer chip. This retimer chip is referred as fixed vs pe retimer.
29 * Unlike native dp connection this chip requires a modified link training
30 * protocol based on 8b/10b link training. Since this is a non standard sequence
31 * and we must support this hardware, we decided to isolate it in its own
32 * training sequence inside its own file.
33 */
34 #include "link_dp_training_fixed_vs_pe_retimer.h"
35 #include "link_dp_training_8b_10b.h"
36 #include "link_dpcd.h"
37 #include "link_dp_phy.h"
38 #include "link_dp_capability.h"
39 #include "link_ddc.h"
40
41 #define DC_LOGGER \
42 link->ctx->logger
43
dp_fixed_vs_pe_read_lane_adjust(struct dc_link * link,union dpcd_training_lane dpcd_lane_adjust[LANE_COUNT_DP_MAX])44 void dp_fixed_vs_pe_read_lane_adjust(
45 struct dc_link *link,
46 union dpcd_training_lane dpcd_lane_adjust[LANE_COUNT_DP_MAX])
47 {
48 const uint8_t vendor_lttpr_write_data_vs[3] = {0x0, 0x53, 0x63};
49 const uint8_t vendor_lttpr_write_data_pe[3] = {0x0, 0x54, 0x63};
50 uint8_t dprx_vs = 0;
51 uint8_t dprx_pe = 0;
52 uint8_t lane;
53
54 /* W/A to read lane settings requested by DPRX */
55 link_configure_fixed_vs_pe_retimer(link->ddc,
56 &vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs));
57
58 link_query_fixed_vs_pe_retimer(link->ddc, &dprx_vs, 1);
59
60 link_configure_fixed_vs_pe_retimer(link->ddc,
61 &vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe));
62
63 link_query_fixed_vs_pe_retimer(link->ddc, &dprx_pe, 1);
64
65 for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
66 dpcd_lane_adjust[lane].bits.VOLTAGE_SWING_SET = (dprx_vs >> (2 * lane)) & 0x3;
67 dpcd_lane_adjust[lane].bits.PRE_EMPHASIS_SET = (dprx_pe >> (2 * lane)) & 0x3;
68 }
69 }
70
71
dp_fixed_vs_pe_set_retimer_lane_settings(struct dc_link * link,const union dpcd_training_lane dpcd_lane_adjust[LANE_COUNT_DP_MAX],uint8_t lane_count)72 void dp_fixed_vs_pe_set_retimer_lane_settings(
73 struct dc_link *link,
74 const union dpcd_training_lane dpcd_lane_adjust[LANE_COUNT_DP_MAX],
75 uint8_t lane_count)
76 {
77 const uint8_t vendor_lttpr_write_data_reset[4] = {0x1, 0x50, 0x63, 0xFF};
78 uint8_t vendor_lttpr_write_data_vs[4] = {0x1, 0x51, 0x63, 0x0};
79 uint8_t vendor_lttpr_write_data_pe[4] = {0x1, 0x52, 0x63, 0x0};
80 uint8_t lane = 0;
81
82 for (lane = 0; lane < lane_count; lane++) {
83 vendor_lttpr_write_data_vs[3] |=
84 dpcd_lane_adjust[lane].bits.VOLTAGE_SWING_SET << (2 * lane);
85 vendor_lttpr_write_data_pe[3] |=
86 dpcd_lane_adjust[lane].bits.PRE_EMPHASIS_SET << (2 * lane);
87 }
88
89 /* Force LTTPR to output desired VS and PE */
90 link_configure_fixed_vs_pe_retimer(link->ddc,
91 &vendor_lttpr_write_data_reset[0], sizeof(vendor_lttpr_write_data_reset));
92
93 link_configure_fixed_vs_pe_retimer(link->ddc,
94 &vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs));
95
96 link_configure_fixed_vs_pe_retimer(link->ddc,
97 &vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe));
98 }
99
perform_fixed_vs_pe_nontransparent_training_sequence(struct dc_link * link,const struct link_resource * link_res,struct link_training_settings * lt_settings)100 static enum link_training_result perform_fixed_vs_pe_nontransparent_training_sequence(
101 struct dc_link *link,
102 const struct link_resource *link_res,
103 struct link_training_settings *lt_settings)
104 {
105 enum link_training_result status = LINK_TRAINING_SUCCESS;
106 uint8_t lane = 0;
107 uint8_t toggle_rate = 0x6;
108 uint8_t target_rate = 0x6;
109 bool apply_toggle_rate_wa = false;
110 uint8_t repeater_cnt;
111 uint8_t repeater_id;
112
113 /* Fixed VS/PE specific: Force CR AUX RD Interval to at least 16ms */
114 if (lt_settings->cr_pattern_time < 16000)
115 lt_settings->cr_pattern_time = 16000;
116
117 /* Fixed VS/PE specific: Toggle link rate */
118 apply_toggle_rate_wa = ((link->vendor_specific_lttpr_link_rate_wa == target_rate) || (link->vendor_specific_lttpr_link_rate_wa == 0));
119 target_rate = get_dpcd_link_rate(<_settings->link_settings);
120 toggle_rate = (target_rate == 0x6) ? 0xA : 0x6;
121
122 if (apply_toggle_rate_wa)
123 lt_settings->link_settings.link_rate = toggle_rate;
124
125 if (link->ctx->dc->work_arounds.lt_early_cr_pattern)
126 start_clock_recovery_pattern_early(link, link_res, lt_settings, DPRX);
127
128 /* 1. set link rate, lane count and spread. */
129 dpcd_set_link_settings(link, lt_settings);
130
131 /* Fixed VS/PE specific: Toggle link rate back*/
132 if (apply_toggle_rate_wa) {
133 core_link_write_dpcd(
134 link,
135 DP_LINK_BW_SET,
136 &target_rate,
137 1);
138 }
139
140 link->vendor_specific_lttpr_link_rate_wa = target_rate;
141
142 if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) {
143
144 /* 2. perform link training (set link training done
145 * to false is done as well)
146 */
147 repeater_cnt = dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
148
149 for (repeater_id = repeater_cnt; (repeater_id > 0 && status == LINK_TRAINING_SUCCESS);
150 repeater_id--) {
151 status = perform_8b_10b_clock_recovery_sequence(link, link_res, lt_settings, repeater_id);
152
153 if (status != LINK_TRAINING_SUCCESS) {
154 repeater_training_done(link, repeater_id);
155 break;
156 }
157
158 status = perform_8b_10b_channel_equalization_sequence(link,
159 link_res,
160 lt_settings,
161 repeater_id);
162
163 repeater_training_done(link, repeater_id);
164
165 if (status != LINK_TRAINING_SUCCESS)
166 break;
167
168 for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
169 lt_settings->dpcd_lane_settings[lane].raw = 0;
170 lt_settings->hw_lane_settings[lane].VOLTAGE_SWING = 0;
171 lt_settings->hw_lane_settings[lane].PRE_EMPHASIS = 0;
172 }
173 }
174 }
175
176 if (status == LINK_TRAINING_SUCCESS) {
177 status = perform_8b_10b_clock_recovery_sequence(link, link_res, lt_settings, DPRX);
178 if (status == LINK_TRAINING_SUCCESS) {
179 status = perform_8b_10b_channel_equalization_sequence(link,
180 link_res,
181 lt_settings,
182 DPRX);
183 }
184 }
185
186 return status;
187 }
188
189
dp_perform_fixed_vs_pe_training_sequence_legacy(struct dc_link * link,const struct link_resource * link_res,struct link_training_settings * lt_settings)190 enum link_training_result dp_perform_fixed_vs_pe_training_sequence_legacy(
191 struct dc_link *link,
192 const struct link_resource *link_res,
193 struct link_training_settings *lt_settings)
194 {
195 const uint8_t vendor_lttpr_write_data_reset[4] = {0x1, 0x50, 0x63, 0xFF};
196 const uint8_t offset = dp_parse_lttpr_repeater_count(
197 link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
198 const uint8_t vendor_lttpr_write_data_intercept_en[4] = {0x1, 0x55, 0x63, 0x0};
199 const uint8_t vendor_lttpr_write_data_intercept_dis[4] = {0x1, 0x55, 0x63, 0x68};
200 uint32_t pre_disable_intercept_delay_ms = 0;
201 uint8_t vendor_lttpr_write_data_vs[4] = {0x1, 0x51, 0x63, 0x0};
202 uint8_t vendor_lttpr_write_data_pe[4] = {0x1, 0x52, 0x63, 0x0};
203 const uint8_t vendor_lttpr_write_data_4lane_1[4] = {0x1, 0x6E, 0xF2, 0x19};
204 const uint8_t vendor_lttpr_write_data_4lane_2[4] = {0x1, 0x6B, 0xF2, 0x01};
205 const uint8_t vendor_lttpr_write_data_4lane_3[4] = {0x1, 0x6D, 0xF2, 0x18};
206 const uint8_t vendor_lttpr_write_data_4lane_4[4] = {0x1, 0x6C, 0xF2, 0x03};
207 const uint8_t vendor_lttpr_write_data_4lane_5[4] = {0x1, 0x03, 0xF3, 0x06};
208 const uint8_t vendor_lttpr_write_data_dpmf[4] = {0x1, 0x6, 0x70, 0x87};
209 enum link_training_result status = LINK_TRAINING_SUCCESS;
210 uint8_t lane = 0;
211 union down_spread_ctrl downspread = {0};
212 union lane_count_set lane_count_set = {0};
213 uint8_t toggle_rate;
214 uint8_t rate;
215
216 /* Only 8b/10b is supported */
217 ASSERT(link_dp_get_encoding_format(<_settings->link_settings) ==
218 DP_8b_10b_ENCODING);
219
220 if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) {
221 status = perform_fixed_vs_pe_nontransparent_training_sequence(link, link_res, lt_settings);
222 return status;
223 }
224
225 if (offset != 0xFF) {
226 if (offset == 2) {
227 pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa;
228
229 /* Certain display and cable configuration require extra delay */
230 } else if (offset > 2) {
231 pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa * 2;
232 }
233 }
234
235 /* Vendor specific: Reset lane settings */
236 link_configure_fixed_vs_pe_retimer(link->ddc,
237 &vendor_lttpr_write_data_reset[0], sizeof(vendor_lttpr_write_data_reset));
238 link_configure_fixed_vs_pe_retimer(link->ddc,
239 &vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs));
240 link_configure_fixed_vs_pe_retimer(link->ddc,
241 &vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe));
242
243 /* Vendor specific: Enable intercept */
244 link_configure_fixed_vs_pe_retimer(link->ddc,
245 &vendor_lttpr_write_data_intercept_en[0], sizeof(vendor_lttpr_write_data_intercept_en));
246
247
248 /* 1. set link rate, lane count and spread. */
249
250 downspread.raw = (uint8_t)(lt_settings->link_settings.link_spread);
251
252 lane_count_set.bits.LANE_COUNT_SET =
253 lt_settings->link_settings.lane_count;
254
255 lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing;
256 lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0;
257
258
259 if (lt_settings->pattern_for_eq < DP_TRAINING_PATTERN_SEQUENCE_4) {
260 lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED =
261 link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED;
262 }
263
264 core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL,
265 &downspread.raw, sizeof(downspread));
266
267 core_link_write_dpcd(link, DP_LANE_COUNT_SET,
268 &lane_count_set.raw, 1);
269
270 rate = get_dpcd_link_rate(<_settings->link_settings);
271
272 /* Vendor specific: Toggle link rate */
273 toggle_rate = (rate == 0x6) ? 0xA : 0x6;
274
275 if (link->vendor_specific_lttpr_link_rate_wa == rate || link->vendor_specific_lttpr_link_rate_wa == 0) {
276 core_link_write_dpcd(
277 link,
278 DP_LINK_BW_SET,
279 &toggle_rate,
280 1);
281 }
282
283 link->vendor_specific_lttpr_link_rate_wa = rate;
284
285 core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1);
286
287 DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x framing = %x\n %x spread = %x\n",
288 __func__,
289 DP_LINK_BW_SET,
290 lt_settings->link_settings.link_rate,
291 DP_LANE_COUNT_SET,
292 lt_settings->link_settings.lane_count,
293 lt_settings->enhanced_framing,
294 DP_DOWNSPREAD_CTRL,
295 lt_settings->link_settings.link_spread);
296
297 link_configure_fixed_vs_pe_retimer(link->ddc,
298 &vendor_lttpr_write_data_dpmf[0],
299 sizeof(vendor_lttpr_write_data_dpmf));
300
301 if (lt_settings->link_settings.lane_count == LANE_COUNT_FOUR) {
302 link_configure_fixed_vs_pe_retimer(link->ddc,
303 &vendor_lttpr_write_data_4lane_1[0], sizeof(vendor_lttpr_write_data_4lane_1));
304 link_configure_fixed_vs_pe_retimer(link->ddc,
305 &vendor_lttpr_write_data_4lane_2[0], sizeof(vendor_lttpr_write_data_4lane_2));
306 link_configure_fixed_vs_pe_retimer(link->ddc,
307 &vendor_lttpr_write_data_4lane_3[0], sizeof(vendor_lttpr_write_data_4lane_3));
308 link_configure_fixed_vs_pe_retimer(link->ddc,
309 &vendor_lttpr_write_data_4lane_4[0], sizeof(vendor_lttpr_write_data_4lane_4));
310 link_configure_fixed_vs_pe_retimer(link->ddc,
311 &vendor_lttpr_write_data_4lane_5[0], sizeof(vendor_lttpr_write_data_4lane_5));
312 }
313
314 /* 2. Perform link training */
315
316 /* Perform Clock Recovery Sequence */
317 if (status == LINK_TRAINING_SUCCESS) {
318 const uint8_t max_vendor_dpcd_retries = 10;
319 uint32_t retries_cr;
320 uint32_t retry_count;
321 uint32_t wait_time_microsec;
322 enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
323 union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX];
324 union lane_align_status_updated dpcd_lane_status_updated;
325 union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
326 uint8_t i = 0;
327
328 retries_cr = 0;
329 retry_count = 0;
330
331 memset(&dpcd_lane_status, '\0', sizeof(dpcd_lane_status));
332 memset(&dpcd_lane_status_updated, '\0',
333 sizeof(dpcd_lane_status_updated));
334
335 while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) &&
336 (retry_count < LINK_TRAINING_MAX_CR_RETRY)) {
337
338
339 /* 1. call HWSS to set lane settings */
340 dp_set_hw_lane_settings(
341 link,
342 link_res,
343 lt_settings,
344 0);
345
346 /* 2. update DPCD of the receiver */
347 if (!retry_count) {
348 /* EPR #361076 - write as a 5-byte burst,
349 * but only for the 1-st iteration.
350 */
351 dpcd_set_lt_pattern_and_lane_settings(
352 link,
353 lt_settings,
354 lt_settings->pattern_for_cr,
355 0);
356 /* Vendor specific: Disable intercept */
357 for (i = 0; i < max_vendor_dpcd_retries; i++) {
358 if (pre_disable_intercept_delay_ms != 0)
359 msleep(pre_disable_intercept_delay_ms);
360 if (link_configure_fixed_vs_pe_retimer(link->ddc,
361 &vendor_lttpr_write_data_intercept_dis[0],
362 sizeof(vendor_lttpr_write_data_intercept_dis)))
363 break;
364
365 link_configure_fixed_vs_pe_retimer(link->ddc,
366 &vendor_lttpr_write_data_intercept_en[0],
367 sizeof(vendor_lttpr_write_data_intercept_en));
368 }
369 } else {
370 vendor_lttpr_write_data_vs[3] = 0;
371 vendor_lttpr_write_data_pe[3] = 0;
372
373 for (lane = 0; lane < lane_count; lane++) {
374 vendor_lttpr_write_data_vs[3] |=
375 lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane);
376 vendor_lttpr_write_data_pe[3] |=
377 lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane);
378 }
379
380 /* Vendor specific: Update VS and PE to DPRX requested value */
381 link_configure_fixed_vs_pe_retimer(link->ddc,
382 &vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs));
383 link_configure_fixed_vs_pe_retimer(link->ddc,
384 &vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe));
385
386 dpcd_set_lane_settings(
387 link,
388 lt_settings,
389 0);
390 }
391
392 /* 3. wait receiver to lock-on*/
393 wait_time_microsec = lt_settings->cr_pattern_time;
394
395 dp_wait_for_training_aux_rd_interval(
396 link,
397 wait_time_microsec);
398
399 /* 4. Read lane status and requested drive
400 * settings as set by the sink
401 */
402 dp_get_lane_status_and_lane_adjust(
403 link,
404 lt_settings,
405 dpcd_lane_status,
406 &dpcd_lane_status_updated,
407 dpcd_lane_adjust,
408 0);
409
410 /* 5. check CR done*/
411 if (dp_is_cr_done(lane_count, dpcd_lane_status)) {
412 status = LINK_TRAINING_SUCCESS;
413 break;
414 }
415
416 /* 6. max VS reached*/
417 if (dp_is_max_vs_reached(lt_settings))
418 break;
419
420 /* 7. same lane settings */
421 /* Note: settings are the same for all lanes,
422 * so comparing first lane is sufficient
423 */
424 if (lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET ==
425 dpcd_lane_adjust[0].bits.VOLTAGE_SWING_LANE)
426 retries_cr++;
427 else
428 retries_cr = 0;
429
430 /* 8. update VS/PE/PC2 in lt_settings*/
431 dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
432 lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
433 retry_count++;
434 }
435
436 if (retry_count >= LINK_TRAINING_MAX_CR_RETRY) {
437 ASSERT(0);
438 DC_LOG_ERROR("%s: Link Training Error, could not get CR after %d tries. Possibly voltage swing issue",
439 __func__,
440 LINK_TRAINING_MAX_CR_RETRY);
441
442 }
443
444 status = dp_get_cr_failure(lane_count, dpcd_lane_status);
445 }
446
447 /* Perform Channel EQ Sequence */
448 if (status == LINK_TRAINING_SUCCESS) {
449 enum dc_dp_training_pattern tr_pattern;
450 uint32_t retries_ch_eq;
451 uint32_t wait_time_microsec;
452 enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
453 union lane_align_status_updated dpcd_lane_status_updated = {0};
454 union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
455 union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
456
457 /* Note: also check that TPS4 is a supported feature*/
458 tr_pattern = lt_settings->pattern_for_eq;
459
460 dp_set_hw_training_pattern(link, link_res, tr_pattern, 0);
461
462 status = LINK_TRAINING_EQ_FAIL_EQ;
463
464 for (retries_ch_eq = 0; retries_ch_eq <= LINK_TRAINING_MAX_RETRY_COUNT;
465 retries_ch_eq++) {
466
467 dp_set_hw_lane_settings(link, link_res, lt_settings, 0);
468
469 vendor_lttpr_write_data_vs[3] = 0;
470 vendor_lttpr_write_data_pe[3] = 0;
471
472 for (lane = 0; lane < lane_count; lane++) {
473 vendor_lttpr_write_data_vs[3] |=
474 lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane);
475 vendor_lttpr_write_data_pe[3] |=
476 lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane);
477 }
478
479 /* Vendor specific: Update VS and PE to DPRX requested value */
480 link_configure_fixed_vs_pe_retimer(link->ddc,
481 &vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs));
482 link_configure_fixed_vs_pe_retimer(link->ddc,
483 &vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe));
484
485 /* 2. update DPCD*/
486 if (!retries_ch_eq)
487 /* EPR #361076 - write as a 5-byte burst,
488 * but only for the 1-st iteration
489 */
490
491 dpcd_set_lt_pattern_and_lane_settings(
492 link,
493 lt_settings,
494 tr_pattern, 0);
495 else
496 dpcd_set_lane_settings(link, lt_settings, 0);
497
498 /* 3. wait for receiver to lock-on*/
499 wait_time_microsec = lt_settings->eq_pattern_time;
500
501 dp_wait_for_training_aux_rd_interval(
502 link,
503 wait_time_microsec);
504
505 /* 4. Read lane status and requested
506 * drive settings as set by the sink
507 */
508 dp_get_lane_status_and_lane_adjust(
509 link,
510 lt_settings,
511 dpcd_lane_status,
512 &dpcd_lane_status_updated,
513 dpcd_lane_adjust,
514 0);
515
516 /* 5. check CR done*/
517 if (!dp_is_cr_done(lane_count, dpcd_lane_status)) {
518 status = LINK_TRAINING_EQ_FAIL_CR;
519 break;
520 }
521
522 /* 6. check CHEQ done*/
523 if (dp_is_ch_eq_done(lane_count, dpcd_lane_status) &&
524 dp_is_symbol_locked(lane_count, dpcd_lane_status) &&
525 dp_is_interlane_aligned(dpcd_lane_status_updated)) {
526 status = LINK_TRAINING_SUCCESS;
527 break;
528 }
529
530 /* 7. update VS/PE/PC2 in lt_settings*/
531 dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
532 lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
533 }
534 }
535
536 return status;
537 }
538
dp_perform_fixed_vs_pe_training_sequence(struct dc_link * link,const struct link_resource * link_res,struct link_training_settings * lt_settings)539 enum link_training_result dp_perform_fixed_vs_pe_training_sequence(
540 struct dc_link *link,
541 const struct link_resource *link_res,
542 struct link_training_settings *lt_settings)
543 {
544 const uint8_t vendor_lttpr_write_data_reset[4] = {0x1, 0x50, 0x63, 0xFF};
545 const uint8_t offset = dp_parse_lttpr_repeater_count(
546 link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
547 const uint8_t vendor_lttpr_write_data_intercept_en[4] = {0x1, 0x55, 0x63, 0x0};
548 const uint8_t vendor_lttpr_write_data_intercept_dis[4] = {0x1, 0x55, 0x63, 0x6E};
549 const uint8_t vendor_lttpr_write_data_adicora_eq1[4] = {0x1, 0x55, 0x63, 0x2E};
550 const uint8_t vendor_lttpr_write_data_adicora_eq2[4] = {0x1, 0x55, 0x63, 0x01};
551 const uint8_t vendor_lttpr_write_data_adicora_eq3[4] = {0x1, 0x55, 0x63, 0x68};
552 uint32_t pre_disable_intercept_delay_ms = 0;
553 uint8_t vendor_lttpr_write_data_vs[4] = {0x1, 0x51, 0x63, 0x0};
554 uint8_t vendor_lttpr_write_data_pe[4] = {0x1, 0x52, 0x63, 0x0};
555 const uint8_t vendor_lttpr_write_data_4lane_1[4] = {0x1, 0x6E, 0xF2, 0x19};
556 const uint8_t vendor_lttpr_write_data_4lane_2[4] = {0x1, 0x6B, 0xF2, 0x01};
557 const uint8_t vendor_lttpr_write_data_4lane_3[4] = {0x1, 0x6D, 0xF2, 0x18};
558 const uint8_t vendor_lttpr_write_data_4lane_4[4] = {0x1, 0x6C, 0xF2, 0x03};
559 const uint8_t vendor_lttpr_write_data_4lane_5[4] = {0x1, 0x03, 0xF3, 0x06};
560 const uint8_t vendor_lttpr_write_data_dpmf[4] = {0x1, 0x6, 0x70, 0x87};
561 enum link_training_result status = LINK_TRAINING_SUCCESS;
562 uint8_t lane = 0;
563 union down_spread_ctrl downspread = {0};
564 union lane_count_set lane_count_set = {0};
565 uint8_t toggle_rate;
566 uint8_t rate;
567
568 /* Only 8b/10b is supported */
569 ASSERT(link_dp_get_encoding_format(<_settings->link_settings) ==
570 DP_8b_10b_ENCODING);
571
572 if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) {
573 status = perform_fixed_vs_pe_nontransparent_training_sequence(link, link_res, lt_settings);
574 return status;
575 }
576
577 if (offset != 0xFF) {
578 if (offset == 2) {
579 pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa;
580
581 /* Certain display and cable configuration require extra delay */
582 } else if (offset > 2) {
583 pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa * 2;
584 }
585 }
586
587 /* Vendor specific: Reset lane settings */
588 link_configure_fixed_vs_pe_retimer(link->ddc,
589 &vendor_lttpr_write_data_reset[0], sizeof(vendor_lttpr_write_data_reset));
590 link_configure_fixed_vs_pe_retimer(link->ddc,
591 &vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs));
592 link_configure_fixed_vs_pe_retimer(link->ddc,
593 &vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe));
594
595 /* Vendor specific: Enable intercept */
596 link_configure_fixed_vs_pe_retimer(link->ddc,
597 &vendor_lttpr_write_data_intercept_en[0], sizeof(vendor_lttpr_write_data_intercept_en));
598
599 /* 1. set link rate, lane count and spread. */
600
601 downspread.raw = (uint8_t)(lt_settings->link_settings.link_spread);
602
603 lane_count_set.bits.LANE_COUNT_SET =
604 lt_settings->link_settings.lane_count;
605
606 lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing;
607 lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0;
608
609
610 if (lt_settings->pattern_for_eq < DP_TRAINING_PATTERN_SEQUENCE_4) {
611 lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED =
612 link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED;
613 }
614
615 core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL,
616 &downspread.raw, sizeof(downspread));
617
618 core_link_write_dpcd(link, DP_LANE_COUNT_SET,
619 &lane_count_set.raw, 1);
620
621 rate = get_dpcd_link_rate(<_settings->link_settings);
622
623 /* Vendor specific: Toggle link rate */
624 toggle_rate = (rate == 0x6) ? 0xA : 0x6;
625
626 if (link->vendor_specific_lttpr_link_rate_wa == rate || link->vendor_specific_lttpr_link_rate_wa == 0) {
627 core_link_write_dpcd(
628 link,
629 DP_LINK_BW_SET,
630 &toggle_rate,
631 1);
632 }
633
634 link->vendor_specific_lttpr_link_rate_wa = rate;
635
636 core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1);
637
638 DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x framing = %x\n %x spread = %x\n",
639 __func__,
640 DP_LINK_BW_SET,
641 lt_settings->link_settings.link_rate,
642 DP_LANE_COUNT_SET,
643 lt_settings->link_settings.lane_count,
644 lt_settings->enhanced_framing,
645 DP_DOWNSPREAD_CTRL,
646 lt_settings->link_settings.link_spread);
647
648 link_configure_fixed_vs_pe_retimer(link->ddc,
649 &vendor_lttpr_write_data_dpmf[0],
650 sizeof(vendor_lttpr_write_data_dpmf));
651
652 if (lt_settings->link_settings.lane_count == LANE_COUNT_FOUR) {
653 link_configure_fixed_vs_pe_retimer(link->ddc,
654 &vendor_lttpr_write_data_4lane_1[0], sizeof(vendor_lttpr_write_data_4lane_1));
655 link_configure_fixed_vs_pe_retimer(link->ddc,
656 &vendor_lttpr_write_data_4lane_2[0], sizeof(vendor_lttpr_write_data_4lane_2));
657 link_configure_fixed_vs_pe_retimer(link->ddc,
658 &vendor_lttpr_write_data_4lane_3[0], sizeof(vendor_lttpr_write_data_4lane_3));
659 link_configure_fixed_vs_pe_retimer(link->ddc,
660 &vendor_lttpr_write_data_4lane_4[0], sizeof(vendor_lttpr_write_data_4lane_4));
661 link_configure_fixed_vs_pe_retimer(link->ddc,
662 &vendor_lttpr_write_data_4lane_5[0], sizeof(vendor_lttpr_write_data_4lane_5));
663 }
664
665 /* 2. Perform link training */
666
667 /* Perform Clock Recovery Sequence */
668 if (status == LINK_TRAINING_SUCCESS) {
669 const uint8_t max_vendor_dpcd_retries = 10;
670 uint32_t retries_cr;
671 uint32_t retry_count;
672 uint32_t wait_time_microsec;
673 enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
674 union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX];
675 union lane_align_status_updated dpcd_lane_status_updated;
676 union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
677 uint8_t i = 0;
678
679 retries_cr = 0;
680 retry_count = 0;
681
682 memset(&dpcd_lane_status, '\0', sizeof(dpcd_lane_status));
683 memset(&dpcd_lane_status_updated, '\0',
684 sizeof(dpcd_lane_status_updated));
685
686 while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) &&
687 (retry_count < LINK_TRAINING_MAX_CR_RETRY)) {
688
689
690 /* 1. call HWSS to set lane settings */
691 dp_set_hw_lane_settings(
692 link,
693 link_res,
694 lt_settings,
695 0);
696
697 /* 2. update DPCD of the receiver */
698 if (!retry_count) {
699 /* EPR #361076 - write as a 5-byte burst,
700 * but only for the 1-st iteration.
701 */
702 dpcd_set_lt_pattern_and_lane_settings(
703 link,
704 lt_settings,
705 lt_settings->pattern_for_cr,
706 0);
707 /* Vendor specific: Disable intercept */
708 for (i = 0; i < max_vendor_dpcd_retries; i++) {
709 if (pre_disable_intercept_delay_ms != 0)
710 msleep(pre_disable_intercept_delay_ms);
711 if (link_configure_fixed_vs_pe_retimer(link->ddc,
712 &vendor_lttpr_write_data_intercept_dis[0],
713 sizeof(vendor_lttpr_write_data_intercept_dis)))
714 break;
715
716 link_configure_fixed_vs_pe_retimer(link->ddc,
717 &vendor_lttpr_write_data_intercept_en[0],
718 sizeof(vendor_lttpr_write_data_intercept_en));
719 }
720 } else {
721 vendor_lttpr_write_data_vs[3] = 0;
722 vendor_lttpr_write_data_pe[3] = 0;
723
724 for (lane = 0; lane < lane_count; lane++) {
725 vendor_lttpr_write_data_vs[3] |=
726 lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane);
727 vendor_lttpr_write_data_pe[3] |=
728 lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane);
729 }
730
731 /* Vendor specific: Update VS and PE to DPRX requested value */
732 link_configure_fixed_vs_pe_retimer(link->ddc,
733 &vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs));
734 link_configure_fixed_vs_pe_retimer(link->ddc,
735 &vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe));
736
737 dpcd_set_lane_settings(
738 link,
739 lt_settings,
740 0);
741 }
742
743 /* 3. wait receiver to lock-on*/
744 wait_time_microsec = lt_settings->cr_pattern_time;
745
746 dp_wait_for_training_aux_rd_interval(
747 link,
748 wait_time_microsec);
749
750 /* 4. Read lane status and requested drive
751 * settings as set by the sink
752 */
753 dp_get_lane_status_and_lane_adjust(
754 link,
755 lt_settings,
756 dpcd_lane_status,
757 &dpcd_lane_status_updated,
758 dpcd_lane_adjust,
759 0);
760
761 /* 5. check CR done*/
762 if (dp_is_cr_done(lane_count, dpcd_lane_status)) {
763 status = LINK_TRAINING_SUCCESS;
764 break;
765 }
766
767 /* 6. max VS reached*/
768 if (dp_is_max_vs_reached(lt_settings))
769 break;
770
771 /* 7. same lane settings */
772 /* Note: settings are the same for all lanes,
773 * so comparing first lane is sufficient
774 */
775 if (lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET ==
776 dpcd_lane_adjust[0].bits.VOLTAGE_SWING_LANE)
777 retries_cr++;
778 else
779 retries_cr = 0;
780
781 /* 8. update VS/PE/PC2 in lt_settings*/
782 dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
783 lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
784 retry_count++;
785 }
786
787 if (retry_count >= LINK_TRAINING_MAX_CR_RETRY) {
788 ASSERT(0);
789 DC_LOG_ERROR("%s: Link Training Error, could not get CR after %d tries. Possibly voltage swing issue",
790 __func__,
791 LINK_TRAINING_MAX_CR_RETRY);
792
793 }
794
795 status = dp_get_cr_failure(lane_count, dpcd_lane_status);
796 }
797
798 /* Perform Channel EQ Sequence */
799 if (status == LINK_TRAINING_SUCCESS) {
800 enum dc_dp_training_pattern tr_pattern;
801 uint32_t retries_ch_eq;
802 uint32_t wait_time_microsec;
803 enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
804 union lane_align_status_updated dpcd_lane_status_updated = {0};
805 union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
806 union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
807
808 link_configure_fixed_vs_pe_retimer(link->ddc,
809 &vendor_lttpr_write_data_adicora_eq1[0],
810 sizeof(vendor_lttpr_write_data_adicora_eq1));
811 link_configure_fixed_vs_pe_retimer(link->ddc,
812 &vendor_lttpr_write_data_adicora_eq2[0],
813 sizeof(vendor_lttpr_write_data_adicora_eq2));
814
815
816 /* Note: also check that TPS4 is a supported feature*/
817 tr_pattern = lt_settings->pattern_for_eq;
818
819 dp_set_hw_training_pattern(link, link_res, tr_pattern, 0);
820
821 status = LINK_TRAINING_EQ_FAIL_EQ;
822
823 for (retries_ch_eq = 0; retries_ch_eq <= LINK_TRAINING_MAX_RETRY_COUNT;
824 retries_ch_eq++) {
825
826 dp_set_hw_lane_settings(link, link_res, lt_settings, 0);
827
828 vendor_lttpr_write_data_vs[3] = 0;
829 vendor_lttpr_write_data_pe[3] = 0;
830
831 for (lane = 0; lane < lane_count; lane++) {
832 vendor_lttpr_write_data_vs[3] |=
833 lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane);
834 vendor_lttpr_write_data_pe[3] |=
835 lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane);
836 }
837
838 /* Vendor specific: Update VS and PE to DPRX requested value */
839 link_configure_fixed_vs_pe_retimer(link->ddc,
840 &vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs));
841 link_configure_fixed_vs_pe_retimer(link->ddc,
842 &vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe));
843
844 /* 2. update DPCD*/
845 if (!retries_ch_eq) {
846 /* EPR #361076 - write as a 5-byte burst,
847 * but only for the 1-st iteration
848 */
849
850 dpcd_set_lt_pattern_and_lane_settings(
851 link,
852 lt_settings,
853 tr_pattern, 0);
854
855 link_configure_fixed_vs_pe_retimer(link->ddc,
856 &vendor_lttpr_write_data_adicora_eq3[0],
857 sizeof(vendor_lttpr_write_data_adicora_eq3));
858
859 } else
860 dpcd_set_lane_settings(link, lt_settings, 0);
861
862 /* 3. wait for receiver to lock-on*/
863 wait_time_microsec = lt_settings->eq_pattern_time;
864
865 dp_wait_for_training_aux_rd_interval(
866 link,
867 wait_time_microsec);
868
869 /* 4. Read lane status and requested
870 * drive settings as set by the sink
871 */
872 dp_get_lane_status_and_lane_adjust(
873 link,
874 lt_settings,
875 dpcd_lane_status,
876 &dpcd_lane_status_updated,
877 dpcd_lane_adjust,
878 0);
879
880 /* 5. check CR done*/
881 if (!dp_is_cr_done(lane_count, dpcd_lane_status)) {
882 status = LINK_TRAINING_EQ_FAIL_CR;
883 break;
884 }
885
886 /* 6. check CHEQ done*/
887 if (dp_is_ch_eq_done(lane_count, dpcd_lane_status) &&
888 dp_is_symbol_locked(lane_count, dpcd_lane_status) &&
889 dp_is_interlane_aligned(dpcd_lane_status_updated)) {
890 status = LINK_TRAINING_SUCCESS;
891 break;
892 }
893
894 /* 7. update VS/PE/PC2 in lt_settings*/
895 dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
896 lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
897 }
898 }
899
900 return status;
901 }
902