1/*
2 * Copyright 2022 Advanced Micro Devices, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Authors: AMD
23 *
24 */
25
26/* FILE POLICY AND INTENDED USAGE:
27 * This file implements 8b/10b link training specially modified to support an
28 * embedded retimer chip. This retimer chip is referred as fixed vs pe retimer.
29 * Unlike native dp connection this chip requires a modified link training
30 * protocol based on 8b/10b link training. Since this is a non standard sequence
31 * and we must support this hardware, we decided to isolate it in its own
32 * training sequence inside its own file.
33 */
34#include "link_dp_training_fixed_vs_pe_retimer.h"
35#include "link_dp_training_8b_10b.h"
36#include "link_dpcd.h"
37#include "link_dp_phy.h"
38#include "link_dp_capability.h"
39#include "link_ddc.h"
40
41#define DC_LOGGER \
42 link->ctx->logger
43
44void dp_fixed_vs_pe_read_lane_adjust(
45 struct dc_link *link,
46 union dpcd_training_lane dpcd_lane_adjust[LANE_COUNT_DP_MAX])
47{
48 const uint8_t vendor_lttpr_write_data_vs[3] = {0x0, 0x53, 0x63};
49 const uint8_t vendor_lttpr_write_data_pe[3] = {0x0, 0x54, 0x63};
50 uint8_t dprx_vs = 0;
51 uint8_t dprx_pe = 0;
52 uint8_t lane;
53
54 /* W/A to read lane settings requested by DPRX */
55 link_configure_fixed_vs_pe_retimer(ddc: link->ddc,
56 data: &vendor_lttpr_write_data_vs[0], length: sizeof(vendor_lttpr_write_data_vs));
57
58 link_query_fixed_vs_pe_retimer(ddc: link->ddc, data: &dprx_vs, length: 1);
59
60 link_configure_fixed_vs_pe_retimer(ddc: link->ddc,
61 data: &vendor_lttpr_write_data_pe[0], length: sizeof(vendor_lttpr_write_data_pe));
62
63 link_query_fixed_vs_pe_retimer(ddc: link->ddc, data: &dprx_pe, length: 1);
64
65 for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
66 dpcd_lane_adjust[lane].bits.VOLTAGE_SWING_SET = (dprx_vs >> (2 * lane)) & 0x3;
67 dpcd_lane_adjust[lane].bits.PRE_EMPHASIS_SET = (dprx_pe >> (2 * lane)) & 0x3;
68 }
69}
70
71
72void dp_fixed_vs_pe_set_retimer_lane_settings(
73 struct dc_link *link,
74 const union dpcd_training_lane dpcd_lane_adjust[LANE_COUNT_DP_MAX],
75 uint8_t lane_count)
76{
77 const uint8_t vendor_lttpr_write_data_reset[4] = {0x1, 0x50, 0x63, 0xFF};
78 uint8_t vendor_lttpr_write_data_vs[4] = {0x1, 0x51, 0x63, 0x0};
79 uint8_t vendor_lttpr_write_data_pe[4] = {0x1, 0x52, 0x63, 0x0};
80 uint8_t lane = 0;
81
82 for (lane = 0; lane < lane_count; lane++) {
83 vendor_lttpr_write_data_vs[3] |=
84 dpcd_lane_adjust[lane].bits.VOLTAGE_SWING_SET << (2 * lane);
85 vendor_lttpr_write_data_pe[3] |=
86 dpcd_lane_adjust[lane].bits.PRE_EMPHASIS_SET << (2 * lane);
87 }
88
89 /* Force LTTPR to output desired VS and PE */
90 link_configure_fixed_vs_pe_retimer(ddc: link->ddc,
91 data: &vendor_lttpr_write_data_reset[0], length: sizeof(vendor_lttpr_write_data_reset));
92
93 link_configure_fixed_vs_pe_retimer(ddc: link->ddc,
94 data: &vendor_lttpr_write_data_vs[0], length: sizeof(vendor_lttpr_write_data_vs));
95
96 link_configure_fixed_vs_pe_retimer(ddc: link->ddc,
97 data: &vendor_lttpr_write_data_pe[0], length: sizeof(vendor_lttpr_write_data_pe));
98}
99
100static enum link_training_result perform_fixed_vs_pe_nontransparent_training_sequence(
101 struct dc_link *link,
102 const struct link_resource *link_res,
103 struct link_training_settings *lt_settings)
104{
105 enum link_training_result status = LINK_TRAINING_SUCCESS;
106 uint8_t lane = 0;
107 uint8_t toggle_rate = 0x6;
108 uint8_t target_rate = 0x6;
109 bool apply_toggle_rate_wa = false;
110 uint8_t repeater_cnt;
111 uint8_t repeater_id;
112
113 /* Fixed VS/PE specific: Force CR AUX RD Interval to at least 16ms */
114 if (lt_settings->cr_pattern_time < 16000)
115 lt_settings->cr_pattern_time = 16000;
116
117 /* Fixed VS/PE specific: Toggle link rate */
118 apply_toggle_rate_wa = ((link->vendor_specific_lttpr_link_rate_wa == target_rate) || (link->vendor_specific_lttpr_link_rate_wa == 0));
119 target_rate = get_dpcd_link_rate(link_settings: &lt_settings->link_settings);
120 toggle_rate = (target_rate == 0x6) ? 0xA : 0x6;
121
122 if (apply_toggle_rate_wa)
123 lt_settings->link_settings.link_rate = toggle_rate;
124
125 if (link->ctx->dc->work_arounds.lt_early_cr_pattern)
126 start_clock_recovery_pattern_early(link, link_res, lt_settings, offset: DPRX);
127
128 /* 1. set link rate, lane count and spread. */
129 dpcd_set_link_settings(link, lt_settings);
130
131 /* Fixed VS/PE specific: Toggle link rate back*/
132 if (apply_toggle_rate_wa) {
133 core_link_write_dpcd(
134 link,
135 DP_LINK_BW_SET,
136 data: &target_rate,
137 size: 1);
138 }
139
140 link->vendor_specific_lttpr_link_rate_wa = target_rate;
141
142 if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) {
143
144 /* 2. perform link training (set link training done
145 * to false is done as well)
146 */
147 repeater_cnt = dp_parse_lttpr_repeater_count(lttpr_repeater_count: link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
148
149 for (repeater_id = repeater_cnt; (repeater_id > 0 && status == LINK_TRAINING_SUCCESS);
150 repeater_id--) {
151 status = perform_8b_10b_clock_recovery_sequence(link, link_res, lt_settings, offset: repeater_id);
152
153 if (status != LINK_TRAINING_SUCCESS) {
154 repeater_training_done(link, offset: repeater_id);
155 break;
156 }
157
158 status = perform_8b_10b_channel_equalization_sequence(link,
159 link_res,
160 lt_settings,
161 offset: repeater_id);
162
163 repeater_training_done(link, offset: repeater_id);
164
165 if (status != LINK_TRAINING_SUCCESS)
166 break;
167
168 for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
169 lt_settings->dpcd_lane_settings[lane].raw = 0;
170 lt_settings->hw_lane_settings[lane].VOLTAGE_SWING = 0;
171 lt_settings->hw_lane_settings[lane].PRE_EMPHASIS = 0;
172 }
173 }
174 }
175
176 if (status == LINK_TRAINING_SUCCESS) {
177 status = perform_8b_10b_clock_recovery_sequence(link, link_res, lt_settings, offset: DPRX);
178 if (status == LINK_TRAINING_SUCCESS) {
179 status = perform_8b_10b_channel_equalization_sequence(link,
180 link_res,
181 lt_settings,
182 offset: DPRX);
183 }
184 }
185
186 return status;
187}
188
189enum link_training_result dp_perform_fixed_vs_pe_training_sequence(
190 struct dc_link *link,
191 const struct link_resource *link_res,
192 struct link_training_settings *lt_settings)
193{
194 const uint8_t vendor_lttpr_write_data_reset[4] = {0x1, 0x50, 0x63, 0xFF};
195 const uint8_t offset = dp_parse_lttpr_repeater_count(
196 lttpr_repeater_count: link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
197 const uint8_t vendor_lttpr_write_data_intercept_en[4] = {0x1, 0x55, 0x63, 0x0};
198 const uint8_t vendor_lttpr_write_data_intercept_dis[4] = {0x1, 0x55, 0x63, 0x6E};
199 const uint8_t vendor_lttpr_write_data_adicora_eq1[4] = {0x1, 0x55, 0x63, 0x2E};
200 const uint8_t vendor_lttpr_write_data_adicora_eq2[4] = {0x1, 0x55, 0x63, 0x01};
201 const uint8_t vendor_lttpr_write_data_adicora_eq3[4] = {0x1, 0x55, 0x63, 0x68};
202 uint32_t pre_disable_intercept_delay_ms = 0;
203 uint8_t vendor_lttpr_write_data_vs[4] = {0x1, 0x51, 0x63, 0x0};
204 uint8_t vendor_lttpr_write_data_pe[4] = {0x1, 0x52, 0x63, 0x0};
205 const uint8_t vendor_lttpr_write_data_4lane_1[4] = {0x1, 0x6E, 0xF2, 0x19};
206 const uint8_t vendor_lttpr_write_data_4lane_2[4] = {0x1, 0x6B, 0xF2, 0x01};
207 const uint8_t vendor_lttpr_write_data_4lane_3[4] = {0x1, 0x6D, 0xF2, 0x18};
208 const uint8_t vendor_lttpr_write_data_4lane_4[4] = {0x1, 0x6C, 0xF2, 0x03};
209 const uint8_t vendor_lttpr_write_data_4lane_5[4] = {0x1, 0x03, 0xF3, 0x06};
210 const uint8_t vendor_lttpr_write_data_dpmf[4] = {0x1, 0x6, 0x70, 0x87};
211 enum link_training_result status = LINK_TRAINING_SUCCESS;
212 uint8_t lane = 0;
213 union down_spread_ctrl downspread = {0};
214 union lane_count_set lane_count_set = {0};
215 uint8_t toggle_rate;
216 uint8_t rate;
217
218 /* Only 8b/10b is supported */
219 ASSERT(link_dp_get_encoding_format(&lt_settings->link_settings) ==
220 DP_8b_10b_ENCODING);
221
222 if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) {
223 status = perform_fixed_vs_pe_nontransparent_training_sequence(link, link_res, lt_settings);
224 return status;
225 }
226
227 if (offset != 0xFF) {
228 if (offset == 2) {
229 pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa;
230
231 /* Certain display and cable configuration require extra delay */
232 } else if (offset > 2) {
233 pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa * 2;
234 }
235 }
236
237 /* Vendor specific: Reset lane settings */
238 link_configure_fixed_vs_pe_retimer(ddc: link->ddc,
239 data: &vendor_lttpr_write_data_reset[0], length: sizeof(vendor_lttpr_write_data_reset));
240 link_configure_fixed_vs_pe_retimer(ddc: link->ddc,
241 data: &vendor_lttpr_write_data_vs[0], length: sizeof(vendor_lttpr_write_data_vs));
242 link_configure_fixed_vs_pe_retimer(ddc: link->ddc,
243 data: &vendor_lttpr_write_data_pe[0], length: sizeof(vendor_lttpr_write_data_pe));
244
245 /* Vendor specific: Enable intercept */
246 link_configure_fixed_vs_pe_retimer(ddc: link->ddc,
247 data: &vendor_lttpr_write_data_intercept_en[0], length: sizeof(vendor_lttpr_write_data_intercept_en));
248
249 /* 1. set link rate, lane count and spread. */
250
251 downspread.raw = (uint8_t)(lt_settings->link_settings.link_spread);
252
253 lane_count_set.bits.LANE_COUNT_SET =
254 lt_settings->link_settings.lane_count;
255
256 lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing;
257 lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0;
258
259
260 if (lt_settings->pattern_for_eq < DP_TRAINING_PATTERN_SEQUENCE_4) {
261 lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED =
262 link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED;
263 }
264
265 core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL,
266 data: &downspread.raw, size: sizeof(downspread));
267
268 core_link_write_dpcd(link, DP_LANE_COUNT_SET,
269 data: &lane_count_set.raw, size: 1);
270
271 rate = get_dpcd_link_rate(link_settings: &lt_settings->link_settings);
272
273 if (!link->dpcd_caps.lttpr_caps.main_link_channel_coding.bits.DP_128b_132b_SUPPORTED) {
274 /* Vendor specific: Toggle link rate */
275 toggle_rate = (rate == 0x6) ? 0xA : 0x6;
276
277 if (link->vendor_specific_lttpr_link_rate_wa == rate || link->vendor_specific_lttpr_link_rate_wa == 0) {
278 core_link_write_dpcd(
279 link,
280 DP_LINK_BW_SET,
281 data: &toggle_rate,
282 size: 1);
283 }
284
285 link->vendor_specific_lttpr_link_rate_wa = rate;
286 }
287
288 core_link_write_dpcd(link, DP_LINK_BW_SET, data: &rate, size: 1);
289
290 DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x framing = %x\n %x spread = %x\n",
291 __func__,
292 DP_LINK_BW_SET,
293 lt_settings->link_settings.link_rate,
294 DP_LANE_COUNT_SET,
295 lt_settings->link_settings.lane_count,
296 lt_settings->enhanced_framing,
297 DP_DOWNSPREAD_CTRL,
298 lt_settings->link_settings.link_spread);
299
300 link_configure_fixed_vs_pe_retimer(ddc: link->ddc,
301 data: &vendor_lttpr_write_data_dpmf[0],
302 length: sizeof(vendor_lttpr_write_data_dpmf));
303
304 if (lt_settings->link_settings.lane_count == LANE_COUNT_FOUR) {
305 link_configure_fixed_vs_pe_retimer(ddc: link->ddc,
306 data: &vendor_lttpr_write_data_4lane_1[0], length: sizeof(vendor_lttpr_write_data_4lane_1));
307 link_configure_fixed_vs_pe_retimer(ddc: link->ddc,
308 data: &vendor_lttpr_write_data_4lane_2[0], length: sizeof(vendor_lttpr_write_data_4lane_2));
309 link_configure_fixed_vs_pe_retimer(ddc: link->ddc,
310 data: &vendor_lttpr_write_data_4lane_3[0], length: sizeof(vendor_lttpr_write_data_4lane_3));
311 link_configure_fixed_vs_pe_retimer(ddc: link->ddc,
312 data: &vendor_lttpr_write_data_4lane_4[0], length: sizeof(vendor_lttpr_write_data_4lane_4));
313 link_configure_fixed_vs_pe_retimer(ddc: link->ddc,
314 data: &vendor_lttpr_write_data_4lane_5[0], length: sizeof(vendor_lttpr_write_data_4lane_5));
315 }
316
317 /* 2. Perform link training */
318
319 /* Perform Clock Recovery Sequence */
320 if (status == LINK_TRAINING_SUCCESS) {
321 const uint8_t max_vendor_dpcd_retries = 10;
322 uint32_t retries_cr;
323 uint32_t retry_count;
324 uint32_t wait_time_microsec;
325 enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
326 union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX];
327 union lane_align_status_updated dpcd_lane_status_updated;
328 union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
329 uint8_t i = 0;
330
331 retries_cr = 0;
332 retry_count = 0;
333
334 memset(&dpcd_lane_status, '\0', sizeof(dpcd_lane_status));
335 memset(&dpcd_lane_status_updated, '\0',
336 sizeof(dpcd_lane_status_updated));
337
338 while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) &&
339 (retry_count < LINK_TRAINING_MAX_CR_RETRY)) {
340
341
342 /* 1. call HWSS to set lane settings */
343 dp_set_hw_lane_settings(
344 link,
345 link_res,
346 link_settings: lt_settings,
347 offset: 0);
348
349 /* 2. update DPCD of the receiver */
350 if (!retry_count) {
351 /* EPR #361076 - write as a 5-byte burst,
352 * but only for the 1-st iteration.
353 */
354 dpcd_set_lt_pattern_and_lane_settings(
355 link,
356 lt_settings,
357 pattern: lt_settings->pattern_for_cr,
358 offset: 0);
359 /* Vendor specific: Disable intercept */
360 for (i = 0; i < max_vendor_dpcd_retries; i++) {
361 if (pre_disable_intercept_delay_ms != 0)
362 msleep(msecs: pre_disable_intercept_delay_ms);
363 if (link_configure_fixed_vs_pe_retimer(ddc: link->ddc,
364 data: &vendor_lttpr_write_data_intercept_dis[0],
365 length: sizeof(vendor_lttpr_write_data_intercept_dis)))
366 break;
367
368 link_configure_fixed_vs_pe_retimer(ddc: link->ddc,
369 data: &vendor_lttpr_write_data_intercept_en[0],
370 length: sizeof(vendor_lttpr_write_data_intercept_en));
371 }
372 } else {
373 vendor_lttpr_write_data_vs[3] = 0;
374 vendor_lttpr_write_data_pe[3] = 0;
375
376 for (lane = 0; lane < lane_count; lane++) {
377 vendor_lttpr_write_data_vs[3] |=
378 lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane);
379 vendor_lttpr_write_data_pe[3] |=
380 lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane);
381 }
382
383 /* Vendor specific: Update VS and PE to DPRX requested value */
384 link_configure_fixed_vs_pe_retimer(ddc: link->ddc,
385 data: &vendor_lttpr_write_data_vs[0], length: sizeof(vendor_lttpr_write_data_vs));
386 link_configure_fixed_vs_pe_retimer(ddc: link->ddc,
387 data: &vendor_lttpr_write_data_pe[0], length: sizeof(vendor_lttpr_write_data_pe));
388
389 dpcd_set_lane_settings(
390 link,
391 link_training_setting: lt_settings,
392 offset: 0);
393 }
394
395 /* 3. wait receiver to lock-on*/
396 wait_time_microsec = lt_settings->cr_pattern_time;
397
398 dp_wait_for_training_aux_rd_interval(
399 link,
400 wait_in_micro_secs: wait_time_microsec);
401
402 /* 4. Read lane status and requested drive
403 * settings as set by the sink
404 */
405 dp_get_lane_status_and_lane_adjust(
406 link,
407 link_training_setting: lt_settings,
408 ln_status: dpcd_lane_status,
409 ln_align: &dpcd_lane_status_updated,
410 ln_adjust: dpcd_lane_adjust,
411 offset: 0);
412
413 /* 5. check CR done*/
414 if (dp_is_cr_done(ln_count: lane_count, dpcd_lane_status)) {
415 status = LINK_TRAINING_SUCCESS;
416 break;
417 }
418
419 /* 6. max VS reached*/
420 if (dp_is_max_vs_reached(lt_settings))
421 break;
422
423 /* 7. same lane settings */
424 /* Note: settings are the same for all lanes,
425 * so comparing first lane is sufficient
426 */
427 if (lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET ==
428 dpcd_lane_adjust[0].bits.VOLTAGE_SWING_LANE)
429 retries_cr++;
430 else
431 retries_cr = 0;
432
433 /* 8. update VS/PE/PC2 in lt_settings*/
434 dp_decide_lane_settings(lt_settings, ln_adjust: dpcd_lane_adjust,
435 hw_lane_settings: lt_settings->hw_lane_settings, dpcd_lane_settings: lt_settings->dpcd_lane_settings);
436 retry_count++;
437 }
438
439 if (retry_count >= LINK_TRAINING_MAX_CR_RETRY) {
440 ASSERT(0);
441 DC_LOG_ERROR("%s: Link Training Error, could not get CR after %d tries. Possibly voltage swing issue",
442 __func__,
443 LINK_TRAINING_MAX_CR_RETRY);
444
445 }
446
447 status = dp_get_cr_failure(ln_count: lane_count, dpcd_lane_status);
448 }
449
450 /* Perform Channel EQ Sequence */
451 if (status == LINK_TRAINING_SUCCESS) {
452 enum dc_dp_training_pattern tr_pattern;
453 uint32_t retries_ch_eq;
454 uint32_t wait_time_microsec;
455 enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
456 union lane_align_status_updated dpcd_lane_status_updated = {0};
457 union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
458 union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
459
460 link_configure_fixed_vs_pe_retimer(ddc: link->ddc,
461 data: &vendor_lttpr_write_data_adicora_eq1[0],
462 length: sizeof(vendor_lttpr_write_data_adicora_eq1));
463 link_configure_fixed_vs_pe_retimer(ddc: link->ddc,
464 data: &vendor_lttpr_write_data_adicora_eq2[0],
465 length: sizeof(vendor_lttpr_write_data_adicora_eq2));
466
467
468 /* Note: also check that TPS4 is a supported feature*/
469 tr_pattern = lt_settings->pattern_for_eq;
470
471 dp_set_hw_training_pattern(link, link_res, pattern: tr_pattern, offset: 0);
472
473 status = LINK_TRAINING_EQ_FAIL_EQ;
474
475 for (retries_ch_eq = 0; retries_ch_eq <= LINK_TRAINING_MAX_RETRY_COUNT;
476 retries_ch_eq++) {
477
478 dp_set_hw_lane_settings(link, link_res, link_settings: lt_settings, offset: 0);
479
480 vendor_lttpr_write_data_vs[3] = 0;
481 vendor_lttpr_write_data_pe[3] = 0;
482
483 for (lane = 0; lane < lane_count; lane++) {
484 vendor_lttpr_write_data_vs[3] |=
485 lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane);
486 vendor_lttpr_write_data_pe[3] |=
487 lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane);
488 }
489
490 /* Vendor specific: Update VS and PE to DPRX requested value */
491 link_configure_fixed_vs_pe_retimer(ddc: link->ddc,
492 data: &vendor_lttpr_write_data_vs[0], length: sizeof(vendor_lttpr_write_data_vs));
493 link_configure_fixed_vs_pe_retimer(ddc: link->ddc,
494 data: &vendor_lttpr_write_data_pe[0], length: sizeof(vendor_lttpr_write_data_pe));
495
496 /* 2. update DPCD*/
497 if (!retries_ch_eq) {
498 /* EPR #361076 - write as a 5-byte burst,
499 * but only for the 1-st iteration
500 */
501
502 dpcd_set_lt_pattern_and_lane_settings(
503 link,
504 lt_settings,
505 pattern: tr_pattern, offset: 0);
506
507 link_configure_fixed_vs_pe_retimer(ddc: link->ddc,
508 data: &vendor_lttpr_write_data_adicora_eq3[0],
509 length: sizeof(vendor_lttpr_write_data_adicora_eq3));
510
511 } else
512 dpcd_set_lane_settings(link, link_training_setting: lt_settings, offset: 0);
513
514 /* 3. wait for receiver to lock-on*/
515 wait_time_microsec = lt_settings->eq_pattern_time;
516
517 dp_wait_for_training_aux_rd_interval(
518 link,
519 wait_in_micro_secs: wait_time_microsec);
520
521 /* 4. Read lane status and requested
522 * drive settings as set by the sink
523 */
524 dp_get_lane_status_and_lane_adjust(
525 link,
526 link_training_setting: lt_settings,
527 ln_status: dpcd_lane_status,
528 ln_align: &dpcd_lane_status_updated,
529 ln_adjust: dpcd_lane_adjust,
530 offset: 0);
531
532 /* 5. check CR done*/
533 if (!dp_is_cr_done(ln_count: lane_count, dpcd_lane_status)) {
534 status = LINK_TRAINING_EQ_FAIL_CR;
535 break;
536 }
537
538 /* 6. check CHEQ done*/
539 if (dp_is_ch_eq_done(ln_count: lane_count, dpcd_lane_status) &&
540 dp_is_symbol_locked(ln_count: lane_count, dpcd_lane_status) &&
541 dp_is_interlane_aligned(align_status: dpcd_lane_status_updated)) {
542 status = LINK_TRAINING_SUCCESS;
543 break;
544 }
545
546 /* 7. update VS/PE/PC2 in lt_settings*/
547 dp_decide_lane_settings(lt_settings, ln_adjust: dpcd_lane_adjust,
548 hw_lane_settings: lt_settings->hw_lane_settings, dpcd_lane_settings: lt_settings->dpcd_lane_settings);
549 }
550 }
551
552 return status;
553}
554

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