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 128b/132b link training software policies and
28  * sequences.
29  */
30 #include "link_dp_training_128b_132b.h"
31 #include "link_dp_training_8b_10b.h"
32 #include "link_dpcd.h"
33 #include "link_dp_phy.h"
34 #include "link_dp_capability.h"
35 
36 #define DC_LOGGER \
37 	link->ctx->logger
38 
dpcd_128b_132b_set_lane_settings(struct dc_link * link,const struct link_training_settings * link_training_setting)39 static enum dc_status dpcd_128b_132b_set_lane_settings(
40 		struct dc_link *link,
41 		const struct link_training_settings *link_training_setting)
42 {
43 	enum dc_status status = core_link_write_dpcd(link,
44 			DP_TRAINING_LANE0_SET,
45 			(uint8_t *)(link_training_setting->dpcd_lane_settings),
46 			sizeof(link_training_setting->dpcd_lane_settings));
47 
48 	DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X TX_FFE_PRESET_VALUE = %x\n",
49 			__func__,
50 			DP_TRAINING_LANE0_SET,
51 			link_training_setting->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE);
52 	return status;
53 }
54 
dpcd_128b_132b_get_aux_rd_interval(struct dc_link * link,uint32_t * interval_in_us)55 static void dpcd_128b_132b_get_aux_rd_interval(struct dc_link *link,
56 		uint32_t *interval_in_us)
57 {
58 	union dp_128b_132b_training_aux_rd_interval dpcd_interval;
59 	uint32_t interval_unit = 0;
60 
61 	dpcd_interval.raw = 0;
62 	core_link_read_dpcd(link, DP_128B132B_TRAINING_AUX_RD_INTERVAL,
63 			&dpcd_interval.raw, sizeof(dpcd_interval.raw));
64 	interval_unit = dpcd_interval.bits.UNIT ? 1 : 2; /* 0b = 2 ms, 1b = 1 ms */
65 	/* (128b/132b_TRAINING_AUX_RD_INTERVAL value + 1) *
66 	 * INTERVAL_UNIT. The maximum is 256 ms
67 	 */
68 	*interval_in_us = (dpcd_interval.bits.VALUE + 1) * interval_unit * 1000;
69 }
70 
dp_perform_128b_132b_channel_eq_done_sequence(struct dc_link * link,const struct link_resource * link_res,struct link_training_settings * lt_settings)71 static enum link_training_result dp_perform_128b_132b_channel_eq_done_sequence(
72 		struct dc_link *link,
73 		const struct link_resource *link_res,
74 		struct link_training_settings *lt_settings)
75 {
76 	uint8_t loop_count;
77 	uint32_t aux_rd_interval = 0;
78 	uint32_t wait_time = 0;
79 	union lane_align_status_updated dpcd_lane_status_updated = {0};
80 	union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
81 	union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
82 	enum dc_status status = DC_OK;
83 	enum link_training_result result = LINK_TRAINING_SUCCESS;
84 
85 	/* Transmit 128b/132b_TPS1 over Main-Link */
86 	dp_set_hw_training_pattern(link, link_res, lt_settings->pattern_for_cr, DPRX);
87 
88 	/* Set TRAINING_PATTERN_SET to 01h */
89 	dpcd_set_training_pattern(link, lt_settings->pattern_for_cr);
90 
91 	/* Adjust TX_FFE_PRESET_VALUE and Transmit 128b/132b_TPS2 over Main-Link */
92 	dpcd_128b_132b_get_aux_rd_interval(link, &aux_rd_interval);
93 	dp_get_lane_status_and_lane_adjust(link, lt_settings, dpcd_lane_status,
94 			&dpcd_lane_status_updated, dpcd_lane_adjust, DPRX);
95 	dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
96 			lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
97 	dp_set_hw_lane_settings(link, link_res, lt_settings, DPRX);
98 	dp_set_hw_training_pattern(link, link_res, lt_settings->pattern_for_eq, DPRX);
99 
100 	/* Set loop counter to start from 1 */
101 	loop_count = 1;
102 
103 	/* Set TRAINING_PATTERN_SET to 02h and TX_FFE_PRESET_VALUE in one AUX transaction */
104 	dpcd_set_lt_pattern_and_lane_settings(link, lt_settings,
105 			lt_settings->pattern_for_eq, DPRX);
106 
107 	/* poll for channel EQ done */
108 	while (result == LINK_TRAINING_SUCCESS) {
109 		dp_wait_for_training_aux_rd_interval(link, aux_rd_interval);
110 		wait_time += aux_rd_interval;
111 		status = dp_get_lane_status_and_lane_adjust(link, lt_settings, dpcd_lane_status,
112 				&dpcd_lane_status_updated, dpcd_lane_adjust, DPRX);
113 		dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
114 				lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
115 		dpcd_128b_132b_get_aux_rd_interval(link, &aux_rd_interval);
116 		if (status != DC_OK) {
117 			result = LINK_TRAINING_ABORT;
118 		} else if (dp_is_ch_eq_done(lt_settings->link_settings.lane_count,
119 				dpcd_lane_status)) {
120 			/* pass */
121 			break;
122 		} else if (loop_count >= lt_settings->eq_loop_count_limit) {
123 			result = DP_128b_132b_MAX_LOOP_COUNT_REACHED;
124 		} else if (dpcd_lane_status_updated.bits.LT_FAILED_128b_132b) {
125 			result = DP_128b_132b_LT_FAILED;
126 		} else {
127 			dp_set_hw_lane_settings(link, link_res, lt_settings, DPRX);
128 			dpcd_128b_132b_set_lane_settings(link, lt_settings);
129 		}
130 		loop_count++;
131 	}
132 
133 	/* poll for EQ interlane align done */
134 	while (result == LINK_TRAINING_SUCCESS) {
135 		if (status != DC_OK) {
136 			result = LINK_TRAINING_ABORT;
137 		} else if (dpcd_lane_status_updated.bits.EQ_INTERLANE_ALIGN_DONE_128b_132b) {
138 			/* pass */
139 			break;
140 		} else if (wait_time >= lt_settings->eq_wait_time_limit) {
141 			result = DP_128b_132b_CHANNEL_EQ_DONE_TIMEOUT;
142 		} else if (dpcd_lane_status_updated.bits.LT_FAILED_128b_132b) {
143 			result = DP_128b_132b_LT_FAILED;
144 		} else {
145 			dp_wait_for_training_aux_rd_interval(link,
146 					lt_settings->eq_pattern_time);
147 			wait_time += lt_settings->eq_pattern_time;
148 			status = dp_get_lane_status_and_lane_adjust(link, lt_settings, dpcd_lane_status,
149 					&dpcd_lane_status_updated, dpcd_lane_adjust, DPRX);
150 		}
151 	}
152 
153 	return result;
154 }
155 
dp_perform_128b_132b_cds_done_sequence(struct dc_link * link,const struct link_resource * link_res,struct link_training_settings * lt_settings)156 static enum link_training_result dp_perform_128b_132b_cds_done_sequence(
157 		struct dc_link *link,
158 		const struct link_resource *link_res,
159 		struct link_training_settings *lt_settings)
160 {
161 	/* Assumption: assume hardware has transmitted eq pattern */
162 	enum dc_status status = DC_OK;
163 	enum link_training_result result = LINK_TRAINING_SUCCESS;
164 	union lane_align_status_updated dpcd_lane_status_updated = {0};
165 	union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
166 	union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
167 	uint32_t wait_time = 0;
168 
169 	/* initiate CDS done sequence */
170 	dpcd_set_training_pattern(link, lt_settings->pattern_for_cds);
171 
172 	/* poll for CDS interlane align done and symbol lock */
173 	while (result == LINK_TRAINING_SUCCESS) {
174 		dp_wait_for_training_aux_rd_interval(link,
175 				lt_settings->cds_pattern_time);
176 		wait_time += lt_settings->cds_pattern_time;
177 		status = dp_get_lane_status_and_lane_adjust(link, lt_settings, dpcd_lane_status,
178 						&dpcd_lane_status_updated, dpcd_lane_adjust, DPRX);
179 		if (status != DC_OK) {
180 			result = LINK_TRAINING_ABORT;
181 		} else if (dp_is_symbol_locked(lt_settings->link_settings.lane_count, dpcd_lane_status) &&
182 				dpcd_lane_status_updated.bits.CDS_INTERLANE_ALIGN_DONE_128b_132b) {
183 			/* pass */
184 			break;
185 		} else if (dpcd_lane_status_updated.bits.LT_FAILED_128b_132b) {
186 			result = DP_128b_132b_LT_FAILED;
187 		} else if (wait_time >= lt_settings->cds_wait_time_limit) {
188 			result = DP_128b_132b_CDS_DONE_TIMEOUT;
189 		}
190 	}
191 
192 	return result;
193 }
194 
dp_perform_128b_132b_link_training(struct dc_link * link,const struct link_resource * link_res,struct link_training_settings * lt_settings)195 enum link_training_result dp_perform_128b_132b_link_training(
196 		struct dc_link *link,
197 		const struct link_resource *link_res,
198 		struct link_training_settings *lt_settings)
199 {
200 	enum link_training_result result = LINK_TRAINING_SUCCESS;
201 
202 	/* TODO - DP2.0 Link: remove legacy_dp2_lt logic */
203 	if (link->dc->debug.legacy_dp2_lt) {
204 		struct link_training_settings legacy_settings;
205 
206 		decide_8b_10b_training_settings(link,
207 				&lt_settings->link_settings,
208 				&legacy_settings);
209 		return dp_perform_8b_10b_link_training(link, link_res, &legacy_settings);
210 	}
211 
212 	dpcd_set_link_settings(link, lt_settings);
213 
214 	if (result == LINK_TRAINING_SUCCESS) {
215 		result = dp_perform_128b_132b_channel_eq_done_sequence(link, link_res, lt_settings);
216 		if (result == LINK_TRAINING_SUCCESS)
217 			DC_LOG_HW_LINK_TRAINING("%s: Channel EQ done.\n", __func__);
218 	}
219 
220 	if (result == LINK_TRAINING_SUCCESS) {
221 		result = dp_perform_128b_132b_cds_done_sequence(link, link_res, lt_settings);
222 		if (result == LINK_TRAINING_SUCCESS)
223 			DC_LOG_HW_LINK_TRAINING("%s: CDS done.\n", __func__);
224 	}
225 
226 	return result;
227 }
228 
decide_128b_132b_training_settings(struct dc_link * link,const struct dc_link_settings * link_settings,struct link_training_settings * lt_settings)229 void decide_128b_132b_training_settings(struct dc_link *link,
230 		const struct dc_link_settings *link_settings,
231 		struct link_training_settings *lt_settings)
232 {
233 	memset(lt_settings, 0, sizeof(*lt_settings));
234 
235 	lt_settings->link_settings = *link_settings;
236 	/* TODO: should decide link spread when populating link_settings */
237 	lt_settings->link_settings.link_spread = link->dp_ss_off ? LINK_SPREAD_DISABLED :
238 			LINK_SPREAD_05_DOWNSPREAD_30KHZ;
239 
240 	lt_settings->pattern_for_cr = decide_cr_training_pattern(link_settings);
241 	lt_settings->pattern_for_eq = decide_eq_training_pattern(link, link_settings);
242 	lt_settings->eq_pattern_time = 2500;
243 	lt_settings->eq_wait_time_limit = 400000;
244 	lt_settings->eq_loop_count_limit = 20;
245 	lt_settings->pattern_for_cds = DP_128b_132b_TPS2_CDS;
246 	lt_settings->cds_pattern_time = 2500;
247 	lt_settings->cds_wait_time_limit = (dp_parse_lttpr_repeater_count(
248 			link->dpcd_caps.lttpr_caps.phy_repeater_cnt) + 1) * 20000;
249 	lt_settings->disallow_per_lane_settings = true;
250 	lt_settings->lttpr_mode = dp_decide_128b_132b_lttpr_mode(link);
251 	dp_hw_to_dpcd_lane_settings(lt_settings,
252 			lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
253 }
254 
dp_decide_128b_132b_lttpr_mode(struct dc_link * link)255 enum lttpr_mode dp_decide_128b_132b_lttpr_mode(struct dc_link *link)
256 {
257 	enum lttpr_mode mode = LTTPR_MODE_NON_LTTPR;
258 
259 	if (dp_is_lttpr_present(link))
260 		mode = LTTPR_MODE_NON_TRANSPARENT;
261 
262 	DC_LOG_DC("128b_132b chose LTTPR_MODE %d.\n", mode);
263 	return mode;
264 }
265 
266