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 
44 void 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(link->ddc,
56 			&vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs));
57 
58 	link_query_fixed_vs_pe_retimer(link->ddc, &dprx_vs, 1);
59 
60 	link_configure_fixed_vs_pe_retimer(link->ddc,
61 			&vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe));
62 
63 	link_query_fixed_vs_pe_retimer(link->ddc, &dprx_pe, 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 
72 void 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(link->ddc,
91 			&vendor_lttpr_write_data_reset[0], sizeof(vendor_lttpr_write_data_reset));
92 
93 	link_configure_fixed_vs_pe_retimer(link->ddc,
94 			&vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs));
95 
96 	link_configure_fixed_vs_pe_retimer(link->ddc,
97 			&vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe));
98 }
99 
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)
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(&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, 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 				&target_rate,
137 				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(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, repeater_id);
152 
153 			if (status != LINK_TRAINING_SUCCESS) {
154 				repeater_training_done(link, repeater_id);
155 				break;
156 			}
157 
158 			status = perform_8b_10b_channel_equalization_sequence(link,
159 					link_res,
160 					lt_settings,
161 					repeater_id);
162 
163 			repeater_training_done(link, 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, DPRX);
178 		if (status == LINK_TRAINING_SUCCESS) {
179 			status = perform_8b_10b_channel_equalization_sequence(link,
180 								       link_res,
181 								       lt_settings,
182 								       DPRX);
183 		}
184 	}
185 
186 	return status;
187 }
188 
189 
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)
194 {
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;
209 	uint8_t lane = 0;
210 	union down_spread_ctrl downspread = {0};
211 	union lane_count_set lane_count_set = {0};
212 	uint8_t toggle_rate;
213 	uint8_t rate;
214 
215 	/* Only 8b/10b is supported */
216 	ASSERT(link_dp_get_encoding_format(&lt_settings->link_settings) ==
217 			DP_8b_10b_ENCODING);
218 
219 	if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) {
220 		status = perform_fixed_vs_pe_nontransparent_training_sequence(link, link_res, lt_settings);
221 		return status;
222 	}
223 
224 	if (offset != 0xFF) {
225 		if (offset == 2) {
226 			pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa;
227 
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;
231 		}
232 	}
233 
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));
241 
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));
245 
246 
247 	/* 1. set link rate, lane count and spread. */
248 
249 	downspread.raw = (uint8_t)(lt_settings->link_settings.link_spread);
250 
251 	lane_count_set.bits.LANE_COUNT_SET =
252 	lt_settings->link_settings.lane_count;
253 
254 	lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing;
255 	lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0;
256 
257 
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;
261 	}
262 
263 	core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL,
264 		&downspread.raw, sizeof(downspread));
265 
266 	core_link_write_dpcd(link, DP_LANE_COUNT_SET,
267 		&lane_count_set.raw, 1);
268 
269 	rate = get_dpcd_link_rate(&lt_settings->link_settings);
270 
271 	/* Vendor specific: Toggle link rate */
272 	toggle_rate = (rate == 0x6) ? 0xA : 0x6;
273 
274 	if (link->vendor_specific_lttpr_link_rate_wa == rate || link->vendor_specific_lttpr_link_rate_wa == 0) {
275 		core_link_write_dpcd(
276 				link,
277 				DP_LINK_BW_SET,
278 				&toggle_rate,
279 				1);
280 	}
281 
282 	link->vendor_specific_lttpr_link_rate_wa = rate;
283 
284 	core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1);
285 
286 	DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x framing = %x\n %x spread = %x\n",
287 		__func__,
288 		DP_LINK_BW_SET,
289 		lt_settings->link_settings.link_rate,
290 		DP_LANE_COUNT_SET,
291 		lt_settings->link_settings.lane_count,
292 		lt_settings->enhanced_framing,
293 		DP_DOWNSPREAD_CTRL,
294 		lt_settings->link_settings.link_spread);
295 
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));
307 	}
308 
309 	/* 2. Perform link training */
310 
311 	/* Perform Clock Recovery Sequence */
312 	if (status == LINK_TRAINING_SUCCESS) {
313 		const uint8_t max_vendor_dpcd_retries = 10;
314 		uint32_t retries_cr;
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};
321 		uint8_t i = 0;
322 
323 		retries_cr = 0;
324 		retry_count = 0;
325 
326 		memset(&dpcd_lane_status, '\0', sizeof(dpcd_lane_status));
327 		memset(&dpcd_lane_status_updated, '\0',
328 		sizeof(dpcd_lane_status_updated));
329 
330 		while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) &&
331 			(retry_count < LINK_TRAINING_MAX_CR_RETRY)) {
332 
333 
334 			/* 1. call HWSS to set lane settings */
335 			dp_set_hw_lane_settings(
336 					link,
337 					link_res,
338 					lt_settings,
339 					0);
340 
341 			/* 2. update DPCD of the receiver */
342 			if (!retry_count) {
343 				/* EPR #361076 - write as a 5-byte burst,
344 				 * but only for the 1-st iteration.
345 				 */
346 				dpcd_set_lt_pattern_and_lane_settings(
347 						link,
348 						lt_settings,
349 						lt_settings->pattern_for_cr,
350 						0);
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)))
358 						break;
359 
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));
363 				}
364 			} else {
365 				vendor_lttpr_write_data_vs[3] = 0;
366 				vendor_lttpr_write_data_pe[3] = 0;
367 
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);
373 				}
374 
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));
380 
381 				dpcd_set_lane_settings(
382 						link,
383 						lt_settings,
384 						0);
385 			}
386 
387 			/* 3. wait receiver to lock-on*/
388 			wait_time_microsec = lt_settings->cr_pattern_time;
389 
390 			dp_wait_for_training_aux_rd_interval(
391 					link,
392 					wait_time_microsec);
393 
394 			/* 4. Read lane status and requested drive
395 			 * settings as set by the sink
396 			 */
397 			dp_get_lane_status_and_lane_adjust(
398 					link,
399 					lt_settings,
400 					dpcd_lane_status,
401 					&dpcd_lane_status_updated,
402 					dpcd_lane_adjust,
403 					0);
404 
405 			/* 5. check CR done*/
406 			if (dp_is_cr_done(lane_count, dpcd_lane_status)) {
407 				status = LINK_TRAINING_SUCCESS;
408 				break;
409 			}
410 
411 			/* 6. max VS reached*/
412 			if (dp_is_max_vs_reached(lt_settings))
413 				break;
414 
415 			/* 7. same lane settings */
416 			/* Note: settings are the same for all lanes,
417 			 * so comparing first lane is sufficient
418 			 */
419 			if (lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET ==
420 					dpcd_lane_adjust[0].bits.VOLTAGE_SWING_LANE)
421 				retries_cr++;
422 			else
423 				retries_cr = 0;
424 
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);
428 			retry_count++;
429 		}
430 
431 		if (retry_count >= LINK_TRAINING_MAX_CR_RETRY) {
432 			ASSERT(0);
433 			DC_LOG_ERROR("%s: Link Training Error, could not get CR after %d tries. Possibly voltage swing issue",
434 				__func__,
435 				LINK_TRAINING_MAX_CR_RETRY);
436 
437 		}
438 
439 		status = dp_get_cr_failure(lane_count, dpcd_lane_status);
440 	}
441 
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};
451 
452 		/* Note: also check that TPS4 is a supported feature*/
453 		tr_pattern = lt_settings->pattern_for_eq;
454 
455 		dp_set_hw_training_pattern(link, link_res, tr_pattern, 0);
456 
457 		status = LINK_TRAINING_EQ_FAIL_EQ;
458 
459 		for (retries_ch_eq = 0; retries_ch_eq <= LINK_TRAINING_MAX_RETRY_COUNT;
460 			retries_ch_eq++) {
461 
462 			dp_set_hw_lane_settings(link, link_res, lt_settings, 0);
463 
464 			vendor_lttpr_write_data_vs[3] = 0;
465 			vendor_lttpr_write_data_pe[3] = 0;
466 
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);
472 			}
473 
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));
479 
480 			/* 2. update DPCD*/
481 			if (!retries_ch_eq)
482 				/* EPR #361076 - write as a 5-byte burst,
483 				 * but only for the 1-st iteration
484 				 */
485 
486 				dpcd_set_lt_pattern_and_lane_settings(
487 					link,
488 					lt_settings,
489 					tr_pattern, 0);
490 			else
491 				dpcd_set_lane_settings(link, lt_settings, 0);
492 
493 			/* 3. wait for receiver to lock-on*/
494 			wait_time_microsec = lt_settings->eq_pattern_time;
495 
496 			dp_wait_for_training_aux_rd_interval(
497 					link,
498 					wait_time_microsec);
499 
500 			/* 4. Read lane status and requested
501 			 * drive settings as set by the sink
502 			 */
503 			dp_get_lane_status_and_lane_adjust(
504 				link,
505 				lt_settings,
506 				dpcd_lane_status,
507 				&dpcd_lane_status_updated,
508 				dpcd_lane_adjust,
509 				0);
510 
511 			/* 5. check CR done*/
512 			if (!dp_is_cr_done(lane_count, dpcd_lane_status)) {
513 				status = LINK_TRAINING_EQ_FAIL_CR;
514 				break;
515 			}
516 
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;
522 				break;
523 			}
524 
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);
528 		}
529 	}
530 
531 	return status;
532 }
533 
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)
538 {
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;
556 	uint8_t lane = 0;
557 	union down_spread_ctrl downspread = {0};
558 	union lane_count_set lane_count_set = {0};
559 	uint8_t toggle_rate;
560 	uint8_t rate;
561 
562 	/* Only 8b/10b is supported */
563 	ASSERT(link_dp_get_encoding_format(&lt_settings->link_settings) ==
564 			DP_8b_10b_ENCODING);
565 
566 	if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) {
567 		status = perform_fixed_vs_pe_nontransparent_training_sequence(link, link_res, lt_settings);
568 		return status;
569 	}
570 
571 	if (offset != 0xFF) {
572 		if (offset == 2) {
573 			pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa;
574 
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;
578 		}
579 	}
580 
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));
588 
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));
592 
593 	/* 1. set link rate, lane count and spread. */
594 
595 	downspread.raw = (uint8_t)(lt_settings->link_settings.link_spread);
596 
597 	lane_count_set.bits.LANE_COUNT_SET =
598 	lt_settings->link_settings.lane_count;
599 
600 	lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing;
601 	lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0;
602 
603 
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;
607 	}
608 
609 	core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL,
610 		&downspread.raw, sizeof(downspread));
611 
612 	core_link_write_dpcd(link, DP_LANE_COUNT_SET,
613 		&lane_count_set.raw, 1);
614 
615 	rate = get_dpcd_link_rate(&lt_settings->link_settings);
616 
617 	/* Vendor specific: Toggle link rate */
618 	toggle_rate = (rate == 0x6) ? 0xA : 0x6;
619 
620 	if (link->vendor_specific_lttpr_link_rate_wa == rate || link->vendor_specific_lttpr_link_rate_wa == 0) {
621 		core_link_write_dpcd(
622 				link,
623 				DP_LINK_BW_SET,
624 				&toggle_rate,
625 				1);
626 	}
627 
628 	link->vendor_specific_lttpr_link_rate_wa = rate;
629 
630 	core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1);
631 
632 	DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x framing = %x\n %x spread = %x\n",
633 		__func__,
634 		DP_LINK_BW_SET,
635 		lt_settings->link_settings.link_rate,
636 		DP_LANE_COUNT_SET,
637 		lt_settings->link_settings.lane_count,
638 		lt_settings->enhanced_framing,
639 		DP_DOWNSPREAD_CTRL,
640 		lt_settings->link_settings.link_spread);
641 
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));
653 	}
654 
655 	/* 2. Perform link training */
656 
657 	/* Perform Clock Recovery Sequence */
658 	if (status == LINK_TRAINING_SUCCESS) {
659 		const uint8_t max_vendor_dpcd_retries = 10;
660 		uint32_t retries_cr;
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};
667 		uint8_t i = 0;
668 
669 		retries_cr = 0;
670 		retry_count = 0;
671 
672 		memset(&dpcd_lane_status, '\0', sizeof(dpcd_lane_status));
673 		memset(&dpcd_lane_status_updated, '\0',
674 		sizeof(dpcd_lane_status_updated));
675 
676 		while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) &&
677 			(retry_count < LINK_TRAINING_MAX_CR_RETRY)) {
678 
679 
680 			/* 1. call HWSS to set lane settings */
681 			dp_set_hw_lane_settings(
682 					link,
683 					link_res,
684 					lt_settings,
685 					0);
686 
687 			/* 2. update DPCD of the receiver */
688 			if (!retry_count) {
689 				/* EPR #361076 - write as a 5-byte burst,
690 				 * but only for the 1-st iteration.
691 				 */
692 				dpcd_set_lt_pattern_and_lane_settings(
693 						link,
694 						lt_settings,
695 						lt_settings->pattern_for_cr,
696 						0);
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)))
704 						break;
705 
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));
709 				}
710 			} else {
711 				vendor_lttpr_write_data_vs[3] = 0;
712 				vendor_lttpr_write_data_pe[3] = 0;
713 
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);
719 				}
720 
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));
726 
727 				dpcd_set_lane_settings(
728 						link,
729 						lt_settings,
730 						0);
731 			}
732 
733 			/* 3. wait receiver to lock-on*/
734 			wait_time_microsec = lt_settings->cr_pattern_time;
735 
736 			dp_wait_for_training_aux_rd_interval(
737 					link,
738 					wait_time_microsec);
739 
740 			/* 4. Read lane status and requested drive
741 			 * settings as set by the sink
742 			 */
743 			dp_get_lane_status_and_lane_adjust(
744 					link,
745 					lt_settings,
746 					dpcd_lane_status,
747 					&dpcd_lane_status_updated,
748 					dpcd_lane_adjust,
749 					0);
750 
751 			/* 5. check CR done*/
752 			if (dp_is_cr_done(lane_count, dpcd_lane_status)) {
753 				status = LINK_TRAINING_SUCCESS;
754 				break;
755 			}
756 
757 			/* 6. max VS reached*/
758 			if (dp_is_max_vs_reached(lt_settings))
759 				break;
760 
761 			/* 7. same lane settings */
762 			/* Note: settings are the same for all lanes,
763 			 * so comparing first lane is sufficient
764 			 */
765 			if (lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET ==
766 					dpcd_lane_adjust[0].bits.VOLTAGE_SWING_LANE)
767 				retries_cr++;
768 			else
769 				retries_cr = 0;
770 
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);
774 			retry_count++;
775 		}
776 
777 		if (retry_count >= LINK_TRAINING_MAX_CR_RETRY) {
778 			ASSERT(0);
779 			DC_LOG_ERROR("%s: Link Training Error, could not get CR after %d tries. Possibly voltage swing issue",
780 				__func__,
781 				LINK_TRAINING_MAX_CR_RETRY);
782 
783 		}
784 
785 		status = dp_get_cr_failure(lane_count, dpcd_lane_status);
786 	}
787 
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};
797 
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));
804 
805 
806 		/* Note: also check that TPS4 is a supported feature*/
807 		tr_pattern = lt_settings->pattern_for_eq;
808 
809 		dp_set_hw_training_pattern(link, link_res, tr_pattern, 0);
810 
811 		status = LINK_TRAINING_EQ_FAIL_EQ;
812 
813 		for (retries_ch_eq = 0; retries_ch_eq <= LINK_TRAINING_MAX_RETRY_COUNT;
814 			retries_ch_eq++) {
815 
816 			dp_set_hw_lane_settings(link, link_res, lt_settings, 0);
817 
818 			vendor_lttpr_write_data_vs[3] = 0;
819 			vendor_lttpr_write_data_pe[3] = 0;
820 
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);
826 			}
827 
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));
833 
834 			/* 2. update DPCD*/
835 			if (!retries_ch_eq) {
836 				/* EPR #361076 - write as a 5-byte burst,
837 				 * but only for the 1-st iteration
838 				 */
839 
840 				dpcd_set_lt_pattern_and_lane_settings(
841 					link,
842 					lt_settings,
843 					tr_pattern, 0);
844 
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));
848 
849 			} else
850 				dpcd_set_lane_settings(link, lt_settings, 0);
851 
852 			/* 3. wait for receiver to lock-on*/
853 			wait_time_microsec = lt_settings->eq_pattern_time;
854 
855 			dp_wait_for_training_aux_rd_interval(
856 					link,
857 					wait_time_microsec);
858 
859 			/* 4. Read lane status and requested
860 			 * drive settings as set by the sink
861 			 */
862 			dp_get_lane_status_and_lane_adjust(
863 				link,
864 				lt_settings,
865 				dpcd_lane_status,
866 				&dpcd_lane_status_updated,
867 				dpcd_lane_adjust,
868 				0);
869 
870 			/* 5. check CR done*/
871 			if (!dp_is_cr_done(lane_count, dpcd_lane_status)) {
872 				status = LINK_TRAINING_EQ_FAIL_CR;
873 				break;
874 			}
875 
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;
881 				break;
882 			}
883 
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);
887 		}
888 	}
889 
890 	return status;
891 }
892