2 * Copyright 2022 Advanced Micro Devices, Inc.
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:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
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.
26 /* FILE POLICY AND INTENDED USAGE:
27 * This file implements 8b/10b link training specially modified to support an
28 * embedded retimer chip. This retimer chip is referred as fixed vs pe retimer.
29 * Unlike native dp connection this chip requires a modified link training
30 * protocol based on 8b/10b link training. Since this is a non standard sequence
31 * and we must support this hardware, we decided to isolate it in its own
32 * training sequence inside its own file.
34 #include "link_dp_training_fixed_vs_pe_retimer.h"
35 #include "link_dp_training_8b_10b.h"
36 #include "link_dpcd.h"
37 #include "link_dp_phy.h"
38 #include "link_dp_capability.h"
44 void dp_fixed_vs_pe_read_lane_adjust(
46 union dpcd_training_lane dpcd_lane_adjust[LANE_COUNT_DP_MAX])
48 const uint8_t vendor_lttpr_write_data_vs[3] = {0x0, 0x53, 0x63};
49 const uint8_t vendor_lttpr_write_data_pe[3] = {0x0, 0x54, 0x63};
54 /* W/A to read lane settings requested by DPRX */
55 link_configure_fixed_vs_pe_retimer(link->ddc,
56 &vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs));
58 link_query_fixed_vs_pe_retimer(link->ddc, &dprx_vs, 1);
60 link_configure_fixed_vs_pe_retimer(link->ddc,
61 &vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe));
63 link_query_fixed_vs_pe_retimer(link->ddc, &dprx_pe, 1);
65 for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
66 dpcd_lane_adjust[lane].bits.VOLTAGE_SWING_SET = (dprx_vs >> (2 * lane)) & 0x3;
67 dpcd_lane_adjust[lane].bits.PRE_EMPHASIS_SET = (dprx_pe >> (2 * lane)) & 0x3;
72 void dp_fixed_vs_pe_set_retimer_lane_settings(
74 const union dpcd_training_lane dpcd_lane_adjust[LANE_COUNT_DP_MAX],
77 const uint8_t vendor_lttpr_write_data_reset[4] = {0x1, 0x50, 0x63, 0xFF};
78 uint8_t vendor_lttpr_write_data_vs[4] = {0x1, 0x51, 0x63, 0x0};
79 uint8_t vendor_lttpr_write_data_pe[4] = {0x1, 0x52, 0x63, 0x0};
82 for (lane = 0; lane < lane_count; lane++) {
83 vendor_lttpr_write_data_vs[3] |=
84 dpcd_lane_adjust[lane].bits.VOLTAGE_SWING_SET << (2 * lane);
85 vendor_lttpr_write_data_pe[3] |=
86 dpcd_lane_adjust[lane].bits.PRE_EMPHASIS_SET << (2 * lane);
89 /* Force LTTPR to output desired VS and PE */
90 link_configure_fixed_vs_pe_retimer(link->ddc,
91 &vendor_lttpr_write_data_reset[0], sizeof(vendor_lttpr_write_data_reset));
93 link_configure_fixed_vs_pe_retimer(link->ddc,
94 &vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs));
96 link_configure_fixed_vs_pe_retimer(link->ddc,
97 &vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe));
100 static enum link_training_result perform_fixed_vs_pe_nontransparent_training_sequence(
101 struct dc_link *link,
102 const struct link_resource *link_res,
103 struct link_training_settings *lt_settings)
105 enum link_training_result status = LINK_TRAINING_SUCCESS;
107 uint8_t toggle_rate = 0x6;
108 uint8_t target_rate = 0x6;
109 bool apply_toggle_rate_wa = false;
110 uint8_t repeater_cnt;
113 /* Fixed VS/PE specific: Force CR AUX RD Interval to at least 16ms */
114 if (lt_settings->cr_pattern_time < 16000)
115 lt_settings->cr_pattern_time = 16000;
117 /* Fixed VS/PE specific: Toggle link rate */
118 apply_toggle_rate_wa = ((link->vendor_specific_lttpr_link_rate_wa == target_rate) || (link->vendor_specific_lttpr_link_rate_wa == 0));
119 target_rate = get_dpcd_link_rate(<_settings->link_settings);
120 toggle_rate = (target_rate == 0x6) ? 0xA : 0x6;
122 if (apply_toggle_rate_wa)
123 lt_settings->link_settings.link_rate = toggle_rate;
125 if (link->ctx->dc->work_arounds.lt_early_cr_pattern)
126 start_clock_recovery_pattern_early(link, link_res, lt_settings, DPRX);
128 /* 1. set link rate, lane count and spread. */
129 dpcd_set_link_settings(link, lt_settings);
131 /* Fixed VS/PE specific: Toggle link rate back*/
132 if (apply_toggle_rate_wa) {
133 core_link_write_dpcd(
140 link->vendor_specific_lttpr_link_rate_wa = target_rate;
142 if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) {
144 /* 2. perform link training (set link training done
145 * to false is done as well)
147 repeater_cnt = dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
149 for (repeater_id = repeater_cnt; (repeater_id > 0 && status == LINK_TRAINING_SUCCESS);
151 status = perform_8b_10b_clock_recovery_sequence(link, link_res, lt_settings, repeater_id);
153 if (status != LINK_TRAINING_SUCCESS) {
154 repeater_training_done(link, repeater_id);
158 status = perform_8b_10b_channel_equalization_sequence(link,
163 repeater_training_done(link, repeater_id);
165 if (status != LINK_TRAINING_SUCCESS)
168 for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
169 lt_settings->dpcd_lane_settings[lane].raw = 0;
170 lt_settings->hw_lane_settings[lane].VOLTAGE_SWING = 0;
171 lt_settings->hw_lane_settings[lane].PRE_EMPHASIS = 0;
176 if (status == LINK_TRAINING_SUCCESS) {
177 status = perform_8b_10b_clock_recovery_sequence(link, link_res, lt_settings, DPRX);
178 if (status == LINK_TRAINING_SUCCESS) {
179 status = perform_8b_10b_channel_equalization_sequence(link,
190 enum link_training_result dp_perform_fixed_vs_pe_training_sequence_legacy(
191 struct dc_link *link,
192 const struct link_resource *link_res,
193 struct link_training_settings *lt_settings)
195 const uint8_t vendor_lttpr_write_data_reset[4] = {0x1, 0x50, 0x63, 0xFF};
196 const uint8_t offset = dp_parse_lttpr_repeater_count(
197 link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
198 const uint8_t vendor_lttpr_write_data_intercept_en[4] = {0x1, 0x55, 0x63, 0x0};
199 const uint8_t vendor_lttpr_write_data_intercept_dis[4] = {0x1, 0x55, 0x63, 0x68};
200 uint32_t pre_disable_intercept_delay_ms = 0;
201 uint8_t vendor_lttpr_write_data_vs[4] = {0x1, 0x51, 0x63, 0x0};
202 uint8_t vendor_lttpr_write_data_pe[4] = {0x1, 0x52, 0x63, 0x0};
203 const uint8_t vendor_lttpr_write_data_4lane_1[4] = {0x1, 0x6E, 0xF2, 0x19};
204 const uint8_t vendor_lttpr_write_data_4lane_2[4] = {0x1, 0x6B, 0xF2, 0x01};
205 const uint8_t vendor_lttpr_write_data_4lane_3[4] = {0x1, 0x6D, 0xF2, 0x18};
206 const uint8_t vendor_lttpr_write_data_4lane_4[4] = {0x1, 0x6C, 0xF2, 0x03};
207 const uint8_t vendor_lttpr_write_data_4lane_5[4] = {0x1, 0x03, 0xF3, 0x06};
208 enum link_training_result status = LINK_TRAINING_SUCCESS;
210 union down_spread_ctrl downspread = {0};
211 union lane_count_set lane_count_set = {0};
215 /* Only 8b/10b is supported */
216 ASSERT(link_dp_get_encoding_format(<_settings->link_settings) ==
219 if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) {
220 status = perform_fixed_vs_pe_nontransparent_training_sequence(link, link_res, lt_settings);
224 if (offset != 0xFF) {
226 pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa;
228 /* Certain display and cable configuration require extra delay */
229 } else if (offset > 2) {
230 pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa * 2;
234 /* Vendor specific: Reset lane settings */
235 link_configure_fixed_vs_pe_retimer(link->ddc,
236 &vendor_lttpr_write_data_reset[0], sizeof(vendor_lttpr_write_data_reset));
237 link_configure_fixed_vs_pe_retimer(link->ddc,
238 &vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs));
239 link_configure_fixed_vs_pe_retimer(link->ddc,
240 &vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe));
242 /* Vendor specific: Enable intercept */
243 link_configure_fixed_vs_pe_retimer(link->ddc,
244 &vendor_lttpr_write_data_intercept_en[0], sizeof(vendor_lttpr_write_data_intercept_en));
247 /* 1. set link rate, lane count and spread. */
249 downspread.raw = (uint8_t)(lt_settings->link_settings.link_spread);
251 lane_count_set.bits.LANE_COUNT_SET =
252 lt_settings->link_settings.lane_count;
254 lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing;
255 lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0;
258 if (lt_settings->pattern_for_eq < DP_TRAINING_PATTERN_SEQUENCE_4) {
259 lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED =
260 link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED;
263 core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL,
264 &downspread.raw, sizeof(downspread));
266 core_link_write_dpcd(link, DP_LANE_COUNT_SET,
267 &lane_count_set.raw, 1);
269 rate = get_dpcd_link_rate(<_settings->link_settings);
271 /* Vendor specific: Toggle link rate */
272 toggle_rate = (rate == 0x6) ? 0xA : 0x6;
274 if (link->vendor_specific_lttpr_link_rate_wa == rate || link->vendor_specific_lttpr_link_rate_wa == 0) {
275 core_link_write_dpcd(
282 link->vendor_specific_lttpr_link_rate_wa = rate;
284 core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1);
286 DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x framing = %x\n %x spread = %x\n",
289 lt_settings->link_settings.link_rate,
291 lt_settings->link_settings.lane_count,
292 lt_settings->enhanced_framing,
294 lt_settings->link_settings.link_spread);
296 if (lt_settings->link_settings.lane_count == LANE_COUNT_FOUR) {
297 link_configure_fixed_vs_pe_retimer(link->ddc,
298 &vendor_lttpr_write_data_4lane_1[0], sizeof(vendor_lttpr_write_data_4lane_1));
299 link_configure_fixed_vs_pe_retimer(link->ddc,
300 &vendor_lttpr_write_data_4lane_2[0], sizeof(vendor_lttpr_write_data_4lane_2));
301 link_configure_fixed_vs_pe_retimer(link->ddc,
302 &vendor_lttpr_write_data_4lane_3[0], sizeof(vendor_lttpr_write_data_4lane_3));
303 link_configure_fixed_vs_pe_retimer(link->ddc,
304 &vendor_lttpr_write_data_4lane_4[0], sizeof(vendor_lttpr_write_data_4lane_4));
305 link_configure_fixed_vs_pe_retimer(link->ddc,
306 &vendor_lttpr_write_data_4lane_5[0], sizeof(vendor_lttpr_write_data_4lane_5));
309 /* 2. Perform link training */
311 /* Perform Clock Recovery Sequence */
312 if (status == LINK_TRAINING_SUCCESS) {
313 const uint8_t max_vendor_dpcd_retries = 10;
315 uint32_t retry_count;
316 uint32_t wait_time_microsec;
317 enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
318 union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX];
319 union lane_align_status_updated dpcd_lane_status_updated;
320 union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
326 memset(&dpcd_lane_status, '\0', sizeof(dpcd_lane_status));
327 memset(&dpcd_lane_status_updated, '\0',
328 sizeof(dpcd_lane_status_updated));
330 while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) &&
331 (retry_count < LINK_TRAINING_MAX_CR_RETRY)) {
334 /* 1. call HWSS to set lane settings */
335 dp_set_hw_lane_settings(
341 /* 2. update DPCD of the receiver */
343 /* EPR #361076 - write as a 5-byte burst,
344 * but only for the 1-st iteration.
346 dpcd_set_lt_pattern_and_lane_settings(
349 lt_settings->pattern_for_cr,
351 /* Vendor specific: Disable intercept */
352 for (i = 0; i < max_vendor_dpcd_retries; i++) {
353 if (pre_disable_intercept_delay_ms != 0)
354 msleep(pre_disable_intercept_delay_ms);
355 if (link_configure_fixed_vs_pe_retimer(link->ddc,
356 &vendor_lttpr_write_data_intercept_dis[0],
357 sizeof(vendor_lttpr_write_data_intercept_dis)))
360 link_configure_fixed_vs_pe_retimer(link->ddc,
361 &vendor_lttpr_write_data_intercept_en[0],
362 sizeof(vendor_lttpr_write_data_intercept_en));
365 vendor_lttpr_write_data_vs[3] = 0;
366 vendor_lttpr_write_data_pe[3] = 0;
368 for (lane = 0; lane < lane_count; lane++) {
369 vendor_lttpr_write_data_vs[3] |=
370 lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane);
371 vendor_lttpr_write_data_pe[3] |=
372 lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane);
375 /* Vendor specific: Update VS and PE to DPRX requested value */
376 link_configure_fixed_vs_pe_retimer(link->ddc,
377 &vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs));
378 link_configure_fixed_vs_pe_retimer(link->ddc,
379 &vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe));
381 dpcd_set_lane_settings(
387 /* 3. wait receiver to lock-on*/
388 wait_time_microsec = lt_settings->cr_pattern_time;
390 dp_wait_for_training_aux_rd_interval(
394 /* 4. Read lane status and requested drive
395 * settings as set by the sink
397 dp_get_lane_status_and_lane_adjust(
401 &dpcd_lane_status_updated,
405 /* 5. check CR done*/
406 if (dp_is_cr_done(lane_count, dpcd_lane_status)) {
407 status = LINK_TRAINING_SUCCESS;
411 /* 6. max VS reached*/
412 if (dp_is_max_vs_reached(lt_settings))
415 /* 7. same lane settings */
416 /* Note: settings are the same for all lanes,
417 * so comparing first lane is sufficient
419 if (lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET ==
420 dpcd_lane_adjust[0].bits.VOLTAGE_SWING_LANE)
425 /* 8. update VS/PE/PC2 in lt_settings*/
426 dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
427 lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
431 if (retry_count >= LINK_TRAINING_MAX_CR_RETRY) {
433 DC_LOG_ERROR("%s: Link Training Error, could not get CR after %d tries. Possibly voltage swing issue",
435 LINK_TRAINING_MAX_CR_RETRY);
439 status = dp_get_cr_failure(lane_count, dpcd_lane_status);
442 /* Perform Channel EQ Sequence */
443 if (status == LINK_TRAINING_SUCCESS) {
444 enum dc_dp_training_pattern tr_pattern;
445 uint32_t retries_ch_eq;
446 uint32_t wait_time_microsec;
447 enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
448 union lane_align_status_updated dpcd_lane_status_updated = {0};
449 union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
450 union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
452 /* Note: also check that TPS4 is a supported feature*/
453 tr_pattern = lt_settings->pattern_for_eq;
455 dp_set_hw_training_pattern(link, link_res, tr_pattern, 0);
457 status = LINK_TRAINING_EQ_FAIL_EQ;
459 for (retries_ch_eq = 0; retries_ch_eq <= LINK_TRAINING_MAX_RETRY_COUNT;
462 dp_set_hw_lane_settings(link, link_res, lt_settings, 0);
464 vendor_lttpr_write_data_vs[3] = 0;
465 vendor_lttpr_write_data_pe[3] = 0;
467 for (lane = 0; lane < lane_count; lane++) {
468 vendor_lttpr_write_data_vs[3] |=
469 lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane);
470 vendor_lttpr_write_data_pe[3] |=
471 lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane);
474 /* Vendor specific: Update VS and PE to DPRX requested value */
475 link_configure_fixed_vs_pe_retimer(link->ddc,
476 &vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs));
477 link_configure_fixed_vs_pe_retimer(link->ddc,
478 &vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe));
482 /* EPR #361076 - write as a 5-byte burst,
483 * but only for the 1-st iteration
486 dpcd_set_lt_pattern_and_lane_settings(
491 dpcd_set_lane_settings(link, lt_settings, 0);
493 /* 3. wait for receiver to lock-on*/
494 wait_time_microsec = lt_settings->eq_pattern_time;
496 dp_wait_for_training_aux_rd_interval(
500 /* 4. Read lane status and requested
501 * drive settings as set by the sink
503 dp_get_lane_status_and_lane_adjust(
507 &dpcd_lane_status_updated,
511 /* 5. check CR done*/
512 if (!dp_is_cr_done(lane_count, dpcd_lane_status)) {
513 status = LINK_TRAINING_EQ_FAIL_CR;
517 /* 6. check CHEQ done*/
518 if (dp_is_ch_eq_done(lane_count, dpcd_lane_status) &&
519 dp_is_symbol_locked(lane_count, dpcd_lane_status) &&
520 dp_is_interlane_aligned(dpcd_lane_status_updated)) {
521 status = LINK_TRAINING_SUCCESS;
525 /* 7. update VS/PE/PC2 in lt_settings*/
526 dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
527 lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
534 enum link_training_result dp_perform_fixed_vs_pe_training_sequence(
535 struct dc_link *link,
536 const struct link_resource *link_res,
537 struct link_training_settings *lt_settings)
539 const uint8_t vendor_lttpr_write_data_reset[4] = {0x1, 0x50, 0x63, 0xFF};
540 const uint8_t offset = dp_parse_lttpr_repeater_count(
541 link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
542 const uint8_t vendor_lttpr_write_data_intercept_en[4] = {0x1, 0x55, 0x63, 0x0};
543 const uint8_t vendor_lttpr_write_data_intercept_dis[4] = {0x1, 0x55, 0x63, 0x6E};
544 const uint8_t vendor_lttpr_write_data_adicora_eq1[4] = {0x1, 0x55, 0x63, 0x2E};
545 const uint8_t vendor_lttpr_write_data_adicora_eq2[4] = {0x1, 0x55, 0x63, 0x01};
546 const uint8_t vendor_lttpr_write_data_adicora_eq3[4] = {0x1, 0x55, 0x63, 0x68};
547 uint32_t pre_disable_intercept_delay_ms = 0;
548 uint8_t vendor_lttpr_write_data_vs[4] = {0x1, 0x51, 0x63, 0x0};
549 uint8_t vendor_lttpr_write_data_pe[4] = {0x1, 0x52, 0x63, 0x0};
550 const uint8_t vendor_lttpr_write_data_4lane_1[4] = {0x1, 0x6E, 0xF2, 0x19};
551 const uint8_t vendor_lttpr_write_data_4lane_2[4] = {0x1, 0x6B, 0xF2, 0x01};
552 const uint8_t vendor_lttpr_write_data_4lane_3[4] = {0x1, 0x6D, 0xF2, 0x18};
553 const uint8_t vendor_lttpr_write_data_4lane_4[4] = {0x1, 0x6C, 0xF2, 0x03};
554 const uint8_t vendor_lttpr_write_data_4lane_5[4] = {0x1, 0x03, 0xF3, 0x06};
555 enum link_training_result status = LINK_TRAINING_SUCCESS;
557 union down_spread_ctrl downspread = {0};
558 union lane_count_set lane_count_set = {0};
562 /* Only 8b/10b is supported */
563 ASSERT(link_dp_get_encoding_format(<_settings->link_settings) ==
566 if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) {
567 status = perform_fixed_vs_pe_nontransparent_training_sequence(link, link_res, lt_settings);
571 if (offset != 0xFF) {
573 pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa;
575 /* Certain display and cable configuration require extra delay */
576 } else if (offset > 2) {
577 pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa * 2;
581 /* Vendor specific: Reset lane settings */
582 link_configure_fixed_vs_pe_retimer(link->ddc,
583 &vendor_lttpr_write_data_reset[0], sizeof(vendor_lttpr_write_data_reset));
584 link_configure_fixed_vs_pe_retimer(link->ddc,
585 &vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs));
586 link_configure_fixed_vs_pe_retimer(link->ddc,
587 &vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe));
589 /* Vendor specific: Enable intercept */
590 link_configure_fixed_vs_pe_retimer(link->ddc,
591 &vendor_lttpr_write_data_intercept_en[0], sizeof(vendor_lttpr_write_data_intercept_en));
593 /* 1. set link rate, lane count and spread. */
595 downspread.raw = (uint8_t)(lt_settings->link_settings.link_spread);
597 lane_count_set.bits.LANE_COUNT_SET =
598 lt_settings->link_settings.lane_count;
600 lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing;
601 lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0;
604 if (lt_settings->pattern_for_eq < DP_TRAINING_PATTERN_SEQUENCE_4) {
605 lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED =
606 link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED;
609 core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL,
610 &downspread.raw, sizeof(downspread));
612 core_link_write_dpcd(link, DP_LANE_COUNT_SET,
613 &lane_count_set.raw, 1);
615 rate = get_dpcd_link_rate(<_settings->link_settings);
617 /* Vendor specific: Toggle link rate */
618 toggle_rate = (rate == 0x6) ? 0xA : 0x6;
620 if (link->vendor_specific_lttpr_link_rate_wa == rate || link->vendor_specific_lttpr_link_rate_wa == 0) {
621 core_link_write_dpcd(
628 link->vendor_specific_lttpr_link_rate_wa = rate;
630 core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1);
632 DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x framing = %x\n %x spread = %x\n",
635 lt_settings->link_settings.link_rate,
637 lt_settings->link_settings.lane_count,
638 lt_settings->enhanced_framing,
640 lt_settings->link_settings.link_spread);
642 if (lt_settings->link_settings.lane_count == LANE_COUNT_FOUR) {
643 link_configure_fixed_vs_pe_retimer(link->ddc,
644 &vendor_lttpr_write_data_4lane_1[0], sizeof(vendor_lttpr_write_data_4lane_1));
645 link_configure_fixed_vs_pe_retimer(link->ddc,
646 &vendor_lttpr_write_data_4lane_2[0], sizeof(vendor_lttpr_write_data_4lane_2));
647 link_configure_fixed_vs_pe_retimer(link->ddc,
648 &vendor_lttpr_write_data_4lane_3[0], sizeof(vendor_lttpr_write_data_4lane_3));
649 link_configure_fixed_vs_pe_retimer(link->ddc,
650 &vendor_lttpr_write_data_4lane_4[0], sizeof(vendor_lttpr_write_data_4lane_4));
651 link_configure_fixed_vs_pe_retimer(link->ddc,
652 &vendor_lttpr_write_data_4lane_5[0], sizeof(vendor_lttpr_write_data_4lane_5));
655 /* 2. Perform link training */
657 /* Perform Clock Recovery Sequence */
658 if (status == LINK_TRAINING_SUCCESS) {
659 const uint8_t max_vendor_dpcd_retries = 10;
661 uint32_t retry_count;
662 uint32_t wait_time_microsec;
663 enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
664 union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX];
665 union lane_align_status_updated dpcd_lane_status_updated;
666 union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
672 memset(&dpcd_lane_status, '\0', sizeof(dpcd_lane_status));
673 memset(&dpcd_lane_status_updated, '\0',
674 sizeof(dpcd_lane_status_updated));
676 while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) &&
677 (retry_count < LINK_TRAINING_MAX_CR_RETRY)) {
680 /* 1. call HWSS to set lane settings */
681 dp_set_hw_lane_settings(
687 /* 2. update DPCD of the receiver */
689 /* EPR #361076 - write as a 5-byte burst,
690 * but only for the 1-st iteration.
692 dpcd_set_lt_pattern_and_lane_settings(
695 lt_settings->pattern_for_cr,
697 /* Vendor specific: Disable intercept */
698 for (i = 0; i < max_vendor_dpcd_retries; i++) {
699 if (pre_disable_intercept_delay_ms != 0)
700 msleep(pre_disable_intercept_delay_ms);
701 if (link_configure_fixed_vs_pe_retimer(link->ddc,
702 &vendor_lttpr_write_data_intercept_dis[0],
703 sizeof(vendor_lttpr_write_data_intercept_dis)))
706 link_configure_fixed_vs_pe_retimer(link->ddc,
707 &vendor_lttpr_write_data_intercept_en[0],
708 sizeof(vendor_lttpr_write_data_intercept_en));
711 vendor_lttpr_write_data_vs[3] = 0;
712 vendor_lttpr_write_data_pe[3] = 0;
714 for (lane = 0; lane < lane_count; lane++) {
715 vendor_lttpr_write_data_vs[3] |=
716 lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane);
717 vendor_lttpr_write_data_pe[3] |=
718 lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane);
721 /* Vendor specific: Update VS and PE to DPRX requested value */
722 link_configure_fixed_vs_pe_retimer(link->ddc,
723 &vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs));
724 link_configure_fixed_vs_pe_retimer(link->ddc,
725 &vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe));
727 dpcd_set_lane_settings(
733 /* 3. wait receiver to lock-on*/
734 wait_time_microsec = lt_settings->cr_pattern_time;
736 dp_wait_for_training_aux_rd_interval(
740 /* 4. Read lane status and requested drive
741 * settings as set by the sink
743 dp_get_lane_status_and_lane_adjust(
747 &dpcd_lane_status_updated,
751 /* 5. check CR done*/
752 if (dp_is_cr_done(lane_count, dpcd_lane_status)) {
753 status = LINK_TRAINING_SUCCESS;
757 /* 6. max VS reached*/
758 if (dp_is_max_vs_reached(lt_settings))
761 /* 7. same lane settings */
762 /* Note: settings are the same for all lanes,
763 * so comparing first lane is sufficient
765 if (lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET ==
766 dpcd_lane_adjust[0].bits.VOLTAGE_SWING_LANE)
771 /* 8. update VS/PE/PC2 in lt_settings*/
772 dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
773 lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
777 if (retry_count >= LINK_TRAINING_MAX_CR_RETRY) {
779 DC_LOG_ERROR("%s: Link Training Error, could not get CR after %d tries. Possibly voltage swing issue",
781 LINK_TRAINING_MAX_CR_RETRY);
785 status = dp_get_cr_failure(lane_count, dpcd_lane_status);
788 /* Perform Channel EQ Sequence */
789 if (status == LINK_TRAINING_SUCCESS) {
790 enum dc_dp_training_pattern tr_pattern;
791 uint32_t retries_ch_eq;
792 uint32_t wait_time_microsec;
793 enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
794 union lane_align_status_updated dpcd_lane_status_updated = {0};
795 union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
796 union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
798 link_configure_fixed_vs_pe_retimer(link->ddc,
799 &vendor_lttpr_write_data_adicora_eq1[0],
800 sizeof(vendor_lttpr_write_data_adicora_eq1));
801 link_configure_fixed_vs_pe_retimer(link->ddc,
802 &vendor_lttpr_write_data_adicora_eq2[0],
803 sizeof(vendor_lttpr_write_data_adicora_eq2));
806 /* Note: also check that TPS4 is a supported feature*/
807 tr_pattern = lt_settings->pattern_for_eq;
809 dp_set_hw_training_pattern(link, link_res, tr_pattern, 0);
811 status = LINK_TRAINING_EQ_FAIL_EQ;
813 for (retries_ch_eq = 0; retries_ch_eq <= LINK_TRAINING_MAX_RETRY_COUNT;
816 dp_set_hw_lane_settings(link, link_res, lt_settings, 0);
818 vendor_lttpr_write_data_vs[3] = 0;
819 vendor_lttpr_write_data_pe[3] = 0;
821 for (lane = 0; lane < lane_count; lane++) {
822 vendor_lttpr_write_data_vs[3] |=
823 lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane);
824 vendor_lttpr_write_data_pe[3] |=
825 lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane);
828 /* Vendor specific: Update VS and PE to DPRX requested value */
829 link_configure_fixed_vs_pe_retimer(link->ddc,
830 &vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs));
831 link_configure_fixed_vs_pe_retimer(link->ddc,
832 &vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe));
835 if (!retries_ch_eq) {
836 /* EPR #361076 - write as a 5-byte burst,
837 * but only for the 1-st iteration
840 dpcd_set_lt_pattern_and_lane_settings(
845 link_configure_fixed_vs_pe_retimer(link->ddc,
846 &vendor_lttpr_write_data_adicora_eq3[0],
847 sizeof(vendor_lttpr_write_data_adicora_eq3));
850 dpcd_set_lane_settings(link, lt_settings, 0);
852 /* 3. wait for receiver to lock-on*/
853 wait_time_microsec = lt_settings->eq_pattern_time;
855 dp_wait_for_training_aux_rd_interval(
859 /* 4. Read lane status and requested
860 * drive settings as set by the sink
862 dp_get_lane_status_and_lane_adjust(
866 &dpcd_lane_status_updated,
870 /* 5. check CR done*/
871 if (!dp_is_cr_done(lane_count, dpcd_lane_status)) {
872 status = LINK_TRAINING_EQ_FAIL_CR;
876 /* 6. check CHEQ done*/
877 if (dp_is_ch_eq_done(lane_count, dpcd_lane_status) &&
878 dp_is_symbol_locked(lane_count, dpcd_lane_status) &&
879 dp_is_interlane_aligned(dpcd_lane_status_updated)) {
880 status = LINK_TRAINING_SUCCESS;
884 /* 7. update VS/PE/PC2 in lt_settings*/
885 dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
886 lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);