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 enum link_training_result status = LINK_TRAINING_SUCCESS;
209 uint8_t lane = 0;
210 union down_spread_ctrl downspread = {0};
211 union lane_count_set lane_count_set = {0};
212 uint8_t toggle_rate;
213 uint8_t rate;
214
215 /* Only 8b/10b is supported */
216 ASSERT(link_dp_get_encoding_format(<_settings->link_settings) ==
217 DP_8b_10b_ENCODING);
218
219 if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) {
220 status = perform_fixed_vs_pe_nontransparent_training_sequence(link, link_res, lt_settings);
221 return status;
222 }
223
224 if (offset != 0xFF) {
225 if (offset == 2) {
226 pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa;
227
228 /* Certain display and cable configuration require extra delay */
229 } else if (offset > 2) {
230 pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa * 2;
231 }
232 }
233
234 /* Vendor specific: Reset lane settings */
235 link_configure_fixed_vs_pe_retimer(link->ddc,
236 &vendor_lttpr_write_data_reset[0], sizeof(vendor_lttpr_write_data_reset));
237 link_configure_fixed_vs_pe_retimer(link->ddc,
238 &vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs));
239 link_configure_fixed_vs_pe_retimer(link->ddc,
240 &vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe));
241
242 /* Vendor specific: Enable intercept */
243 link_configure_fixed_vs_pe_retimer(link->ddc,
244 &vendor_lttpr_write_data_intercept_en[0], sizeof(vendor_lttpr_write_data_intercept_en));
245
246
247 /* 1. set link rate, lane count and spread. */
248
249 downspread.raw = (uint8_t)(lt_settings->link_settings.link_spread);
250
251 lane_count_set.bits.LANE_COUNT_SET =
252 lt_settings->link_settings.lane_count;
253
254 lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing;
255 lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0;
256
257
258 if (lt_settings->pattern_for_eq < DP_TRAINING_PATTERN_SEQUENCE_4) {
259 lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED =
260 link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED;
261 }
262
263 core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL,
264 &downspread.raw, sizeof(downspread));
265
266 core_link_write_dpcd(link, DP_LANE_COUNT_SET,
267 &lane_count_set.raw, 1);
268
269 rate = get_dpcd_link_rate(<_settings->link_settings);
270
271 /* Vendor specific: Toggle link rate */
272 toggle_rate = (rate == 0x6) ? 0xA : 0x6;
273
274 if (link->vendor_specific_lttpr_link_rate_wa == rate || link->vendor_specific_lttpr_link_rate_wa == 0) {
275 core_link_write_dpcd(
276 link,
277 DP_LINK_BW_SET,
278 &toggle_rate,
279 1);
280 }
281
282 link->vendor_specific_lttpr_link_rate_wa = rate;
283
284 core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1);
285
286 DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x framing = %x\n %x spread = %x\n",
287 __func__,
288 DP_LINK_BW_SET,
289 lt_settings->link_settings.link_rate,
290 DP_LANE_COUNT_SET,
291 lt_settings->link_settings.lane_count,
292 lt_settings->enhanced_framing,
293 DP_DOWNSPREAD_CTRL,
294 lt_settings->link_settings.link_spread);
295
296 if (lt_settings->link_settings.lane_count == LANE_COUNT_FOUR) {
297 link_configure_fixed_vs_pe_retimer(link->ddc,
298 &vendor_lttpr_write_data_4lane_1[0], sizeof(vendor_lttpr_write_data_4lane_1));
299 link_configure_fixed_vs_pe_retimer(link->ddc,
300 &vendor_lttpr_write_data_4lane_2[0], sizeof(vendor_lttpr_write_data_4lane_2));
301 link_configure_fixed_vs_pe_retimer(link->ddc,
302 &vendor_lttpr_write_data_4lane_3[0], sizeof(vendor_lttpr_write_data_4lane_3));
303 link_configure_fixed_vs_pe_retimer(link->ddc,
304 &vendor_lttpr_write_data_4lane_4[0], sizeof(vendor_lttpr_write_data_4lane_4));
305 link_configure_fixed_vs_pe_retimer(link->ddc,
306 &vendor_lttpr_write_data_4lane_5[0], sizeof(vendor_lttpr_write_data_4lane_5));
307 }
308
309 /* 2. Perform link training */
310
311 /* Perform Clock Recovery Sequence */
312 if (status == LINK_TRAINING_SUCCESS) {
313 const uint8_t max_vendor_dpcd_retries = 10;
314 uint32_t retries_cr;
315 uint32_t retry_count;
316 uint32_t wait_time_microsec;
317 enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
318 union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX];
319 union lane_align_status_updated dpcd_lane_status_updated;
320 union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
321 uint8_t i = 0;
322
323 retries_cr = 0;
324 retry_count = 0;
325
326 memset(&dpcd_lane_status, '\0', sizeof(dpcd_lane_status));
327 memset(&dpcd_lane_status_updated, '\0',
328 sizeof(dpcd_lane_status_updated));
329
330 while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) &&
331 (retry_count < LINK_TRAINING_MAX_CR_RETRY)) {
332
333
334 /* 1. call HWSS to set lane settings */
335 dp_set_hw_lane_settings(
336 link,
337 link_res,
338 lt_settings,
339 0);
340
341 /* 2. update DPCD of the receiver */
342 if (!retry_count) {
343 /* EPR #361076 - write as a 5-byte burst,
344 * but only for the 1-st iteration.
345 */
346 dpcd_set_lt_pattern_and_lane_settings(
347 link,
348 lt_settings,
349 lt_settings->pattern_for_cr,
350 0);
351 /* Vendor specific: Disable intercept */
352 for (i = 0; i < max_vendor_dpcd_retries; i++) {
353 if (pre_disable_intercept_delay_ms != 0)
354 msleep(pre_disable_intercept_delay_ms);
355 if (link_configure_fixed_vs_pe_retimer(link->ddc,
356 &vendor_lttpr_write_data_intercept_dis[0],
357 sizeof(vendor_lttpr_write_data_intercept_dis)))
358 break;
359
360 link_configure_fixed_vs_pe_retimer(link->ddc,
361 &vendor_lttpr_write_data_intercept_en[0],
362 sizeof(vendor_lttpr_write_data_intercept_en));
363 }
364 } else {
365 vendor_lttpr_write_data_vs[3] = 0;
366 vendor_lttpr_write_data_pe[3] = 0;
367
368 for (lane = 0; lane < lane_count; lane++) {
369 vendor_lttpr_write_data_vs[3] |=
370 lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane);
371 vendor_lttpr_write_data_pe[3] |=
372 lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane);
373 }
374
375 /* Vendor specific: Update VS and PE to DPRX requested value */
376 link_configure_fixed_vs_pe_retimer(link->ddc,
377 &vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs));
378 link_configure_fixed_vs_pe_retimer(link->ddc,
379 &vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe));
380
381 dpcd_set_lane_settings(
382 link,
383 lt_settings,
384 0);
385 }
386
387 /* 3. wait receiver to lock-on*/
388 wait_time_microsec = lt_settings->cr_pattern_time;
389
390 dp_wait_for_training_aux_rd_interval(
391 link,
392 wait_time_microsec);
393
394 /* 4. Read lane status and requested drive
395 * settings as set by the sink
396 */
397 dp_get_lane_status_and_lane_adjust(
398 link,
399 lt_settings,
400 dpcd_lane_status,
401 &dpcd_lane_status_updated,
402 dpcd_lane_adjust,
403 0);
404
405 /* 5. check CR done*/
406 if (dp_is_cr_done(lane_count, dpcd_lane_status)) {
407 status = LINK_TRAINING_SUCCESS;
408 break;
409 }
410
411 /* 6. max VS reached*/
412 if (dp_is_max_vs_reached(lt_settings))
413 break;
414
415 /* 7. same lane settings */
416 /* Note: settings are the same for all lanes,
417 * so comparing first lane is sufficient
418 */
419 if (lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET ==
420 dpcd_lane_adjust[0].bits.VOLTAGE_SWING_LANE)
421 retries_cr++;
422 else
423 retries_cr = 0;
424
425 /* 8. update VS/PE/PC2 in lt_settings*/
426 dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
427 lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
428 retry_count++;
429 }
430
431 if (retry_count >= LINK_TRAINING_MAX_CR_RETRY) {
432 ASSERT(0);
433 DC_LOG_ERROR("%s: Link Training Error, could not get CR after %d tries. Possibly voltage swing issue",
434 __func__,
435 LINK_TRAINING_MAX_CR_RETRY);
436
437 }
438
439 status = dp_get_cr_failure(lane_count, dpcd_lane_status);
440 }
441
442 /* Perform Channel EQ Sequence */
443 if (status == LINK_TRAINING_SUCCESS) {
444 enum dc_dp_training_pattern tr_pattern;
445 uint32_t retries_ch_eq;
446 uint32_t wait_time_microsec;
447 enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
448 union lane_align_status_updated dpcd_lane_status_updated = {0};
449 union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
450 union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
451
452 /* Note: also check that TPS4 is a supported feature*/
453 tr_pattern = lt_settings->pattern_for_eq;
454
455 dp_set_hw_training_pattern(link, link_res, tr_pattern, 0);
456
457 status = LINK_TRAINING_EQ_FAIL_EQ;
458
459 for (retries_ch_eq = 0; retries_ch_eq <= LINK_TRAINING_MAX_RETRY_COUNT;
460 retries_ch_eq++) {
461
462 dp_set_hw_lane_settings(link, link_res, lt_settings, 0);
463
464 vendor_lttpr_write_data_vs[3] = 0;
465 vendor_lttpr_write_data_pe[3] = 0;
466
467 for (lane = 0; lane < lane_count; lane++) {
468 vendor_lttpr_write_data_vs[3] |=
469 lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane);
470 vendor_lttpr_write_data_pe[3] |=
471 lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane);
472 }
473
474 /* Vendor specific: Update VS and PE to DPRX requested value */
475 link_configure_fixed_vs_pe_retimer(link->ddc,
476 &vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs));
477 link_configure_fixed_vs_pe_retimer(link->ddc,
478 &vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe));
479
480 /* 2. update DPCD*/
481 if (!retries_ch_eq)
482 /* EPR #361076 - write as a 5-byte burst,
483 * but only for the 1-st iteration
484 */
485
486 dpcd_set_lt_pattern_and_lane_settings(
487 link,
488 lt_settings,
489 tr_pattern, 0);
490 else
491 dpcd_set_lane_settings(link, lt_settings, 0);
492
493 /* 3. wait for receiver to lock-on*/
494 wait_time_microsec = lt_settings->eq_pattern_time;
495
496 dp_wait_for_training_aux_rd_interval(
497 link,
498 wait_time_microsec);
499
500 /* 4. Read lane status and requested
501 * drive settings as set by the sink
502 */
503 dp_get_lane_status_and_lane_adjust(
504 link,
505 lt_settings,
506 dpcd_lane_status,
507 &dpcd_lane_status_updated,
508 dpcd_lane_adjust,
509 0);
510
511 /* 5. check CR done*/
512 if (!dp_is_cr_done(lane_count, dpcd_lane_status)) {
513 status = LINK_TRAINING_EQ_FAIL_CR;
514 break;
515 }
516
517 /* 6. check CHEQ done*/
518 if (dp_is_ch_eq_done(lane_count, dpcd_lane_status) &&
519 dp_is_symbol_locked(lane_count, dpcd_lane_status) &&
520 dp_is_interlane_aligned(dpcd_lane_status_updated)) {
521 status = LINK_TRAINING_SUCCESS;
522 break;
523 }
524
525 /* 7. update VS/PE/PC2 in lt_settings*/
526 dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
527 lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
528 }
529 }
530
531 return status;
532 }
533
dp_perform_fixed_vs_pe_training_sequence(struct dc_link * link,const struct link_resource * link_res,struct link_training_settings * lt_settings)534 enum link_training_result dp_perform_fixed_vs_pe_training_sequence(
535 struct dc_link *link,
536 const struct link_resource *link_res,
537 struct link_training_settings *lt_settings)
538 {
539 const uint8_t vendor_lttpr_write_data_reset[4] = {0x1, 0x50, 0x63, 0xFF};
540 const uint8_t offset = dp_parse_lttpr_repeater_count(
541 link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
542 const uint8_t vendor_lttpr_write_data_intercept_en[4] = {0x1, 0x55, 0x63, 0x0};
543 const uint8_t vendor_lttpr_write_data_intercept_dis[4] = {0x1, 0x55, 0x63, 0x6E};
544 const uint8_t vendor_lttpr_write_data_adicora_eq1[4] = {0x1, 0x55, 0x63, 0x2E};
545 const uint8_t vendor_lttpr_write_data_adicora_eq2[4] = {0x1, 0x55, 0x63, 0x01};
546 const uint8_t vendor_lttpr_write_data_adicora_eq3[4] = {0x1, 0x55, 0x63, 0x68};
547 uint32_t pre_disable_intercept_delay_ms = 0;
548 uint8_t vendor_lttpr_write_data_vs[4] = {0x1, 0x51, 0x63, 0x0};
549 uint8_t vendor_lttpr_write_data_pe[4] = {0x1, 0x52, 0x63, 0x0};
550 const uint8_t vendor_lttpr_write_data_4lane_1[4] = {0x1, 0x6E, 0xF2, 0x19};
551 const uint8_t vendor_lttpr_write_data_4lane_2[4] = {0x1, 0x6B, 0xF2, 0x01};
552 const uint8_t vendor_lttpr_write_data_4lane_3[4] = {0x1, 0x6D, 0xF2, 0x18};
553 const uint8_t vendor_lttpr_write_data_4lane_4[4] = {0x1, 0x6C, 0xF2, 0x03};
554 const uint8_t vendor_lttpr_write_data_4lane_5[4] = {0x1, 0x03, 0xF3, 0x06};
555 enum link_training_result status = LINK_TRAINING_SUCCESS;
556 uint8_t lane = 0;
557 union down_spread_ctrl downspread = {0};
558 union lane_count_set lane_count_set = {0};
559 uint8_t toggle_rate;
560 uint8_t rate;
561
562 /* Only 8b/10b is supported */
563 ASSERT(link_dp_get_encoding_format(<_settings->link_settings) ==
564 DP_8b_10b_ENCODING);
565
566 if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) {
567 status = perform_fixed_vs_pe_nontransparent_training_sequence(link, link_res, lt_settings);
568 return status;
569 }
570
571 if (offset != 0xFF) {
572 if (offset == 2) {
573 pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa;
574
575 /* Certain display and cable configuration require extra delay */
576 } else if (offset > 2) {
577 pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa * 2;
578 }
579 }
580
581 /* Vendor specific: Reset lane settings */
582 link_configure_fixed_vs_pe_retimer(link->ddc,
583 &vendor_lttpr_write_data_reset[0], sizeof(vendor_lttpr_write_data_reset));
584 link_configure_fixed_vs_pe_retimer(link->ddc,
585 &vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs));
586 link_configure_fixed_vs_pe_retimer(link->ddc,
587 &vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe));
588
589 /* Vendor specific: Enable intercept */
590 link_configure_fixed_vs_pe_retimer(link->ddc,
591 &vendor_lttpr_write_data_intercept_en[0], sizeof(vendor_lttpr_write_data_intercept_en));
592
593 /* 1. set link rate, lane count and spread. */
594
595 downspread.raw = (uint8_t)(lt_settings->link_settings.link_spread);
596
597 lane_count_set.bits.LANE_COUNT_SET =
598 lt_settings->link_settings.lane_count;
599
600 lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing;
601 lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0;
602
603
604 if (lt_settings->pattern_for_eq < DP_TRAINING_PATTERN_SEQUENCE_4) {
605 lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED =
606 link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED;
607 }
608
609 core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL,
610 &downspread.raw, sizeof(downspread));
611
612 core_link_write_dpcd(link, DP_LANE_COUNT_SET,
613 &lane_count_set.raw, 1);
614
615 rate = get_dpcd_link_rate(<_settings->link_settings);
616
617 /* Vendor specific: Toggle link rate */
618 toggle_rate = (rate == 0x6) ? 0xA : 0x6;
619
620 if (link->vendor_specific_lttpr_link_rate_wa == rate || link->vendor_specific_lttpr_link_rate_wa == 0) {
621 core_link_write_dpcd(
622 link,
623 DP_LINK_BW_SET,
624 &toggle_rate,
625 1);
626 }
627
628 link->vendor_specific_lttpr_link_rate_wa = rate;
629
630 core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1);
631
632 DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x framing = %x\n %x spread = %x\n",
633 __func__,
634 DP_LINK_BW_SET,
635 lt_settings->link_settings.link_rate,
636 DP_LANE_COUNT_SET,
637 lt_settings->link_settings.lane_count,
638 lt_settings->enhanced_framing,
639 DP_DOWNSPREAD_CTRL,
640 lt_settings->link_settings.link_spread);
641
642 if (lt_settings->link_settings.lane_count == LANE_COUNT_FOUR) {
643 link_configure_fixed_vs_pe_retimer(link->ddc,
644 &vendor_lttpr_write_data_4lane_1[0], sizeof(vendor_lttpr_write_data_4lane_1));
645 link_configure_fixed_vs_pe_retimer(link->ddc,
646 &vendor_lttpr_write_data_4lane_2[0], sizeof(vendor_lttpr_write_data_4lane_2));
647 link_configure_fixed_vs_pe_retimer(link->ddc,
648 &vendor_lttpr_write_data_4lane_3[0], sizeof(vendor_lttpr_write_data_4lane_3));
649 link_configure_fixed_vs_pe_retimer(link->ddc,
650 &vendor_lttpr_write_data_4lane_4[0], sizeof(vendor_lttpr_write_data_4lane_4));
651 link_configure_fixed_vs_pe_retimer(link->ddc,
652 &vendor_lttpr_write_data_4lane_5[0], sizeof(vendor_lttpr_write_data_4lane_5));
653 }
654
655 /* 2. Perform link training */
656
657 /* Perform Clock Recovery Sequence */
658 if (status == LINK_TRAINING_SUCCESS) {
659 const uint8_t max_vendor_dpcd_retries = 10;
660 uint32_t retries_cr;
661 uint32_t retry_count;
662 uint32_t wait_time_microsec;
663 enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
664 union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX];
665 union lane_align_status_updated dpcd_lane_status_updated;
666 union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
667 uint8_t i = 0;
668
669 retries_cr = 0;
670 retry_count = 0;
671
672 memset(&dpcd_lane_status, '\0', sizeof(dpcd_lane_status));
673 memset(&dpcd_lane_status_updated, '\0',
674 sizeof(dpcd_lane_status_updated));
675
676 while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) &&
677 (retry_count < LINK_TRAINING_MAX_CR_RETRY)) {
678
679
680 /* 1. call HWSS to set lane settings */
681 dp_set_hw_lane_settings(
682 link,
683 link_res,
684 lt_settings,
685 0);
686
687 /* 2. update DPCD of the receiver */
688 if (!retry_count) {
689 /* EPR #361076 - write as a 5-byte burst,
690 * but only for the 1-st iteration.
691 */
692 dpcd_set_lt_pattern_and_lane_settings(
693 link,
694 lt_settings,
695 lt_settings->pattern_for_cr,
696 0);
697 /* Vendor specific: Disable intercept */
698 for (i = 0; i < max_vendor_dpcd_retries; i++) {
699 if (pre_disable_intercept_delay_ms != 0)
700 msleep(pre_disable_intercept_delay_ms);
701 if (link_configure_fixed_vs_pe_retimer(link->ddc,
702 &vendor_lttpr_write_data_intercept_dis[0],
703 sizeof(vendor_lttpr_write_data_intercept_dis)))
704 break;
705
706 link_configure_fixed_vs_pe_retimer(link->ddc,
707 &vendor_lttpr_write_data_intercept_en[0],
708 sizeof(vendor_lttpr_write_data_intercept_en));
709 }
710 } else {
711 vendor_lttpr_write_data_vs[3] = 0;
712 vendor_lttpr_write_data_pe[3] = 0;
713
714 for (lane = 0; lane < lane_count; lane++) {
715 vendor_lttpr_write_data_vs[3] |=
716 lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane);
717 vendor_lttpr_write_data_pe[3] |=
718 lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane);
719 }
720
721 /* Vendor specific: Update VS and PE to DPRX requested value */
722 link_configure_fixed_vs_pe_retimer(link->ddc,
723 &vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs));
724 link_configure_fixed_vs_pe_retimer(link->ddc,
725 &vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe));
726
727 dpcd_set_lane_settings(
728 link,
729 lt_settings,
730 0);
731 }
732
733 /* 3. wait receiver to lock-on*/
734 wait_time_microsec = lt_settings->cr_pattern_time;
735
736 dp_wait_for_training_aux_rd_interval(
737 link,
738 wait_time_microsec);
739
740 /* 4. Read lane status and requested drive
741 * settings as set by the sink
742 */
743 dp_get_lane_status_and_lane_adjust(
744 link,
745 lt_settings,
746 dpcd_lane_status,
747 &dpcd_lane_status_updated,
748 dpcd_lane_adjust,
749 0);
750
751 /* 5. check CR done*/
752 if (dp_is_cr_done(lane_count, dpcd_lane_status)) {
753 status = LINK_TRAINING_SUCCESS;
754 break;
755 }
756
757 /* 6. max VS reached*/
758 if (dp_is_max_vs_reached(lt_settings))
759 break;
760
761 /* 7. same lane settings */
762 /* Note: settings are the same for all lanes,
763 * so comparing first lane is sufficient
764 */
765 if (lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET ==
766 dpcd_lane_adjust[0].bits.VOLTAGE_SWING_LANE)
767 retries_cr++;
768 else
769 retries_cr = 0;
770
771 /* 8. update VS/PE/PC2 in lt_settings*/
772 dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
773 lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
774 retry_count++;
775 }
776
777 if (retry_count >= LINK_TRAINING_MAX_CR_RETRY) {
778 ASSERT(0);
779 DC_LOG_ERROR("%s: Link Training Error, could not get CR after %d tries. Possibly voltage swing issue",
780 __func__,
781 LINK_TRAINING_MAX_CR_RETRY);
782
783 }
784
785 status = dp_get_cr_failure(lane_count, dpcd_lane_status);
786 }
787
788 /* Perform Channel EQ Sequence */
789 if (status == LINK_TRAINING_SUCCESS) {
790 enum dc_dp_training_pattern tr_pattern;
791 uint32_t retries_ch_eq;
792 uint32_t wait_time_microsec;
793 enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
794 union lane_align_status_updated dpcd_lane_status_updated = {0};
795 union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
796 union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
797
798 link_configure_fixed_vs_pe_retimer(link->ddc,
799 &vendor_lttpr_write_data_adicora_eq1[0],
800 sizeof(vendor_lttpr_write_data_adicora_eq1));
801 link_configure_fixed_vs_pe_retimer(link->ddc,
802 &vendor_lttpr_write_data_adicora_eq2[0],
803 sizeof(vendor_lttpr_write_data_adicora_eq2));
804
805
806 /* Note: also check that TPS4 is a supported feature*/
807 tr_pattern = lt_settings->pattern_for_eq;
808
809 dp_set_hw_training_pattern(link, link_res, tr_pattern, 0);
810
811 status = LINK_TRAINING_EQ_FAIL_EQ;
812
813 for (retries_ch_eq = 0; retries_ch_eq <= LINK_TRAINING_MAX_RETRY_COUNT;
814 retries_ch_eq++) {
815
816 dp_set_hw_lane_settings(link, link_res, lt_settings, 0);
817
818 vendor_lttpr_write_data_vs[3] = 0;
819 vendor_lttpr_write_data_pe[3] = 0;
820
821 for (lane = 0; lane < lane_count; lane++) {
822 vendor_lttpr_write_data_vs[3] |=
823 lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane);
824 vendor_lttpr_write_data_pe[3] |=
825 lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane);
826 }
827
828 /* Vendor specific: Update VS and PE to DPRX requested value */
829 link_configure_fixed_vs_pe_retimer(link->ddc,
830 &vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs));
831 link_configure_fixed_vs_pe_retimer(link->ddc,
832 &vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe));
833
834 /* 2. update DPCD*/
835 if (!retries_ch_eq) {
836 /* EPR #361076 - write as a 5-byte burst,
837 * but only for the 1-st iteration
838 */
839
840 dpcd_set_lt_pattern_and_lane_settings(
841 link,
842 lt_settings,
843 tr_pattern, 0);
844
845 link_configure_fixed_vs_pe_retimer(link->ddc,
846 &vendor_lttpr_write_data_adicora_eq3[0],
847 sizeof(vendor_lttpr_write_data_adicora_eq3));
848
849 } else
850 dpcd_set_lane_settings(link, lt_settings, 0);
851
852 /* 3. wait for receiver to lock-on*/
853 wait_time_microsec = lt_settings->eq_pattern_time;
854
855 dp_wait_for_training_aux_rd_interval(
856 link,
857 wait_time_microsec);
858
859 /* 4. Read lane status and requested
860 * drive settings as set by the sink
861 */
862 dp_get_lane_status_and_lane_adjust(
863 link,
864 lt_settings,
865 dpcd_lane_status,
866 &dpcd_lane_status_updated,
867 dpcd_lane_adjust,
868 0);
869
870 /* 5. check CR done*/
871 if (!dp_is_cr_done(lane_count, dpcd_lane_status)) {
872 status = LINK_TRAINING_EQ_FAIL_CR;
873 break;
874 }
875
876 /* 6. check CHEQ done*/
877 if (dp_is_ch_eq_done(lane_count, dpcd_lane_status) &&
878 dp_is_symbol_locked(lane_count, dpcd_lane_status) &&
879 dp_is_interlane_aligned(dpcd_lane_status_updated)) {
880 status = LINK_TRAINING_SUCCESS;
881 break;
882 }
883
884 /* 7. update VS/PE/PC2 in lt_settings*/
885 dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
886 lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
887 }
888 }
889
890 return status;
891 }
892