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 | |
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 | data: (uint8_t *)(link_training_setting->dpcd_lane_settings), |
46 | size: 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 | |
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 | data: &dpcd_interval.raw, size: 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 | |
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, pattern: lt_settings->pattern_for_cr, offset: DPRX); |
87 | |
88 | /* Set TRAINING_PATTERN_SET to 01h */ |
89 | dpcd_set_training_pattern(link, training_pattern: 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, interval_in_us: &aux_rd_interval); |
93 | dp_get_lane_status_and_lane_adjust(link, link_training_setting: lt_settings, ln_status: dpcd_lane_status, |
94 | ln_align: &dpcd_lane_status_updated, ln_adjust: dpcd_lane_adjust, offset: DPRX); |
95 | dp_decide_lane_settings(lt_settings, ln_adjust: dpcd_lane_adjust, |
96 | hw_lane_settings: lt_settings->hw_lane_settings, dpcd_lane_settings: lt_settings->dpcd_lane_settings); |
97 | dp_set_hw_lane_settings(link, link_res, link_settings: lt_settings, offset: DPRX); |
98 | dp_set_hw_training_pattern(link, link_res, pattern: lt_settings->pattern_for_eq, offset: 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 | pattern: lt_settings->pattern_for_eq, offset: DPRX); |
106 | |
107 | /* poll for channel EQ done */ |
108 | while (result == LINK_TRAINING_SUCCESS) { |
109 | dp_wait_for_training_aux_rd_interval(link, wait_in_micro_secs: aux_rd_interval); |
110 | wait_time += aux_rd_interval; |
111 | status = dp_get_lane_status_and_lane_adjust(link, link_training_setting: lt_settings, ln_status: dpcd_lane_status, |
112 | ln_align: &dpcd_lane_status_updated, ln_adjust: dpcd_lane_adjust, offset: DPRX); |
113 | dp_decide_lane_settings(lt_settings, ln_adjust: dpcd_lane_adjust, |
114 | hw_lane_settings: lt_settings->hw_lane_settings, dpcd_lane_settings: lt_settings->dpcd_lane_settings); |
115 | dpcd_128b_132b_get_aux_rd_interval(link, interval_in_us: &aux_rd_interval); |
116 | if (status != DC_OK) { |
117 | result = LINK_TRAINING_ABORT; |
118 | } else if (dp_is_ch_eq_done(ln_count: 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, link_settings: lt_settings, offset: DPRX); |
128 | dpcd_128b_132b_set_lane_settings(link, link_training_setting: 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 | wait_in_micro_secs: lt_settings->eq_pattern_time); |
147 | wait_time += lt_settings->eq_pattern_time; |
148 | status = dp_get_lane_status_and_lane_adjust(link, link_training_setting: lt_settings, ln_status: dpcd_lane_status, |
149 | ln_align: &dpcd_lane_status_updated, ln_adjust: dpcd_lane_adjust, offset: DPRX); |
150 | } |
151 | } |
152 | |
153 | return result; |
154 | } |
155 | |
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, training_pattern: 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 | wait_in_micro_secs: lt_settings->cds_pattern_time); |
176 | wait_time += lt_settings->cds_pattern_time; |
177 | status = dp_get_lane_status_and_lane_adjust(link, link_training_setting: lt_settings, ln_status: dpcd_lane_status, |
178 | ln_align: &dpcd_lane_status_updated, ln_adjust: dpcd_lane_adjust, offset: DPRX); |
179 | if (status != DC_OK) { |
180 | result = LINK_TRAINING_ABORT; |
181 | } else if (dp_is_symbol_locked(ln_count: 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 | |
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 | link_setting: <_settings->link_settings, |
208 | lt_settings: &legacy_settings); |
209 | return dp_perform_8b_10b_link_training(link, link_res, lt_settings: &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 | |
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 | lttpr_repeater_count: 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 | hw_lane_settings: lt_settings->hw_lane_settings, dpcd_lane_settings: lt_settings->dpcd_lane_settings); |
253 | } |
254 | |
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 | |