]> Git Repo - linux.git/blob - drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c
Linux 6.14-rc3
[linux.git] / drivers / gpu / drm / amd / display / dc / link / protocols / link_dp_training.c
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
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
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
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
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
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
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
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
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(&lt_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(&lt_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
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 */
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 (overrides->ffe_preset != NULL)
740                 lt_settings->ffe_preset = overrides->ffe_preset;
741         /* Override HW lane settings with BIOS forced values if present */
742         if ((link->chip_caps & AMD_EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) &&
743                         lt_settings->lttpr_mode == LTTPR_MODE_TRANSPARENT) {
744                 lt_settings->voltage_swing = &link->bios_forced_drive_settings.VOLTAGE_SWING;
745                 lt_settings->pre_emphasis = &link->bios_forced_drive_settings.PRE_EMPHASIS;
746                 lt_settings->always_match_dpcd_with_hw_lane_settings = false;
747         }
748         for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
749                 lt_settings->hw_lane_settings[lane].VOLTAGE_SWING =
750                         lt_settings->voltage_swing != NULL ?
751                         *lt_settings->voltage_swing :
752                         VOLTAGE_SWING_LEVEL0;
753                 lt_settings->hw_lane_settings[lane].PRE_EMPHASIS =
754                         lt_settings->pre_emphasis != NULL ?
755                         *lt_settings->pre_emphasis
756                         : PRE_EMPHASIS_DISABLED;
757                 lt_settings->hw_lane_settings[lane].POST_CURSOR2 =
758                         lt_settings->post_cursor2 != NULL ?
759                         *lt_settings->post_cursor2
760                         : POST_CURSOR2_DISABLED;
761         }
762
763         if (lt_settings->always_match_dpcd_with_hw_lane_settings)
764                 dp_hw_to_dpcd_lane_settings(lt_settings,
765                                 lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
766
767         /* Override training timings */
768         if (overrides->cr_pattern_time != NULL)
769                 lt_settings->cr_pattern_time = *overrides->cr_pattern_time;
770         if (overrides->eq_pattern_time != NULL)
771                 lt_settings->eq_pattern_time = *overrides->eq_pattern_time;
772         if (overrides->pattern_for_cr != NULL)
773                 lt_settings->pattern_for_cr = *overrides->pattern_for_cr;
774         if (overrides->pattern_for_eq != NULL)
775                 lt_settings->pattern_for_eq = *overrides->pattern_for_eq;
776         if (overrides->enhanced_framing != NULL)
777                 lt_settings->enhanced_framing = *overrides->enhanced_framing;
778         if (link->preferred_training_settings.fec_enable != NULL)
779                 lt_settings->should_set_fec_ready = *link->preferred_training_settings.fec_enable;
780
781         /* Check DP tunnel LTTPR mode debug option. */
782         if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA && link->dc->debug.dpia_debug.bits.force_non_lttpr)
783                 lt_settings->lttpr_mode = LTTPR_MODE_NON_LTTPR;
784
785         dp_get_lttpr_mode_override(link, &lt_settings->lttpr_mode);
786
787 }
788
789 enum dc_dp_training_pattern decide_cr_training_pattern(
790                 const struct dc_link_settings *link_settings)
791 {
792         switch (link_dp_get_encoding_format(link_settings)) {
793         case DP_8b_10b_ENCODING:
794         default:
795                 return DP_TRAINING_PATTERN_SEQUENCE_1;
796         case DP_128b_132b_ENCODING:
797                 return DP_128b_132b_TPS1;
798         }
799 }
800
801 enum dc_dp_training_pattern decide_eq_training_pattern(struct dc_link *link,
802                 const struct dc_link_settings *link_settings)
803 {
804         struct link_encoder *link_enc;
805         struct encoder_feature_support *enc_caps;
806         struct dpcd_caps *rx_caps = &link->dpcd_caps;
807         enum dc_dp_training_pattern pattern = DP_TRAINING_PATTERN_SEQUENCE_2;
808
809         link_enc = link_enc_cfg_get_link_enc(link);
810         ASSERT(link_enc);
811         enc_caps = &link_enc->features;
812
813         switch (link_dp_get_encoding_format(link_settings)) {
814         case DP_8b_10b_ENCODING:
815                 if (enc_caps->flags.bits.IS_TPS4_CAPABLE &&
816                                 rx_caps->max_down_spread.bits.TPS4_SUPPORTED)
817                         pattern = DP_TRAINING_PATTERN_SEQUENCE_4;
818                 else if (enc_caps->flags.bits.IS_TPS3_CAPABLE &&
819                                 rx_caps->max_ln_count.bits.TPS3_SUPPORTED)
820                         pattern = DP_TRAINING_PATTERN_SEQUENCE_3;
821                 else
822                         pattern = DP_TRAINING_PATTERN_SEQUENCE_2;
823                 break;
824         case DP_128b_132b_ENCODING:
825                 pattern = DP_128b_132b_TPS2;
826                 break;
827         default:
828                 pattern = DP_TRAINING_PATTERN_SEQUENCE_2;
829                 break;
830         }
831         return pattern;
832 }
833
834 enum lttpr_mode dp_decide_lttpr_mode(struct dc_link *link,
835                 struct dc_link_settings *link_setting)
836 {
837         enum dp_link_encoding encoding = link_dp_get_encoding_format(link_setting);
838
839         if (encoding == DP_8b_10b_ENCODING)
840                 return dp_decide_8b_10b_lttpr_mode(link);
841         else if (encoding == DP_128b_132b_ENCODING)
842                 return dp_decide_128b_132b_lttpr_mode(link);
843
844         ASSERT(0);
845         return LTTPR_MODE_NON_LTTPR;
846 }
847
848 void dp_decide_lane_settings(
849                 const struct link_training_settings *lt_settings,
850                 const union lane_adjust ln_adjust[LANE_COUNT_DP_MAX],
851                 struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX],
852                 union dpcd_training_lane *dpcd_lane_settings)
853 {
854         uint32_t lane;
855
856         for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
857                 if (link_dp_get_encoding_format(&lt_settings->link_settings) ==
858                                 DP_8b_10b_ENCODING) {
859                         hw_lane_settings[lane].VOLTAGE_SWING =
860                                         (enum dc_voltage_swing)(ln_adjust[lane].bits.
861                                                         VOLTAGE_SWING_LANE);
862                         hw_lane_settings[lane].PRE_EMPHASIS =
863                                         (enum dc_pre_emphasis)(ln_adjust[lane].bits.
864                                                         PRE_EMPHASIS_LANE);
865                 } else if (link_dp_get_encoding_format(&lt_settings->link_settings) ==
866                                 DP_128b_132b_ENCODING) {
867                         hw_lane_settings[lane].FFE_PRESET.raw =
868                                         ln_adjust[lane].tx_ffe.PRESET_VALUE;
869                 }
870         }
871         dp_hw_to_dpcd_lane_settings(lt_settings, hw_lane_settings, dpcd_lane_settings);
872
873         if (lt_settings->disallow_per_lane_settings) {
874                 /* we find the maximum of the requested settings across all lanes*/
875                 /* and set this maximum for all lanes*/
876                 maximize_lane_settings(lt_settings, hw_lane_settings);
877                 override_lane_settings(lt_settings, hw_lane_settings);
878
879                 if (lt_settings->always_match_dpcd_with_hw_lane_settings)
880                         dp_hw_to_dpcd_lane_settings(lt_settings, hw_lane_settings, dpcd_lane_settings);
881         }
882
883 }
884
885 void dp_decide_training_settings(
886                 struct dc_link *link,
887                 const struct dc_link_settings *link_settings,
888                 struct link_training_settings *lt_settings)
889 {
890         if (link_dp_get_encoding_format(link_settings) == DP_8b_10b_ENCODING)
891                 decide_8b_10b_training_settings(link, link_settings, lt_settings);
892         else if (link_dp_get_encoding_format(link_settings) == DP_128b_132b_ENCODING)
893                 decide_128b_132b_training_settings(link, link_settings, lt_settings);
894 }
895
896
897 enum dc_status configure_lttpr_mode_transparent(struct dc_link *link)
898 {
899         uint8_t repeater_mode = DP_PHY_REPEATER_MODE_TRANSPARENT;
900
901         DC_LOG_HW_LINK_TRAINING("%s\n Set LTTPR to Transparent Mode\n", __func__);
902         return core_link_write_dpcd(link,
903                         DP_PHY_REPEATER_MODE,
904                         (uint8_t *)&repeater_mode,
905                         sizeof(repeater_mode));
906 }
907
908 static enum dc_status configure_lttpr_mode_non_transparent(
909                 struct dc_link *link,
910                 const struct link_training_settings *lt_settings)
911 {
912         /* aux timeout is already set to extended */
913         /* RESET/SET lttpr mode to enable non transparent mode */
914         uint8_t repeater_cnt;
915         uint32_t aux_interval_address;
916         uint8_t repeater_id;
917         enum dc_status result = DC_ERROR_UNEXPECTED;
918         uint8_t repeater_mode = DP_PHY_REPEATER_MODE_TRANSPARENT;
919         const struct dc *dc = link->dc;
920
921         enum dp_link_encoding encoding = dc->link_srv->dp_get_encoding_format(&lt_settings->link_settings);
922
923         if (encoding == DP_8b_10b_ENCODING) {
924                 DC_LOG_HW_LINK_TRAINING("%s\n Set LTTPR to Transparent Mode\n", __func__);
925                 result = core_link_write_dpcd(link,
926                                 DP_PHY_REPEATER_MODE,
927                                 (uint8_t *)&repeater_mode,
928                                 sizeof(repeater_mode));
929
930         }
931
932         if (result == DC_OK) {
933                 link->dpcd_caps.lttpr_caps.mode = repeater_mode;
934         }
935
936         if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) {
937
938                 DC_LOG_HW_LINK_TRAINING("%s\n Set LTTPR to Non Transparent Mode\n", __func__);
939
940                 repeater_mode = DP_PHY_REPEATER_MODE_NON_TRANSPARENT;
941                 result = core_link_write_dpcd(link,
942                                 DP_PHY_REPEATER_MODE,
943                                 (uint8_t *)&repeater_mode,
944                                 sizeof(repeater_mode));
945
946                 if (result == DC_OK) {
947                         link->dpcd_caps.lttpr_caps.mode = repeater_mode;
948                 }
949
950                 if (encoding == DP_8b_10b_ENCODING) {
951                         repeater_cnt = dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
952
953                         /* Driver does not need to train the first hop. Skip DPCD read and clear
954                          * AUX_RD_INTERVAL for DPTX-to-DPIA hop.
955                          */
956                         if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA && repeater_cnt > 0 && repeater_cnt < MAX_REPEATER_CNT)
957                                 link->dpcd_caps.lttpr_caps.aux_rd_interval[--repeater_cnt] = 0;
958
959                         for (repeater_id = repeater_cnt; repeater_id > 0 && repeater_id < MAX_REPEATER_CNT; repeater_id--) {
960                                 aux_interval_address = DP_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER1 +
961                                                 ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (repeater_id - 1));
962                                 core_link_read_dpcd(
963                                                 link,
964                                                 aux_interval_address,
965                                                 (uint8_t *)&link->dpcd_caps.lttpr_caps.aux_rd_interval[repeater_id - 1],
966                                                 sizeof(link->dpcd_caps.lttpr_caps.aux_rd_interval[repeater_id - 1]));
967                                 link->dpcd_caps.lttpr_caps.aux_rd_interval[repeater_id - 1] &= 0x7F;
968                         }
969                 }
970         }
971
972         return result;
973 }
974
975 enum dc_status dpcd_configure_lttpr_mode(struct dc_link *link, struct link_training_settings *lt_settings)
976 {
977         enum dc_status status = DC_OK;
978
979         if (lt_settings->lttpr_mode == LTTPR_MODE_TRANSPARENT)
980                 status = configure_lttpr_mode_transparent(link);
981
982         else if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT)
983                 status = configure_lttpr_mode_non_transparent(link, lt_settings);
984
985         return status;
986 }
987
988 void repeater_training_done(struct dc_link *link, uint32_t offset)
989 {
990         union dpcd_training_pattern dpcd_pattern = {0};
991
992         const uint32_t dpcd_base_lt_offset =
993                         DP_TRAINING_PATTERN_SET_PHY_REPEATER1 +
994                                 ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
995         /* Set training not in progress*/
996         dpcd_pattern.v1_4.TRAINING_PATTERN_SET = DPCD_TRAINING_PATTERN_VIDEOIDLE;
997
998         core_link_write_dpcd(
999                 link,
1000                 dpcd_base_lt_offset,
1001                 &dpcd_pattern.raw,
1002                 1);
1003
1004         DC_LOG_HW_LINK_TRAINING("%s\n LTTPR Id: %d 0x%X pattern = %x\n",
1005                 __func__,
1006                 offset,
1007                 dpcd_base_lt_offset,
1008                 dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
1009 }
1010
1011 static enum link_training_result dpcd_exit_training_mode(struct dc_link *link, enum dp_link_encoding encoding)
1012 {
1013         enum dc_status status;
1014         uint8_t sink_status = 0;
1015         uint8_t i;
1016
1017         /* clear training pattern set */
1018         status = dpcd_set_training_pattern(link, DP_TRAINING_PATTERN_VIDEOIDLE);
1019
1020         if (dp_check_dpcd_reqeust_status(link, status))
1021                 return LINK_TRAINING_ABORT;
1022
1023         if (encoding == DP_128b_132b_ENCODING) {
1024                 /* poll for intra-hop disable */
1025                 for (i = 0; i < 10; i++) {
1026                         if ((core_link_read_dpcd(link, DP_SINK_STATUS, &sink_status, 1) == DC_OK) &&
1027                                         (sink_status & DP_INTRA_HOP_AUX_REPLY_INDICATION) == 0)
1028                                 break;
1029                         fsleep(1000);
1030                 }
1031         }
1032
1033         return LINK_TRAINING_SUCCESS;
1034 }
1035
1036 enum dc_status dpcd_configure_channel_coding(struct dc_link *link,
1037                 struct link_training_settings *lt_settings)
1038 {
1039         enum dp_link_encoding encoding =
1040                         link_dp_get_encoding_format(
1041                                         &lt_settings->link_settings);
1042         enum dc_status status;
1043
1044         status = core_link_write_dpcd(
1045                         link,
1046                         DP_MAIN_LINK_CHANNEL_CODING_SET,
1047                         (uint8_t *) &encoding,
1048                         1);
1049         DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X MAIN_LINK_CHANNEL_CODING_SET = %x\n",
1050                                         __func__,
1051                                         DP_MAIN_LINK_CHANNEL_CODING_SET,
1052                                         encoding);
1053
1054         return status;
1055 }
1056
1057 enum dc_status dpcd_set_training_pattern(
1058         struct dc_link *link,
1059         enum dc_dp_training_pattern training_pattern)
1060 {
1061         enum dc_status status;
1062         union dpcd_training_pattern dpcd_pattern = {0};
1063
1064         dpcd_pattern.v1_4.TRAINING_PATTERN_SET =
1065                         dp_training_pattern_to_dpcd_training_pattern(
1066                                         link, training_pattern);
1067
1068         status = core_link_write_dpcd(
1069                 link,
1070                 DP_TRAINING_PATTERN_SET,
1071                 &dpcd_pattern.raw,
1072                 1);
1073
1074         DC_LOG_HW_LINK_TRAINING("%s\n %x pattern = %x\n",
1075                 __func__,
1076                 DP_TRAINING_PATTERN_SET,
1077                 dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
1078
1079         return status;
1080 }
1081
1082 enum dc_status dpcd_set_link_settings(
1083         struct dc_link *link,
1084         const struct link_training_settings *lt_settings)
1085 {
1086         uint8_t rate;
1087         enum dc_status status;
1088
1089         union down_spread_ctrl downspread = {0};
1090         union lane_count_set lane_count_set = {0};
1091
1092         downspread.raw = (uint8_t)
1093         (lt_settings->link_settings.link_spread);
1094
1095         lane_count_set.bits.LANE_COUNT_SET =
1096         lt_settings->link_settings.lane_count;
1097
1098         lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing;
1099         lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0;
1100
1101
1102         if (link->ep_type == DISPLAY_ENDPOINT_PHY &&
1103                         lt_settings->pattern_for_eq < DP_TRAINING_PATTERN_SEQUENCE_4) {
1104                 lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED =
1105                                 link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED;
1106         }
1107
1108         status = core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL,
1109                 &downspread.raw, sizeof(downspread));
1110         if (status != DC_OK)
1111                 DC_LOG_ERROR("%s:%d: core_link_write_dpcd (DP_DOWNSPREAD_CTRL) failed\n", __func__, __LINE__);
1112
1113         status = core_link_write_dpcd(link, DP_LANE_COUNT_SET,
1114                 &lane_count_set.raw, 1);
1115         if (status != DC_OK)
1116                 DC_LOG_ERROR("%s:%d: core_link_write_dpcd (DP_LANE_COUNT_SET) failed\n", __func__, __LINE__);
1117
1118         if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_13 &&
1119                         lt_settings->link_settings.use_link_rate_set == true) {
1120                 rate = 0;
1121                 /* WA for some MUX chips that will power down with eDP and lose supported
1122                  * link rate set for eDP 1.4. Source reads DPCD 0x010 again to ensure
1123                  * MUX chip gets link rate set back before link training.
1124                  */
1125                 if (link->connector_signal == SIGNAL_TYPE_EDP) {
1126                         uint8_t supported_link_rates[16] = {0};
1127
1128                         core_link_read_dpcd(link, DP_SUPPORTED_LINK_RATES,
1129                                         supported_link_rates, sizeof(supported_link_rates));
1130                 }
1131                 status = core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1);
1132                 if (status != DC_OK)
1133                         DC_LOG_ERROR("%s:%d: core_link_write_dpcd (DP_LINK_BW_SET) failed\n", __func__, __LINE__);
1134
1135                 status = core_link_write_dpcd(link, DP_LINK_RATE_SET,
1136                                 &lt_settings->link_settings.link_rate_set, 1);
1137                 if (status != DC_OK)
1138                         DC_LOG_ERROR("%s:%d: core_link_write_dpcd (DP_LINK_RATE_SET) failed\n", __func__, __LINE__);
1139         } else {
1140                 rate = get_dpcd_link_rate(&lt_settings->link_settings);
1141
1142                 status = core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1);
1143                 if (status != DC_OK)
1144                         DC_LOG_ERROR("%s:%d: core_link_write_dpcd (DP_LINK_BW_SET) failed\n", __func__, __LINE__);
1145         }
1146
1147         if (rate) {
1148                 DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x framing = %x\n %x spread = %x\n",
1149                         __func__,
1150                         DP_LINK_BW_SET,
1151                         lt_settings->link_settings.link_rate,
1152                         DP_LANE_COUNT_SET,
1153                         lt_settings->link_settings.lane_count,
1154                         lt_settings->enhanced_framing,
1155                         DP_DOWNSPREAD_CTRL,
1156                         lt_settings->link_settings.link_spread);
1157         } else {
1158                 DC_LOG_HW_LINK_TRAINING("%s\n %x rate set = %x\n %x lane = %x framing = %x\n %x spread = %x\n",
1159                         __func__,
1160                         DP_LINK_RATE_SET,
1161                         lt_settings->link_settings.link_rate_set,
1162                         DP_LANE_COUNT_SET,
1163                         lt_settings->link_settings.lane_count,
1164                         lt_settings->enhanced_framing,
1165                         DP_DOWNSPREAD_CTRL,
1166                         lt_settings->link_settings.link_spread);
1167         }
1168
1169         return status;
1170 }
1171
1172 enum dc_status dpcd_set_lane_settings(
1173         struct dc_link *link,
1174         const struct link_training_settings *link_training_setting,
1175         uint32_t offset)
1176 {
1177         unsigned int lane0_set_address;
1178         enum dc_status status;
1179         lane0_set_address = DP_TRAINING_LANE0_SET;
1180
1181         if (is_repeater(link_training_setting, offset))
1182                 lane0_set_address = DP_TRAINING_LANE0_SET_PHY_REPEATER1 +
1183                 ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
1184
1185         status = core_link_write_dpcd(link,
1186                 lane0_set_address,
1187                 (uint8_t *)(link_training_setting->dpcd_lane_settings),
1188                 link_training_setting->link_settings.lane_count);
1189
1190         if (is_repeater(link_training_setting, offset)) {
1191                 DC_LOG_HW_LINK_TRAINING("%s\n LTTPR Repeater ID: %d\n"
1192                                 " 0x%X VS set = %x  PE set = %x max VS Reached = %x  max PE Reached = %x\n",
1193                         __func__,
1194                         offset,
1195                         lane0_set_address,
1196                         link_training_setting->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET,
1197                         link_training_setting->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET,
1198                         link_training_setting->dpcd_lane_settings[0].bits.MAX_SWING_REACHED,
1199                         link_training_setting->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED);
1200
1201         } else {
1202                 DC_LOG_HW_LINK_TRAINING("%s\n 0x%X VS set = %x  PE set = %x max VS Reached = %x  max PE Reached = %x\n",
1203                         __func__,
1204                         lane0_set_address,
1205                         link_training_setting->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET,
1206                         link_training_setting->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET,
1207                         link_training_setting->dpcd_lane_settings[0].bits.MAX_SWING_REACHED,
1208                         link_training_setting->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED);
1209         }
1210
1211         return status;
1212 }
1213
1214 void dpcd_set_lt_pattern_and_lane_settings(
1215         struct dc_link *link,
1216         const struct link_training_settings *lt_settings,
1217         enum dc_dp_training_pattern pattern,
1218         uint32_t offset)
1219 {
1220         uint32_t dpcd_base_lt_offset;
1221         uint8_t dpcd_lt_buffer[5] = {0};
1222         union dpcd_training_pattern dpcd_pattern = {0};
1223         uint32_t size_in_bytes;
1224         bool edp_workaround = false; /* TODO link_prop.INTERNAL */
1225         dpcd_base_lt_offset = DP_TRAINING_PATTERN_SET;
1226
1227         if (is_repeater(lt_settings, offset))
1228                 dpcd_base_lt_offset = DP_TRAINING_PATTERN_SET_PHY_REPEATER1 +
1229                         ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
1230
1231         /*****************************************************************
1232         * DpcdAddress_TrainingPatternSet
1233         *****************************************************************/
1234         dpcd_pattern.v1_4.TRAINING_PATTERN_SET =
1235                 dp_training_pattern_to_dpcd_training_pattern(link, pattern);
1236
1237         dpcd_pattern.v1_4.SCRAMBLING_DISABLE =
1238                 dp_initialize_scrambling_data_symbols(link, pattern);
1239
1240         dpcd_lt_buffer[DP_TRAINING_PATTERN_SET - DP_TRAINING_PATTERN_SET]
1241                 = dpcd_pattern.raw;
1242
1243         if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA)
1244                 dpia_set_tps_notification(
1245                         link,
1246                         lt_settings,
1247                         dpcd_pattern.v1_4.TRAINING_PATTERN_SET,
1248                         offset);
1249
1250         if (is_repeater(lt_settings, offset)) {
1251                 DC_LOG_HW_LINK_TRAINING("%s\n LTTPR Repeater ID: %d\n 0x%X pattern = %x\n",
1252                         __func__,
1253                         offset,
1254                         dpcd_base_lt_offset,
1255                         dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
1256         } else {
1257                 DC_LOG_HW_LINK_TRAINING("%s\n 0x%X pattern = %x\n",
1258                         __func__,
1259                         dpcd_base_lt_offset,
1260                         dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
1261         }
1262
1263         /* concatenate everything into one buffer*/
1264         size_in_bytes = lt_settings->link_settings.lane_count *
1265                         sizeof(lt_settings->dpcd_lane_settings[0]);
1266
1267          // 0x00103 - 0x00102
1268         memmove(
1269                 &dpcd_lt_buffer[DP_TRAINING_LANE0_SET - DP_TRAINING_PATTERN_SET],
1270                 lt_settings->dpcd_lane_settings,
1271                 size_in_bytes);
1272
1273         if (is_repeater(lt_settings, offset)) {
1274                 if (link_dp_get_encoding_format(&lt_settings->link_settings) ==
1275                                 DP_128b_132b_ENCODING)
1276                         DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n"
1277                                         " 0x%X TX_FFE_PRESET_VALUE = %x\n",
1278                                         __func__,
1279                                         offset,
1280                                         dpcd_base_lt_offset,
1281                                         lt_settings->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE);
1282                 else if (link_dp_get_encoding_format(&lt_settings->link_settings) ==
1283                                 DP_8b_10b_ENCODING)
1284                 DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n"
1285                                 " 0x%X VS set = %x PE set = %x max VS Reached = %x  max PE Reached = %x\n",
1286                         __func__,
1287                         offset,
1288                         dpcd_base_lt_offset,
1289                         lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET,
1290                         lt_settings->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET,
1291                         lt_settings->dpcd_lane_settings[0].bits.MAX_SWING_REACHED,
1292                         lt_settings->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED);
1293         } else {
1294                 if (link_dp_get_encoding_format(&lt_settings->link_settings) ==
1295                                 DP_128b_132b_ENCODING)
1296                         DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X TX_FFE_PRESET_VALUE = %x\n",
1297                                         __func__,
1298                                         dpcd_base_lt_offset,
1299                                         lt_settings->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE);
1300                 else if (link_dp_get_encoding_format(&lt_settings->link_settings) ==
1301                                 DP_8b_10b_ENCODING)
1302                         DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X VS set = %x  PE set = %x max VS Reached = %x  max PE Reached = %x\n",
1303                                         __func__,
1304                                         dpcd_base_lt_offset,
1305                                         lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET,
1306                                         lt_settings->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET,
1307                                         lt_settings->dpcd_lane_settings[0].bits.MAX_SWING_REACHED,
1308                                         lt_settings->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED);
1309         }
1310         if (edp_workaround) {
1311                 /* for eDP write in 2 parts because the 5-byte burst is
1312                 * causing issues on some eDP panels (EPR#366724)
1313                 */
1314                 core_link_write_dpcd(
1315                         link,
1316                         DP_TRAINING_PATTERN_SET,
1317                         &dpcd_pattern.raw,
1318                         sizeof(dpcd_pattern.raw));
1319
1320                 core_link_write_dpcd(
1321                         link,
1322                         DP_TRAINING_LANE0_SET,
1323                         (uint8_t *)(lt_settings->dpcd_lane_settings),
1324                         size_in_bytes);
1325
1326         } else if (link_dp_get_encoding_format(&lt_settings->link_settings) ==
1327                         DP_128b_132b_ENCODING) {
1328                 core_link_write_dpcd(
1329                                 link,
1330                                 dpcd_base_lt_offset,
1331                                 dpcd_lt_buffer,
1332                                 sizeof(dpcd_lt_buffer));
1333         } else
1334                 /* write it all in (1 + number-of-lanes)-byte burst*/
1335                 core_link_write_dpcd(
1336                                 link,
1337                                 dpcd_base_lt_offset,
1338                                 dpcd_lt_buffer,
1339                                 size_in_bytes + sizeof(dpcd_pattern.raw));
1340 }
1341
1342 void start_clock_recovery_pattern_early(struct dc_link *link,
1343                 const struct link_resource *link_res,
1344                 struct link_training_settings *lt_settings,
1345                 uint32_t offset)
1346 {
1347         DC_LOG_HW_LINK_TRAINING("%s\n GPU sends TPS1. Wait 400us.\n",
1348                         __func__);
1349         dp_set_hw_training_pattern(link, link_res, lt_settings->pattern_for_cr, offset);
1350         dp_set_hw_lane_settings(link, link_res, lt_settings, offset);
1351         udelay(400);
1352 }
1353
1354 void dp_set_hw_test_pattern(
1355         struct dc_link *link,
1356         const struct link_resource *link_res,
1357         enum dp_test_pattern test_pattern,
1358         uint8_t *custom_pattern,
1359         uint32_t custom_pattern_size)
1360 {
1361         const struct link_hwss *link_hwss = get_link_hwss(link, link_res);
1362         struct encoder_set_dp_phy_pattern_param pattern_param = {0};
1363
1364         pattern_param.dp_phy_pattern = test_pattern;
1365         pattern_param.custom_pattern = custom_pattern;
1366         pattern_param.custom_pattern_size = custom_pattern_size;
1367         pattern_param.dp_panel_mode = dp_get_panel_mode(link);
1368
1369         if (link_hwss->ext.set_dp_link_test_pattern)
1370                 link_hwss->ext.set_dp_link_test_pattern(link, link_res, &pattern_param);
1371 }
1372
1373 bool dp_set_hw_training_pattern(
1374         struct dc_link *link,
1375         const struct link_resource *link_res,
1376         enum dc_dp_training_pattern pattern,
1377         uint32_t offset)
1378 {
1379         enum dp_test_pattern test_pattern = DP_TEST_PATTERN_UNSUPPORTED;
1380
1381         switch (pattern) {
1382         case DP_TRAINING_PATTERN_SEQUENCE_1:
1383                 test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN1;
1384                 break;
1385         case DP_TRAINING_PATTERN_SEQUENCE_2:
1386                 test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN2;
1387                 break;
1388         case DP_TRAINING_PATTERN_SEQUENCE_3:
1389                 test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN3;
1390                 break;
1391         case DP_TRAINING_PATTERN_SEQUENCE_4:
1392                 test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN4;
1393                 break;
1394         case DP_128b_132b_TPS1:
1395                 test_pattern = DP_TEST_PATTERN_128b_132b_TPS1_TRAINING_MODE;
1396                 break;
1397         case DP_128b_132b_TPS2:
1398                 test_pattern = DP_TEST_PATTERN_128b_132b_TPS2_TRAINING_MODE;
1399                 break;
1400         default:
1401                 break;
1402         }
1403
1404         dp_set_hw_test_pattern(link, link_res, test_pattern, NULL, 0);
1405
1406         return true;
1407 }
1408
1409 static bool perform_post_lt_adj_req_sequence(
1410                 struct dc_link *link,
1411                 const struct link_resource *link_res,
1412                 struct link_training_settings *lt_settings)
1413 {
1414         enum dc_lane_count lane_count =
1415         lt_settings->link_settings.lane_count;
1416
1417         uint32_t adj_req_count;
1418         uint32_t adj_req_timer;
1419         bool req_drv_setting_changed;
1420         uint32_t lane;
1421         union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
1422         union lane_align_status_updated dpcd_lane_status_updated = {0};
1423         union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
1424
1425         req_drv_setting_changed = false;
1426         for (adj_req_count = 0; adj_req_count < POST_LT_ADJ_REQ_LIMIT;
1427         adj_req_count++) {
1428
1429                 req_drv_setting_changed = false;
1430
1431                 for (adj_req_timer = 0;
1432                         adj_req_timer < POST_LT_ADJ_REQ_TIMEOUT;
1433                         adj_req_timer++) {
1434
1435                         dp_get_lane_status_and_lane_adjust(
1436                                 link,
1437                                 lt_settings,
1438                                 dpcd_lane_status,
1439                                 &dpcd_lane_status_updated,
1440                                 dpcd_lane_adjust,
1441                                 DPRX);
1442
1443                         if (dpcd_lane_status_updated.bits.
1444                                         POST_LT_ADJ_REQ_IN_PROGRESS == 0)
1445                                 return true;
1446
1447                         if (!dp_is_cr_done(lane_count, dpcd_lane_status))
1448                                 return false;
1449
1450                         if (!dp_is_ch_eq_done(lane_count, dpcd_lane_status) ||
1451                                         !dp_is_symbol_locked(lane_count, dpcd_lane_status) ||
1452                                         !dp_is_interlane_aligned(dpcd_lane_status_updated))
1453                                 return false;
1454
1455                         for (lane = 0; lane < (uint32_t)(lane_count); lane++) {
1456
1457                                 if (lt_settings->
1458                                 dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET !=
1459                                 dpcd_lane_adjust[lane].bits.VOLTAGE_SWING_LANE ||
1460                                 lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET !=
1461                                 dpcd_lane_adjust[lane].bits.PRE_EMPHASIS_LANE) {
1462
1463                                         req_drv_setting_changed = true;
1464                                         break;
1465                                 }
1466                         }
1467
1468                         if (req_drv_setting_changed) {
1469                                 dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
1470                                                 lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
1471
1472                                 dp_set_drive_settings(link,
1473                                                 link_res,
1474                                                 lt_settings);
1475                                 break;
1476                         }
1477
1478                         msleep(1);
1479                 }
1480
1481                 if (!req_drv_setting_changed) {
1482                         DC_LOG_WARNING("%s: Post Link Training Adjust Request Timed out\n",
1483                                 __func__);
1484
1485                         ASSERT(0);
1486                         return true;
1487                 }
1488         }
1489         DC_LOG_WARNING("%s: Post Link Training Adjust Request limit reached\n",
1490                 __func__);
1491
1492         ASSERT(0);
1493         return true;
1494
1495 }
1496
1497 static enum link_training_result dp_transition_to_video_idle(
1498         struct dc_link *link,
1499         const struct link_resource *link_res,
1500         struct link_training_settings *lt_settings,
1501         enum link_training_result status)
1502 {
1503         union lane_count_set lane_count_set = {0};
1504
1505         /* 4. mainlink output idle pattern*/
1506         dp_set_hw_test_pattern(link, link_res, DP_TEST_PATTERN_VIDEO_MODE, NULL, 0);
1507
1508         /*
1509          * 5. post training adjust if required
1510          * If the upstream DPTX and downstream DPRX both support TPS4,
1511          * TPS4 must be used instead of POST_LT_ADJ_REQ.
1512          */
1513         if (link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED != 1 ||
1514                         lt_settings->pattern_for_eq >= DP_TRAINING_PATTERN_SEQUENCE_4) {
1515                 /* delay 5ms after Main Link output idle pattern and then check
1516                  * DPCD 0202h.
1517                  */
1518                 if (link->connector_signal != SIGNAL_TYPE_EDP && status == LINK_TRAINING_SUCCESS) {
1519                         msleep(5);
1520                         if (!link->skip_fallback_on_link_loss)
1521                                 status = dp_check_link_loss_status(link, lt_settings);
1522                 }
1523                 return status;
1524         }
1525
1526         if (status == LINK_TRAINING_SUCCESS &&
1527                 perform_post_lt_adj_req_sequence(link, link_res, lt_settings) == false)
1528                 status = LINK_TRAINING_LQA_FAIL;
1529
1530         lane_count_set.bits.LANE_COUNT_SET = lt_settings->link_settings.lane_count;
1531         lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing;
1532         lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0;
1533
1534         core_link_write_dpcd(
1535                 link,
1536                 DP_LANE_COUNT_SET,
1537                 &lane_count_set.raw,
1538                 sizeof(lane_count_set));
1539
1540         return status;
1541 }
1542
1543 enum link_training_result dp_perform_link_training(
1544         struct dc_link *link,
1545         const struct link_resource *link_res,
1546         const struct dc_link_settings *link_settings,
1547         bool skip_video_pattern)
1548 {
1549         enum link_training_result status = LINK_TRAINING_SUCCESS;
1550         struct link_training_settings lt_settings = {0};
1551         enum dp_link_encoding encoding =
1552                         link_dp_get_encoding_format(link_settings);
1553
1554         /* decide training settings */
1555         dp_decide_training_settings(
1556                         link,
1557                         link_settings,
1558                         &lt_settings);
1559
1560         override_training_settings(
1561                         link,
1562                         &link->preferred_training_settings,
1563                         &lt_settings);
1564
1565         /* reset previous training states */
1566         dpcd_exit_training_mode(link, encoding);
1567
1568         /* configure link prior to entering training mode */
1569         dpcd_configure_lttpr_mode(link, &lt_settings);
1570         dp_set_fec_ready(link, link_res, lt_settings.should_set_fec_ready);
1571         dpcd_configure_channel_coding(link, &lt_settings);
1572
1573         /* enter training mode:
1574          * Per DP specs starting from here, DPTX device shall not issue
1575          * Non-LT AUX transactions inside training mode.
1576          */
1577         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)
1578                 status = dp_perform_fixed_vs_pe_training_sequence(link, link_res, &lt_settings);
1579         else if (encoding == DP_8b_10b_ENCODING)
1580                 status = dp_perform_8b_10b_link_training(link, link_res, &lt_settings);
1581         else if (encoding == DP_128b_132b_ENCODING)
1582                 status = dp_perform_128b_132b_link_training(link, link_res, &lt_settings);
1583         else
1584                 ASSERT(0);
1585
1586         /* exit training mode */
1587         if ((dpcd_exit_training_mode(link, encoding) != LINK_TRAINING_SUCCESS || status == LINK_TRAINING_ABORT) &&
1588                         link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA)
1589                 dpia_training_abort(link, &lt_settings, 0);
1590
1591         /* switch to video idle */
1592         if ((status == LINK_TRAINING_SUCCESS) || !skip_video_pattern)
1593                 status = dp_transition_to_video_idle(link,
1594                                 link_res,
1595                                 &lt_settings,
1596                                 status);
1597
1598         /* dump debug data */
1599         dp_log_training_result(link, &lt_settings, status);
1600         if (status != LINK_TRAINING_SUCCESS)
1601                 link->ctx->dc->debug_data.ltFailCount++;
1602         return status;
1603 }
1604
1605 bool perform_link_training_with_retries(
1606         const struct dc_link_settings *link_setting,
1607         bool skip_video_pattern,
1608         int attempts,
1609         struct pipe_ctx *pipe_ctx,
1610         enum signal_type signal,
1611         bool do_fallback)
1612 {
1613         int j;
1614         uint8_t delay_between_attempts = LINK_TRAINING_RETRY_DELAY;
1615         struct dc_stream_state *stream = pipe_ctx->stream;
1616         struct dc_link *link = stream->link;
1617         enum dp_panel_mode panel_mode = dp_get_panel_mode(link);
1618         enum link_training_result status = LINK_TRAINING_CR_FAIL_LANE0;
1619         struct dc_link_settings cur_link_settings = *link_setting;
1620         struct dc_link_settings max_link_settings = *link_setting;
1621         const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
1622         int fail_count = 0;
1623         bool is_link_bw_low = false; /* link bandwidth < stream bandwidth */
1624         bool is_link_bw_min = /* RBR x 1 */
1625                 (cur_link_settings.link_rate <= LINK_RATE_LOW) &&
1626                 (cur_link_settings.lane_count <= LANE_COUNT_ONE);
1627
1628         dp_trace_commit_lt_init(link);
1629
1630
1631         if (link_dp_get_encoding_format(&cur_link_settings) == DP_8b_10b_ENCODING)
1632                 /* We need to do this before the link training to ensure the idle
1633                  * pattern in SST mode will be sent right after the link training
1634                  */
1635                 link_hwss->setup_stream_encoder(pipe_ctx);
1636
1637         dp_trace_set_lt_start_timestamp(link, false);
1638         j = 0;
1639         while (j < attempts && fail_count < (attempts * 10)) {
1640
1641                 DC_LOG_HW_LINK_TRAINING("%s: Beginning link(%d) training attempt %u of %d @ rate(%d) x lane(%d) @ spread = %x\n",
1642                                         __func__, link->link_index, (unsigned int)j + 1, attempts,
1643                                        cur_link_settings.link_rate, cur_link_settings.lane_count,
1644                                        cur_link_settings.link_spread);
1645
1646                 dp_enable_link_phy(
1647                         link,
1648                         &pipe_ctx->link_res,
1649                         signal,
1650                         pipe_ctx->clock_source->id,
1651                         &cur_link_settings);
1652
1653                 if (stream->sink_patches.dppowerup_delay > 0) {
1654                         int delay_dp_power_up_in_ms = stream->sink_patches.dppowerup_delay;
1655
1656                         msleep(delay_dp_power_up_in_ms);
1657                 }
1658
1659                 edp_set_panel_assr(link, pipe_ctx, &panel_mode, true);
1660
1661                 dp_set_panel_mode(link, panel_mode);
1662
1663                 if (link->aux_access_disabled) {
1664                         dp_perform_link_training_skip_aux(link, &pipe_ctx->link_res, &cur_link_settings);
1665                         return true;
1666                 } else {
1667                         if (!link->dc->config.consolidated_dpia_dp_lt && link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) {
1668                                 status = dpia_perform_link_training(
1669                                                 link,
1670                                                 &pipe_ctx->link_res,
1671                                                 &cur_link_settings,
1672                                                 skip_video_pattern);
1673
1674                                 /* Transmit idle pattern once training successful. */
1675                                 if (status == LINK_TRAINING_SUCCESS && !is_link_bw_low) {
1676                                         dp_set_hw_test_pattern(link, &pipe_ctx->link_res, DP_TEST_PATTERN_VIDEO_MODE, NULL, 0);
1677                                         // Update verified link settings to current one
1678                                         // Because DPIA LT might fallback to lower link setting.
1679                                         if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
1680                                                 link->verified_link_cap.link_rate = link->cur_link_settings.link_rate;
1681                                                 link->verified_link_cap.lane_count = link->cur_link_settings.lane_count;
1682                                                 dm_helpers_dp_mst_update_branch_bandwidth(link->ctx, link);
1683                                         }
1684                                 }
1685                         } else {
1686                                 status = dp_perform_link_training(
1687                                                 link,
1688                                                 &pipe_ctx->link_res,
1689                                                 &cur_link_settings,
1690                                                 skip_video_pattern);
1691                         }
1692
1693                         dp_trace_lt_total_count_increment(link, false);
1694                         dp_trace_lt_result_update(link, status, false);
1695                         dp_trace_set_lt_end_timestamp(link, false);
1696                         if (status == LINK_TRAINING_SUCCESS && !is_link_bw_low) {
1697                                 // Update verified link settings to current one
1698                                 // Because DPIA LT might fallback to lower link setting.
1699                                 if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA &&
1700                                                 stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
1701                                         link->verified_link_cap.link_rate = link->cur_link_settings.link_rate;
1702                                         link->verified_link_cap.lane_count = link->cur_link_settings.lane_count;
1703                                         dm_helpers_dp_mst_update_branch_bandwidth(link->ctx, link);
1704                                 }
1705                                 return true;
1706                         }
1707                 }
1708
1709                 fail_count++;
1710                 dp_trace_lt_fail_count_update(link, fail_count, false);
1711                 if (link->ep_type == DISPLAY_ENDPOINT_PHY) {
1712                         /* latest link training still fail or link training is aborted
1713                          * skip delay and keep PHY on
1714                          */
1715                         if (j == (attempts - 1) || (status == LINK_TRAINING_ABORT))
1716                                 break;
1717                 }
1718
1719                 if (j == (attempts - 1)) {
1720                         DC_LOG_WARNING(
1721                                 "%s: Link(%d) training attempt %u of %d failed @ rate(%d) x lane(%d) @ spread = %x : fail reason:(%d)\n",
1722                                 __func__, link->link_index, (unsigned int)j + 1, attempts,
1723                                 cur_link_settings.link_rate, cur_link_settings.lane_count,
1724                                 cur_link_settings.link_spread, status);
1725                 } else {
1726                         DC_LOG_HW_LINK_TRAINING(
1727                                 "%s: Link(%d) training attempt %u of %d failed @ rate(%d) x lane(%d) @ spread = %x : fail reason:(%d)\n",
1728                                 __func__, link->link_index, (unsigned int)j + 1, attempts,
1729                                 cur_link_settings.link_rate, cur_link_settings.lane_count,
1730                                 cur_link_settings.link_spread, status);
1731                 }
1732
1733                 dp_disable_link_phy(link, &pipe_ctx->link_res, signal);
1734
1735                 /* Abort link training if failure due to sink being unplugged. */
1736                 if (status == LINK_TRAINING_ABORT) {
1737                         enum dc_connection_type type = dc_connection_none;
1738
1739                         if (link_detect_connection_type(link, &type) && type == dc_connection_none) {
1740                                 DC_LOG_HW_LINK_TRAINING("%s: Aborting training because sink unplugged\n", __func__);
1741                                 break;
1742                         }
1743                 }
1744
1745                 /* Try to train again at original settings if:
1746                  * - not falling back between training attempts;
1747                  * - aborted previous attempt due to reasons other than sink unplug;
1748                  * - successfully trained but at a link rate lower than that required by stream;
1749                  * - reached minimum link bandwidth.
1750                  */
1751                 if (!do_fallback || (status == LINK_TRAINING_ABORT) ||
1752                                 (status == LINK_TRAINING_SUCCESS && is_link_bw_low) ||
1753                                 is_link_bw_min) {
1754                         j++;
1755                         cur_link_settings = *link_setting;
1756                         delay_between_attempts += LINK_TRAINING_RETRY_DELAY;
1757                         is_link_bw_low = false;
1758                         is_link_bw_min = (cur_link_settings.link_rate <= LINK_RATE_LOW) &&
1759                                 (cur_link_settings.lane_count <= LANE_COUNT_ONE);
1760
1761                 } else if (do_fallback) { /* Try training at lower link bandwidth if doing fallback. */
1762                         uint32_t req_bw;
1763                         uint32_t link_bw;
1764                         enum dc_link_encoding_format link_encoding = DC_LINK_ENCODING_UNSPECIFIED;
1765
1766                         decide_fallback_link_setting(link, &max_link_settings,
1767                                         &cur_link_settings, status);
1768
1769                         if (link_dp_get_encoding_format(&cur_link_settings) == DP_8b_10b_ENCODING)
1770                                 link_encoding = DC_LINK_ENCODING_DP_8b_10b;
1771                         else if (link_dp_get_encoding_format(&cur_link_settings) == DP_128b_132b_ENCODING)
1772                                 link_encoding = DC_LINK_ENCODING_DP_128b_132b;
1773
1774                         /* Flag if reduced link bandwidth no longer meets stream requirements or fallen back to
1775                          * minimum link bandwidth.
1776                          */
1777                         req_bw = dc_bandwidth_in_kbps_from_timing(&stream->timing, link_encoding);
1778                         link_bw = dp_link_bandwidth_kbps(link, &cur_link_settings);
1779                         is_link_bw_low = (req_bw > link_bw);
1780                         is_link_bw_min = ((cur_link_settings.link_rate <= LINK_RATE_LOW) &&
1781                                 (cur_link_settings.lane_count <= LANE_COUNT_ONE));
1782
1783                         if (is_link_bw_low) {
1784                                 DC_LOG_WARNING(
1785                                         "%s: Link(%d) bandwidth too low after fallback req_bw(%d) > link_bw(%d)\n",
1786                                         __func__, link->link_index, req_bw, link_bw);
1787
1788                                 return false;
1789                         }
1790                 }
1791
1792                 msleep(delay_between_attempts);
1793         }
1794
1795         return false;
1796 }
1797
This page took 0.140798 seconds and 4 git commands to generate.