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 all generic dp link training helper functions and top
28 * level generic training sequence. All variations of dp link training sequence
29 * should be called inside the top level training functions in this file to
30 * ensure the integrity of our overall training procedure across different types
31 * of link encoding and back end hardware.
32 */
33#include "link_dp_training.h"
34#include "link_dp_training_8b_10b.h"
35#include "link_dp_training_128b_132b.h"
36#include "link_dp_training_auxless.h"
37#include "link_dp_training_dpia.h"
38#include "link_dp_training_fixed_vs_pe_retimer.h"
39#include "link_dpcd.h"
40#include "link/accessories/link_dp_trace.h"
41#include "link_dp_phy.h"
42#include "link_dp_capability.h"
43#include "link_edp_panel_control.h"
44#include "link/link_detection.h"
45#include "link/link_validation.h"
46#include "atomfirmware.h"
47#include "link_enc_cfg.h"
48#include "resource.h"
49#include "dm_helpers.h"
50
51#define DC_LOGGER \
52 link->ctx->logger
53
54#define POST_LT_ADJ_REQ_LIMIT 6
55#define POST_LT_ADJ_REQ_TIMEOUT 200
56#define LINK_TRAINING_RETRY_DELAY 50 /* ms */
57
58void dp_log_training_result(
59 struct dc_link *link,
60 const struct link_training_settings *lt_settings,
61 enum link_training_result status)
62{
63 char *link_rate = "Unknown";
64 char *lt_result = "Unknown";
65 char *lt_spread = "Disabled";
66
67 switch (lt_settings->link_settings.link_rate) {
68 case LINK_RATE_LOW:
69 link_rate = "RBR";
70 break;
71 case LINK_RATE_RATE_2:
72 link_rate = "R2";
73 break;
74 case LINK_RATE_RATE_3:
75 link_rate = "R3";
76 break;
77 case LINK_RATE_HIGH:
78 link_rate = "HBR";
79 break;
80 case LINK_RATE_RBR2:
81 link_rate = "RBR2";
82 break;
83 case LINK_RATE_RATE_6:
84 link_rate = "R6";
85 break;
86 case LINK_RATE_HIGH2:
87 link_rate = "HBR2";
88 break;
89 case LINK_RATE_RATE_8:
90 link_rate = "R8";
91 break;
92 case LINK_RATE_HIGH3:
93 link_rate = "HBR3";
94 break;
95 case LINK_RATE_UHBR10:
96 link_rate = "UHBR10";
97 break;
98 case LINK_RATE_UHBR13_5:
99 link_rate = "UHBR13.5";
100 break;
101 case LINK_RATE_UHBR20:
102 link_rate = "UHBR20";
103 break;
104 default:
105 break;
106 }
107
108 switch (status) {
109 case LINK_TRAINING_SUCCESS:
110 lt_result = "pass";
111 break;
112 case LINK_TRAINING_CR_FAIL_LANE0:
113 lt_result = "CR failed lane0";
114 break;
115 case LINK_TRAINING_CR_FAIL_LANE1:
116 lt_result = "CR failed lane1";
117 break;
118 case LINK_TRAINING_CR_FAIL_LANE23:
119 lt_result = "CR failed lane23";
120 break;
121 case LINK_TRAINING_EQ_FAIL_CR:
122 lt_result = "CR failed in EQ";
123 break;
124 case LINK_TRAINING_EQ_FAIL_CR_PARTIAL:
125 lt_result = "CR failed in EQ partially";
126 break;
127 case LINK_TRAINING_EQ_FAIL_EQ:
128 lt_result = "EQ failed";
129 break;
130 case LINK_TRAINING_LQA_FAIL:
131 lt_result = "LQA failed";
132 break;
133 case LINK_TRAINING_LINK_LOSS:
134 lt_result = "Link loss";
135 break;
136 case DP_128b_132b_LT_FAILED:
137 lt_result = "LT_FAILED received";
138 break;
139 case DP_128b_132b_MAX_LOOP_COUNT_REACHED:
140 lt_result = "max loop count reached";
141 break;
142 case DP_128b_132b_CHANNEL_EQ_DONE_TIMEOUT:
143 lt_result = "channel EQ timeout";
144 break;
145 case DP_128b_132b_CDS_DONE_TIMEOUT:
146 lt_result = "CDS timeout";
147 break;
148 default:
149 break;
150 }
151
152 switch (lt_settings->link_settings.link_spread) {
153 case LINK_SPREAD_DISABLED:
154 lt_spread = "Disabled";
155 break;
156 case LINK_SPREAD_05_DOWNSPREAD_30KHZ:
157 lt_spread = "0.5% 30KHz";
158 break;
159 case LINK_SPREAD_05_DOWNSPREAD_33KHZ:
160 lt_spread = "0.5% 33KHz";
161 break;
162 default:
163 break;
164 }
165
166 /* Connectivity log: link training */
167
168 /* TODO - DP2.0 Log: add connectivity log for FFE PRESET */
169
170 CONN_MSG_LT(link, "%sx%d %s VS=%d, PE=%d, DS=%s",
171 link_rate,
172 lt_settings->link_settings.lane_count,
173 lt_result,
174 lt_settings->hw_lane_settings[0].VOLTAGE_SWING,
175 lt_settings->hw_lane_settings[0].PRE_EMPHASIS,
176 lt_spread);
177}
178
179uint8_t dp_initialize_scrambling_data_symbols(
180 struct dc_link *link,
181 enum dc_dp_training_pattern pattern)
182{
183 uint8_t disable_scrabled_data_symbols = 0;
184
185 switch (pattern) {
186 case DP_TRAINING_PATTERN_SEQUENCE_1:
187 case DP_TRAINING_PATTERN_SEQUENCE_2:
188 case DP_TRAINING_PATTERN_SEQUENCE_3:
189 disable_scrabled_data_symbols = 1;
190 break;
191 case DP_TRAINING_PATTERN_SEQUENCE_4:
192 case DP_128b_132b_TPS1:
193 case DP_128b_132b_TPS2:
194 disable_scrabled_data_symbols = 0;
195 break;
196 default:
197 ASSERT(0);
198 DC_LOG_HW_LINK_TRAINING("%s: Invalid HW Training pattern: %d\n",
199 __func__, pattern);
200 break;
201 }
202 return disable_scrabled_data_symbols;
203}
204
205enum dpcd_training_patterns
206 dp_training_pattern_to_dpcd_training_pattern(
207 struct dc_link *link,
208 enum dc_dp_training_pattern pattern)
209{
210 enum dpcd_training_patterns dpcd_tr_pattern =
211 DPCD_TRAINING_PATTERN_VIDEOIDLE;
212
213 switch (pattern) {
214 case DP_TRAINING_PATTERN_SEQUENCE_1:
215 DC_LOG_HW_LINK_TRAINING("%s: Using DP training pattern TPS1\n", __func__);
216 dpcd_tr_pattern = DPCD_TRAINING_PATTERN_1;
217 break;
218 case DP_TRAINING_PATTERN_SEQUENCE_2:
219 DC_LOG_HW_LINK_TRAINING("%s: Using DP training pattern TPS2\n", __func__);
220 dpcd_tr_pattern = DPCD_TRAINING_PATTERN_2;
221 break;
222 case DP_TRAINING_PATTERN_SEQUENCE_3:
223 DC_LOG_HW_LINK_TRAINING("%s: Using DP training pattern TPS3\n", __func__);
224 dpcd_tr_pattern = DPCD_TRAINING_PATTERN_3;
225 break;
226 case DP_TRAINING_PATTERN_SEQUENCE_4:
227 DC_LOG_HW_LINK_TRAINING("%s: Using DP training pattern TPS4\n", __func__);
228 dpcd_tr_pattern = DPCD_TRAINING_PATTERN_4;
229 break;
230 case DP_128b_132b_TPS1:
231 DC_LOG_HW_LINK_TRAINING("%s: Using DP 128b/132b training pattern TPS1\n", __func__);
232 dpcd_tr_pattern = DPCD_128b_132b_TPS1;
233 break;
234 case DP_128b_132b_TPS2:
235 DC_LOG_HW_LINK_TRAINING("%s: Using DP 128b/132b training pattern TPS2\n", __func__);
236 dpcd_tr_pattern = DPCD_128b_132b_TPS2;
237 break;
238 case DP_128b_132b_TPS2_CDS:
239 DC_LOG_HW_LINK_TRAINING("%s: Using DP 128b/132b training pattern TPS2 CDS\n",
240 __func__);
241 dpcd_tr_pattern = DPCD_128b_132b_TPS2_CDS;
242 break;
243 case DP_TRAINING_PATTERN_VIDEOIDLE:
244 DC_LOG_HW_LINK_TRAINING("%s: Using DP training pattern videoidle\n", __func__);
245 dpcd_tr_pattern = DPCD_TRAINING_PATTERN_VIDEOIDLE;
246 break;
247 default:
248 ASSERT(0);
249 DC_LOG_HW_LINK_TRAINING("%s: Invalid HW Training pattern: %d\n",
250 __func__, pattern);
251 break;
252 }
253
254 return dpcd_tr_pattern;
255}
256
257uint8_t dp_get_nibble_at_index(const uint8_t *buf,
258 uint32_t index)
259{
260 uint8_t nibble;
261 nibble = buf[index / 2];
262
263 if (index % 2)
264 nibble >>= 4;
265 else
266 nibble &= 0x0F;
267
268 return nibble;
269}
270
271void dp_wait_for_training_aux_rd_interval(
272 struct dc_link *link,
273 uint32_t wait_in_micro_secs)
274{
275 fsleep(usecs: wait_in_micro_secs);
276
277 DC_LOG_HW_LINK_TRAINING("%s:\n wait = %d\n",
278 __func__,
279 wait_in_micro_secs);
280}
281
282/* maximum pre emphasis level allowed for each voltage swing level*/
283static const enum dc_pre_emphasis voltage_swing_to_pre_emphasis[] = {
284 PRE_EMPHASIS_LEVEL3,
285 PRE_EMPHASIS_LEVEL2,
286 PRE_EMPHASIS_LEVEL1,
287 PRE_EMPHASIS_DISABLED };
288
289static enum dc_pre_emphasis get_max_pre_emphasis_for_voltage_swing(
290 enum dc_voltage_swing voltage)
291{
292 enum dc_pre_emphasis pre_emphasis;
293 pre_emphasis = PRE_EMPHASIS_MAX_LEVEL;
294
295 if (voltage <= VOLTAGE_SWING_MAX_LEVEL)
296 pre_emphasis = voltage_swing_to_pre_emphasis[voltage];
297
298 return pre_emphasis;
299
300}
301
302static void maximize_lane_settings(const struct link_training_settings *lt_settings,
303 struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX])
304{
305 uint32_t lane;
306 struct dc_lane_settings max_requested;
307
308 max_requested.VOLTAGE_SWING = lane_settings[0].VOLTAGE_SWING;
309 max_requested.PRE_EMPHASIS = lane_settings[0].PRE_EMPHASIS;
310 max_requested.FFE_PRESET = lane_settings[0].FFE_PRESET;
311
312 /* Determine what the maximum of the requested settings are*/
313 for (lane = 1; lane < lt_settings->link_settings.lane_count; lane++) {
314 if (lane_settings[lane].VOLTAGE_SWING > max_requested.VOLTAGE_SWING)
315 max_requested.VOLTAGE_SWING = lane_settings[lane].VOLTAGE_SWING;
316
317 if (lane_settings[lane].PRE_EMPHASIS > max_requested.PRE_EMPHASIS)
318 max_requested.PRE_EMPHASIS = lane_settings[lane].PRE_EMPHASIS;
319 if (lane_settings[lane].FFE_PRESET.settings.level >
320 max_requested.FFE_PRESET.settings.level)
321 max_requested.FFE_PRESET.settings.level =
322 lane_settings[lane].FFE_PRESET.settings.level;
323 }
324
325 /* make sure the requested settings are
326 * not higher than maximum settings*/
327 if (max_requested.VOLTAGE_SWING > VOLTAGE_SWING_MAX_LEVEL)
328 max_requested.VOLTAGE_SWING = VOLTAGE_SWING_MAX_LEVEL;
329
330 if (max_requested.PRE_EMPHASIS > PRE_EMPHASIS_MAX_LEVEL)
331 max_requested.PRE_EMPHASIS = PRE_EMPHASIS_MAX_LEVEL;
332 if (max_requested.FFE_PRESET.settings.level > DP_FFE_PRESET_MAX_LEVEL)
333 max_requested.FFE_PRESET.settings.level = DP_FFE_PRESET_MAX_LEVEL;
334
335 /* make sure the pre-emphasis matches the voltage swing*/
336 if (max_requested.PRE_EMPHASIS >
337 get_max_pre_emphasis_for_voltage_swing(
338 voltage: max_requested.VOLTAGE_SWING))
339 max_requested.PRE_EMPHASIS =
340 get_max_pre_emphasis_for_voltage_swing(
341 voltage: max_requested.VOLTAGE_SWING);
342
343 for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
344 lane_settings[lane].VOLTAGE_SWING = max_requested.VOLTAGE_SWING;
345 lane_settings[lane].PRE_EMPHASIS = max_requested.PRE_EMPHASIS;
346 lane_settings[lane].FFE_PRESET = max_requested.FFE_PRESET;
347 }
348}
349
350void dp_hw_to_dpcd_lane_settings(
351 const struct link_training_settings *lt_settings,
352 const struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX],
353 union dpcd_training_lane dpcd_lane_settings[LANE_COUNT_DP_MAX])
354{
355 uint8_t lane = 0;
356
357 for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
358 if (link_dp_get_encoding_format(link_settings: &lt_settings->link_settings) ==
359 DP_8b_10b_ENCODING) {
360 dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET =
361 (uint8_t)(hw_lane_settings[lane].VOLTAGE_SWING);
362 dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET =
363 (uint8_t)(hw_lane_settings[lane].PRE_EMPHASIS);
364 dpcd_lane_settings[lane].bits.MAX_SWING_REACHED =
365 (hw_lane_settings[lane].VOLTAGE_SWING ==
366 VOLTAGE_SWING_MAX_LEVEL ? 1 : 0);
367 dpcd_lane_settings[lane].bits.MAX_PRE_EMPHASIS_REACHED =
368 (hw_lane_settings[lane].PRE_EMPHASIS ==
369 PRE_EMPHASIS_MAX_LEVEL ? 1 : 0);
370 } else if (link_dp_get_encoding_format(link_settings: &lt_settings->link_settings) ==
371 DP_128b_132b_ENCODING) {
372 dpcd_lane_settings[lane].tx_ffe.PRESET_VALUE =
373 hw_lane_settings[lane].FFE_PRESET.settings.level;
374 }
375 }
376}
377
378uint8_t get_dpcd_link_rate(const struct dc_link_settings *link_settings)
379{
380 uint8_t link_rate = 0;
381 enum dp_link_encoding encoding = link_dp_get_encoding_format(link_settings);
382
383 if (encoding == DP_128b_132b_ENCODING)
384 switch (link_settings->link_rate) {
385 case LINK_RATE_UHBR10:
386 link_rate = 0x1;
387 break;
388 case LINK_RATE_UHBR20:
389 link_rate = 0x2;
390 break;
391 case LINK_RATE_UHBR13_5:
392 link_rate = 0x4;
393 break;
394 default:
395 link_rate = 0;
396 break;
397 }
398 else if (encoding == DP_8b_10b_ENCODING)
399 link_rate = (uint8_t) link_settings->link_rate;
400 else
401 link_rate = 0;
402
403 return link_rate;
404}
405
406/* Only used for channel equalization */
407uint32_t dp_translate_training_aux_read_interval(uint32_t dpcd_aux_read_interval)
408{
409 unsigned int aux_rd_interval_us = 400;
410
411 switch (dpcd_aux_read_interval) {
412 case 0x01:
413 aux_rd_interval_us = 4000;
414 break;
415 case 0x02:
416 aux_rd_interval_us = 8000;
417 break;
418 case 0x03:
419 aux_rd_interval_us = 12000;
420 break;
421 case 0x04:
422 aux_rd_interval_us = 16000;
423 break;
424 case 0x05:
425 aux_rd_interval_us = 32000;
426 break;
427 case 0x06:
428 aux_rd_interval_us = 64000;
429 break;
430 default:
431 break;
432 }
433
434 return aux_rd_interval_us;
435}
436
437enum link_training_result dp_get_cr_failure(enum dc_lane_count ln_count,
438 union lane_status *dpcd_lane_status)
439{
440 enum link_training_result result = LINK_TRAINING_SUCCESS;
441
442 if (ln_count >= LANE_COUNT_ONE && !dpcd_lane_status[0].bits.CR_DONE_0)
443 result = LINK_TRAINING_CR_FAIL_LANE0;
444 else if (ln_count >= LANE_COUNT_TWO && !dpcd_lane_status[1].bits.CR_DONE_0)
445 result = LINK_TRAINING_CR_FAIL_LANE1;
446 else if (ln_count >= LANE_COUNT_FOUR && !dpcd_lane_status[2].bits.CR_DONE_0)
447 result = LINK_TRAINING_CR_FAIL_LANE23;
448 else if (ln_count >= LANE_COUNT_FOUR && !dpcd_lane_status[3].bits.CR_DONE_0)
449 result = LINK_TRAINING_CR_FAIL_LANE23;
450 return result;
451}
452
453bool is_repeater(const struct link_training_settings *lt_settings, uint32_t offset)
454{
455 return (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) && (offset != 0);
456}
457
458bool dp_is_max_vs_reached(
459 const struct link_training_settings *lt_settings)
460{
461 uint32_t lane;
462 for (lane = 0; lane <
463 (uint32_t)(lt_settings->link_settings.lane_count);
464 lane++) {
465 if (lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET
466 == VOLTAGE_SWING_MAX_LEVEL)
467 return true;
468 }
469 return false;
470
471}
472
473bool dp_is_cr_done(enum dc_lane_count ln_count,
474 union lane_status *dpcd_lane_status)
475{
476 bool done = true;
477 uint32_t lane;
478 /*LANEx_CR_DONE bits All 1's?*/
479 for (lane = 0; lane < (uint32_t)(ln_count); lane++) {
480 if (!dpcd_lane_status[lane].bits.CR_DONE_0)
481 done = false;
482 }
483 return done;
484
485}
486
487bool dp_is_ch_eq_done(enum dc_lane_count ln_count,
488 union lane_status *dpcd_lane_status)
489{
490 bool done = true;
491 uint32_t lane;
492 for (lane = 0; lane < (uint32_t)(ln_count); lane++)
493 if (!dpcd_lane_status[lane].bits.CHANNEL_EQ_DONE_0)
494 done = false;
495 return done;
496}
497
498bool dp_is_symbol_locked(enum dc_lane_count ln_count,
499 union lane_status *dpcd_lane_status)
500{
501 bool locked = true;
502 uint32_t lane;
503 for (lane = 0; lane < (uint32_t)(ln_count); lane++)
504 if (!dpcd_lane_status[lane].bits.SYMBOL_LOCKED_0)
505 locked = false;
506 return locked;
507}
508
509bool dp_is_interlane_aligned(union lane_align_status_updated align_status)
510{
511 return align_status.bits.INTERLANE_ALIGN_DONE == 1;
512}
513
514enum link_training_result dp_check_link_loss_status(
515 struct dc_link *link,
516 const struct link_training_settings *link_training_setting)
517{
518 enum link_training_result status = LINK_TRAINING_SUCCESS;
519 union lane_status lane_status;
520 union lane_align_status_updated dpcd_lane_status_updated;
521 uint8_t dpcd_buf[6] = {0};
522 uint32_t lane;
523
524 core_link_read_dpcd(
525 link,
526 DP_SINK_COUNT,
527 data: (uint8_t *)(dpcd_buf),
528 size: sizeof(dpcd_buf));
529
530 /*parse lane status*/
531 for (lane = 0; lane < link->cur_link_settings.lane_count; lane++) {
532 /*
533 * check lanes status
534 */
535 lane_status.raw = dp_get_nibble_at_index(buf: &dpcd_buf[2], index: lane);
536 dpcd_lane_status_updated.raw = dpcd_buf[4];
537
538 if (!lane_status.bits.CHANNEL_EQ_DONE_0 ||
539 !lane_status.bits.CR_DONE_0 ||
540 !lane_status.bits.SYMBOL_LOCKED_0 ||
541 !dp_is_interlane_aligned(align_status: dpcd_lane_status_updated)) {
542 /* if one of the channel equalization, clock
543 * recovery or symbol lock is dropped
544 * consider it as (link has been
545 * dropped) dp sink status has changed
546 */
547 status = LINK_TRAINING_LINK_LOSS;
548 break;
549 }
550 }
551
552 return status;
553}
554
555enum dc_status dp_get_lane_status_and_lane_adjust(
556 struct dc_link *link,
557 const struct link_training_settings *link_training_setting,
558 union lane_status ln_status[LANE_COUNT_DP_MAX],
559 union lane_align_status_updated *ln_align,
560 union lane_adjust ln_adjust[LANE_COUNT_DP_MAX],
561 uint32_t offset)
562{
563 unsigned int lane01_status_address = DP_LANE0_1_STATUS;
564 uint8_t lane_adjust_offset = 4;
565 unsigned int lane01_adjust_address;
566 uint8_t dpcd_buf[6] = {0};
567 uint32_t lane;
568 enum dc_status status;
569
570 if (is_repeater(lt_settings: link_training_setting, offset)) {
571 lane01_status_address =
572 DP_LANE0_1_STATUS_PHY_REPEATER1 +
573 ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
574 lane_adjust_offset = 3;
575 }
576
577 status = core_link_read_dpcd(
578 link,
579 address: lane01_status_address,
580 data: (uint8_t *)(dpcd_buf),
581 size: sizeof(dpcd_buf));
582
583 if (status != DC_OK) {
584 DC_LOG_HW_LINK_TRAINING("%s:\n Failed to read from address 0x%X,"
585 " keep current lane status and lane adjust unchanged",
586 __func__,
587 lane01_status_address);
588 return status;
589 }
590
591 for (lane = 0; lane <
592 (uint32_t)(link_training_setting->link_settings.lane_count);
593 lane++) {
594
595 ln_status[lane].raw =
596 dp_get_nibble_at_index(buf: &dpcd_buf[0], index: lane);
597 ln_adjust[lane].raw =
598 dp_get_nibble_at_index(buf: &dpcd_buf[lane_adjust_offset], index: lane);
599 }
600
601 ln_align->raw = dpcd_buf[2];
602
603 if (is_repeater(lt_settings: link_training_setting, offset)) {
604 DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n"
605 " 0x%X Lane01Status = %x\n 0x%X Lane23Status = %x\n ",
606 __func__,
607 offset,
608 lane01_status_address, dpcd_buf[0],
609 lane01_status_address + 1, dpcd_buf[1]);
610
611 lane01_adjust_address = DP_ADJUST_REQUEST_LANE0_1_PHY_REPEATER1 +
612 ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
613
614 DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n"
615 " 0x%X Lane01AdjustRequest = %x\n 0x%X Lane23AdjustRequest = %x\n",
616 __func__,
617 offset,
618 lane01_adjust_address,
619 dpcd_buf[lane_adjust_offset],
620 lane01_adjust_address + 1,
621 dpcd_buf[lane_adjust_offset + 1]);
622 } else {
623 DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X Lane01Status = %x\n 0x%X Lane23Status = %x\n ",
624 __func__,
625 lane01_status_address, dpcd_buf[0],
626 lane01_status_address + 1, dpcd_buf[1]);
627
628 lane01_adjust_address = DP_ADJUST_REQUEST_LANE0_1;
629
630 DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X Lane01AdjustRequest = %x\n 0x%X Lane23AdjustRequest = %x\n",
631 __func__,
632 lane01_adjust_address,
633 dpcd_buf[lane_adjust_offset],
634 lane01_adjust_address + 1,
635 dpcd_buf[lane_adjust_offset + 1]);
636 }
637
638 return status;
639}
640
641static void override_lane_settings(const struct link_training_settings *lt_settings,
642 struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX])
643{
644 uint32_t lane;
645
646 if (lt_settings->voltage_swing == NULL &&
647 lt_settings->pre_emphasis == NULL &&
648 lt_settings->ffe_preset == NULL &&
649 lt_settings->post_cursor2 == NULL)
650
651 return;
652
653 for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
654 if (lt_settings->voltage_swing)
655 lane_settings[lane].VOLTAGE_SWING = *lt_settings->voltage_swing;
656 if (lt_settings->pre_emphasis)
657 lane_settings[lane].PRE_EMPHASIS = *lt_settings->pre_emphasis;
658 if (lt_settings->post_cursor2)
659 lane_settings[lane].POST_CURSOR2 = *lt_settings->post_cursor2;
660 if (lt_settings->ffe_preset)
661 lane_settings[lane].FFE_PRESET = *lt_settings->ffe_preset;
662 }
663}
664
665void dp_get_lttpr_mode_override(struct dc_link *link, enum lttpr_mode *override)
666{
667 if (!dp_is_lttpr_present(link))
668 return;
669
670 if (link->dc->debug.lttpr_mode_override == LTTPR_MODE_TRANSPARENT) {
671 *override = LTTPR_MODE_TRANSPARENT;
672 } else if (link->dc->debug.lttpr_mode_override == LTTPR_MODE_NON_TRANSPARENT) {
673 *override = LTTPR_MODE_NON_TRANSPARENT;
674 } else if (link->dc->debug.lttpr_mode_override == LTTPR_MODE_NON_LTTPR) {
675 *override = LTTPR_MODE_NON_LTTPR;
676 }
677 DC_LOG_DC("lttpr_mode_override chose LTTPR_MODE = %d\n", (uint8_t)(*override));
678}
679
680void override_training_settings(
681 struct dc_link *link,
682 const struct dc_link_training_overrides *overrides,
683 struct link_training_settings *lt_settings)
684{
685 uint32_t lane;
686
687 /* Override link spread */
688 if (!link->dp_ss_off && overrides->downspread != NULL)
689 lt_settings->link_settings.link_spread = *overrides->downspread ?
690 LINK_SPREAD_05_DOWNSPREAD_30KHZ
691 : LINK_SPREAD_DISABLED;
692
693 /* Override lane settings */
694 if (overrides->voltage_swing != NULL)
695 lt_settings->voltage_swing = overrides->voltage_swing;
696 if (overrides->pre_emphasis != NULL)
697 lt_settings->pre_emphasis = overrides->pre_emphasis;
698 if (overrides->post_cursor2 != NULL)
699 lt_settings->post_cursor2 = overrides->post_cursor2;
700 if (overrides->ffe_preset != NULL)
701 lt_settings->ffe_preset = overrides->ffe_preset;
702 /* Override HW lane settings with BIOS forced values if present */
703 if ((link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) &&
704 lt_settings->lttpr_mode == LTTPR_MODE_TRANSPARENT) {
705 lt_settings->voltage_swing = &link->bios_forced_drive_settings.VOLTAGE_SWING;
706 lt_settings->pre_emphasis = &link->bios_forced_drive_settings.PRE_EMPHASIS;
707 lt_settings->always_match_dpcd_with_hw_lane_settings = false;
708 }
709 for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
710 lt_settings->hw_lane_settings[lane].VOLTAGE_SWING =
711 lt_settings->voltage_swing != NULL ?
712 *lt_settings->voltage_swing :
713 VOLTAGE_SWING_LEVEL0;
714 lt_settings->hw_lane_settings[lane].PRE_EMPHASIS =
715 lt_settings->pre_emphasis != NULL ?
716 *lt_settings->pre_emphasis
717 : PRE_EMPHASIS_DISABLED;
718 lt_settings->hw_lane_settings[lane].POST_CURSOR2 =
719 lt_settings->post_cursor2 != NULL ?
720 *lt_settings->post_cursor2
721 : POST_CURSOR2_DISABLED;
722 }
723
724 if (lt_settings->always_match_dpcd_with_hw_lane_settings)
725 dp_hw_to_dpcd_lane_settings(lt_settings,
726 hw_lane_settings: lt_settings->hw_lane_settings, dpcd_lane_settings: lt_settings->dpcd_lane_settings);
727
728 /* Override training timings */
729 if (overrides->cr_pattern_time != NULL)
730 lt_settings->cr_pattern_time = *overrides->cr_pattern_time;
731 if (overrides->eq_pattern_time != NULL)
732 lt_settings->eq_pattern_time = *overrides->eq_pattern_time;
733 if (overrides->pattern_for_cr != NULL)
734 lt_settings->pattern_for_cr = *overrides->pattern_for_cr;
735 if (overrides->pattern_for_eq != NULL)
736 lt_settings->pattern_for_eq = *overrides->pattern_for_eq;
737 if (overrides->enhanced_framing != NULL)
738 lt_settings->enhanced_framing = *overrides->enhanced_framing;
739 if (link->preferred_training_settings.fec_enable != NULL)
740 lt_settings->should_set_fec_ready = *link->preferred_training_settings.fec_enable;
741
742 /* Check DP tunnel LTTPR mode debug option. */
743 if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA && link->dc->debug.dpia_debug.bits.force_non_lttpr)
744 lt_settings->lttpr_mode = LTTPR_MODE_NON_LTTPR;
745
746 dp_get_lttpr_mode_override(link, override: &lt_settings->lttpr_mode);
747
748}
749
750enum dc_dp_training_pattern decide_cr_training_pattern(
751 const struct dc_link_settings *link_settings)
752{
753 switch (link_dp_get_encoding_format(link_settings)) {
754 case DP_8b_10b_ENCODING:
755 default:
756 return DP_TRAINING_PATTERN_SEQUENCE_1;
757 case DP_128b_132b_ENCODING:
758 return DP_128b_132b_TPS1;
759 }
760}
761
762enum dc_dp_training_pattern decide_eq_training_pattern(struct dc_link *link,
763 const struct dc_link_settings *link_settings)
764{
765 struct link_encoder *link_enc;
766 struct encoder_feature_support *enc_caps;
767 struct dpcd_caps *rx_caps = &link->dpcd_caps;
768 enum dc_dp_training_pattern pattern = DP_TRAINING_PATTERN_SEQUENCE_2;
769
770 link_enc = link_enc_cfg_get_link_enc(link);
771 ASSERT(link_enc);
772 enc_caps = &link_enc->features;
773
774 switch (link_dp_get_encoding_format(link_settings)) {
775 case DP_8b_10b_ENCODING:
776 if (enc_caps->flags.bits.IS_TPS4_CAPABLE &&
777 rx_caps->max_down_spread.bits.TPS4_SUPPORTED)
778 pattern = DP_TRAINING_PATTERN_SEQUENCE_4;
779 else if (enc_caps->flags.bits.IS_TPS3_CAPABLE &&
780 rx_caps->max_ln_count.bits.TPS3_SUPPORTED)
781 pattern = DP_TRAINING_PATTERN_SEQUENCE_3;
782 else
783 pattern = DP_TRAINING_PATTERN_SEQUENCE_2;
784 break;
785 case DP_128b_132b_ENCODING:
786 pattern = DP_128b_132b_TPS2;
787 break;
788 default:
789 pattern = DP_TRAINING_PATTERN_SEQUENCE_2;
790 break;
791 }
792 return pattern;
793}
794
795enum lttpr_mode dp_decide_lttpr_mode(struct dc_link *link,
796 struct dc_link_settings *link_setting)
797{
798 enum dp_link_encoding encoding = link_dp_get_encoding_format(link_settings: link_setting);
799
800 if (encoding == DP_8b_10b_ENCODING)
801 return dp_decide_8b_10b_lttpr_mode(link);
802 else if (encoding == DP_128b_132b_ENCODING)
803 return dp_decide_128b_132b_lttpr_mode(link);
804
805 ASSERT(0);
806 return LTTPR_MODE_NON_LTTPR;
807}
808
809void dp_decide_lane_settings(
810 const struct link_training_settings *lt_settings,
811 const union lane_adjust ln_adjust[LANE_COUNT_DP_MAX],
812 struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX],
813 union dpcd_training_lane *dpcd_lane_settings)
814{
815 uint32_t lane;
816
817 for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
818 if (link_dp_get_encoding_format(link_settings: &lt_settings->link_settings) ==
819 DP_8b_10b_ENCODING) {
820 hw_lane_settings[lane].VOLTAGE_SWING =
821 (enum dc_voltage_swing)(ln_adjust[lane].bits.
822 VOLTAGE_SWING_LANE);
823 hw_lane_settings[lane].PRE_EMPHASIS =
824 (enum dc_pre_emphasis)(ln_adjust[lane].bits.
825 PRE_EMPHASIS_LANE);
826 } else if (link_dp_get_encoding_format(link_settings: &lt_settings->link_settings) ==
827 DP_128b_132b_ENCODING) {
828 hw_lane_settings[lane].FFE_PRESET.raw =
829 ln_adjust[lane].tx_ffe.PRESET_VALUE;
830 }
831 }
832 dp_hw_to_dpcd_lane_settings(lt_settings, hw_lane_settings, dpcd_lane_settings);
833
834 if (lt_settings->disallow_per_lane_settings) {
835 /* we find the maximum of the requested settings across all lanes*/
836 /* and set this maximum for all lanes*/
837 maximize_lane_settings(lt_settings, lane_settings: hw_lane_settings);
838 override_lane_settings(lt_settings, lane_settings: hw_lane_settings);
839
840 if (lt_settings->always_match_dpcd_with_hw_lane_settings)
841 dp_hw_to_dpcd_lane_settings(lt_settings, hw_lane_settings, dpcd_lane_settings);
842 }
843
844}
845
846void dp_decide_training_settings(
847 struct dc_link *link,
848 const struct dc_link_settings *link_settings,
849 struct link_training_settings *lt_settings)
850{
851 if (link_dp_get_encoding_format(link_settings) == DP_8b_10b_ENCODING)
852 decide_8b_10b_training_settings(link, link_setting: link_settings, lt_settings);
853 else if (link_dp_get_encoding_format(link_settings) == DP_128b_132b_ENCODING)
854 decide_128b_132b_training_settings(link, link_settings, lt_settings);
855}
856
857
858enum dc_status configure_lttpr_mode_transparent(struct dc_link *link)
859{
860 uint8_t repeater_mode = DP_PHY_REPEATER_MODE_TRANSPARENT;
861
862 DC_LOG_HW_LINK_TRAINING("%s\n Set LTTPR to Transparent Mode\n", __func__);
863 return core_link_write_dpcd(link,
864 DP_PHY_REPEATER_MODE,
865 data: (uint8_t *)&repeater_mode,
866 size: sizeof(repeater_mode));
867}
868
869static enum dc_status configure_lttpr_mode_non_transparent(
870 struct dc_link *link,
871 const struct link_training_settings *lt_settings)
872{
873 /* aux timeout is already set to extended */
874 /* RESET/SET lttpr mode to enable non transparent mode */
875 uint8_t repeater_cnt;
876 uint32_t aux_interval_address;
877 uint8_t repeater_id;
878 enum dc_status result = DC_ERROR_UNEXPECTED;
879 uint8_t repeater_mode = DP_PHY_REPEATER_MODE_TRANSPARENT;
880 const struct dc *dc = link->dc;
881
882 enum dp_link_encoding encoding = dc->link_srv->dp_get_encoding_format(&lt_settings->link_settings);
883
884 if (encoding == DP_8b_10b_ENCODING) {
885 DC_LOG_HW_LINK_TRAINING("%s\n Set LTTPR to Transparent Mode\n", __func__);
886 result = core_link_write_dpcd(link,
887 DP_PHY_REPEATER_MODE,
888 data: (uint8_t *)&repeater_mode,
889 size: sizeof(repeater_mode));
890
891 }
892
893 if (result == DC_OK) {
894 link->dpcd_caps.lttpr_caps.mode = repeater_mode;
895 }
896
897 if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) {
898
899 DC_LOG_HW_LINK_TRAINING("%s\n Set LTTPR to Non Transparent Mode\n", __func__);
900
901 repeater_mode = DP_PHY_REPEATER_MODE_NON_TRANSPARENT;
902 result = core_link_write_dpcd(link,
903 DP_PHY_REPEATER_MODE,
904 data: (uint8_t *)&repeater_mode,
905 size: sizeof(repeater_mode));
906
907 if (result == DC_OK) {
908 link->dpcd_caps.lttpr_caps.mode = repeater_mode;
909 }
910
911 if (encoding == DP_8b_10b_ENCODING) {
912 repeater_cnt = dp_parse_lttpr_repeater_count(lttpr_repeater_count: link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
913
914 /* Driver does not need to train the first hop. Skip DPCD read and clear
915 * AUX_RD_INTERVAL for DPTX-to-DPIA hop.
916 */
917 if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA)
918 link->dpcd_caps.lttpr_caps.aux_rd_interval[--repeater_cnt] = 0;
919
920 for (repeater_id = repeater_cnt; repeater_id > 0; repeater_id--) {
921 aux_interval_address = DP_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER1 +
922 ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (repeater_id - 1));
923 core_link_read_dpcd(
924 link,
925 address: aux_interval_address,
926 data: (uint8_t *)&link->dpcd_caps.lttpr_caps.aux_rd_interval[repeater_id - 1],
927 size: sizeof(link->dpcd_caps.lttpr_caps.aux_rd_interval[repeater_id - 1]));
928 link->dpcd_caps.lttpr_caps.aux_rd_interval[repeater_id - 1] &= 0x7F;
929 }
930 }
931 }
932
933 return result;
934}
935
936enum dc_status dpcd_configure_lttpr_mode(struct dc_link *link, struct link_training_settings *lt_settings)
937{
938 enum dc_status status = DC_OK;
939
940 if (lt_settings->lttpr_mode == LTTPR_MODE_TRANSPARENT)
941 status = configure_lttpr_mode_transparent(link);
942
943 else if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT)
944 status = configure_lttpr_mode_non_transparent(link, lt_settings);
945
946 return status;
947}
948
949void repeater_training_done(struct dc_link *link, uint32_t offset)
950{
951 union dpcd_training_pattern dpcd_pattern = {0};
952
953 const uint32_t dpcd_base_lt_offset =
954 DP_TRAINING_PATTERN_SET_PHY_REPEATER1 +
955 ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
956 /* Set training not in progress*/
957 dpcd_pattern.v1_4.TRAINING_PATTERN_SET = DPCD_TRAINING_PATTERN_VIDEOIDLE;
958
959 core_link_write_dpcd(
960 link,
961 address: dpcd_base_lt_offset,
962 data: &dpcd_pattern.raw,
963 size: 1);
964
965 DC_LOG_HW_LINK_TRAINING("%s\n LTTPR Id: %d 0x%X pattern = %x\n",
966 __func__,
967 offset,
968 dpcd_base_lt_offset,
969 dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
970}
971
972static void dpcd_exit_training_mode(struct dc_link *link, enum dp_link_encoding encoding)
973{
974 uint8_t sink_status = 0;
975 uint8_t i;
976
977 /* clear training pattern set */
978 dpcd_set_training_pattern(link, training_pattern: DP_TRAINING_PATTERN_VIDEOIDLE);
979
980 if (encoding == DP_128b_132b_ENCODING) {
981 /* poll for intra-hop disable */
982 for (i = 0; i < 10; i++) {
983 if ((core_link_read_dpcd(link, DP_SINK_STATUS, data: &sink_status, size: 1) == DC_OK) &&
984 (sink_status & DP_INTRA_HOP_AUX_REPLY_INDICATION) == 0)
985 break;
986 fsleep(usecs: 1000);
987 }
988 }
989}
990
991enum dc_status dpcd_configure_channel_coding(struct dc_link *link,
992 struct link_training_settings *lt_settings)
993{
994 enum dp_link_encoding encoding =
995 link_dp_get_encoding_format(
996 link_settings: &lt_settings->link_settings);
997 enum dc_status status;
998
999 status = core_link_write_dpcd(
1000 link,
1001 DP_MAIN_LINK_CHANNEL_CODING_SET,
1002 data: (uint8_t *) &encoding,
1003 size: 1);
1004 DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X MAIN_LINK_CHANNEL_CODING_SET = %x\n",
1005 __func__,
1006 DP_MAIN_LINK_CHANNEL_CODING_SET,
1007 encoding);
1008
1009 return status;
1010}
1011
1012void dpcd_set_training_pattern(
1013 struct dc_link *link,
1014 enum dc_dp_training_pattern training_pattern)
1015{
1016 union dpcd_training_pattern dpcd_pattern = {0};
1017
1018 dpcd_pattern.v1_4.TRAINING_PATTERN_SET =
1019 dp_training_pattern_to_dpcd_training_pattern(
1020 link, pattern: training_pattern);
1021
1022 core_link_write_dpcd(
1023 link,
1024 DP_TRAINING_PATTERN_SET,
1025 data: &dpcd_pattern.raw,
1026 size: 1);
1027
1028 DC_LOG_HW_LINK_TRAINING("%s\n %x pattern = %x\n",
1029 __func__,
1030 DP_TRAINING_PATTERN_SET,
1031 dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
1032}
1033
1034enum dc_status dpcd_set_link_settings(
1035 struct dc_link *link,
1036 const struct link_training_settings *lt_settings)
1037{
1038 uint8_t rate;
1039 enum dc_status status;
1040
1041 union down_spread_ctrl downspread = {0};
1042 union lane_count_set lane_count_set = {0};
1043
1044 downspread.raw = (uint8_t)
1045 (lt_settings->link_settings.link_spread);
1046
1047 lane_count_set.bits.LANE_COUNT_SET =
1048 lt_settings->link_settings.lane_count;
1049
1050 lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing;
1051 lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0;
1052
1053
1054 if (link->ep_type == DISPLAY_ENDPOINT_PHY &&
1055 lt_settings->pattern_for_eq < DP_TRAINING_PATTERN_SEQUENCE_4) {
1056 lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED =
1057 link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED;
1058 }
1059
1060 status = core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL,
1061 data: &downspread.raw, size: sizeof(downspread));
1062
1063 status = core_link_write_dpcd(link, DP_LANE_COUNT_SET,
1064 data: &lane_count_set.raw, size: 1);
1065
1066 if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_13 &&
1067 lt_settings->link_settings.use_link_rate_set == true) {
1068 rate = 0;
1069 /* WA for some MUX chips that will power down with eDP and lose supported
1070 * link rate set for eDP 1.4. Source reads DPCD 0x010 again to ensure
1071 * MUX chip gets link rate set back before link training.
1072 */
1073 if (link->connector_signal == SIGNAL_TYPE_EDP) {
1074 uint8_t supported_link_rates[16];
1075
1076 core_link_read_dpcd(link, DP_SUPPORTED_LINK_RATES,
1077 data: supported_link_rates, size: sizeof(supported_link_rates));
1078 }
1079 status = core_link_write_dpcd(link, DP_LINK_BW_SET, data: &rate, size: 1);
1080 status = core_link_write_dpcd(link, DP_LINK_RATE_SET,
1081 data: &lt_settings->link_settings.link_rate_set, size: 1);
1082 } else {
1083 rate = get_dpcd_link_rate(link_settings: &lt_settings->link_settings);
1084
1085 status = core_link_write_dpcd(link, DP_LINK_BW_SET, data: &rate, size: 1);
1086 }
1087
1088 if (rate) {
1089 DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x framing = %x\n %x spread = %x\n",
1090 __func__,
1091 DP_LINK_BW_SET,
1092 lt_settings->link_settings.link_rate,
1093 DP_LANE_COUNT_SET,
1094 lt_settings->link_settings.lane_count,
1095 lt_settings->enhanced_framing,
1096 DP_DOWNSPREAD_CTRL,
1097 lt_settings->link_settings.link_spread);
1098 } else {
1099 DC_LOG_HW_LINK_TRAINING("%s\n %x rate set = %x\n %x lane = %x framing = %x\n %x spread = %x\n",
1100 __func__,
1101 DP_LINK_RATE_SET,
1102 lt_settings->link_settings.link_rate_set,
1103 DP_LANE_COUNT_SET,
1104 lt_settings->link_settings.lane_count,
1105 lt_settings->enhanced_framing,
1106 DP_DOWNSPREAD_CTRL,
1107 lt_settings->link_settings.link_spread);
1108 }
1109
1110 return status;
1111}
1112
1113enum dc_status dpcd_set_lane_settings(
1114 struct dc_link *link,
1115 const struct link_training_settings *link_training_setting,
1116 uint32_t offset)
1117{
1118 unsigned int lane0_set_address;
1119 enum dc_status status;
1120 lane0_set_address = DP_TRAINING_LANE0_SET;
1121
1122 if (is_repeater(lt_settings: link_training_setting, offset))
1123 lane0_set_address = DP_TRAINING_LANE0_SET_PHY_REPEATER1 +
1124 ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
1125
1126 status = core_link_write_dpcd(link,
1127 address: lane0_set_address,
1128 data: (uint8_t *)(link_training_setting->dpcd_lane_settings),
1129 size: link_training_setting->link_settings.lane_count);
1130
1131 if (is_repeater(lt_settings: link_training_setting, offset)) {
1132 DC_LOG_HW_LINK_TRAINING("%s\n LTTPR Repeater ID: %d\n"
1133 " 0x%X VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n",
1134 __func__,
1135 offset,
1136 lane0_set_address,
1137 link_training_setting->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET,
1138 link_training_setting->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET,
1139 link_training_setting->dpcd_lane_settings[0].bits.MAX_SWING_REACHED,
1140 link_training_setting->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED);
1141
1142 } else {
1143 DC_LOG_HW_LINK_TRAINING("%s\n 0x%X VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n",
1144 __func__,
1145 lane0_set_address,
1146 link_training_setting->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET,
1147 link_training_setting->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET,
1148 link_training_setting->dpcd_lane_settings[0].bits.MAX_SWING_REACHED,
1149 link_training_setting->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED);
1150 }
1151
1152 return status;
1153}
1154
1155void dpcd_set_lt_pattern_and_lane_settings(
1156 struct dc_link *link,
1157 const struct link_training_settings *lt_settings,
1158 enum dc_dp_training_pattern pattern,
1159 uint32_t offset)
1160{
1161 uint32_t dpcd_base_lt_offset;
1162 uint8_t dpcd_lt_buffer[5] = {0};
1163 union dpcd_training_pattern dpcd_pattern = {0};
1164 uint32_t size_in_bytes;
1165 bool edp_workaround = false; /* TODO link_prop.INTERNAL */
1166 dpcd_base_lt_offset = DP_TRAINING_PATTERN_SET;
1167
1168 if (is_repeater(lt_settings, offset))
1169 dpcd_base_lt_offset = DP_TRAINING_PATTERN_SET_PHY_REPEATER1 +
1170 ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
1171
1172 /*****************************************************************
1173 * DpcdAddress_TrainingPatternSet
1174 *****************************************************************/
1175 dpcd_pattern.v1_4.TRAINING_PATTERN_SET =
1176 dp_training_pattern_to_dpcd_training_pattern(link, pattern);
1177
1178 dpcd_pattern.v1_4.SCRAMBLING_DISABLE =
1179 dp_initialize_scrambling_data_symbols(link, pattern);
1180
1181 dpcd_lt_buffer[DP_TRAINING_PATTERN_SET - DP_TRAINING_PATTERN_SET]
1182 = dpcd_pattern.raw;
1183
1184 if (is_repeater(lt_settings, offset)) {
1185 DC_LOG_HW_LINK_TRAINING("%s\n LTTPR Repeater ID: %d\n 0x%X pattern = %x\n",
1186 __func__,
1187 offset,
1188 dpcd_base_lt_offset,
1189 dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
1190 } else {
1191 DC_LOG_HW_LINK_TRAINING("%s\n 0x%X pattern = %x\n",
1192 __func__,
1193 dpcd_base_lt_offset,
1194 dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
1195 }
1196
1197 /* concatenate everything into one buffer*/
1198 size_in_bytes = lt_settings->link_settings.lane_count *
1199 sizeof(lt_settings->dpcd_lane_settings[0]);
1200
1201 // 0x00103 - 0x00102
1202 memmove(
1203 &dpcd_lt_buffer[DP_TRAINING_LANE0_SET - DP_TRAINING_PATTERN_SET],
1204 lt_settings->dpcd_lane_settings,
1205 size_in_bytes);
1206
1207 if (is_repeater(lt_settings, offset)) {
1208 if (link_dp_get_encoding_format(link_settings: &lt_settings->link_settings) ==
1209 DP_128b_132b_ENCODING)
1210 DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n"
1211 " 0x%X TX_FFE_PRESET_VALUE = %x\n",
1212 __func__,
1213 offset,
1214 dpcd_base_lt_offset,
1215 lt_settings->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE);
1216 else if (link_dp_get_encoding_format(link_settings: &lt_settings->link_settings) ==
1217 DP_8b_10b_ENCODING)
1218 DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n"
1219 " 0x%X VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n",
1220 __func__,
1221 offset,
1222 dpcd_base_lt_offset,
1223 lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET,
1224 lt_settings->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET,
1225 lt_settings->dpcd_lane_settings[0].bits.MAX_SWING_REACHED,
1226 lt_settings->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED);
1227 } else {
1228 if (link_dp_get_encoding_format(link_settings: &lt_settings->link_settings) ==
1229 DP_128b_132b_ENCODING)
1230 DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X TX_FFE_PRESET_VALUE = %x\n",
1231 __func__,
1232 dpcd_base_lt_offset,
1233 lt_settings->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE);
1234 else if (link_dp_get_encoding_format(link_settings: &lt_settings->link_settings) ==
1235 DP_8b_10b_ENCODING)
1236 DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n",
1237 __func__,
1238 dpcd_base_lt_offset,
1239 lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET,
1240 lt_settings->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET,
1241 lt_settings->dpcd_lane_settings[0].bits.MAX_SWING_REACHED,
1242 lt_settings->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED);
1243 }
1244 if (edp_workaround) {
1245 /* for eDP write in 2 parts because the 5-byte burst is
1246 * causing issues on some eDP panels (EPR#366724)
1247 */
1248 core_link_write_dpcd(
1249 link,
1250 DP_TRAINING_PATTERN_SET,
1251 data: &dpcd_pattern.raw,
1252 size: sizeof(dpcd_pattern.raw));
1253
1254 core_link_write_dpcd(
1255 link,
1256 DP_TRAINING_LANE0_SET,
1257 data: (uint8_t *)(lt_settings->dpcd_lane_settings),
1258 size: size_in_bytes);
1259
1260 } else if (link_dp_get_encoding_format(link_settings: &lt_settings->link_settings) ==
1261 DP_128b_132b_ENCODING) {
1262 core_link_write_dpcd(
1263 link,
1264 address: dpcd_base_lt_offset,
1265 data: dpcd_lt_buffer,
1266 size: sizeof(dpcd_lt_buffer));
1267 } else
1268 /* write it all in (1 + number-of-lanes)-byte burst*/
1269 core_link_write_dpcd(
1270 link,
1271 address: dpcd_base_lt_offset,
1272 data: dpcd_lt_buffer,
1273 size: size_in_bytes + sizeof(dpcd_pattern.raw));
1274}
1275
1276void start_clock_recovery_pattern_early(struct dc_link *link,
1277 const struct link_resource *link_res,
1278 struct link_training_settings *lt_settings,
1279 uint32_t offset)
1280{
1281 DC_LOG_HW_LINK_TRAINING("%s\n GPU sends TPS1. Wait 400us.\n",
1282 __func__);
1283 dp_set_hw_training_pattern(link, link_res, pattern: lt_settings->pattern_for_cr, offset);
1284 dp_set_hw_lane_settings(link, link_res, link_settings: lt_settings, offset);
1285 udelay(400);
1286}
1287
1288void dp_set_hw_test_pattern(
1289 struct dc_link *link,
1290 const struct link_resource *link_res,
1291 enum dp_test_pattern test_pattern,
1292 uint8_t *custom_pattern,
1293 uint32_t custom_pattern_size)
1294{
1295 const struct link_hwss *link_hwss = get_link_hwss(link, link_res);
1296 struct encoder_set_dp_phy_pattern_param pattern_param = {0};
1297
1298 pattern_param.dp_phy_pattern = test_pattern;
1299 pattern_param.custom_pattern = custom_pattern;
1300 pattern_param.custom_pattern_size = custom_pattern_size;
1301 pattern_param.dp_panel_mode = dp_get_panel_mode(link);
1302
1303 if (link_hwss->ext.set_dp_link_test_pattern)
1304 link_hwss->ext.set_dp_link_test_pattern(link, link_res, &pattern_param);
1305}
1306
1307bool dp_set_hw_training_pattern(
1308 struct dc_link *link,
1309 const struct link_resource *link_res,
1310 enum dc_dp_training_pattern pattern,
1311 uint32_t offset)
1312{
1313 enum dp_test_pattern test_pattern = DP_TEST_PATTERN_UNSUPPORTED;
1314
1315 switch (pattern) {
1316 case DP_TRAINING_PATTERN_SEQUENCE_1:
1317 test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN1;
1318 break;
1319 case DP_TRAINING_PATTERN_SEQUENCE_2:
1320 test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN2;
1321 break;
1322 case DP_TRAINING_PATTERN_SEQUENCE_3:
1323 test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN3;
1324 break;
1325 case DP_TRAINING_PATTERN_SEQUENCE_4:
1326 test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN4;
1327 break;
1328 case DP_128b_132b_TPS1:
1329 test_pattern = DP_TEST_PATTERN_128b_132b_TPS1_TRAINING_MODE;
1330 break;
1331 case DP_128b_132b_TPS2:
1332 test_pattern = DP_TEST_PATTERN_128b_132b_TPS2_TRAINING_MODE;
1333 break;
1334 default:
1335 break;
1336 }
1337
1338 dp_set_hw_test_pattern(link, link_res, test_pattern, NULL, custom_pattern_size: 0);
1339
1340 return true;
1341}
1342
1343static bool perform_post_lt_adj_req_sequence(
1344 struct dc_link *link,
1345 const struct link_resource *link_res,
1346 struct link_training_settings *lt_settings)
1347{
1348 enum dc_lane_count lane_count =
1349 lt_settings->link_settings.lane_count;
1350
1351 uint32_t adj_req_count;
1352 uint32_t adj_req_timer;
1353 bool req_drv_setting_changed;
1354 uint32_t lane;
1355 union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
1356 union lane_align_status_updated dpcd_lane_status_updated = {0};
1357 union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
1358
1359 req_drv_setting_changed = false;
1360 for (adj_req_count = 0; adj_req_count < POST_LT_ADJ_REQ_LIMIT;
1361 adj_req_count++) {
1362
1363 req_drv_setting_changed = false;
1364
1365 for (adj_req_timer = 0;
1366 adj_req_timer < POST_LT_ADJ_REQ_TIMEOUT;
1367 adj_req_timer++) {
1368
1369 dp_get_lane_status_and_lane_adjust(
1370 link,
1371 link_training_setting: lt_settings,
1372 ln_status: dpcd_lane_status,
1373 ln_align: &dpcd_lane_status_updated,
1374 ln_adjust: dpcd_lane_adjust,
1375 offset: DPRX);
1376
1377 if (dpcd_lane_status_updated.bits.
1378 POST_LT_ADJ_REQ_IN_PROGRESS == 0)
1379 return true;
1380
1381 if (!dp_is_cr_done(ln_count: lane_count, dpcd_lane_status))
1382 return false;
1383
1384 if (!dp_is_ch_eq_done(ln_count: lane_count, dpcd_lane_status) ||
1385 !dp_is_symbol_locked(ln_count: lane_count, dpcd_lane_status) ||
1386 !dp_is_interlane_aligned(align_status: dpcd_lane_status_updated))
1387 return false;
1388
1389 for (lane = 0; lane < (uint32_t)(lane_count); lane++) {
1390
1391 if (lt_settings->
1392 dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET !=
1393 dpcd_lane_adjust[lane].bits.VOLTAGE_SWING_LANE ||
1394 lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET !=
1395 dpcd_lane_adjust[lane].bits.PRE_EMPHASIS_LANE) {
1396
1397 req_drv_setting_changed = true;
1398 break;
1399 }
1400 }
1401
1402 if (req_drv_setting_changed) {
1403 dp_decide_lane_settings(lt_settings, ln_adjust: dpcd_lane_adjust,
1404 hw_lane_settings: lt_settings->hw_lane_settings, dpcd_lane_settings: lt_settings->dpcd_lane_settings);
1405
1406 dp_set_drive_settings(link,
1407 link_res,
1408 lt_settings);
1409 break;
1410 }
1411
1412 msleep(msecs: 1);
1413 }
1414
1415 if (!req_drv_setting_changed) {
1416 DC_LOG_WARNING("%s: Post Link Training Adjust Request Timed out\n",
1417 __func__);
1418
1419 ASSERT(0);
1420 return true;
1421 }
1422 }
1423 DC_LOG_WARNING("%s: Post Link Training Adjust Request limit reached\n",
1424 __func__);
1425
1426 ASSERT(0);
1427 return true;
1428
1429}
1430
1431static enum link_training_result dp_transition_to_video_idle(
1432 struct dc_link *link,
1433 const struct link_resource *link_res,
1434 struct link_training_settings *lt_settings,
1435 enum link_training_result status)
1436{
1437 union lane_count_set lane_count_set = {0};
1438
1439 /* 4. mainlink output idle pattern*/
1440 dp_set_hw_test_pattern(link, link_res, test_pattern: DP_TEST_PATTERN_VIDEO_MODE, NULL, custom_pattern_size: 0);
1441
1442 /*
1443 * 5. post training adjust if required
1444 * If the upstream DPTX and downstream DPRX both support TPS4,
1445 * TPS4 must be used instead of POST_LT_ADJ_REQ.
1446 */
1447 if (link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED != 1 ||
1448 lt_settings->pattern_for_eq >= DP_TRAINING_PATTERN_SEQUENCE_4) {
1449 /* delay 5ms after Main Link output idle pattern and then check
1450 * DPCD 0202h.
1451 */
1452 if (link->connector_signal != SIGNAL_TYPE_EDP && status == LINK_TRAINING_SUCCESS) {
1453 msleep(msecs: 5);
1454 status = dp_check_link_loss_status(link, link_training_setting: lt_settings);
1455 }
1456 return status;
1457 }
1458
1459 if (status == LINK_TRAINING_SUCCESS &&
1460 perform_post_lt_adj_req_sequence(link, link_res, lt_settings) == false)
1461 status = LINK_TRAINING_LQA_FAIL;
1462
1463 lane_count_set.bits.LANE_COUNT_SET = lt_settings->link_settings.lane_count;
1464 lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing;
1465 lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0;
1466
1467 core_link_write_dpcd(
1468 link,
1469 DP_LANE_COUNT_SET,
1470 data: &lane_count_set.raw,
1471 size: sizeof(lane_count_set));
1472
1473 return status;
1474}
1475
1476enum link_training_result dp_perform_link_training(
1477 struct dc_link *link,
1478 const struct link_resource *link_res,
1479 const struct dc_link_settings *link_settings,
1480 bool skip_video_pattern)
1481{
1482 enum link_training_result status = LINK_TRAINING_SUCCESS;
1483 struct link_training_settings lt_settings = {0};
1484 enum dp_link_encoding encoding =
1485 link_dp_get_encoding_format(link_settings);
1486
1487 /* decide training settings */
1488 dp_decide_training_settings(
1489 link,
1490 link_settings,
1491 lt_settings: &lt_settings);
1492
1493 override_training_settings(
1494 link,
1495 overrides: &link->preferred_training_settings,
1496 lt_settings: &lt_settings);
1497
1498 /* reset previous training states */
1499 dpcd_exit_training_mode(link, encoding);
1500
1501 /* configure link prior to entering training mode */
1502 dpcd_configure_lttpr_mode(link, lt_settings: &lt_settings);
1503 dp_set_fec_ready(link, link_res, ready: lt_settings.should_set_fec_ready);
1504 dpcd_configure_channel_coding(link, lt_settings: &lt_settings);
1505
1506 /* enter training mode:
1507 * Per DP specs starting from here, DPTX device shall not issue
1508 * Non-LT AUX transactions inside training mode.
1509 */
1510 if ((link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) && encoding == DP_8b_10b_ENCODING)
1511 status = dp_perform_fixed_vs_pe_training_sequence(link, link_res, lt_settings: &lt_settings);
1512 else if (encoding == DP_8b_10b_ENCODING)
1513 status = dp_perform_8b_10b_link_training(link, link_res, lt_settings: &lt_settings);
1514 else if (encoding == DP_128b_132b_ENCODING)
1515 status = dp_perform_128b_132b_link_training(link, link_res, lt_settings: &lt_settings);
1516 else
1517 ASSERT(0);
1518
1519 /* exit training mode */
1520 dpcd_exit_training_mode(link, encoding);
1521
1522 /* switch to video idle */
1523 if ((status == LINK_TRAINING_SUCCESS) || !skip_video_pattern)
1524 status = dp_transition_to_video_idle(link,
1525 link_res,
1526 lt_settings: &lt_settings,
1527 status);
1528
1529 /* dump debug data */
1530 dp_log_training_result(link, lt_settings: &lt_settings, status);
1531 if (status != LINK_TRAINING_SUCCESS)
1532 link->ctx->dc->debug_data.ltFailCount++;
1533 return status;
1534}
1535
1536bool perform_link_training_with_retries(
1537 const struct dc_link_settings *link_setting,
1538 bool skip_video_pattern,
1539 int attempts,
1540 struct pipe_ctx *pipe_ctx,
1541 enum signal_type signal,
1542 bool do_fallback)
1543{
1544 int j;
1545 uint8_t delay_between_attempts = LINK_TRAINING_RETRY_DELAY;
1546 struct dc_stream_state *stream = pipe_ctx->stream;
1547 struct dc_link *link = stream->link;
1548 enum dp_panel_mode panel_mode = dp_get_panel_mode(link);
1549 enum link_training_result status = LINK_TRAINING_CR_FAIL_LANE0;
1550 struct dc_link_settings cur_link_settings = *link_setting;
1551 struct dc_link_settings max_link_settings = *link_setting;
1552 const struct link_hwss *link_hwss = get_link_hwss(link, link_res: &pipe_ctx->link_res);
1553 int fail_count = 0;
1554 bool is_link_bw_low = false; /* link bandwidth < stream bandwidth */
1555 bool is_link_bw_min = /* RBR x 1 */
1556 (cur_link_settings.link_rate <= LINK_RATE_LOW) &&
1557 (cur_link_settings.lane_count <= LANE_COUNT_ONE);
1558
1559 dp_trace_commit_lt_init(link);
1560
1561
1562 if (link_dp_get_encoding_format(link_settings: &cur_link_settings) == DP_8b_10b_ENCODING)
1563 /* We need to do this before the link training to ensure the idle
1564 * pattern in SST mode will be sent right after the link training
1565 */
1566 link_hwss->setup_stream_encoder(pipe_ctx);
1567
1568 dp_trace_set_lt_start_timestamp(link, in_detection: false);
1569 j = 0;
1570 while (j < attempts && fail_count < (attempts * 10)) {
1571
1572 DC_LOG_HW_LINK_TRAINING("%s: Beginning link(%d) training attempt %u of %d @ rate(%d) x lane(%d) @ spread = %x\n",
1573 __func__, link->link_index, (unsigned int)j + 1, attempts,
1574 cur_link_settings.link_rate, cur_link_settings.lane_count,
1575 cur_link_settings.link_spread);
1576
1577 dp_enable_link_phy(
1578 link,
1579 link_res: &pipe_ctx->link_res,
1580 signal,
1581 clock_source: pipe_ctx->clock_source->id,
1582 link_settings: &cur_link_settings);
1583
1584 if (stream->sink_patches.dppowerup_delay > 0) {
1585 int delay_dp_power_up_in_ms = stream->sink_patches.dppowerup_delay;
1586
1587 msleep(msecs: delay_dp_power_up_in_ms);
1588 }
1589
1590 if (panel_mode == DP_PANEL_MODE_EDP) {
1591 struct cp_psp *cp_psp = &stream->ctx->cp_psp;
1592
1593 if (cp_psp && cp_psp->funcs.enable_assr) {
1594 /* ASSR is bound to fail with unsigned PSP
1595 * verstage used during devlopment phase.
1596 * Report and continue with eDP panel mode to
1597 * perform eDP link training with right settings
1598 */
1599 bool result;
1600 result = cp_psp->funcs.enable_assr(cp_psp->handle, link);
1601 if (!result && link->panel_mode != DP_PANEL_MODE_EDP)
1602 panel_mode = DP_PANEL_MODE_DEFAULT;
1603 }
1604 }
1605
1606 dp_set_panel_mode(link, panel_mode);
1607
1608 if (link->aux_access_disabled) {
1609 dp_perform_link_training_skip_aux(link, link_res: &pipe_ctx->link_res, link_setting: &cur_link_settings);
1610 return true;
1611 } else {
1612 /** @todo Consolidate USB4 DP and DPx.x training. */
1613 if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) {
1614 status = dpia_perform_link_training(
1615 link,
1616 link_res: &pipe_ctx->link_res,
1617 link_setting: &cur_link_settings,
1618 skip_video_pattern);
1619
1620 /* Transmit idle pattern once training successful. */
1621 if (status == LINK_TRAINING_SUCCESS && !is_link_bw_low) {
1622 dp_set_hw_test_pattern(link, link_res: &pipe_ctx->link_res, test_pattern: DP_TEST_PATTERN_VIDEO_MODE, NULL, custom_pattern_size: 0);
1623 // Update verified link settings to current one
1624 // Because DPIA LT might fallback to lower link setting.
1625 if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
1626 link->verified_link_cap.link_rate = link->cur_link_settings.link_rate;
1627 link->verified_link_cap.lane_count = link->cur_link_settings.lane_count;
1628 dm_helpers_dp_mst_update_branch_bandwidth(ctx: link->ctx, link);
1629 }
1630 }
1631 } else {
1632 status = dp_perform_link_training(
1633 link,
1634 link_res: &pipe_ctx->link_res,
1635 link_settings: &cur_link_settings,
1636 skip_video_pattern);
1637 }
1638
1639 dp_trace_lt_total_count_increment(link, in_detection: false);
1640 dp_trace_lt_result_update(link, result: status, in_detection: false);
1641 dp_trace_set_lt_end_timestamp(link, in_detection: false);
1642 if (status == LINK_TRAINING_SUCCESS && !is_link_bw_low)
1643 return true;
1644 }
1645
1646 fail_count++;
1647 dp_trace_lt_fail_count_update(link, fail_count, in_detection: false);
1648 if (link->ep_type == DISPLAY_ENDPOINT_PHY) {
1649 /* latest link training still fail or link training is aborted
1650 * skip delay and keep PHY on
1651 */
1652 if (j == (attempts - 1) || (status == LINK_TRAINING_ABORT))
1653 break;
1654 }
1655
1656 if (j == (attempts - 1)) {
1657 DC_LOG_WARNING(
1658 "%s: Link(%d) training attempt %u of %d failed @ rate(%d) x lane(%d) @ spread = %x : fail reason:(%d)\n",
1659 __func__, link->link_index, (unsigned int)j + 1, attempts,
1660 cur_link_settings.link_rate, cur_link_settings.lane_count,
1661 cur_link_settings.link_spread, status);
1662 } else {
1663 DC_LOG_HW_LINK_TRAINING(
1664 "%s: Link(%d) training attempt %u of %d failed @ rate(%d) x lane(%d) @ spread = %x : fail reason:(%d)\n",
1665 __func__, link->link_index, (unsigned int)j + 1, attempts,
1666 cur_link_settings.link_rate, cur_link_settings.lane_count,
1667 cur_link_settings.link_spread, status);
1668 }
1669
1670 dp_disable_link_phy(link, link_res: &pipe_ctx->link_res, signal);
1671
1672 /* Abort link training if failure due to sink being unplugged. */
1673 if (status == LINK_TRAINING_ABORT) {
1674 enum dc_connection_type type = dc_connection_none;
1675
1676 link_detect_connection_type(link, type: &type);
1677 if (type == dc_connection_none) {
1678 DC_LOG_HW_LINK_TRAINING("%s: Aborting training because sink unplugged\n", __func__);
1679 break;
1680 }
1681 }
1682
1683 /* Try to train again at original settings if:
1684 * - not falling back between training attempts;
1685 * - aborted previous attempt due to reasons other than sink unplug;
1686 * - successfully trained but at a link rate lower than that required by stream;
1687 * - reached minimum link bandwidth.
1688 */
1689 if (!do_fallback || (status == LINK_TRAINING_ABORT) ||
1690 (status == LINK_TRAINING_SUCCESS && is_link_bw_low) ||
1691 is_link_bw_min) {
1692 j++;
1693 cur_link_settings = *link_setting;
1694 delay_between_attempts += LINK_TRAINING_RETRY_DELAY;
1695 is_link_bw_low = false;
1696 is_link_bw_min = (cur_link_settings.link_rate <= LINK_RATE_LOW) &&
1697 (cur_link_settings.lane_count <= LANE_COUNT_ONE);
1698
1699 } else if (do_fallback) { /* Try training at lower link bandwidth if doing fallback. */
1700 uint32_t req_bw;
1701 uint32_t link_bw;
1702 enum dc_link_encoding_format link_encoding = DC_LINK_ENCODING_UNSPECIFIED;
1703
1704 decide_fallback_link_setting(link, max: &max_link_settings,
1705 cur: &cur_link_settings, training_result: status);
1706
1707 if (link_dp_get_encoding_format(link_settings: &cur_link_settings) == DP_8b_10b_ENCODING)
1708 link_encoding = DC_LINK_ENCODING_DP_8b_10b;
1709 else if (link_dp_get_encoding_format(link_settings: &cur_link_settings) == DP_128b_132b_ENCODING)
1710 link_encoding = DC_LINK_ENCODING_DP_128b_132b;
1711
1712 /* Flag if reduced link bandwidth no longer meets stream requirements or fallen back to
1713 * minimum link bandwidth.
1714 */
1715 req_bw = dc_bandwidth_in_kbps_from_timing(timing: &stream->timing, link_encoding);
1716 link_bw = dp_link_bandwidth_kbps(link, link_settings: &cur_link_settings);
1717 is_link_bw_low = (req_bw > link_bw);
1718 is_link_bw_min = ((cur_link_settings.link_rate <= LINK_RATE_LOW) &&
1719 (cur_link_settings.lane_count <= LANE_COUNT_ONE));
1720
1721 if (is_link_bw_low)
1722 DC_LOG_WARNING(
1723 "%s: Link(%d) bandwidth too low after fallback req_bw(%d) > link_bw(%d)\n",
1724 __func__, link->link_index, req_bw, link_bw);
1725 }
1726
1727 msleep(msecs: delay_between_attempts);
1728 }
1729
1730 return false;
1731}
1732
1733

source code of linux/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c