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 dp 8b/10b link training software policies and
28  * sequences.
29  */
30 #include "link_dp_training_8b_10b.h"
31 #include "link_dpcd.h"
32 #include "link_dp_phy.h"
33 #include "link_dp_capability.h"
34 
35 #define DC_LOGGER \
36 	link->ctx->logger
37 
get_cr_training_aux_rd_interval(struct dc_link * link,const struct dc_link_settings * link_settings)38 static int32_t get_cr_training_aux_rd_interval(struct dc_link *link,
39 		const struct dc_link_settings *link_settings)
40 {
41 	union training_aux_rd_interval training_rd_interval;
42 	uint32_t wait_in_micro_secs = 100;
43 
44 	memset(&training_rd_interval, 0, sizeof(training_rd_interval));
45 	if (link_dp_get_encoding_format(link_settings) == DP_8b_10b_ENCODING &&
46 			link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_12) {
47 		core_link_read_dpcd(
48 				link,
49 				DP_TRAINING_AUX_RD_INTERVAL,
50 				(uint8_t *)&training_rd_interval,
51 				sizeof(training_rd_interval));
52 		if (training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL)
53 			wait_in_micro_secs = training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL * 4000;
54 	}
55 	return wait_in_micro_secs;
56 }
57 
get_eq_training_aux_rd_interval(struct dc_link * link,const struct dc_link_settings * link_settings)58 static uint32_t get_eq_training_aux_rd_interval(
59 	struct dc_link *link,
60 	const struct dc_link_settings *link_settings)
61 {
62 	union training_aux_rd_interval training_rd_interval;
63 
64 	memset(&training_rd_interval, 0, sizeof(training_rd_interval));
65 	if (link_dp_get_encoding_format(link_settings) == DP_128b_132b_ENCODING) {
66 		core_link_read_dpcd(
67 				link,
68 				DP_128B132B_TRAINING_AUX_RD_INTERVAL,
69 				(uint8_t *)&training_rd_interval,
70 				sizeof(training_rd_interval));
71 	} else if (link_dp_get_encoding_format(link_settings) == DP_8b_10b_ENCODING &&
72 			link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_12) {
73 		core_link_read_dpcd(
74 				link,
75 				DP_TRAINING_AUX_RD_INTERVAL,
76 				(uint8_t *)&training_rd_interval,
77 				sizeof(training_rd_interval));
78 	}
79 
80 	switch (training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL) {
81 	case 0: return 400;
82 	case 1: return 4000;
83 	case 2: return 8000;
84 	case 3: return 12000;
85 	case 4: return 16000;
86 	case 5: return 32000;
87 	case 6: return 64000;
88 	default: return 400;
89 	}
90 }
91 
decide_8b_10b_training_settings(struct dc_link * link,const struct dc_link_settings * link_setting,struct link_training_settings * lt_settings)92 void decide_8b_10b_training_settings(
93 	 struct dc_link *link,
94 	const struct dc_link_settings *link_setting,
95 	struct link_training_settings *lt_settings)
96 {
97 	memset(lt_settings, '\0', sizeof(struct link_training_settings));
98 
99 	/* Initialize link settings */
100 	lt_settings->link_settings.use_link_rate_set = link_setting->use_link_rate_set;
101 	lt_settings->link_settings.link_rate_set = link_setting->link_rate_set;
102 	lt_settings->link_settings.link_rate = link_setting->link_rate;
103 	lt_settings->link_settings.lane_count = link_setting->lane_count;
104 	/* TODO hard coded to SS for now
105 	 * lt_settings.link_settings.link_spread =
106 	 * dal_display_path_is_ss_supported(
107 	 * path_mode->display_path) ?
108 	 * LINK_SPREAD_05_DOWNSPREAD_30KHZ :
109 	 * LINK_SPREAD_DISABLED;
110 	 */
111 	lt_settings->link_settings.link_spread = link->dp_ss_off ?
112 			LINK_SPREAD_DISABLED : LINK_SPREAD_05_DOWNSPREAD_30KHZ;
113 	lt_settings->cr_pattern_time = get_cr_training_aux_rd_interval(link, link_setting);
114 	lt_settings->eq_pattern_time = get_eq_training_aux_rd_interval(link, link_setting);
115 	lt_settings->pattern_for_cr = decide_cr_training_pattern(link_setting);
116 	lt_settings->pattern_for_eq = decide_eq_training_pattern(link, link_setting);
117 	lt_settings->enhanced_framing = 1;
118 	lt_settings->should_set_fec_ready = true;
119 	lt_settings->disallow_per_lane_settings = true;
120 	lt_settings->always_match_dpcd_with_hw_lane_settings = true;
121 	lt_settings->lttpr_mode = dp_decide_8b_10b_lttpr_mode(link);
122 	dp_hw_to_dpcd_lane_settings(lt_settings, lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
123 }
124 
dp_decide_8b_10b_lttpr_mode(struct dc_link * link)125 enum lttpr_mode dp_decide_8b_10b_lttpr_mode(struct dc_link *link)
126 {
127 	bool is_lttpr_present = dp_is_lttpr_present(link);
128 	bool vbios_lttpr_force_non_transparent = link->dc->caps.vbios_lttpr_enable;
129 	bool vbios_lttpr_aware = link->dc->caps.vbios_lttpr_aware;
130 
131 	if (!is_lttpr_present)
132 		return LTTPR_MODE_NON_LTTPR;
133 
134 	if (vbios_lttpr_aware) {
135 		if (vbios_lttpr_force_non_transparent) {
136 			DC_LOG_DC("chose LTTPR_MODE_NON_TRANSPARENT due to VBIOS DCE_INFO_CAPS_LTTPR_SUPPORT_ENABLE set to 1.\n");
137 			return LTTPR_MODE_NON_TRANSPARENT;
138 		} else {
139 			DC_LOG_DC("chose LTTPR_MODE_NON_TRANSPARENT by default due to VBIOS not set DCE_INFO_CAPS_LTTPR_SUPPORT_ENABLE set to 1.\n");
140 			return LTTPR_MODE_TRANSPARENT;
141 		}
142 	}
143 
144 	if (link->dc->config.allow_lttpr_non_transparent_mode.bits.DP1_4A &&
145 			link->dc->caps.extended_aux_timeout_support) {
146 		DC_LOG_DC("chose LTTPR_MODE_NON_TRANSPARENT by default and dc->config.allow_lttpr_non_transparent_mode.bits.DP1_4A set to 1.\n");
147 		return LTTPR_MODE_NON_TRANSPARENT;
148 	}
149 
150 	DC_LOG_DC("chose LTTPR_MODE_NON_LTTPR.\n");
151 	return LTTPR_MODE_NON_LTTPR;
152 }
153 
perform_8b_10b_clock_recovery_sequence(struct dc_link * link,const struct link_resource * link_res,struct link_training_settings * lt_settings,uint32_t offset)154 enum link_training_result perform_8b_10b_clock_recovery_sequence(
155 	struct dc_link *link,
156 	const struct link_resource *link_res,
157 	struct link_training_settings *lt_settings,
158 	uint32_t offset)
159 {
160 	uint32_t retries_cr;
161 	uint32_t retry_count;
162 	uint32_t wait_time_microsec;
163 	enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
164 	union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX];
165 	union lane_align_status_updated dpcd_lane_status_updated;
166 	union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
167 
168 	retries_cr = 0;
169 	retry_count = 0;
170 
171 	memset(&dpcd_lane_status, '\0', sizeof(dpcd_lane_status));
172 	memset(&dpcd_lane_status_updated, '\0',
173 	sizeof(dpcd_lane_status_updated));
174 
175 	if (!link->ctx->dc->work_arounds.lt_early_cr_pattern)
176 		dp_set_hw_training_pattern(link, link_res, lt_settings->pattern_for_cr, offset);
177 
178 	/* najeeb - The synaptics MST hub can put the LT in
179 	* infinite loop by switching the VS
180 	*/
181 	/* between level 0 and level 1 continuously, here
182 	* we try for CR lock for LinkTrainingMaxCRRetry count*/
183 	while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) &&
184 		(retry_count < LINK_TRAINING_MAX_CR_RETRY)) {
185 
186 
187 		/* 1. call HWSS to set lane settings*/
188 		dp_set_hw_lane_settings(
189 				link,
190 				link_res,
191 				lt_settings,
192 				offset);
193 
194 		/* 2. update DPCD of the receiver*/
195 		if (!retry_count)
196 			/* EPR #361076 - write as a 5-byte burst,
197 			 * but only for the 1-st iteration.*/
198 			dpcd_set_lt_pattern_and_lane_settings(
199 					link,
200 					lt_settings,
201 					lt_settings->pattern_for_cr,
202 					offset);
203 		else
204 			dpcd_set_lane_settings(
205 					link,
206 					lt_settings,
207 					offset);
208 
209 		/* 3. wait receiver to lock-on*/
210 		wait_time_microsec = lt_settings->cr_pattern_time;
211 
212 		dp_wait_for_training_aux_rd_interval(
213 				link,
214 				wait_time_microsec);
215 
216 		/* 4. Read lane status and requested drive
217 		* settings as set by the sink
218 		*/
219 		dp_get_lane_status_and_lane_adjust(
220 				link,
221 				lt_settings,
222 				dpcd_lane_status,
223 				&dpcd_lane_status_updated,
224 				dpcd_lane_adjust,
225 				offset);
226 
227 		/* 5. check CR done*/
228 		if (dp_is_cr_done(lane_count, dpcd_lane_status)) {
229 			DC_LOG_HW_LINK_TRAINING("%s: Clock recovery OK\n", __func__);
230 			return LINK_TRAINING_SUCCESS;
231 		}
232 
233 		/* 6. max VS reached*/
234 		if ((link_dp_get_encoding_format(&lt_settings->link_settings) ==
235 				DP_8b_10b_ENCODING) &&
236 				dp_is_max_vs_reached(lt_settings))
237 			break;
238 
239 		/* 7. same lane settings*/
240 		/* Note: settings are the same for all lanes,
241 		 * so comparing first lane is sufficient*/
242 		if ((link_dp_get_encoding_format(&lt_settings->link_settings) == DP_8b_10b_ENCODING) &&
243 				lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET ==
244 						dpcd_lane_adjust[0].bits.VOLTAGE_SWING_LANE)
245 			retries_cr++;
246 		else if ((link_dp_get_encoding_format(&lt_settings->link_settings) == DP_128b_132b_ENCODING) &&
247 				lt_settings->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE ==
248 						dpcd_lane_adjust[0].tx_ffe.PRESET_VALUE)
249 			retries_cr++;
250 		else
251 			retries_cr = 0;
252 
253 		/* 8. update VS/PE/PC2 in lt_settings*/
254 		dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
255 				lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
256 		retry_count++;
257 	}
258 
259 	if (retry_count >= LINK_TRAINING_MAX_CR_RETRY) {
260 		ASSERT(0);
261 		DC_LOG_ERROR("%s: Link Training Error, could not get CR after %d tries. Possibly voltage swing issue",
262 			__func__,
263 			LINK_TRAINING_MAX_CR_RETRY);
264 
265 	}
266 
267 	return dp_get_cr_failure(lane_count, dpcd_lane_status);
268 }
269 
perform_8b_10b_channel_equalization_sequence(struct dc_link * link,const struct link_resource * link_res,struct link_training_settings * lt_settings,uint32_t offset)270 enum link_training_result perform_8b_10b_channel_equalization_sequence(
271 	struct dc_link *link,
272 	const struct link_resource *link_res,
273 	struct link_training_settings *lt_settings,
274 	uint32_t offset)
275 {
276 	enum dc_dp_training_pattern tr_pattern;
277 	uint32_t retries_ch_eq;
278 	uint32_t wait_time_microsec;
279 	enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
280 	union lane_align_status_updated dpcd_lane_status_updated = {0};
281 	union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
282 	union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
283 
284 	/* Note: also check that TPS4 is a supported feature*/
285 	tr_pattern = lt_settings->pattern_for_eq;
286 
287 	if (is_repeater(lt_settings, offset) && link_dp_get_encoding_format(&lt_settings->link_settings) == DP_8b_10b_ENCODING)
288 		tr_pattern = DP_TRAINING_PATTERN_SEQUENCE_4;
289 
290 	dp_set_hw_training_pattern(link, link_res, tr_pattern, offset);
291 
292 	for (retries_ch_eq = 0; retries_ch_eq <= LINK_TRAINING_MAX_RETRY_COUNT;
293 		retries_ch_eq++) {
294 
295 		dp_set_hw_lane_settings(link, link_res, lt_settings, offset);
296 
297 		/* 2. update DPCD*/
298 		if (!retries_ch_eq)
299 			/* EPR #361076 - write as a 5-byte burst,
300 			 * but only for the 1-st iteration
301 			 */
302 
303 			dpcd_set_lt_pattern_and_lane_settings(
304 				link,
305 				lt_settings,
306 				tr_pattern, offset);
307 		else
308 			dpcd_set_lane_settings(link, lt_settings, offset);
309 
310 		/* 3. wait for receiver to lock-on*/
311 		wait_time_microsec = lt_settings->eq_pattern_time;
312 
313 		if (is_repeater(lt_settings, offset))
314 			wait_time_microsec =
315 					dp_translate_training_aux_read_interval(
316 						link->dpcd_caps.lttpr_caps.aux_rd_interval[offset - 1]);
317 
318 		dp_wait_for_training_aux_rd_interval(
319 				link,
320 				wait_time_microsec);
321 
322 		/* 4. Read lane status and requested
323 		 * drive settings as set by the sink*/
324 
325 		dp_get_lane_status_and_lane_adjust(
326 			link,
327 			lt_settings,
328 			dpcd_lane_status,
329 			&dpcd_lane_status_updated,
330 			dpcd_lane_adjust,
331 			offset);
332 
333 		/* 5. check CR done*/
334 		if (!dp_is_cr_done(lane_count, dpcd_lane_status))
335 			return dpcd_lane_status[0].bits.CR_DONE_0 ?
336 					LINK_TRAINING_EQ_FAIL_CR_PARTIAL :
337 					LINK_TRAINING_EQ_FAIL_CR;
338 
339 		/* 6. check CHEQ done*/
340 		if (dp_is_ch_eq_done(lane_count, dpcd_lane_status) &&
341 				dp_is_symbol_locked(lane_count, dpcd_lane_status) &&
342 				dp_is_interlane_aligned(dpcd_lane_status_updated))
343 			return LINK_TRAINING_SUCCESS;
344 
345 		/* 7. update VS/PE/PC2 in lt_settings*/
346 		dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
347 				lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
348 	}
349 
350 	return LINK_TRAINING_EQ_FAIL_EQ;
351 
352 }
353 
dp_perform_8b_10b_link_training(struct dc_link * link,const struct link_resource * link_res,struct link_training_settings * lt_settings)354 enum link_training_result dp_perform_8b_10b_link_training(
355 		struct dc_link *link,
356 		const struct link_resource *link_res,
357 		struct link_training_settings *lt_settings)
358 {
359 	enum link_training_result status = LINK_TRAINING_SUCCESS;
360 
361 	uint8_t repeater_cnt;
362 	uint8_t repeater_id;
363 	uint8_t lane = 0;
364 
365 	if (link->ctx->dc->work_arounds.lt_early_cr_pattern)
366 		start_clock_recovery_pattern_early(link, link_res, lt_settings, DPRX);
367 
368 	/* 1. set link rate, lane count and spread. */
369 	dpcd_set_link_settings(link, lt_settings);
370 
371 	if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) {
372 
373 		/* 2. perform link training (set link training done
374 		 *  to false is done as well)
375 		 */
376 		repeater_cnt = dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
377 
378 		for (repeater_id = repeater_cnt; (repeater_id > 0 && status == LINK_TRAINING_SUCCESS);
379 				repeater_id--) {
380 			status = perform_8b_10b_clock_recovery_sequence(link, link_res, lt_settings, repeater_id);
381 
382 			if (status != LINK_TRAINING_SUCCESS) {
383 				repeater_training_done(link, repeater_id);
384 				break;
385 			}
386 
387 			status = perform_8b_10b_channel_equalization_sequence(link,
388 					link_res,
389 					lt_settings,
390 					repeater_id);
391 			if (status == LINK_TRAINING_SUCCESS)
392 				DC_LOG_HW_LINK_TRAINING("%s: Channel EQ done.\n", __func__);
393 
394 			repeater_training_done(link, repeater_id);
395 
396 			if (status != LINK_TRAINING_SUCCESS)
397 				break;
398 
399 			for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
400 				lt_settings->dpcd_lane_settings[lane].raw = 0;
401 				lt_settings->hw_lane_settings[lane].VOLTAGE_SWING = 0;
402 				lt_settings->hw_lane_settings[lane].PRE_EMPHASIS = 0;
403 			}
404 		}
405 	}
406 
407 	if (status == LINK_TRAINING_SUCCESS) {
408 		status = perform_8b_10b_clock_recovery_sequence(link, link_res, lt_settings, DPRX);
409 		if (status == LINK_TRAINING_SUCCESS) {
410 			status = perform_8b_10b_channel_equalization_sequence(link,
411 					link_res,
412 					lt_settings,
413 					DPRX);
414 			if (status == LINK_TRAINING_SUCCESS)
415 				DC_LOG_HW_LINK_TRAINING("%s: Channel EQ done.\n", __func__);
416 		}
417 	}
418 
419 	return status;
420 }
421