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 
dp_fixed_vs_pe_read_lane_adjust(struct dc_link * link,union dpcd_training_lane dpcd_lane_adjust[LANE_COUNT_DP_MAX])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 
dp_fixed_vs_pe_set_retimer_lane_settings(struct dc_link * link,const union dpcd_training_lane dpcd_lane_adjust[LANE_COUNT_DP_MAX],uint8_t lane_count)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 
perform_fixed_vs_pe_nontransparent_training_sequence(struct dc_link * link,const struct link_resource * link_res,struct link_training_settings * lt_settings)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 
dp_perform_fixed_vs_pe_training_sequence_legacy(struct dc_link * link,const struct link_resource * link_res,struct link_training_settings * lt_settings)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 	const uint8_t vendor_lttpr_write_data_dpmf[4] = {0x1, 0x6, 0x70, 0x87};
209 	enum link_training_result status = LINK_TRAINING_SUCCESS;
210 	uint8_t lane = 0;
211 	union down_spread_ctrl downspread = {0};
212 	union lane_count_set lane_count_set = {0};
213 	uint8_t toggle_rate;
214 	uint8_t rate;
215 
216 	/* Only 8b/10b is supported */
217 	ASSERT(link_dp_get_encoding_format(&lt_settings->link_settings) ==
218 			DP_8b_10b_ENCODING);
219 
220 	if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) {
221 		status = perform_fixed_vs_pe_nontransparent_training_sequence(link, link_res, lt_settings);
222 		return status;
223 	}
224 
225 	if (offset != 0xFF) {
226 		if (offset == 2) {
227 			pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa;
228 
229 		/* Certain display and cable configuration require extra delay */
230 		} else if (offset > 2) {
231 			pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa * 2;
232 		}
233 	}
234 
235 	/* Vendor specific: Reset lane settings */
236 	link_configure_fixed_vs_pe_retimer(link->ddc,
237 			&vendor_lttpr_write_data_reset[0], sizeof(vendor_lttpr_write_data_reset));
238 	link_configure_fixed_vs_pe_retimer(link->ddc,
239 			&vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs));
240 	link_configure_fixed_vs_pe_retimer(link->ddc,
241 			&vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe));
242 
243 	/* Vendor specific: Enable intercept */
244 	link_configure_fixed_vs_pe_retimer(link->ddc,
245 			&vendor_lttpr_write_data_intercept_en[0], sizeof(vendor_lttpr_write_data_intercept_en));
246 
247 
248 	/* 1. set link rate, lane count and spread. */
249 
250 	downspread.raw = (uint8_t)(lt_settings->link_settings.link_spread);
251 
252 	lane_count_set.bits.LANE_COUNT_SET =
253 	lt_settings->link_settings.lane_count;
254 
255 	lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing;
256 	lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0;
257 
258 
259 	if (lt_settings->pattern_for_eq < DP_TRAINING_PATTERN_SEQUENCE_4) {
260 		lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED =
261 				link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED;
262 	}
263 
264 	core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL,
265 		&downspread.raw, sizeof(downspread));
266 
267 	core_link_write_dpcd(link, DP_LANE_COUNT_SET,
268 		&lane_count_set.raw, 1);
269 
270 	rate = get_dpcd_link_rate(&lt_settings->link_settings);
271 
272 	/* Vendor specific: Toggle link rate */
273 	toggle_rate = (rate == 0x6) ? 0xA : 0x6;
274 
275 	if (link->vendor_specific_lttpr_link_rate_wa == rate || link->vendor_specific_lttpr_link_rate_wa == 0) {
276 		core_link_write_dpcd(
277 				link,
278 				DP_LINK_BW_SET,
279 				&toggle_rate,
280 				1);
281 	}
282 
283 	link->vendor_specific_lttpr_link_rate_wa = rate;
284 
285 	core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1);
286 
287 	DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x framing = %x\n %x spread = %x\n",
288 		__func__,
289 		DP_LINK_BW_SET,
290 		lt_settings->link_settings.link_rate,
291 		DP_LANE_COUNT_SET,
292 		lt_settings->link_settings.lane_count,
293 		lt_settings->enhanced_framing,
294 		DP_DOWNSPREAD_CTRL,
295 		lt_settings->link_settings.link_spread);
296 
297 	link_configure_fixed_vs_pe_retimer(link->ddc,
298 			&vendor_lttpr_write_data_dpmf[0],
299 			sizeof(vendor_lttpr_write_data_dpmf));
300 
301 	if (lt_settings->link_settings.lane_count == LANE_COUNT_FOUR) {
302 		link_configure_fixed_vs_pe_retimer(link->ddc,
303 				&vendor_lttpr_write_data_4lane_1[0], sizeof(vendor_lttpr_write_data_4lane_1));
304 		link_configure_fixed_vs_pe_retimer(link->ddc,
305 				&vendor_lttpr_write_data_4lane_2[0], sizeof(vendor_lttpr_write_data_4lane_2));
306 		link_configure_fixed_vs_pe_retimer(link->ddc,
307 				&vendor_lttpr_write_data_4lane_3[0], sizeof(vendor_lttpr_write_data_4lane_3));
308 		link_configure_fixed_vs_pe_retimer(link->ddc,
309 				&vendor_lttpr_write_data_4lane_4[0], sizeof(vendor_lttpr_write_data_4lane_4));
310 		link_configure_fixed_vs_pe_retimer(link->ddc,
311 				&vendor_lttpr_write_data_4lane_5[0], sizeof(vendor_lttpr_write_data_4lane_5));
312 	}
313 
314 	/* 2. Perform link training */
315 
316 	/* Perform Clock Recovery Sequence */
317 	if (status == LINK_TRAINING_SUCCESS) {
318 		const uint8_t max_vendor_dpcd_retries = 10;
319 		uint32_t retries_cr;
320 		uint32_t retry_count;
321 		uint32_t wait_time_microsec;
322 		enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
323 		union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX];
324 		union lane_align_status_updated dpcd_lane_status_updated;
325 		union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
326 		uint8_t i = 0;
327 
328 		retries_cr = 0;
329 		retry_count = 0;
330 
331 		memset(&dpcd_lane_status, '\0', sizeof(dpcd_lane_status));
332 		memset(&dpcd_lane_status_updated, '\0',
333 		sizeof(dpcd_lane_status_updated));
334 
335 		while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) &&
336 			(retry_count < LINK_TRAINING_MAX_CR_RETRY)) {
337 
338 
339 			/* 1. call HWSS to set lane settings */
340 			dp_set_hw_lane_settings(
341 					link,
342 					link_res,
343 					lt_settings,
344 					0);
345 
346 			/* 2. update DPCD of the receiver */
347 			if (!retry_count) {
348 				/* EPR #361076 - write as a 5-byte burst,
349 				 * but only for the 1-st iteration.
350 				 */
351 				dpcd_set_lt_pattern_and_lane_settings(
352 						link,
353 						lt_settings,
354 						lt_settings->pattern_for_cr,
355 						0);
356 				/* Vendor specific: Disable intercept */
357 				for (i = 0; i < max_vendor_dpcd_retries; i++) {
358 					if (pre_disable_intercept_delay_ms != 0)
359 						msleep(pre_disable_intercept_delay_ms);
360 					if (link_configure_fixed_vs_pe_retimer(link->ddc,
361 							&vendor_lttpr_write_data_intercept_dis[0],
362 							sizeof(vendor_lttpr_write_data_intercept_dis)))
363 						break;
364 
365 					link_configure_fixed_vs_pe_retimer(link->ddc,
366 							&vendor_lttpr_write_data_intercept_en[0],
367 							sizeof(vendor_lttpr_write_data_intercept_en));
368 				}
369 			} else {
370 				vendor_lttpr_write_data_vs[3] = 0;
371 				vendor_lttpr_write_data_pe[3] = 0;
372 
373 				for (lane = 0; lane < lane_count; lane++) {
374 					vendor_lttpr_write_data_vs[3] |=
375 							lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane);
376 					vendor_lttpr_write_data_pe[3] |=
377 							lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane);
378 				}
379 
380 				/* Vendor specific: Update VS and PE to DPRX requested value */
381 				link_configure_fixed_vs_pe_retimer(link->ddc,
382 						&vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs));
383 				link_configure_fixed_vs_pe_retimer(link->ddc,
384 						&vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe));
385 
386 				dpcd_set_lane_settings(
387 						link,
388 						lt_settings,
389 						0);
390 			}
391 
392 			/* 3. wait receiver to lock-on*/
393 			wait_time_microsec = lt_settings->cr_pattern_time;
394 
395 			dp_wait_for_training_aux_rd_interval(
396 					link,
397 					wait_time_microsec);
398 
399 			/* 4. Read lane status and requested drive
400 			 * settings as set by the sink
401 			 */
402 			dp_get_lane_status_and_lane_adjust(
403 					link,
404 					lt_settings,
405 					dpcd_lane_status,
406 					&dpcd_lane_status_updated,
407 					dpcd_lane_adjust,
408 					0);
409 
410 			/* 5. check CR done*/
411 			if (dp_is_cr_done(lane_count, dpcd_lane_status)) {
412 				status = LINK_TRAINING_SUCCESS;
413 				break;
414 			}
415 
416 			/* 6. max VS reached*/
417 			if (dp_is_max_vs_reached(lt_settings))
418 				break;
419 
420 			/* 7. same lane settings */
421 			/* Note: settings are the same for all lanes,
422 			 * so comparing first lane is sufficient
423 			 */
424 			if (lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET ==
425 					dpcd_lane_adjust[0].bits.VOLTAGE_SWING_LANE)
426 				retries_cr++;
427 			else
428 				retries_cr = 0;
429 
430 			/* 8. update VS/PE/PC2 in lt_settings*/
431 			dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
432 					lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
433 			retry_count++;
434 		}
435 
436 		if (retry_count >= LINK_TRAINING_MAX_CR_RETRY) {
437 			ASSERT(0);
438 			DC_LOG_ERROR("%s: Link Training Error, could not get CR after %d tries. Possibly voltage swing issue",
439 				__func__,
440 				LINK_TRAINING_MAX_CR_RETRY);
441 
442 		}
443 
444 		status = dp_get_cr_failure(lane_count, dpcd_lane_status);
445 	}
446 
447 	/* Perform Channel EQ Sequence */
448 	if (status == LINK_TRAINING_SUCCESS) {
449 		enum dc_dp_training_pattern tr_pattern;
450 		uint32_t retries_ch_eq;
451 		uint32_t wait_time_microsec;
452 		enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
453 		union lane_align_status_updated dpcd_lane_status_updated = {0};
454 		union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
455 		union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
456 
457 		/* Note: also check that TPS4 is a supported feature*/
458 		tr_pattern = lt_settings->pattern_for_eq;
459 
460 		dp_set_hw_training_pattern(link, link_res, tr_pattern, 0);
461 
462 		status = LINK_TRAINING_EQ_FAIL_EQ;
463 
464 		for (retries_ch_eq = 0; retries_ch_eq <= LINK_TRAINING_MAX_RETRY_COUNT;
465 			retries_ch_eq++) {
466 
467 			dp_set_hw_lane_settings(link, link_res, lt_settings, 0);
468 
469 			vendor_lttpr_write_data_vs[3] = 0;
470 			vendor_lttpr_write_data_pe[3] = 0;
471 
472 			for (lane = 0; lane < lane_count; lane++) {
473 				vendor_lttpr_write_data_vs[3] |=
474 						lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane);
475 				vendor_lttpr_write_data_pe[3] |=
476 						lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane);
477 			}
478 
479 			/* Vendor specific: Update VS and PE to DPRX requested value */
480 			link_configure_fixed_vs_pe_retimer(link->ddc,
481 					&vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs));
482 			link_configure_fixed_vs_pe_retimer(link->ddc,
483 					&vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe));
484 
485 			/* 2. update DPCD*/
486 			if (!retries_ch_eq)
487 				/* EPR #361076 - write as a 5-byte burst,
488 				 * but only for the 1-st iteration
489 				 */
490 
491 				dpcd_set_lt_pattern_and_lane_settings(
492 					link,
493 					lt_settings,
494 					tr_pattern, 0);
495 			else
496 				dpcd_set_lane_settings(link, lt_settings, 0);
497 
498 			/* 3. wait for receiver to lock-on*/
499 			wait_time_microsec = lt_settings->eq_pattern_time;
500 
501 			dp_wait_for_training_aux_rd_interval(
502 					link,
503 					wait_time_microsec);
504 
505 			/* 4. Read lane status and requested
506 			 * drive settings as set by the sink
507 			 */
508 			dp_get_lane_status_and_lane_adjust(
509 				link,
510 				lt_settings,
511 				dpcd_lane_status,
512 				&dpcd_lane_status_updated,
513 				dpcd_lane_adjust,
514 				0);
515 
516 			/* 5. check CR done*/
517 			if (!dp_is_cr_done(lane_count, dpcd_lane_status)) {
518 				status = LINK_TRAINING_EQ_FAIL_CR;
519 				break;
520 			}
521 
522 			/* 6. check CHEQ done*/
523 			if (dp_is_ch_eq_done(lane_count, dpcd_lane_status) &&
524 					dp_is_symbol_locked(lane_count, dpcd_lane_status) &&
525 					dp_is_interlane_aligned(dpcd_lane_status_updated)) {
526 				status = LINK_TRAINING_SUCCESS;
527 				break;
528 			}
529 
530 			/* 7. update VS/PE/PC2 in lt_settings*/
531 			dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
532 					lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
533 		}
534 	}
535 
536 	return status;
537 }
538 
dp_perform_fixed_vs_pe_training_sequence(struct dc_link * link,const struct link_resource * link_res,struct link_training_settings * lt_settings)539 enum link_training_result dp_perform_fixed_vs_pe_training_sequence(
540 	struct dc_link *link,
541 	const struct link_resource *link_res,
542 	struct link_training_settings *lt_settings)
543 {
544 	const uint8_t vendor_lttpr_write_data_reset[4] = {0x1, 0x50, 0x63, 0xFF};
545 	const uint8_t offset = dp_parse_lttpr_repeater_count(
546 			link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
547 	const uint8_t vendor_lttpr_write_data_intercept_en[4] = {0x1, 0x55, 0x63, 0x0};
548 	const uint8_t vendor_lttpr_write_data_intercept_dis[4] = {0x1, 0x55, 0x63, 0x6E};
549 	const uint8_t vendor_lttpr_write_data_adicora_eq1[4] = {0x1, 0x55, 0x63, 0x2E};
550 	const uint8_t vendor_lttpr_write_data_adicora_eq2[4] = {0x1, 0x55, 0x63, 0x01};
551 	const uint8_t vendor_lttpr_write_data_adicora_eq3[4] = {0x1, 0x55, 0x63, 0x68};
552 	uint32_t pre_disable_intercept_delay_ms = 0;
553 	uint8_t vendor_lttpr_write_data_vs[4] = {0x1, 0x51, 0x63, 0x0};
554 	uint8_t vendor_lttpr_write_data_pe[4] = {0x1, 0x52, 0x63, 0x0};
555 	const uint8_t vendor_lttpr_write_data_4lane_1[4] = {0x1, 0x6E, 0xF2, 0x19};
556 	const uint8_t vendor_lttpr_write_data_4lane_2[4] = {0x1, 0x6B, 0xF2, 0x01};
557 	const uint8_t vendor_lttpr_write_data_4lane_3[4] = {0x1, 0x6D, 0xF2, 0x18};
558 	const uint8_t vendor_lttpr_write_data_4lane_4[4] = {0x1, 0x6C, 0xF2, 0x03};
559 	const uint8_t vendor_lttpr_write_data_4lane_5[4] = {0x1, 0x03, 0xF3, 0x06};
560 	const uint8_t vendor_lttpr_write_data_dpmf[4] = {0x1, 0x6, 0x70, 0x87};
561 	enum link_training_result status = LINK_TRAINING_SUCCESS;
562 	uint8_t lane = 0;
563 	union down_spread_ctrl downspread = {0};
564 	union lane_count_set lane_count_set = {0};
565 	uint8_t toggle_rate;
566 	uint8_t rate;
567 
568 	/* Only 8b/10b is supported */
569 	ASSERT(link_dp_get_encoding_format(&lt_settings->link_settings) ==
570 			DP_8b_10b_ENCODING);
571 
572 	if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) {
573 		status = perform_fixed_vs_pe_nontransparent_training_sequence(link, link_res, lt_settings);
574 		return status;
575 	}
576 
577 	if (offset != 0xFF) {
578 		if (offset == 2) {
579 			pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa;
580 
581 		/* Certain display and cable configuration require extra delay */
582 		} else if (offset > 2) {
583 			pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa * 2;
584 		}
585 	}
586 
587 	/* Vendor specific: Reset lane settings */
588 	link_configure_fixed_vs_pe_retimer(link->ddc,
589 			&vendor_lttpr_write_data_reset[0], sizeof(vendor_lttpr_write_data_reset));
590 	link_configure_fixed_vs_pe_retimer(link->ddc,
591 			&vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs));
592 	link_configure_fixed_vs_pe_retimer(link->ddc,
593 			&vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe));
594 
595 	/* Vendor specific: Enable intercept */
596 	link_configure_fixed_vs_pe_retimer(link->ddc,
597 			&vendor_lttpr_write_data_intercept_en[0], sizeof(vendor_lttpr_write_data_intercept_en));
598 
599 	/* 1. set link rate, lane count and spread. */
600 
601 	downspread.raw = (uint8_t)(lt_settings->link_settings.link_spread);
602 
603 	lane_count_set.bits.LANE_COUNT_SET =
604 	lt_settings->link_settings.lane_count;
605 
606 	lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing;
607 	lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0;
608 
609 
610 	if (lt_settings->pattern_for_eq < DP_TRAINING_PATTERN_SEQUENCE_4) {
611 		lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED =
612 				link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED;
613 	}
614 
615 	core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL,
616 		&downspread.raw, sizeof(downspread));
617 
618 	core_link_write_dpcd(link, DP_LANE_COUNT_SET,
619 		&lane_count_set.raw, 1);
620 
621 	rate = get_dpcd_link_rate(&lt_settings->link_settings);
622 
623 	/* Vendor specific: Toggle link rate */
624 	toggle_rate = (rate == 0x6) ? 0xA : 0x6;
625 
626 	if (link->vendor_specific_lttpr_link_rate_wa == rate || link->vendor_specific_lttpr_link_rate_wa == 0) {
627 		core_link_write_dpcd(
628 				link,
629 				DP_LINK_BW_SET,
630 				&toggle_rate,
631 				1);
632 	}
633 
634 	link->vendor_specific_lttpr_link_rate_wa = rate;
635 
636 	core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1);
637 
638 	DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x framing = %x\n %x spread = %x\n",
639 		__func__,
640 		DP_LINK_BW_SET,
641 		lt_settings->link_settings.link_rate,
642 		DP_LANE_COUNT_SET,
643 		lt_settings->link_settings.lane_count,
644 		lt_settings->enhanced_framing,
645 		DP_DOWNSPREAD_CTRL,
646 		lt_settings->link_settings.link_spread);
647 
648 	link_configure_fixed_vs_pe_retimer(link->ddc,
649 			&vendor_lttpr_write_data_dpmf[0],
650 			sizeof(vendor_lttpr_write_data_dpmf));
651 
652 	if (lt_settings->link_settings.lane_count == LANE_COUNT_FOUR) {
653 		link_configure_fixed_vs_pe_retimer(link->ddc,
654 				&vendor_lttpr_write_data_4lane_1[0], sizeof(vendor_lttpr_write_data_4lane_1));
655 		link_configure_fixed_vs_pe_retimer(link->ddc,
656 				&vendor_lttpr_write_data_4lane_2[0], sizeof(vendor_lttpr_write_data_4lane_2));
657 		link_configure_fixed_vs_pe_retimer(link->ddc,
658 				&vendor_lttpr_write_data_4lane_3[0], sizeof(vendor_lttpr_write_data_4lane_3));
659 		link_configure_fixed_vs_pe_retimer(link->ddc,
660 				&vendor_lttpr_write_data_4lane_4[0], sizeof(vendor_lttpr_write_data_4lane_4));
661 		link_configure_fixed_vs_pe_retimer(link->ddc,
662 				&vendor_lttpr_write_data_4lane_5[0], sizeof(vendor_lttpr_write_data_4lane_5));
663 	}
664 
665 	/* 2. Perform link training */
666 
667 	/* Perform Clock Recovery Sequence */
668 	if (status == LINK_TRAINING_SUCCESS) {
669 		const uint8_t max_vendor_dpcd_retries = 10;
670 		uint32_t retries_cr;
671 		uint32_t retry_count;
672 		uint32_t wait_time_microsec;
673 		enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
674 		union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX];
675 		union lane_align_status_updated dpcd_lane_status_updated;
676 		union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
677 		uint8_t i = 0;
678 
679 		retries_cr = 0;
680 		retry_count = 0;
681 
682 		memset(&dpcd_lane_status, '\0', sizeof(dpcd_lane_status));
683 		memset(&dpcd_lane_status_updated, '\0',
684 		sizeof(dpcd_lane_status_updated));
685 
686 		while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) &&
687 			(retry_count < LINK_TRAINING_MAX_CR_RETRY)) {
688 
689 
690 			/* 1. call HWSS to set lane settings */
691 			dp_set_hw_lane_settings(
692 					link,
693 					link_res,
694 					lt_settings,
695 					0);
696 
697 			/* 2. update DPCD of the receiver */
698 			if (!retry_count) {
699 				/* EPR #361076 - write as a 5-byte burst,
700 				 * but only for the 1-st iteration.
701 				 */
702 				dpcd_set_lt_pattern_and_lane_settings(
703 						link,
704 						lt_settings,
705 						lt_settings->pattern_for_cr,
706 						0);
707 				/* Vendor specific: Disable intercept */
708 				for (i = 0; i < max_vendor_dpcd_retries; i++) {
709 					if (pre_disable_intercept_delay_ms != 0)
710 						msleep(pre_disable_intercept_delay_ms);
711 					if (link_configure_fixed_vs_pe_retimer(link->ddc,
712 							&vendor_lttpr_write_data_intercept_dis[0],
713 							sizeof(vendor_lttpr_write_data_intercept_dis)))
714 						break;
715 
716 					link_configure_fixed_vs_pe_retimer(link->ddc,
717 							&vendor_lttpr_write_data_intercept_en[0],
718 							sizeof(vendor_lttpr_write_data_intercept_en));
719 				}
720 			} else {
721 				vendor_lttpr_write_data_vs[3] = 0;
722 				vendor_lttpr_write_data_pe[3] = 0;
723 
724 				for (lane = 0; lane < lane_count; lane++) {
725 					vendor_lttpr_write_data_vs[3] |=
726 							lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane);
727 					vendor_lttpr_write_data_pe[3] |=
728 							lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane);
729 				}
730 
731 				/* Vendor specific: Update VS and PE to DPRX requested value */
732 				link_configure_fixed_vs_pe_retimer(link->ddc,
733 						&vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs));
734 				link_configure_fixed_vs_pe_retimer(link->ddc,
735 						&vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe));
736 
737 				dpcd_set_lane_settings(
738 						link,
739 						lt_settings,
740 						0);
741 			}
742 
743 			/* 3. wait receiver to lock-on*/
744 			wait_time_microsec = lt_settings->cr_pattern_time;
745 
746 			dp_wait_for_training_aux_rd_interval(
747 					link,
748 					wait_time_microsec);
749 
750 			/* 4. Read lane status and requested drive
751 			 * settings as set by the sink
752 			 */
753 			dp_get_lane_status_and_lane_adjust(
754 					link,
755 					lt_settings,
756 					dpcd_lane_status,
757 					&dpcd_lane_status_updated,
758 					dpcd_lane_adjust,
759 					0);
760 
761 			/* 5. check CR done*/
762 			if (dp_is_cr_done(lane_count, dpcd_lane_status)) {
763 				status = LINK_TRAINING_SUCCESS;
764 				break;
765 			}
766 
767 			/* 6. max VS reached*/
768 			if (dp_is_max_vs_reached(lt_settings))
769 				break;
770 
771 			/* 7. same lane settings */
772 			/* Note: settings are the same for all lanes,
773 			 * so comparing first lane is sufficient
774 			 */
775 			if (lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET ==
776 					dpcd_lane_adjust[0].bits.VOLTAGE_SWING_LANE)
777 				retries_cr++;
778 			else
779 				retries_cr = 0;
780 
781 			/* 8. update VS/PE/PC2 in lt_settings*/
782 			dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
783 					lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
784 			retry_count++;
785 		}
786 
787 		if (retry_count >= LINK_TRAINING_MAX_CR_RETRY) {
788 			ASSERT(0);
789 			DC_LOG_ERROR("%s: Link Training Error, could not get CR after %d tries. Possibly voltage swing issue",
790 				__func__,
791 				LINK_TRAINING_MAX_CR_RETRY);
792 
793 		}
794 
795 		status = dp_get_cr_failure(lane_count, dpcd_lane_status);
796 	}
797 
798 	/* Perform Channel EQ Sequence */
799 	if (status == LINK_TRAINING_SUCCESS) {
800 		enum dc_dp_training_pattern tr_pattern;
801 		uint32_t retries_ch_eq;
802 		uint32_t wait_time_microsec;
803 		enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
804 		union lane_align_status_updated dpcd_lane_status_updated = {0};
805 		union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
806 		union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
807 
808 		link_configure_fixed_vs_pe_retimer(link->ddc,
809 				&vendor_lttpr_write_data_adicora_eq1[0],
810 				sizeof(vendor_lttpr_write_data_adicora_eq1));
811 		link_configure_fixed_vs_pe_retimer(link->ddc,
812 				&vendor_lttpr_write_data_adicora_eq2[0],
813 				sizeof(vendor_lttpr_write_data_adicora_eq2));
814 
815 
816 		/* Note: also check that TPS4 is a supported feature*/
817 		tr_pattern = lt_settings->pattern_for_eq;
818 
819 		dp_set_hw_training_pattern(link, link_res, tr_pattern, 0);
820 
821 		status = LINK_TRAINING_EQ_FAIL_EQ;
822 
823 		for (retries_ch_eq = 0; retries_ch_eq <= LINK_TRAINING_MAX_RETRY_COUNT;
824 			retries_ch_eq++) {
825 
826 			dp_set_hw_lane_settings(link, link_res, lt_settings, 0);
827 
828 			vendor_lttpr_write_data_vs[3] = 0;
829 			vendor_lttpr_write_data_pe[3] = 0;
830 
831 			for (lane = 0; lane < lane_count; lane++) {
832 				vendor_lttpr_write_data_vs[3] |=
833 						lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane);
834 				vendor_lttpr_write_data_pe[3] |=
835 						lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane);
836 			}
837 
838 			/* Vendor specific: Update VS and PE to DPRX requested value */
839 			link_configure_fixed_vs_pe_retimer(link->ddc,
840 					&vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs));
841 			link_configure_fixed_vs_pe_retimer(link->ddc,
842 					&vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe));
843 
844 			/* 2. update DPCD*/
845 			if (!retries_ch_eq) {
846 				/* EPR #361076 - write as a 5-byte burst,
847 				 * but only for the 1-st iteration
848 				 */
849 
850 				dpcd_set_lt_pattern_and_lane_settings(
851 					link,
852 					lt_settings,
853 					tr_pattern, 0);
854 
855 				link_configure_fixed_vs_pe_retimer(link->ddc,
856 						&vendor_lttpr_write_data_adicora_eq3[0],
857 						sizeof(vendor_lttpr_write_data_adicora_eq3));
858 
859 			} else
860 				dpcd_set_lane_settings(link, lt_settings, 0);
861 
862 			/* 3. wait for receiver to lock-on*/
863 			wait_time_microsec = lt_settings->eq_pattern_time;
864 
865 			dp_wait_for_training_aux_rd_interval(
866 					link,
867 					wait_time_microsec);
868 
869 			/* 4. Read lane status and requested
870 			 * drive settings as set by the sink
871 			 */
872 			dp_get_lane_status_and_lane_adjust(
873 				link,
874 				lt_settings,
875 				dpcd_lane_status,
876 				&dpcd_lane_status_updated,
877 				dpcd_lane_adjust,
878 				0);
879 
880 			/* 5. check CR done*/
881 			if (!dp_is_cr_done(lane_count, dpcd_lane_status)) {
882 				status = LINK_TRAINING_EQ_FAIL_CR;
883 				break;
884 			}
885 
886 			/* 6. check CHEQ done*/
887 			if (dp_is_ch_eq_done(lane_count, dpcd_lane_status) &&
888 					dp_is_symbol_locked(lane_count, dpcd_lane_status) &&
889 					dp_is_interlane_aligned(dpcd_lane_status_updated)) {
890 				status = LINK_TRAINING_SUCCESS;
891 				break;
892 			}
893 
894 			/* 7. update VS/PE/PC2 in lt_settings*/
895 			dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
896 					lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
897 		}
898 	}
899 
900 	return status;
901 }
902