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
dp_log_training_result(struct dc_link * link,const struct link_training_settings * lt_settings,enum link_training_result status)58 void 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
dp_initialize_scrambling_data_symbols(struct dc_link * link,enum dc_dp_training_pattern pattern)179 uint8_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
205 enum dpcd_training_patterns
dp_training_pattern_to_dpcd_training_pattern(struct dc_link * link,enum dc_dp_training_pattern pattern)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
dp_get_nibble_at_index(const uint8_t * buf,uint32_t index)257 uint8_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
dp_wait_for_training_aux_rd_interval(struct dc_link * link,uint32_t wait_in_micro_secs)271 void dp_wait_for_training_aux_rd_interval(
272 struct dc_link *link,
273 uint32_t wait_in_micro_secs)
274 {
275 usleep_range_state(wait_in_micro_secs, wait_in_micro_secs, TASK_UNINTERRUPTIBLE);
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*/
283 static 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
get_max_pre_emphasis_for_voltage_swing(enum dc_voltage_swing voltage)289 static 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
maximize_lane_settings(const struct link_training_settings * lt_settings,struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX])302 static 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
333 /* Note, we are not checking
334 * if max_requested.FFE_PRESET.settings.level > DP_FFE_PRESET_MAX_LEVEL,
335 * since FFE_PRESET.settings.level is 4 bits and DP_FFE_PRESET_MAX_LEVEL equals 15,
336 * so FFE_PRESET.settings.level will never be greater than 15.
337 */
338
339 /* make sure the pre-emphasis matches the voltage swing*/
340 if (max_requested.PRE_EMPHASIS >
341 get_max_pre_emphasis_for_voltage_swing(
342 max_requested.VOLTAGE_SWING))
343 max_requested.PRE_EMPHASIS =
344 get_max_pre_emphasis_for_voltage_swing(
345 max_requested.VOLTAGE_SWING);
346
347 for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
348 lane_settings[lane].VOLTAGE_SWING = max_requested.VOLTAGE_SWING;
349 lane_settings[lane].PRE_EMPHASIS = max_requested.PRE_EMPHASIS;
350 lane_settings[lane].FFE_PRESET = max_requested.FFE_PRESET;
351 }
352 }
353
dp_hw_to_dpcd_lane_settings(const struct link_training_settings * lt_settings,const struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX],union dpcd_training_lane dpcd_lane_settings[LANE_COUNT_DP_MAX])354 void dp_hw_to_dpcd_lane_settings(
355 const struct link_training_settings *lt_settings,
356 const struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX],
357 union dpcd_training_lane dpcd_lane_settings[LANE_COUNT_DP_MAX])
358 {
359 uint8_t lane = 0;
360
361 for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
362 if (link_dp_get_encoding_format(<_settings->link_settings) ==
363 DP_8b_10b_ENCODING) {
364 dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET =
365 (uint8_t)(hw_lane_settings[lane].VOLTAGE_SWING);
366 dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET =
367 (uint8_t)(hw_lane_settings[lane].PRE_EMPHASIS);
368 dpcd_lane_settings[lane].bits.MAX_SWING_REACHED =
369 (hw_lane_settings[lane].VOLTAGE_SWING ==
370 VOLTAGE_SWING_MAX_LEVEL ? 1 : 0);
371 dpcd_lane_settings[lane].bits.MAX_PRE_EMPHASIS_REACHED =
372 (hw_lane_settings[lane].PRE_EMPHASIS ==
373 PRE_EMPHASIS_MAX_LEVEL ? 1 : 0);
374 } else if (link_dp_get_encoding_format(<_settings->link_settings) ==
375 DP_128b_132b_ENCODING) {
376 dpcd_lane_settings[lane].tx_ffe.PRESET_VALUE =
377 hw_lane_settings[lane].FFE_PRESET.settings.level;
378 }
379 }
380 }
381
get_dpcd_link_rate(const struct dc_link_settings * link_settings)382 uint8_t get_dpcd_link_rate(const struct dc_link_settings *link_settings)
383 {
384 uint8_t link_rate = 0;
385 enum dp_link_encoding encoding = link_dp_get_encoding_format(link_settings);
386
387 if (encoding == DP_128b_132b_ENCODING)
388 switch (link_settings->link_rate) {
389 case LINK_RATE_UHBR10:
390 link_rate = 0x1;
391 break;
392 case LINK_RATE_UHBR20:
393 link_rate = 0x2;
394 break;
395 case LINK_RATE_UHBR13_5:
396 link_rate = 0x4;
397 break;
398 default:
399 link_rate = 0;
400 break;
401 }
402 else if (encoding == DP_8b_10b_ENCODING)
403 link_rate = (uint8_t) link_settings->link_rate;
404 else
405 link_rate = 0;
406
407 return link_rate;
408 }
409
410 /* Only used for channel equalization */
dp_translate_training_aux_read_interval(uint32_t dpcd_aux_read_interval)411 uint32_t dp_translate_training_aux_read_interval(uint32_t dpcd_aux_read_interval)
412 {
413 unsigned int aux_rd_interval_us = 400;
414
415 switch (dpcd_aux_read_interval) {
416 case 0x01:
417 aux_rd_interval_us = 4000;
418 break;
419 case 0x02:
420 aux_rd_interval_us = 8000;
421 break;
422 case 0x03:
423 aux_rd_interval_us = 12000;
424 break;
425 case 0x04:
426 aux_rd_interval_us = 16000;
427 break;
428 case 0x05:
429 aux_rd_interval_us = 32000;
430 break;
431 case 0x06:
432 aux_rd_interval_us = 64000;
433 break;
434 default:
435 break;
436 }
437
438 return aux_rd_interval_us;
439 }
440
dp_get_cr_failure(enum dc_lane_count ln_count,union lane_status * dpcd_lane_status)441 enum link_training_result dp_get_cr_failure(enum dc_lane_count ln_count,
442 union lane_status *dpcd_lane_status)
443 {
444 enum link_training_result result = LINK_TRAINING_SUCCESS;
445
446 if (ln_count >= LANE_COUNT_ONE && !dpcd_lane_status[0].bits.CR_DONE_0)
447 result = LINK_TRAINING_CR_FAIL_LANE0;
448 else if (ln_count >= LANE_COUNT_TWO && !dpcd_lane_status[1].bits.CR_DONE_0)
449 result = LINK_TRAINING_CR_FAIL_LANE1;
450 else if (ln_count >= LANE_COUNT_FOUR && !dpcd_lane_status[2].bits.CR_DONE_0)
451 result = LINK_TRAINING_CR_FAIL_LANE23;
452 else if (ln_count >= LANE_COUNT_FOUR && !dpcd_lane_status[3].bits.CR_DONE_0)
453 result = LINK_TRAINING_CR_FAIL_LANE23;
454 return result;
455 }
456
is_repeater(const struct link_training_settings * lt_settings,uint32_t offset)457 bool is_repeater(const struct link_training_settings *lt_settings, uint32_t offset)
458 {
459 return (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) && (offset != 0);
460 }
461
dp_is_max_vs_reached(const struct link_training_settings * lt_settings)462 bool dp_is_max_vs_reached(
463 const struct link_training_settings *lt_settings)
464 {
465 uint32_t lane;
466 for (lane = 0; lane <
467 (uint32_t)(lt_settings->link_settings.lane_count);
468 lane++) {
469 if (lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET
470 == VOLTAGE_SWING_MAX_LEVEL)
471 return true;
472 }
473 return false;
474
475 }
476
dp_is_cr_done(enum dc_lane_count ln_count,union lane_status * dpcd_lane_status)477 bool dp_is_cr_done(enum dc_lane_count ln_count,
478 union lane_status *dpcd_lane_status)
479 {
480 bool done = true;
481 uint32_t lane;
482 /*LANEx_CR_DONE bits All 1's?*/
483 for (lane = 0; lane < (uint32_t)(ln_count); lane++) {
484 if (!dpcd_lane_status[lane].bits.CR_DONE_0)
485 done = false;
486 }
487 return done;
488
489 }
490
dp_is_ch_eq_done(enum dc_lane_count ln_count,union lane_status * dpcd_lane_status)491 bool dp_is_ch_eq_done(enum dc_lane_count ln_count,
492 union lane_status *dpcd_lane_status)
493 {
494 bool done = true;
495 uint32_t lane;
496 for (lane = 0; lane < (uint32_t)(ln_count); lane++)
497 if (!dpcd_lane_status[lane].bits.CHANNEL_EQ_DONE_0)
498 done = false;
499 return done;
500 }
501
dp_is_symbol_locked(enum dc_lane_count ln_count,union lane_status * dpcd_lane_status)502 bool dp_is_symbol_locked(enum dc_lane_count ln_count,
503 union lane_status *dpcd_lane_status)
504 {
505 bool locked = true;
506 uint32_t lane;
507 for (lane = 0; lane < (uint32_t)(ln_count); lane++)
508 if (!dpcd_lane_status[lane].bits.SYMBOL_LOCKED_0)
509 locked = false;
510 return locked;
511 }
512
dp_is_interlane_aligned(union lane_align_status_updated align_status)513 bool dp_is_interlane_aligned(union lane_align_status_updated align_status)
514 {
515 return align_status.bits.INTERLANE_ALIGN_DONE == 1;
516 }
517
dp_check_interlane_aligned(union lane_align_status_updated align_status,struct dc_link * link,uint8_t retries)518 bool dp_check_interlane_aligned(union lane_align_status_updated align_status,
519 struct dc_link *link,
520 uint8_t retries)
521 {
522 /* Take into consideration corner case for DP 1.4a LL Compliance CTS as USB4
523 * has to share encoders unlike DP and USBC
524 */
525 return (dp_is_interlane_aligned(align_status) ||
526 (link->skip_fallback_on_link_loss && retries));
527 }
528
dp_get_eq_aux_rd_interval(const struct dc_link * link,const struct link_training_settings * lt_settings,uint32_t offset,uint8_t retries)529 uint32_t dp_get_eq_aux_rd_interval(
530 const struct dc_link *link,
531 const struct link_training_settings *lt_settings,
532 uint32_t offset,
533 uint8_t retries)
534 {
535 if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) {
536 if (offset == 0 && retries == 1 && lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT)
537 return max(lt_settings->eq_pattern_time, (uint32_t) DPIA_CLK_SYNC_DELAY);
538 else
539 return dpia_get_eq_aux_rd_interval(link, lt_settings, offset);
540 } else if (is_repeater(lt_settings, offset))
541 return dp_translate_training_aux_read_interval(
542 link->dpcd_caps.lttpr_caps.aux_rd_interval[offset - 1]);
543 else
544 return lt_settings->eq_pattern_time;
545 }
546
dp_check_dpcd_reqeust_status(const struct dc_link * link,enum dc_status status)547 bool dp_check_dpcd_reqeust_status(const struct dc_link *link,
548 enum dc_status status)
549 {
550 return (status != DC_OK && link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA);
551 }
552
dp_check_link_loss_status(struct dc_link * link,const struct link_training_settings * link_training_setting)553 enum link_training_result dp_check_link_loss_status(
554 struct dc_link *link,
555 const struct link_training_settings *link_training_setting)
556 {
557 enum link_training_result status = LINK_TRAINING_SUCCESS;
558 union lane_status lane_status;
559 union lane_align_status_updated dpcd_lane_status_updated;
560 uint8_t dpcd_buf[6] = {0};
561 uint32_t lane;
562
563 core_link_read_dpcd(
564 link,
565 DP_SINK_COUNT,
566 (uint8_t *)(dpcd_buf),
567 sizeof(dpcd_buf));
568
569 /*parse lane status*/
570 for (lane = 0; lane < link->cur_link_settings.lane_count; lane++) {
571 /*
572 * check lanes status
573 */
574 lane_status.raw = dp_get_nibble_at_index(&dpcd_buf[2], lane);
575 dpcd_lane_status_updated.raw = dpcd_buf[4];
576
577 if (!lane_status.bits.CHANNEL_EQ_DONE_0 ||
578 !lane_status.bits.CR_DONE_0 ||
579 !lane_status.bits.SYMBOL_LOCKED_0 ||
580 !dp_is_interlane_aligned(dpcd_lane_status_updated)) {
581 /* if one of the channel equalization, clock
582 * recovery or symbol lock is dropped
583 * consider it as (link has been
584 * dropped) dp sink status has changed
585 */
586 status = LINK_TRAINING_LINK_LOSS;
587 break;
588 }
589 }
590
591 return status;
592 }
593
dp_get_lane_status_and_lane_adjust(struct dc_link * link,const struct link_training_settings * link_training_setting,union lane_status ln_status[LANE_COUNT_DP_MAX],union lane_align_status_updated * ln_align,union lane_adjust ln_adjust[LANE_COUNT_DP_MAX],uint32_t offset)594 enum dc_status dp_get_lane_status_and_lane_adjust(
595 struct dc_link *link,
596 const struct link_training_settings *link_training_setting,
597 union lane_status ln_status[LANE_COUNT_DP_MAX],
598 union lane_align_status_updated *ln_align,
599 union lane_adjust ln_adjust[LANE_COUNT_DP_MAX],
600 uint32_t offset)
601 {
602 unsigned int lane01_status_address = DP_LANE0_1_STATUS;
603 uint8_t lane_adjust_offset = 4;
604 unsigned int lane01_adjust_address;
605 uint8_t dpcd_buf[6] = {0};
606 uint32_t lane;
607 enum dc_status status;
608
609 if (is_repeater(link_training_setting, offset)) {
610 lane01_status_address =
611 DP_LANE0_1_STATUS_PHY_REPEATER1 +
612 ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
613 lane_adjust_offset = 3;
614 }
615
616 status = core_link_read_dpcd(
617 link,
618 lane01_status_address,
619 (uint8_t *)(dpcd_buf),
620 sizeof(dpcd_buf));
621
622 if (status != DC_OK) {
623 DC_LOG_HW_LINK_TRAINING("%s:\n Failed to read from address 0x%X,"
624 " keep current lane status and lane adjust unchanged",
625 __func__,
626 lane01_status_address);
627 return status;
628 }
629
630 for (lane = 0; lane <
631 (uint32_t)(link_training_setting->link_settings.lane_count);
632 lane++) {
633
634 ln_status[lane].raw =
635 dp_get_nibble_at_index(&dpcd_buf[0], lane);
636 ln_adjust[lane].raw =
637 dp_get_nibble_at_index(&dpcd_buf[lane_adjust_offset], lane);
638 }
639
640 ln_align->raw = dpcd_buf[2];
641
642 if (is_repeater(link_training_setting, offset)) {
643 DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n"
644 " 0x%X Lane01Status = %x\n 0x%X Lane23Status = %x\n ",
645 __func__,
646 offset,
647 lane01_status_address, dpcd_buf[0],
648 lane01_status_address + 1, dpcd_buf[1]);
649
650 lane01_adjust_address = DP_ADJUST_REQUEST_LANE0_1_PHY_REPEATER1 +
651 ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
652
653 DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n"
654 " 0x%X Lane01AdjustRequest = %x\n 0x%X Lane23AdjustRequest = %x\n",
655 __func__,
656 offset,
657 lane01_adjust_address,
658 dpcd_buf[lane_adjust_offset],
659 lane01_adjust_address + 1,
660 dpcd_buf[lane_adjust_offset + 1]);
661 } else {
662 DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X Lane01Status = %x\n 0x%X Lane23Status = %x\n ",
663 __func__,
664 lane01_status_address, dpcd_buf[0],
665 lane01_status_address + 1, dpcd_buf[1]);
666
667 lane01_adjust_address = DP_ADJUST_REQUEST_LANE0_1;
668
669 DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X Lane01AdjustRequest = %x\n 0x%X Lane23AdjustRequest = %x\n",
670 __func__,
671 lane01_adjust_address,
672 dpcd_buf[lane_adjust_offset],
673 lane01_adjust_address + 1,
674 dpcd_buf[lane_adjust_offset + 1]);
675 }
676
677 return status;
678 }
679
override_lane_settings(const struct link_training_settings * lt_settings,struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX])680 static void override_lane_settings(const struct link_training_settings *lt_settings,
681 struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX])
682 {
683 uint32_t lane;
684
685 if (lt_settings->voltage_swing == NULL &&
686 lt_settings->pre_emphasis == NULL &&
687 lt_settings->ffe_preset == NULL &&
688 lt_settings->post_cursor2 == NULL)
689
690 return;
691
692 for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
693 if (lt_settings->voltage_swing)
694 lane_settings[lane].VOLTAGE_SWING = *lt_settings->voltage_swing;
695 if (lt_settings->pre_emphasis)
696 lane_settings[lane].PRE_EMPHASIS = *lt_settings->pre_emphasis;
697 if (lt_settings->post_cursor2)
698 lane_settings[lane].POST_CURSOR2 = *lt_settings->post_cursor2;
699 if (lt_settings->ffe_preset)
700 lane_settings[lane].FFE_PRESET = *lt_settings->ffe_preset;
701 }
702 }
703
dp_get_lttpr_mode_override(struct dc_link * link,enum lttpr_mode * override)704 void dp_get_lttpr_mode_override(struct dc_link *link, enum lttpr_mode *override)
705 {
706 if (!dp_is_lttpr_present(link))
707 return;
708
709 if (link->dc->debug.lttpr_mode_override == LTTPR_MODE_TRANSPARENT) {
710 *override = LTTPR_MODE_TRANSPARENT;
711 } else if (link->dc->debug.lttpr_mode_override == LTTPR_MODE_NON_TRANSPARENT) {
712 *override = LTTPR_MODE_NON_TRANSPARENT;
713 } else if (link->dc->debug.lttpr_mode_override == LTTPR_MODE_NON_LTTPR) {
714 *override = LTTPR_MODE_NON_LTTPR;
715 }
716 DC_LOG_DC("lttpr_mode_override chose LTTPR_MODE = %d\n", (uint8_t)(*override));
717 }
718
override_training_settings(struct dc_link * link,const struct dc_link_training_overrides * overrides,struct link_training_settings * lt_settings)719 void override_training_settings(
720 struct dc_link *link,
721 const struct dc_link_training_overrides *overrides,
722 struct link_training_settings *lt_settings)
723 {
724 uint32_t lane;
725
726 /* Override link spread */
727 if (!link->dp_ss_off && overrides->downspread != NULL)
728 lt_settings->link_settings.link_spread = *overrides->downspread ?
729 LINK_SPREAD_05_DOWNSPREAD_30KHZ
730 : LINK_SPREAD_DISABLED;
731
732 /* Override lane settings */
733 if (overrides->voltage_swing != NULL)
734 lt_settings->voltage_swing = overrides->voltage_swing;
735 if (overrides->pre_emphasis != NULL)
736 lt_settings->pre_emphasis = overrides->pre_emphasis;
737 if (overrides->post_cursor2 != NULL)
738 lt_settings->post_cursor2 = overrides->post_cursor2;
739 if (link->wa_flags.force_dp_ffe_preset && !dp_is_lttpr_present(link))
740 lt_settings->ffe_preset = &link->forced_dp_ffe_preset;
741 if (overrides->ffe_preset != NULL)
742 lt_settings->ffe_preset = overrides->ffe_preset;
743 /* Override HW lane settings with BIOS forced values if present */
744 if ((link->chip_caps & AMD_EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) &&
745 lt_settings->lttpr_mode == LTTPR_MODE_TRANSPARENT) {
746 lt_settings->voltage_swing = &link->bios_forced_drive_settings.VOLTAGE_SWING;
747 lt_settings->pre_emphasis = &link->bios_forced_drive_settings.PRE_EMPHASIS;
748 lt_settings->always_match_dpcd_with_hw_lane_settings = false;
749 }
750 for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
751 lt_settings->hw_lane_settings[lane].VOLTAGE_SWING =
752 lt_settings->voltage_swing != NULL ?
753 *lt_settings->voltage_swing :
754 VOLTAGE_SWING_LEVEL0;
755 lt_settings->hw_lane_settings[lane].PRE_EMPHASIS =
756 lt_settings->pre_emphasis != NULL ?
757 *lt_settings->pre_emphasis
758 : PRE_EMPHASIS_DISABLED;
759 lt_settings->hw_lane_settings[lane].POST_CURSOR2 =
760 lt_settings->post_cursor2 != NULL ?
761 *lt_settings->post_cursor2
762 : POST_CURSOR2_DISABLED;
763 }
764
765 if (lt_settings->always_match_dpcd_with_hw_lane_settings)
766 dp_hw_to_dpcd_lane_settings(lt_settings,
767 lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
768
769 /* Override training timings */
770 if (overrides->cr_pattern_time != NULL)
771 lt_settings->cr_pattern_time = *overrides->cr_pattern_time;
772 if (overrides->eq_pattern_time != NULL)
773 lt_settings->eq_pattern_time = *overrides->eq_pattern_time;
774 if (overrides->pattern_for_cr != NULL)
775 lt_settings->pattern_for_cr = *overrides->pattern_for_cr;
776 if (overrides->pattern_for_eq != NULL)
777 lt_settings->pattern_for_eq = *overrides->pattern_for_eq;
778 if (overrides->enhanced_framing != NULL)
779 lt_settings->enhanced_framing = *overrides->enhanced_framing;
780 if (link->preferred_training_settings.fec_enable != NULL)
781 lt_settings->should_set_fec_ready = *link->preferred_training_settings.fec_enable;
782
783 /* Check DP tunnel LTTPR mode debug option. */
784 if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA && link->dc->debug.dpia_debug.bits.force_non_lttpr)
785 lt_settings->lttpr_mode = LTTPR_MODE_NON_LTTPR;
786
787 dp_get_lttpr_mode_override(link, <_settings->lttpr_mode);
788
789 }
790
decide_cr_training_pattern(const struct dc_link_settings * link_settings)791 enum dc_dp_training_pattern decide_cr_training_pattern(
792 const struct dc_link_settings *link_settings)
793 {
794 switch (link_dp_get_encoding_format(link_settings)) {
795 case DP_8b_10b_ENCODING:
796 default:
797 return DP_TRAINING_PATTERN_SEQUENCE_1;
798 case DP_128b_132b_ENCODING:
799 return DP_128b_132b_TPS1;
800 }
801 }
802
decide_eq_training_pattern(struct dc_link * link,const struct link_resource * link_res,const struct dc_link_settings * link_settings)803 enum dc_dp_training_pattern decide_eq_training_pattern(struct dc_link *link,
804 const struct link_resource *link_res,
805 const struct dc_link_settings *link_settings)
806 {
807 struct link_encoder *link_enc = link_res->dio_link_enc;
808 struct encoder_feature_support *enc_caps;
809 struct dpcd_caps *rx_caps = &link->dpcd_caps;
810 enum dc_dp_training_pattern pattern = DP_TRAINING_PATTERN_SEQUENCE_2;
811
812 switch (link_dp_get_encoding_format(link_settings)) {
813 case DP_8b_10b_ENCODING:
814 if (!link->dc->config.unify_link_enc_assignment)
815 link_enc = link_enc_cfg_get_link_enc(link);
816
817 if (!link_enc)
818 break;
819
820 enc_caps = &link_enc->features;
821 if (enc_caps->flags.bits.IS_TPS4_CAPABLE &&
822 rx_caps->max_down_spread.bits.TPS4_SUPPORTED)
823 pattern = DP_TRAINING_PATTERN_SEQUENCE_4;
824 else if (enc_caps->flags.bits.IS_TPS3_CAPABLE &&
825 rx_caps->max_ln_count.bits.TPS3_SUPPORTED)
826 pattern = DP_TRAINING_PATTERN_SEQUENCE_3;
827 else
828 pattern = DP_TRAINING_PATTERN_SEQUENCE_2;
829 break;
830 case DP_128b_132b_ENCODING:
831 pattern = DP_128b_132b_TPS2;
832 break;
833 default:
834 pattern = DP_TRAINING_PATTERN_SEQUENCE_2;
835 break;
836 }
837 return pattern;
838 }
839
dp_decide_lttpr_mode(struct dc_link * link,struct dc_link_settings * link_setting)840 enum lttpr_mode dp_decide_lttpr_mode(struct dc_link *link,
841 struct dc_link_settings *link_setting)
842 {
843 enum dp_link_encoding encoding = link_dp_get_encoding_format(link_setting);
844
845 if (encoding == DP_8b_10b_ENCODING)
846 return dp_decide_8b_10b_lttpr_mode(link);
847 else if (encoding == DP_128b_132b_ENCODING)
848 return dp_decide_128b_132b_lttpr_mode(link);
849
850 ASSERT(0);
851 return LTTPR_MODE_NON_LTTPR;
852 }
853
dp_decide_lane_settings(const struct link_training_settings * lt_settings,const union lane_adjust ln_adjust[LANE_COUNT_DP_MAX],struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX],union dpcd_training_lane * dpcd_lane_settings)854 void dp_decide_lane_settings(
855 const struct link_training_settings *lt_settings,
856 const union lane_adjust ln_adjust[LANE_COUNT_DP_MAX],
857 struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX],
858 union dpcd_training_lane *dpcd_lane_settings)
859 {
860 uint32_t lane;
861
862 for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
863 if (link_dp_get_encoding_format(<_settings->link_settings) ==
864 DP_8b_10b_ENCODING) {
865 hw_lane_settings[lane].VOLTAGE_SWING =
866 (enum dc_voltage_swing)(ln_adjust[lane].bits.
867 VOLTAGE_SWING_LANE);
868 hw_lane_settings[lane].PRE_EMPHASIS =
869 (enum dc_pre_emphasis)(ln_adjust[lane].bits.
870 PRE_EMPHASIS_LANE);
871 } else if (link_dp_get_encoding_format(<_settings->link_settings) ==
872 DP_128b_132b_ENCODING) {
873 hw_lane_settings[lane].FFE_PRESET.raw =
874 ln_adjust[lane].tx_ffe.PRESET_VALUE;
875 }
876 }
877 dp_hw_to_dpcd_lane_settings(lt_settings, hw_lane_settings, dpcd_lane_settings);
878
879 if (lt_settings->disallow_per_lane_settings) {
880 /* we find the maximum of the requested settings across all lanes*/
881 /* and set this maximum for all lanes*/
882 maximize_lane_settings(lt_settings, hw_lane_settings);
883 override_lane_settings(lt_settings, hw_lane_settings);
884
885 if (lt_settings->always_match_dpcd_with_hw_lane_settings)
886 dp_hw_to_dpcd_lane_settings(lt_settings, hw_lane_settings, dpcd_lane_settings);
887 }
888
889 }
890
dp_decide_training_settings(struct dc_link * link,const struct link_resource * link_res,const struct dc_link_settings * link_settings,struct link_training_settings * lt_settings)891 void dp_decide_training_settings(
892 struct dc_link *link,
893 const struct link_resource *link_res,
894 const struct dc_link_settings *link_settings,
895 struct link_training_settings *lt_settings)
896 {
897 if (link_dp_get_encoding_format(link_settings) == DP_8b_10b_ENCODING)
898 decide_8b_10b_training_settings(link, link_res, link_settings, lt_settings);
899 else if (link_dp_get_encoding_format(link_settings) == DP_128b_132b_ENCODING)
900 decide_128b_132b_training_settings(link, link_res, link_settings, lt_settings);
901 }
902
903
configure_lttpr_mode_transparent(struct dc_link * link)904 enum dc_status configure_lttpr_mode_transparent(struct dc_link *link)
905 {
906 uint8_t repeater_mode = DP_PHY_REPEATER_MODE_TRANSPARENT;
907
908 DC_LOG_HW_LINK_TRAINING("%s\n Set LTTPR to Transparent Mode\n", __func__);
909 return core_link_write_dpcd(link,
910 DP_PHY_REPEATER_MODE,
911 (uint8_t *)&repeater_mode,
912 sizeof(repeater_mode));
913 }
914
configure_lttpr_mode_non_transparent(struct dc_link * link,const struct link_training_settings * lt_settings)915 static enum dc_status configure_lttpr_mode_non_transparent(
916 struct dc_link *link,
917 const struct link_training_settings *lt_settings)
918 {
919 /* aux timeout is already set to extended */
920 /* RESET/SET lttpr mode to enable non transparent mode */
921 uint8_t repeater_cnt;
922 uint32_t aux_interval_address;
923 uint8_t repeater_id;
924 enum dc_status result = DC_ERROR_UNEXPECTED;
925 uint8_t repeater_mode = DP_PHY_REPEATER_MODE_TRANSPARENT;
926 const struct dc *dc = link->dc;
927
928 enum dp_link_encoding encoding = dc->link_srv->dp_get_encoding_format(<_settings->link_settings);
929
930 if (encoding == DP_8b_10b_ENCODING) {
931 DC_LOG_HW_LINK_TRAINING("%s\n Set LTTPR to Transparent Mode\n", __func__);
932 result = core_link_write_dpcd(link,
933 DP_PHY_REPEATER_MODE,
934 (uint8_t *)&repeater_mode,
935 sizeof(repeater_mode));
936
937 }
938
939 if (result == DC_OK) {
940 link->dpcd_caps.lttpr_caps.mode = repeater_mode;
941 }
942
943 if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) {
944
945 DC_LOG_HW_LINK_TRAINING("%s\n Set LTTPR to Non Transparent Mode\n", __func__);
946
947 repeater_mode = DP_PHY_REPEATER_MODE_NON_TRANSPARENT;
948 result = core_link_write_dpcd(link,
949 DP_PHY_REPEATER_MODE,
950 (uint8_t *)&repeater_mode,
951 sizeof(repeater_mode));
952
953 if (result == DC_OK) {
954 link->dpcd_caps.lttpr_caps.mode = repeater_mode;
955 }
956
957 if (encoding == DP_8b_10b_ENCODING) {
958 repeater_cnt = dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
959
960 /* Driver does not need to train the first hop. Skip DPCD read and clear
961 * AUX_RD_INTERVAL for DPTX-to-DPIA hop.
962 */
963 if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA && repeater_cnt > 0 && repeater_cnt < MAX_REPEATER_CNT)
964 link->dpcd_caps.lttpr_caps.aux_rd_interval[--repeater_cnt] = 0;
965
966 for (repeater_id = repeater_cnt; repeater_id > 0 && repeater_id < MAX_REPEATER_CNT; repeater_id--) {
967 aux_interval_address = DP_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER1 +
968 ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (repeater_id - 1));
969 core_link_read_dpcd(
970 link,
971 aux_interval_address,
972 (uint8_t *)&link->dpcd_caps.lttpr_caps.aux_rd_interval[repeater_id - 1],
973 sizeof(link->dpcd_caps.lttpr_caps.aux_rd_interval[repeater_id - 1]));
974 link->dpcd_caps.lttpr_caps.aux_rd_interval[repeater_id - 1] &= 0x7F;
975 }
976 }
977 }
978
979 return result;
980 }
981
dpcd_configure_lttpr_mode(struct dc_link * link,struct link_training_settings * lt_settings)982 enum dc_status dpcd_configure_lttpr_mode(struct dc_link *link, struct link_training_settings *lt_settings)
983 {
984 enum dc_status status = DC_OK;
985
986 if (lt_settings->lttpr_mode == LTTPR_MODE_TRANSPARENT)
987 status = configure_lttpr_mode_transparent(link);
988
989 else if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT)
990 status = configure_lttpr_mode_non_transparent(link, lt_settings);
991
992 return status;
993 }
994
repeater_training_done(struct dc_link * link,uint32_t offset)995 void repeater_training_done(struct dc_link *link, uint32_t offset)
996 {
997 union dpcd_training_pattern dpcd_pattern = {0};
998
999 const uint32_t dpcd_base_lt_offset =
1000 DP_TRAINING_PATTERN_SET_PHY_REPEATER1 +
1001 ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
1002 /* Set training not in progress*/
1003 dpcd_pattern.v1_4.TRAINING_PATTERN_SET = DPCD_TRAINING_PATTERN_VIDEOIDLE;
1004
1005 core_link_write_dpcd(
1006 link,
1007 dpcd_base_lt_offset,
1008 &dpcd_pattern.raw,
1009 1);
1010
1011 DC_LOG_HW_LINK_TRAINING("%s\n LTTPR Id: %d 0x%X pattern = %x\n",
1012 __func__,
1013 offset,
1014 dpcd_base_lt_offset,
1015 dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
1016 }
1017
dpcd_exit_training_mode(struct dc_link * link,enum dp_link_encoding encoding)1018 static enum link_training_result dpcd_exit_training_mode(struct dc_link *link, enum dp_link_encoding encoding)
1019 {
1020 enum dc_status status;
1021 uint8_t sink_status = 0;
1022 uint8_t i;
1023
1024 /* clear training pattern set */
1025 status = dpcd_set_training_pattern(link, DP_TRAINING_PATTERN_VIDEOIDLE);
1026
1027 if (dp_check_dpcd_reqeust_status(link, status))
1028 return LINK_TRAINING_ABORT;
1029
1030 if (encoding == DP_128b_132b_ENCODING) {
1031 /* poll for intra-hop disable */
1032 for (i = 0; i < 10; i++) {
1033 if ((core_link_read_dpcd(link, DP_SINK_STATUS, &sink_status, 1) == DC_OK) &&
1034 (sink_status & DP_INTRA_HOP_AUX_REPLY_INDICATION) == 0)
1035 break;
1036 fsleep(1000);
1037 }
1038 }
1039
1040 return LINK_TRAINING_SUCCESS;
1041 }
1042
dpcd_configure_channel_coding(struct dc_link * link,struct link_training_settings * lt_settings)1043 enum dc_status dpcd_configure_channel_coding(struct dc_link *link,
1044 struct link_training_settings *lt_settings)
1045 {
1046 enum dp_link_encoding encoding =
1047 link_dp_get_encoding_format(
1048 <_settings->link_settings);
1049 enum dc_status status;
1050
1051 status = core_link_write_dpcd(
1052 link,
1053 DP_MAIN_LINK_CHANNEL_CODING_SET,
1054 (uint8_t *) &encoding,
1055 1);
1056 DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X MAIN_LINK_CHANNEL_CODING_SET = %x\n",
1057 __func__,
1058 DP_MAIN_LINK_CHANNEL_CODING_SET,
1059 encoding);
1060
1061 return status;
1062 }
1063
dpcd_set_training_pattern(struct dc_link * link,enum dc_dp_training_pattern training_pattern)1064 enum dc_status dpcd_set_training_pattern(
1065 struct dc_link *link,
1066 enum dc_dp_training_pattern training_pattern)
1067 {
1068 enum dc_status status;
1069 union dpcd_training_pattern dpcd_pattern = {0};
1070
1071 dpcd_pattern.v1_4.TRAINING_PATTERN_SET =
1072 dp_training_pattern_to_dpcd_training_pattern(
1073 link, training_pattern);
1074
1075 status = core_link_write_dpcd(
1076 link,
1077 DP_TRAINING_PATTERN_SET,
1078 &dpcd_pattern.raw,
1079 1);
1080
1081 DC_LOG_HW_LINK_TRAINING("%s\n %x pattern = %x\n",
1082 __func__,
1083 DP_TRAINING_PATTERN_SET,
1084 dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
1085
1086 return status;
1087 }
1088
dpcd_set_link_settings(struct dc_link * link,const struct link_training_settings * lt_settings)1089 enum dc_status dpcd_set_link_settings(
1090 struct dc_link *link,
1091 const struct link_training_settings *lt_settings)
1092 {
1093 uint8_t rate;
1094 enum dc_status status;
1095
1096 union down_spread_ctrl downspread = {0};
1097 union lane_count_set lane_count_set = {0};
1098
1099 downspread.raw = (uint8_t)
1100 (lt_settings->link_settings.link_spread);
1101
1102 lane_count_set.bits.LANE_COUNT_SET =
1103 lt_settings->link_settings.lane_count;
1104
1105 lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing;
1106 lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0;
1107
1108
1109 if (link->ep_type == DISPLAY_ENDPOINT_PHY &&
1110 lt_settings->pattern_for_eq < DP_TRAINING_PATTERN_SEQUENCE_4) {
1111 lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED =
1112 link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED;
1113 }
1114
1115 status = core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL,
1116 &downspread.raw, sizeof(downspread));
1117 if (status != DC_OK)
1118 DC_LOG_ERROR("%s:%d: core_link_write_dpcd (DP_DOWNSPREAD_CTRL) failed\n", __func__, __LINE__);
1119
1120 status = core_link_write_dpcd(link, DP_LANE_COUNT_SET,
1121 &lane_count_set.raw, 1);
1122 if (status != DC_OK)
1123 DC_LOG_ERROR("%s:%d: core_link_write_dpcd (DP_LANE_COUNT_SET) failed\n", __func__, __LINE__);
1124
1125 if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_13 &&
1126 lt_settings->link_settings.use_link_rate_set == true) {
1127 rate = 0;
1128 /* WA for some MUX chips that will power down with eDP and lose supported
1129 * link rate set for eDP 1.4. Source reads DPCD 0x010 again to ensure
1130 * MUX chip gets link rate set back before link training.
1131 */
1132 if (link->connector_signal == SIGNAL_TYPE_EDP) {
1133 uint8_t supported_link_rates[16] = {0};
1134
1135 core_link_read_dpcd(link, DP_SUPPORTED_LINK_RATES,
1136 supported_link_rates, sizeof(supported_link_rates));
1137 }
1138 status = core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1);
1139 if (status != DC_OK)
1140 DC_LOG_ERROR("%s:%d: core_link_write_dpcd (DP_LINK_BW_SET) failed\n", __func__, __LINE__);
1141
1142 status = core_link_write_dpcd(link, DP_LINK_RATE_SET,
1143 <_settings->link_settings.link_rate_set, 1);
1144 if (status != DC_OK)
1145 DC_LOG_ERROR("%s:%d: core_link_write_dpcd (DP_LINK_RATE_SET) failed\n", __func__, __LINE__);
1146 } else {
1147 rate = get_dpcd_link_rate(<_settings->link_settings);
1148
1149 status = core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1);
1150 if (status != DC_OK)
1151 DC_LOG_ERROR("%s:%d: core_link_write_dpcd (DP_LINK_BW_SET) failed\n", __func__, __LINE__);
1152 }
1153
1154 if (rate) {
1155 DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x framing = %x\n %x spread = %x\n",
1156 __func__,
1157 DP_LINK_BW_SET,
1158 lt_settings->link_settings.link_rate,
1159 DP_LANE_COUNT_SET,
1160 lt_settings->link_settings.lane_count,
1161 lt_settings->enhanced_framing,
1162 DP_DOWNSPREAD_CTRL,
1163 lt_settings->link_settings.link_spread);
1164 } else {
1165 DC_LOG_HW_LINK_TRAINING("%s\n %x rate set = %x\n %x lane = %x framing = %x\n %x spread = %x\n",
1166 __func__,
1167 DP_LINK_RATE_SET,
1168 lt_settings->link_settings.link_rate_set,
1169 DP_LANE_COUNT_SET,
1170 lt_settings->link_settings.lane_count,
1171 lt_settings->enhanced_framing,
1172 DP_DOWNSPREAD_CTRL,
1173 lt_settings->link_settings.link_spread);
1174 }
1175
1176 return status;
1177 }
1178
dpcd_set_lane_settings(struct dc_link * link,const struct link_training_settings * link_training_setting,uint32_t offset)1179 enum dc_status dpcd_set_lane_settings(
1180 struct dc_link *link,
1181 const struct link_training_settings *link_training_setting,
1182 uint32_t offset)
1183 {
1184 unsigned int lane0_set_address;
1185 enum dc_status status;
1186 lane0_set_address = DP_TRAINING_LANE0_SET;
1187
1188 if (is_repeater(link_training_setting, offset))
1189 lane0_set_address = DP_TRAINING_LANE0_SET_PHY_REPEATER1 +
1190 ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
1191
1192 status = core_link_write_dpcd(link,
1193 lane0_set_address,
1194 (uint8_t *)(link_training_setting->dpcd_lane_settings),
1195 link_training_setting->link_settings.lane_count);
1196
1197 if (is_repeater(link_training_setting, offset)) {
1198 DC_LOG_HW_LINK_TRAINING("%s\n LTTPR Repeater ID: %d\n"
1199 " 0x%X VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n",
1200 __func__,
1201 offset,
1202 lane0_set_address,
1203 link_training_setting->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET,
1204 link_training_setting->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET,
1205 link_training_setting->dpcd_lane_settings[0].bits.MAX_SWING_REACHED,
1206 link_training_setting->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED);
1207
1208 } else {
1209 DC_LOG_HW_LINK_TRAINING("%s\n 0x%X VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n",
1210 __func__,
1211 lane0_set_address,
1212 link_training_setting->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET,
1213 link_training_setting->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET,
1214 link_training_setting->dpcd_lane_settings[0].bits.MAX_SWING_REACHED,
1215 link_training_setting->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED);
1216 }
1217
1218 return status;
1219 }
1220
dpcd_set_lt_pattern_and_lane_settings(struct dc_link * link,const struct link_training_settings * lt_settings,enum dc_dp_training_pattern pattern,uint32_t offset)1221 void dpcd_set_lt_pattern_and_lane_settings(
1222 struct dc_link *link,
1223 const struct link_training_settings *lt_settings,
1224 enum dc_dp_training_pattern pattern,
1225 uint32_t offset)
1226 {
1227 uint32_t dpcd_base_lt_offset;
1228 uint8_t dpcd_lt_buffer[5] = {0};
1229 union dpcd_training_pattern dpcd_pattern = {0};
1230 uint32_t size_in_bytes;
1231 bool edp_workaround = false; /* TODO link_prop.INTERNAL */
1232 dpcd_base_lt_offset = DP_TRAINING_PATTERN_SET;
1233
1234 if (is_repeater(lt_settings, offset))
1235 dpcd_base_lt_offset = DP_TRAINING_PATTERN_SET_PHY_REPEATER1 +
1236 ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
1237
1238 /*****************************************************************
1239 * DpcdAddress_TrainingPatternSet
1240 *****************************************************************/
1241 dpcd_pattern.v1_4.TRAINING_PATTERN_SET =
1242 dp_training_pattern_to_dpcd_training_pattern(link, pattern);
1243
1244 dpcd_pattern.v1_4.SCRAMBLING_DISABLE =
1245 dp_initialize_scrambling_data_symbols(link, pattern);
1246
1247 dpcd_lt_buffer[DP_TRAINING_PATTERN_SET - DP_TRAINING_PATTERN_SET]
1248 = dpcd_pattern.raw;
1249
1250 if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA)
1251 dpia_set_tps_notification(
1252 link,
1253 lt_settings,
1254 dpcd_pattern.v1_4.TRAINING_PATTERN_SET,
1255 offset);
1256
1257 if (is_repeater(lt_settings, offset)) {
1258 DC_LOG_HW_LINK_TRAINING("%s\n LTTPR Repeater ID: %d\n 0x%X pattern = %x\n",
1259 __func__,
1260 offset,
1261 dpcd_base_lt_offset,
1262 dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
1263 } else {
1264 DC_LOG_HW_LINK_TRAINING("%s\n 0x%X pattern = %x\n",
1265 __func__,
1266 dpcd_base_lt_offset,
1267 dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
1268 }
1269
1270 /* concatenate everything into one buffer*/
1271 size_in_bytes = lt_settings->link_settings.lane_count *
1272 sizeof(lt_settings->dpcd_lane_settings[0]);
1273
1274 // 0x00103 - 0x00102
1275 memmove(
1276 &dpcd_lt_buffer[DP_TRAINING_LANE0_SET - DP_TRAINING_PATTERN_SET],
1277 lt_settings->dpcd_lane_settings,
1278 size_in_bytes);
1279
1280 if (is_repeater(lt_settings, offset)) {
1281 if (link_dp_get_encoding_format(<_settings->link_settings) ==
1282 DP_128b_132b_ENCODING)
1283 DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n"
1284 " 0x%X TX_FFE_PRESET_VALUE = %x\n",
1285 __func__,
1286 offset,
1287 dpcd_base_lt_offset,
1288 lt_settings->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE);
1289 else if (link_dp_get_encoding_format(<_settings->link_settings) ==
1290 DP_8b_10b_ENCODING)
1291 DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n"
1292 " 0x%X VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n",
1293 __func__,
1294 offset,
1295 dpcd_base_lt_offset,
1296 lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET,
1297 lt_settings->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET,
1298 lt_settings->dpcd_lane_settings[0].bits.MAX_SWING_REACHED,
1299 lt_settings->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED);
1300 } else {
1301 if (link_dp_get_encoding_format(<_settings->link_settings) ==
1302 DP_128b_132b_ENCODING)
1303 DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X TX_FFE_PRESET_VALUE = %x\n",
1304 __func__,
1305 dpcd_base_lt_offset,
1306 lt_settings->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE);
1307 else if (link_dp_get_encoding_format(<_settings->link_settings) ==
1308 DP_8b_10b_ENCODING)
1309 DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n",
1310 __func__,
1311 dpcd_base_lt_offset,
1312 lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET,
1313 lt_settings->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET,
1314 lt_settings->dpcd_lane_settings[0].bits.MAX_SWING_REACHED,
1315 lt_settings->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED);
1316 }
1317 if (edp_workaround) {
1318 /* for eDP write in 2 parts because the 5-byte burst is
1319 * causing issues on some eDP panels (EPR#366724)
1320 */
1321 core_link_write_dpcd(
1322 link,
1323 DP_TRAINING_PATTERN_SET,
1324 &dpcd_pattern.raw,
1325 sizeof(dpcd_pattern.raw));
1326
1327 core_link_write_dpcd(
1328 link,
1329 DP_TRAINING_LANE0_SET,
1330 (uint8_t *)(lt_settings->dpcd_lane_settings),
1331 size_in_bytes);
1332
1333 } else if (link_dp_get_encoding_format(<_settings->link_settings) ==
1334 DP_128b_132b_ENCODING) {
1335 core_link_write_dpcd(
1336 link,
1337 dpcd_base_lt_offset,
1338 dpcd_lt_buffer,
1339 sizeof(dpcd_lt_buffer));
1340 } else
1341 /* write it all in (1 + number-of-lanes)-byte burst*/
1342 core_link_write_dpcd(
1343 link,
1344 dpcd_base_lt_offset,
1345 dpcd_lt_buffer,
1346 size_in_bytes + sizeof(dpcd_pattern.raw));
1347 }
1348
start_clock_recovery_pattern_early(struct dc_link * link,const struct link_resource * link_res,struct link_training_settings * lt_settings,uint32_t offset)1349 void start_clock_recovery_pattern_early(struct dc_link *link,
1350 const struct link_resource *link_res,
1351 struct link_training_settings *lt_settings,
1352 uint32_t offset)
1353 {
1354 DC_LOG_HW_LINK_TRAINING("%s\n GPU sends TPS1. Wait 400us.\n",
1355 __func__);
1356 dp_set_hw_training_pattern(link, link_res, lt_settings->pattern_for_cr, offset);
1357 dp_set_hw_lane_settings(link, link_res, lt_settings, offset);
1358 udelay(400);
1359 }
1360
dp_set_hw_test_pattern(struct dc_link * link,const struct link_resource * link_res,enum dp_test_pattern test_pattern,uint8_t * custom_pattern,uint32_t custom_pattern_size)1361 void dp_set_hw_test_pattern(
1362 struct dc_link *link,
1363 const struct link_resource *link_res,
1364 enum dp_test_pattern test_pattern,
1365 uint8_t *custom_pattern,
1366 uint32_t custom_pattern_size)
1367 {
1368 const struct link_hwss *link_hwss = get_link_hwss(link, link_res);
1369 struct encoder_set_dp_phy_pattern_param pattern_param = {0};
1370
1371 pattern_param.dp_phy_pattern = test_pattern;
1372 pattern_param.custom_pattern = custom_pattern;
1373 pattern_param.custom_pattern_size = custom_pattern_size;
1374 pattern_param.dp_panel_mode = dp_get_panel_mode(link);
1375
1376 if (link_hwss->ext.set_dp_link_test_pattern)
1377 link_hwss->ext.set_dp_link_test_pattern(link, link_res, &pattern_param);
1378 }
1379
dp_set_hw_training_pattern(struct dc_link * link,const struct link_resource * link_res,enum dc_dp_training_pattern pattern,uint32_t offset)1380 bool dp_set_hw_training_pattern(
1381 struct dc_link *link,
1382 const struct link_resource *link_res,
1383 enum dc_dp_training_pattern pattern,
1384 uint32_t offset)
1385 {
1386 enum dp_test_pattern test_pattern = DP_TEST_PATTERN_UNSUPPORTED;
1387
1388 switch (pattern) {
1389 case DP_TRAINING_PATTERN_SEQUENCE_1:
1390 test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN1;
1391 break;
1392 case DP_TRAINING_PATTERN_SEQUENCE_2:
1393 test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN2;
1394 break;
1395 case DP_TRAINING_PATTERN_SEQUENCE_3:
1396 test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN3;
1397 break;
1398 case DP_TRAINING_PATTERN_SEQUENCE_4:
1399 test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN4;
1400 break;
1401 case DP_128b_132b_TPS1:
1402 test_pattern = DP_TEST_PATTERN_128b_132b_TPS1_TRAINING_MODE;
1403 break;
1404 case DP_128b_132b_TPS2:
1405 test_pattern = DP_TEST_PATTERN_128b_132b_TPS2_TRAINING_MODE;
1406 break;
1407 default:
1408 break;
1409 }
1410
1411 dp_set_hw_test_pattern(link, link_res, test_pattern, NULL, 0);
1412
1413 return true;
1414 }
1415
perform_post_lt_adj_req_sequence(struct dc_link * link,const struct link_resource * link_res,struct link_training_settings * lt_settings)1416 static bool perform_post_lt_adj_req_sequence(
1417 struct dc_link *link,
1418 const struct link_resource *link_res,
1419 struct link_training_settings *lt_settings)
1420 {
1421 enum dc_lane_count lane_count =
1422 lt_settings->link_settings.lane_count;
1423
1424 uint32_t adj_req_count;
1425 uint32_t adj_req_timer;
1426 bool req_drv_setting_changed;
1427 uint32_t lane;
1428 union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
1429 union lane_align_status_updated dpcd_lane_status_updated = {0};
1430 union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
1431
1432 req_drv_setting_changed = false;
1433 for (adj_req_count = 0; adj_req_count < POST_LT_ADJ_REQ_LIMIT;
1434 adj_req_count++) {
1435
1436 req_drv_setting_changed = false;
1437
1438 for (adj_req_timer = 0;
1439 adj_req_timer < POST_LT_ADJ_REQ_TIMEOUT;
1440 adj_req_timer++) {
1441
1442 dp_get_lane_status_and_lane_adjust(
1443 link,
1444 lt_settings,
1445 dpcd_lane_status,
1446 &dpcd_lane_status_updated,
1447 dpcd_lane_adjust,
1448 DPRX);
1449
1450 if (dpcd_lane_status_updated.bits.
1451 POST_LT_ADJ_REQ_IN_PROGRESS == 0)
1452 return true;
1453
1454 if (!dp_is_cr_done(lane_count, dpcd_lane_status))
1455 return false;
1456
1457 if (!dp_is_ch_eq_done(lane_count, dpcd_lane_status) ||
1458 !dp_is_symbol_locked(lane_count, dpcd_lane_status) ||
1459 !dp_is_interlane_aligned(dpcd_lane_status_updated))
1460 return false;
1461
1462 for (lane = 0; lane < (uint32_t)(lane_count); lane++) {
1463
1464 if (lt_settings->
1465 dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET !=
1466 dpcd_lane_adjust[lane].bits.VOLTAGE_SWING_LANE ||
1467 lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET !=
1468 dpcd_lane_adjust[lane].bits.PRE_EMPHASIS_LANE) {
1469
1470 req_drv_setting_changed = true;
1471 break;
1472 }
1473 }
1474
1475 if (req_drv_setting_changed) {
1476 dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
1477 lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
1478
1479 dp_set_drive_settings(link,
1480 link_res,
1481 lt_settings);
1482 break;
1483 }
1484
1485 msleep(1);
1486 }
1487
1488 if (!req_drv_setting_changed) {
1489 DC_LOG_WARNING("%s: Post Link Training Adjust Request Timed out\n",
1490 __func__);
1491
1492 ASSERT(0);
1493 return true;
1494 }
1495 }
1496 DC_LOG_WARNING("%s: Post Link Training Adjust Request limit reached\n",
1497 __func__);
1498
1499 ASSERT(0);
1500 return true;
1501
1502 }
1503
dp_transition_to_video_idle(struct dc_link * link,const struct link_resource * link_res,struct link_training_settings * lt_settings,enum link_training_result status)1504 static enum link_training_result dp_transition_to_video_idle(
1505 struct dc_link *link,
1506 const struct link_resource *link_res,
1507 struct link_training_settings *lt_settings,
1508 enum link_training_result status)
1509 {
1510 union lane_count_set lane_count_set = {0};
1511
1512 /* 4. mainlink output idle pattern*/
1513 dp_set_hw_test_pattern(link, link_res, DP_TEST_PATTERN_VIDEO_MODE, NULL, 0);
1514
1515 /*
1516 * 5. post training adjust if required
1517 * If the upstream DPTX and downstream DPRX both support TPS4,
1518 * TPS4 must be used instead of POST_LT_ADJ_REQ.
1519 */
1520 if (link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED != 1 ||
1521 lt_settings->pattern_for_eq >= DP_TRAINING_PATTERN_SEQUENCE_4) {
1522 /* delay 5ms after Main Link output idle pattern and then check
1523 * DPCD 0202h.
1524 */
1525 if (link->connector_signal != SIGNAL_TYPE_EDP && status == LINK_TRAINING_SUCCESS) {
1526 msleep(5);
1527 if (!link->skip_fallback_on_link_loss)
1528 status = dp_check_link_loss_status(link, lt_settings);
1529 }
1530 return status;
1531 }
1532
1533 if (status == LINK_TRAINING_SUCCESS &&
1534 perform_post_lt_adj_req_sequence(link, link_res, lt_settings) == false)
1535 status = LINK_TRAINING_LQA_FAIL;
1536
1537 lane_count_set.bits.LANE_COUNT_SET = lt_settings->link_settings.lane_count;
1538 lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing;
1539 lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0;
1540
1541 core_link_write_dpcd(
1542 link,
1543 DP_LANE_COUNT_SET,
1544 &lane_count_set.raw,
1545 sizeof(lane_count_set));
1546
1547 return status;
1548 }
1549
dp_perform_link_training(struct dc_link * link,const struct link_resource * link_res,const struct dc_link_settings * link_settings,bool skip_video_pattern)1550 enum link_training_result dp_perform_link_training(
1551 struct dc_link *link,
1552 const struct link_resource *link_res,
1553 const struct dc_link_settings *link_settings,
1554 bool skip_video_pattern)
1555 {
1556 enum link_training_result status = LINK_TRAINING_SUCCESS;
1557 struct link_training_settings lt_settings = {0};
1558 enum dp_link_encoding encoding =
1559 link_dp_get_encoding_format(link_settings);
1560
1561 /* decide training settings */
1562 dp_decide_training_settings(
1563 link,
1564 link_res,
1565 link_settings,
1566 <_settings);
1567
1568 override_training_settings(
1569 link,
1570 &link->preferred_training_settings,
1571 <_settings);
1572
1573 /* reset previous training states */
1574 dpcd_exit_training_mode(link, encoding);
1575
1576 /* configure link prior to entering training mode */
1577 dpcd_configure_lttpr_mode(link, <_settings);
1578 if (link_dp_get_encoding_format(link_settings) == DP_8b_10b_ENCODING)
1579 dp_set_fec_ready(link, link_res, lt_settings.should_set_fec_ready);
1580 dpcd_configure_channel_coding(link, <_settings);
1581
1582 /* enter training mode:
1583 * Per DP specs starting from here, DPTX device shall not issue
1584 * Non-LT AUX transactions inside training mode.
1585 */
1586 if (((link->chip_caps & AMD_EXT_DISPLAY_PATH_CAPS__EXT_CHIP_MASK) == AMD_EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) && encoding == DP_8b_10b_ENCODING)
1587 status = dp_perform_fixed_vs_pe_training_sequence(link, link_res, <_settings);
1588 else if (encoding == DP_8b_10b_ENCODING)
1589 status = dp_perform_8b_10b_link_training(link, link_res, <_settings);
1590 else if (encoding == DP_128b_132b_ENCODING)
1591 status = dp_perform_128b_132b_link_training(link, link_res, <_settings);
1592 else
1593 ASSERT(0);
1594
1595 /* exit training mode */
1596 if ((dpcd_exit_training_mode(link, encoding) != LINK_TRAINING_SUCCESS || status == LINK_TRAINING_ABORT) &&
1597 link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA)
1598 dpia_training_abort(link, <_settings, 0);
1599
1600 /* switch to video idle */
1601 if ((status == LINK_TRAINING_SUCCESS) || !skip_video_pattern)
1602 status = dp_transition_to_video_idle(link,
1603 link_res,
1604 <_settings,
1605 status);
1606
1607 /* dump debug data */
1608 dp_log_training_result(link, <_settings, status);
1609 if (status != LINK_TRAINING_SUCCESS)
1610 link->ctx->dc->debug_data.ltFailCount++;
1611 return status;
1612 }
1613
perform_link_training_with_retries(const struct dc_link_settings * link_setting,bool skip_video_pattern,int attempts,struct pipe_ctx * pipe_ctx,enum signal_type signal,bool do_fallback)1614 bool perform_link_training_with_retries(
1615 const struct dc_link_settings *link_setting,
1616 bool skip_video_pattern,
1617 int attempts,
1618 struct pipe_ctx *pipe_ctx,
1619 enum signal_type signal,
1620 bool do_fallback)
1621 {
1622 int j;
1623 uint8_t delay_between_attempts = LINK_TRAINING_RETRY_DELAY;
1624 struct dc_stream_state *stream = pipe_ctx->stream;
1625 struct dc_link *link = stream->link;
1626 enum dp_panel_mode panel_mode = dp_get_panel_mode(link);
1627 enum link_training_result status = LINK_TRAINING_CR_FAIL_LANE0;
1628 struct dc_link_settings cur_link_settings = *link_setting;
1629 struct dc_link_settings max_link_settings = *link_setting;
1630 const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
1631 int fail_count = 0;
1632 bool is_link_bw_low = false; /* link bandwidth < stream bandwidth */
1633 bool is_link_bw_min = /* RBR x 1 */
1634 (cur_link_settings.link_rate <= LINK_RATE_LOW) &&
1635 (cur_link_settings.lane_count <= LANE_COUNT_ONE);
1636
1637 dp_trace_commit_lt_init(link);
1638
1639
1640 if (link_dp_get_encoding_format(&cur_link_settings) == DP_8b_10b_ENCODING)
1641 /* We need to do this before the link training to ensure the idle
1642 * pattern in SST mode will be sent right after the link training
1643 */
1644 link_hwss->setup_stream_encoder(pipe_ctx);
1645
1646 dp_trace_set_lt_start_timestamp(link, false);
1647 j = 0;
1648 while (j < attempts && fail_count < (attempts * 10)) {
1649
1650 DC_LOG_HW_LINK_TRAINING("%s: Beginning link(%d) training attempt %u of %d @ rate(%d) x lane(%d) @ spread = %x\n",
1651 __func__, link->link_index, (unsigned int)j + 1, attempts,
1652 cur_link_settings.link_rate, cur_link_settings.lane_count,
1653 cur_link_settings.link_spread);
1654
1655 dp_enable_link_phy(
1656 link,
1657 &pipe_ctx->link_res,
1658 signal,
1659 pipe_ctx->clock_source->id,
1660 &cur_link_settings);
1661
1662 if (stream->sink_patches.dppowerup_delay > 0) {
1663 int delay_dp_power_up_in_ms = stream->sink_patches.dppowerup_delay;
1664
1665 msleep(delay_dp_power_up_in_ms);
1666 }
1667
1668 edp_set_panel_assr(link, pipe_ctx, &panel_mode, true);
1669
1670 dp_set_panel_mode(link, panel_mode);
1671
1672 if (link->aux_access_disabled) {
1673 dp_perform_link_training_skip_aux(link, &pipe_ctx->link_res, &cur_link_settings);
1674 return true;
1675 } else {
1676 if (!link->dc->config.consolidated_dpia_dp_lt && link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) {
1677 status = dpia_perform_link_training(
1678 link,
1679 &pipe_ctx->link_res,
1680 &cur_link_settings,
1681 skip_video_pattern);
1682
1683 /* Transmit idle pattern once training successful. */
1684 if (status == LINK_TRAINING_SUCCESS && !is_link_bw_low) {
1685 dp_set_hw_test_pattern(link, &pipe_ctx->link_res, DP_TEST_PATTERN_VIDEO_MODE, NULL, 0);
1686 // Update verified link settings to current one
1687 // Because DPIA LT might fallback to lower link setting.
1688 if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
1689 link->verified_link_cap.link_rate = link->cur_link_settings.link_rate;
1690 link->verified_link_cap.lane_count = link->cur_link_settings.lane_count;
1691 dm_helpers_dp_mst_update_branch_bandwidth(link->ctx, link);
1692 }
1693 }
1694 } else {
1695 status = dp_perform_link_training(
1696 link,
1697 &pipe_ctx->link_res,
1698 &cur_link_settings,
1699 skip_video_pattern);
1700 }
1701
1702 dp_trace_lt_total_count_increment(link, false);
1703 dp_trace_lt_result_update(link, status, false);
1704 dp_trace_set_lt_end_timestamp(link, false);
1705 if (status == LINK_TRAINING_SUCCESS && !is_link_bw_low) {
1706 // Update verified link settings to current one
1707 // Because DPIA LT might fallback to lower link setting.
1708 if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA &&
1709 stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
1710 link->verified_link_cap.link_rate = link->cur_link_settings.link_rate;
1711 link->verified_link_cap.lane_count = link->cur_link_settings.lane_count;
1712 dm_helpers_dp_mst_update_branch_bandwidth(link->ctx, link);
1713 }
1714 return true;
1715 }
1716 }
1717
1718 fail_count++;
1719 dp_trace_lt_fail_count_update(link, fail_count, false);
1720 if (link->ep_type == DISPLAY_ENDPOINT_PHY) {
1721 /* latest link training still fail or link training is aborted
1722 * skip delay and keep PHY on
1723 */
1724 if (j == (attempts - 1) || (status == LINK_TRAINING_ABORT))
1725 break;
1726 }
1727
1728 if (j == (attempts - 1)) {
1729 DC_LOG_WARNING(
1730 "%s: Link(%d) training attempt %u of %d failed @ rate(%d) x lane(%d) @ spread = %x : fail reason:(%d)\n",
1731 __func__, link->link_index, (unsigned int)j + 1, attempts,
1732 cur_link_settings.link_rate, cur_link_settings.lane_count,
1733 cur_link_settings.link_spread, status);
1734 } else {
1735 DC_LOG_HW_LINK_TRAINING(
1736 "%s: Link(%d) training attempt %u of %d failed @ rate(%d) x lane(%d) @ spread = %x : fail reason:(%d)\n",
1737 __func__, link->link_index, (unsigned int)j + 1, attempts,
1738 cur_link_settings.link_rate, cur_link_settings.lane_count,
1739 cur_link_settings.link_spread, status);
1740 }
1741
1742 dp_disable_link_phy(link, &pipe_ctx->link_res, signal);
1743
1744 /* Abort link training if failure due to sink being unplugged. */
1745 if (status == LINK_TRAINING_ABORT) {
1746 enum dc_connection_type type = dc_connection_none;
1747
1748 if (link_detect_connection_type(link, &type) && type == dc_connection_none) {
1749 DC_LOG_HW_LINK_TRAINING("%s: Aborting training because sink unplugged\n", __func__);
1750 break;
1751 }
1752 }
1753
1754 /* Try to train again at original settings if:
1755 * - not falling back between training attempts;
1756 * - aborted previous attempt due to reasons other than sink unplug;
1757 * - successfully trained but at a link rate lower than that required by stream;
1758 * - reached minimum link bandwidth.
1759 */
1760 if (!do_fallback || (status == LINK_TRAINING_ABORT) ||
1761 (status == LINK_TRAINING_SUCCESS && is_link_bw_low) ||
1762 is_link_bw_min) {
1763 j++;
1764 cur_link_settings = *link_setting;
1765 delay_between_attempts += LINK_TRAINING_RETRY_DELAY;
1766 is_link_bw_low = false;
1767 is_link_bw_min = (cur_link_settings.link_rate <= LINK_RATE_LOW) &&
1768 (cur_link_settings.lane_count <= LANE_COUNT_ONE);
1769
1770 } else if (do_fallback) { /* Try training at lower link bandwidth if doing fallback. */
1771 uint32_t req_bw;
1772 uint32_t link_bw;
1773 enum dc_link_encoding_format link_encoding = DC_LINK_ENCODING_UNSPECIFIED;
1774
1775 decide_fallback_link_setting(link, &max_link_settings,
1776 &cur_link_settings, status);
1777
1778 if (link_dp_get_encoding_format(&cur_link_settings) == DP_8b_10b_ENCODING)
1779 link_encoding = DC_LINK_ENCODING_DP_8b_10b;
1780 else if (link_dp_get_encoding_format(&cur_link_settings) == DP_128b_132b_ENCODING)
1781 link_encoding = DC_LINK_ENCODING_DP_128b_132b;
1782
1783 /* Flag if reduced link bandwidth no longer meets stream requirements or fallen back to
1784 * minimum link bandwidth.
1785 */
1786 req_bw = dc_bandwidth_in_kbps_from_timing(&stream->timing, link_encoding);
1787 link_bw = dp_link_bandwidth_kbps(link, &cur_link_settings);
1788 is_link_bw_low = (req_bw > link_bw);
1789 is_link_bw_min = ((cur_link_settings.link_rate <= LINK_RATE_LOW) &&
1790 (cur_link_settings.lane_count <= LANE_COUNT_ONE));
1791
1792 if (is_link_bw_low)
1793 DC_LOG_WARNING(
1794 "%s: Link(%d) bandwidth too low after fallback req_bw(%d) > link_bw(%d)\n",
1795 __func__, link->link_index, req_bw, link_bw);
1796 }
1797
1798 msleep(delay_between_attempts);
1799 }
1800
1801 return false;
1802 }
1803
1804