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(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
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(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
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(&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
190enum 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						drm_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
534enum 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						drm_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