File: | dev/pci/drm/amd/display/dc/core/dc_link_dp.c |
Warning: | line 662, column 7 Branch condition evaluates to a garbage value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* | ||||
2 | * Copyright 2015 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 | #include "dm_services.h" | ||||
25 | #include "dc.h" | ||||
26 | #include "dc_link_dp.h" | ||||
27 | #include "dm_helpers.h" | ||||
28 | #include "opp.h" | ||||
29 | #include "dsc.h" | ||||
30 | #include "clk_mgr.h" | ||||
31 | #include "resource.h" | ||||
32 | |||||
33 | #include "inc/core_types.h" | ||||
34 | #include "link_hwss.h" | ||||
35 | #include "dc_link_ddc.h" | ||||
36 | #include "core_status.h" | ||||
37 | #include "dpcd_defs.h" | ||||
38 | #include "dc_dmub_srv.h" | ||||
39 | #include "dce/dmub_hw_lock_mgr.h" | ||||
40 | #include "inc/dc_link_dpia.h" | ||||
41 | #include "inc/link_enc_cfg.h" | ||||
42 | #include "link/link_dp_trace.h" | ||||
43 | |||||
44 | /*Travis*/ | ||||
45 | static const uint8_t DP_VGA_LVDS_CONVERTER_ID_2[] = "sivarT"; | ||||
46 | /*Nutmeg*/ | ||||
47 | static const uint8_t DP_VGA_LVDS_CONVERTER_ID_3[] = "dnomlA"; | ||||
48 | |||||
49 | #define DC_LOGGERlink->ctx->logger \ | ||||
50 | link->ctx->logger | ||||
51 | #define DC_TRACE_LEVEL_MESSAGE(...) /* do nothing */ | ||||
52 | |||||
53 | #include "link_dpcd.h" | ||||
54 | |||||
55 | #ifndef MAX | ||||
56 | #define MAX(X, Y)(((X)>(Y))?(X):(Y)) ((X) > (Y) ? (X) : (Y)) | ||||
57 | #endif | ||||
58 | #ifndef MIN | ||||
59 | #define MIN(X, Y)(((X)<(Y))?(X):(Y)) ((X) < (Y) ? (X) : (Y)) | ||||
60 | #endif | ||||
61 | |||||
62 | /* maximum pre emphasis level allowed for each voltage swing level*/ | ||||
63 | static const enum dc_pre_emphasis | ||||
64 | voltage_swing_to_pre_emphasis[] = { PRE_EMPHASIS_LEVEL3, | ||||
65 | PRE_EMPHASIS_LEVEL2, | ||||
66 | PRE_EMPHASIS_LEVEL1, | ||||
67 | PRE_EMPHASIS_DISABLED }; | ||||
68 | |||||
69 | enum { | ||||
70 | POST_LT_ADJ_REQ_LIMIT = 6, | ||||
71 | POST_LT_ADJ_REQ_TIMEOUT = 200 | ||||
72 | }; | ||||
73 | |||||
74 | struct dp_lt_fallback_entry { | ||||
75 | enum dc_lane_count lane_count; | ||||
76 | enum dc_link_rate link_rate; | ||||
77 | }; | ||||
78 | |||||
79 | static const struct dp_lt_fallback_entry dp_lt_fallbacks[] = { | ||||
80 | /* This link training fallback array is ordered by | ||||
81 | * link bandwidth from highest to lowest. | ||||
82 | * DP specs makes it a normative policy to always | ||||
83 | * choose the next highest link bandwidth during | ||||
84 | * link training fallback. | ||||
85 | */ | ||||
86 | {LANE_COUNT_FOUR, LINK_RATE_UHBR20}, | ||||
87 | {LANE_COUNT_FOUR, LINK_RATE_UHBR13_5}, | ||||
88 | {LANE_COUNT_TWO, LINK_RATE_UHBR20}, | ||||
89 | {LANE_COUNT_FOUR, LINK_RATE_UHBR10}, | ||||
90 | {LANE_COUNT_TWO, LINK_RATE_UHBR13_5}, | ||||
91 | {LANE_COUNT_FOUR, LINK_RATE_HIGH3}, | ||||
92 | {LANE_COUNT_ONE, LINK_RATE_UHBR20}, | ||||
93 | {LANE_COUNT_TWO, LINK_RATE_UHBR10}, | ||||
94 | {LANE_COUNT_FOUR, LINK_RATE_HIGH2}, | ||||
95 | {LANE_COUNT_ONE, LINK_RATE_UHBR13_5}, | ||||
96 | {LANE_COUNT_TWO, LINK_RATE_HIGH3}, | ||||
97 | {LANE_COUNT_ONE, LINK_RATE_UHBR10}, | ||||
98 | {LANE_COUNT_TWO, LINK_RATE_HIGH2}, | ||||
99 | {LANE_COUNT_FOUR, LINK_RATE_HIGH}, | ||||
100 | {LANE_COUNT_ONE, LINK_RATE_HIGH3}, | ||||
101 | {LANE_COUNT_FOUR, LINK_RATE_LOW}, | ||||
102 | {LANE_COUNT_ONE, LINK_RATE_HIGH2}, | ||||
103 | {LANE_COUNT_TWO, LINK_RATE_HIGH}, | ||||
104 | {LANE_COUNT_TWO, LINK_RATE_LOW}, | ||||
105 | {LANE_COUNT_ONE, LINK_RATE_HIGH}, | ||||
106 | {LANE_COUNT_ONE, LINK_RATE_LOW}, | ||||
107 | }; | ||||
108 | |||||
109 | static const struct dc_link_settings fail_safe_link_settings = { | ||||
110 | .lane_count = LANE_COUNT_ONE, | ||||
111 | .link_rate = LINK_RATE_LOW, | ||||
112 | .link_spread = LINK_SPREAD_DISABLED, | ||||
113 | }; | ||||
114 | |||||
115 | static bool_Bool decide_fallback_link_setting( | ||||
116 | struct dc_link *link, | ||||
117 | struct dc_link_settings *max, | ||||
118 | struct dc_link_settings *cur, | ||||
119 | enum link_training_result training_result); | ||||
120 | static void maximize_lane_settings(const struct link_training_settings *lt_settings, | ||||
121 | struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX]); | ||||
122 | static void override_lane_settings(const struct link_training_settings *lt_settings, | ||||
123 | struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX]); | ||||
124 | |||||
125 | static uint32_t get_cr_training_aux_rd_interval(struct dc_link *link, | ||||
126 | const struct dc_link_settings *link_settings) | ||||
127 | { | ||||
128 | union training_aux_rd_interval training_rd_interval; | ||||
129 | uint32_t wait_in_micro_secs = 100; | ||||
130 | |||||
131 | memset(&training_rd_interval, 0, sizeof(training_rd_interval))__builtin_memset((&training_rd_interval), (0), (sizeof(training_rd_interval ))); | ||||
132 | if (dp_get_link_encoding_format(link_settings) == DP_8b_10b_ENCODING && | ||||
133 | link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_12) { | ||||
134 | core_link_read_dpcd( | ||||
135 | link, | ||||
136 | DP_TRAINING_AUX_RD_INTERVAL0x00e, | ||||
137 | (uint8_t *)&training_rd_interval, | ||||
138 | sizeof(training_rd_interval)); | ||||
139 | if (training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL) | ||||
140 | wait_in_micro_secs = training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL * 4000; | ||||
141 | } | ||||
142 | |||||
143 | return wait_in_micro_secs; | ||||
144 | } | ||||
145 | |||||
146 | static uint32_t get_eq_training_aux_rd_interval( | ||||
147 | struct dc_link *link, | ||||
148 | const struct dc_link_settings *link_settings) | ||||
149 | { | ||||
150 | union training_aux_rd_interval training_rd_interval; | ||||
151 | |||||
152 | memset(&training_rd_interval, 0, sizeof(training_rd_interval))__builtin_memset((&training_rd_interval), (0), (sizeof(training_rd_interval ))); | ||||
153 | if (dp_get_link_encoding_format(link_settings) == DP_128b_132b_ENCODING) { | ||||
154 | core_link_read_dpcd( | ||||
155 | link, | ||||
156 | DP_128b_132b_TRAINING_AUX_RD_INTERVAL0x2216, | ||||
157 | (uint8_t *)&training_rd_interval, | ||||
158 | sizeof(training_rd_interval)); | ||||
159 | } else if (dp_get_link_encoding_format(link_settings) == DP_8b_10b_ENCODING && | ||||
160 | link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_12) { | ||||
161 | core_link_read_dpcd( | ||||
162 | link, | ||||
163 | DP_TRAINING_AUX_RD_INTERVAL0x00e, | ||||
164 | (uint8_t *)&training_rd_interval, | ||||
165 | sizeof(training_rd_interval)); | ||||
166 | } | ||||
167 | |||||
168 | switch (training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL) { | ||||
169 | case 0: return 400; | ||||
170 | case 1: return 4000; | ||||
171 | case 2: return 8000; | ||||
172 | case 3: return 12000; | ||||
173 | case 4: return 16000; | ||||
174 | case 5: return 32000; | ||||
175 | case 6: return 64000; | ||||
176 | default: return 400; | ||||
177 | } | ||||
178 | } | ||||
179 | |||||
180 | void dp_wait_for_training_aux_rd_interval( | ||||
181 | struct dc_link *link, | ||||
182 | uint32_t wait_in_micro_secs) | ||||
183 | { | ||||
184 | if (wait_in_micro_secs > 1000) | ||||
185 | drm_msleep(wait_in_micro_secs/1000)mdelay(wait_in_micro_secs/1000); | ||||
186 | else | ||||
187 | udelay(wait_in_micro_secs); | ||||
188 | |||||
189 | DC_LOG_HW_LINK_TRAINING("%s:\n wait = %d\n",do { } while(0) | ||||
190 | __func__,do { } while(0) | ||||
191 | wait_in_micro_secs)do { } while(0); | ||||
192 | } | ||||
193 | |||||
194 | enum dpcd_training_patterns | ||||
195 | dc_dp_training_pattern_to_dpcd_training_pattern( | ||||
196 | struct dc_link *link, | ||||
197 | enum dc_dp_training_pattern pattern) | ||||
198 | { | ||||
199 | enum dpcd_training_patterns dpcd_tr_pattern = | ||||
200 | DPCD_TRAINING_PATTERN_VIDEOIDLE; | ||||
201 | |||||
202 | switch (pattern) { | ||||
203 | case DP_TRAINING_PATTERN_SEQUENCE_1: | ||||
204 | dpcd_tr_pattern = DPCD_TRAINING_PATTERN_1; | ||||
205 | break; | ||||
206 | case DP_TRAINING_PATTERN_SEQUENCE_2: | ||||
207 | dpcd_tr_pattern = DPCD_TRAINING_PATTERN_2; | ||||
208 | break; | ||||
209 | case DP_TRAINING_PATTERN_SEQUENCE_3: | ||||
210 | dpcd_tr_pattern = DPCD_TRAINING_PATTERN_3; | ||||
211 | break; | ||||
212 | case DP_TRAINING_PATTERN_SEQUENCE_4: | ||||
213 | dpcd_tr_pattern = DPCD_TRAINING_PATTERN_4; | ||||
214 | break; | ||||
215 | case DP_128b_132b_TPS1: | ||||
216 | dpcd_tr_pattern = DPCD_128b_132b_TPS1; | ||||
217 | break; | ||||
218 | case DP_128b_132b_TPS2: | ||||
219 | dpcd_tr_pattern = DPCD_128b_132b_TPS2; | ||||
220 | break; | ||||
221 | case DP_128b_132b_TPS2_CDS: | ||||
222 | dpcd_tr_pattern = DPCD_128b_132b_TPS2_CDS; | ||||
223 | break; | ||||
224 | case DP_TRAINING_PATTERN_VIDEOIDLE: | ||||
225 | dpcd_tr_pattern = DPCD_TRAINING_PATTERN_VIDEOIDLE; | ||||
226 | break; | ||||
227 | default: | ||||
228 | ASSERT(0)do { if (({ static int __warned; int __ret = !!(!(0)); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n" , "!(0)", "/usr/src/sys/dev/pci/drm/amd/display/dc/core/dc_link_dp.c" , 228); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | ||||
229 | DC_LOG_HW_LINK_TRAINING("%s: Invalid HW Training pattern: %d\n",do { } while(0) | ||||
230 | __func__, pattern)do { } while(0); | ||||
231 | break; | ||||
232 | } | ||||
233 | |||||
234 | return dpcd_tr_pattern; | ||||
235 | } | ||||
236 | |||||
237 | static void dpcd_set_training_pattern( | ||||
238 | struct dc_link *link, | ||||
239 | enum dc_dp_training_pattern training_pattern) | ||||
240 | { | ||||
241 | union dpcd_training_pattern dpcd_pattern = {0}; | ||||
242 | |||||
243 | dpcd_pattern.v1_4.TRAINING_PATTERN_SET = | ||||
244 | dc_dp_training_pattern_to_dpcd_training_pattern( | ||||
245 | link, training_pattern); | ||||
246 | |||||
247 | core_link_write_dpcd( | ||||
248 | link, | ||||
249 | DP_TRAINING_PATTERN_SET0x102, | ||||
250 | &dpcd_pattern.raw, | ||||
251 | 1); | ||||
252 | |||||
253 | DC_LOG_HW_LINK_TRAINING("%s\n %x pattern = %x\n",do { } while(0) | ||||
254 | __func__,do { } while(0) | ||||
255 | DP_TRAINING_PATTERN_SET,do { } while(0) | ||||
256 | dpcd_pattern.v1_4.TRAINING_PATTERN_SET)do { } while(0); | ||||
257 | } | ||||
258 | |||||
259 | static enum dc_dp_training_pattern decide_cr_training_pattern( | ||||
260 | const struct dc_link_settings *link_settings) | ||||
261 | { | ||||
262 | switch (dp_get_link_encoding_format(link_settings)) { | ||||
263 | case DP_8b_10b_ENCODING: | ||||
264 | default: | ||||
265 | return DP_TRAINING_PATTERN_SEQUENCE_1; | ||||
266 | case DP_128b_132b_ENCODING: | ||||
267 | return DP_128b_132b_TPS1; | ||||
268 | } | ||||
269 | } | ||||
270 | |||||
271 | static enum dc_dp_training_pattern decide_eq_training_pattern(struct dc_link *link, | ||||
272 | const struct dc_link_settings *link_settings) | ||||
273 | { | ||||
274 | struct link_encoder *link_enc; | ||||
275 | struct encoder_feature_support *enc_caps; | ||||
276 | struct dpcd_caps *rx_caps = &link->dpcd_caps; | ||||
277 | enum dc_dp_training_pattern pattern = DP_TRAINING_PATTERN_SEQUENCE_2; | ||||
278 | |||||
279 | link_enc = link_enc_cfg_get_link_enc(link); | ||||
280 | ASSERT(link_enc)do { if (({ static int __warned; int __ret = !!(!(link_enc)); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n" , "!(link_enc)", "/usr/src/sys/dev/pci/drm/amd/display/dc/core/dc_link_dp.c" , 280); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | ||||
281 | enc_caps = &link_enc->features; | ||||
282 | |||||
283 | switch (dp_get_link_encoding_format(link_settings)) { | ||||
284 | case DP_8b_10b_ENCODING: | ||||
285 | if (enc_caps->flags.bits.IS_TPS4_CAPABLE && | ||||
286 | rx_caps->max_down_spread.bits.TPS4_SUPPORTED) | ||||
287 | pattern = DP_TRAINING_PATTERN_SEQUENCE_4; | ||||
288 | else if (enc_caps->flags.bits.IS_TPS3_CAPABLE && | ||||
289 | rx_caps->max_ln_count.bits.TPS3_SUPPORTED) | ||||
290 | pattern = DP_TRAINING_PATTERN_SEQUENCE_3; | ||||
291 | else | ||||
292 | pattern = DP_TRAINING_PATTERN_SEQUENCE_2; | ||||
293 | break; | ||||
294 | case DP_128b_132b_ENCODING: | ||||
295 | pattern = DP_128b_132b_TPS2; | ||||
296 | break; | ||||
297 | default: | ||||
298 | pattern = DP_TRAINING_PATTERN_SEQUENCE_2; | ||||
299 | break; | ||||
300 | } | ||||
301 | return pattern; | ||||
302 | } | ||||
303 | |||||
304 | static uint8_t get_dpcd_link_rate(const struct dc_link_settings *link_settings) | ||||
305 | { | ||||
306 | uint8_t link_rate = 0; | ||||
307 | enum dp_link_encoding encoding = dp_get_link_encoding_format(link_settings); | ||||
308 | |||||
309 | if (encoding == DP_128b_132b_ENCODING) | ||||
310 | switch (link_settings->link_rate) { | ||||
311 | case LINK_RATE_UHBR10: | ||||
312 | link_rate = 0x1; | ||||
313 | break; | ||||
314 | case LINK_RATE_UHBR20: | ||||
315 | link_rate = 0x2; | ||||
316 | break; | ||||
317 | case LINK_RATE_UHBR13_5: | ||||
318 | link_rate = 0x4; | ||||
319 | break; | ||||
320 | default: | ||||
321 | link_rate = 0; | ||||
322 | break; | ||||
323 | } | ||||
324 | else if (encoding == DP_8b_10b_ENCODING) | ||||
325 | link_rate = (uint8_t) link_settings->link_rate; | ||||
326 | else | ||||
327 | link_rate = 0; | ||||
328 | |||||
329 | return link_rate; | ||||
330 | } | ||||
331 | |||||
332 | static void dp_fixed_vs_pe_read_lane_adjust( | ||||
333 | struct dc_link *link, | ||||
334 | union dpcd_training_lane dpcd_lane_adjust[LANE_COUNT_DP_MAX]) | ||||
335 | { | ||||
336 | const uint8_t vendor_lttpr_write_data_vs[3] = {0x0, 0x53, 0x63}; | ||||
337 | const uint8_t vendor_lttpr_write_data_pe[3] = {0x0, 0x54, 0x63}; | ||||
338 | const uint8_t offset = dp_convert_to_count( | ||||
339 | link->dpcd_caps.lttpr_caps.phy_repeater_cnt); | ||||
340 | uint32_t vendor_lttpr_write_address = 0xF004F; | ||||
341 | uint32_t vendor_lttpr_read_address = 0xF0053; | ||||
342 | uint8_t dprx_vs = 0; | ||||
343 | uint8_t dprx_pe = 0; | ||||
344 | uint8_t lane; | ||||
345 | |||||
346 | if (offset != 0xFF) { | ||||
347 | vendor_lttpr_write_address += | ||||
348 | ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE0x50) * (offset - 1)); | ||||
349 | vendor_lttpr_read_address += | ||||
350 | ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE0x50) * (offset - 1)); | ||||
351 | } | ||||
352 | |||||
353 | /* W/A to read lane settings requested by DPRX */ | ||||
354 | core_link_write_dpcd( | ||||
355 | link, | ||||
356 | vendor_lttpr_write_address, | ||||
357 | &vendor_lttpr_write_data_vs[0], | ||||
358 | sizeof(vendor_lttpr_write_data_vs)); | ||||
359 | core_link_read_dpcd( | ||||
360 | link, | ||||
361 | vendor_lttpr_read_address, | ||||
362 | &dprx_vs, | ||||
363 | 1); | ||||
364 | core_link_write_dpcd( | ||||
365 | link, | ||||
366 | vendor_lttpr_write_address, | ||||
367 | &vendor_lttpr_write_data_pe[0], | ||||
368 | sizeof(vendor_lttpr_write_data_pe)); | ||||
369 | core_link_read_dpcd( | ||||
370 | link, | ||||
371 | vendor_lttpr_read_address, | ||||
372 | &dprx_pe, | ||||
373 | 1); | ||||
374 | |||||
375 | for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) { | ||||
376 | dpcd_lane_adjust[lane].bits.VOLTAGE_SWING_SET = (dprx_vs >> (2 * lane)) & 0x3; | ||||
377 | dpcd_lane_adjust[lane].bits.PRE_EMPHASIS_SET = (dprx_pe >> (2 * lane)) & 0x3; | ||||
378 | } | ||||
379 | } | ||||
380 | |||||
381 | static void dp_fixed_vs_pe_set_retimer_lane_settings( | ||||
382 | struct dc_link *link, | ||||
383 | const union dpcd_training_lane dpcd_lane_adjust[LANE_COUNT_DP_MAX], | ||||
384 | uint8_t lane_count) | ||||
385 | { | ||||
386 | const uint8_t offset = dp_convert_to_count( | ||||
387 | link->dpcd_caps.lttpr_caps.phy_repeater_cnt); | ||||
388 | const uint8_t vendor_lttpr_write_data_reset[4] = {0x1, 0x50, 0x63, 0xFF}; | ||||
389 | uint32_t vendor_lttpr_write_address = 0xF004F; | ||||
390 | uint8_t vendor_lttpr_write_data_vs[4] = {0x1, 0x51, 0x63, 0x0}; | ||||
391 | uint8_t vendor_lttpr_write_data_pe[4] = {0x1, 0x52, 0x63, 0x0}; | ||||
392 | uint8_t lane = 0; | ||||
393 | |||||
394 | if (offset != 0xFF) { | ||||
395 | vendor_lttpr_write_address += | ||||
396 | ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE0x50) * (offset - 1)); | ||||
397 | } | ||||
398 | |||||
399 | for (lane = 0; lane < lane_count; lane++) { | ||||
400 | vendor_lttpr_write_data_vs[3] |= | ||||
401 | dpcd_lane_adjust[lane].bits.VOLTAGE_SWING_SET << (2 * lane); | ||||
402 | vendor_lttpr_write_data_pe[3] |= | ||||
403 | dpcd_lane_adjust[lane].bits.PRE_EMPHASIS_SET << (2 * lane); | ||||
404 | } | ||||
405 | |||||
406 | /* Force LTTPR to output desired VS and PE */ | ||||
407 | core_link_write_dpcd( | ||||
408 | link, | ||||
409 | vendor_lttpr_write_address, | ||||
410 | &vendor_lttpr_write_data_reset[0], | ||||
411 | sizeof(vendor_lttpr_write_data_reset)); | ||||
412 | core_link_write_dpcd( | ||||
413 | link, | ||||
414 | vendor_lttpr_write_address, | ||||
415 | &vendor_lttpr_write_data_vs[0], | ||||
416 | sizeof(vendor_lttpr_write_data_vs)); | ||||
417 | core_link_write_dpcd( | ||||
418 | link, | ||||
419 | vendor_lttpr_write_address, | ||||
420 | &vendor_lttpr_write_data_pe[0], | ||||
421 | sizeof(vendor_lttpr_write_data_pe)); | ||||
422 | } | ||||
423 | |||||
424 | enum dc_status dpcd_set_link_settings( | ||||
425 | struct dc_link *link, | ||||
426 | const struct link_training_settings *lt_settings) | ||||
427 | { | ||||
428 | uint8_t rate; | ||||
429 | enum dc_status status; | ||||
430 | |||||
431 | union down_spread_ctrl downspread = {0}; | ||||
432 | union lane_count_set lane_count_set = {0}; | ||||
433 | |||||
434 | downspread.raw = (uint8_t) | ||||
435 | (lt_settings->link_settings.link_spread); | ||||
436 | |||||
437 | lane_count_set.bits.LANE_COUNT_SET = | ||||
438 | lt_settings->link_settings.lane_count; | ||||
439 | |||||
440 | lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing; | ||||
441 | lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0; | ||||
442 | |||||
443 | |||||
444 | if (link->ep_type == DISPLAY_ENDPOINT_PHY && | ||||
445 | lt_settings->pattern_for_eq < DP_TRAINING_PATTERN_SEQUENCE_4) { | ||||
446 | lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = | ||||
447 | link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED; | ||||
448 | } | ||||
449 | |||||
450 | status = core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL0x107, | ||||
451 | &downspread.raw, sizeof(downspread)); | ||||
452 | |||||
453 | status = core_link_write_dpcd(link, DP_LANE_COUNT_SET0x101, | ||||
454 | &lane_count_set.raw, 1); | ||||
455 | |||||
456 | if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_13 && | ||||
457 | lt_settings->link_settings.use_link_rate_set == true1) { | ||||
458 | rate = 0; | ||||
459 | /* WA for some MUX chips that will power down with eDP and lose supported | ||||
460 | * link rate set for eDP 1.4. Source reads DPCD 0x010 again to ensure | ||||
461 | * MUX chip gets link rate set back before link training. | ||||
462 | */ | ||||
463 | if (link->connector_signal == SIGNAL_TYPE_EDP) { | ||||
464 | uint8_t supported_link_rates[16]; | ||||
465 | |||||
466 | core_link_read_dpcd(link, DP_SUPPORTED_LINK_RATES0x010, | ||||
467 | supported_link_rates, sizeof(supported_link_rates)); | ||||
468 | } | ||||
469 | status = core_link_write_dpcd(link, DP_LINK_BW_SET0x100, &rate, 1); | ||||
470 | status = core_link_write_dpcd(link, DP_LINK_RATE_SET0x115, | ||||
471 | <_settings->link_settings.link_rate_set, 1); | ||||
472 | } else { | ||||
473 | rate = get_dpcd_link_rate(<_settings->link_settings); | ||||
474 | |||||
475 | status = core_link_write_dpcd(link, DP_LINK_BW_SET0x100, &rate, 1); | ||||
476 | } | ||||
477 | |||||
478 | if (rate) { | ||||
479 | DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x framing = %x\n %x spread = %x\n",do { } while(0) | ||||
480 | __func__,do { } while(0) | ||||
481 | DP_LINK_BW_SET,do { } while(0) | ||||
482 | lt_settings->link_settings.link_rate,do { } while(0) | ||||
483 | DP_LANE_COUNT_SET,do { } while(0) | ||||
484 | lt_settings->link_settings.lane_count,do { } while(0) | ||||
485 | lt_settings->enhanced_framing,do { } while(0) | ||||
486 | DP_DOWNSPREAD_CTRL,do { } while(0) | ||||
487 | lt_settings->link_settings.link_spread)do { } while(0); | ||||
488 | } else { | ||||
489 | DC_LOG_HW_LINK_TRAINING("%s\n %x rate set = %x\n %x lane = %x framing = %x\n %x spread = %x\n",do { } while(0) | ||||
490 | __func__,do { } while(0) | ||||
491 | DP_LINK_RATE_SET,do { } while(0) | ||||
492 | lt_settings->link_settings.link_rate_set,do { } while(0) | ||||
493 | DP_LANE_COUNT_SET,do { } while(0) | ||||
494 | lt_settings->link_settings.lane_count,do { } while(0) | ||||
495 | lt_settings->enhanced_framing,do { } while(0) | ||||
496 | DP_DOWNSPREAD_CTRL,do { } while(0) | ||||
497 | lt_settings->link_settings.link_spread)do { } while(0); | ||||
498 | } | ||||
499 | |||||
500 | return status; | ||||
501 | } | ||||
502 | |||||
503 | uint8_t dc_dp_initialize_scrambling_data_symbols( | ||||
504 | struct dc_link *link, | ||||
505 | enum dc_dp_training_pattern pattern) | ||||
506 | { | ||||
507 | uint8_t disable_scrabled_data_symbols = 0; | ||||
508 | |||||
509 | switch (pattern) { | ||||
510 | case DP_TRAINING_PATTERN_SEQUENCE_1: | ||||
511 | case DP_TRAINING_PATTERN_SEQUENCE_2: | ||||
512 | case DP_TRAINING_PATTERN_SEQUENCE_3: | ||||
513 | disable_scrabled_data_symbols = 1; | ||||
514 | break; | ||||
515 | case DP_TRAINING_PATTERN_SEQUENCE_4: | ||||
516 | case DP_128b_132b_TPS1: | ||||
517 | case DP_128b_132b_TPS2: | ||||
518 | disable_scrabled_data_symbols = 0; | ||||
519 | break; | ||||
520 | default: | ||||
521 | ASSERT(0)do { if (({ static int __warned; int __ret = !!(!(0)); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n" , "!(0)", "/usr/src/sys/dev/pci/drm/amd/display/dc/core/dc_link_dp.c" , 521); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | ||||
522 | DC_LOG_HW_LINK_TRAINING("%s: Invalid HW Training pattern: %d\n",do { } while(0) | ||||
523 | __func__, pattern)do { } while(0); | ||||
524 | break; | ||||
525 | } | ||||
526 | return disable_scrabled_data_symbols; | ||||
527 | } | ||||
528 | |||||
529 | static inline bool_Bool is_repeater(const struct link_training_settings *lt_settings, uint32_t offset) | ||||
530 | { | ||||
531 | return (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) && (offset != 0); | ||||
532 | } | ||||
533 | |||||
534 | static void dpcd_set_lt_pattern_and_lane_settings( | ||||
535 | struct dc_link *link, | ||||
536 | const struct link_training_settings *lt_settings, | ||||
537 | enum dc_dp_training_pattern pattern, | ||||
538 | uint32_t offset) | ||||
539 | { | ||||
540 | uint32_t dpcd_base_lt_offset; | ||||
541 | |||||
542 | uint8_t dpcd_lt_buffer[5] = {0}; | ||||
543 | union dpcd_training_pattern dpcd_pattern = {0}; | ||||
544 | uint32_t size_in_bytes; | ||||
545 | bool_Bool edp_workaround = false0; /* TODO link_prop.INTERNAL */ | ||||
546 | dpcd_base_lt_offset = DP_TRAINING_PATTERN_SET0x102; | ||||
547 | |||||
548 | if (is_repeater(lt_settings, offset)) | ||||
549 | dpcd_base_lt_offset = DP_TRAINING_PATTERN_SET_PHY_REPEATER10xf0010 + | ||||
550 | ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE0x50) * (offset - 1)); | ||||
551 | |||||
552 | /***************************************************************** | ||||
553 | * DpcdAddress_TrainingPatternSet | ||||
554 | *****************************************************************/ | ||||
555 | dpcd_pattern.v1_4.TRAINING_PATTERN_SET = | ||||
556 | dc_dp_training_pattern_to_dpcd_training_pattern(link, pattern); | ||||
557 | |||||
558 | dpcd_pattern.v1_4.SCRAMBLING_DISABLE = | ||||
559 | dc_dp_initialize_scrambling_data_symbols(link, pattern); | ||||
560 | |||||
561 | dpcd_lt_buffer[DP_TRAINING_PATTERN_SET0x102 - DP_TRAINING_PATTERN_SET0x102] | ||||
562 | = dpcd_pattern.raw; | ||||
563 | |||||
564 | if (is_repeater(lt_settings, offset)) { | ||||
565 | DC_LOG_HW_LINK_TRAINING("%s\n LTTPR Repeater ID: %d\n 0x%X pattern = %x\n",do { } while(0) | ||||
566 | __func__,do { } while(0) | ||||
567 | offset,do { } while(0) | ||||
568 | dpcd_base_lt_offset,do { } while(0) | ||||
569 | dpcd_pattern.v1_4.TRAINING_PATTERN_SET)do { } while(0); | ||||
570 | } else { | ||||
571 | DC_LOG_HW_LINK_TRAINING("%s\n 0x%X pattern = %x\n",do { } while(0) | ||||
572 | __func__,do { } while(0) | ||||
573 | dpcd_base_lt_offset,do { } while(0) | ||||
574 | dpcd_pattern.v1_4.TRAINING_PATTERN_SET)do { } while(0); | ||||
575 | } | ||||
576 | |||||
577 | /* concatenate everything into one buffer*/ | ||||
578 | size_in_bytes = lt_settings->link_settings.lane_count * | ||||
579 | sizeof(lt_settings->dpcd_lane_settings[0]); | ||||
580 | |||||
581 | // 0x00103 - 0x00102 | ||||
582 | memmove(__builtin_memmove((&dpcd_lt_buffer[0x103 - 0x102]), (lt_settings ->dpcd_lane_settings), (size_in_bytes)) | ||||
583 | &dpcd_lt_buffer[DP_TRAINING_LANE0_SET - DP_TRAINING_PATTERN_SET],__builtin_memmove((&dpcd_lt_buffer[0x103 - 0x102]), (lt_settings ->dpcd_lane_settings), (size_in_bytes)) | ||||
584 | lt_settings->dpcd_lane_settings,__builtin_memmove((&dpcd_lt_buffer[0x103 - 0x102]), (lt_settings ->dpcd_lane_settings), (size_in_bytes)) | ||||
585 | size_in_bytes)__builtin_memmove((&dpcd_lt_buffer[0x103 - 0x102]), (lt_settings ->dpcd_lane_settings), (size_in_bytes)); | ||||
586 | |||||
587 | if (is_repeater(lt_settings, offset)) { | ||||
588 | if (dp_get_link_encoding_format(<_settings->link_settings) == | ||||
589 | DP_128b_132b_ENCODING) | ||||
590 | DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n"do { } while(0) | ||||
591 | " 0x%X TX_FFE_PRESET_VALUE = %x\n",do { } while(0) | ||||
592 | __func__,do { } while(0) | ||||
593 | offset,do { } while(0) | ||||
594 | dpcd_base_lt_offset,do { } while(0) | ||||
595 | lt_settings->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE)do { } while(0); | ||||
596 | else if (dp_get_link_encoding_format(<_settings->link_settings) == | ||||
597 | DP_8b_10b_ENCODING) | ||||
598 | DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n"do { } while(0) | ||||
599 | " 0x%X VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n",do { } while(0) | ||||
600 | __func__,do { } while(0) | ||||
601 | offset,do { } while(0) | ||||
602 | dpcd_base_lt_offset,do { } while(0) | ||||
603 | lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET,do { } while(0) | ||||
604 | lt_settings->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET,do { } while(0) | ||||
605 | lt_settings->dpcd_lane_settings[0].bits.MAX_SWING_REACHED,do { } while(0) | ||||
606 | lt_settings->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED)do { } while(0); | ||||
607 | } else { | ||||
608 | if (dp_get_link_encoding_format(<_settings->link_settings) == | ||||
609 | DP_128b_132b_ENCODING) | ||||
610 | DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X TX_FFE_PRESET_VALUE = %x\n",do { } while(0) | ||||
611 | __func__,do { } while(0) | ||||
612 | dpcd_base_lt_offset,do { } while(0) | ||||
613 | lt_settings->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE)do { } while(0); | ||||
614 | else if (dp_get_link_encoding_format(<_settings->link_settings) == | ||||
615 | DP_8b_10b_ENCODING) | ||||
616 | DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n",do { } while(0) | ||||
617 | __func__,do { } while(0) | ||||
618 | dpcd_base_lt_offset,do { } while(0) | ||||
619 | lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET,do { } while(0) | ||||
620 | lt_settings->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET,do { } while(0) | ||||
621 | lt_settings->dpcd_lane_settings[0].bits.MAX_SWING_REACHED,do { } while(0) | ||||
622 | lt_settings->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED)do { } while(0); | ||||
623 | } | ||||
624 | if (edp_workaround) { | ||||
625 | /* for eDP write in 2 parts because the 5-byte burst is | ||||
626 | * causing issues on some eDP panels (EPR#366724) | ||||
627 | */ | ||||
628 | core_link_write_dpcd( | ||||
629 | link, | ||||
630 | DP_TRAINING_PATTERN_SET0x102, | ||||
631 | &dpcd_pattern.raw, | ||||
632 | sizeof(dpcd_pattern.raw)); | ||||
633 | |||||
634 | core_link_write_dpcd( | ||||
635 | link, | ||||
636 | DP_TRAINING_LANE0_SET0x103, | ||||
637 | (uint8_t *)(lt_settings->dpcd_lane_settings), | ||||
638 | size_in_bytes); | ||||
639 | |||||
640 | } else if (dp_get_link_encoding_format(<_settings->link_settings) == | ||||
641 | DP_128b_132b_ENCODING) { | ||||
642 | core_link_write_dpcd( | ||||
643 | link, | ||||
644 | dpcd_base_lt_offset, | ||||
645 | dpcd_lt_buffer, | ||||
646 | sizeof(dpcd_lt_buffer)); | ||||
647 | } else | ||||
648 | /* write it all in (1 + number-of-lanes)-byte burst*/ | ||||
649 | core_link_write_dpcd( | ||||
650 | link, | ||||
651 | dpcd_base_lt_offset, | ||||
652 | dpcd_lt_buffer, | ||||
653 | size_in_bytes + sizeof(dpcd_pattern.raw)); | ||||
654 | } | ||||
655 | |||||
656 | bool_Bool dp_is_cr_done(enum dc_lane_count ln_count, | ||||
657 | union lane_status *dpcd_lane_status) | ||||
658 | { | ||||
659 | uint32_t lane; | ||||
660 | /*LANEx_CR_DONE bits All 1's?*/ | ||||
661 | for (lane = 0; lane < (uint32_t)(ln_count); lane++) { | ||||
662 | if (!dpcd_lane_status[lane].bits.CR_DONE_0) | ||||
| |||||
663 | return false0; | ||||
664 | } | ||||
665 | return true1; | ||||
666 | } | ||||
667 | |||||
668 | bool_Bool dp_is_ch_eq_done(enum dc_lane_count ln_count, | ||||
669 | union lane_status *dpcd_lane_status) | ||||
670 | { | ||||
671 | bool_Bool done = true1; | ||||
672 | uint32_t lane; | ||||
673 | for (lane = 0; lane < (uint32_t)(ln_count); lane++) | ||||
674 | if (!dpcd_lane_status[lane].bits.CHANNEL_EQ_DONE_0) | ||||
675 | done = false0; | ||||
676 | return done; | ||||
677 | } | ||||
678 | |||||
679 | bool_Bool dp_is_symbol_locked(enum dc_lane_count ln_count, | ||||
680 | union lane_status *dpcd_lane_status) | ||||
681 | { | ||||
682 | bool_Bool locked = true1; | ||||
683 | uint32_t lane; | ||||
684 | for (lane = 0; lane < (uint32_t)(ln_count); lane++) | ||||
685 | if (!dpcd_lane_status[lane].bits.SYMBOL_LOCKED_0) | ||||
686 | locked = false0; | ||||
687 | return locked; | ||||
688 | } | ||||
689 | |||||
690 | bool_Bool dp_is_interlane_aligned(union lane_align_status_updated align_status) | ||||
691 | { | ||||
692 | return align_status.bits.INTERLANE_ALIGN_DONE == 1; | ||||
693 | } | ||||
694 | |||||
695 | void dp_hw_to_dpcd_lane_settings( | ||||
696 | const struct link_training_settings *lt_settings, | ||||
697 | const struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX], | ||||
698 | union dpcd_training_lane dpcd_lane_settings[]) | ||||
699 | { | ||||
700 | uint8_t lane = 0; | ||||
701 | |||||
702 | for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) { | ||||
703 | if (dp_get_link_encoding_format(<_settings->link_settings) == | ||||
704 | DP_8b_10b_ENCODING) { | ||||
705 | dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET = | ||||
706 | (uint8_t)(hw_lane_settings[lane].VOLTAGE_SWING); | ||||
707 | dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET = | ||||
708 | (uint8_t)(hw_lane_settings[lane].PRE_EMPHASIS); | ||||
709 | dpcd_lane_settings[lane].bits.MAX_SWING_REACHED = | ||||
710 | (hw_lane_settings[lane].VOLTAGE_SWING == | ||||
711 | VOLTAGE_SWING_MAX_LEVEL ? 1 : 0); | ||||
712 | dpcd_lane_settings[lane].bits.MAX_PRE_EMPHASIS_REACHED = | ||||
713 | (hw_lane_settings[lane].PRE_EMPHASIS == | ||||
714 | PRE_EMPHASIS_MAX_LEVEL ? 1 : 0); | ||||
715 | } | ||||
716 | else if (dp_get_link_encoding_format(<_settings->link_settings) == | ||||
717 | DP_128b_132b_ENCODING) { | ||||
718 | dpcd_lane_settings[lane].tx_ffe.PRESET_VALUE = | ||||
719 | hw_lane_settings[lane].FFE_PRESET.settings.level; | ||||
720 | } | ||||
721 | } | ||||
722 | } | ||||
723 | |||||
724 | void dp_decide_lane_settings( | ||||
725 | const struct link_training_settings *lt_settings, | ||||
726 | const union lane_adjust ln_adjust[LANE_COUNT_DP_MAX], | ||||
727 | struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX], | ||||
728 | union dpcd_training_lane dpcd_lane_settings[]) | ||||
729 | { | ||||
730 | uint32_t lane; | ||||
731 | |||||
732 | for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) { | ||||
733 | if (dp_get_link_encoding_format(<_settings->link_settings) == | ||||
734 | DP_8b_10b_ENCODING) { | ||||
735 | hw_lane_settings[lane].VOLTAGE_SWING = | ||||
736 | (enum dc_voltage_swing)(ln_adjust[lane].bits. | ||||
737 | VOLTAGE_SWING_LANE); | ||||
738 | hw_lane_settings[lane].PRE_EMPHASIS = | ||||
739 | (enum dc_pre_emphasis)(ln_adjust[lane].bits. | ||||
740 | PRE_EMPHASIS_LANE); | ||||
741 | } | ||||
742 | else if (dp_get_link_encoding_format(<_settings->link_settings) == | ||||
743 | DP_128b_132b_ENCODING) { | ||||
744 | hw_lane_settings[lane].FFE_PRESET.raw = | ||||
745 | ln_adjust[lane].tx_ffe.PRESET_VALUE; | ||||
746 | } | ||||
747 | } | ||||
748 | dp_hw_to_dpcd_lane_settings(lt_settings, hw_lane_settings, dpcd_lane_settings); | ||||
749 | |||||
750 | if (lt_settings->disallow_per_lane_settings) { | ||||
751 | /* we find the maximum of the requested settings across all lanes*/ | ||||
752 | /* and set this maximum for all lanes*/ | ||||
753 | maximize_lane_settings(lt_settings, hw_lane_settings); | ||||
754 | override_lane_settings(lt_settings, hw_lane_settings); | ||||
755 | |||||
756 | if (lt_settings->always_match_dpcd_with_hw_lane_settings) | ||||
757 | dp_hw_to_dpcd_lane_settings(lt_settings, hw_lane_settings, dpcd_lane_settings); | ||||
758 | } | ||||
759 | |||||
760 | } | ||||
761 | |||||
762 | static uint8_t get_nibble_at_index(const uint8_t *buf, | ||||
763 | uint32_t index) | ||||
764 | { | ||||
765 | uint8_t nibble; | ||||
766 | nibble = buf[index / 2]; | ||||
767 | |||||
768 | if (index % 2) | ||||
769 | nibble >>= 4; | ||||
770 | else | ||||
771 | nibble &= 0x0F; | ||||
772 | |||||
773 | return nibble; | ||||
774 | } | ||||
775 | |||||
776 | static enum dc_pre_emphasis get_max_pre_emphasis_for_voltage_swing( | ||||
777 | enum dc_voltage_swing voltage) | ||||
778 | { | ||||
779 | enum dc_pre_emphasis pre_emphasis; | ||||
780 | pre_emphasis = PRE_EMPHASIS_MAX_LEVEL; | ||||
781 | |||||
782 | if (voltage <= VOLTAGE_SWING_MAX_LEVEL) | ||||
783 | pre_emphasis = voltage_swing_to_pre_emphasis[voltage]; | ||||
784 | |||||
785 | return pre_emphasis; | ||||
786 | |||||
787 | } | ||||
788 | |||||
789 | static void maximize_lane_settings(const struct link_training_settings *lt_settings, | ||||
790 | struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX]) | ||||
791 | { | ||||
792 | uint32_t lane; | ||||
793 | struct dc_lane_settings max_requested; | ||||
794 | |||||
795 | max_requested.VOLTAGE_SWING = lane_settings[0].VOLTAGE_SWING; | ||||
796 | max_requested.PRE_EMPHASIS = lane_settings[0].PRE_EMPHASIS; | ||||
797 | max_requested.FFE_PRESET = lane_settings[0].FFE_PRESET; | ||||
798 | |||||
799 | /* Determine what the maximum of the requested settings are*/ | ||||
800 | for (lane = 1; lane < lt_settings->link_settings.lane_count; lane++) { | ||||
801 | if (lane_settings[lane].VOLTAGE_SWING > max_requested.VOLTAGE_SWING) | ||||
802 | max_requested.VOLTAGE_SWING = lane_settings[lane].VOLTAGE_SWING; | ||||
803 | |||||
804 | if (lane_settings[lane].PRE_EMPHASIS > max_requested.PRE_EMPHASIS) | ||||
805 | max_requested.PRE_EMPHASIS = lane_settings[lane].PRE_EMPHASIS; | ||||
806 | if (lane_settings[lane].FFE_PRESET.settings.level > | ||||
807 | max_requested.FFE_PRESET.settings.level) | ||||
808 | max_requested.FFE_PRESET.settings.level = | ||||
809 | lane_settings[lane].FFE_PRESET.settings.level; | ||||
810 | } | ||||
811 | |||||
812 | /* make sure the requested settings are | ||||
813 | * not higher than maximum settings*/ | ||||
814 | if (max_requested.VOLTAGE_SWING > VOLTAGE_SWING_MAX_LEVEL) | ||||
815 | max_requested.VOLTAGE_SWING = VOLTAGE_SWING_MAX_LEVEL; | ||||
816 | |||||
817 | if (max_requested.PRE_EMPHASIS > PRE_EMPHASIS_MAX_LEVEL) | ||||
818 | max_requested.PRE_EMPHASIS = PRE_EMPHASIS_MAX_LEVEL; | ||||
819 | if (max_requested.FFE_PRESET.settings.level > DP_FFE_PRESET_MAX_LEVEL) | ||||
820 | max_requested.FFE_PRESET.settings.level = DP_FFE_PRESET_MAX_LEVEL; | ||||
821 | |||||
822 | /* make sure the pre-emphasis matches the voltage swing*/ | ||||
823 | if (max_requested.PRE_EMPHASIS > | ||||
824 | get_max_pre_emphasis_for_voltage_swing( | ||||
825 | max_requested.VOLTAGE_SWING)) | ||||
826 | max_requested.PRE_EMPHASIS = | ||||
827 | get_max_pre_emphasis_for_voltage_swing( | ||||
828 | max_requested.VOLTAGE_SWING); | ||||
829 | |||||
830 | for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) { | ||||
831 | lane_settings[lane].VOLTAGE_SWING = max_requested.VOLTAGE_SWING; | ||||
832 | lane_settings[lane].PRE_EMPHASIS = max_requested.PRE_EMPHASIS; | ||||
833 | lane_settings[lane].FFE_PRESET = max_requested.FFE_PRESET; | ||||
834 | } | ||||
835 | } | ||||
836 | |||||
837 | static void override_lane_settings(const struct link_training_settings *lt_settings, | ||||
838 | struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX]) | ||||
839 | { | ||||
840 | uint32_t lane; | ||||
841 | |||||
842 | if (lt_settings->voltage_swing == NULL((void *)0) && | ||||
843 | lt_settings->pre_emphasis == NULL((void *)0) && | ||||
844 | lt_settings->ffe_preset == NULL((void *)0) && | ||||
845 | lt_settings->post_cursor2 == NULL((void *)0)) | ||||
846 | |||||
847 | return; | ||||
848 | |||||
849 | for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) { | ||||
850 | if (lt_settings->voltage_swing) | ||||
851 | lane_settings[lane].VOLTAGE_SWING = *lt_settings->voltage_swing; | ||||
852 | if (lt_settings->pre_emphasis) | ||||
853 | lane_settings[lane].PRE_EMPHASIS = *lt_settings->pre_emphasis; | ||||
854 | if (lt_settings->post_cursor2) | ||||
855 | lane_settings[lane].POST_CURSOR2 = *lt_settings->post_cursor2; | ||||
856 | if (lt_settings->ffe_preset) | ||||
857 | lane_settings[lane].FFE_PRESET = *lt_settings->ffe_preset; | ||||
858 | } | ||||
859 | } | ||||
860 | |||||
861 | enum dc_status dp_get_lane_status_and_lane_adjust( | ||||
862 | struct dc_link *link, | ||||
863 | const struct link_training_settings *link_training_setting, | ||||
864 | union lane_status ln_status[LANE_COUNT_DP_MAX], | ||||
865 | union lane_align_status_updated *ln_align, | ||||
866 | union lane_adjust ln_adjust[LANE_COUNT_DP_MAX], | ||||
867 | uint32_t offset) | ||||
868 | { | ||||
869 | unsigned int lane01_status_address = DP_LANE0_1_STATUS0x202; | ||||
870 | uint8_t lane_adjust_offset = 4; | ||||
871 | unsigned int lane01_adjust_address; | ||||
872 | uint8_t dpcd_buf[6] = {0}; | ||||
873 | uint32_t lane; | ||||
874 | enum dc_status status; | ||||
875 | |||||
876 | if (is_repeater(link_training_setting, offset)) { | ||||
877 | lane01_status_address = | ||||
878 | DP_LANE0_1_STATUS_PHY_REPEATER10xf0030 + | ||||
879 | ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE0x50) * (offset - 1)); | ||||
880 | lane_adjust_offset = 3; | ||||
881 | } | ||||
882 | |||||
883 | status = core_link_read_dpcd( | ||||
884 | link, | ||||
885 | lane01_status_address, | ||||
886 | (uint8_t *)(dpcd_buf), | ||||
887 | sizeof(dpcd_buf)); | ||||
888 | |||||
889 | if (status != DC_OK) { | ||||
890 | DC_LOG_HW_LINK_TRAINING("%s:\n Failed to read from address 0x%X,"do { } while(0) | ||||
891 | " keep current lane status and lane adjust unchanged",do { } while(0) | ||||
892 | __func__,do { } while(0) | ||||
893 | lane01_status_address)do { } while(0); | ||||
894 | return status; | ||||
895 | } | ||||
896 | |||||
897 | for (lane = 0; lane < | ||||
898 | (uint32_t)(link_training_setting->link_settings.lane_count); | ||||
899 | lane++) { | ||||
900 | |||||
901 | ln_status[lane].raw = | ||||
902 | get_nibble_at_index(&dpcd_buf[0], lane); | ||||
903 | ln_adjust[lane].raw = | ||||
904 | get_nibble_at_index(&dpcd_buf[lane_adjust_offset], lane); | ||||
905 | } | ||||
906 | |||||
907 | ln_align->raw = dpcd_buf[2]; | ||||
908 | |||||
909 | if (is_repeater(link_training_setting, offset)) { | ||||
910 | DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n"do { } while(0) | ||||
911 | " 0x%X Lane01Status = %x\n 0x%X Lane23Status = %x\n ",do { } while(0) | ||||
912 | __func__,do { } while(0) | ||||
913 | offset,do { } while(0) | ||||
914 | lane01_status_address, dpcd_buf[0],do { } while(0) | ||||
915 | lane01_status_address + 1, dpcd_buf[1])do { } while(0); | ||||
916 | |||||
917 | lane01_adjust_address = DP_ADJUST_REQUEST_LANE0_1_PHY_REPEATER10xf0033 + | ||||
918 | ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE0x50) * (offset - 1)); | ||||
919 | |||||
920 | DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n"do { } while(0) | ||||
921 | " 0x%X Lane01AdjustRequest = %x\n 0x%X Lane23AdjustRequest = %x\n",do { } while(0) | ||||
922 | __func__,do { } while(0) | ||||
923 | offset,do { } while(0) | ||||
924 | lane01_adjust_address,do { } while(0) | ||||
925 | dpcd_buf[lane_adjust_offset],do { } while(0) | ||||
926 | lane01_adjust_address + 1,do { } while(0) | ||||
927 | dpcd_buf[lane_adjust_offset + 1])do { } while(0); | ||||
928 | } else { | ||||
929 | DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X Lane01Status = %x\n 0x%X Lane23Status = %x\n ",do { } while(0) | ||||
930 | __func__,do { } while(0) | ||||
931 | lane01_status_address, dpcd_buf[0],do { } while(0) | ||||
932 | lane01_status_address + 1, dpcd_buf[1])do { } while(0); | ||||
933 | |||||
934 | lane01_adjust_address = DP_ADJUST_REQUEST_LANE0_10x206; | ||||
935 | |||||
936 | DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X Lane01AdjustRequest = %x\n 0x%X Lane23AdjustRequest = %x\n",do { } while(0) | ||||
937 | __func__,do { } while(0) | ||||
938 | lane01_adjust_address,do { } while(0) | ||||
939 | dpcd_buf[lane_adjust_offset],do { } while(0) | ||||
940 | lane01_adjust_address + 1,do { } while(0) | ||||
941 | dpcd_buf[lane_adjust_offset + 1])do { } while(0); | ||||
942 | } | ||||
943 | |||||
944 | return status; | ||||
945 | } | ||||
946 | |||||
947 | static enum dc_status dpcd_128b_132b_set_lane_settings( | ||||
948 | struct dc_link *link, | ||||
949 | const struct link_training_settings *link_training_setting) | ||||
950 | { | ||||
951 | enum dc_status status = core_link_write_dpcd(link, | ||||
952 | DP_TRAINING_LANE0_SET0x103, | ||||
953 | (uint8_t *)(link_training_setting->dpcd_lane_settings), | ||||
954 | sizeof(link_training_setting->dpcd_lane_settings)); | ||||
955 | |||||
956 | DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X TX_FFE_PRESET_VALUE = %x\n",do { } while(0) | ||||
957 | __func__,do { } while(0) | ||||
958 | DP_TRAINING_LANE0_SET,do { } while(0) | ||||
959 | link_training_setting->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE)do { } while(0); | ||||
960 | return status; | ||||
961 | } | ||||
962 | |||||
963 | |||||
964 | enum dc_status dpcd_set_lane_settings( | ||||
965 | struct dc_link *link, | ||||
966 | const struct link_training_settings *link_training_setting, | ||||
967 | uint32_t offset) | ||||
968 | { | ||||
969 | unsigned int lane0_set_address; | ||||
970 | enum dc_status status; | ||||
971 | |||||
972 | lane0_set_address = DP_TRAINING_LANE0_SET0x103; | ||||
973 | |||||
974 | if (is_repeater(link_training_setting, offset)) | ||||
975 | lane0_set_address = DP_TRAINING_LANE0_SET_PHY_REPEATER10xf0011 + | ||||
976 | ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE0x50) * (offset - 1)); | ||||
977 | |||||
978 | status = core_link_write_dpcd(link, | ||||
979 | lane0_set_address, | ||||
980 | (uint8_t *)(link_training_setting->dpcd_lane_settings), | ||||
981 | link_training_setting->link_settings.lane_count); | ||||
982 | |||||
983 | if (is_repeater(link_training_setting, offset)) { | ||||
984 | DC_LOG_HW_LINK_TRAINING("%s\n LTTPR Repeater ID: %d\n"do { } while(0) | ||||
985 | " 0x%X VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n",do { } while(0) | ||||
986 | __func__,do { } while(0) | ||||
987 | offset,do { } while(0) | ||||
988 | lane0_set_address,do { } while(0) | ||||
989 | link_training_setting->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET,do { } while(0) | ||||
990 | link_training_setting->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET,do { } while(0) | ||||
991 | link_training_setting->dpcd_lane_settings[0].bits.MAX_SWING_REACHED,do { } while(0) | ||||
992 | link_training_setting->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED)do { } while(0); | ||||
993 | |||||
994 | } else { | ||||
995 | DC_LOG_HW_LINK_TRAINING("%s\n 0x%X VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n",do { } while(0) | ||||
996 | __func__,do { } while(0) | ||||
997 | lane0_set_address,do { } while(0) | ||||
998 | link_training_setting->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET,do { } while(0) | ||||
999 | link_training_setting->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET,do { } while(0) | ||||
1000 | link_training_setting->dpcd_lane_settings[0].bits.MAX_SWING_REACHED,do { } while(0) | ||||
1001 | link_training_setting->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED)do { } while(0); | ||||
1002 | } | ||||
1003 | |||||
1004 | return status; | ||||
1005 | } | ||||
1006 | |||||
1007 | bool_Bool dp_is_max_vs_reached( | ||||
1008 | const struct link_training_settings *lt_settings) | ||||
1009 | { | ||||
1010 | uint32_t lane; | ||||
1011 | for (lane = 0; lane < | ||||
1012 | (uint32_t)(lt_settings->link_settings.lane_count); | ||||
1013 | lane++) { | ||||
1014 | if (lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET | ||||
1015 | == VOLTAGE_SWING_MAX_LEVEL) | ||||
1016 | return true1; | ||||
1017 | } | ||||
1018 | return false0; | ||||
1019 | |||||
1020 | } | ||||
1021 | |||||
1022 | static bool_Bool perform_post_lt_adj_req_sequence( | ||||
1023 | struct dc_link *link, | ||||
1024 | const struct link_resource *link_res, | ||||
1025 | struct link_training_settings *lt_settings) | ||||
1026 | { | ||||
1027 | enum dc_lane_count lane_count = | ||||
1028 | lt_settings->link_settings.lane_count; | ||||
1029 | |||||
1030 | uint32_t adj_req_count; | ||||
1031 | uint32_t adj_req_timer; | ||||
1032 | bool_Bool req_drv_setting_changed; | ||||
1033 | uint32_t lane; | ||||
1034 | union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0}; | ||||
1035 | union lane_align_status_updated dpcd_lane_status_updated = {0}; | ||||
1036 | union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0}; | ||||
1037 | |||||
1038 | req_drv_setting_changed = false0; | ||||
1039 | for (adj_req_count = 0; adj_req_count < POST_LT_ADJ_REQ_LIMIT; | ||||
1040 | adj_req_count++) { | ||||
1041 | |||||
1042 | req_drv_setting_changed = false0; | ||||
1043 | |||||
1044 | for (adj_req_timer = 0; | ||||
1045 | adj_req_timer < POST_LT_ADJ_REQ_TIMEOUT; | ||||
1046 | adj_req_timer++) { | ||||
1047 | |||||
1048 | dp_get_lane_status_and_lane_adjust( | ||||
1049 | link, | ||||
1050 | lt_settings, | ||||
1051 | dpcd_lane_status, | ||||
1052 | &dpcd_lane_status_updated, | ||||
1053 | dpcd_lane_adjust, | ||||
1054 | DPRX); | ||||
1055 | |||||
1056 | if (dpcd_lane_status_updated.bits. | ||||
1057 | POST_LT_ADJ_REQ_IN_PROGRESS == 0) | ||||
1058 | return true1; | ||||
1059 | |||||
1060 | if (!dp_is_cr_done(lane_count, dpcd_lane_status)) | ||||
1061 | return false0; | ||||
1062 | |||||
1063 | if (!dp_is_ch_eq_done(lane_count, dpcd_lane_status) || | ||||
1064 | !dp_is_symbol_locked(lane_count, dpcd_lane_status) || | ||||
1065 | !dp_is_interlane_aligned(dpcd_lane_status_updated)) | ||||
1066 | return false0; | ||||
1067 | |||||
1068 | for (lane = 0; lane < (uint32_t)(lane_count); lane++) { | ||||
1069 | |||||
1070 | if (lt_settings-> | ||||
1071 | dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET != | ||||
1072 | dpcd_lane_adjust[lane].bits.VOLTAGE_SWING_LANE || | ||||
1073 | lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET != | ||||
1074 | dpcd_lane_adjust[lane].bits.PRE_EMPHASIS_LANE) { | ||||
1075 | |||||
1076 | req_drv_setting_changed = true1; | ||||
1077 | break; | ||||
1078 | } | ||||
1079 | } | ||||
1080 | |||||
1081 | if (req_drv_setting_changed) { | ||||
1082 | dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, | ||||
1083 | lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); | ||||
1084 | |||||
1085 | dc_link_dp_set_drive_settings(link, | ||||
1086 | link_res, | ||||
1087 | lt_settings); | ||||
1088 | break; | ||||
1089 | } | ||||
1090 | |||||
1091 | drm_msleep(1)mdelay(1); | ||||
1092 | } | ||||
1093 | |||||
1094 | if (!req_drv_setting_changed) { | ||||
1095 | DC_LOG_WARNING("%s: Post Link Training Adjust Request Timed out\n",printk("\0014" "[" "drm" "] " "%s: Post Link Training Adjust Request Timed out\n" , __func__) | ||||
1096 | __func__)printk("\0014" "[" "drm" "] " "%s: Post Link Training Adjust Request Timed out\n" , __func__); | ||||
1097 | |||||
1098 | ASSERT(0)do { if (({ static int __warned; int __ret = !!(!(0)); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n" , "!(0)", "/usr/src/sys/dev/pci/drm/amd/display/dc/core/dc_link_dp.c" , 1098); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | ||||
1099 | return true1; | ||||
1100 | } | ||||
1101 | } | ||||
1102 | DC_LOG_WARNING("%s: Post Link Training Adjust Request limit reached\n",printk("\0014" "[" "drm" "] " "%s: Post Link Training Adjust Request limit reached\n" , __func__) | ||||
1103 | __func__)printk("\0014" "[" "drm" "] " "%s: Post Link Training Adjust Request limit reached\n" , __func__); | ||||
1104 | |||||
1105 | ASSERT(0)do { if (({ static int __warned; int __ret = !!(!(0)); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n" , "!(0)", "/usr/src/sys/dev/pci/drm/amd/display/dc/core/dc_link_dp.c" , 1105); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | ||||
1106 | return true1; | ||||
1107 | |||||
1108 | } | ||||
1109 | |||||
1110 | /* Only used for channel equalization */ | ||||
1111 | uint32_t dp_translate_training_aux_read_interval(uint32_t dpcd_aux_read_interval) | ||||
1112 | { | ||||
1113 | unsigned int aux_rd_interval_us = 400; | ||||
1114 | |||||
1115 | switch (dpcd_aux_read_interval) { | ||||
1116 | case 0x01: | ||||
1117 | aux_rd_interval_us = 4000; | ||||
1118 | break; | ||||
1119 | case 0x02: | ||||
1120 | aux_rd_interval_us = 8000; | ||||
1121 | break; | ||||
1122 | case 0x03: | ||||
1123 | aux_rd_interval_us = 12000; | ||||
1124 | break; | ||||
1125 | case 0x04: | ||||
1126 | aux_rd_interval_us = 16000; | ||||
1127 | break; | ||||
1128 | case 0x05: | ||||
1129 | aux_rd_interval_us = 32000; | ||||
1130 | break; | ||||
1131 | case 0x06: | ||||
1132 | aux_rd_interval_us = 64000; | ||||
1133 | break; | ||||
1134 | default: | ||||
1135 | break; | ||||
1136 | } | ||||
1137 | |||||
1138 | return aux_rd_interval_us; | ||||
1139 | } | ||||
1140 | |||||
1141 | enum link_training_result dp_get_cr_failure(enum dc_lane_count ln_count, | ||||
1142 | union lane_status *dpcd_lane_status) | ||||
1143 | { | ||||
1144 | enum link_training_result result = LINK_TRAINING_SUCCESS; | ||||
1145 | |||||
1146 | if (ln_count >= LANE_COUNT_ONE && !dpcd_lane_status[0].bits.CR_DONE_0) | ||||
1147 | result = LINK_TRAINING_CR_FAIL_LANE0; | ||||
1148 | else if (ln_count >= LANE_COUNT_TWO && !dpcd_lane_status[1].bits.CR_DONE_0) | ||||
1149 | result = LINK_TRAINING_CR_FAIL_LANE1; | ||||
1150 | else if (ln_count >= LANE_COUNT_FOUR && !dpcd_lane_status[2].bits.CR_DONE_0) | ||||
1151 | result = LINK_TRAINING_CR_FAIL_LANE23; | ||||
1152 | else if (ln_count >= LANE_COUNT_FOUR && !dpcd_lane_status[3].bits.CR_DONE_0) | ||||
1153 | result = LINK_TRAINING_CR_FAIL_LANE23; | ||||
1154 | return result; | ||||
1155 | } | ||||
1156 | |||||
1157 | static enum link_training_result perform_channel_equalization_sequence( | ||||
1158 | struct dc_link *link, | ||||
1159 | const struct link_resource *link_res, | ||||
1160 | struct link_training_settings *lt_settings, | ||||
1161 | uint32_t offset) | ||||
1162 | { | ||||
1163 | enum dc_dp_training_pattern tr_pattern; | ||||
1164 | uint32_t retries_ch_eq; | ||||
1165 | uint32_t wait_time_microsec; | ||||
1166 | enum dc_lane_count lane_count = lt_settings->link_settings.lane_count; | ||||
1167 | union lane_align_status_updated dpcd_lane_status_updated = {0}; | ||||
1168 | union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0}; | ||||
1169 | union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0}; | ||||
1170 | |||||
1171 | /* Note: also check that TPS4 is a supported feature*/ | ||||
1172 | tr_pattern = lt_settings->pattern_for_eq; | ||||
1173 | |||||
1174 | if (is_repeater(lt_settings, offset) && dp_get_link_encoding_format(<_settings->link_settings) == DP_8b_10b_ENCODING) | ||||
1175 | tr_pattern = DP_TRAINING_PATTERN_SEQUENCE_4; | ||||
1176 | |||||
1177 | dp_set_hw_training_pattern(link, link_res, tr_pattern, offset); | ||||
1178 | |||||
1179 | for (retries_ch_eq = 0; retries_ch_eq <= LINK_TRAINING_MAX_RETRY_COUNT; | ||||
1180 | retries_ch_eq++) { | ||||
1181 | |||||
1182 | dp_set_hw_lane_settings(link, link_res, lt_settings, offset); | ||||
1183 | |||||
1184 | /* 2. update DPCD*/ | ||||
1185 | if (!retries_ch_eq) | ||||
1186 | /* EPR #361076 - write as a 5-byte burst, | ||||
1187 | * but only for the 1-st iteration | ||||
1188 | */ | ||||
1189 | |||||
1190 | dpcd_set_lt_pattern_and_lane_settings( | ||||
1191 | link, | ||||
1192 | lt_settings, | ||||
1193 | tr_pattern, offset); | ||||
1194 | else | ||||
1195 | dpcd_set_lane_settings(link, lt_settings, offset); | ||||
1196 | |||||
1197 | /* 3. wait for receiver to lock-on*/ | ||||
1198 | wait_time_microsec = lt_settings->eq_pattern_time; | ||||
1199 | |||||
1200 | if (is_repeater(lt_settings, offset)) | ||||
1201 | wait_time_microsec = | ||||
1202 | dp_translate_training_aux_read_interval( | ||||
1203 | link->dpcd_caps.lttpr_caps.aux_rd_interval[offset - 1]); | ||||
1204 | |||||
1205 | dp_wait_for_training_aux_rd_interval( | ||||
1206 | link, | ||||
1207 | wait_time_microsec); | ||||
1208 | |||||
1209 | /* 4. Read lane status and requested | ||||
1210 | * drive settings as set by the sink*/ | ||||
1211 | |||||
1212 | dp_get_lane_status_and_lane_adjust( | ||||
1213 | link, | ||||
1214 | lt_settings, | ||||
1215 | dpcd_lane_status, | ||||
1216 | &dpcd_lane_status_updated, | ||||
1217 | dpcd_lane_adjust, | ||||
1218 | offset); | ||||
1219 | |||||
1220 | /* 5. check CR done*/ | ||||
1221 | if (!dp_is_cr_done(lane_count, dpcd_lane_status)) | ||||
1222 | return dpcd_lane_status[0].bits.CR_DONE_0 ? | ||||
1223 | LINK_TRAINING_EQ_FAIL_CR_PARTIAL : | ||||
1224 | LINK_TRAINING_EQ_FAIL_CR; | ||||
1225 | |||||
1226 | /* 6. check CHEQ done*/ | ||||
1227 | if (dp_is_ch_eq_done(lane_count, dpcd_lane_status) && | ||||
1228 | dp_is_symbol_locked(lane_count, dpcd_lane_status) && | ||||
1229 | dp_is_interlane_aligned(dpcd_lane_status_updated)) | ||||
1230 | return LINK_TRAINING_SUCCESS; | ||||
1231 | |||||
1232 | /* 7. update VS/PE/PC2 in lt_settings*/ | ||||
1233 | dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, | ||||
1234 | lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); | ||||
1235 | } | ||||
1236 | |||||
1237 | return LINK_TRAINING_EQ_FAIL_EQ; | ||||
1238 | |||||
1239 | } | ||||
1240 | |||||
1241 | static void start_clock_recovery_pattern_early(struct dc_link *link, | ||||
1242 | const struct link_resource *link_res, | ||||
1243 | struct link_training_settings *lt_settings, | ||||
1244 | uint32_t offset) | ||||
1245 | { | ||||
1246 | DC_LOG_HW_LINK_TRAINING("%s\n GPU sends TPS1. Wait 400us.\n",do { } while(0) | ||||
1247 | __func__)do { } while(0); | ||||
1248 | dp_set_hw_training_pattern(link, link_res, lt_settings->pattern_for_cr, offset); | ||||
1249 | dp_set_hw_lane_settings(link, link_res, lt_settings, offset); | ||||
1250 | udelay(400); | ||||
1251 | } | ||||
1252 | |||||
1253 | static enum link_training_result perform_clock_recovery_sequence( | ||||
1254 | struct dc_link *link, | ||||
1255 | const struct link_resource *link_res, | ||||
1256 | struct link_training_settings *lt_settings, | ||||
1257 | uint32_t offset) | ||||
1258 | { | ||||
1259 | uint32_t retries_cr; | ||||
1260 | uint32_t retry_count; | ||||
1261 | uint32_t wait_time_microsec; | ||||
1262 | enum dc_lane_count lane_count = lt_settings->link_settings.lane_count; | ||||
1263 | union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX]; | ||||
1264 | union lane_align_status_updated dpcd_lane_status_updated; | ||||
1265 | union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0}; | ||||
1266 | |||||
1267 | retries_cr = 0; | ||||
1268 | retry_count = 0; | ||||
1269 | |||||
1270 | memset(&dpcd_lane_status, '\0', sizeof(dpcd_lane_status))__builtin_memset((&dpcd_lane_status), ('\0'), (sizeof(dpcd_lane_status ))); | ||||
1271 | memset(&dpcd_lane_status_updated, '\0',__builtin_memset((&dpcd_lane_status_updated), ('\0'), (sizeof (dpcd_lane_status_updated))) | ||||
1272 | sizeof(dpcd_lane_status_updated))__builtin_memset((&dpcd_lane_status_updated), ('\0'), (sizeof (dpcd_lane_status_updated))); | ||||
1273 | |||||
1274 | if (!link->ctx->dc->work_arounds.lt_early_cr_pattern) | ||||
1275 | dp_set_hw_training_pattern(link, link_res, lt_settings->pattern_for_cr, offset); | ||||
1276 | |||||
1277 | /* najeeb - The synaptics MST hub can put the LT in | ||||
1278 | * infinite loop by switching the VS | ||||
1279 | */ | ||||
1280 | /* between level 0 and level 1 continuously, here | ||||
1281 | * we try for CR lock for LinkTrainingMaxCRRetry count*/ | ||||
1282 | while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) && | ||||
1283 | (retry_count < LINK_TRAINING_MAX_CR_RETRY)) { | ||||
1284 | |||||
1285 | |||||
1286 | /* 1. call HWSS to set lane settings*/ | ||||
1287 | dp_set_hw_lane_settings( | ||||
1288 | link, | ||||
1289 | link_res, | ||||
1290 | lt_settings, | ||||
1291 | offset); | ||||
1292 | |||||
1293 | /* 2. update DPCD of the receiver*/ | ||||
1294 | if (!retry_count) | ||||
1295 | /* EPR #361076 - write as a 5-byte burst, | ||||
1296 | * but only for the 1-st iteration.*/ | ||||
1297 | dpcd_set_lt_pattern_and_lane_settings( | ||||
1298 | link, | ||||
1299 | lt_settings, | ||||
1300 | lt_settings->pattern_for_cr, | ||||
1301 | offset); | ||||
1302 | else | ||||
1303 | dpcd_set_lane_settings( | ||||
1304 | link, | ||||
1305 | lt_settings, | ||||
1306 | offset); | ||||
1307 | |||||
1308 | /* 3. wait receiver to lock-on*/ | ||||
1309 | wait_time_microsec = lt_settings->cr_pattern_time; | ||||
1310 | |||||
1311 | dp_wait_for_training_aux_rd_interval( | ||||
1312 | link, | ||||
1313 | wait_time_microsec); | ||||
1314 | |||||
1315 | /* 4. Read lane status and requested drive | ||||
1316 | * settings as set by the sink | ||||
1317 | */ | ||||
1318 | dp_get_lane_status_and_lane_adjust( | ||||
1319 | link, | ||||
1320 | lt_settings, | ||||
1321 | dpcd_lane_status, | ||||
1322 | &dpcd_lane_status_updated, | ||||
1323 | dpcd_lane_adjust, | ||||
1324 | offset); | ||||
1325 | |||||
1326 | /* 5. check CR done*/ | ||||
1327 | if (dp_is_cr_done(lane_count, dpcd_lane_status)) | ||||
1328 | return LINK_TRAINING_SUCCESS; | ||||
1329 | |||||
1330 | /* 6. max VS reached*/ | ||||
1331 | if ((dp_get_link_encoding_format(<_settings->link_settings) == | ||||
1332 | DP_8b_10b_ENCODING) && | ||||
1333 | dp_is_max_vs_reached(lt_settings)) | ||||
1334 | break; | ||||
1335 | |||||
1336 | /* 7. same lane settings*/ | ||||
1337 | /* Note: settings are the same for all lanes, | ||||
1338 | * so comparing first lane is sufficient*/ | ||||
1339 | if ((dp_get_link_encoding_format(<_settings->link_settings) == DP_8b_10b_ENCODING) && | ||||
1340 | lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET == | ||||
1341 | dpcd_lane_adjust[0].bits.VOLTAGE_SWING_LANE) | ||||
1342 | retries_cr++; | ||||
1343 | else if ((dp_get_link_encoding_format(<_settings->link_settings) == DP_128b_132b_ENCODING) && | ||||
1344 | lt_settings->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE == | ||||
1345 | dpcd_lane_adjust[0].tx_ffe.PRESET_VALUE) | ||||
1346 | retries_cr++; | ||||
1347 | else | ||||
1348 | retries_cr = 0; | ||||
1349 | |||||
1350 | /* 8. update VS/PE/PC2 in lt_settings*/ | ||||
1351 | dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, | ||||
1352 | lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); | ||||
1353 | retry_count++; | ||||
1354 | } | ||||
1355 | |||||
1356 | if (retry_count >= LINK_TRAINING_MAX_CR_RETRY) { | ||||
1357 | ASSERT(0)do { if (({ static int __warned; int __ret = !!(!(0)); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n" , "!(0)", "/usr/src/sys/dev/pci/drm/amd/display/dc/core/dc_link_dp.c" , 1357); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | ||||
1358 | DC_LOG_ERROR("%s: Link Training Error, could not get CR after %d tries. Possibly voltage swing issue",__drm_err("%s: Link Training Error, could not get CR after %d tries. Possibly voltage swing issue" , __func__, LINK_TRAINING_MAX_CR_RETRY) | ||||
1359 | __func__,__drm_err("%s: Link Training Error, could not get CR after %d tries. Possibly voltage swing issue" , __func__, LINK_TRAINING_MAX_CR_RETRY) | ||||
1360 | LINK_TRAINING_MAX_CR_RETRY)__drm_err("%s: Link Training Error, could not get CR after %d tries. Possibly voltage swing issue" , __func__, LINK_TRAINING_MAX_CR_RETRY); | ||||
1361 | |||||
1362 | } | ||||
1363 | |||||
1364 | return dp_get_cr_failure(lane_count, dpcd_lane_status); | ||||
1365 | } | ||||
1366 | |||||
1367 | static inline enum link_training_result dp_transition_to_video_idle( | ||||
1368 | struct dc_link *link, | ||||
1369 | const struct link_resource *link_res, | ||||
1370 | struct link_training_settings *lt_settings, | ||||
1371 | enum link_training_result status) | ||||
1372 | { | ||||
1373 | union lane_count_set lane_count_set = {0}; | ||||
1374 | |||||
1375 | /* 4. mainlink output idle pattern*/ | ||||
1376 | dp_set_hw_test_pattern(link, link_res, DP_TEST_PATTERN_VIDEO_MODE, NULL((void *)0), 0); | ||||
1377 | |||||
1378 | /* | ||||
1379 | * 5. post training adjust if required | ||||
1380 | * If the upstream DPTX and downstream DPRX both support TPS4, | ||||
1381 | * TPS4 must be used instead of POST_LT_ADJ_REQ. | ||||
1382 | */ | ||||
1383 | if (link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED != 1 || | ||||
1384 | lt_settings->pattern_for_eq >= DP_TRAINING_PATTERN_SEQUENCE_4) { | ||||
1385 | /* delay 5ms after Main Link output idle pattern and then check | ||||
1386 | * DPCD 0202h. | ||||
1387 | */ | ||||
1388 | if (link->connector_signal != SIGNAL_TYPE_EDP && status == LINK_TRAINING_SUCCESS) { | ||||
1389 | drm_msleep(5)mdelay(5); | ||||
1390 | status = dp_check_link_loss_status(link, lt_settings); | ||||
1391 | } | ||||
1392 | return status; | ||||
1393 | } | ||||
1394 | |||||
1395 | if (status == LINK_TRAINING_SUCCESS && | ||||
1396 | perform_post_lt_adj_req_sequence(link, link_res, lt_settings) == false0) | ||||
1397 | status = LINK_TRAINING_LQA_FAIL; | ||||
1398 | |||||
1399 | lane_count_set.bits.LANE_COUNT_SET = lt_settings->link_settings.lane_count; | ||||
1400 | lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing; | ||||
1401 | lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0; | ||||
1402 | |||||
1403 | core_link_write_dpcd( | ||||
1404 | link, | ||||
1405 | DP_LANE_COUNT_SET0x101, | ||||
1406 | &lane_count_set.raw, | ||||
1407 | sizeof(lane_count_set)); | ||||
1408 | |||||
1409 | return status; | ||||
1410 | } | ||||
1411 | |||||
1412 | enum link_training_result dp_check_link_loss_status( | ||||
1413 | struct dc_link *link, | ||||
1414 | const struct link_training_settings *link_training_setting) | ||||
1415 | { | ||||
1416 | enum link_training_result status = LINK_TRAINING_SUCCESS; | ||||
1417 | union lane_status lane_status; | ||||
1418 | uint8_t dpcd_buf[6] = {0}; | ||||
1419 | uint32_t lane; | ||||
1420 | |||||
1421 | core_link_read_dpcd( | ||||
1422 | link, | ||||
1423 | DP_SINK_COUNT0x200, | ||||
1424 | (uint8_t *)(dpcd_buf), | ||||
1425 | sizeof(dpcd_buf)); | ||||
1426 | |||||
1427 | /*parse lane status*/ | ||||
1428 | for (lane = 0; lane < link->cur_link_settings.lane_count; lane++) { | ||||
1429 | /* | ||||
1430 | * check lanes status | ||||
1431 | */ | ||||
1432 | lane_status.raw = get_nibble_at_index(&dpcd_buf[2], lane); | ||||
1433 | |||||
1434 | if (!lane_status.bits.CHANNEL_EQ_DONE_0 || | ||||
1435 | !lane_status.bits.CR_DONE_0 || | ||||
1436 | !lane_status.bits.SYMBOL_LOCKED_0) { | ||||
1437 | /* if one of the channel equalization, clock | ||||
1438 | * recovery or symbol lock is dropped | ||||
1439 | * consider it as (link has been | ||||
1440 | * dropped) dp sink status has changed | ||||
1441 | */ | ||||
1442 | status = LINK_TRAINING_LINK_LOSS; | ||||
1443 | break; | ||||
1444 | } | ||||
1445 | } | ||||
1446 | |||||
1447 | return status; | ||||
1448 | } | ||||
1449 | |||||
1450 | static inline void decide_8b_10b_training_settings( | ||||
1451 | struct dc_link *link, | ||||
1452 | const struct dc_link_settings *link_setting, | ||||
1453 | struct link_training_settings *lt_settings) | ||||
1454 | { | ||||
1455 | memset(lt_settings, '\0', sizeof(struct link_training_settings))__builtin_memset((lt_settings), ('\0'), (sizeof(struct link_training_settings ))); | ||||
1456 | |||||
1457 | /* Initialize link settings */ | ||||
1458 | lt_settings->link_settings.use_link_rate_set = link_setting->use_link_rate_set; | ||||
1459 | lt_settings->link_settings.link_rate_set = link_setting->link_rate_set; | ||||
1460 | lt_settings->link_settings.link_rate = link_setting->link_rate; | ||||
1461 | lt_settings->link_settings.lane_count = link_setting->lane_count; | ||||
1462 | /* TODO hard coded to SS for now | ||||
1463 | * lt_settings.link_settings.link_spread = | ||||
1464 | * dal_display_path_is_ss_supported( | ||||
1465 | * path_mode->display_path) ? | ||||
1466 | * LINK_SPREAD_05_DOWNSPREAD_30KHZ : | ||||
1467 | * LINK_SPREAD_DISABLED; | ||||
1468 | */ | ||||
1469 | lt_settings->link_settings.link_spread = link->dp_ss_off ? | ||||
1470 | LINK_SPREAD_DISABLED : LINK_SPREAD_05_DOWNSPREAD_30KHZ; | ||||
1471 | lt_settings->cr_pattern_time = get_cr_training_aux_rd_interval(link, link_setting); | ||||
1472 | lt_settings->eq_pattern_time = get_eq_training_aux_rd_interval(link, link_setting); | ||||
1473 | lt_settings->pattern_for_cr = decide_cr_training_pattern(link_setting); | ||||
1474 | lt_settings->pattern_for_eq = decide_eq_training_pattern(link, link_setting); | ||||
1475 | lt_settings->enhanced_framing = 1; | ||||
1476 | lt_settings->should_set_fec_ready = true1; | ||||
1477 | lt_settings->disallow_per_lane_settings = true1; | ||||
1478 | lt_settings->always_match_dpcd_with_hw_lane_settings = true1; | ||||
1479 | lt_settings->lttpr_mode = dp_decide_8b_10b_lttpr_mode(link); | ||||
1480 | dp_hw_to_dpcd_lane_settings(lt_settings, lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); | ||||
1481 | } | ||||
1482 | |||||
1483 | static inline void decide_128b_132b_training_settings(struct dc_link *link, | ||||
1484 | const struct dc_link_settings *link_settings, | ||||
1485 | struct link_training_settings *lt_settings) | ||||
1486 | { | ||||
1487 | memset(lt_settings, 0, sizeof(*lt_settings))__builtin_memset((lt_settings), (0), (sizeof(*lt_settings))); | ||||
1488 | |||||
1489 | lt_settings->link_settings = *link_settings; | ||||
1490 | /* TODO: should decide link spread when populating link_settings */ | ||||
1491 | lt_settings->link_settings.link_spread = link->dp_ss_off ? LINK_SPREAD_DISABLED : | ||||
1492 | LINK_SPREAD_05_DOWNSPREAD_30KHZ; | ||||
1493 | |||||
1494 | lt_settings->pattern_for_cr = decide_cr_training_pattern(link_settings); | ||||
1495 | lt_settings->pattern_for_eq = decide_eq_training_pattern(link, link_settings); | ||||
1496 | lt_settings->eq_pattern_time = 2500; | ||||
1497 | lt_settings->eq_wait_time_limit = 400000; | ||||
1498 | lt_settings->eq_loop_count_limit = 20; | ||||
1499 | lt_settings->pattern_for_cds = DP_128b_132b_TPS2_CDS; | ||||
1500 | lt_settings->cds_pattern_time = 2500; | ||||
1501 | lt_settings->cds_wait_time_limit = (dp_convert_to_count( | ||||
1502 | link->dpcd_caps.lttpr_caps.phy_repeater_cnt) + 1) * 20000; | ||||
1503 | lt_settings->disallow_per_lane_settings = true1; | ||||
1504 | lt_settings->lttpr_mode = dp_decide_128b_132b_lttpr_mode(link); | ||||
1505 | dp_hw_to_dpcd_lane_settings(lt_settings, | ||||
1506 | lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); | ||||
1507 | } | ||||
1508 | |||||
1509 | void dp_decide_training_settings( | ||||
1510 | struct dc_link *link, | ||||
1511 | const struct dc_link_settings *link_settings, | ||||
1512 | struct link_training_settings *lt_settings) | ||||
1513 | { | ||||
1514 | if (dp_get_link_encoding_format(link_settings) == DP_8b_10b_ENCODING) | ||||
1515 | decide_8b_10b_training_settings(link, link_settings, lt_settings); | ||||
1516 | else if (dp_get_link_encoding_format(link_settings) == DP_128b_132b_ENCODING) | ||||
1517 | decide_128b_132b_training_settings(link, link_settings, lt_settings); | ||||
1518 | } | ||||
1519 | |||||
1520 | static void override_training_settings( | ||||
1521 | struct dc_link *link, | ||||
1522 | const struct dc_link_training_overrides *overrides, | ||||
1523 | struct link_training_settings *lt_settings) | ||||
1524 | { | ||||
1525 | uint32_t lane; | ||||
1526 | |||||
1527 | /* Override link spread */ | ||||
1528 | if (!link->dp_ss_off && overrides->downspread != NULL((void *)0)) | ||||
1529 | lt_settings->link_settings.link_spread = *overrides->downspread ? | ||||
1530 | LINK_SPREAD_05_DOWNSPREAD_30KHZ | ||||
1531 | : LINK_SPREAD_DISABLED; | ||||
1532 | |||||
1533 | /* Override lane settings */ | ||||
1534 | if (overrides->voltage_swing != NULL((void *)0)) | ||||
1535 | lt_settings->voltage_swing = overrides->voltage_swing; | ||||
1536 | if (overrides->pre_emphasis != NULL((void *)0)) | ||||
1537 | lt_settings->pre_emphasis = overrides->pre_emphasis; | ||||
1538 | if (overrides->post_cursor2 != NULL((void *)0)) | ||||
1539 | lt_settings->post_cursor2 = overrides->post_cursor2; | ||||
1540 | if (overrides->ffe_preset != NULL((void *)0)) | ||||
1541 | lt_settings->ffe_preset = overrides->ffe_preset; | ||||
1542 | /* Override HW lane settings with BIOS forced values if present */ | ||||
1543 | if (link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN && | ||||
1544 | lt_settings->lttpr_mode == LTTPR_MODE_TRANSPARENT) { | ||||
1545 | lt_settings->voltage_swing = &link->bios_forced_drive_settings.VOLTAGE_SWING; | ||||
1546 | lt_settings->pre_emphasis = &link->bios_forced_drive_settings.PRE_EMPHASIS; | ||||
1547 | lt_settings->always_match_dpcd_with_hw_lane_settings = false0; | ||||
1548 | } | ||||
1549 | for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) { | ||||
1550 | lt_settings->hw_lane_settings[lane].VOLTAGE_SWING = | ||||
1551 | lt_settings->voltage_swing != NULL((void *)0) ? | ||||
1552 | *lt_settings->voltage_swing : | ||||
1553 | VOLTAGE_SWING_LEVEL0; | ||||
1554 | lt_settings->hw_lane_settings[lane].PRE_EMPHASIS = | ||||
1555 | lt_settings->pre_emphasis != NULL((void *)0) ? | ||||
1556 | *lt_settings->pre_emphasis | ||||
1557 | : PRE_EMPHASIS_DISABLED; | ||||
1558 | lt_settings->hw_lane_settings[lane].POST_CURSOR2 = | ||||
1559 | lt_settings->post_cursor2 != NULL((void *)0) ? | ||||
1560 | *lt_settings->post_cursor2 | ||||
1561 | : POST_CURSOR2_DISABLED; | ||||
1562 | } | ||||
1563 | |||||
1564 | if (lt_settings->always_match_dpcd_with_hw_lane_settings) | ||||
1565 | dp_hw_to_dpcd_lane_settings(lt_settings, | ||||
1566 | lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); | ||||
1567 | |||||
1568 | /* Initialize training timings */ | ||||
1569 | if (overrides->cr_pattern_time != NULL((void *)0)) | ||||
1570 | lt_settings->cr_pattern_time = *overrides->cr_pattern_time; | ||||
1571 | |||||
1572 | if (overrides->eq_pattern_time != NULL((void *)0)) | ||||
1573 | lt_settings->eq_pattern_time = *overrides->eq_pattern_time; | ||||
1574 | |||||
1575 | if (overrides->pattern_for_cr != NULL((void *)0)) | ||||
1576 | lt_settings->pattern_for_cr = *overrides->pattern_for_cr; | ||||
1577 | if (overrides->pattern_for_eq != NULL((void *)0)) | ||||
1578 | lt_settings->pattern_for_eq = *overrides->pattern_for_eq; | ||||
1579 | |||||
1580 | if (overrides->enhanced_framing != NULL((void *)0)) | ||||
1581 | lt_settings->enhanced_framing = *overrides->enhanced_framing; | ||||
1582 | |||||
1583 | if (link->preferred_training_settings.fec_enable != NULL((void *)0)) | ||||
1584 | lt_settings->should_set_fec_ready = *link->preferred_training_settings.fec_enable; | ||||
1585 | |||||
1586 | #if defined(CONFIG_DRM_AMD_DC_DCN1) | ||||
1587 | /* Check DP tunnel LTTPR mode debug option. */ | ||||
1588 | if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA && link->dc->debug.dpia_debug.bits.force_non_lttpr) | ||||
1589 | lt_settings->lttpr_mode = LTTPR_MODE_NON_LTTPR; | ||||
1590 | |||||
1591 | #endif | ||||
1592 | dp_get_lttpr_mode_override(link, <_settings->lttpr_mode); | ||||
1593 | |||||
1594 | } | ||||
1595 | |||||
1596 | uint8_t dp_convert_to_count(uint8_t lttpr_repeater_count) | ||||
1597 | { | ||||
1598 | switch (lttpr_repeater_count) { | ||||
1599 | case 0x80: // 1 lttpr repeater | ||||
1600 | return 1; | ||||
1601 | case 0x40: // 2 lttpr repeaters | ||||
1602 | return 2; | ||||
1603 | case 0x20: // 3 lttpr repeaters | ||||
1604 | return 3; | ||||
1605 | case 0x10: // 4 lttpr repeaters | ||||
1606 | return 4; | ||||
1607 | case 0x08: // 5 lttpr repeaters | ||||
1608 | return 5; | ||||
1609 | case 0x04: // 6 lttpr repeaters | ||||
1610 | return 6; | ||||
1611 | case 0x02: // 7 lttpr repeaters | ||||
1612 | return 7; | ||||
1613 | case 0x01: // 8 lttpr repeaters | ||||
1614 | return 8; | ||||
1615 | default: | ||||
1616 | break; | ||||
1617 | } | ||||
1618 | return 0; // invalid value | ||||
1619 | } | ||||
1620 | |||||
1621 | static enum dc_status configure_lttpr_mode_transparent(struct dc_link *link) | ||||
1622 | { | ||||
1623 | uint8_t repeater_mode = DP_PHY_REPEATER_MODE_TRANSPARENT0x55; | ||||
1624 | |||||
1625 | DC_LOG_HW_LINK_TRAINING("%s\n Set LTTPR to Transparent Mode\n", __func__)do { } while(0); | ||||
1626 | return core_link_write_dpcd(link, | ||||
1627 | DP_PHY_REPEATER_MODE0xf0003, | ||||
1628 | (uint8_t *)&repeater_mode, | ||||
1629 | sizeof(repeater_mode)); | ||||
1630 | } | ||||
1631 | |||||
1632 | static enum dc_status configure_lttpr_mode_non_transparent( | ||||
1633 | struct dc_link *link, | ||||
1634 | const struct link_training_settings *lt_settings) | ||||
1635 | { | ||||
1636 | /* aux timeout is already set to extended */ | ||||
1637 | /* RESET/SET lttpr mode to enable non transparent mode */ | ||||
1638 | uint8_t repeater_cnt; | ||||
1639 | uint32_t aux_interval_address; | ||||
1640 | uint8_t repeater_id; | ||||
1641 | enum dc_status result = DC_ERROR_UNEXPECTED; | ||||
1642 | uint8_t repeater_mode = DP_PHY_REPEATER_MODE_TRANSPARENT0x55; | ||||
1643 | |||||
1644 | enum dp_link_encoding encoding = dp_get_link_encoding_format(<_settings->link_settings); | ||||
1645 | |||||
1646 | if (encoding == DP_8b_10b_ENCODING) { | ||||
1647 | DC_LOG_HW_LINK_TRAINING("%s\n Set LTTPR to Transparent Mode\n", __func__)do { } while(0); | ||||
1648 | result = core_link_write_dpcd(link, | ||||
1649 | DP_PHY_REPEATER_MODE0xf0003, | ||||
1650 | (uint8_t *)&repeater_mode, | ||||
1651 | sizeof(repeater_mode)); | ||||
1652 | |||||
1653 | } | ||||
1654 | |||||
1655 | if (result == DC_OK) { | ||||
1656 | link->dpcd_caps.lttpr_caps.mode = repeater_mode; | ||||
1657 | } | ||||
1658 | |||||
1659 | if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) { | ||||
1660 | |||||
1661 | DC_LOG_HW_LINK_TRAINING("%s\n Set LTTPR to Non Transparent Mode\n", __func__)do { } while(0); | ||||
1662 | |||||
1663 | repeater_mode = DP_PHY_REPEATER_MODE_NON_TRANSPARENT0xaa; | ||||
1664 | result = core_link_write_dpcd(link, | ||||
1665 | DP_PHY_REPEATER_MODE0xf0003, | ||||
1666 | (uint8_t *)&repeater_mode, | ||||
1667 | sizeof(repeater_mode)); | ||||
1668 | |||||
1669 | if (result == DC_OK) { | ||||
1670 | link->dpcd_caps.lttpr_caps.mode = repeater_mode; | ||||
1671 | } | ||||
1672 | |||||
1673 | if (encoding == DP_8b_10b_ENCODING) { | ||||
1674 | repeater_cnt = dp_convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt); | ||||
1675 | |||||
1676 | /* Driver does not need to train the first hop. Skip DPCD read and clear | ||||
1677 | * AUX_RD_INTERVAL for DPTX-to-DPIA hop. | ||||
1678 | */ | ||||
1679 | if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) | ||||
1680 | link->dpcd_caps.lttpr_caps.aux_rd_interval[--repeater_cnt] = 0; | ||||
1681 | |||||
1682 | for (repeater_id = repeater_cnt; repeater_id > 0; repeater_id--) { | ||||
1683 | aux_interval_address = DP_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER10xf0020 + | ||||
1684 | ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE0x50) * (repeater_id - 1)); | ||||
1685 | core_link_read_dpcd( | ||||
1686 | link, | ||||
1687 | aux_interval_address, | ||||
1688 | (uint8_t *)&link->dpcd_caps.lttpr_caps.aux_rd_interval[repeater_id - 1], | ||||
1689 | sizeof(link->dpcd_caps.lttpr_caps.aux_rd_interval[repeater_id - 1])); | ||||
1690 | link->dpcd_caps.lttpr_caps.aux_rd_interval[repeater_id - 1] &= 0x7F; | ||||
1691 | } | ||||
1692 | } | ||||
1693 | } | ||||
1694 | |||||
1695 | return result; | ||||
1696 | } | ||||
1697 | |||||
1698 | static void repeater_training_done(struct dc_link *link, uint32_t offset) | ||||
1699 | { | ||||
1700 | union dpcd_training_pattern dpcd_pattern = {0}; | ||||
1701 | |||||
1702 | const uint32_t dpcd_base_lt_offset = | ||||
1703 | DP_TRAINING_PATTERN_SET_PHY_REPEATER10xf0010 + | ||||
1704 | ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE0x50) * (offset - 1)); | ||||
1705 | /* Set training not in progress*/ | ||||
1706 | dpcd_pattern.v1_4.TRAINING_PATTERN_SET = DPCD_TRAINING_PATTERN_VIDEOIDLE; | ||||
1707 | |||||
1708 | core_link_write_dpcd( | ||||
1709 | link, | ||||
1710 | dpcd_base_lt_offset, | ||||
1711 | &dpcd_pattern.raw, | ||||
1712 | 1); | ||||
1713 | |||||
1714 | DC_LOG_HW_LINK_TRAINING("%s\n LTTPR Id: %d 0x%X pattern = %x\n",do { } while(0) | ||||
1715 | __func__,do { } while(0) | ||||
1716 | offset,do { } while(0) | ||||
1717 | dpcd_base_lt_offset,do { } while(0) | ||||
1718 | dpcd_pattern.v1_4.TRAINING_PATTERN_SET)do { } while(0); | ||||
1719 | } | ||||
1720 | |||||
1721 | static void print_status_message( | ||||
1722 | struct dc_link *link, | ||||
1723 | const struct link_training_settings *lt_settings, | ||||
1724 | enum link_training_result status) | ||||
1725 | { | ||||
1726 | char *link_rate = "Unknown"; | ||||
1727 | char *lt_result = "Unknown"; | ||||
1728 | char *lt_spread = "Disabled"; | ||||
1729 | |||||
1730 | switch (lt_settings->link_settings.link_rate) { | ||||
1731 | case LINK_RATE_LOW: | ||||
1732 | link_rate = "RBR"; | ||||
1733 | break; | ||||
1734 | case LINK_RATE_RATE_2: | ||||
1735 | link_rate = "R2"; | ||||
1736 | break; | ||||
1737 | case LINK_RATE_RATE_3: | ||||
1738 | link_rate = "R3"; | ||||
1739 | break; | ||||
1740 | case LINK_RATE_HIGH: | ||||
1741 | link_rate = "HBR"; | ||||
1742 | break; | ||||
1743 | case LINK_RATE_RBR2: | ||||
1744 | link_rate = "RBR2"; | ||||
1745 | break; | ||||
1746 | case LINK_RATE_RATE_6: | ||||
1747 | link_rate = "R6"; | ||||
1748 | break; | ||||
1749 | case LINK_RATE_HIGH2: | ||||
1750 | link_rate = "HBR2"; | ||||
1751 | break; | ||||
1752 | case LINK_RATE_HIGH3: | ||||
1753 | link_rate = "HBR3"; | ||||
1754 | break; | ||||
1755 | case LINK_RATE_UHBR10: | ||||
1756 | link_rate = "UHBR10"; | ||||
1757 | break; | ||||
1758 | case LINK_RATE_UHBR13_5: | ||||
1759 | link_rate = "UHBR13.5"; | ||||
1760 | break; | ||||
1761 | case LINK_RATE_UHBR20: | ||||
1762 | link_rate = "UHBR20"; | ||||
1763 | break; | ||||
1764 | default: | ||||
1765 | break; | ||||
1766 | } | ||||
1767 | |||||
1768 | switch (status) { | ||||
1769 | case LINK_TRAINING_SUCCESS: | ||||
1770 | lt_result = "pass"; | ||||
1771 | break; | ||||
1772 | case LINK_TRAINING_CR_FAIL_LANE0: | ||||
1773 | lt_result = "CR failed lane0"; | ||||
1774 | break; | ||||
1775 | case LINK_TRAINING_CR_FAIL_LANE1: | ||||
1776 | lt_result = "CR failed lane1"; | ||||
1777 | break; | ||||
1778 | case LINK_TRAINING_CR_FAIL_LANE23: | ||||
1779 | lt_result = "CR failed lane23"; | ||||
1780 | break; | ||||
1781 | case LINK_TRAINING_EQ_FAIL_CR: | ||||
1782 | lt_result = "CR failed in EQ"; | ||||
1783 | break; | ||||
1784 | case LINK_TRAINING_EQ_FAIL_CR_PARTIAL: | ||||
1785 | lt_result = "CR failed in EQ partially"; | ||||
1786 | break; | ||||
1787 | case LINK_TRAINING_EQ_FAIL_EQ: | ||||
1788 | lt_result = "EQ failed"; | ||||
1789 | break; | ||||
1790 | case LINK_TRAINING_LQA_FAIL: | ||||
1791 | lt_result = "LQA failed"; | ||||
1792 | break; | ||||
1793 | case LINK_TRAINING_LINK_LOSS: | ||||
1794 | lt_result = "Link loss"; | ||||
1795 | break; | ||||
1796 | case DP_128b_132b_LT_FAILED: | ||||
1797 | lt_result = "LT_FAILED received"; | ||||
1798 | break; | ||||
1799 | case DP_128b_132b_MAX_LOOP_COUNT_REACHED: | ||||
1800 | lt_result = "max loop count reached"; | ||||
1801 | break; | ||||
1802 | case DP_128b_132b_CHANNEL_EQ_DONE_TIMEOUT: | ||||
1803 | lt_result = "channel EQ timeout"; | ||||
1804 | break; | ||||
1805 | case DP_128b_132b_CDS_DONE_TIMEOUT: | ||||
1806 | lt_result = "CDS timeout"; | ||||
1807 | break; | ||||
1808 | default: | ||||
1809 | break; | ||||
1810 | } | ||||
1811 | |||||
1812 | switch (lt_settings->link_settings.link_spread) { | ||||
1813 | case LINK_SPREAD_DISABLED: | ||||
1814 | lt_spread = "Disabled"; | ||||
1815 | break; | ||||
1816 | case LINK_SPREAD_05_DOWNSPREAD_30KHZ: | ||||
1817 | lt_spread = "0.5% 30KHz"; | ||||
1818 | break; | ||||
1819 | case LINK_SPREAD_05_DOWNSPREAD_33KHZ: | ||||
1820 | lt_spread = "0.5% 33KHz"; | ||||
1821 | break; | ||||
1822 | default: | ||||
1823 | break; | ||||
1824 | } | ||||
1825 | |||||
1826 | /* Connectivity log: link training */ | ||||
1827 | |||||
1828 | /* TODO - DP2.0 Log: add connectivity log for FFE PRESET */ | ||||
1829 | |||||
1830 | CONN_MSG_LT(link, "%sx%d %s VS=%d, PE=%d, DS=%s",do { (void)(link); ___drm_dbg(((void *)0), DRM_UT_KMS, "%sx%d %s VS=%d, PE=%d, DS=%s" , link_rate, lt_settings->link_settings.lane_count, lt_result , lt_settings->hw_lane_settings[0].VOLTAGE_SWING, lt_settings ->hw_lane_settings[0].PRE_EMPHASIS, lt_spread); } while (0 ) | ||||
1831 | link_rate,do { (void)(link); ___drm_dbg(((void *)0), DRM_UT_KMS, "%sx%d %s VS=%d, PE=%d, DS=%s" , link_rate, lt_settings->link_settings.lane_count, lt_result , lt_settings->hw_lane_settings[0].VOLTAGE_SWING, lt_settings ->hw_lane_settings[0].PRE_EMPHASIS, lt_spread); } while (0 ) | ||||
1832 | lt_settings->link_settings.lane_count,do { (void)(link); ___drm_dbg(((void *)0), DRM_UT_KMS, "%sx%d %s VS=%d, PE=%d, DS=%s" , link_rate, lt_settings->link_settings.lane_count, lt_result , lt_settings->hw_lane_settings[0].VOLTAGE_SWING, lt_settings ->hw_lane_settings[0].PRE_EMPHASIS, lt_spread); } while (0 ) | ||||
1833 | lt_result,do { (void)(link); ___drm_dbg(((void *)0), DRM_UT_KMS, "%sx%d %s VS=%d, PE=%d, DS=%s" , link_rate, lt_settings->link_settings.lane_count, lt_result , lt_settings->hw_lane_settings[0].VOLTAGE_SWING, lt_settings ->hw_lane_settings[0].PRE_EMPHASIS, lt_spread); } while (0 ) | ||||
1834 | lt_settings->hw_lane_settings[0].VOLTAGE_SWING,do { (void)(link); ___drm_dbg(((void *)0), DRM_UT_KMS, "%sx%d %s VS=%d, PE=%d, DS=%s" , link_rate, lt_settings->link_settings.lane_count, lt_result , lt_settings->hw_lane_settings[0].VOLTAGE_SWING, lt_settings ->hw_lane_settings[0].PRE_EMPHASIS, lt_spread); } while (0 ) | ||||
1835 | lt_settings->hw_lane_settings[0].PRE_EMPHASIS,do { (void)(link); ___drm_dbg(((void *)0), DRM_UT_KMS, "%sx%d %s VS=%d, PE=%d, DS=%s" , link_rate, lt_settings->link_settings.lane_count, lt_result , lt_settings->hw_lane_settings[0].VOLTAGE_SWING, lt_settings ->hw_lane_settings[0].PRE_EMPHASIS, lt_spread); } while (0 ) | ||||
1836 | lt_spread)do { (void)(link); ___drm_dbg(((void *)0), DRM_UT_KMS, "%sx%d %s VS=%d, PE=%d, DS=%s" , link_rate, lt_settings->link_settings.lane_count, lt_result , lt_settings->hw_lane_settings[0].VOLTAGE_SWING, lt_settings ->hw_lane_settings[0].PRE_EMPHASIS, lt_spread); } while (0 ); | ||||
1837 | } | ||||
1838 | |||||
1839 | void dc_link_dp_set_drive_settings( | ||||
1840 | struct dc_link *link, | ||||
1841 | const struct link_resource *link_res, | ||||
1842 | struct link_training_settings *lt_settings) | ||||
1843 | { | ||||
1844 | /* program ASIC PHY settings*/ | ||||
1845 | dp_set_hw_lane_settings(link, link_res, lt_settings, DPRX); | ||||
1846 | |||||
1847 | dp_hw_to_dpcd_lane_settings(lt_settings, | ||||
1848 | lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); | ||||
1849 | |||||
1850 | /* Notify DP sink the PHY settings from source */ | ||||
1851 | dpcd_set_lane_settings(link, lt_settings, DPRX); | ||||
1852 | } | ||||
1853 | |||||
1854 | bool_Bool dc_link_dp_perform_link_training_skip_aux( | ||||
1855 | struct dc_link *link, | ||||
1856 | const struct link_resource *link_res, | ||||
1857 | const struct dc_link_settings *link_setting) | ||||
1858 | { | ||||
1859 | struct link_training_settings lt_settings = {0}; | ||||
1860 | |||||
1861 | dp_decide_training_settings( | ||||
1862 | link, | ||||
1863 | link_setting, | ||||
1864 | <_settings); | ||||
1865 | override_training_settings( | ||||
1866 | link, | ||||
1867 | &link->preferred_training_settings, | ||||
1868 | <_settings); | ||||
1869 | |||||
1870 | /* 1. Perform_clock_recovery_sequence. */ | ||||
1871 | |||||
1872 | /* transmit training pattern for clock recovery */ | ||||
1873 | dp_set_hw_training_pattern(link, link_res, lt_settings.pattern_for_cr, DPRX); | ||||
1874 | |||||
1875 | /* call HWSS to set lane settings*/ | ||||
1876 | dp_set_hw_lane_settings(link, link_res, <_settings, DPRX); | ||||
1877 | |||||
1878 | /* wait receiver to lock-on*/ | ||||
1879 | dp_wait_for_training_aux_rd_interval(link, lt_settings.cr_pattern_time); | ||||
1880 | |||||
1881 | /* 2. Perform_channel_equalization_sequence. */ | ||||
1882 | |||||
1883 | /* transmit training pattern for channel equalization. */ | ||||
1884 | dp_set_hw_training_pattern(link, link_res, lt_settings.pattern_for_eq, DPRX); | ||||
1885 | |||||
1886 | /* call HWSS to set lane settings*/ | ||||
1887 | dp_set_hw_lane_settings(link, link_res, <_settings, DPRX); | ||||
1888 | |||||
1889 | /* wait receiver to lock-on. */ | ||||
1890 | dp_wait_for_training_aux_rd_interval(link, lt_settings.eq_pattern_time); | ||||
1891 | |||||
1892 | /* 3. Perform_link_training_int. */ | ||||
1893 | |||||
1894 | /* Mainlink output idle pattern. */ | ||||
1895 | dp_set_hw_test_pattern(link, link_res, DP_TEST_PATTERN_VIDEO_MODE, NULL((void *)0), 0); | ||||
1896 | |||||
1897 | print_status_message(link, <_settings, LINK_TRAINING_SUCCESS); | ||||
1898 | |||||
1899 | return true1; | ||||
1900 | } | ||||
1901 | |||||
1902 | enum dc_status dpcd_configure_lttpr_mode(struct dc_link *link, struct link_training_settings *lt_settings) | ||||
1903 | { | ||||
1904 | enum dc_status status = DC_OK; | ||||
1905 | |||||
1906 | if (lt_settings->lttpr_mode == LTTPR_MODE_TRANSPARENT) | ||||
1907 | status = configure_lttpr_mode_transparent(link); | ||||
1908 | |||||
1909 | else if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) | ||||
1910 | status = configure_lttpr_mode_non_transparent(link, lt_settings); | ||||
1911 | |||||
1912 | return status; | ||||
1913 | } | ||||
1914 | |||||
1915 | static void dpcd_exit_training_mode(struct dc_link *link) | ||||
1916 | { | ||||
1917 | uint8_t sink_status = 0; | ||||
1918 | uint8_t i; | ||||
1919 | |||||
1920 | /* clear training pattern set */ | ||||
1921 | dpcd_set_training_pattern(link, DP_TRAINING_PATTERN_VIDEOIDLE); | ||||
1922 | |||||
1923 | /* poll for intra-hop disable */ | ||||
1924 | for (i = 0; i < 10; i++) { | ||||
1925 | if ((core_link_read_dpcd(link, DP_SINK_STATUS0x205, &sink_status, 1) == DC_OK) && | ||||
1926 | (sink_status & DP_INTRA_HOP_AUX_REPLY_INDICATION(1 << 3)) == 0) | ||||
1927 | break; | ||||
1928 | udelay(1000); | ||||
1929 | } | ||||
1930 | } | ||||
1931 | |||||
1932 | enum dc_status dpcd_configure_channel_coding(struct dc_link *link, | ||||
1933 | struct link_training_settings *lt_settings) | ||||
1934 | { | ||||
1935 | enum dp_link_encoding encoding = | ||||
1936 | dp_get_link_encoding_format( | ||||
1937 | <_settings->link_settings); | ||||
1938 | enum dc_status status; | ||||
1939 | |||||
1940 | status = core_link_write_dpcd( | ||||
1941 | link, | ||||
1942 | DP_MAIN_LINK_CHANNEL_CODING_SET0x108, | ||||
1943 | (uint8_t *) &encoding, | ||||
1944 | 1); | ||||
1945 | DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X MAIN_LINK_CHANNEL_CODING_SET = %x\n",do { } while(0) | ||||
1946 | __func__,do { } while(0) | ||||
1947 | DP_MAIN_LINK_CHANNEL_CODING_SET,do { } while(0) | ||||
1948 | encoding)do { } while(0); | ||||
1949 | |||||
1950 | return status; | ||||
1951 | } | ||||
1952 | |||||
1953 | static void dpcd_128b_132b_get_aux_rd_interval(struct dc_link *link, | ||||
1954 | uint32_t *interval_in_us) | ||||
1955 | { | ||||
1956 | union dp_128b_132b_training_aux_rd_interval dpcd_interval; | ||||
1957 | uint32_t interval_unit = 0; | ||||
1958 | |||||
1959 | dpcd_interval.raw = 0; | ||||
1960 | core_link_read_dpcd(link, DP_128b_132b_TRAINING_AUX_RD_INTERVAL0x2216, | ||||
1961 | &dpcd_interval.raw, sizeof(dpcd_interval.raw)); | ||||
1962 | interval_unit = dpcd_interval.bits.UNIT ? 1 : 2; /* 0b = 2 ms, 1b = 1 ms */ | ||||
1963 | /* (128b/132b_TRAINING_AUX_RD_INTERVAL value + 1) * | ||||
1964 | * INTERVAL_UNIT. The maximum is 256 ms | ||||
1965 | */ | ||||
1966 | *interval_in_us = (dpcd_interval.bits.VALUE + 1) * interval_unit * 1000; | ||||
1967 | } | ||||
1968 | |||||
1969 | static enum link_training_result dp_perform_128b_132b_channel_eq_done_sequence( | ||||
1970 | struct dc_link *link, | ||||
1971 | const struct link_resource *link_res, | ||||
1972 | struct link_training_settings *lt_settings) | ||||
1973 | { | ||||
1974 | uint8_t loop_count; | ||||
1975 | uint32_t aux_rd_interval = 0; | ||||
1976 | uint32_t wait_time = 0; | ||||
1977 | union lane_align_status_updated dpcd_lane_status_updated = {0}; | ||||
1978 | union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0}; | ||||
1979 | enum dc_status status = DC_OK; | ||||
1980 | enum link_training_result result = LINK_TRAINING_SUCCESS; | ||||
1981 | union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0}; | ||||
1982 | |||||
1983 | /* Transmit 128b/132b_TPS1 over Main-Link */ | ||||
1984 | dp_set_hw_training_pattern(link, link_res, lt_settings->pattern_for_cr, DPRX); | ||||
1985 | /* Set TRAINING_PATTERN_SET to 01h */ | ||||
1986 | dpcd_set_training_pattern(link, lt_settings->pattern_for_cr); | ||||
1987 | |||||
1988 | /* Adjust TX_FFE_PRESET_VALUE and Transmit 128b/132b_TPS2 over Main-Link */ | ||||
1989 | dpcd_128b_132b_get_aux_rd_interval(link, &aux_rd_interval); | ||||
1990 | dp_get_lane_status_and_lane_adjust(link, lt_settings, dpcd_lane_status, | ||||
1991 | &dpcd_lane_status_updated, dpcd_lane_adjust, DPRX); | ||||
1992 | dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, | ||||
1993 | lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); | ||||
1994 | dp_set_hw_lane_settings(link, link_res, lt_settings, DPRX); | ||||
1995 | dp_set_hw_training_pattern(link, link_res, lt_settings->pattern_for_eq, DPRX); | ||||
1996 | |||||
1997 | /* Set loop counter to start from 1 */ | ||||
1998 | loop_count = 1; | ||||
1999 | |||||
2000 | /* Set TRAINING_PATTERN_SET to 02h and TX_FFE_PRESET_VALUE in one AUX transaction */ | ||||
2001 | dpcd_set_lt_pattern_and_lane_settings(link, lt_settings, | ||||
2002 | lt_settings->pattern_for_eq, DPRX); | ||||
2003 | |||||
2004 | /* poll for channel EQ done */ | ||||
2005 | while (result == LINK_TRAINING_SUCCESS) { | ||||
2006 | dp_wait_for_training_aux_rd_interval(link, aux_rd_interval); | ||||
2007 | wait_time += aux_rd_interval; | ||||
2008 | status = dp_get_lane_status_and_lane_adjust(link, lt_settings, dpcd_lane_status, | ||||
2009 | &dpcd_lane_status_updated, dpcd_lane_adjust, DPRX); | ||||
2010 | dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, | ||||
2011 | lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); | ||||
2012 | dpcd_128b_132b_get_aux_rd_interval(link, &aux_rd_interval); | ||||
2013 | if (status != DC_OK) { | ||||
2014 | result = LINK_TRAINING_ABORT; | ||||
2015 | } else if (dp_is_ch_eq_done(lt_settings->link_settings.lane_count, | ||||
2016 | dpcd_lane_status)) { | ||||
2017 | /* pass */ | ||||
2018 | break; | ||||
2019 | } else if (loop_count >= lt_settings->eq_loop_count_limit) { | ||||
2020 | result = DP_128b_132b_MAX_LOOP_COUNT_REACHED; | ||||
2021 | } else if (dpcd_lane_status_updated.bits.LT_FAILED_128b_132b) { | ||||
2022 | result = DP_128b_132b_LT_FAILED; | ||||
2023 | } else { | ||||
2024 | dp_set_hw_lane_settings(link, link_res, lt_settings, DPRX); | ||||
2025 | dpcd_128b_132b_set_lane_settings(link, lt_settings); | ||||
2026 | } | ||||
2027 | loop_count++; | ||||
2028 | } | ||||
2029 | |||||
2030 | /* poll for EQ interlane align done */ | ||||
2031 | while (result == LINK_TRAINING_SUCCESS) { | ||||
2032 | if (status != DC_OK) { | ||||
2033 | result = LINK_TRAINING_ABORT; | ||||
2034 | } else if (dpcd_lane_status_updated.bits.EQ_INTERLANE_ALIGN_DONE_128b_132b) { | ||||
2035 | /* pass */ | ||||
2036 | break; | ||||
2037 | } else if (wait_time >= lt_settings->eq_wait_time_limit) { | ||||
2038 | result = DP_128b_132b_CHANNEL_EQ_DONE_TIMEOUT; | ||||
2039 | } else if (dpcd_lane_status_updated.bits.LT_FAILED_128b_132b) { | ||||
2040 | result = DP_128b_132b_LT_FAILED; | ||||
2041 | } else { | ||||
2042 | dp_wait_for_training_aux_rd_interval(link, | ||||
2043 | lt_settings->eq_pattern_time); | ||||
2044 | wait_time += lt_settings->eq_pattern_time; | ||||
2045 | status = dp_get_lane_status_and_lane_adjust(link, lt_settings, dpcd_lane_status, | ||||
2046 | &dpcd_lane_status_updated, dpcd_lane_adjust, DPRX); | ||||
2047 | } | ||||
2048 | } | ||||
2049 | |||||
2050 | return result; | ||||
2051 | } | ||||
2052 | |||||
2053 | static enum link_training_result dp_perform_128b_132b_cds_done_sequence( | ||||
2054 | struct dc_link *link, | ||||
2055 | const struct link_resource *link_res, | ||||
2056 | struct link_training_settings *lt_settings) | ||||
2057 | { | ||||
2058 | /* Assumption: assume hardware has transmitted eq pattern */ | ||||
2059 | enum dc_status status = DC_OK; | ||||
2060 | enum link_training_result result = LINK_TRAINING_SUCCESS; | ||||
2061 | union lane_align_status_updated dpcd_lane_status_updated = {0}; | ||||
2062 | union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0}; | ||||
2063 | union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0}; | ||||
2064 | uint32_t wait_time = 0; | ||||
2065 | |||||
2066 | /* initiate CDS done sequence */ | ||||
2067 | dpcd_set_training_pattern(link, lt_settings->pattern_for_cds); | ||||
2068 | |||||
2069 | /* poll for CDS interlane align done and symbol lock */ | ||||
2070 | while (result == LINK_TRAINING_SUCCESS) { | ||||
2071 | dp_wait_for_training_aux_rd_interval(link, | ||||
2072 | lt_settings->cds_pattern_time); | ||||
2073 | wait_time += lt_settings->cds_pattern_time; | ||||
2074 | status = dp_get_lane_status_and_lane_adjust(link, lt_settings, dpcd_lane_status, | ||||
2075 | &dpcd_lane_status_updated, dpcd_lane_adjust, DPRX); | ||||
2076 | if (status != DC_OK) { | ||||
2077 | result = LINK_TRAINING_ABORT; | ||||
2078 | } else if (dp_is_symbol_locked(lt_settings->link_settings.lane_count, dpcd_lane_status) && | ||||
2079 | dpcd_lane_status_updated.bits.CDS_INTERLANE_ALIGN_DONE_128b_132b) { | ||||
2080 | /* pass */ | ||||
2081 | break; | ||||
2082 | } else if (dpcd_lane_status_updated.bits.LT_FAILED_128b_132b) { | ||||
2083 | result = DP_128b_132b_LT_FAILED; | ||||
2084 | } else if (wait_time >= lt_settings->cds_wait_time_limit) { | ||||
2085 | result = DP_128b_132b_CDS_DONE_TIMEOUT; | ||||
2086 | } | ||||
2087 | } | ||||
2088 | |||||
2089 | return result; | ||||
2090 | } | ||||
2091 | |||||
2092 | static enum link_training_result dp_perform_8b_10b_link_training( | ||||
2093 | struct dc_link *link, | ||||
2094 | const struct link_resource *link_res, | ||||
2095 | struct link_training_settings *lt_settings) | ||||
2096 | { | ||||
2097 | enum link_training_result status = LINK_TRAINING_SUCCESS; | ||||
2098 | |||||
2099 | uint8_t repeater_cnt; | ||||
2100 | uint8_t repeater_id; | ||||
2101 | uint8_t lane = 0; | ||||
2102 | |||||
2103 | if (link->ctx->dc->work_arounds.lt_early_cr_pattern) | ||||
2104 | start_clock_recovery_pattern_early(link, link_res, lt_settings, DPRX); | ||||
2105 | |||||
2106 | /* 1. set link rate, lane count and spread. */ | ||||
2107 | dpcd_set_link_settings(link, lt_settings); | ||||
2108 | |||||
2109 | if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) { | ||||
2110 | |||||
2111 | /* 2. perform link training (set link training done | ||||
2112 | * to false is done as well) | ||||
2113 | */ | ||||
2114 | repeater_cnt = dp_convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt); | ||||
2115 | |||||
2116 | for (repeater_id = repeater_cnt; (repeater_id > 0 && status == LINK_TRAINING_SUCCESS); | ||||
2117 | repeater_id--) { | ||||
2118 | status = perform_clock_recovery_sequence(link, link_res, lt_settings, repeater_id); | ||||
2119 | |||||
2120 | if (status != LINK_TRAINING_SUCCESS) { | ||||
2121 | repeater_training_done(link, repeater_id); | ||||
2122 | break; | ||||
2123 | } | ||||
2124 | |||||
2125 | status = perform_channel_equalization_sequence(link, | ||||
2126 | link_res, | ||||
2127 | lt_settings, | ||||
2128 | repeater_id); | ||||
2129 | |||||
2130 | repeater_training_done(link, repeater_id); | ||||
2131 | |||||
2132 | if (status != LINK_TRAINING_SUCCESS) | ||||
2133 | break; | ||||
2134 | |||||
2135 | for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) { | ||||
2136 | lt_settings->dpcd_lane_settings[lane].raw = 0; | ||||
2137 | lt_settings->hw_lane_settings[lane].VOLTAGE_SWING = 0; | ||||
2138 | lt_settings->hw_lane_settings[lane].PRE_EMPHASIS = 0; | ||||
2139 | } | ||||
2140 | } | ||||
2141 | } | ||||
2142 | |||||
2143 | if (status == LINK_TRAINING_SUCCESS) { | ||||
2144 | status = perform_clock_recovery_sequence(link, link_res, lt_settings, DPRX); | ||||
2145 | if (status == LINK_TRAINING_SUCCESS) { | ||||
2146 | status = perform_channel_equalization_sequence(link, | ||||
2147 | link_res, | ||||
2148 | lt_settings, | ||||
2149 | DPRX); | ||||
2150 | } | ||||
2151 | } | ||||
2152 | |||||
2153 | return status; | ||||
2154 | } | ||||
2155 | |||||
2156 | static enum link_training_result dp_perform_128b_132b_link_training( | ||||
2157 | struct dc_link *link, | ||||
2158 | const struct link_resource *link_res, | ||||
2159 | struct link_training_settings *lt_settings) | ||||
2160 | { | ||||
2161 | enum link_training_result result = LINK_TRAINING_SUCCESS; | ||||
2162 | |||||
2163 | /* TODO - DP2.0 Link: remove legacy_dp2_lt logic */ | ||||
2164 | if (link->dc->debug.legacy_dp2_lt) { | ||||
2165 | struct link_training_settings legacy_settings; | ||||
2166 | |||||
2167 | decide_8b_10b_training_settings(link, | ||||
2168 | <_settings->link_settings, | ||||
2169 | &legacy_settings); | ||||
2170 | return dp_perform_8b_10b_link_training(link, link_res, &legacy_settings); | ||||
2171 | } | ||||
2172 | |||||
2173 | dpcd_set_link_settings(link, lt_settings); | ||||
2174 | |||||
2175 | if (result == LINK_TRAINING_SUCCESS) | ||||
2176 | result = dp_perform_128b_132b_channel_eq_done_sequence(link, link_res, lt_settings); | ||||
2177 | |||||
2178 | if (result == LINK_TRAINING_SUCCESS) | ||||
2179 | result = dp_perform_128b_132b_cds_done_sequence(link, link_res, lt_settings); | ||||
2180 | |||||
2181 | return result; | ||||
2182 | } | ||||
2183 | |||||
2184 | static enum link_training_result perform_fixed_vs_pe_nontransparent_training_sequence( | ||||
2185 | struct dc_link *link, | ||||
2186 | const struct link_resource *link_res, | ||||
2187 | struct link_training_settings *lt_settings) | ||||
2188 | { | ||||
2189 | enum link_training_result status = LINK_TRAINING_SUCCESS; | ||||
2190 | uint8_t lane = 0; | ||||
2191 | uint8_t toggle_rate = 0x6; | ||||
2192 | uint8_t target_rate = 0x6; | ||||
2193 | bool_Bool apply_toggle_rate_wa = false0; | ||||
2194 | uint8_t repeater_cnt; | ||||
2195 | uint8_t repeater_id; | ||||
2196 | |||||
2197 | /* Fixed VS/PE specific: Force CR AUX RD Interval to at least 16ms */ | ||||
2198 | if (lt_settings->cr_pattern_time < 16000) | ||||
2199 | lt_settings->cr_pattern_time = 16000; | ||||
2200 | |||||
2201 | /* Fixed VS/PE specific: Toggle link rate */ | ||||
2202 | apply_toggle_rate_wa = (link->vendor_specific_lttpr_link_rate_wa == target_rate); | ||||
2203 | target_rate = get_dpcd_link_rate(<_settings->link_settings); | ||||
2204 | toggle_rate = (target_rate == 0x6) ? 0xA : 0x6; | ||||
2205 | |||||
2206 | if (apply_toggle_rate_wa) | ||||
2207 | lt_settings->link_settings.link_rate = toggle_rate; | ||||
2208 | |||||
2209 | if (link->ctx->dc->work_arounds.lt_early_cr_pattern) | ||||
2210 | start_clock_recovery_pattern_early(link, link_res, lt_settings, DPRX); | ||||
2211 | |||||
2212 | /* 1. set link rate, lane count and spread. */ | ||||
2213 | dpcd_set_link_settings(link, lt_settings); | ||||
2214 | |||||
2215 | /* Fixed VS/PE specific: Toggle link rate back*/ | ||||
2216 | if (apply_toggle_rate_wa) { | ||||
2217 | core_link_write_dpcd( | ||||
2218 | link, | ||||
2219 | DP_LINK_BW_SET0x100, | ||||
2220 | &target_rate, | ||||
2221 | 1); | ||||
2222 | } | ||||
2223 | |||||
2224 | link->vendor_specific_lttpr_link_rate_wa = target_rate; | ||||
2225 | |||||
2226 | if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) { | ||||
2227 | |||||
2228 | /* 2. perform link training (set link training done | ||||
2229 | * to false is done as well) | ||||
2230 | */ | ||||
2231 | repeater_cnt = dp_convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt); | ||||
2232 | |||||
2233 | for (repeater_id = repeater_cnt; (repeater_id > 0 && status == LINK_TRAINING_SUCCESS); | ||||
2234 | repeater_id--) { | ||||
2235 | status = perform_clock_recovery_sequence(link, link_res, lt_settings, repeater_id); | ||||
2236 | |||||
2237 | if (status != LINK_TRAINING_SUCCESS) { | ||||
2238 | repeater_training_done(link, repeater_id); | ||||
2239 | break; | ||||
2240 | } | ||||
2241 | |||||
2242 | status = perform_channel_equalization_sequence(link, | ||||
2243 | link_res, | ||||
2244 | lt_settings, | ||||
2245 | repeater_id); | ||||
2246 | |||||
2247 | repeater_training_done(link, repeater_id); | ||||
2248 | |||||
2249 | if (status != LINK_TRAINING_SUCCESS) | ||||
2250 | break; | ||||
2251 | |||||
2252 | for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) { | ||||
2253 | lt_settings->dpcd_lane_settings[lane].raw = 0; | ||||
2254 | lt_settings->hw_lane_settings[lane].VOLTAGE_SWING = 0; | ||||
2255 | lt_settings->hw_lane_settings[lane].PRE_EMPHASIS = 0; | ||||
2256 | } | ||||
2257 | } | ||||
2258 | } | ||||
2259 | |||||
2260 | if (status == LINK_TRAINING_SUCCESS) { | ||||
2261 | status = perform_clock_recovery_sequence(link, link_res, lt_settings, DPRX); | ||||
2262 | if (status == LINK_TRAINING_SUCCESS) { | ||||
2263 | status = perform_channel_equalization_sequence(link, | ||||
2264 | link_res, | ||||
2265 | lt_settings, | ||||
2266 | DPRX); | ||||
2267 | } | ||||
2268 | } | ||||
2269 | |||||
2270 | return status; | ||||
2271 | } | ||||
2272 | |||||
2273 | static enum link_training_result dp_perform_fixed_vs_pe_training_sequence( | ||||
2274 | struct dc_link *link, | ||||
2275 | const struct link_resource *link_res, | ||||
2276 | struct link_training_settings *lt_settings) | ||||
2277 | { | ||||
2278 | const uint8_t vendor_lttpr_write_data_reset[4] = {0x1, 0x50, 0x63, 0xFF}; | ||||
2279 | const uint8_t offset = dp_convert_to_count( | ||||
2280 | link->dpcd_caps.lttpr_caps.phy_repeater_cnt); | ||||
2281 | const uint8_t vendor_lttpr_write_data_intercept_en[4] = {0x1, 0x55, 0x63, 0x0}; | ||||
2282 | const uint8_t vendor_lttpr_write_data_intercept_dis[4] = {0x1, 0x55, 0x63, 0x68}; | ||||
2283 | uint32_t pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa; | ||||
2284 | uint8_t vendor_lttpr_write_data_vs[4] = {0x1, 0x51, 0x63, 0x0}; | ||||
2285 | uint8_t vendor_lttpr_write_data_pe[4] = {0x1, 0x52, 0x63, 0x0}; | ||||
2286 | uint32_t vendor_lttpr_write_address = 0xF004F; | ||||
2287 | enum link_training_result status = LINK_TRAINING_SUCCESS; | ||||
2288 | uint8_t lane = 0; | ||||
2289 | union down_spread_ctrl downspread = {0}; | ||||
2290 | union lane_count_set lane_count_set = {0}; | ||||
2291 | uint8_t toggle_rate; | ||||
2292 | uint8_t rate; | ||||
2293 | |||||
2294 | /* Only 8b/10b is supported */ | ||||
2295 | ASSERT(dp_get_link_encoding_format(<_settings->link_settings) ==do { if (({ static int __warned; int __ret = !!(!(dp_get_link_encoding_format (<_settings->link_settings) == DP_8b_10b_ENCODING)); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n" , "!(dp_get_link_encoding_format(<_settings->link_settings) == DP_8b_10b_ENCODING)" , "/usr/src/sys/dev/pci/drm/amd/display/dc/core/dc_link_dp.c" , 2296); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0) | ||||
2296 | DP_8b_10b_ENCODING)do { if (({ static int __warned; int __ret = !!(!(dp_get_link_encoding_format (<_settings->link_settings) == DP_8b_10b_ENCODING)); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n" , "!(dp_get_link_encoding_format(<_settings->link_settings) == DP_8b_10b_ENCODING)" , "/usr/src/sys/dev/pci/drm/amd/display/dc/core/dc_link_dp.c" , 2296); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | ||||
2297 | |||||
2298 | if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) { | ||||
2299 | status = perform_fixed_vs_pe_nontransparent_training_sequence(link, link_res, lt_settings); | ||||
2300 | return status; | ||||
2301 | } | ||||
2302 | |||||
2303 | if (offset != 0xFF) { | ||||
2304 | vendor_lttpr_write_address += | ||||
2305 | ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE0x50) * (offset - 1)); | ||||
2306 | |||||
2307 | /* Certain display and cable configuration require extra delay */ | ||||
2308 | if (offset > 2) | ||||
2309 | pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa * 2; | ||||
2310 | } | ||||
2311 | |||||
2312 | /* Vendor specific: Reset lane settings */ | ||||
2313 | core_link_write_dpcd( | ||||
2314 | link, | ||||
2315 | vendor_lttpr_write_address, | ||||
2316 | &vendor_lttpr_write_data_reset[0], | ||||
2317 | sizeof(vendor_lttpr_write_data_reset)); | ||||
2318 | core_link_write_dpcd( | ||||
2319 | link, | ||||
2320 | vendor_lttpr_write_address, | ||||
2321 | &vendor_lttpr_write_data_vs[0], | ||||
2322 | sizeof(vendor_lttpr_write_data_vs)); | ||||
2323 | core_link_write_dpcd( | ||||
2324 | link, | ||||
2325 | vendor_lttpr_write_address, | ||||
2326 | &vendor_lttpr_write_data_pe[0], | ||||
2327 | sizeof(vendor_lttpr_write_data_pe)); | ||||
2328 | |||||
2329 | /* Vendor specific: Enable intercept */ | ||||
2330 | core_link_write_dpcd( | ||||
2331 | link, | ||||
2332 | vendor_lttpr_write_address, | ||||
2333 | &vendor_lttpr_write_data_intercept_en[0], | ||||
2334 | sizeof(vendor_lttpr_write_data_intercept_en)); | ||||
2335 | |||||
2336 | /* 1. set link rate, lane count and spread. */ | ||||
2337 | |||||
2338 | downspread.raw = (uint8_t)(lt_settings->link_settings.link_spread); | ||||
2339 | |||||
2340 | lane_count_set.bits.LANE_COUNT_SET = | ||||
2341 | lt_settings->link_settings.lane_count; | ||||
2342 | |||||
2343 | lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing; | ||||
2344 | lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0; | ||||
2345 | |||||
2346 | |||||
2347 | if (lt_settings->pattern_for_eq < DP_TRAINING_PATTERN_SEQUENCE_4) { | ||||
2348 | lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = | ||||
2349 | link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED; | ||||
2350 | } | ||||
2351 | |||||
2352 | core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL0x107, | ||||
2353 | &downspread.raw, sizeof(downspread)); | ||||
2354 | |||||
2355 | core_link_write_dpcd(link, DP_LANE_COUNT_SET0x101, | ||||
2356 | &lane_count_set.raw, 1); | ||||
2357 | |||||
2358 | rate = get_dpcd_link_rate(<_settings->link_settings); | ||||
2359 | |||||
2360 | /* Vendor specific: Toggle link rate */ | ||||
2361 | toggle_rate = (rate == 0x6) ? 0xA : 0x6; | ||||
2362 | |||||
2363 | if (link->vendor_specific_lttpr_link_rate_wa == rate) { | ||||
2364 | core_link_write_dpcd( | ||||
2365 | link, | ||||
2366 | DP_LINK_BW_SET0x100, | ||||
2367 | &toggle_rate, | ||||
2368 | 1); | ||||
2369 | } | ||||
2370 | |||||
2371 | link->vendor_specific_lttpr_link_rate_wa = rate; | ||||
2372 | |||||
2373 | core_link_write_dpcd(link, DP_LINK_BW_SET0x100, &rate, 1); | ||||
2374 | |||||
2375 | DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x framing = %x\n %x spread = %x\n",do { } while(0) | ||||
2376 | __func__,do { } while(0) | ||||
2377 | DP_LINK_BW_SET,do { } while(0) | ||||
2378 | lt_settings->link_settings.link_rate,do { } while(0) | ||||
2379 | DP_LANE_COUNT_SET,do { } while(0) | ||||
2380 | lt_settings->link_settings.lane_count,do { } while(0) | ||||
2381 | lt_settings->enhanced_framing,do { } while(0) | ||||
2382 | DP_DOWNSPREAD_CTRL,do { } while(0) | ||||
2383 | lt_settings->link_settings.link_spread)do { } while(0); | ||||
2384 | |||||
2385 | /* 2. Perform link training */ | ||||
2386 | |||||
2387 | /* Perform Clock Recovery Sequence */ | ||||
2388 | if (status == LINK_TRAINING_SUCCESS) { | ||||
2389 | const uint8_t max_vendor_dpcd_retries = 10; | ||||
2390 | uint32_t retries_cr; | ||||
2391 | uint32_t retry_count; | ||||
2392 | uint32_t wait_time_microsec; | ||||
2393 | enum dc_lane_count lane_count = lt_settings->link_settings.lane_count; | ||||
2394 | union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX]; | ||||
2395 | union lane_align_status_updated dpcd_lane_status_updated; | ||||
2396 | union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0}; | ||||
2397 | enum dc_status dpcd_status = DC_OK; | ||||
2398 | uint8_t i = 0; | ||||
2399 | |||||
2400 | retries_cr = 0; | ||||
2401 | retry_count = 0; | ||||
2402 | |||||
2403 | memset(&dpcd_lane_status, '\0', sizeof(dpcd_lane_status))__builtin_memset((&dpcd_lane_status), ('\0'), (sizeof(dpcd_lane_status ))); | ||||
2404 | memset(&dpcd_lane_status_updated, '\0',__builtin_memset((&dpcd_lane_status_updated), ('\0'), (sizeof (dpcd_lane_status_updated))) | ||||
2405 | sizeof(dpcd_lane_status_updated))__builtin_memset((&dpcd_lane_status_updated), ('\0'), (sizeof (dpcd_lane_status_updated))); | ||||
2406 | |||||
2407 | while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) && | ||||
2408 | (retry_count < LINK_TRAINING_MAX_CR_RETRY)) { | ||||
2409 | |||||
2410 | |||||
2411 | /* 1. call HWSS to set lane settings */ | ||||
2412 | dp_set_hw_lane_settings( | ||||
2413 | link, | ||||
2414 | link_res, | ||||
2415 | lt_settings, | ||||
2416 | 0); | ||||
2417 | |||||
2418 | /* 2. update DPCD of the receiver */ | ||||
2419 | if (!retry_count) { | ||||
2420 | /* EPR #361076 - write as a 5-byte burst, | ||||
2421 | * but only for the 1-st iteration. | ||||
2422 | */ | ||||
2423 | dpcd_set_lt_pattern_and_lane_settings( | ||||
2424 | link, | ||||
2425 | lt_settings, | ||||
2426 | lt_settings->pattern_for_cr, | ||||
2427 | 0); | ||||
2428 | /* Vendor specific: Disable intercept */ | ||||
2429 | for (i = 0; i < max_vendor_dpcd_retries; i++) { | ||||
2430 | drm_msleep(pre_disable_intercept_delay_ms)mdelay(pre_disable_intercept_delay_ms); | ||||
2431 | dpcd_status = core_link_write_dpcd( | ||||
2432 | link, | ||||
2433 | vendor_lttpr_write_address, | ||||
2434 | &vendor_lttpr_write_data_intercept_dis[0], | ||||
2435 | sizeof(vendor_lttpr_write_data_intercept_dis)); | ||||
2436 | |||||
2437 | if (dpcd_status == DC_OK) | ||||
2438 | break; | ||||
2439 | |||||
2440 | core_link_write_dpcd( | ||||
2441 | link, | ||||
2442 | vendor_lttpr_write_address, | ||||
2443 | &vendor_lttpr_write_data_intercept_en[0], | ||||
2444 | sizeof(vendor_lttpr_write_data_intercept_en)); | ||||
2445 | } | ||||
2446 | } else { | ||||
2447 | vendor_lttpr_write_data_vs[3] = 0; | ||||
2448 | vendor_lttpr_write_data_pe[3] = 0; | ||||
2449 | |||||
2450 | for (lane = 0; lane < lane_count; lane++) { | ||||
2451 | vendor_lttpr_write_data_vs[3] |= | ||||
2452 | lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane); | ||||
2453 | vendor_lttpr_write_data_pe[3] |= | ||||
2454 | lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane); | ||||
2455 | } | ||||
2456 | |||||
2457 | /* Vendor specific: Update VS and PE to DPRX requested value */ | ||||
2458 | core_link_write_dpcd( | ||||
2459 | link, | ||||
2460 | vendor_lttpr_write_address, | ||||
2461 | &vendor_lttpr_write_data_vs[0], | ||||
2462 | sizeof(vendor_lttpr_write_data_vs)); | ||||
2463 | core_link_write_dpcd( | ||||
2464 | link, | ||||
2465 | vendor_lttpr_write_address, | ||||
2466 | &vendor_lttpr_write_data_pe[0], | ||||
2467 | sizeof(vendor_lttpr_write_data_pe)); | ||||
2468 | |||||
2469 | dpcd_set_lane_settings( | ||||
2470 | link, | ||||
2471 | lt_settings, | ||||
2472 | 0); | ||||
2473 | } | ||||
2474 | |||||
2475 | /* 3. wait receiver to lock-on*/ | ||||
2476 | wait_time_microsec = lt_settings->cr_pattern_time; | ||||
2477 | |||||
2478 | dp_wait_for_training_aux_rd_interval( | ||||
2479 | link, | ||||
2480 | wait_time_microsec); | ||||
2481 | |||||
2482 | /* 4. Read lane status and requested drive | ||||
2483 | * settings as set by the sink | ||||
2484 | */ | ||||
2485 | dp_get_lane_status_and_lane_adjust( | ||||
2486 | link, | ||||
2487 | lt_settings, | ||||
2488 | dpcd_lane_status, | ||||
2489 | &dpcd_lane_status_updated, | ||||
2490 | dpcd_lane_adjust, | ||||
2491 | 0); | ||||
2492 | |||||
2493 | /* 5. check CR done*/ | ||||
2494 | if (dp_is_cr_done(lane_count, dpcd_lane_status)) { | ||||
2495 | status = LINK_TRAINING_SUCCESS; | ||||
2496 | break; | ||||
2497 | } | ||||
2498 | |||||
2499 | /* 6. max VS reached*/ | ||||
2500 | if (dp_is_max_vs_reached(lt_settings)) | ||||
2501 | break; | ||||
2502 | |||||
2503 | /* 7. same lane settings */ | ||||
2504 | /* Note: settings are the same for all lanes, | ||||
2505 | * so comparing first lane is sufficient | ||||
2506 | */ | ||||
2507 | if (lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET == | ||||
2508 | dpcd_lane_adjust[0].bits.VOLTAGE_SWING_LANE) | ||||
2509 | retries_cr++; | ||||
2510 | else | ||||
2511 | retries_cr = 0; | ||||
2512 | |||||
2513 | /* 8. update VS/PE/PC2 in lt_settings*/ | ||||
2514 | dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, | ||||
2515 | lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); | ||||
2516 | retry_count++; | ||||
2517 | } | ||||
2518 | |||||
2519 | if (retry_count >= LINK_TRAINING_MAX_CR_RETRY) { | ||||
2520 | ASSERT(0)do { if (({ static int __warned; int __ret = !!(!(0)); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n" , "!(0)", "/usr/src/sys/dev/pci/drm/amd/display/dc/core/dc_link_dp.c" , 2520); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | ||||
2521 | DC_LOG_ERROR("%s: Link Training Error, could not get CR after %d tries. Possibly voltage swing issue",__drm_err("%s: Link Training Error, could not get CR after %d tries. Possibly voltage swing issue" , __func__, LINK_TRAINING_MAX_CR_RETRY) | ||||
2522 | __func__,__drm_err("%s: Link Training Error, could not get CR after %d tries. Possibly voltage swing issue" , __func__, LINK_TRAINING_MAX_CR_RETRY) | ||||
2523 | LINK_TRAINING_MAX_CR_RETRY)__drm_err("%s: Link Training Error, could not get CR after %d tries. Possibly voltage swing issue" , __func__, LINK_TRAINING_MAX_CR_RETRY); | ||||
2524 | |||||
2525 | } | ||||
2526 | |||||
2527 | status = dp_get_cr_failure(lane_count, dpcd_lane_status); | ||||
2528 | } | ||||
2529 | |||||
2530 | /* Perform Channel EQ Sequence */ | ||||
2531 | if (status == LINK_TRAINING_SUCCESS) { | ||||
2532 | enum dc_dp_training_pattern tr_pattern; | ||||
2533 | uint32_t retries_ch_eq; | ||||
2534 | uint32_t wait_time_microsec; | ||||
2535 | enum dc_lane_count lane_count = lt_settings->link_settings.lane_count; | ||||
2536 | union lane_align_status_updated dpcd_lane_status_updated = {0}; | ||||
2537 | union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0}; | ||||
2538 | union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0}; | ||||
2539 | |||||
2540 | /* Note: also check that TPS4 is a supported feature*/ | ||||
2541 | tr_pattern = lt_settings->pattern_for_eq; | ||||
2542 | |||||
2543 | dp_set_hw_training_pattern(link, link_res, tr_pattern, 0); | ||||
2544 | |||||
2545 | status = LINK_TRAINING_EQ_FAIL_EQ; | ||||
2546 | |||||
2547 | for (retries_ch_eq = 0; retries_ch_eq <= LINK_TRAINING_MAX_RETRY_COUNT; | ||||
2548 | retries_ch_eq++) { | ||||
2549 | |||||
2550 | dp_set_hw_lane_settings(link, link_res, lt_settings, 0); | ||||
2551 | |||||
2552 | vendor_lttpr_write_data_vs[3] = 0; | ||||
2553 | vendor_lttpr_write_data_pe[3] = 0; | ||||
2554 | |||||
2555 | for (lane = 0; lane < lane_count; lane++) { | ||||
2556 | vendor_lttpr_write_data_vs[3] |= | ||||
2557 | lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane); | ||||
2558 | vendor_lttpr_write_data_pe[3] |= | ||||
2559 | lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane); | ||||
2560 | } | ||||
2561 | |||||
2562 | /* Vendor specific: Update VS and PE to DPRX requested value */ | ||||
2563 | core_link_write_dpcd( | ||||
2564 | link, | ||||
2565 | vendor_lttpr_write_address, | ||||
2566 | &vendor_lttpr_write_data_vs[0], | ||||
2567 | sizeof(vendor_lttpr_write_data_vs)); | ||||
2568 | core_link_write_dpcd( | ||||
2569 | link, | ||||
2570 | vendor_lttpr_write_address, | ||||
2571 | &vendor_lttpr_write_data_pe[0], | ||||
2572 | sizeof(vendor_lttpr_write_data_pe)); | ||||
2573 | |||||
2574 | /* 2. update DPCD*/ | ||||
2575 | if (!retries_ch_eq) | ||||
2576 | /* EPR #361076 - write as a 5-byte burst, | ||||
2577 | * but only for the 1-st iteration | ||||
2578 | */ | ||||
2579 | |||||
2580 | dpcd_set_lt_pattern_and_lane_settings( | ||||
2581 | link, | ||||
2582 | lt_settings, | ||||
2583 | tr_pattern, 0); | ||||
2584 | else | ||||
2585 | dpcd_set_lane_settings(link, lt_settings, 0); | ||||
2586 | |||||
2587 | /* 3. wait for receiver to lock-on*/ | ||||
2588 | wait_time_microsec = lt_settings->eq_pattern_time; | ||||
2589 | |||||
2590 | dp_wait_for_training_aux_rd_interval( | ||||
2591 | link, | ||||
2592 | wait_time_microsec); | ||||
2593 | |||||
2594 | /* 4. Read lane status and requested | ||||
2595 | * drive settings as set by the sink | ||||
2596 | */ | ||||
2597 | dp_get_lane_status_and_lane_adjust( | ||||
2598 | link, | ||||
2599 | lt_settings, | ||||
2600 | dpcd_lane_status, | ||||
2601 | &dpcd_lane_status_updated, | ||||
2602 | dpcd_lane_adjust, | ||||
2603 | 0); | ||||
2604 | |||||
2605 | /* 5. check CR done*/ | ||||
2606 | if (!dp_is_cr_done(lane_count, dpcd_lane_status)) { | ||||
2607 | status = LINK_TRAINING_EQ_FAIL_CR; | ||||
2608 | break; | ||||
2609 | } | ||||
2610 | |||||
2611 | /* 6. check CHEQ done*/ | ||||
2612 | if (dp_is_ch_eq_done(lane_count, dpcd_lane_status) && | ||||
2613 | dp_is_symbol_locked(lane_count, dpcd_lane_status) && | ||||
2614 | dp_is_interlane_aligned(dpcd_lane_status_updated)) { | ||||
2615 | status = LINK_TRAINING_SUCCESS; | ||||
2616 | break; | ||||
2617 | } | ||||
2618 | |||||
2619 | /* 7. update VS/PE/PC2 in lt_settings*/ | ||||
2620 | dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, | ||||
2621 | lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); | ||||
2622 | } | ||||
2623 | } | ||||
2624 | |||||
2625 | return status; | ||||
2626 | } | ||||
2627 | |||||
2628 | |||||
2629 | enum link_training_result dc_link_dp_perform_link_training( | ||||
2630 | struct dc_link *link, | ||||
2631 | const struct link_resource *link_res, | ||||
2632 | const struct dc_link_settings *link_settings, | ||||
2633 | bool_Bool skip_video_pattern) | ||||
2634 | { | ||||
2635 | enum link_training_result status = LINK_TRAINING_SUCCESS; | ||||
2636 | struct link_training_settings lt_settings = {0}; | ||||
2637 | enum dp_link_encoding encoding = | ||||
2638 | dp_get_link_encoding_format(link_settings); | ||||
2639 | |||||
2640 | /* decide training settings */ | ||||
2641 | dp_decide_training_settings( | ||||
2642 | link, | ||||
2643 | link_settings, | ||||
2644 | <_settings); | ||||
2645 | |||||
2646 | override_training_settings( | ||||
2647 | link, | ||||
2648 | &link->preferred_training_settings, | ||||
2649 | <_settings); | ||||
2650 | |||||
2651 | /* reset previous training states */ | ||||
2652 | dpcd_exit_training_mode(link); | ||||
2653 | |||||
2654 | /* configure link prior to entering training mode */ | ||||
2655 | dpcd_configure_lttpr_mode(link, <_settings); | ||||
2656 | dp_set_fec_ready(link, link_res, lt_settings.should_set_fec_ready); | ||||
2657 | dpcd_configure_channel_coding(link, <_settings); | ||||
2658 | |||||
2659 | /* enter training mode: | ||||
2660 | * Per DP specs starting from here, DPTX device shall not issue | ||||
2661 | * Non-LT AUX transactions inside training mode. | ||||
2662 | */ | ||||
2663 | if (link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN && encoding == DP_8b_10b_ENCODING) | ||||
2664 | status = dp_perform_fixed_vs_pe_training_sequence(link, link_res, <_settings); | ||||
2665 | else if (encoding == DP_8b_10b_ENCODING) | ||||
2666 | status = dp_perform_8b_10b_link_training(link, link_res, <_settings); | ||||
2667 | else if (encoding == DP_128b_132b_ENCODING) | ||||
2668 | status = dp_perform_128b_132b_link_training(link, link_res, <_settings); | ||||
2669 | else | ||||
2670 | ASSERT(0)do { if (({ static int __warned; int __ret = !!(!(0)); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n" , "!(0)", "/usr/src/sys/dev/pci/drm/amd/display/dc/core/dc_link_dp.c" , 2670); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | ||||
2671 | |||||
2672 | /* exit training mode */ | ||||
2673 | dpcd_exit_training_mode(link); | ||||
2674 | |||||
2675 | /* switch to video idle */ | ||||
2676 | if ((status == LINK_TRAINING_SUCCESS) || !skip_video_pattern) | ||||
2677 | status = dp_transition_to_video_idle(link, | ||||
2678 | link_res, | ||||
2679 | <_settings, | ||||
2680 | status); | ||||
2681 | |||||
2682 | /* dump debug data */ | ||||
2683 | print_status_message(link, <_settings, status); | ||||
2684 | if (status != LINK_TRAINING_SUCCESS) | ||||
2685 | link->ctx->dc->debug_data.ltFailCount++; | ||||
2686 | return status; | ||||
2687 | } | ||||
2688 | |||||
2689 | bool_Bool perform_link_training_with_retries( | ||||
2690 | const struct dc_link_settings *link_setting, | ||||
2691 | bool_Bool skip_video_pattern, | ||||
2692 | int attempts, | ||||
2693 | struct pipe_ctx *pipe_ctx, | ||||
2694 | enum amd_signal_type signal, | ||||
2695 | bool_Bool do_fallback) | ||||
2696 | { | ||||
2697 | int j; | ||||
2698 | uint8_t delay_between_attempts = LINK_TRAINING_RETRY_DELAY50; | ||||
2699 | struct dc_stream_state *stream = pipe_ctx->stream; | ||||
2700 | struct dc_link *link = stream->link; | ||||
2701 | enum dp_panel_mode panel_mode = dp_get_panel_mode(link); | ||||
2702 | enum link_training_result status = LINK_TRAINING_CR_FAIL_LANE0; | ||||
2703 | struct dc_link_settings cur_link_settings = *link_setting; | ||||
2704 | struct dc_link_settings max_link_settings = *link_setting; | ||||
2705 | const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res); | ||||
2706 | int fail_count = 0; | ||||
2707 | bool_Bool is_link_bw_low = false0; /* link bandwidth < stream bandwidth */ | ||||
2708 | bool_Bool is_link_bw_min = /* RBR x 1 */ | ||||
2709 | (cur_link_settings.link_rate <= LINK_RATE_LOW) && | ||||
2710 | (cur_link_settings.lane_count <= LANE_COUNT_ONE); | ||||
2711 | |||||
2712 | dp_trace_commit_lt_init(link); | ||||
2713 | |||||
2714 | if (dp_get_link_encoding_format(&cur_link_settings) == DP_8b_10b_ENCODING) | ||||
2715 | /* We need to do this before the link training to ensure the idle | ||||
2716 | * pattern in SST mode will be sent right after the link training | ||||
2717 | */ | ||||
2718 | link_hwss->setup_stream_encoder(pipe_ctx); | ||||
2719 | |||||
2720 | dp_trace_set_lt_start_timestamp(link, false0); | ||||
2721 | j = 0; | ||||
2722 | while (j < attempts && fail_count < (attempts * 10)) { | ||||
2723 | |||||
2724 | DC_LOG_HW_LINK_TRAINING("%s: Beginning link(%d) training attempt %u of %d @ rate(%d) x lane(%d)\n",do { } while(0) | ||||
2725 | __func__, link->link_index, (unsigned int)j + 1, attempts, cur_link_settings.link_rate,do { } while(0) | ||||
2726 | cur_link_settings.lane_count)do { } while(0); | ||||
2727 | |||||
2728 | dp_enable_link_phy( | ||||
2729 | link, | ||||
2730 | &pipe_ctx->link_res, | ||||
2731 | signal, | ||||
2732 | pipe_ctx->clock_source->id, | ||||
2733 | &cur_link_settings); | ||||
2734 | |||||
2735 | if (stream->sink_patches.dppowerup_delay > 0) { | ||||
2736 | int delay_dp_power_up_in_ms = stream->sink_patches.dppowerup_delay; | ||||
2737 | |||||
2738 | drm_msleep(delay_dp_power_up_in_ms)mdelay(delay_dp_power_up_in_ms); | ||||
2739 | } | ||||
2740 | |||||
2741 | #ifdef CONFIG_DRM_AMD_DC_HDCP | ||||
2742 | if (panel_mode == DP_PANEL_MODE_EDP) { | ||||
2743 | struct cp_psp *cp_psp = &stream->ctx->cp_psp; | ||||
2744 | |||||
2745 | if (cp_psp && cp_psp->funcs.enable_assr) | ||||
2746 | /* ASSR is bound to fail with unsigned PSP | ||||
2747 | * verstage used during devlopment phase. | ||||
2748 | * Report and continue with eDP panel mode to | ||||
2749 | * perform eDP link training with right settings | ||||
2750 | */ | ||||
2751 | cp_psp->funcs.enable_assr(cp_psp->handle, link); | ||||
2752 | } | ||||
2753 | #endif | ||||
2754 | |||||
2755 | dp_set_panel_mode(link, panel_mode); | ||||
2756 | |||||
2757 | if (link->aux_access_disabled) { | ||||
2758 | dc_link_dp_perform_link_training_skip_aux(link, &pipe_ctx->link_res, &cur_link_settings); | ||||
2759 | return true1; | ||||
2760 | } else { | ||||
2761 | /** @todo Consolidate USB4 DP and DPx.x training. */ | ||||
2762 | if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) { | ||||
2763 | status = dc_link_dpia_perform_link_training(link, | ||||
2764 | &pipe_ctx->link_res, | ||||
2765 | &cur_link_settings, | ||||
2766 | skip_video_pattern); | ||||
2767 | |||||
2768 | /* Transmit idle pattern once training successful. */ | ||||
2769 | if (status == LINK_TRAINING_SUCCESS && !is_link_bw_low) { | ||||
2770 | dp_set_hw_test_pattern(link, &pipe_ctx->link_res, DP_TEST_PATTERN_VIDEO_MODE, NULL((void *)0), 0); | ||||
2771 | /* Update verified link settings to current one | ||||
2772 | * Because DPIA LT might fallback to lower link setting. | ||||
2773 | */ | ||||
2774 | link->verified_link_cap.link_rate = link->cur_link_settings.link_rate; | ||||
2775 | link->verified_link_cap.lane_count = link->cur_link_settings.lane_count; | ||||
2776 | } | ||||
2777 | } else { | ||||
2778 | status = dc_link_dp_perform_link_training(link, | ||||
2779 | &pipe_ctx->link_res, | ||||
2780 | &cur_link_settings, | ||||
2781 | skip_video_pattern); | ||||
2782 | } | ||||
2783 | |||||
2784 | dp_trace_lt_total_count_increment(link, false0); | ||||
2785 | dp_trace_lt_result_update(link, status, false0); | ||||
2786 | dp_trace_set_lt_end_timestamp(link, false0); | ||||
2787 | if (status == LINK_TRAINING_SUCCESS && !is_link_bw_low) | ||||
2788 | return true1; | ||||
2789 | } | ||||
2790 | |||||
2791 | fail_count++; | ||||
2792 | dp_trace_lt_fail_count_update(link, fail_count, false0); | ||||
2793 | if (link->ep_type == DISPLAY_ENDPOINT_PHY) { | ||||
2794 | /* latest link training still fail or link training is aborted | ||||
2795 | * skip delay and keep PHY on | ||||
2796 | */ | ||||
2797 | if (j == (attempts - 1) || (status == LINK_TRAINING_ABORT)) | ||||
2798 | break; | ||||
2799 | } | ||||
2800 | |||||
2801 | DC_LOG_WARNING("%s: Link(%d) training attempt %u of %d failed @ rate(%d) x lane(%d) : fail reason:(%d)\n",printk("\0014" "[" "drm" "] " "%s: Link(%d) training attempt %u of %d failed @ rate(%d) x lane(%d) : fail reason:(%d)\n" , __func__, link->link_index, (unsigned int)j + 1, attempts , cur_link_settings.link_rate, cur_link_settings.lane_count, status ) | ||||
2802 | __func__, link->link_index, (unsigned int)j + 1, attempts, cur_link_settings.link_rate,printk("\0014" "[" "drm" "] " "%s: Link(%d) training attempt %u of %d failed @ rate(%d) x lane(%d) : fail reason:(%d)\n" , __func__, link->link_index, (unsigned int)j + 1, attempts , cur_link_settings.link_rate, cur_link_settings.lane_count, status ) | ||||
2803 | cur_link_settings.lane_count, status)printk("\0014" "[" "drm" "] " "%s: Link(%d) training attempt %u of %d failed @ rate(%d) x lane(%d) : fail reason:(%d)\n" , __func__, link->link_index, (unsigned int)j + 1, attempts , cur_link_settings.link_rate, cur_link_settings.lane_count, status ); | ||||
2804 | |||||
2805 | dp_disable_link_phy(link, &pipe_ctx->link_res, signal); | ||||
2806 | |||||
2807 | /* Abort link training if failure due to sink being unplugged. */ | ||||
2808 | if (status == LINK_TRAINING_ABORT) { | ||||
2809 | enum dc_connection_type type = dc_connection_none; | ||||
2810 | |||||
2811 | dc_link_detect_sink(link, &type); | ||||
2812 | if (type == dc_connection_none) { | ||||
2813 | DC_LOG_HW_LINK_TRAINING("%s: Aborting training because sink unplugged\n", __func__)do { } while(0); | ||||
2814 | break; | ||||
2815 | } | ||||
2816 | } | ||||
2817 | |||||
2818 | /* Try to train again at original settings if: | ||||
2819 | * - not falling back between training attempts; | ||||
2820 | * - aborted previous attempt due to reasons other than sink unplug; | ||||
2821 | * - successfully trained but at a link rate lower than that required by stream; | ||||
2822 | * - reached minimum link bandwidth. | ||||
2823 | */ | ||||
2824 | if (!do_fallback || (status == LINK_TRAINING_ABORT) || | ||||
2825 | (status == LINK_TRAINING_SUCCESS && is_link_bw_low) || | ||||
2826 | is_link_bw_min) { | ||||
2827 | j++; | ||||
2828 | cur_link_settings = *link_setting; | ||||
2829 | delay_between_attempts += LINK_TRAINING_RETRY_DELAY50; | ||||
2830 | is_link_bw_low = false0; | ||||
2831 | is_link_bw_min = (cur_link_settings.link_rate <= LINK_RATE_LOW) && | ||||
2832 | (cur_link_settings.lane_count <= LANE_COUNT_ONE); | ||||
2833 | |||||
2834 | } else if (do_fallback) { /* Try training at lower link bandwidth if doing fallback. */ | ||||
2835 | uint32_t req_bw; | ||||
2836 | uint32_t link_bw; | ||||
2837 | |||||
2838 | decide_fallback_link_setting(link, &max_link_settings, | ||||
2839 | &cur_link_settings, status); | ||||
2840 | /* Fail link training if reduced link bandwidth no longer meets | ||||
2841 | * stream requirements. | ||||
2842 | */ | ||||
2843 | req_bw = dc_bandwidth_in_kbps_from_timing(&stream->timing); | ||||
2844 | link_bw = dc_link_bandwidth_kbps(link, &cur_link_settings); | ||||
2845 | is_link_bw_low = (req_bw > link_bw); | ||||
2846 | is_link_bw_min = ((cur_link_settings.link_rate <= LINK_RATE_LOW) && | ||||
2847 | (cur_link_settings.lane_count <= LANE_COUNT_ONE)); | ||||
2848 | if (is_link_bw_low) | ||||
2849 | DC_LOG_WARNING(printk("\0014" "[" "drm" "] " "%s: Link(%d) bandwidth too low after fallback req_bw(%d) > link_bw(%d)\n" , __func__, link->link_index, req_bw, link_bw) | ||||
2850 | "%s: Link(%d) bandwidth too low after fallback req_bw(%d) > link_bw(%d)\n",printk("\0014" "[" "drm" "] " "%s: Link(%d) bandwidth too low after fallback req_bw(%d) > link_bw(%d)\n" , __func__, link->link_index, req_bw, link_bw) | ||||
2851 | __func__, link->link_index, req_bw, link_bw)printk("\0014" "[" "drm" "] " "%s: Link(%d) bandwidth too low after fallback req_bw(%d) > link_bw(%d)\n" , __func__, link->link_index, req_bw, link_bw); | ||||
2852 | } | ||||
2853 | |||||
2854 | drm_msleep(delay_between_attempts)mdelay(delay_between_attempts); | ||||
2855 | } | ||||
2856 | return false0; | ||||
2857 | } | ||||
2858 | |||||
2859 | static enum clock_source_id get_clock_source_id(struct dc_link *link) | ||||
2860 | { | ||||
2861 | enum clock_source_id dp_cs_id = CLOCK_SOURCE_ID_UNDEFINED; | ||||
2862 | struct clock_source *dp_cs = link->dc->res_pool->dp_clock_source; | ||||
2863 | |||||
2864 | if (dp_cs != NULL((void *)0)) { | ||||
2865 | dp_cs_id = dp_cs->id; | ||||
2866 | } else { | ||||
2867 | /* | ||||
2868 | * dp clock source is not initialized for some reason. | ||||
2869 | * Should not happen, CLOCK_SOURCE_ID_EXTERNAL will be used | ||||
2870 | */ | ||||
2871 | ASSERT(dp_cs)do { if (({ static int __warned; int __ret = !!(!(dp_cs)); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n" , "!(dp_cs)", "/usr/src/sys/dev/pci/drm/amd/display/dc/core/dc_link_dp.c" , 2871); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | ||||
2872 | } | ||||
2873 | |||||
2874 | return dp_cs_id; | ||||
2875 | } | ||||
2876 | |||||
2877 | static void set_dp_mst_mode(struct dc_link *link, const struct link_resource *link_res, | ||||
2878 | bool_Bool mst_enable) | ||||
2879 | { | ||||
2880 | if (mst_enable == false0 && | ||||
2881 | link->type == dc_connection_mst_branch) { | ||||
2882 | /* Disable MST on link. Use only local sink. */ | ||||
2883 | dp_disable_link_phy_mst(link, link_res, link->connector_signal); | ||||
2884 | |||||
2885 | link->type = dc_connection_single; | ||||
2886 | link->local_sink = link->remote_sinks[0]; | ||||
2887 | link->local_sink->sink_signal = SIGNAL_TYPE_DISPLAY_PORT; | ||||
2888 | dc_sink_retain(link->local_sink); | ||||
2889 | dm_helpers_dp_mst_stop_top_mgr(link->ctx, link); | ||||
2890 | } else if (mst_enable == true1 && | ||||
2891 | link->type == dc_connection_single && | ||||
2892 | link->remote_sinks[0] != NULL((void *)0)) { | ||||
2893 | /* Re-enable MST on link. */ | ||||
2894 | dp_disable_link_phy(link, link_res, link->connector_signal); | ||||
2895 | dp_enable_mst_on_sink(link, true1); | ||||
2896 | |||||
2897 | link->type = dc_connection_mst_branch; | ||||
2898 | link->local_sink->sink_signal = SIGNAL_TYPE_DISPLAY_PORT_MST; | ||||
2899 | } | ||||
2900 | } | ||||
2901 | |||||
2902 | bool_Bool dc_link_dp_sync_lt_begin(struct dc_link *link) | ||||
2903 | { | ||||
2904 | /* Begin Sync LT. During this time, | ||||
2905 | * DPCD:600h must not be powered down. | ||||
2906 | */ | ||||
2907 | link->sync_lt_in_progress = true1; | ||||
2908 | |||||
2909 | /*Clear any existing preferred settings.*/ | ||||
2910 | memset(&link->preferred_training_settings, 0,__builtin_memset((&link->preferred_training_settings), (0), (sizeof(struct dc_link_training_overrides))) | ||||
2911 | sizeof(struct dc_link_training_overrides))__builtin_memset((&link->preferred_training_settings), (0), (sizeof(struct dc_link_training_overrides))); | ||||
2912 | memset(&link->preferred_link_setting, 0,__builtin_memset((&link->preferred_link_setting), (0), (sizeof(struct dc_link_settings))) | ||||
2913 | sizeof(struct dc_link_settings))__builtin_memset((&link->preferred_link_setting), (0), (sizeof(struct dc_link_settings))); | ||||
2914 | |||||
2915 | return true1; | ||||
2916 | } | ||||
2917 | |||||
2918 | enum link_training_result dc_link_dp_sync_lt_attempt( | ||||
2919 | struct dc_link *link, | ||||
2920 | const struct link_resource *link_res, | ||||
2921 | struct dc_link_settings *link_settings, | ||||
2922 | struct dc_link_training_overrides *lt_overrides) | ||||
2923 | { | ||||
2924 | struct link_training_settings lt_settings = {0}; | ||||
2925 | enum link_training_result lt_status = LINK_TRAINING_SUCCESS; | ||||
2926 | enum dp_panel_mode panel_mode = DP_PANEL_MODE_DEFAULT; | ||||
2927 | enum clock_source_id dp_cs_id = CLOCK_SOURCE_ID_EXTERNAL; | ||||
2928 | bool_Bool fec_enable = false0; | ||||
2929 | |||||
2930 | dp_decide_training_settings( | ||||
2931 | link, | ||||
2932 | link_settings, | ||||
2933 | <_settings); | ||||
2934 | override_training_settings( | ||||
2935 | link, | ||||
2936 | lt_overrides, | ||||
2937 | <_settings); | ||||
2938 | /* Setup MST Mode */ | ||||
2939 | if (lt_overrides->mst_enable) | ||||
2940 | set_dp_mst_mode(link, link_res, *lt_overrides->mst_enable); | ||||
2941 | |||||
2942 | /* Disable link */ | ||||
2943 | dp_disable_link_phy(link, link_res, link->connector_signal); | ||||
2944 | |||||
2945 | /* Enable link */ | ||||
2946 | dp_cs_id = get_clock_source_id(link); | ||||
2947 | dp_enable_link_phy(link, link_res, link->connector_signal, | ||||
2948 | dp_cs_id, link_settings); | ||||
2949 | |||||
2950 | /* Set FEC enable */ | ||||
2951 | if (dp_get_link_encoding_format(link_settings) == DP_8b_10b_ENCODING) { | ||||
2952 | fec_enable = lt_overrides->fec_enable && *lt_overrides->fec_enable; | ||||
2953 | dp_set_fec_ready(link, NULL((void *)0), fec_enable); | ||||
2954 | } | ||||
2955 | |||||
2956 | if (lt_overrides->alternate_scrambler_reset) { | ||||
2957 | if (*lt_overrides->alternate_scrambler_reset) | ||||
2958 | panel_mode = DP_PANEL_MODE_EDP; | ||||
2959 | else | ||||
2960 | panel_mode = DP_PANEL_MODE_DEFAULT; | ||||
2961 | } else | ||||
2962 | panel_mode = dp_get_panel_mode(link); | ||||
2963 | |||||
2964 | dp_set_panel_mode(link, panel_mode); | ||||
2965 | |||||
2966 | /* Attempt to train with given link training settings */ | ||||
2967 | if (link->ctx->dc->work_arounds.lt_early_cr_pattern) | ||||
2968 | start_clock_recovery_pattern_early(link, link_res, <_settings, DPRX); | ||||
2969 | |||||
2970 | /* Set link rate, lane count and spread. */ | ||||
2971 | dpcd_set_link_settings(link, <_settings); | ||||
2972 | |||||
2973 | /* 2. perform link training (set link training done | ||||
2974 | * to false is done as well) | ||||
2975 | */ | ||||
2976 | lt_status = perform_clock_recovery_sequence(link, link_res, <_settings, DPRX); | ||||
2977 | if (lt_status == LINK_TRAINING_SUCCESS) { | ||||
2978 | lt_status = perform_channel_equalization_sequence(link, | ||||
2979 | link_res, | ||||
2980 | <_settings, | ||||
2981 | DPRX); | ||||
2982 | } | ||||
2983 | |||||
2984 | /* 3. Sync LT must skip TRAINING_PATTERN_SET:0 (video pattern)*/ | ||||
2985 | /* 4. print status message*/ | ||||
2986 | print_status_message(link, <_settings, lt_status); | ||||
2987 | |||||
2988 | return lt_status; | ||||
2989 | } | ||||
2990 | |||||
2991 | bool_Bool dc_link_dp_sync_lt_end(struct dc_link *link, bool_Bool link_down) | ||||
2992 | { | ||||
2993 | /* If input parameter is set, shut down phy. | ||||
2994 | * Still shouldn't turn off dp_receiver (DPCD:600h) | ||||
2995 | */ | ||||
2996 | if (link_down == true1) { | ||||
2997 | struct dc_link_settings link_settings = link->cur_link_settings; | ||||
2998 | dp_disable_link_phy(link, NULL((void *)0), link->connector_signal); | ||||
2999 | if (dp_get_link_encoding_format(&link_settings) == DP_8b_10b_ENCODING) | ||||
3000 | dp_set_fec_ready(link, NULL((void *)0), false0); | ||||
3001 | } | ||||
3002 | |||||
3003 | link->sync_lt_in_progress = false0; | ||||
3004 | return true1; | ||||
3005 | } | ||||
3006 | |||||
3007 | static enum dc_link_rate get_lttpr_max_link_rate(struct dc_link *link) | ||||
3008 | { | ||||
3009 | enum dc_link_rate lttpr_max_link_rate = link->dpcd_caps.lttpr_caps.max_link_rate; | ||||
3010 | |||||
3011 | if (link->dpcd_caps.lttpr_caps.supported_128b_132b_rates.bits.UHBR20) | ||||
3012 | lttpr_max_link_rate = LINK_RATE_UHBR20; | ||||
3013 | else if (link->dpcd_caps.lttpr_caps.supported_128b_132b_rates.bits.UHBR13_5) | ||||
3014 | lttpr_max_link_rate = LINK_RATE_UHBR13_5; | ||||
3015 | else if (link->dpcd_caps.lttpr_caps.supported_128b_132b_rates.bits.UHBR10) | ||||
3016 | lttpr_max_link_rate = LINK_RATE_UHBR10; | ||||
3017 | |||||
3018 | return lttpr_max_link_rate; | ||||
3019 | } | ||||
3020 | |||||
3021 | static enum dc_link_rate get_cable_max_link_rate(struct dc_link *link) | ||||
3022 | { | ||||
3023 | enum dc_link_rate cable_max_link_rate = LINK_RATE_HIGH3; | ||||
3024 | |||||
3025 | if (link->dpcd_caps.cable_id.bits.UHBR10_20_CAPABILITY & DP_UHBR20(1 << 1)) | ||||
3026 | cable_max_link_rate = LINK_RATE_UHBR20; | ||||
3027 | else if (link->dpcd_caps.cable_id.bits.UHBR13_5_CAPABILITY) | ||||
3028 | cable_max_link_rate = LINK_RATE_UHBR13_5; | ||||
3029 | else if (link->dpcd_caps.cable_id.bits.UHBR10_20_CAPABILITY & DP_UHBR10(1 << 0)) | ||||
3030 | cable_max_link_rate = LINK_RATE_UHBR10; | ||||
3031 | |||||
3032 | return cable_max_link_rate; | ||||
3033 | } | ||||
3034 | |||||
3035 | bool_Bool dc_link_dp_get_max_link_enc_cap(const struct dc_link *link, struct dc_link_settings *max_link_enc_cap) | ||||
3036 | { | ||||
3037 | struct link_encoder *link_enc = NULL((void *)0); | ||||
3038 | |||||
3039 | if (!max_link_enc_cap) { | ||||
3040 | DC_LOG_ERROR("%s: Could not return max link encoder caps", __func__)__drm_err("%s: Could not return max link encoder caps", __func__ ); | ||||
3041 | return false0; | ||||
3042 | } | ||||
3043 | |||||
3044 | link_enc = link_enc_cfg_get_link_enc(link); | ||||
3045 | ASSERT(link_enc)do { if (({ static int __warned; int __ret = !!(!(link_enc)); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n" , "!(link_enc)", "/usr/src/sys/dev/pci/drm/amd/display/dc/core/dc_link_dp.c" , 3045); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | ||||
3046 | |||||
3047 | if (link_enc && link_enc->funcs->get_max_link_cap) { | ||||
3048 | link_enc->funcs->get_max_link_cap(link_enc, max_link_enc_cap); | ||||
3049 | return true1; | ||||
3050 | } | ||||
3051 | |||||
3052 | DC_LOG_ERROR("%s: Max link encoder caps unknown", __func__)__drm_err("%s: Max link encoder caps unknown", __func__); | ||||
3053 | max_link_enc_cap->lane_count = 1; | ||||
3054 | max_link_enc_cap->link_rate = 6; | ||||
3055 | return false0; | ||||
3056 | } | ||||
3057 | |||||
3058 | |||||
3059 | struct dc_link_settings dp_get_max_link_cap(struct dc_link *link) | ||||
3060 | { | ||||
3061 | struct dc_link_settings max_link_cap = {0}; | ||||
3062 | enum dc_link_rate lttpr_max_link_rate; | ||||
3063 | enum dc_link_rate cable_max_link_rate; | ||||
3064 | struct link_encoder *link_enc = NULL((void *)0); | ||||
3065 | |||||
3066 | |||||
3067 | link_enc = link_enc_cfg_get_link_enc(link); | ||||
3068 | ASSERT(link_enc)do { if (({ static int __warned; int __ret = !!(!(link_enc)); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n" , "!(link_enc)", "/usr/src/sys/dev/pci/drm/amd/display/dc/core/dc_link_dp.c" , 3068); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | ||||
3069 | |||||
3070 | /* get max link encoder capability */ | ||||
3071 | if (link_enc) | ||||
3072 | link_enc->funcs->get_max_link_cap(link_enc, &max_link_cap); | ||||
3073 | |||||
3074 | /* Lower link settings based on sink's link cap */ | ||||
3075 | if (link->reported_link_cap.lane_count < max_link_cap.lane_count) | ||||
3076 | max_link_cap.lane_count = | ||||
3077 | link->reported_link_cap.lane_count; | ||||
3078 | if (link->reported_link_cap.link_rate < max_link_cap.link_rate) | ||||
3079 | max_link_cap.link_rate = | ||||
3080 | link->reported_link_cap.link_rate; | ||||
3081 | if (link->reported_link_cap.link_spread < | ||||
3082 | max_link_cap.link_spread) | ||||
3083 | max_link_cap.link_spread = | ||||
3084 | link->reported_link_cap.link_spread; | ||||
3085 | |||||
3086 | /* Lower link settings based on cable attributes */ | ||||
3087 | cable_max_link_rate = get_cable_max_link_rate(link); | ||||
3088 | |||||
3089 | if (!link->dc->debug.ignore_cable_id && | ||||
3090 | cable_max_link_rate < max_link_cap.link_rate) | ||||
3091 | max_link_cap.link_rate = cable_max_link_rate; | ||||
3092 | |||||
3093 | /* | ||||
3094 | * account for lttpr repeaters cap | ||||
3095 | * notes: repeaters do not snoop in the DPRX Capabilities addresses (3.6.3). | ||||
3096 | */ | ||||
3097 | if (dp_is_lttpr_present(link)) { | ||||
3098 | if (link->dpcd_caps.lttpr_caps.max_lane_count < max_link_cap.lane_count) | ||||
3099 | max_link_cap.lane_count = link->dpcd_caps.lttpr_caps.max_lane_count; | ||||
3100 | lttpr_max_link_rate = get_lttpr_max_link_rate(link); | ||||
3101 | |||||
3102 | if (lttpr_max_link_rate < max_link_cap.link_rate) | ||||
3103 | max_link_cap.link_rate = lttpr_max_link_rate; | ||||
3104 | |||||
3105 | DC_LOG_HW_LINK_TRAINING("%s\n Training with LTTPR, max_lane count %d max_link rate %d \n",do { } while(0) | ||||
3106 | __func__,do { } while(0) | ||||
3107 | max_link_cap.lane_count,do { } while(0) | ||||
3108 | max_link_cap.link_rate)do { } while(0); | ||||
3109 | } | ||||
3110 | |||||
3111 | if (dp_get_link_encoding_format(&max_link_cap) == DP_128b_132b_ENCODING && | ||||
3112 | link->dc->debug.disable_uhbr) | ||||
3113 | max_link_cap.link_rate = LINK_RATE_HIGH3; | ||||
3114 | |||||
3115 | return max_link_cap; | ||||
3116 | } | ||||
3117 | |||||
3118 | enum dc_status read_hpd_rx_irq_data( | ||||
3119 | struct dc_link *link, | ||||
3120 | union hpd_irq_data *irq_data) | ||||
3121 | { | ||||
3122 | static enum dc_status retval; | ||||
3123 | |||||
3124 | /* The HW reads 16 bytes from 200h on HPD, | ||||
3125 | * but if we get an AUX_DEFER, the HW cannot retry | ||||
3126 | * and this causes the CTS tests 4.3.2.1 - 3.2.4 to | ||||
3127 | * fail, so we now explicitly read 6 bytes which is | ||||
3128 | * the req from the above mentioned test cases. | ||||
3129 | * | ||||
3130 | * For DP 1.4 we need to read those from 2002h range. | ||||
3131 | */ | ||||
3132 | if (link->dpcd_caps.dpcd_rev.raw < DPCD_REV_14) | ||||
3133 | retval = core_link_read_dpcd( | ||||
3134 | link, | ||||
3135 | DP_SINK_COUNT0x200, | ||||
3136 | irq_data->raw, | ||||
3137 | sizeof(union hpd_irq_data)); | ||||
3138 | else { | ||||
3139 | /* Read 14 bytes in a single read and then copy only the required fields. | ||||
3140 | * This is more efficient than doing it in two separate AUX reads. */ | ||||
3141 | |||||
3142 | uint8_t tmp[DP_SINK_STATUS_ESI0x200f - DP_SINK_COUNT_ESI0x2002 + 1]; | ||||
3143 | |||||
3144 | retval = core_link_read_dpcd( | ||||
3145 | link, | ||||
3146 | DP_SINK_COUNT_ESI0x2002, | ||||
3147 | tmp, | ||||
3148 | sizeof(tmp)); | ||||
3149 | |||||
3150 | if (retval != DC_OK) | ||||
3151 | return retval; | ||||
3152 | |||||
3153 | irq_data->bytes.sink_cnt.raw = tmp[DP_SINK_COUNT_ESI0x2002 - DP_SINK_COUNT_ESI0x2002]; | ||||
3154 | irq_data->bytes.device_service_irq.raw = tmp[DP_DEVICE_SERVICE_IRQ_VECTOR_ESI00x2003 - DP_SINK_COUNT_ESI0x2002]; | ||||
3155 | irq_data->bytes.lane01_status.raw = tmp[DP_LANE0_1_STATUS_ESI0x200c - DP_SINK_COUNT_ESI0x2002]; | ||||
3156 | irq_data->bytes.lane23_status.raw = tmp[DP_LANE2_3_STATUS_ESI0x200d - DP_SINK_COUNT_ESI0x2002]; | ||||
3157 | irq_data->bytes.lane_status_updated.raw = tmp[DP_LANE_ALIGN_STATUS_UPDATED_ESI0x200e - DP_SINK_COUNT_ESI0x2002]; | ||||
3158 | irq_data->bytes.sink_status.raw = tmp[DP_SINK_STATUS_ESI0x200f - DP_SINK_COUNT_ESI0x2002]; | ||||
3159 | } | ||||
3160 | |||||
3161 | return retval; | ||||
3162 | } | ||||
3163 | |||||
3164 | bool_Bool hpd_rx_irq_check_link_loss_status( | ||||
3165 | struct dc_link *link, | ||||
3166 | union hpd_irq_data *hpd_irq_dpcd_data) | ||||
3167 | { | ||||
3168 | uint8_t irq_reg_rx_power_state = 0; | ||||
3169 | enum dc_status dpcd_result = DC_ERROR_UNEXPECTED; | ||||
3170 | union lane_status lane_status; | ||||
3171 | uint32_t lane; | ||||
3172 | bool_Bool sink_status_changed; | ||||
3173 | bool_Bool return_code; | ||||
3174 | |||||
3175 | sink_status_changed = false0; | ||||
3176 | return_code = false0; | ||||
3177 | |||||
3178 | if (link->cur_link_settings.lane_count == 0) | ||||
3179 | return return_code; | ||||
3180 | |||||
3181 | /*1. Check that Link Status changed, before re-training.*/ | ||||
3182 | |||||
3183 | /*parse lane status*/ | ||||
3184 | for (lane = 0; lane < link->cur_link_settings.lane_count; lane++) { | ||||
3185 | /* check status of lanes 0,1 | ||||
3186 | * changed DpcdAddress_Lane01Status (0x202) | ||||
3187 | */ | ||||
3188 | lane_status.raw = get_nibble_at_index( | ||||
3189 | &hpd_irq_dpcd_data->bytes.lane01_status.raw, | ||||
3190 | lane); | ||||
3191 | |||||
3192 | if (!lane_status.bits.CHANNEL_EQ_DONE_0 || | ||||
3193 | !lane_status.bits.CR_DONE_0 || | ||||
3194 | !lane_status.bits.SYMBOL_LOCKED_0) { | ||||
3195 | /* if one of the channel equalization, clock | ||||
3196 | * recovery or symbol lock is dropped | ||||
3197 | * consider it as (link has been | ||||
3198 | * dropped) dp sink status has changed | ||||
3199 | */ | ||||
3200 | sink_status_changed = true1; | ||||
3201 | break; | ||||
3202 | } | ||||
3203 | } | ||||
3204 | |||||
3205 | /* Check interlane align.*/ | ||||
3206 | if (sink_status_changed || | ||||
3207 | !hpd_irq_dpcd_data->bytes.lane_status_updated.bits.INTERLANE_ALIGN_DONE) { | ||||
3208 | |||||
3209 | DC_LOG_HW_HPD_IRQ("%s: Link Status changed.\n", __func__)___drm_dbg(((void *)0), DRM_UT_KMS, "%s: Link Status changed.\n" , __func__); | ||||
3210 | |||||
3211 | return_code = true1; | ||||
3212 | |||||
3213 | /*2. Check that we can handle interrupt: Not in FS DOS, | ||||
3214 | * Not in "Display Timeout" state, Link is trained. | ||||
3215 | */ | ||||
3216 | dpcd_result = core_link_read_dpcd(link, | ||||
3217 | DP_SET_POWER0x600, | ||||
3218 | &irq_reg_rx_power_state, | ||||
3219 | sizeof(irq_reg_rx_power_state)); | ||||
3220 | |||||
3221 | if (dpcd_result != DC_OK) { | ||||
3222 | DC_LOG_HW_HPD_IRQ("%s: DPCD read failed to obtain power state.\n",___drm_dbg(((void *)0), DRM_UT_KMS, "%s: DPCD read failed to obtain power state.\n" , __func__) | ||||
3223 | __func__)___drm_dbg(((void *)0), DRM_UT_KMS, "%s: DPCD read failed to obtain power state.\n" , __func__); | ||||
3224 | } else { | ||||
3225 | if (irq_reg_rx_power_state != DP_SET_POWER_D00x1) | ||||
3226 | return_code = false0; | ||||
3227 | } | ||||
3228 | } | ||||
3229 | |||||
3230 | return return_code; | ||||
3231 | } | ||||
3232 | |||||
3233 | static bool_Bool dp_verify_link_cap( | ||||
3234 | struct dc_link *link, | ||||
3235 | struct dc_link_settings *known_limit_link_setting, | ||||
3236 | int *fail_count) | ||||
3237 | { | ||||
3238 | struct dc_link_settings cur_link_settings = {0}; | ||||
3239 | struct dc_link_settings max_link_settings = *known_limit_link_setting; | ||||
3240 | bool_Bool success = false0; | ||||
3241 | bool_Bool skip_video_pattern; | ||||
3242 | enum clock_source_id dp_cs_id = get_clock_source_id(link); | ||||
3243 | enum link_training_result status = LINK_TRAINING_SUCCESS; | ||||
3244 | union hpd_irq_data irq_data; | ||||
3245 | struct link_resource link_res; | ||||
3246 | |||||
3247 | memset(&irq_data, 0, sizeof(irq_data))__builtin_memset((&irq_data), (0), (sizeof(irq_data))); | ||||
3248 | cur_link_settings = max_link_settings; | ||||
3249 | |||||
3250 | /* Grant extended timeout request */ | ||||
3251 | if (dp_is_lttpr_present(link) && link->dpcd_caps.lttpr_caps.max_ext_timeout > 0) { | ||||
3252 | uint8_t grant = link->dpcd_caps.lttpr_caps.max_ext_timeout & 0x80; | ||||
3253 | |||||
3254 | core_link_write_dpcd(link, DP_PHY_REPEATER_EXTENDED_WAIT_TIMEOUT0xf0005, &grant, sizeof(grant)); | ||||
3255 | } | ||||
3256 | |||||
3257 | do { | ||||
3258 | if (!get_temp_dp_link_res(link, &link_res, &cur_link_settings)) | ||||
3259 | continue; | ||||
3260 | |||||
3261 | skip_video_pattern = cur_link_settings.link_rate != LINK_RATE_LOW; | ||||
3262 | dp_enable_link_phy( | ||||
3263 | link, | ||||
3264 | &link_res, | ||||
3265 | link->connector_signal, | ||||
3266 | dp_cs_id, | ||||
3267 | &cur_link_settings); | ||||
3268 | |||||
3269 | status = dc_link_dp_perform_link_training( | ||||
3270 | link, | ||||
3271 | &link_res, | ||||
3272 | &cur_link_settings, | ||||
3273 | skip_video_pattern); | ||||
3274 | |||||
3275 | if (status == LINK_TRAINING_SUCCESS) { | ||||
3276 | success = true1; | ||||
3277 | udelay(1000); | ||||
3278 | if (read_hpd_rx_irq_data(link, &irq_data) == DC_OK && | ||||
3279 | hpd_rx_irq_check_link_loss_status( | ||||
3280 | link, | ||||
3281 | &irq_data)) | ||||
3282 | (*fail_count)++; | ||||
3283 | |||||
3284 | } else { | ||||
3285 | (*fail_count)++; | ||||
3286 | } | ||||
3287 | dp_trace_lt_total_count_increment(link, true1); | ||||
3288 | dp_trace_lt_result_update(link, status, true1); | ||||
3289 | dp_disable_link_phy(link, &link_res, link->connector_signal); | ||||
3290 | } while (!success && decide_fallback_link_setting(link, | ||||
3291 | &max_link_settings, &cur_link_settings, status)); | ||||
3292 | |||||
3293 | link->verified_link_cap = success ? | ||||
3294 | cur_link_settings : fail_safe_link_settings; | ||||
3295 | return success; | ||||
3296 | } | ||||
3297 | |||||
3298 | static void apply_usbc_combo_phy_reset_wa(struct dc_link *link, | ||||
3299 | struct dc_link_settings *link_settings) | ||||
3300 | { | ||||
3301 | /* Temporary Renoir-specific workaround PHY will sometimes be in bad | ||||
3302 | * state on hotplugging display from certain USB-C dongle, so add extra | ||||
3303 | * cycle of enabling and disabling the PHY before first link training. | ||||
3304 | */ | ||||
3305 | struct link_resource link_res = {0}; | ||||
3306 | enum clock_source_id dp_cs_id = get_clock_source_id(link); | ||||
3307 | |||||
3308 | dp_enable_link_phy(link, &link_res, link->connector_signal, | ||||
3309 | dp_cs_id, link_settings); | ||||
3310 | dp_disable_link_phy(link, &link_res, link->connector_signal); | ||||
3311 | } | ||||
3312 | |||||
3313 | bool_Bool dp_verify_link_cap_with_retries( | ||||
3314 | struct dc_link *link, | ||||
3315 | struct dc_link_settings *known_limit_link_setting, | ||||
3316 | int attempts) | ||||
3317 | { | ||||
3318 | int i = 0; | ||||
3319 | bool_Bool success = false0; | ||||
3320 | int fail_count = 0; | ||||
3321 | |||||
3322 | dp_trace_detect_lt_init(link); | ||||
3323 | |||||
3324 | if (link->link_enc && link->link_enc->features.flags.bits.DP_IS_USB_C && | ||||
3325 | link->dc->debug.usbc_combo_phy_reset_wa) | ||||
3326 | apply_usbc_combo_phy_reset_wa(link, known_limit_link_setting); | ||||
3327 | |||||
3328 | dp_trace_set_lt_start_timestamp(link, false0); | ||||
3329 | for (i = 0; i < attempts; i++) { | ||||
3330 | enum dc_connection_type type = dc_connection_none; | ||||
3331 | |||||
3332 | memset(&link->verified_link_cap, 0,__builtin_memset((&link->verified_link_cap), (0), (sizeof (struct dc_link_settings))) | ||||
3333 | sizeof(struct dc_link_settings))__builtin_memset((&link->verified_link_cap), (0), (sizeof (struct dc_link_settings))); | ||||
3334 | if (!dc_link_detect_sink(link, &type) || type == dc_connection_none) { | ||||
3335 | link->verified_link_cap = fail_safe_link_settings; | ||||
3336 | break; | ||||
3337 | } else if (dp_verify_link_cap(link, known_limit_link_setting, | ||||
3338 | &fail_count) && fail_count == 0) { | ||||
3339 | success = true1; | ||||
3340 | break; | ||||
3341 | } | ||||
3342 | drm_msleep(10)mdelay(10); | ||||
3343 | } | ||||
3344 | |||||
3345 | dp_trace_lt_fail_count_update(link, fail_count, true1); | ||||
3346 | dp_trace_set_lt_end_timestamp(link, true1); | ||||
3347 | |||||
3348 | return success; | ||||
3349 | } | ||||
3350 | |||||
3351 | /* in DP compliance test, DPR-120 may have | ||||
3352 | * a random value in its MAX_LINK_BW dpcd field. | ||||
3353 | * We map it to the maximum supported link rate that | ||||
3354 | * is smaller than MAX_LINK_BW in this case. | ||||
3355 | */ | ||||
3356 | static enum dc_link_rate get_link_rate_from_max_link_bw( | ||||
3357 | uint8_t max_link_bw) | ||||
3358 | { | ||||
3359 | enum dc_link_rate link_rate; | ||||
3360 | |||||
3361 | if (max_link_bw >= LINK_RATE_HIGH3) { | ||||
3362 | link_rate = LINK_RATE_HIGH3; | ||||
3363 | } else if (max_link_bw < LINK_RATE_HIGH3 | ||||
3364 | && max_link_bw >= LINK_RATE_HIGH2) { | ||||
3365 | link_rate = LINK_RATE_HIGH2; | ||||
3366 | } else if (max_link_bw < LINK_RATE_HIGH2 | ||||
3367 | && max_link_bw >= LINK_RATE_HIGH) { | ||||
3368 | link_rate = LINK_RATE_HIGH; | ||||
3369 | } else if (max_link_bw < LINK_RATE_HIGH | ||||
3370 | && max_link_bw >= LINK_RATE_LOW) { | ||||
3371 | link_rate = LINK_RATE_LOW; | ||||
3372 | } else { | ||||
3373 | link_rate = LINK_RATE_UNKNOWN; | ||||
3374 | } | ||||
3375 | |||||
3376 | return link_rate; | ||||
3377 | } | ||||
3378 | |||||
3379 | static inline bool_Bool reached_minimum_lane_count(enum dc_lane_count lane_count) | ||||
3380 | { | ||||
3381 | return lane_count <= LANE_COUNT_ONE; | ||||
3382 | } | ||||
3383 | |||||
3384 | static inline bool_Bool reached_minimum_link_rate(enum dc_link_rate link_rate) | ||||
3385 | { | ||||
3386 | return link_rate <= LINK_RATE_LOW; | ||||
3387 | } | ||||
3388 | |||||
3389 | static enum dc_lane_count reduce_lane_count(enum dc_lane_count lane_count) | ||||
3390 | { | ||||
3391 | switch (lane_count) { | ||||
3392 | case LANE_COUNT_FOUR: | ||||
3393 | return LANE_COUNT_TWO; | ||||
3394 | case LANE_COUNT_TWO: | ||||
3395 | return LANE_COUNT_ONE; | ||||
3396 | case LANE_COUNT_ONE: | ||||
3397 | return LANE_COUNT_UNKNOWN; | ||||
3398 | default: | ||||
3399 | return LANE_COUNT_UNKNOWN; | ||||
3400 | } | ||||
3401 | } | ||||
3402 | |||||
3403 | static enum dc_link_rate reduce_link_rate(enum dc_link_rate link_rate) | ||||
3404 | { | ||||
3405 | switch (link_rate) { | ||||
3406 | case LINK_RATE_UHBR20: | ||||
3407 | return LINK_RATE_UHBR13_5; | ||||
3408 | case LINK_RATE_UHBR13_5: | ||||
3409 | return LINK_RATE_UHBR10; | ||||
3410 | case LINK_RATE_UHBR10: | ||||
3411 | return LINK_RATE_HIGH3; | ||||
3412 | case LINK_RATE_HIGH3: | ||||
3413 | return LINK_RATE_HIGH2; | ||||
3414 | case LINK_RATE_HIGH2: | ||||
3415 | return LINK_RATE_HIGH; | ||||
3416 | case LINK_RATE_HIGH: | ||||
3417 | return LINK_RATE_LOW; | ||||
3418 | case LINK_RATE_LOW: | ||||
3419 | return LINK_RATE_UNKNOWN; | ||||
3420 | default: | ||||
3421 | return LINK_RATE_UNKNOWN; | ||||
3422 | } | ||||
3423 | } | ||||
3424 | |||||
3425 | static enum dc_lane_count increase_lane_count(enum dc_lane_count lane_count) | ||||
3426 | { | ||||
3427 | switch (lane_count) { | ||||
3428 | case LANE_COUNT_ONE: | ||||
3429 | return LANE_COUNT_TWO; | ||||
3430 | case LANE_COUNT_TWO: | ||||
3431 | return LANE_COUNT_FOUR; | ||||
3432 | default: | ||||
3433 | return LANE_COUNT_UNKNOWN; | ||||
3434 | } | ||||
3435 | } | ||||
3436 | |||||
3437 | static enum dc_link_rate increase_link_rate(struct dc_link *link, | ||||
3438 | enum dc_link_rate link_rate) | ||||
3439 | { | ||||
3440 | switch (link_rate) { | ||||
3441 | case LINK_RATE_LOW: | ||||
3442 | return LINK_RATE_HIGH; | ||||
3443 | case LINK_RATE_HIGH: | ||||
3444 | return LINK_RATE_HIGH2; | ||||
3445 | case LINK_RATE_HIGH2: | ||||
3446 | return LINK_RATE_HIGH3; | ||||
3447 | case LINK_RATE_HIGH3: | ||||
3448 | return LINK_RATE_UHBR10; | ||||
3449 | case LINK_RATE_UHBR10: | ||||
3450 | /* upto DP2.x specs UHBR13.5 is the only link rate that could be | ||||
3451 | * not supported by DPRX when higher link rate is supported. | ||||
3452 | * so we treat it as a special case for code simplicity. When we | ||||
3453 | * have new specs with more link rates like this, we should | ||||
3454 | * consider a more generic solution to handle discrete link | ||||
3455 | * rate capabilities. | ||||
3456 | */ | ||||
3457 | return link->dpcd_caps.dp_128b_132b_supported_link_rates.bits.UHBR13_5 ? | ||||
3458 | LINK_RATE_UHBR13_5 : LINK_RATE_UHBR20; | ||||
3459 | case LINK_RATE_UHBR13_5: | ||||
3460 | return LINK_RATE_UHBR20; | ||||
3461 | default: | ||||
3462 | return LINK_RATE_UNKNOWN; | ||||
3463 | } | ||||
3464 | } | ||||
3465 | |||||
3466 | static bool_Bool decide_fallback_link_setting_max_bw_policy( | ||||
3467 | struct dc_link *link, | ||||
3468 | const struct dc_link_settings *max, | ||||
3469 | struct dc_link_settings *cur, | ||||
3470 | enum link_training_result training_result) | ||||
3471 | { | ||||
3472 | uint8_t cur_idx = 0, next_idx; | ||||
3473 | bool_Bool found = false0; | ||||
3474 | |||||
3475 | if (training_result == LINK_TRAINING_ABORT) | ||||
3476 | return false0; | ||||
3477 | |||||
3478 | while (cur_idx < ARRAY_SIZE(dp_lt_fallbacks)(sizeof((dp_lt_fallbacks)) / sizeof((dp_lt_fallbacks)[0]))) | ||||
3479 | /* find current index */ | ||||
3480 | if (dp_lt_fallbacks[cur_idx].lane_count == cur->lane_count && | ||||
3481 | dp_lt_fallbacks[cur_idx].link_rate == cur->link_rate) | ||||
3482 | break; | ||||
3483 | else | ||||
3484 | cur_idx++; | ||||
3485 | |||||
3486 | next_idx = cur_idx + 1; | ||||
3487 | |||||
3488 | while (next_idx < ARRAY_SIZE(dp_lt_fallbacks)(sizeof((dp_lt_fallbacks)) / sizeof((dp_lt_fallbacks)[0]))) | ||||
3489 | /* find next index */ | ||||
3490 | if (dp_lt_fallbacks[next_idx].lane_count > max->lane_count || | ||||
3491 | dp_lt_fallbacks[next_idx].link_rate > max->link_rate) | ||||
3492 | next_idx++; | ||||
3493 | else if (dp_lt_fallbacks[next_idx].link_rate == LINK_RATE_UHBR13_5 && | ||||
3494 | link->dpcd_caps.dp_128b_132b_supported_link_rates.bits.UHBR13_5 == 0) | ||||
3495 | /* upto DP2.x specs UHBR13.5 is the only link rate that | ||||
3496 | * could be not supported by DPRX when higher link rate | ||||
3497 | * is supported. so we treat it as a special case for | ||||
3498 | * code simplicity. When we have new specs with more | ||||
3499 | * link rates like this, we should consider a more | ||||
3500 | * generic solution to handle discrete link rate | ||||
3501 | * capabilities. | ||||
3502 | */ | ||||
3503 | next_idx++; | ||||
3504 | else | ||||
3505 | break; | ||||
3506 | |||||
3507 | if (next_idx < ARRAY_SIZE(dp_lt_fallbacks)(sizeof((dp_lt_fallbacks)) / sizeof((dp_lt_fallbacks)[0]))) { | ||||
3508 | cur->lane_count = dp_lt_fallbacks[next_idx].lane_count; | ||||
3509 | cur->link_rate = dp_lt_fallbacks[next_idx].link_rate; | ||||
3510 | found = true1; | ||||
3511 | } | ||||
3512 | |||||
3513 | return found; | ||||
3514 | } | ||||
3515 | |||||
3516 | /* | ||||
3517 | * function: set link rate and lane count fallback based | ||||
3518 | * on current link setting and last link training result | ||||
3519 | * return value: | ||||
3520 | * true - link setting could be set | ||||
3521 | * false - has reached minimum setting | ||||
3522 | * and no further fallback could be done | ||||
3523 | */ | ||||
3524 | static bool_Bool decide_fallback_link_setting( | ||||
3525 | struct dc_link *link, | ||||
3526 | struct dc_link_settings *max, | ||||
3527 | struct dc_link_settings *cur, | ||||
3528 | enum link_training_result training_result) | ||||
3529 | { | ||||
3530 | if (dp_get_link_encoding_format(max) == DP_128b_132b_ENCODING || | ||||
3531 | link->dc->debug.force_dp2_lt_fallback_method) | ||||
3532 | return decide_fallback_link_setting_max_bw_policy(link, max, cur, | ||||
3533 | training_result); | ||||
3534 | |||||
3535 | switch (training_result) { | ||||
3536 | case LINK_TRAINING_CR_FAIL_LANE0: | ||||
3537 | case LINK_TRAINING_CR_FAIL_LANE1: | ||||
3538 | case LINK_TRAINING_CR_FAIL_LANE23: | ||||
3539 | case LINK_TRAINING_LQA_FAIL: | ||||
3540 | { | ||||
3541 | if (!reached_minimum_link_rate(cur->link_rate)) { | ||||
3542 | cur->link_rate = reduce_link_rate(cur->link_rate); | ||||
3543 | } else if (!reached_minimum_lane_count(cur->lane_count)) { | ||||
3544 | cur->link_rate = max->link_rate; | ||||
3545 | if (training_result == LINK_TRAINING_CR_FAIL_LANE0) | ||||
3546 | return false0; | ||||
3547 | else if (training_result == LINK_TRAINING_CR_FAIL_LANE1) | ||||
3548 | cur->lane_count = LANE_COUNT_ONE; | ||||
3549 | else if (training_result == LINK_TRAINING_CR_FAIL_LANE23) | ||||
3550 | cur->lane_count = LANE_COUNT_TWO; | ||||
3551 | else | ||||
3552 | cur->lane_count = reduce_lane_count(cur->lane_count); | ||||
3553 | } else { | ||||
3554 | return false0; | ||||
3555 | } | ||||
3556 | break; | ||||
3557 | } | ||||
3558 | case LINK_TRAINING_EQ_FAIL_EQ: | ||||
3559 | case LINK_TRAINING_EQ_FAIL_CR_PARTIAL: | ||||
3560 | { | ||||
3561 | if (!reached_minimum_lane_count(cur->lane_count)) { | ||||
3562 | cur->lane_count = reduce_lane_count(cur->lane_count); | ||||
3563 | } else if (!reached_minimum_link_rate(cur->link_rate)) { | ||||
3564 | cur->link_rate = reduce_link_rate(cur->link_rate); | ||||
3565 | /* Reduce max link rate to avoid potential infinite loop. | ||||
3566 | * Needed so that any subsequent CR_FAIL fallback can't | ||||
3567 | * re-set the link rate higher than the link rate from | ||||
3568 | * the latest EQ_FAIL fallback. | ||||
3569 | */ | ||||
3570 | max->link_rate = cur->link_rate; | ||||
3571 | cur->lane_count = max->lane_count; | ||||
3572 | } else { | ||||
3573 | return false0; | ||||
3574 | } | ||||
3575 | break; | ||||
3576 | } | ||||
3577 | case LINK_TRAINING_EQ_FAIL_CR: | ||||
3578 | { | ||||
3579 | if (!reached_minimum_link_rate(cur->link_rate)) { | ||||
3580 | cur->link_rate = reduce_link_rate(cur->link_rate); | ||||
3581 | /* Reduce max link rate to avoid potential infinite loop. | ||||
3582 | * Needed so that any subsequent CR_FAIL fallback can't | ||||
3583 | * re-set the link rate higher than the link rate from | ||||
3584 | * the latest EQ_FAIL fallback. | ||||
3585 | */ | ||||
3586 | max->link_rate = cur->link_rate; | ||||
3587 | cur->lane_count = max->lane_count; | ||||
3588 | } else { | ||||
3589 | return false0; | ||||
3590 | } | ||||
3591 | break; | ||||
3592 | } | ||||
3593 | default: | ||||
3594 | return false0; | ||||
3595 | } | ||||
3596 | return true1; | ||||
3597 | } | ||||
3598 | |||||
3599 | bool_Bool dp_validate_mode_timing( | ||||
3600 | struct dc_link *link, | ||||
3601 | const struct dc_crtc_timing *timing) | ||||
3602 | { | ||||
3603 | uint32_t req_bw; | ||||
3604 | uint32_t max_bw; | ||||
3605 | |||||
3606 | const struct dc_link_settings *link_setting; | ||||
3607 | |||||
3608 | /* According to spec, VSC SDP should be used if pixel format is YCbCr420 */ | ||||
3609 | if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420 && | ||||
3610 | !link->dpcd_caps.dprx_feature.bits.VSC_SDP_COLORIMETRY_SUPPORTED && | ||||
3611 | dal_graphics_object_id_get_connector_id(link->link_id) != CONNECTOR_ID_VIRTUAL) | ||||
3612 | return false0; | ||||
3613 | |||||
3614 | /*always DP fail safe mode*/ | ||||
3615 | if ((timing->pix_clk_100hz / 10) == (uint32_t) 25175 && | ||||
3616 | timing->h_addressable == (uint32_t) 640 && | ||||
3617 | timing->v_addressable == (uint32_t) 480) | ||||
3618 | return true1; | ||||
3619 | |||||
3620 | link_setting = dc_link_get_link_cap(link); | ||||
3621 | |||||
3622 | /* TODO: DYNAMIC_VALIDATION needs to be implemented */ | ||||
3623 | /*if (flags.DYNAMIC_VALIDATION == 1 && | ||||
3624 | link->verified_link_cap.lane_count != LANE_COUNT_UNKNOWN) | ||||
3625 | link_setting = &link->verified_link_cap; | ||||
3626 | */ | ||||
3627 | |||||
3628 | req_bw = dc_bandwidth_in_kbps_from_timing(timing); | ||||
3629 | max_bw = dc_link_bandwidth_kbps(link, link_setting); | ||||
3630 | |||||
3631 | if (req_bw <= max_bw) { | ||||
3632 | /* remember the biggest mode here, during | ||||
3633 | * initial link training (to get | ||||
3634 | * verified_link_cap), LS sends event about | ||||
3635 | * cannot train at reported cap to upper | ||||
3636 | * layer and upper layer will re-enumerate modes. | ||||
3637 | * this is not necessary if the lower | ||||
3638 | * verified_link_cap is enough to drive | ||||
3639 | * all the modes */ | ||||
3640 | |||||
3641 | /* TODO: DYNAMIC_VALIDATION needs to be implemented */ | ||||
3642 | /* if (flags.DYNAMIC_VALIDATION == 1) | ||||
3643 | dpsst->max_req_bw_for_verified_linkcap = dal_max( | ||||
3644 | dpsst->max_req_bw_for_verified_linkcap, req_bw); */ | ||||
3645 | return true1; | ||||
3646 | } else | ||||
3647 | return false0; | ||||
3648 | } | ||||
3649 | |||||
3650 | static bool_Bool decide_dp_link_settings(struct dc_link *link, struct dc_link_settings *link_setting, uint32_t req_bw) | ||||
3651 | { | ||||
3652 | struct dc_link_settings initial_link_setting = { | ||||
3653 | LANE_COUNT_ONE, LINK_RATE_LOW, LINK_SPREAD_DISABLED, false0, 0}; | ||||
3654 | struct dc_link_settings current_link_setting = | ||||
3655 | initial_link_setting; | ||||
3656 | uint32_t link_bw; | ||||
3657 | |||||
3658 | if (req_bw > dc_link_bandwidth_kbps(link, &link->verified_link_cap)) | ||||
3659 | return false0; | ||||
3660 | |||||
3661 | /* search for the minimum link setting that: | ||||
3662 | * 1. is supported according to the link training result | ||||
3663 | * 2. could support the b/w requested by the timing | ||||
3664 | */ | ||||
3665 | while (current_link_setting.link_rate <= | ||||
3666 | link->verified_link_cap.link_rate) { | ||||
3667 | link_bw = dc_link_bandwidth_kbps( | ||||
3668 | link, | ||||
3669 | ¤t_link_setting); | ||||
3670 | if (req_bw <= link_bw) { | ||||
3671 | *link_setting = current_link_setting; | ||||
3672 | return true1; | ||||
3673 | } | ||||
3674 | |||||
3675 | if (current_link_setting.lane_count < | ||||
3676 | link->verified_link_cap.lane_count) { | ||||
3677 | current_link_setting.lane_count = | ||||
3678 | increase_lane_count( | ||||
3679 | current_link_setting.lane_count); | ||||
3680 | } else { | ||||
3681 | current_link_setting.link_rate = | ||||
3682 | increase_link_rate(link, | ||||
3683 | current_link_setting.link_rate); | ||||
3684 | current_link_setting.lane_count = | ||||
3685 | initial_link_setting.lane_count; | ||||
3686 | } | ||||
3687 | } | ||||
3688 | |||||
3689 | return false0; | ||||
3690 | } | ||||
3691 | |||||
3692 | bool_Bool decide_edp_link_settings(struct dc_link *link, struct dc_link_settings *link_setting, uint32_t req_bw) | ||||
3693 | { | ||||
3694 | struct dc_link_settings initial_link_setting; | ||||
3695 | struct dc_link_settings current_link_setting; | ||||
3696 | uint32_t link_bw; | ||||
3697 | |||||
3698 | /* | ||||
3699 | * edp_supported_link_rates_count is only valid for eDP v1.4 or higher. | ||||
3700 | * Per VESA eDP spec, "The DPCD revision for eDP v1.4 is 13h" | ||||
3701 | */ | ||||
3702 | if (link->dpcd_caps.dpcd_rev.raw < DPCD_REV_13 || | ||||
3703 | link->dpcd_caps.edp_supported_link_rates_count == 0) { | ||||
3704 | *link_setting = link->verified_link_cap; | ||||
3705 | return true1; | ||||
3706 | } | ||||
3707 | |||||
3708 | memset(&initial_link_setting, 0, sizeof(initial_link_setting))__builtin_memset((&initial_link_setting), (0), (sizeof(initial_link_setting ))); | ||||
3709 | initial_link_setting.lane_count = LANE_COUNT_ONE; | ||||
3710 | initial_link_setting.link_rate = link->dpcd_caps.edp_supported_link_rates[0]; | ||||
3711 | initial_link_setting.link_spread = LINK_SPREAD_DISABLED; | ||||
3712 | initial_link_setting.use_link_rate_set = true1; | ||||
3713 | initial_link_setting.link_rate_set = 0; | ||||
3714 | current_link_setting = initial_link_setting; | ||||
3715 | |||||
3716 | /* search for the minimum link setting that: | ||||
3717 | * 1. is supported according to the link training result | ||||
3718 | * 2. could support the b/w requested by the timing | ||||
3719 | */ | ||||
3720 | while (current_link_setting.link_rate <= | ||||
3721 | link->verified_link_cap.link_rate) { | ||||
3722 | link_bw = dc_link_bandwidth_kbps( | ||||
3723 | link, | ||||
3724 | ¤t_link_setting); | ||||
3725 | if (req_bw <= link_bw) { | ||||
3726 | *link_setting = current_link_setting; | ||||
3727 | return true1; | ||||
3728 | } | ||||
3729 | |||||
3730 | if (current_link_setting.lane_count < | ||||
3731 | link->verified_link_cap.lane_count) { | ||||
3732 | current_link_setting.lane_count = | ||||
3733 | increase_lane_count( | ||||
3734 | current_link_setting.lane_count); | ||||
3735 | } else { | ||||
3736 | if (current_link_setting.link_rate_set < link->dpcd_caps.edp_supported_link_rates_count) { | ||||
3737 | current_link_setting.link_rate_set++; | ||||
3738 | current_link_setting.link_rate = | ||||
3739 | link->dpcd_caps.edp_supported_link_rates[current_link_setting.link_rate_set]; | ||||
3740 | current_link_setting.lane_count = | ||||
3741 | initial_link_setting.lane_count; | ||||
3742 | } else | ||||
3743 | break; | ||||
3744 | } | ||||
3745 | } | ||||
3746 | return false0; | ||||
3747 | } | ||||
3748 | |||||
3749 | static bool_Bool decide_edp_link_settings_with_dsc(struct dc_link *link, | ||||
3750 | struct dc_link_settings *link_setting, | ||||
3751 | uint32_t req_bw, | ||||
3752 | enum dc_link_rate max_link_rate) | ||||
3753 | { | ||||
3754 | struct dc_link_settings initial_link_setting; | ||||
3755 | struct dc_link_settings current_link_setting; | ||||
3756 | uint32_t link_bw; | ||||
3757 | |||||
3758 | unsigned int policy = 0; | ||||
3759 | |||||
3760 | policy = link->panel_config.dsc.force_dsc_edp_policy; | ||||
3761 | if (max_link_rate == LINK_RATE_UNKNOWN) | ||||
3762 | max_link_rate = link->verified_link_cap.link_rate; | ||||
3763 | /* | ||||
3764 | * edp_supported_link_rates_count is only valid for eDP v1.4 or higher. | ||||
3765 | * Per VESA eDP spec, "The DPCD revision for eDP v1.4 is 13h" | ||||
3766 | */ | ||||
3767 | if ((link->dpcd_caps.dpcd_rev.raw < DPCD_REV_13 || | ||||
3768 | link->dpcd_caps.edp_supported_link_rates_count == 0)) { | ||||
3769 | /* for DSC enabled case, we search for minimum lane count */ | ||||
3770 | memset(&initial_link_setting, 0, sizeof(initial_link_setting))__builtin_memset((&initial_link_setting), (0), (sizeof(initial_link_setting ))); | ||||
3771 | initial_link_setting.lane_count = LANE_COUNT_ONE; | ||||
3772 | initial_link_setting.link_rate = LINK_RATE_LOW; | ||||
3773 | initial_link_setting.link_spread = LINK_SPREAD_DISABLED; | ||||
3774 | initial_link_setting.use_link_rate_set = false0; | ||||
3775 | initial_link_setting.link_rate_set = 0; | ||||
3776 | current_link_setting = initial_link_setting; | ||||
3777 | if (req_bw > dc_link_bandwidth_kbps(link, &link->verified_link_cap)) | ||||
3778 | return false0; | ||||
3779 | |||||
3780 | /* search for the minimum link setting that: | ||||
3781 | * 1. is supported according to the link training result | ||||
3782 | * 2. could support the b/w requested by the timing | ||||
3783 | */ | ||||
3784 | while (current_link_setting.link_rate <= | ||||
3785 | max_link_rate) { | ||||
3786 | link_bw = dc_link_bandwidth_kbps( | ||||
3787 | link, | ||||
3788 | ¤t_link_setting); | ||||
3789 | if (req_bw <= link_bw) { | ||||
3790 | *link_setting = current_link_setting; | ||||
3791 | return true1; | ||||
3792 | } | ||||
3793 | if (policy) { | ||||
3794 | /* minimize lane */ | ||||
3795 | if (current_link_setting.link_rate < max_link_rate) { | ||||
3796 | current_link_setting.link_rate = | ||||
3797 | increase_link_rate(link, | ||||
3798 | current_link_setting.link_rate); | ||||
3799 | } else { | ||||
3800 | if (current_link_setting.lane_count < | ||||
3801 | link->verified_link_cap.lane_count) { | ||||
3802 | current_link_setting.lane_count = | ||||
3803 | increase_lane_count( | ||||
3804 | current_link_setting.lane_count); | ||||
3805 | current_link_setting.link_rate = initial_link_setting.link_rate; | ||||
3806 | } else | ||||
3807 | break; | ||||
3808 | } | ||||
3809 | } else { | ||||
3810 | /* minimize link rate */ | ||||
3811 | if (current_link_setting.lane_count < | ||||
3812 | link->verified_link_cap.lane_count) { | ||||
3813 | current_link_setting.lane_count = | ||||
3814 | increase_lane_count( | ||||
3815 | current_link_setting.lane_count); | ||||
3816 | } else { | ||||
3817 | current_link_setting.link_rate = | ||||
3818 | increase_link_rate(link, | ||||
3819 | current_link_setting.link_rate); | ||||
3820 | current_link_setting.lane_count = | ||||
3821 | initial_link_setting.lane_count; | ||||
3822 | } | ||||
3823 | } | ||||
3824 | } | ||||
3825 | return false0; | ||||
3826 | } | ||||
3827 | |||||
3828 | /* if optimize edp link is supported */ | ||||
3829 | memset(&initial_link_setting, 0, sizeof(initial_link_setting))__builtin_memset((&initial_link_setting), (0), (sizeof(initial_link_setting ))); | ||||
3830 | initial_link_setting.lane_count = LANE_COUNT_ONE; | ||||
3831 | initial_link_setting.link_rate = link->dpcd_caps.edp_supported_link_rates[0]; | ||||
3832 | initial_link_setting.link_spread = LINK_SPREAD_DISABLED; | ||||
3833 | initial_link_setting.use_link_rate_set = true1; | ||||
3834 | initial_link_setting.link_rate_set = 0; | ||||
3835 | current_link_setting = initial_link_setting; | ||||
3836 | |||||
3837 | /* search for the minimum link setting that: | ||||
3838 | * 1. is supported according to the link training result | ||||
3839 | * 2. could support the b/w requested by the timing | ||||
3840 | */ | ||||
3841 | while (current_link_setting.link_rate <= | ||||
3842 | max_link_rate) { | ||||
3843 | link_bw = dc_link_bandwidth_kbps( | ||||
3844 | link, | ||||
3845 | ¤t_link_setting); | ||||
3846 | if (req_bw <= link_bw) { | ||||
3847 | *link_setting = current_link_setting; | ||||
3848 | return true1; | ||||
3849 | } | ||||
3850 | if (policy) { | ||||
3851 | /* minimize lane */ | ||||
3852 | if (current_link_setting.link_rate_set < | ||||
3853 | link->dpcd_caps.edp_supported_link_rates_count | ||||
3854 | && current_link_setting.link_rate < max_link_rate) { | ||||
3855 | current_link_setting.link_rate_set++; | ||||
3856 | current_link_setting.link_rate = | ||||
3857 | link->dpcd_caps.edp_supported_link_rates[current_link_setting.link_rate_set]; | ||||
3858 | } else { | ||||
3859 | if (current_link_setting.lane_count < link->verified_link_cap.lane_count) { | ||||
3860 | current_link_setting.lane_count = | ||||
3861 | increase_lane_count( | ||||
3862 | current_link_setting.lane_count); | ||||
3863 | current_link_setting.link_rate_set = initial_link_setting.link_rate_set; | ||||
3864 | current_link_setting.link_rate = | ||||
3865 | link->dpcd_caps.edp_supported_link_rates[current_link_setting.link_rate_set]; | ||||
3866 | } else | ||||
3867 | break; | ||||
3868 | } | ||||
3869 | } else { | ||||
3870 | /* minimize link rate */ | ||||
3871 | if (current_link_setting.lane_count < | ||||
3872 | link->verified_link_cap.lane_count) { | ||||
3873 | current_link_setting.lane_count = | ||||
3874 | increase_lane_count( | ||||
3875 | current_link_setting.lane_count); | ||||
3876 | } else { | ||||
3877 | if (current_link_setting.link_rate_set < link->dpcd_caps.edp_supported_link_rates_count) { | ||||
3878 | current_link_setting.link_rate_set++; | ||||
3879 | current_link_setting.link_rate = | ||||
3880 | link->dpcd_caps.edp_supported_link_rates[current_link_setting.link_rate_set]; | ||||
3881 | current_link_setting.lane_count = | ||||
3882 | initial_link_setting.lane_count; | ||||
3883 | } else | ||||
3884 | break; | ||||
3885 | } | ||||
3886 | } | ||||
3887 | } | ||||
3888 | return false0; | ||||
3889 | } | ||||
3890 | |||||
3891 | static bool_Bool decide_mst_link_settings(const struct dc_link *link, struct dc_link_settings *link_setting) | ||||
3892 | { | ||||
3893 | *link_setting = link->verified_link_cap; | ||||
3894 | return true1; | ||||
3895 | } | ||||
3896 | |||||
3897 | bool_Bool decide_link_settings(struct dc_stream_state *stream, | ||||
3898 | struct dc_link_settings *link_setting) | ||||
3899 | { | ||||
3900 | struct dc_link *link = stream->link; | ||||
3901 | uint32_t req_bw = dc_bandwidth_in_kbps_from_timing(&stream->timing); | ||||
3902 | |||||
3903 | memset(link_setting, 0, sizeof(*link_setting))__builtin_memset((link_setting), (0), (sizeof(*link_setting)) ); | ||||
3904 | |||||
3905 | /* if preferred is specified through AMDDP, use it, if it's enough | ||||
3906 | * to drive the mode | ||||
3907 | */ | ||||
3908 | if (link->preferred_link_setting.lane_count != | ||||
3909 | LANE_COUNT_UNKNOWN && | ||||
3910 | link->preferred_link_setting.link_rate != | ||||
3911 | LINK_RATE_UNKNOWN) { | ||||
3912 | *link_setting = link->preferred_link_setting; | ||||
3913 | return true1; | ||||
3914 | } | ||||
3915 | |||||
3916 | /* MST doesn't perform link training for now | ||||
3917 | * TODO: add MST specific link training routine | ||||
3918 | */ | ||||
3919 | if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) { | ||||
3920 | decide_mst_link_settings(link, link_setting); | ||||
3921 | } else if (link->connector_signal == SIGNAL_TYPE_EDP) { | ||||
3922 | /* enable edp link optimization for DSC eDP case */ | ||||
3923 | if (stream->timing.flags.DSC) { | ||||
3924 | enum dc_link_rate max_link_rate = LINK_RATE_UNKNOWN; | ||||
3925 | |||||
3926 | if (link->panel_config.dsc.force_dsc_edp_policy) { | ||||
3927 | /* calculate link max link rate cap*/ | ||||
3928 | struct dc_link_settings tmp_link_setting; | ||||
3929 | struct dc_crtc_timing tmp_timing = stream->timing; | ||||
3930 | uint32_t orig_req_bw; | ||||
3931 | |||||
3932 | tmp_link_setting.link_rate = LINK_RATE_UNKNOWN; | ||||
3933 | tmp_timing.flags.DSC = 0; | ||||
3934 | orig_req_bw = dc_bandwidth_in_kbps_from_timing(&tmp_timing); | ||||
3935 | decide_edp_link_settings(link, &tmp_link_setting, orig_req_bw); | ||||
3936 | max_link_rate = tmp_link_setting.link_rate; | ||||
3937 | } | ||||
3938 | decide_edp_link_settings_with_dsc(link, link_setting, req_bw, max_link_rate); | ||||
3939 | } else { | ||||
3940 | decide_edp_link_settings(link, link_setting, req_bw); | ||||
3941 | } | ||||
3942 | } else { | ||||
3943 | decide_dp_link_settings(link, link_setting, req_bw); | ||||
3944 | } | ||||
3945 | |||||
3946 | return link_setting->lane_count != LANE_COUNT_UNKNOWN && | ||||
3947 | link_setting->link_rate != LINK_RATE_UNKNOWN; | ||||
3948 | } | ||||
3949 | |||||
3950 | /*************************Short Pulse IRQ***************************/ | ||||
3951 | bool_Bool dc_link_dp_allow_hpd_rx_irq(const struct dc_link *link) | ||||
3952 | { | ||||
3953 | /* | ||||
3954 | * Don't handle RX IRQ unless one of following is met: | ||||
3955 | * 1) The link is established (cur_link_settings != unknown) | ||||
3956 | * 2) We know we're dealing with a branch device, SST or MST | ||||
3957 | */ | ||||
3958 | |||||
3959 | if ((link->cur_link_settings.lane_count != LANE_COUNT_UNKNOWN) || | ||||
3960 | is_dp_branch_device(link)) | ||||
3961 | return true1; | ||||
3962 | |||||
3963 | return false0; | ||||
3964 | } | ||||
3965 | |||||
3966 | static bool_Bool handle_hpd_irq_psr_sink(struct dc_link *link) | ||||
3967 | { | ||||
3968 | union dpcd_psr_configuration psr_configuration; | ||||
3969 | |||||
3970 | if (!link->psr_settings.psr_feature_enabled) | ||||
3971 | return false0; | ||||
3972 | |||||
3973 | dm_helpers_dp_read_dpcd( | ||||
3974 | link->ctx, | ||||
3975 | link, | ||||
3976 | 368,/*DpcdAddress_PSR_Enable_Cfg*/ | ||||
3977 | &psr_configuration.raw, | ||||
3978 | sizeof(psr_configuration.raw)); | ||||
3979 | |||||
3980 | if (psr_configuration.bits.ENABLE) { | ||||
3981 | unsigned char dpcdbuf[3] = {0}; | ||||
3982 | union psr_error_status psr_error_status; | ||||
3983 | union psr_sink_psr_status psr_sink_psr_status; | ||||
3984 | |||||
3985 | dm_helpers_dp_read_dpcd( | ||||
3986 | link->ctx, | ||||
3987 | link, | ||||
3988 | 0x2006, /*DpcdAddress_PSR_Error_Status*/ | ||||
3989 | (unsigned char *) dpcdbuf, | ||||
3990 | sizeof(dpcdbuf)); | ||||
3991 | |||||
3992 | /*DPCD 2006h ERROR STATUS*/ | ||||
3993 | psr_error_status.raw = dpcdbuf[0]; | ||||
3994 | /*DPCD 2008h SINK PANEL SELF REFRESH STATUS*/ | ||||
3995 | psr_sink_psr_status.raw = dpcdbuf[2]; | ||||
3996 | |||||
3997 | if (psr_error_status.bits.LINK_CRC_ERROR || | ||||
3998 | psr_error_status.bits.RFB_STORAGE_ERROR || | ||||
3999 | psr_error_status.bits.VSC_SDP_ERROR) { | ||||
4000 | bool_Bool allow_active; | ||||
4001 | |||||
4002 | /* Acknowledge and clear error bits */ | ||||
4003 | dm_helpers_dp_write_dpcd( | ||||
4004 | link->ctx, | ||||
4005 | link, | ||||
4006 | 8198,/*DpcdAddress_PSR_Error_Status*/ | ||||
4007 | &psr_error_status.raw, | ||||
4008 | sizeof(psr_error_status.raw)); | ||||
4009 | |||||
4010 | /* PSR error, disable and re-enable PSR */ | ||||
4011 | if (link->psr_settings.psr_allow_active) { | ||||
4012 | allow_active = false0; | ||||
4013 | dc_link_set_psr_allow_active(link, &allow_active, true1, false0, NULL((void *)0)); | ||||
4014 | allow_active = true1; | ||||
4015 | dc_link_set_psr_allow_active(link, &allow_active, true1, false0, NULL((void *)0)); | ||||
4016 | } | ||||
4017 | |||||
4018 | return true1; | ||||
4019 | } else if (psr_sink_psr_status.bits.SINK_SELF_REFRESH_STATUS == | ||||
4020 | PSR_SINK_STATE_ACTIVE_DISPLAY_FROM_SINK_RFB){ | ||||
4021 | /* No error is detect, PSR is active. | ||||
4022 | * We should return with IRQ_HPD handled without | ||||
4023 | * checking for loss of sync since PSR would have | ||||
4024 | * powered down main link. | ||||
4025 | */ | ||||
4026 | return true1; | ||||
4027 | } | ||||
4028 | } | ||||
4029 | return false0; | ||||
4030 | } | ||||
4031 | |||||
4032 | static enum dc_link_rate get_link_rate_from_test_link_rate(uint8_t test_rate) | ||||
4033 | { | ||||
4034 | switch (test_rate) { | ||||
4035 | case DP_TEST_LINK_RATE_RBR: | ||||
4036 | return LINK_RATE_LOW; | ||||
4037 | case DP_TEST_LINK_RATE_HBR: | ||||
4038 | return LINK_RATE_HIGH; | ||||
4039 | case DP_TEST_LINK_RATE_HBR2: | ||||
4040 | return LINK_RATE_HIGH2; | ||||
4041 | case DP_TEST_LINK_RATE_HBR3: | ||||
4042 | return LINK_RATE_HIGH3; | ||||
4043 | case DP_TEST_LINK_RATE_UHBR10: | ||||
4044 | return LINK_RATE_UHBR10; | ||||
4045 | case DP_TEST_LINK_RATE_UHBR20: | ||||
4046 | return LINK_RATE_UHBR20; | ||||
4047 | case DP_TEST_LINK_RATE_UHBR13_5: | ||||
4048 | return LINK_RATE_UHBR13_5; | ||||
4049 | default: | ||||
4050 | return LINK_RATE_UNKNOWN; | ||||
4051 | } | ||||
4052 | } | ||||
4053 | |||||
4054 | static void dp_test_send_link_training(struct dc_link *link) | ||||
4055 | { | ||||
4056 | struct dc_link_settings link_settings = {0}; | ||||
4057 | uint8_t test_rate = 0; | ||||
4058 | |||||
4059 | core_link_read_dpcd( | ||||
4060 | link, | ||||
4061 | DP_TEST_LANE_COUNT0x220, | ||||
4062 | (unsigned char *)(&link_settings.lane_count), | ||||
4063 | 1); | ||||
4064 | core_link_read_dpcd( | ||||
4065 | link, | ||||
4066 | DP_TEST_LINK_RATE0x219, | ||||
4067 | &test_rate, | ||||
4068 | 1); | ||||
4069 | link_settings.link_rate = get_link_rate_from_test_link_rate(test_rate); | ||||
4070 | |||||
4071 | /* Set preferred link settings */ | ||||
4072 | link->verified_link_cap.lane_count = link_settings.lane_count; | ||||
4073 | link->verified_link_cap.link_rate = link_settings.link_rate; | ||||
4074 | |||||
4075 | dp_retrain_link_dp_test(link, &link_settings, false0); | ||||
4076 | } | ||||
4077 | |||||
4078 | /* TODO Raven hbr2 compliance eye output is unstable | ||||
4079 | * (toggling on and off) with debugger break | ||||
4080 | * This caueses intermittent PHY automation failure | ||||
4081 | * Need to look into the root cause */ | ||||
4082 | static void dp_test_send_phy_test_pattern(struct dc_link *link) | ||||
4083 | { | ||||
4084 | union phy_test_pattern dpcd_test_pattern; | ||||
4085 | union lane_adjust dpcd_lane_adjustment[2]; | ||||
4086 | unsigned char dpcd_post_cursor_2_adjustment = 0; | ||||
4087 | unsigned char test_pattern_buffer[ | ||||
4088 | (DP_TEST_264BIT_CUSTOM_PATTERN_263_2560x2250 - | ||||
4089 | DP_TEST_264BIT_CUSTOM_PATTERN_7_00x2230)+1] = {0}; | ||||
4090 | unsigned int test_pattern_size = 0; | ||||
4091 | enum dp_test_pattern test_pattern; | ||||
4092 | union lane_adjust dpcd_lane_adjust; | ||||
4093 | unsigned int lane; | ||||
4094 | struct link_training_settings link_training_settings; | ||||
4095 | |||||
4096 | dpcd_test_pattern.raw = 0; | ||||
4097 | memset(dpcd_lane_adjustment, 0, sizeof(dpcd_lane_adjustment))__builtin_memset((dpcd_lane_adjustment), (0), (sizeof(dpcd_lane_adjustment ))); | ||||
4098 | memset(&link_training_settings, 0, sizeof(link_training_settings))__builtin_memset((&link_training_settings), (0), (sizeof( link_training_settings))); | ||||
4099 | |||||
4100 | /* get phy test pattern and pattern parameters from DP receiver */ | ||||
4101 | core_link_read_dpcd( | ||||
4102 | link, | ||||
4103 | DP_PHY_TEST_PATTERN0x248, | ||||
4104 | &dpcd_test_pattern.raw, | ||||
4105 | sizeof(dpcd_test_pattern)); | ||||
4106 | core_link_read_dpcd( | ||||
4107 | link, | ||||
4108 | DP_ADJUST_REQUEST_LANE0_10x206, | ||||
4109 | &dpcd_lane_adjustment[0].raw, | ||||
4110 | sizeof(dpcd_lane_adjustment)); | ||||
4111 | |||||
4112 | /* prepare link training settings */ | ||||
4113 | link_training_settings.link_settings = link->cur_link_settings; | ||||
4114 | |||||
4115 | link_training_settings.lttpr_mode = dp_decide_lttpr_mode(link, &link->cur_link_settings); | ||||
4116 | |||||
4117 | if ((link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) && | ||||
4118 | link_training_settings.lttpr_mode == LTTPR_MODE_TRANSPARENT) | ||||
4119 | dp_fixed_vs_pe_read_lane_adjust( | ||||
4120 | link, | ||||
4121 | link_training_settings.dpcd_lane_settings); | ||||
4122 | |||||
4123 | /*get post cursor 2 parameters | ||||
4124 | * For DP 1.1a or eariler, this DPCD register's value is 0 | ||||
4125 | * For DP 1.2 or later: | ||||
4126 | * Bits 1:0 = POST_CURSOR2_LANE0; Bits 3:2 = POST_CURSOR2_LANE1 | ||||
4127 | * Bits 5:4 = POST_CURSOR2_LANE2; Bits 7:6 = POST_CURSOR2_LANE3 | ||||
4128 | */ | ||||
4129 | core_link_read_dpcd( | ||||
4130 | link, | ||||
4131 | DP_ADJUST_REQUEST_POST_CURSOR20x20c, | ||||
4132 | &dpcd_post_cursor_2_adjustment, | ||||
4133 | sizeof(dpcd_post_cursor_2_adjustment)); | ||||
4134 | |||||
4135 | /* translate request */ | ||||
4136 | switch (dpcd_test_pattern.bits.PATTERN) { | ||||
4137 | case PHY_TEST_PATTERN_D10_2: | ||||
4138 | test_pattern = DP_TEST_PATTERN_D102; | ||||
4139 | break; | ||||
4140 | case PHY_TEST_PATTERN_SYMBOL_ERROR: | ||||
4141 | test_pattern = DP_TEST_PATTERN_SYMBOL_ERROR; | ||||
4142 | break; | ||||
4143 | case PHY_TEST_PATTERN_PRBS7: | ||||
4144 | test_pattern = DP_TEST_PATTERN_PRBS7; | ||||
4145 | break; | ||||
4146 | case PHY_TEST_PATTERN_80BIT_CUSTOM: | ||||
4147 | test_pattern = DP_TEST_PATTERN_80BIT_CUSTOM; | ||||
4148 | break; | ||||
4149 | case PHY_TEST_PATTERN_CP2520_1: | ||||
4150 | /* CP2520 pattern is unstable, temporarily use TPS4 instead */ | ||||
4151 | test_pattern = (link->dc->caps.force_dp_tps4_for_cp2520 == 1) ? | ||||
4152 | DP_TEST_PATTERN_TRAINING_PATTERN4 : | ||||
4153 | DP_TEST_PATTERN_HBR2_COMPLIANCE_EYE; | ||||
4154 | break; | ||||
4155 | case PHY_TEST_PATTERN_CP2520_2: | ||||
4156 | /* CP2520 pattern is unstable, temporarily use TPS4 instead */ | ||||
4157 | test_pattern = (link->dc->caps.force_dp_tps4_for_cp2520 == 1) ? | ||||
4158 | DP_TEST_PATTERN_TRAINING_PATTERN4 : | ||||
4159 | DP_TEST_PATTERN_HBR2_COMPLIANCE_EYE; | ||||
4160 | break; | ||||
4161 | case PHY_TEST_PATTERN_CP2520_3: | ||||
4162 | test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN4; | ||||
4163 | break; | ||||
4164 | case PHY_TEST_PATTERN_128b_132b_TPS1: | ||||
4165 | test_pattern = DP_TEST_PATTERN_128b_132b_TPS1; | ||||
4166 | break; | ||||
4167 | case PHY_TEST_PATTERN_128b_132b_TPS2: | ||||
4168 | test_pattern = DP_TEST_PATTERN_128b_132b_TPS2; | ||||
4169 | break; | ||||
4170 | case PHY_TEST_PATTERN_PRBS9: | ||||
4171 | test_pattern = DP_TEST_PATTERN_PRBS9; | ||||
4172 | break; | ||||
4173 | case PHY_TEST_PATTERN_PRBS11: | ||||
4174 | test_pattern = DP_TEST_PATTERN_PRBS11; | ||||
4175 | break; | ||||
4176 | case PHY_TEST_PATTERN_PRBS15: | ||||
4177 | test_pattern = DP_TEST_PATTERN_PRBS15; | ||||
4178 | break; | ||||
4179 | case PHY_TEST_PATTERN_PRBS23: | ||||
4180 | test_pattern = DP_TEST_PATTERN_PRBS23; | ||||
4181 | break; | ||||
4182 | case PHY_TEST_PATTERN_PRBS31: | ||||
4183 | test_pattern = DP_TEST_PATTERN_PRBS31; | ||||
4184 | break; | ||||
4185 | case PHY_TEST_PATTERN_264BIT_CUSTOM: | ||||
4186 | test_pattern = DP_TEST_PATTERN_264BIT_CUSTOM; | ||||
4187 | break; | ||||
4188 | case PHY_TEST_PATTERN_SQUARE_PULSE: | ||||
4189 | test_pattern = DP_TEST_PATTERN_SQUARE_PULSE; | ||||
4190 | break; | ||||
4191 | default: | ||||
4192 | test_pattern = DP_TEST_PATTERN_VIDEO_MODE; | ||||
4193 | break; | ||||
4194 | } | ||||
4195 | |||||
4196 | if (test_pattern == DP_TEST_PATTERN_80BIT_CUSTOM) { | ||||
4197 | test_pattern_size = (DP_TEST_80BIT_CUSTOM_PATTERN_79_720x259 - | ||||
4198 | DP_TEST_80BIT_CUSTOM_PATTERN_7_00x250) + 1; | ||||
4199 | core_link_read_dpcd( | ||||
4200 | link, | ||||
4201 | DP_TEST_80BIT_CUSTOM_PATTERN_7_00x250, | ||||
4202 | test_pattern_buffer, | ||||
4203 | test_pattern_size); | ||||
4204 | } | ||||
4205 | |||||
4206 | if (test_pattern == DP_TEST_PATTERN_SQUARE_PULSE) { | ||||
4207 | test_pattern_size = 1; // Square pattern data is 1 byte (DP spec) | ||||
4208 | core_link_read_dpcd( | ||||
4209 | link, | ||||
4210 | DP_PHY_SQUARE_PATTERN0x249, | ||||
4211 | test_pattern_buffer, | ||||
4212 | test_pattern_size); | ||||
4213 | } | ||||
4214 | |||||
4215 | if (test_pattern == DP_TEST_PATTERN_264BIT_CUSTOM) { | ||||
4216 | test_pattern_size = (DP_TEST_264BIT_CUSTOM_PATTERN_263_2560x2250- | ||||
4217 | DP_TEST_264BIT_CUSTOM_PATTERN_7_00x2230) + 1; | ||||
4218 | core_link_read_dpcd( | ||||
4219 | link, | ||||
4220 | DP_TEST_264BIT_CUSTOM_PATTERN_7_00x2230, | ||||
4221 | test_pattern_buffer, | ||||
4222 | test_pattern_size); | ||||
4223 | } | ||||
4224 | |||||
4225 | for (lane = 0; lane < | ||||
4226 | (unsigned int)(link->cur_link_settings.lane_count); | ||||
4227 | lane++) { | ||||
4228 | dpcd_lane_adjust.raw = | ||||
4229 | get_nibble_at_index(&dpcd_lane_adjustment[0].raw, lane); | ||||
4230 | if (dp_get_link_encoding_format(&link->cur_link_settings) == | ||||
4231 | DP_8b_10b_ENCODING) { | ||||
4232 | link_training_settings.hw_lane_settings[lane].VOLTAGE_SWING = | ||||
4233 | (enum dc_voltage_swing) | ||||
4234 | (dpcd_lane_adjust.bits.VOLTAGE_SWING_LANE); | ||||
4235 | link_training_settings.hw_lane_settings[lane].PRE_EMPHASIS = | ||||
4236 | (enum dc_pre_emphasis) | ||||
4237 | (dpcd_lane_adjust.bits.PRE_EMPHASIS_LANE); | ||||
4238 | link_training_settings.hw_lane_settings[lane].POST_CURSOR2 = | ||||
4239 | (enum dc_post_cursor2) | ||||
4240 | ((dpcd_post_cursor_2_adjustment >> (lane * 2)) & 0x03); | ||||
4241 | } else if (dp_get_link_encoding_format(&link->cur_link_settings) == | ||||
4242 | DP_128b_132b_ENCODING) { | ||||
4243 | link_training_settings.hw_lane_settings[lane].FFE_PRESET.raw = | ||||
4244 | dpcd_lane_adjust.tx_ffe.PRESET_VALUE; | ||||
4245 | } | ||||
4246 | } | ||||
4247 | |||||
4248 | dp_hw_to_dpcd_lane_settings(&link_training_settings, | ||||
4249 | link_training_settings.hw_lane_settings, | ||||
4250 | link_training_settings.dpcd_lane_settings); | ||||
4251 | /*Usage: Measure DP physical lane signal | ||||
4252 | * by DP SI test equipment automatically. | ||||
4253 | * PHY test pattern request is generated by equipment via HPD interrupt. | ||||
4254 | * HPD needs to be active all the time. HPD should be active | ||||
4255 | * all the time. Do not touch it. | ||||
4256 | * forward request to DS | ||||
4257 | */ | ||||
4258 | dc_link_dp_set_test_pattern( | ||||
4259 | link, | ||||
4260 | test_pattern, | ||||
4261 | DP_TEST_PATTERN_COLOR_SPACE_UNDEFINED, | ||||
4262 | &link_training_settings, | ||||
4263 | test_pattern_buffer, | ||||
4264 | test_pattern_size); | ||||
4265 | } | ||||
4266 | |||||
4267 | static void dp_test_get_audio_test_data(struct dc_link *link, bool_Bool disable_video) | ||||
4268 | { | ||||
4269 | union audio_test_mode dpcd_test_mode = {0}; | ||||
4270 | struct audio_test_pattern_type dpcd_pattern_type = {0}; | ||||
4271 | union audio_test_pattern_period dpcd_pattern_period[AUDIO_CHANNELS_COUNT] = {0}; | ||||
4272 | enum dp_test_pattern test_pattern = DP_TEST_PATTERN_AUDIO_OPERATOR_DEFINED; | ||||
4273 | |||||
4274 | struct pipe_ctx *pipes = link->dc->current_state->res_ctx.pipe_ctx; | ||||
4275 | struct pipe_ctx *pipe_ctx = &pipes[0]; | ||||
4276 | unsigned int channel_count; | ||||
4277 | unsigned int channel = 0; | ||||
4278 | unsigned int modes = 0; | ||||
4279 | unsigned int sampling_rate_in_hz = 0; | ||||
4280 | |||||
4281 | // get audio test mode and test pattern parameters | ||||
4282 | core_link_read_dpcd( | ||||
4283 | link, | ||||
4284 | DP_TEST_AUDIO_MODE0x271, | ||||
4285 | &dpcd_test_mode.raw, | ||||
4286 | sizeof(dpcd_test_mode)); | ||||
4287 | |||||
4288 | core_link_read_dpcd( | ||||
4289 | link, | ||||
4290 | DP_TEST_AUDIO_PATTERN_TYPE0x272, | ||||
4291 | &dpcd_pattern_type.value, | ||||
4292 | sizeof(dpcd_pattern_type)); | ||||
4293 | |||||
4294 | channel_count = min(dpcd_test_mode.bits.channel_count + 1, AUDIO_CHANNELS_COUNT)(((dpcd_test_mode.bits.channel_count + 1)<(AUDIO_CHANNELS_COUNT ))?(dpcd_test_mode.bits.channel_count + 1):(AUDIO_CHANNELS_COUNT )); | ||||
4295 | |||||
4296 | // read pattern periods for requested channels when sawTooth pattern is requested | ||||
4297 | if (dpcd_pattern_type.value == AUDIO_TEST_PATTERN_SAWTOOTH || | ||||
4298 | dpcd_pattern_type.value == AUDIO_TEST_PATTERN_OPERATOR_DEFINED) { | ||||
4299 | |||||
4300 | test_pattern = (dpcd_pattern_type.value == AUDIO_TEST_PATTERN_SAWTOOTH) ? | ||||
4301 | DP_TEST_PATTERN_AUDIO_SAWTOOTH : DP_TEST_PATTERN_AUDIO_OPERATOR_DEFINED; | ||||
4302 | // read period for each channel | ||||
4303 | for (channel = 0; channel < channel_count; channel++) { | ||||
4304 | core_link_read_dpcd( | ||||
4305 | link, | ||||
4306 | DP_TEST_AUDIO_PERIOD_CH10x273 + channel, | ||||
4307 | &dpcd_pattern_period[channel].raw, | ||||
4308 | sizeof(dpcd_pattern_period[channel])); | ||||
4309 | } | ||||
4310 | } | ||||
4311 | |||||
4312 | // translate sampling rate | ||||
4313 | switch (dpcd_test_mode.bits.sampling_rate) { | ||||
4314 | case AUDIO_SAMPLING_RATE_32KHZ: | ||||
4315 | sampling_rate_in_hz = 32000; | ||||
4316 | break; | ||||
4317 | case AUDIO_SAMPLING_RATE_44_1KHZ: | ||||
4318 | sampling_rate_in_hz = 44100; | ||||
4319 | break; | ||||
4320 | case AUDIO_SAMPLING_RATE_48KHZ: | ||||
4321 | sampling_rate_in_hz = 48000; | ||||
4322 | break; | ||||
4323 | case AUDIO_SAMPLING_RATE_88_2KHZ: | ||||
4324 | sampling_rate_in_hz = 88200; | ||||
4325 | break; | ||||
4326 | case AUDIO_SAMPLING_RATE_96KHZ: | ||||
4327 | sampling_rate_in_hz = 96000; | ||||
4328 | break; | ||||
4329 | case AUDIO_SAMPLING_RATE_176_4KHZ: | ||||
4330 | sampling_rate_in_hz = 176400; | ||||
4331 | break; | ||||
4332 | case AUDIO_SAMPLING_RATE_192KHZ: | ||||
4333 | sampling_rate_in_hz = 192000; | ||||
4334 | break; | ||||
4335 | default: | ||||
4336 | sampling_rate_in_hz = 0; | ||||
4337 | break; | ||||
4338 | } | ||||
4339 | |||||
4340 | link->audio_test_data.flags.test_requested = 1; | ||||
4341 | link->audio_test_data.flags.disable_video = disable_video; | ||||
4342 | link->audio_test_data.sampling_rate = sampling_rate_in_hz; | ||||
4343 | link->audio_test_data.channel_count = channel_count; | ||||
4344 | link->audio_test_data.pattern_type = test_pattern; | ||||
4345 | |||||
4346 | if (test_pattern == DP_TEST_PATTERN_AUDIO_SAWTOOTH) { | ||||
4347 | for (modes = 0; modes < pipe_ctx->stream->audio_info.mode_count; modes++) { | ||||
4348 | link->audio_test_data.pattern_period[modes] = dpcd_pattern_period[modes].bits.pattern_period; | ||||
4349 | } | ||||
4350 | } | ||||
4351 | } | ||||
4352 | |||||
4353 | void dc_link_dp_handle_automated_test(struct dc_link *link) | ||||
4354 | { | ||||
4355 | union test_request test_request; | ||||
4356 | union test_response test_response; | ||||
4357 | |||||
4358 | memset(&test_request, 0, sizeof(test_request))__builtin_memset((&test_request), (0), (sizeof(test_request ))); | ||||
4359 | memset(&test_response, 0, sizeof(test_response))__builtin_memset((&test_response), (0), (sizeof(test_response ))); | ||||
4360 | |||||
4361 | core_link_read_dpcd( | ||||
4362 | link, | ||||
4363 | DP_TEST_REQUEST0x218, | ||||
4364 | &test_request.raw, | ||||
4365 | sizeof(union test_request)); | ||||
4366 | if (test_request.bits.LINK_TRAINING) { | ||||
4367 | /* ACK first to let DP RX test box monitor LT sequence */ | ||||
4368 | test_response.bits.ACK = 1; | ||||
4369 | core_link_write_dpcd( | ||||
4370 | link, | ||||
4371 | DP_TEST_RESPONSE0x260, | ||||
4372 | &test_response.raw, | ||||
4373 | sizeof(test_response)); | ||||
4374 | dp_test_send_link_training(link); | ||||
4375 | /* no acknowledge request is needed again */ | ||||
4376 | test_response.bits.ACK = 0; | ||||
4377 | } | ||||
4378 | if (test_request.bits.LINK_TEST_PATTRN) { | ||||
4379 | union test_misc dpcd_test_params; | ||||
4380 | union link_test_pattern dpcd_test_pattern; | ||||
4381 | |||||
4382 | memset(&dpcd_test_pattern, 0, sizeof(dpcd_test_pattern))__builtin_memset((&dpcd_test_pattern), (0), (sizeof(dpcd_test_pattern ))); | ||||
4383 | memset(&dpcd_test_params, 0, sizeof(dpcd_test_params))__builtin_memset((&dpcd_test_params), (0), (sizeof(dpcd_test_params ))); | ||||
4384 | |||||
4385 | /* get link test pattern and pattern parameters */ | ||||
4386 | core_link_read_dpcd( | ||||
4387 | link, | ||||
4388 | DP_TEST_PATTERN0x221, | ||||
4389 | &dpcd_test_pattern.raw, | ||||
4390 | sizeof(dpcd_test_pattern)); | ||||
4391 | core_link_read_dpcd( | ||||
4392 | link, | ||||
4393 | DP_TEST_MISC00x232, | ||||
4394 | &dpcd_test_params.raw, | ||||
4395 | sizeof(dpcd_test_params)); | ||||
4396 | test_response.bits.ACK = dm_helpers_dp_handle_test_pattern_request(link->ctx, link, | ||||
4397 | dpcd_test_pattern, dpcd_test_params) ? 1 : 0; | ||||
4398 | } | ||||
4399 | |||||
4400 | if (test_request.bits.AUDIO_TEST_PATTERN) { | ||||
4401 | dp_test_get_audio_test_data(link, test_request.bits.TEST_AUDIO_DISABLED_VIDEO); | ||||
4402 | test_response.bits.ACK = 1; | ||||
4403 | } | ||||
4404 | |||||
4405 | if (test_request.bits.PHY_TEST_PATTERN) { | ||||
4406 | dp_test_send_phy_test_pattern(link); | ||||
4407 | test_response.bits.ACK = 1; | ||||
4408 | } | ||||
4409 | |||||
4410 | /* send request acknowledgment */ | ||||
4411 | if (test_response.bits.ACK) | ||||
4412 | core_link_write_dpcd( | ||||
4413 | link, | ||||
4414 | DP_TEST_RESPONSE0x260, | ||||
4415 | &test_response.raw, | ||||
4416 | sizeof(test_response)); | ||||
4417 | } | ||||
4418 | |||||
4419 | void dc_link_dp_handle_link_loss(struct dc_link *link) | ||||
4420 | { | ||||
4421 | int i; | ||||
4422 | struct pipe_ctx *pipe_ctx; | ||||
4423 | |||||
4424 | for (i = 0; i < MAX_PIPES6; i++) { | ||||
4425 | pipe_ctx = &link->dc->current_state->res_ctx.pipe_ctx[i]; | ||||
4426 | if (pipe_ctx && pipe_ctx->stream && pipe_ctx->stream->link == link) | ||||
4427 | break; | ||||
4428 | } | ||||
4429 | |||||
4430 | if (pipe_ctx == NULL((void *)0) || pipe_ctx->stream == NULL((void *)0)) | ||||
4431 | return; | ||||
4432 | |||||
4433 | for (i = 0; i < MAX_PIPES6; i++) { | ||||
4434 | pipe_ctx = &link->dc->current_state->res_ctx.pipe_ctx[i]; | ||||
4435 | if (pipe_ctx && pipe_ctx->stream && !pipe_ctx->stream->dpms_off && | ||||
4436 | pipe_ctx->stream->link == link && !pipe_ctx->prev_odm_pipe) | ||||
4437 | core_link_disable_stream(pipe_ctx); | ||||
4438 | } | ||||
4439 | |||||
4440 | for (i = 0; i < MAX_PIPES6; i++) { | ||||
4441 | pipe_ctx = &link->dc->current_state->res_ctx.pipe_ctx[i]; | ||||
4442 | if (pipe_ctx && pipe_ctx->stream && !pipe_ctx->stream->dpms_off && | ||||
4443 | pipe_ctx->stream->link == link && !pipe_ctx->prev_odm_pipe) | ||||
4444 | core_link_enable_stream(link->dc->current_state, pipe_ctx); | ||||
4445 | } | ||||
4446 | } | ||||
4447 | |||||
4448 | bool_Bool dc_link_handle_hpd_rx_irq(struct dc_link *link, union hpd_irq_data *out_hpd_irq_dpcd_data, bool_Bool *out_link_loss, | ||||
4449 | bool_Bool defer_handling, bool_Bool *has_left_work) | ||||
4450 | { | ||||
4451 | union hpd_irq_data hpd_irq_dpcd_data = {0}; | ||||
4452 | union device_service_irq device_service_clear = {0}; | ||||
4453 | enum dc_status result; | ||||
4454 | bool_Bool status = false0; | ||||
4455 | |||||
4456 | if (out_link_loss) | ||||
4457 | *out_link_loss = false0; | ||||
4458 | |||||
4459 | if (has_left_work) | ||||
4460 | *has_left_work = false0; | ||||
4461 | /* For use cases related to down stream connection status change, | ||||
4462 | * PSR and device auto test, refer to function handle_sst_hpd_irq | ||||
4463 | * in DAL2.1*/ | ||||
4464 | |||||
4465 | DC_LOG_HW_HPD_IRQ("%s: Got short pulse HPD on link %d\n",___drm_dbg(((void *)0), DRM_UT_KMS, "%s: Got short pulse HPD on link %d\n" , __func__, link->link_index) | ||||
4466 | __func__, link->link_index)___drm_dbg(((void *)0), DRM_UT_KMS, "%s: Got short pulse HPD on link %d\n" , __func__, link->link_index); | ||||
4467 | |||||
4468 | |||||
4469 | /* All the "handle_hpd_irq_xxx()" methods | ||||
4470 | * should be called only after | ||||
4471 | * dal_dpsst_ls_read_hpd_irq_data | ||||
4472 | * Order of calls is important too | ||||
4473 | */ | ||||
4474 | result = read_hpd_rx_irq_data(link, &hpd_irq_dpcd_data); | ||||
4475 | if (out_hpd_irq_dpcd_data) | ||||
4476 | *out_hpd_irq_dpcd_data = hpd_irq_dpcd_data; | ||||
4477 | |||||
4478 | if (result != DC_OK) { | ||||
4479 | DC_LOG_HW_HPD_IRQ("%s: DPCD read failed to obtain irq data\n",___drm_dbg(((void *)0), DRM_UT_KMS, "%s: DPCD read failed to obtain irq data\n" , __func__) | ||||
4480 | __func__)___drm_dbg(((void *)0), DRM_UT_KMS, "%s: DPCD read failed to obtain irq data\n" , __func__); | ||||
4481 | return false0; | ||||
4482 | } | ||||
4483 | |||||
4484 | if (hpd_irq_dpcd_data.bytes.device_service_irq.bits.AUTOMATED_TEST) { | ||||
4485 | device_service_clear.bits.AUTOMATED_TEST = 1; | ||||
4486 | core_link_write_dpcd( | ||||
4487 | link, | ||||
4488 | DP_DEVICE_SERVICE_IRQ_VECTOR0x201, | ||||
4489 | &device_service_clear.raw, | ||||
4490 | sizeof(device_service_clear.raw)); | ||||
4491 | device_service_clear.raw = 0; | ||||
4492 | if (defer_handling && has_left_work) | ||||
4493 | *has_left_work = true1; | ||||
4494 | else | ||||
4495 | dc_link_dp_handle_automated_test(link); | ||||
4496 | return false0; | ||||
4497 | } | ||||
4498 | |||||
4499 | if (!dc_link_dp_allow_hpd_rx_irq(link)) { | ||||
4500 | DC_LOG_HW_HPD_IRQ("%s: skipping HPD handling on %d\n",___drm_dbg(((void *)0), DRM_UT_KMS, "%s: skipping HPD handling on %d\n" , __func__, link->link_index) | ||||
4501 | __func__, link->link_index)___drm_dbg(((void *)0), DRM_UT_KMS, "%s: skipping HPD handling on %d\n" , __func__, link->link_index); | ||||
4502 | return false0; | ||||
4503 | } | ||||
4504 | |||||
4505 | if (handle_hpd_irq_psr_sink(link)) | ||||
4506 | /* PSR-related error was detected and handled */ | ||||
4507 | return true1; | ||||
4508 | |||||
4509 | /* If PSR-related error handled, Main link may be off, | ||||
4510 | * so do not handle as a normal sink status change interrupt. | ||||
4511 | */ | ||||
4512 | |||||
4513 | if (hpd_irq_dpcd_data.bytes.device_service_irq.bits.UP_REQ_MSG_RDY) { | ||||
4514 | if (defer_handling && has_left_work) | ||||
4515 | *has_left_work = true1; | ||||
4516 | return true1; | ||||
4517 | } | ||||
4518 | |||||
4519 | /* check if we have MST msg and return since we poll for it */ | ||||
4520 | if (hpd_irq_dpcd_data.bytes.device_service_irq.bits.DOWN_REP_MSG_RDY) { | ||||
4521 | if (defer_handling && has_left_work) | ||||
4522 | *has_left_work = true1; | ||||
4523 | return false0; | ||||
4524 | } | ||||
4525 | |||||
4526 | /* For now we only handle 'Downstream port status' case. | ||||
4527 | * If we got sink count changed it means | ||||
4528 | * Downstream port status changed, | ||||
4529 | * then DM should call DC to do the detection. | ||||
4530 | * NOTE: Do not handle link loss on eDP since it is internal link*/ | ||||
4531 | if ((link->connector_signal != SIGNAL_TYPE_EDP) && | ||||
4532 | hpd_rx_irq_check_link_loss_status( | ||||
4533 | link, | ||||
4534 | &hpd_irq_dpcd_data)) { | ||||
4535 | /* Connectivity log: link loss */ | ||||
4536 | CONN_DATA_LINK_LOSS(link,do { (void)(link); ___drm_dbg(((void *)0), DRM_UT_KMS, "Status: " ); } while (0) | ||||
4537 | hpd_irq_dpcd_data.raw,do { (void)(link); ___drm_dbg(((void *)0), DRM_UT_KMS, "Status: " ); } while (0) | ||||
4538 | sizeof(hpd_irq_dpcd_data),do { (void)(link); ___drm_dbg(((void *)0), DRM_UT_KMS, "Status: " ); } while (0) | ||||
4539 | "Status: ")do { (void)(link); ___drm_dbg(((void *)0), DRM_UT_KMS, "Status: " ); } while (0); | ||||
4540 | |||||
4541 | if (defer_handling && has_left_work) | ||||
4542 | *has_left_work = true1; | ||||
4543 | else | ||||
4544 | dc_link_dp_handle_link_loss(link); | ||||
4545 | |||||
4546 | status = false0; | ||||
4547 | if (out_link_loss) | ||||
4548 | *out_link_loss = true1; | ||||
4549 | |||||
4550 | dp_trace_link_loss_increment(link); | ||||
4551 | } | ||||
4552 | |||||
4553 | if (link->type == dc_connection_sst_branch && | ||||
4554 | hpd_irq_dpcd_data.bytes.sink_cnt.bits.SINK_COUNT | ||||
4555 | != link->dpcd_sink_count) | ||||
4556 | status = true1; | ||||
4557 | |||||
4558 | /* reasons for HPD RX: | ||||
4559 | * 1. Link Loss - ie Re-train the Link | ||||
4560 | * 2. MST sideband message | ||||
4561 | * 3. Automated Test - ie. Internal Commit | ||||
4562 | * 4. CP (copy protection) - (not interesting for DM???) | ||||
4563 | * 5. DRR | ||||
4564 | * 6. Downstream Port status changed | ||||
4565 | * -ie. Detect - this the only one | ||||
4566 | * which is interesting for DM because | ||||
4567 | * it must call dc_link_detect. | ||||
4568 | */ | ||||
4569 | return status; | ||||
4570 | } | ||||
4571 | |||||
4572 | /*query dpcd for version and mst cap addresses*/ | ||||
4573 | bool_Bool is_mst_supported(struct dc_link *link) | ||||
4574 | { | ||||
4575 | bool_Bool mst = false0; | ||||
4576 | enum dc_status st = DC_OK; | ||||
4577 | union dpcd_rev rev; | ||||
4578 | union mstm_cap cap; | ||||
4579 | |||||
4580 | if (link->preferred_training_settings.mst_enable && | ||||
4581 | *link->preferred_training_settings.mst_enable == false0) { | ||||
4582 | return false0; | ||||
4583 | } | ||||
4584 | |||||
4585 | rev.raw = 0; | ||||
4586 | cap.raw = 0; | ||||
4587 | |||||
4588 | st = core_link_read_dpcd(link, DP_DPCD_REV0x000, &rev.raw, | ||||
4589 | sizeof(rev)); | ||||
4590 | |||||
4591 | if (st == DC_OK && rev.raw >= DPCD_REV_12) { | ||||
4592 | |||||
4593 | st = core_link_read_dpcd(link, DP_MSTM_CAP0x021, | ||||
4594 | &cap.raw, sizeof(cap)); | ||||
4595 | if (st == DC_OK && cap.bits.MST_CAP == 1) | ||||
4596 | mst = true1; | ||||
4597 | } | ||||
4598 | return mst; | ||||
4599 | |||||
4600 | } | ||||
4601 | |||||
4602 | bool_Bool is_dp_active_dongle(const struct dc_link *link) | ||||
4603 | { | ||||
4604 | return (link->dpcd_caps.dongle_type >= DISPLAY_DONGLE_DP_VGA_CONVERTER) && | ||||
4605 | (link->dpcd_caps.dongle_type <= DISPLAY_DONGLE_DP_HDMI_CONVERTER); | ||||
4606 | } | ||||
4607 | |||||
4608 | bool_Bool is_dp_branch_device(const struct dc_link *link) | ||||
4609 | { | ||||
4610 | return link->dpcd_caps.is_branch_dev; | ||||
4611 | } | ||||
4612 | |||||
4613 | static int translate_dpcd_max_bpc(enum dpcd_downstream_port_max_bpc bpc) | ||||
4614 | { | ||||
4615 | switch (bpc) { | ||||
4616 | case DOWN_STREAM_MAX_8BPC: | ||||
4617 | return 8; | ||||
4618 | case DOWN_STREAM_MAX_10BPC: | ||||
4619 | return 10; | ||||
4620 | case DOWN_STREAM_MAX_12BPC: | ||||
4621 | return 12; | ||||
4622 | case DOWN_STREAM_MAX_16BPC: | ||||
4623 | return 16; | ||||
4624 | default: | ||||
4625 | break; | ||||
4626 | } | ||||
4627 | |||||
4628 | return -1; | ||||
4629 | } | ||||
4630 | |||||
4631 | #if defined(CONFIG_DRM_AMD_DC_DCN1) | ||||
4632 | uint32_t dc_link_bw_kbps_from_raw_frl_link_rate_data(uint8_t bw) | ||||
4633 | { | ||||
4634 | switch (bw) { | ||||
4635 | case 0b001: | ||||
4636 | return 9000000; | ||||
4637 | case 0b010: | ||||
4638 | return 18000000; | ||||
4639 | case 0b011: | ||||
4640 | return 24000000; | ||||
4641 | case 0b100: | ||||
4642 | return 32000000; | ||||
4643 | case 0b101: | ||||
4644 | return 40000000; | ||||
4645 | case 0b110: | ||||
4646 | return 48000000; | ||||
4647 | } | ||||
4648 | |||||
4649 | return 0; | ||||
4650 | } | ||||
4651 | |||||
4652 | /* | ||||
4653 | * Return PCON's post FRL link training supported BW if its non-zero, otherwise return max_supported_frl_bw. | ||||
4654 | */ | ||||
4655 | static uint32_t intersect_frl_link_bw_support( | ||||
4656 | const uint32_t max_supported_frl_bw_in_kbps, | ||||
4657 | const union hdmi_encoded_link_bw hdmi_encoded_link_bw) | ||||
4658 | { | ||||
4659 | uint32_t supported_bw_in_kbps = max_supported_frl_bw_in_kbps; | ||||
4660 | |||||
4661 | // HDMI_ENCODED_LINK_BW bits are only valid if HDMI Link Configuration bit is 1 (FRL mode) | ||||
4662 | if (hdmi_encoded_link_bw.bits.FRL_MODE) { | ||||
4663 | if (hdmi_encoded_link_bw.bits.BW_48Gbps) | ||||
4664 | supported_bw_in_kbps = 48000000; | ||||
4665 | else if (hdmi_encoded_link_bw.bits.BW_40Gbps) | ||||
4666 | supported_bw_in_kbps = 40000000; | ||||
4667 | else if (hdmi_encoded_link_bw.bits.BW_32Gbps) | ||||
4668 | supported_bw_in_kbps = 32000000; | ||||
4669 | else if (hdmi_encoded_link_bw.bits.BW_24Gbps) | ||||
4670 | supported_bw_in_kbps = 24000000; | ||||
4671 | else if (hdmi_encoded_link_bw.bits.BW_18Gbps) | ||||
4672 | supported_bw_in_kbps = 18000000; | ||||
4673 | else if (hdmi_encoded_link_bw.bits.BW_9Gbps) | ||||
4674 | supported_bw_in_kbps = 9000000; | ||||
4675 | } | ||||
4676 | |||||
4677 | return supported_bw_in_kbps; | ||||
4678 | } | ||||
4679 | #endif | ||||
4680 | |||||
4681 | static void read_dp_device_vendor_id(struct dc_link *link) | ||||
4682 | { | ||||
4683 | struct dp_device_vendor_id dp_id; | ||||
4684 | |||||
4685 | /* read IEEE branch device id */ | ||||
4686 | core_link_read_dpcd( | ||||
4687 | link, | ||||
4688 | DP_BRANCH_OUI0x500, | ||||
4689 | (uint8_t *)&dp_id, | ||||
4690 | sizeof(dp_id)); | ||||
4691 | |||||
4692 | link->dpcd_caps.branch_dev_id = | ||||
4693 | (dp_id.ieee_oui[0] << 16) + | ||||
4694 | (dp_id.ieee_oui[1] << 8) + | ||||
4695 | dp_id.ieee_oui[2]; | ||||
4696 | |||||
4697 | memmove(__builtin_memmove((link->dpcd_caps.branch_dev_name), (dp_id .ieee_device_id), (sizeof(dp_id.ieee_device_id))) | ||||
4698 | link->dpcd_caps.branch_dev_name,__builtin_memmove((link->dpcd_caps.branch_dev_name), (dp_id .ieee_device_id), (sizeof(dp_id.ieee_device_id))) | ||||
4699 | dp_id.ieee_device_id,__builtin_memmove((link->dpcd_caps.branch_dev_name), (dp_id .ieee_device_id), (sizeof(dp_id.ieee_device_id))) | ||||
4700 | sizeof(dp_id.ieee_device_id))__builtin_memmove((link->dpcd_caps.branch_dev_name), (dp_id .ieee_device_id), (sizeof(dp_id.ieee_device_id))); | ||||
4701 | } | ||||
4702 | |||||
4703 | |||||
4704 | |||||
4705 | static void get_active_converter_info( | ||||
4706 | uint8_t data, struct dc_link *link) | ||||
4707 | { | ||||
4708 | union dp_downstream_port_present ds_port = { .byte = data }; | ||||
4709 | memset(&link->dpcd_caps.dongle_caps, 0, sizeof(link->dpcd_caps.dongle_caps))__builtin_memset((&link->dpcd_caps.dongle_caps), (0), ( sizeof(link->dpcd_caps.dongle_caps))); | ||||
4710 | |||||
4711 | /* decode converter info*/ | ||||
4712 | if (!ds_port.fields.PORT_PRESENT) { | ||||
4713 | link->dpcd_caps.dongle_type = DISPLAY_DONGLE_NONE; | ||||
4714 | ddc_service_set_dongle_type(link->ddc, | ||||
4715 | link->dpcd_caps.dongle_type); | ||||
4716 | link->dpcd_caps.is_branch_dev = false0; | ||||
4717 | return; | ||||
4718 | } | ||||
4719 | |||||
4720 | /* DPCD 0x5 bit 0 = 1, it indicate it's branch device */ | ||||
4721 | link->dpcd_caps.is_branch_dev = ds_port.fields.PORT_PRESENT; | ||||
4722 | |||||
4723 | switch (ds_port.fields.PORT_TYPE) { | ||||
4724 | case DOWNSTREAM_VGA: | ||||
4725 | link->dpcd_caps.dongle_type = DISPLAY_DONGLE_DP_VGA_CONVERTER; | ||||
4726 | break; | ||||
4727 | case DOWNSTREAM_DVI_HDMI_DP_PLUS_PLUS: | ||||
4728 | /* At this point we don't know is it DVI or HDMI or DP++, | ||||
4729 | * assume DVI.*/ | ||||
4730 | link->dpcd_caps.dongle_type = DISPLAY_DONGLE_DP_DVI_CONVERTER; | ||||
4731 | break; | ||||
4732 | default: | ||||
4733 | link->dpcd_caps.dongle_type = DISPLAY_DONGLE_NONE; | ||||
4734 | break; | ||||
4735 | } | ||||
4736 | |||||
4737 | if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_11) { | ||||
4738 | uint8_t det_caps[16]; /* CTS 4.2.2.7 expects source to read Detailed Capabilities Info : 00080h-0008F.*/ | ||||
4739 | union dwnstream_port_caps_byte0 *port_caps = | ||||
4740 | (union dwnstream_port_caps_byte0 *)det_caps; | ||||
4741 | if (core_link_read_dpcd(link, DP_DOWNSTREAM_PORT_00x80, | ||||
4742 | det_caps, sizeof(det_caps)) == DC_OK) { | ||||
4743 | |||||
4744 | switch (port_caps->bits.DWN_STRM_PORTX_TYPE) { | ||||
4745 | /*Handle DP case as DONGLE_NONE*/ | ||||
4746 | case DOWN_STREAM_DETAILED_DP: | ||||
4747 | link->dpcd_caps.dongle_type = DISPLAY_DONGLE_NONE; | ||||
4748 | break; | ||||
4749 | case DOWN_STREAM_DETAILED_VGA: | ||||
4750 | link->dpcd_caps.dongle_type = | ||||
4751 | DISPLAY_DONGLE_DP_VGA_CONVERTER; | ||||
4752 | break; | ||||
4753 | case DOWN_STREAM_DETAILED_DVI: | ||||
4754 | link->dpcd_caps.dongle_type = | ||||
4755 | DISPLAY_DONGLE_DP_DVI_CONVERTER; | ||||
4756 | break; | ||||
4757 | case DOWN_STREAM_DETAILED_HDMI: | ||||
4758 | case DOWN_STREAM_DETAILED_DP_PLUS_PLUS: | ||||
4759 | /*Handle DP++ active converter case, process DP++ case as HDMI case according DP1.4 spec*/ | ||||
4760 | link->dpcd_caps.dongle_type = | ||||
4761 | DISPLAY_DONGLE_DP_HDMI_CONVERTER; | ||||
4762 | |||||
4763 | link->dpcd_caps.dongle_caps.dongle_type = link->dpcd_caps.dongle_type; | ||||
4764 | if (ds_port.fields.DETAILED_CAPS) { | ||||
4765 | |||||
4766 | union dwnstream_port_caps_byte3_hdmi | ||||
4767 | hdmi_caps = {.raw = det_caps[3] }; | ||||
4768 | union dwnstream_port_caps_byte2 | ||||
4769 | hdmi_color_caps = {.raw = det_caps[2] }; | ||||
4770 | link->dpcd_caps.dongle_caps.dp_hdmi_max_pixel_clk_in_khz = | ||||
4771 | det_caps[1] * 2500; | ||||
4772 | |||||
4773 | link->dpcd_caps.dongle_caps.is_dp_hdmi_s3d_converter = | ||||
4774 | hdmi_caps.bits.FRAME_SEQ_TO_FRAME_PACK; | ||||
4775 | /*YCBCR capability only for HDMI case*/ | ||||
4776 | if (port_caps->bits.DWN_STRM_PORTX_TYPE | ||||
4777 | == DOWN_STREAM_DETAILED_HDMI) { | ||||
4778 | link->dpcd_caps.dongle_caps.is_dp_hdmi_ycbcr422_pass_through = | ||||
4779 | hdmi_caps.bits.YCrCr422_PASS_THROUGH; | ||||
4780 | link->dpcd_caps.dongle_caps.is_dp_hdmi_ycbcr420_pass_through = | ||||
4781 | hdmi_caps.bits.YCrCr420_PASS_THROUGH; | ||||
4782 | link->dpcd_caps.dongle_caps.is_dp_hdmi_ycbcr422_converter = | ||||
4783 | hdmi_caps.bits.YCrCr422_CONVERSION; | ||||
4784 | link->dpcd_caps.dongle_caps.is_dp_hdmi_ycbcr420_converter = | ||||
4785 | hdmi_caps.bits.YCrCr420_CONVERSION; | ||||
4786 | } | ||||
4787 | |||||
4788 | link->dpcd_caps.dongle_caps.dp_hdmi_max_bpc = | ||||
4789 | translate_dpcd_max_bpc( | ||||
4790 | hdmi_color_caps.bits.MAX_BITS_PER_COLOR_COMPONENT); | ||||
4791 | |||||
4792 | #if defined(CONFIG_DRM_AMD_DC_DCN1) | ||||
4793 | if (link->dc->caps.dp_hdmi21_pcon_support) { | ||||
4794 | union hdmi_encoded_link_bw hdmi_encoded_link_bw; | ||||
4795 | |||||
4796 | link->dpcd_caps.dongle_caps.dp_hdmi_frl_max_link_bw_in_kbps = | ||||
4797 | dc_link_bw_kbps_from_raw_frl_link_rate_data( | ||||
4798 | hdmi_color_caps.bits.MAX_ENCODED_LINK_BW_SUPPORT); | ||||
4799 | |||||
4800 | // Intersect reported max link bw support with the supported link rate post FRL link training | ||||
4801 | if (core_link_read_dpcd(link, DP_PCON_HDMI_POST_FRL_STATUS0x3036, | ||||
4802 | &hdmi_encoded_link_bw.raw, sizeof(hdmi_encoded_link_bw)) == DC_OK) { | ||||
4803 | link->dpcd_caps.dongle_caps.dp_hdmi_frl_max_link_bw_in_kbps = intersect_frl_link_bw_support( | ||||
4804 | link->dpcd_caps.dongle_caps.dp_hdmi_frl_max_link_bw_in_kbps, | ||||
4805 | hdmi_encoded_link_bw); | ||||
4806 | } | ||||
4807 | |||||
4808 | if (link->dpcd_caps.dongle_caps.dp_hdmi_frl_max_link_bw_in_kbps > 0) | ||||
4809 | link->dpcd_caps.dongle_caps.extendedCapValid = true1; | ||||
4810 | } | ||||
4811 | #endif | ||||
4812 | |||||
4813 | if (link->dpcd_caps.dongle_caps.dp_hdmi_max_pixel_clk_in_khz != 0) | ||||
4814 | link->dpcd_caps.dongle_caps.extendedCapValid = true1; | ||||
4815 | } | ||||
4816 | |||||
4817 | break; | ||||
4818 | } | ||||
4819 | } | ||||
4820 | } | ||||
4821 | |||||
4822 | ddc_service_set_dongle_type(link->ddc, link->dpcd_caps.dongle_type); | ||||
4823 | |||||
4824 | { | ||||
4825 | struct dp_sink_hw_fw_revision dp_hw_fw_revision; | ||||
4826 | |||||
4827 | core_link_read_dpcd( | ||||
4828 | link, | ||||
4829 | DP_BRANCH_REVISION_START0x509, | ||||
4830 | (uint8_t *)&dp_hw_fw_revision, | ||||
4831 | sizeof(dp_hw_fw_revision)); | ||||
4832 | |||||
4833 | link->dpcd_caps.branch_hw_revision = | ||||
4834 | dp_hw_fw_revision.ieee_hw_rev; | ||||
4835 | |||||
4836 | memmove(__builtin_memmove((link->dpcd_caps.branch_fw_revision), (dp_hw_fw_revision .ieee_fw_rev), (sizeof(dp_hw_fw_revision.ieee_fw_rev))) | ||||
4837 | link->dpcd_caps.branch_fw_revision,__builtin_memmove((link->dpcd_caps.branch_fw_revision), (dp_hw_fw_revision .ieee_fw_rev), (sizeof(dp_hw_fw_revision.ieee_fw_rev))) | ||||
4838 | dp_hw_fw_revision.ieee_fw_rev,__builtin_memmove((link->dpcd_caps.branch_fw_revision), (dp_hw_fw_revision .ieee_fw_rev), (sizeof(dp_hw_fw_revision.ieee_fw_rev))) | ||||
4839 | sizeof(dp_hw_fw_revision.ieee_fw_rev))__builtin_memmove((link->dpcd_caps.branch_fw_revision), (dp_hw_fw_revision .ieee_fw_rev), (sizeof(dp_hw_fw_revision.ieee_fw_rev))); | ||||
4840 | } | ||||
4841 | if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_14 && | ||||
4842 | link->dpcd_caps.dongle_type != DISPLAY_DONGLE_NONE) { | ||||
4843 | union dp_dfp_cap_ext dfp_cap_ext; | ||||
4844 | memset(&dfp_cap_ext, '\0', sizeof (dfp_cap_ext))__builtin_memset((&dfp_cap_ext), ('\0'), (sizeof (dfp_cap_ext ))); | ||||
4845 | core_link_read_dpcd( | ||||
4846 | link, | ||||
4847 | DP_DFP_CAPABILITY_EXTENSION_SUPPORT0x0a3, | ||||
4848 | dfp_cap_ext.raw, | ||||
4849 | sizeof(dfp_cap_ext.raw)); | ||||
4850 | link->dpcd_caps.dongle_caps.dfp_cap_ext.supported = dfp_cap_ext.fields.supported; | ||||
4851 | link->dpcd_caps.dongle_caps.dfp_cap_ext.max_pixel_rate_in_mps = | ||||
4852 | dfp_cap_ext.fields.max_pixel_rate_in_mps[0] + | ||||
4853 | (dfp_cap_ext.fields.max_pixel_rate_in_mps[1] << 8); | ||||
4854 | link->dpcd_caps.dongle_caps.dfp_cap_ext.max_video_h_active_width = | ||||
4855 | dfp_cap_ext.fields.max_video_h_active_width[0] + | ||||
4856 | (dfp_cap_ext.fields.max_video_h_active_width[1] << 8); | ||||
4857 | link->dpcd_caps.dongle_caps.dfp_cap_ext.max_video_v_active_height = | ||||
4858 | dfp_cap_ext.fields.max_video_v_active_height[0] + | ||||
4859 | (dfp_cap_ext.fields.max_video_v_active_height[1] << 8); | ||||
4860 | link->dpcd_caps.dongle_caps.dfp_cap_ext.encoding_format_caps = | ||||
4861 | dfp_cap_ext.fields.encoding_format_caps; | ||||
4862 | link->dpcd_caps.dongle_caps.dfp_cap_ext.rgb_color_depth_caps = | ||||
4863 | dfp_cap_ext.fields.rgb_color_depth_caps; | ||||
4864 | link->dpcd_caps.dongle_caps.dfp_cap_ext.ycbcr444_color_depth_caps = | ||||
4865 | dfp_cap_ext.fields.ycbcr444_color_depth_caps; | ||||
4866 | link->dpcd_caps.dongle_caps.dfp_cap_ext.ycbcr422_color_depth_caps = | ||||
4867 | dfp_cap_ext.fields.ycbcr422_color_depth_caps; | ||||
4868 | link->dpcd_caps.dongle_caps.dfp_cap_ext.ycbcr420_color_depth_caps = | ||||
4869 | dfp_cap_ext.fields.ycbcr420_color_depth_caps; | ||||
4870 | DC_LOG_DP2("DFP capability extension is read at link %d", link->link_index)___drm_dbg(((void *)0), DRM_UT_KMS, "DFP capability extension is read at link %d" , link->link_index); | ||||
4871 | DC_LOG_DP2("\tdfp_cap_ext.supported = %s", link->dpcd_caps.dongle_caps.dfp_cap_ext.supported ? "true" : "false")___drm_dbg(((void *)0), DRM_UT_KMS, "\tdfp_cap_ext.supported = %s" , link->dpcd_caps.dongle_caps.dfp_cap_ext.supported ? "true" : "false"); | ||||
4872 | DC_LOG_DP2("\tdfp_cap_ext.max_pixel_rate_in_mps = %d", link->dpcd_caps.dongle_caps.dfp_cap_ext.max_pixel_rate_in_mps)___drm_dbg(((void *)0), DRM_UT_KMS, "\tdfp_cap_ext.max_pixel_rate_in_mps = %d" , link->dpcd_caps.dongle_caps.dfp_cap_ext.max_pixel_rate_in_mps ); | ||||
4873 | DC_LOG_DP2("\tdfp_cap_ext.max_video_h_active_width = %d", link->dpcd_caps.dongle_caps.dfp_cap_ext.max_video_h_active_width)___drm_dbg(((void *)0), DRM_UT_KMS, "\tdfp_cap_ext.max_video_h_active_width = %d" , link->dpcd_caps.dongle_caps.dfp_cap_ext.max_video_h_active_width ); | ||||
4874 | DC_LOG_DP2("\tdfp_cap_ext.max_video_v_active_height = %d", link->dpcd_caps.dongle_caps.dfp_cap_ext.max_video_v_active_height)___drm_dbg(((void *)0), DRM_UT_KMS, "\tdfp_cap_ext.max_video_v_active_height = %d" , link->dpcd_caps.dongle_caps.dfp_cap_ext.max_video_v_active_height ); | ||||
4875 | } | ||||
4876 | } | ||||
4877 | |||||
4878 | static void dp_wa_power_up_0010FA(struct dc_link *link, uint8_t *dpcd_data, | ||||
4879 | int length) | ||||
4880 | { | ||||
4881 | int retry = 0; | ||||
4882 | |||||
4883 | if (!link->dpcd_caps.dpcd_rev.raw) { | ||||
4884 | do { | ||||
4885 | dp_receiver_power_ctrl(link, true1); | ||||
4886 | core_link_read_dpcd(link, DP_DPCD_REV0x000, | ||||
4887 | dpcd_data, length); | ||||
4888 | link->dpcd_caps.dpcd_rev.raw = dpcd_data[ | ||||
4889 | DP_DPCD_REV0x000 - | ||||
4890 | DP_DPCD_REV0x000]; | ||||
4891 | } while (retry++ < 4 && !link->dpcd_caps.dpcd_rev.raw); | ||||
4892 | } | ||||
4893 | |||||
4894 | if (link->dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_VGA_CONVERTER) { | ||||
4895 | switch (link->dpcd_caps.branch_dev_id) { | ||||
4896 | /* 0010FA active dongles (DP-VGA, DP-DLDVI converters) power down | ||||
4897 | * all internal circuits including AUX communication preventing | ||||
4898 | * reading DPCD table and EDID (spec violation). | ||||
4899 | * Encoder will skip DP RX power down on disable_output to | ||||
4900 | * keep receiver powered all the time.*/ | ||||
4901 | case DP_BRANCH_DEVICE_ID_0010FA0x0010FA: | ||||
4902 | case DP_BRANCH_DEVICE_ID_0080E10x0080e1: | ||||
4903 | case DP_BRANCH_DEVICE_ID_00E04C0x00E04C: | ||||
4904 | link->wa_flags.dp_keep_receiver_powered = true1; | ||||
4905 | break; | ||||
4906 | |||||
4907 | /* TODO: May need work around for other dongles. */ | ||||
4908 | default: | ||||
4909 | link->wa_flags.dp_keep_receiver_powered = false0; | ||||
4910 | break; | ||||
4911 | } | ||||
4912 | } else | ||||
4913 | link->wa_flags.dp_keep_receiver_powered = false0; | ||||
4914 | } | ||||
4915 | |||||
4916 | /* Read additional sink caps defined in source specific DPCD area | ||||
4917 | * This function currently only reads from SinkCapability address (DP_SOURCE_SINK_CAP) | ||||
4918 | */ | ||||
4919 | static bool_Bool dpcd_read_sink_ext_caps(struct dc_link *link) | ||||
4920 | { | ||||
4921 | uint8_t dpcd_data; | ||||
4922 | |||||
4923 | if (!link) | ||||
4924 | return false0; | ||||
4925 | |||||
4926 | if (core_link_read_dpcd(link, DP_SOURCE_SINK_CAP0x317, &dpcd_data, 1) != DC_OK) | ||||
4927 | return false0; | ||||
4928 | |||||
4929 | link->dpcd_sink_ext_caps.raw = dpcd_data; | ||||
4930 | return true1; | ||||
4931 | } | ||||
4932 | |||||
4933 | bool_Bool dp_retrieve_lttpr_cap(struct dc_link *link) | ||||
4934 | { | ||||
4935 | uint8_t lttpr_dpcd_data[8]; | ||||
4936 | enum dc_status status = DC_ERROR_UNEXPECTED; | ||||
4937 | bool_Bool is_lttpr_present = false0; | ||||
4938 | |||||
4939 | /* Logic to determine LTTPR support*/ | ||||
4940 | bool_Bool vbios_lttpr_interop = link->dc->caps.vbios_lttpr_aware; | ||||
4941 | |||||
4942 | if (!vbios_lttpr_interop || !link->dc->caps.extended_aux_timeout_support) | ||||
4943 | return false0; | ||||
4944 | |||||
4945 | /* By reading LTTPR capability, RX assumes that we will enable | ||||
4946 | * LTTPR extended aux timeout if LTTPR is present. | ||||
4947 | */ | ||||
4948 | status = core_link_read_dpcd(link, | ||||
4949 | DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV0xf0000, | ||||
4950 | lttpr_dpcd_data, | ||||
4951 | sizeof(lttpr_dpcd_data)); | ||||
4952 | |||||
4953 | link->dpcd_caps.lttpr_caps.revision.raw = | ||||
4954 | lttpr_dpcd_data[DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV0xf0000 - | ||||
4955 | DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV0xf0000]; | ||||
4956 | |||||
4957 | link->dpcd_caps.lttpr_caps.max_link_rate = | ||||
4958 | lttpr_dpcd_data[DP_MAX_LINK_RATE_PHY_REPEATER0xf0001 - | ||||
4959 | DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV0xf0000]; | ||||
4960 | |||||
4961 | link->dpcd_caps.lttpr_caps.phy_repeater_cnt = | ||||
4962 | lttpr_dpcd_data[DP_PHY_REPEATER_CNT0xf0002 - | ||||
4963 | DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV0xf0000]; | ||||
4964 | |||||
4965 | link->dpcd_caps.lttpr_caps.max_lane_count = | ||||
4966 | lttpr_dpcd_data[DP_MAX_LANE_COUNT_PHY_REPEATER0xf0004 - | ||||
4967 | DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV0xf0000]; | ||||
4968 | |||||
4969 | link->dpcd_caps.lttpr_caps.mode = | ||||
4970 | lttpr_dpcd_data[DP_PHY_REPEATER_MODE0xf0003 - | ||||
4971 | DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV0xf0000]; | ||||
4972 | |||||
4973 | link->dpcd_caps.lttpr_caps.max_ext_timeout = | ||||
4974 | lttpr_dpcd_data[DP_PHY_REPEATER_EXTENDED_WAIT_TIMEOUT0xf0005 - | ||||
4975 | DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV0xf0000]; | ||||
4976 | link->dpcd_caps.lttpr_caps.main_link_channel_coding.raw = | ||||
4977 | lttpr_dpcd_data[DP_MAIN_LINK_CHANNEL_CODING_PHY_REPEATER0xf0006 - | ||||
4978 | DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV0xf0000]; | ||||
4979 | |||||
4980 | link->dpcd_caps.lttpr_caps.supported_128b_132b_rates.raw = | ||||
4981 | lttpr_dpcd_data[DP_PHY_REPEATER_128B132B_RATES0xf0007 - | ||||
4982 | DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV0xf0000]; | ||||
4983 | |||||
4984 | /* If this chip cap is set, at least one retimer must exist in the chain | ||||
4985 | * Override count to 1 if we receive a known bad count (0 or an invalid value) | ||||
4986 | */ | ||||
4987 | if (link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN && | ||||
4988 | (dp_convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt) == 0)) { | ||||
4989 | ASSERT(0)do { if (({ static int __warned; int __ret = !!(!(0)); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n" , "!(0)", "/usr/src/sys/dev/pci/drm/amd/display/dc/core/dc_link_dp.c" , 4989); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | ||||
4990 | link->dpcd_caps.lttpr_caps.phy_repeater_cnt = 0x80; | ||||
4991 | DC_LOG_DC("lttpr_caps forced phy_repeater_cnt = %d\n", link->dpcd_caps.lttpr_caps.phy_repeater_cnt)___drm_dbg(((void *)0), DRM_UT_KMS, "lttpr_caps forced phy_repeater_cnt = %d\n" , link->dpcd_caps.lttpr_caps.phy_repeater_cnt); | ||||
4992 | } | ||||
4993 | |||||
4994 | /* Attempt to train in LTTPR transparent mode if repeater count exceeds 8. */ | ||||
4995 | is_lttpr_present = dp_is_lttpr_present(link); | ||||
4996 | |||||
4997 | if (is_lttpr_present) | ||||
4998 | CONN_DATA_DETECT(link, lttpr_dpcd_data, sizeof(lttpr_dpcd_data), "LTTPR Caps: ")do { (void)(link); ___drm_dbg(((void *)0), DRM_UT_KMS, "LTTPR Caps: " ); } while (0); | ||||
4999 | |||||
5000 | DC_LOG_DC("is_lttpr_present = %d\n", is_lttpr_present)___drm_dbg(((void *)0), DRM_UT_KMS, "is_lttpr_present = %d\n" , is_lttpr_present); | ||||
5001 | return is_lttpr_present; | ||||
5002 | } | ||||
5003 | |||||
5004 | bool_Bool dp_is_lttpr_present(struct dc_link *link) | ||||
5005 | { | ||||
5006 | return (dp_convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt) != 0 && | ||||
5007 | link->dpcd_caps.lttpr_caps.max_lane_count > 0 && | ||||
5008 | link->dpcd_caps.lttpr_caps.max_lane_count <= 4 && | ||||
5009 | link->dpcd_caps.lttpr_caps.revision.raw >= 0x14); | ||||
5010 | } | ||||
5011 | |||||
5012 | enum lttpr_mode dp_decide_lttpr_mode(struct dc_link *link, struct dc_link_settings *link_setting) | ||||
5013 | { | ||||
5014 | enum dp_link_encoding encoding = dp_get_link_encoding_format(link_setting); | ||||
5015 | |||||
5016 | if (encoding == DP_8b_10b_ENCODING) | ||||
5017 | return dp_decide_8b_10b_lttpr_mode(link); | ||||
5018 | else if (encoding == DP_128b_132b_ENCODING) | ||||
5019 | return dp_decide_128b_132b_lttpr_mode(link); | ||||
5020 | |||||
5021 | ASSERT(0)do { if (({ static int __warned; int __ret = !!(!(0)); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n" , "!(0)", "/usr/src/sys/dev/pci/drm/amd/display/dc/core/dc_link_dp.c" , 5021); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | ||||
5022 | return LTTPR_MODE_NON_LTTPR; | ||||
5023 | } | ||||
5024 | |||||
5025 | void dp_get_lttpr_mode_override(struct dc_link *link, enum lttpr_mode *override) | ||||
5026 | { | ||||
5027 | if (!dp_is_lttpr_present(link)) | ||||
5028 | return; | ||||
5029 | |||||
5030 | if (link->dc->debug.lttpr_mode_override == LTTPR_MODE_TRANSPARENT) { | ||||
5031 | *override = LTTPR_MODE_TRANSPARENT; | ||||
5032 | } else if (link->dc->debug.lttpr_mode_override == LTTPR_MODE_NON_TRANSPARENT) { | ||||
5033 | *override = LTTPR_MODE_NON_TRANSPARENT; | ||||
5034 | } else if (link->dc->debug.lttpr_mode_override == LTTPR_MODE_NON_LTTPR) { | ||||
5035 | *override = LTTPR_MODE_NON_LTTPR; | ||||
5036 | } | ||||
5037 | DC_LOG_DC("lttpr_mode_override chose LTTPR_MODE = %d\n", (uint8_t)(*override))___drm_dbg(((void *)0), DRM_UT_KMS, "lttpr_mode_override chose LTTPR_MODE = %d\n" , (uint8_t)(*override)); | ||||
5038 | } | ||||
5039 | |||||
5040 | enum lttpr_mode dp_decide_8b_10b_lttpr_mode(struct dc_link *link) | ||||
5041 | { | ||||
5042 | bool_Bool is_lttpr_present = dp_is_lttpr_present(link); | ||||
5043 | bool_Bool vbios_lttpr_force_non_transparent = link->dc->caps.vbios_lttpr_enable; | ||||
5044 | bool_Bool vbios_lttpr_aware = link->dc->caps.vbios_lttpr_aware; | ||||
5045 | |||||
5046 | if (!is_lttpr_present) | ||||
5047 | return LTTPR_MODE_NON_LTTPR; | ||||
5048 | |||||
5049 | if (vbios_lttpr_aware) { | ||||
5050 | if (vbios_lttpr_force_non_transparent) { | ||||
5051 | DC_LOG_DC("chose LTTPR_MODE_NON_TRANSPARENT due to VBIOS DCE_INFO_CAPS_LTTPR_SUPPORT_ENABLE set to 1.\n")___drm_dbg(((void *)0), DRM_UT_KMS, "chose LTTPR_MODE_NON_TRANSPARENT due to VBIOS DCE_INFO_CAPS_LTTPR_SUPPORT_ENABLE set to 1.\n" ); | ||||
5052 | return LTTPR_MODE_NON_TRANSPARENT; | ||||
5053 | } else { | ||||
5054 | 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")___drm_dbg(((void *)0), DRM_UT_KMS, "chose LTTPR_MODE_NON_TRANSPARENT by default due to VBIOS not set DCE_INFO_CAPS_LTTPR_SUPPORT_ENABLE set to 1.\n" ); | ||||
5055 | return LTTPR_MODE_TRANSPARENT; | ||||
5056 | } | ||||
5057 | } | ||||
5058 | |||||
5059 | if (link->dc->config.allow_lttpr_non_transparent_mode.bits.DP1_4A && | ||||
5060 | link->dc->caps.extended_aux_timeout_support) { | ||||
5061 | 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")___drm_dbg(((void *)0), DRM_UT_KMS, "chose LTTPR_MODE_NON_TRANSPARENT by default and dc->config.allow_lttpr_non_transparent_mode.bits.DP1_4A set to 1.\n" ); | ||||
5062 | return LTTPR_MODE_NON_TRANSPARENT; | ||||
5063 | } | ||||
5064 | |||||
5065 | DC_LOG_DC("chose LTTPR_MODE_NON_LTTPR.\n")___drm_dbg(((void *)0), DRM_UT_KMS, "chose LTTPR_MODE_NON_LTTPR.\n" ); | ||||
5066 | return LTTPR_MODE_NON_LTTPR; | ||||
5067 | } | ||||
5068 | |||||
5069 | enum lttpr_mode dp_decide_128b_132b_lttpr_mode(struct dc_link *link) | ||||
5070 | { | ||||
5071 | enum lttpr_mode mode = LTTPR_MODE_NON_LTTPR; | ||||
5072 | |||||
5073 | if (dp_is_lttpr_present(link)) | ||||
5074 | mode = LTTPR_MODE_NON_TRANSPARENT; | ||||
5075 | |||||
5076 | DC_LOG_DC("128b_132b chose LTTPR_MODE %d.\n", mode)___drm_dbg(((void *)0), DRM_UT_KMS, "128b_132b chose LTTPR_MODE %d.\n" , mode); | ||||
5077 | return mode; | ||||
5078 | } | ||||
5079 | |||||
5080 | static bool_Bool get_usbc_cable_id(struct dc_link *link, union dp_cable_id *cable_id) | ||||
5081 | { | ||||
5082 | union dmub_rb_cmd cmd; | ||||
5083 | |||||
5084 | if (!link->ctx->dmub_srv || | ||||
5085 | link->ep_type != DISPLAY_ENDPOINT_PHY || | ||||
5086 | link->link_enc->features.flags.bits.DP_IS_USB_C == 0) | ||||
5087 | return false0; | ||||
5088 | |||||
5089 | memset(&cmd, 0, sizeof(cmd))__builtin_memset((&cmd), (0), (sizeof(cmd))); | ||||
5090 | cmd.cable_id.header.type = DMUB_CMD_GET_USBC_CABLE_ID; | ||||
5091 | cmd.cable_id.header.payload_bytes = sizeof(cmd.cable_id.data); | ||||
5092 | cmd.cable_id.data.input.phy_inst = resource_transmitter_to_phy_idx( | ||||
5093 | link->dc, link->link_enc->transmitter); | ||||
5094 | if (dc_dmub_srv_cmd_with_reply_data(link->ctx->dmub_srv, &cmd) && | ||||
5095 | cmd.cable_id.header.ret_status == 1) { | ||||
5096 | cable_id->raw = cmd.cable_id.data.output_raw; | ||||
5097 | DC_LOG_DC("usbc_cable_id = %d.\n", cable_id->raw)___drm_dbg(((void *)0), DRM_UT_KMS, "usbc_cable_id = %d.\n", cable_id ->raw); | ||||
5098 | } | ||||
5099 | return cmd.cable_id.header.ret_status == 1; | ||||
5100 | } | ||||
5101 | |||||
5102 | static union dp_cable_id intersect_cable_id( | ||||
5103 | union dp_cable_id *a, union dp_cable_id *b) | ||||
5104 | { | ||||
5105 | union dp_cable_id out; | ||||
5106 | |||||
5107 | out.bits.UHBR10_20_CAPABILITY = MIN(a->bits.UHBR10_20_CAPABILITY,(((a->bits.UHBR10_20_CAPABILITY)<(b->bits.UHBR10_20_CAPABILITY ))?(a->bits.UHBR10_20_CAPABILITY):(b->bits.UHBR10_20_CAPABILITY )) | ||||
5108 | b->bits.UHBR10_20_CAPABILITY)(((a->bits.UHBR10_20_CAPABILITY)<(b->bits.UHBR10_20_CAPABILITY ))?(a->bits.UHBR10_20_CAPABILITY):(b->bits.UHBR10_20_CAPABILITY )); | ||||
5109 | out.bits.UHBR13_5_CAPABILITY = MIN(a->bits.UHBR13_5_CAPABILITY,(((a->bits.UHBR13_5_CAPABILITY)<(b->bits.UHBR13_5_CAPABILITY ))?(a->bits.UHBR13_5_CAPABILITY):(b->bits.UHBR13_5_CAPABILITY )) | ||||
5110 | b->bits.UHBR13_5_CAPABILITY)(((a->bits.UHBR13_5_CAPABILITY)<(b->bits.UHBR13_5_CAPABILITY ))?(a->bits.UHBR13_5_CAPABILITY):(b->bits.UHBR13_5_CAPABILITY )); | ||||
5111 | out.bits.CABLE_TYPE = MAX(a->bits.CABLE_TYPE, b->bits.CABLE_TYPE)(((a->bits.CABLE_TYPE)>(b->bits.CABLE_TYPE))?(a-> bits.CABLE_TYPE):(b->bits.CABLE_TYPE)); | ||||
5112 | |||||
5113 | return out; | ||||
5114 | } | ||||
5115 | |||||
5116 | static void retrieve_cable_id(struct dc_link *link) | ||||
5117 | { | ||||
5118 | union dp_cable_id usbc_cable_id; | ||||
5119 | |||||
5120 | link->dpcd_caps.cable_id.raw = 0; | ||||
5121 | core_link_read_dpcd(link, DP_CABLE_ATTRIBUTES_UPDATED_BY_DPRX0x2217, | ||||
5122 | &link->dpcd_caps.cable_id.raw, sizeof(uint8_t)); | ||||
5123 | |||||
5124 | if (get_usbc_cable_id(link, &usbc_cable_id)) | ||||
5125 | link->dpcd_caps.cable_id = intersect_cable_id( | ||||
5126 | &link->dpcd_caps.cable_id, &usbc_cable_id); | ||||
5127 | } | ||||
5128 | |||||
5129 | /* DPRX may take some time to respond to AUX messages after HPD asserted. | ||||
5130 | * If AUX read unsuccessful, try to wake unresponsive DPRX by toggling DPCD SET_POWER (0x600). | ||||
5131 | */ | ||||
5132 | static enum dc_status wa_try_to_wake_dprx(struct dc_link *link, uint64_t timeout_ms) | ||||
5133 | { | ||||
5134 | enum dc_status status = DC_ERROR_UNEXPECTED; | ||||
5135 | uint8_t dpcd_data = 0; | ||||
5136 | uint64_t start_ts = 0; | ||||
5137 | uint64_t current_ts = 0; | ||||
5138 | uint64_t time_taken_ms = 0; | ||||
5139 | enum dc_connection_type type = dc_connection_none; | ||||
5140 | bool_Bool lttpr_present; | ||||
5141 | bool_Bool vbios_lttpr_interop = link->dc->caps.vbios_lttpr_aware; | ||||
5142 | |||||
5143 | lttpr_present = dp_is_lttpr_present(link) || | ||||
5144 | (!vbios_lttpr_interop || !link->dc->caps.extended_aux_timeout_support); | ||||
5145 | DC_LOG_DC("lttpr_present = %d.\n", lttpr_present ? 1 : 0)___drm_dbg(((void *)0), DRM_UT_KMS, "lttpr_present = %d.\n", lttpr_present ? 1 : 0); | ||||
5146 | |||||
5147 | /* Issue an AUX read to test DPRX responsiveness. If LTTPR is supported the first read is expected to | ||||
5148 | * be to determine LTTPR capabilities. Otherwise trying to read power state should be an innocuous AUX read. | ||||
5149 | */ | ||||
5150 | if (lttpr_present) | ||||
5151 | status = core_link_read_dpcd( | ||||
5152 | link, | ||||
5153 | DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV0xf0000, | ||||
5154 | &dpcd_data, | ||||
5155 | sizeof(dpcd_data)); | ||||
5156 | else | ||||
5157 | status = core_link_read_dpcd( | ||||
5158 | link, | ||||
5159 | DP_SET_POWER0x600, | ||||
5160 | &dpcd_data, | ||||
5161 | sizeof(dpcd_data)); | ||||
5162 | |||||
5163 | if (status != DC_OK) { | ||||
5164 | DC_LOG_WARNING("%s: Read DPCD LTTPR_CAP failed - try to toggle DPCD SET_POWER for %lld ms.",printk("\0014" "[" "drm" "] " "%s: Read DPCD LTTPR_CAP failed - try to toggle DPCD SET_POWER for %lld ms." , __func__, timeout_ms) | ||||
5165 | __func__,printk("\0014" "[" "drm" "] " "%s: Read DPCD LTTPR_CAP failed - try to toggle DPCD SET_POWER for %lld ms." , __func__, timeout_ms) | ||||
5166 | timeout_ms)printk("\0014" "[" "drm" "] " "%s: Read DPCD LTTPR_CAP failed - try to toggle DPCD SET_POWER for %lld ms." , __func__, timeout_ms); | ||||
5167 | start_ts = dm_get_timestamp(link->ctx); | ||||
5168 | |||||
5169 | do { | ||||
5170 | if (!dc_link_detect_sink(link, &type) || type == dc_connection_none) | ||||
5171 | break; | ||||
5172 | |||||
5173 | dpcd_data = DP_SET_POWER_D30x2; | ||||
5174 | status = core_link_write_dpcd( | ||||
5175 | link, | ||||
5176 | DP_SET_POWER0x600, | ||||
5177 | &dpcd_data, | ||||
5178 | sizeof(dpcd_data)); | ||||
5179 | |||||
5180 | dpcd_data = DP_SET_POWER_D00x1; | ||||
5181 | status = core_link_write_dpcd( | ||||
5182 | link, | ||||
5183 | DP_SET_POWER0x600, | ||||
5184 | &dpcd_data, | ||||
5185 | sizeof(dpcd_data)); | ||||
5186 | |||||
5187 | current_ts = dm_get_timestamp(link->ctx); | ||||
5188 | time_taken_ms = div_u64(dm_get_elapse_time_in_ns(link->ctx, current_ts, start_ts), 1000000); | ||||
5189 | } while (status != DC_OK && time_taken_ms < timeout_ms); | ||||
5190 | |||||
5191 | DC_LOG_WARNING("%s: DPCD SET_POWER %s after %lld ms%s",printk("\0014" "[" "drm" "] " "%s: DPCD SET_POWER %s after %lld ms%s" , __func__, (status == DC_OK) ? "succeeded" : "failed", time_taken_ms , (type == dc_connection_none) ? ". Unplugged." : ".") | ||||
5192 | __func__,printk("\0014" "[" "drm" "] " "%s: DPCD SET_POWER %s after %lld ms%s" , __func__, (status == DC_OK) ? "succeeded" : "failed", time_taken_ms , (type == dc_connection_none) ? ". Unplugged." : ".") | ||||
5193 | (status == DC_OK) ? "succeeded" : "failed",printk("\0014" "[" "drm" "] " "%s: DPCD SET_POWER %s after %lld ms%s" , __func__, (status == DC_OK) ? "succeeded" : "failed", time_taken_ms , (type == dc_connection_none) ? ". Unplugged." : ".") | ||||
5194 | time_taken_ms,printk("\0014" "[" "drm" "] " "%s: DPCD SET_POWER %s after %lld ms%s" , __func__, (status == DC_OK) ? "succeeded" : "failed", time_taken_ms , (type == dc_connection_none) ? ". Unplugged." : ".") | ||||
5195 | (type == dc_connection_none) ? ". Unplugged." : ".")printk("\0014" "[" "drm" "] " "%s: DPCD SET_POWER %s after %lld ms%s" , __func__, (status == DC_OK) ? "succeeded" : "failed", time_taken_ms , (type == dc_connection_none) ? ". Unplugged." : "."); | ||||
5196 | } | ||||
5197 | |||||
5198 | return status; | ||||
5199 | } | ||||
5200 | |||||
5201 | static bool_Bool retrieve_link_cap(struct dc_link *link) | ||||
5202 | { | ||||
5203 | /* DP_ADAPTER_CAP - DP_DPCD_REV + 1 == 16 and also DP_DSC_BITS_PER_PIXEL_INC - DP_DSC_SUPPORT + 1 == 16, | ||||
5204 | * which means size 16 will be good for both of those DPCD register block reads | ||||
5205 | */ | ||||
5206 | uint8_t dpcd_data[16]; | ||||
5207 | /*Only need to read 1 byte starting from DP_DPRX_FEATURE_ENUMERATION_LIST. | ||||
5208 | */ | ||||
5209 | uint8_t dpcd_dprx_data = '\0'; | ||||
5210 | uint8_t dpcd_power_state = '\0'; | ||||
5211 | |||||
5212 | struct dp_device_vendor_id sink_id; | ||||
5213 | union down_stream_port_count down_strm_port_count; | ||||
5214 | union edp_configuration_cap edp_config_cap; | ||||
5215 | union dp_downstream_port_present ds_port = { 0 }; | ||||
5216 | enum dc_status status = DC_ERROR_UNEXPECTED; | ||||
5217 | uint32_t read_dpcd_retry_cnt = 3; | ||||
5218 | uint32_t aux_channel_retry_cnt = 0; | ||||
5219 | int i; | ||||
5220 | struct dp_sink_hw_fw_revision dp_hw_fw_revision; | ||||
5221 | const uint32_t post_oui_delay = 30; // 30ms | ||||
5222 | bool_Bool is_lttpr_present = false0; | ||||
5223 | |||||
5224 | memset(dpcd_data, '\0', sizeof(dpcd_data))__builtin_memset((dpcd_data), ('\0'), (sizeof(dpcd_data))); | ||||
5225 | memset(&down_strm_port_count,__builtin_memset((&down_strm_port_count), ('\0'), (sizeof (union down_stream_port_count))) | ||||
5226 | '\0', sizeof(union down_stream_port_count))__builtin_memset((&down_strm_port_count), ('\0'), (sizeof (union down_stream_port_count))); | ||||
5227 | memset(&edp_config_cap, '\0',__builtin_memset((&edp_config_cap), ('\0'), (sizeof(union edp_configuration_cap))) | ||||
5228 | sizeof(union edp_configuration_cap))__builtin_memset((&edp_config_cap), ('\0'), (sizeof(union edp_configuration_cap))); | ||||
5229 | |||||
5230 | /* if extended timeout is supported in hardware, | ||||
5231 | * default to LTTPR timeout (3.2ms) first as a W/A for DP link layer | ||||
5232 | * CTS 4.2.1.1 regression introduced by CTS specs requirement update. | ||||
5233 | */ | ||||
5234 | dc_link_aux_try_to_configure_timeout(link->ddc, | ||||
5235 | LINK_AUX_DEFAULT_LTTPR_TIMEOUT_PERIOD3200); | ||||
5236 | |||||
5237 | /* Try to ensure AUX channel active before proceeding. */ | ||||
5238 | if (link->dc->debug.aux_wake_wa.bits.enable_wa) { | ||||
5239 | uint64_t timeout_ms = link->dc->debug.aux_wake_wa.bits.timeout_ms; | ||||
5240 | |||||
5241 | if (link->dc->debug.aux_wake_wa.bits.use_default_timeout) | ||||
5242 | timeout_ms = LINK_AUX_WAKE_TIMEOUT_MS1500; | ||||
5243 | status = wa_try_to_wake_dprx(link, timeout_ms); | ||||
5244 | } | ||||
5245 | |||||
5246 | while (status != DC_OK && aux_channel_retry_cnt < 10) { | ||||
5247 | status = core_link_read_dpcd(link, DP_SET_POWER0x600, | ||||
5248 | &dpcd_power_state, sizeof(dpcd_power_state)); | ||||
5249 | |||||
5250 | /* Delay 1 ms if AUX CH is in power down state. Based on spec | ||||
5251 | * section 2.3.1.2, if AUX CH may be powered down due to | ||||
5252 | * write to DPCD 600h = 2. Sink AUX CH is monitoring differential | ||||
5253 | * signal and may need up to 1 ms before being able to reply. | ||||
5254 | */ | ||||
5255 | if (status != DC_OK || dpcd_power_state == DP_SET_POWER_D30x2) { | ||||
5256 | udelay(1000); | ||||
5257 | aux_channel_retry_cnt++; | ||||
5258 | } | ||||
5259 | } | ||||
5260 | |||||
5261 | /* If aux channel is not active, return false and trigger another detect*/ | ||||
5262 | if (status != DC_OK) { | ||||
5263 | dpcd_power_state = DP_SET_POWER_D00x1; | ||||
5264 | status = core_link_write_dpcd( | ||||
5265 | link, | ||||
5266 | DP_SET_POWER0x600, | ||||
5267 | &dpcd_power_state, | ||||
5268 | sizeof(dpcd_power_state)); | ||||
5269 | |||||
5270 | dpcd_power_state = DP_SET_POWER_D30x2; | ||||
5271 | status = core_link_write_dpcd( | ||||
5272 | link, | ||||
5273 | DP_SET_POWER0x600, | ||||
5274 | &dpcd_power_state, | ||||
5275 | sizeof(dpcd_power_state)); | ||||
5276 | return false0; | ||||
5277 | } | ||||
5278 | |||||
5279 | is_lttpr_present = dp_retrieve_lttpr_cap(link); | ||||
5280 | |||||
5281 | if (is_lttpr_present) | ||||
5282 | configure_lttpr_mode_transparent(link); | ||||
5283 | |||||
5284 | /* Read DP tunneling information. */ | ||||
5285 | status = dpcd_get_tunneling_device_data(link); | ||||
5286 | |||||
5287 | dpcd_set_source_specific_data(link); | ||||
5288 | /* Sink may need to configure internals based on vendor, so allow some | ||||
5289 | * time before proceeding with possibly vendor specific transactions | ||||
5290 | */ | ||||
5291 | drm_msleep(post_oui_delay)mdelay(post_oui_delay); | ||||
5292 | |||||
5293 | for (i = 0; i < read_dpcd_retry_cnt; i++) { | ||||
5294 | status = core_link_read_dpcd( | ||||
5295 | link, | ||||
5296 | DP_DPCD_REV0x000, | ||||
5297 | dpcd_data, | ||||
5298 | sizeof(dpcd_data)); | ||||
5299 | if (status == DC_OK) | ||||
5300 | break; | ||||
5301 | } | ||||
5302 | |||||
5303 | if (status != DC_OK) { | ||||
5304 | dm_error("%s: Read receiver caps dpcd data failed.\n", __func__)__drm_err("%s: Read receiver caps dpcd data failed.\n", __func__ ); | ||||
5305 | return false0; | ||||
5306 | } | ||||
5307 | |||||
5308 | if (!is_lttpr_present) | ||||
5309 | dc_link_aux_try_to_configure_timeout(link->ddc, LINK_AUX_DEFAULT_TIMEOUT_PERIOD552); | ||||
5310 | |||||
5311 | { | ||||
5312 | union training_aux_rd_interval aux_rd_interval; | ||||
5313 | |||||
5314 | aux_rd_interval.raw = | ||||
5315 | dpcd_data[DP_TRAINING_AUX_RD_INTERVAL0x00e]; | ||||
5316 | |||||
5317 | link->dpcd_caps.ext_receiver_cap_field_present = | ||||
5318 | aux_rd_interval.bits.EXT_RECEIVER_CAP_FIELD_PRESENT == 1; | ||||
5319 | |||||
5320 | if (aux_rd_interval.bits.EXT_RECEIVER_CAP_FIELD_PRESENT == 1) { | ||||
5321 | uint8_t ext_cap_data[16]; | ||||
5322 | |||||
5323 | memset(ext_cap_data, '\0', sizeof(ext_cap_data))__builtin_memset((ext_cap_data), ('\0'), (sizeof(ext_cap_data ))); | ||||
5324 | for (i = 0; i < read_dpcd_retry_cnt; i++) { | ||||
5325 | status = core_link_read_dpcd( | ||||
5326 | link, | ||||
5327 | DP_DP13_DPCD_REV0x2200, | ||||
5328 | ext_cap_data, | ||||
5329 | sizeof(ext_cap_data)); | ||||
5330 | if (status == DC_OK) { | ||||
5331 | memcpy(dpcd_data, ext_cap_data, sizeof(dpcd_data))__builtin_memcpy((dpcd_data), (ext_cap_data), (sizeof(dpcd_data ))); | ||||
5332 | break; | ||||
5333 | } | ||||
5334 | } | ||||
5335 | if (status != DC_OK) | ||||
5336 | dm_error("%s: Read extend caps data failed, use cap from dpcd 0.\n", __func__)__drm_err("%s: Read extend caps data failed, use cap from dpcd 0.\n" , __func__); | ||||
5337 | } | ||||
5338 | } | ||||
5339 | |||||
5340 | link->dpcd_caps.dpcd_rev.raw = | ||||
5341 | dpcd_data[DP_DPCD_REV0x000 - DP_DPCD_REV0x000]; | ||||
5342 | |||||
5343 | if (link->dpcd_caps.ext_receiver_cap_field_present) { | ||||
5344 | for (i = 0; i < read_dpcd_retry_cnt; i++) { | ||||
5345 | status = core_link_read_dpcd( | ||||
5346 | link, | ||||
5347 | DP_DPRX_FEATURE_ENUMERATION_LIST0x2210, | ||||
5348 | &dpcd_dprx_data, | ||||
5349 | sizeof(dpcd_dprx_data)); | ||||
5350 | if (status == DC_OK) | ||||
5351 | break; | ||||
5352 | } | ||||
5353 | |||||
5354 | link->dpcd_caps.dprx_feature.raw = dpcd_dprx_data; | ||||
5355 | |||||
5356 | if (status != DC_OK) | ||||
5357 | dm_error("%s: Read DPRX caps data failed.\n", __func__)__drm_err("%s: Read DPRX caps data failed.\n", __func__); | ||||
5358 | } | ||||
5359 | |||||
5360 | else { | ||||
5361 | link->dpcd_caps.dprx_feature.raw = 0; | ||||
5362 | } | ||||
5363 | |||||
5364 | |||||
5365 | /* Error condition checking... | ||||
5366 | * It is impossible for Sink to report Max Lane Count = 0. | ||||
5367 | * It is possible for Sink to report Max Link Rate = 0, if it is | ||||
5368 | * an eDP device that is reporting specialized link rates in the | ||||
5369 | * SUPPORTED_LINK_RATE table. | ||||
5370 | */ | ||||
5371 | if (dpcd_data[DP_MAX_LANE_COUNT0x002 - DP_DPCD_REV0x000] == 0) | ||||
5372 | return false0; | ||||
5373 | |||||
5374 | ds_port.byte = dpcd_data[DP_DOWNSTREAMPORT_PRESENT0x005 - | ||||
5375 | DP_DPCD_REV0x000]; | ||||
5376 | |||||
5377 | read_dp_device_vendor_id(link); | ||||
5378 | |||||
5379 | /* TODO - decouple raw mst capability from policy decision */ | ||||
5380 | link->dpcd_caps.is_mst_capable = is_mst_supported(link); | ||||
5381 | |||||
5382 | get_active_converter_info(ds_port.byte, link); | ||||
5383 | |||||
5384 | dp_wa_power_up_0010FA(link, dpcd_data, sizeof(dpcd_data)); | ||||
5385 | |||||
5386 | down_strm_port_count.raw = dpcd_data[DP_DOWN_STREAM_PORT_COUNT0x007 - | ||||
5387 | DP_DPCD_REV0x000]; | ||||
5388 | |||||
5389 | link->dpcd_caps.allow_invalid_MSA_timing_param = | ||||
5390 | down_strm_port_count.bits.IGNORE_MSA_TIMING_PARAM; | ||||
5391 | |||||
5392 | link->dpcd_caps.max_ln_count.raw = dpcd_data[ | ||||
5393 | DP_MAX_LANE_COUNT0x002 - DP_DPCD_REV0x000]; | ||||
5394 | |||||
5395 | link->dpcd_caps.max_down_spread.raw = dpcd_data[ | ||||
5396 | DP_MAX_DOWNSPREAD0x003 - DP_DPCD_REV0x000]; | ||||
5397 | |||||
5398 | link->reported_link_cap.lane_count = | ||||
5399 | link->dpcd_caps.max_ln_count.bits.MAX_LANE_COUNT; | ||||
5400 | link->reported_link_cap.link_rate = get_link_rate_from_max_link_bw( | ||||
5401 | dpcd_data[DP_MAX_LINK_RATE0x001 - DP_DPCD_REV0x000]); | ||||
5402 | link->reported_link_cap.link_spread = | ||||
5403 | link->dpcd_caps.max_down_spread.bits.MAX_DOWN_SPREAD ? | ||||
5404 | LINK_SPREAD_05_DOWNSPREAD_30KHZ : LINK_SPREAD_DISABLED; | ||||
5405 | |||||
5406 | edp_config_cap.raw = dpcd_data[ | ||||
5407 | DP_EDP_CONFIGURATION_CAP0x00d - DP_DPCD_REV0x000]; | ||||
5408 | link->dpcd_caps.panel_mode_edp = | ||||
5409 | edp_config_cap.bits.ALT_SCRAMBLER_RESET; | ||||
5410 | link->dpcd_caps.dpcd_display_control_capable = | ||||
5411 | edp_config_cap.bits.DPCD_DISPLAY_CONTROL_CAPABLE; | ||||
5412 | link->dpcd_caps.channel_coding_cap.raw = | ||||
5413 | dpcd_data[DP_MAIN_LINK_CHANNEL_CODING0x006 - DP_DPCD_REV0x000]; | ||||
5414 | link->test_pattern_enabled = false0; | ||||
5415 | link->compliance_test_state.raw = 0; | ||||
5416 | |||||
5417 | /* read sink count */ | ||||
5418 | core_link_read_dpcd(link, | ||||
5419 | DP_SINK_COUNT0x200, | ||||
5420 | &link->dpcd_caps.sink_count.raw, | ||||
5421 | sizeof(link->dpcd_caps.sink_count.raw)); | ||||
5422 | |||||
5423 | /* read sink ieee oui */ | ||||
5424 | core_link_read_dpcd(link, | ||||
5425 | DP_SINK_OUI0x400, | ||||
5426 | (uint8_t *)(&sink_id), | ||||
5427 | sizeof(sink_id)); | ||||
5428 | |||||
5429 | link->dpcd_caps.sink_dev_id = | ||||
5430 | (sink_id.ieee_oui[0] << 16) + | ||||
5431 | (sink_id.ieee_oui[1] << 8) + | ||||
5432 | (sink_id.ieee_oui[2]); | ||||
5433 | |||||
5434 | memmove(__builtin_memmove((link->dpcd_caps.sink_dev_id_str), (sink_id .ieee_device_id), (sizeof(sink_id.ieee_device_id))) | ||||
5435 | link->dpcd_caps.sink_dev_id_str,__builtin_memmove((link->dpcd_caps.sink_dev_id_str), (sink_id .ieee_device_id), (sizeof(sink_id.ieee_device_id))) | ||||
5436 | sink_id.ieee_device_id,__builtin_memmove((link->dpcd_caps.sink_dev_id_str), (sink_id .ieee_device_id), (sizeof(sink_id.ieee_device_id))) | ||||
5437 | sizeof(sink_id.ieee_device_id))__builtin_memmove((link->dpcd_caps.sink_dev_id_str), (sink_id .ieee_device_id), (sizeof(sink_id.ieee_device_id))); | ||||
5438 | |||||
5439 | /* Quirk Apple MBP 2017 15" Retina panel: Wrong DP_MAX_LINK_RATE */ | ||||
5440 | { | ||||
5441 | uint8_t str_mbp_2017[] = { 101, 68, 21, 101, 98, 97 }; | ||||
5442 | |||||
5443 | if ((link->dpcd_caps.sink_dev_id == 0x0010fa) && | ||||
5444 | !memcmp(link->dpcd_caps.sink_dev_id_str, str_mbp_2017,__builtin_memcmp((link->dpcd_caps.sink_dev_id_str), (str_mbp_2017 ), (sizeof(str_mbp_2017))) | ||||
5445 | sizeof(str_mbp_2017))__builtin_memcmp((link->dpcd_caps.sink_dev_id_str), (str_mbp_2017 ), (sizeof(str_mbp_2017)))) { | ||||
5446 | link->reported_link_cap.link_rate = 0x0c; | ||||
5447 | } | ||||
5448 | } | ||||
5449 | |||||
5450 | core_link_read_dpcd( | ||||
5451 | link, | ||||
5452 | DP_SINK_HW_REVISION_START0x409, | ||||
5453 | (uint8_t *)&dp_hw_fw_revision, | ||||
5454 | sizeof(dp_hw_fw_revision)); | ||||
5455 | |||||
5456 | link->dpcd_caps.sink_hw_revision = | ||||
5457 | dp_hw_fw_revision.ieee_hw_rev; | ||||
5458 | |||||
5459 | memmove(__builtin_memmove((link->dpcd_caps.sink_fw_revision), (dp_hw_fw_revision .ieee_fw_rev), (sizeof(dp_hw_fw_revision.ieee_fw_rev))) | ||||
5460 | link->dpcd_caps.sink_fw_revision,__builtin_memmove((link->dpcd_caps.sink_fw_revision), (dp_hw_fw_revision .ieee_fw_rev), (sizeof(dp_hw_fw_revision.ieee_fw_rev))) | ||||
5461 | dp_hw_fw_revision.ieee_fw_rev,__builtin_memmove((link->dpcd_caps.sink_fw_revision), (dp_hw_fw_revision .ieee_fw_rev), (sizeof(dp_hw_fw_revision.ieee_fw_rev))) | ||||
5462 | sizeof(dp_hw_fw_revision.ieee_fw_rev))__builtin_memmove((link->dpcd_caps.sink_fw_revision), (dp_hw_fw_revision .ieee_fw_rev), (sizeof(dp_hw_fw_revision.ieee_fw_rev))); | ||||
5463 | |||||
5464 | /* Quirk for Apple MBP 2018 15" Retina panels: wrong DP_MAX_LINK_RATE */ | ||||
5465 | { | ||||
5466 | uint8_t str_mbp_2018[] = { 101, 68, 21, 103, 98, 97 }; | ||||
5467 | uint8_t fwrev_mbp_2018[] = { 7, 4 }; | ||||
5468 | uint8_t fwrev_mbp_2018_vega[] = { 8, 4 }; | ||||
5469 | |||||
5470 | /* We also check for the firmware revision as 16,1 models have an | ||||
5471 | * identical device id and are incorrectly quirked otherwise. | ||||
5472 | */ | ||||
5473 | if ((link->dpcd_caps.sink_dev_id == 0x0010fa) && | ||||
5474 | !memcmp(link->dpcd_caps.sink_dev_id_str, str_mbp_2018,__builtin_memcmp((link->dpcd_caps.sink_dev_id_str), (str_mbp_2018 ), (sizeof(str_mbp_2018))) | ||||
5475 | sizeof(str_mbp_2018))__builtin_memcmp((link->dpcd_caps.sink_dev_id_str), (str_mbp_2018 ), (sizeof(str_mbp_2018))) && | ||||
5476 | (!memcmp(link->dpcd_caps.sink_fw_revision, fwrev_mbp_2018,__builtin_memcmp((link->dpcd_caps.sink_fw_revision), (fwrev_mbp_2018 ), (sizeof(fwrev_mbp_2018))) | ||||
5477 | sizeof(fwrev_mbp_2018))__builtin_memcmp((link->dpcd_caps.sink_fw_revision), (fwrev_mbp_2018 ), (sizeof(fwrev_mbp_2018))) || | ||||
5478 | !memcmp(link->dpcd_caps.sink_fw_revision, fwrev_mbp_2018_vega,__builtin_memcmp((link->dpcd_caps.sink_fw_revision), (fwrev_mbp_2018_vega ), (sizeof(fwrev_mbp_2018_vega))) | ||||
5479 | sizeof(fwrev_mbp_2018_vega))__builtin_memcmp((link->dpcd_caps.sink_fw_revision), (fwrev_mbp_2018_vega ), (sizeof(fwrev_mbp_2018_vega))))) { | ||||
5480 | link->reported_link_cap.link_rate = LINK_RATE_RBR2; | ||||
5481 | } | ||||
5482 | } | ||||
5483 | |||||
5484 | memset(&link->dpcd_caps.dsc_caps, '\0',__builtin_memset((&link->dpcd_caps.dsc_caps), ('\0'), ( sizeof(link->dpcd_caps.dsc_caps))) | ||||
5485 | sizeof(link->dpcd_caps.dsc_caps))__builtin_memset((&link->dpcd_caps.dsc_caps), ('\0'), ( sizeof(link->dpcd_caps.dsc_caps))); | ||||
5486 | memset(&link->dpcd_caps.fec_cap, '\0', sizeof(link->dpcd_caps.fec_cap))__builtin_memset((&link->dpcd_caps.fec_cap), ('\0'), ( sizeof(link->dpcd_caps.fec_cap))); | ||||
5487 | /* Read DSC and FEC sink capabilities if DP revision is 1.4 and up */ | ||||
5488 | if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_14) { | ||||
5489 | status = core_link_read_dpcd( | ||||
5490 | link, | ||||
5491 | DP_FEC_CAPABILITY0x090, | ||||
5492 | &link->dpcd_caps.fec_cap.raw, | ||||
5493 | sizeof(link->dpcd_caps.fec_cap.raw)); | ||||
5494 | status = core_link_read_dpcd( | ||||
5495 | link, | ||||
5496 | DP_DSC_SUPPORT0x060, | ||||
5497 | link->dpcd_caps.dsc_caps.dsc_basic_caps.raw, | ||||
5498 | sizeof(link->dpcd_caps.dsc_caps.dsc_basic_caps.raw)); | ||||
5499 | if (link->dpcd_caps.dongle_type != DISPLAY_DONGLE_NONE) { | ||||
5500 | status = core_link_read_dpcd( | ||||
5501 | link, | ||||
5502 | DP_DSC_BRANCH_OVERALL_THROUGHPUT_00x0a0, | ||||
5503 | link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.raw, | ||||
5504 | sizeof(link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.raw)); | ||||
5505 | DC_LOG_DSC("DSC branch decoder capability is read at link %d", link->link_index)___drm_dbg(((void *)0), DRM_UT_KMS, "DSC branch decoder capability is read at link %d" , link->link_index); | ||||
5506 | DC_LOG_DSC("\tBRANCH_OVERALL_THROUGHPUT_0 = 0x%02x",___drm_dbg(((void *)0), DRM_UT_KMS, "\tBRANCH_OVERALL_THROUGHPUT_0 = 0x%02x" , link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.fields. BRANCH_OVERALL_THROUGHPUT_0) | ||||
5507 | link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.fields.BRANCH_OVERALL_THROUGHPUT_0)___drm_dbg(((void *)0), DRM_UT_KMS, "\tBRANCH_OVERALL_THROUGHPUT_0 = 0x%02x" , link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.fields. BRANCH_OVERALL_THROUGHPUT_0); | ||||
5508 | DC_LOG_DSC("\tBRANCH_OVERALL_THROUGHPUT_1 = 0x%02x",___drm_dbg(((void *)0), DRM_UT_KMS, "\tBRANCH_OVERALL_THROUGHPUT_1 = 0x%02x" , link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.fields. BRANCH_OVERALL_THROUGHPUT_1) | ||||
5509 | link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.fields.BRANCH_OVERALL_THROUGHPUT_1)___drm_dbg(((void *)0), DRM_UT_KMS, "\tBRANCH_OVERALL_THROUGHPUT_1 = 0x%02x" , link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.fields. BRANCH_OVERALL_THROUGHPUT_1); | ||||
5510 | DC_LOG_DSC("\tBRANCH_MAX_LINE_WIDTH 0x%02x",___drm_dbg(((void *)0), DRM_UT_KMS, "\tBRANCH_MAX_LINE_WIDTH 0x%02x" , link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.fields. BRANCH_MAX_LINE_WIDTH) | ||||
5511 | link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.fields.BRANCH_MAX_LINE_WIDTH)___drm_dbg(((void *)0), DRM_UT_KMS, "\tBRANCH_MAX_LINE_WIDTH 0x%02x" , link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.fields. BRANCH_MAX_LINE_WIDTH); | ||||
5512 | } | ||||
5513 | |||||
5514 | /* Apply work around to disable FEC and DSC for USB4 tunneling in TBT3 compatibility mode | ||||
5515 | * only if required. | ||||
5516 | */ | ||||
5517 | if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA && | ||||
5518 | link->dc->debug.dpia_debug.bits.enable_force_tbt3_work_around && | ||||
5519 | link->dpcd_caps.is_branch_dev && | ||||
5520 | link->dpcd_caps.branch_dev_id == DP_BRANCH_DEVICE_ID_90CC240x90CC24 && | ||||
5521 | link->dpcd_caps.branch_hw_revision == DP_BRANCH_HW_REV_100x10 && | ||||
5522 | (link->dpcd_caps.fec_cap.bits.FEC_CAPABLE || | ||||
5523 | link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_SUPPORT)) { | ||||
5524 | /* A TBT3 device is expected to report no support for FEC or DSC to a USB4 DPIA. | ||||
5525 | * Clear FEC and DSC capabilities as a work around if that is not the case. | ||||
5526 | */ | ||||
5527 | link->wa_flags.dpia_forced_tbt3_mode = true1; | ||||
5528 | memset(&link->dpcd_caps.dsc_caps, '\0', sizeof(link->dpcd_caps.dsc_caps))__builtin_memset((&link->dpcd_caps.dsc_caps), ('\0'), ( sizeof(link->dpcd_caps.dsc_caps))); | ||||
5529 | memset(&link->dpcd_caps.fec_cap, '\0', sizeof(link->dpcd_caps.fec_cap))__builtin_memset((&link->dpcd_caps.fec_cap), ('\0'), ( sizeof(link->dpcd_caps.fec_cap))); | ||||
5530 | DC_LOG_DSC("Clear DSC SUPPORT for USB4 link(%d) in TBT3 compatibility mode", link->link_index)___drm_dbg(((void *)0), DRM_UT_KMS, "Clear DSC SUPPORT for USB4 link(%d) in TBT3 compatibility mode" , link->link_index); | ||||
5531 | } else | ||||
5532 | link->wa_flags.dpia_forced_tbt3_mode = false0; | ||||
5533 | } | ||||
5534 | |||||
5535 | if (!dpcd_read_sink_ext_caps(link)) | ||||
5536 | link->dpcd_sink_ext_caps.raw = 0; | ||||
5537 | |||||
5538 | if (link->dpcd_caps.channel_coding_cap.bits.DP_128b_132b_SUPPORTED) { | ||||
5539 | DC_LOG_DP2("128b/132b encoding is supported at link %d", link->link_index)___drm_dbg(((void *)0), DRM_UT_KMS, "128b/132b encoding is supported at link %d" , link->link_index); | ||||
5540 | |||||
5541 | core_link_read_dpcd(link, | ||||
5542 | DP_128b_132b_SUPPORTED_LINK_RATES0x2215, | ||||
5543 | &link->dpcd_caps.dp_128b_132b_supported_link_rates.raw, | ||||
5544 | sizeof(link->dpcd_caps.dp_128b_132b_supported_link_rates.raw)); | ||||
5545 | if (link->dpcd_caps.dp_128b_132b_supported_link_rates.bits.UHBR20) | ||||
5546 | link->reported_link_cap.link_rate = LINK_RATE_UHBR20; | ||||
5547 | else if (link->dpcd_caps.dp_128b_132b_supported_link_rates.bits.UHBR13_5) | ||||
5548 | link->reported_link_cap.link_rate = LINK_RATE_UHBR13_5; | ||||
5549 | else if (link->dpcd_caps.dp_128b_132b_supported_link_rates.bits.UHBR10) | ||||
5550 | link->reported_link_cap.link_rate = LINK_RATE_UHBR10; | ||||
5551 | else | ||||
5552 | dm_error("%s: Invalid RX 128b_132b_supported_link_rates\n", __func__)__drm_err("%s: Invalid RX 128b_132b_supported_link_rates\n", __func__ ); | ||||
5553 | DC_LOG_DP2("128b/132b supported link rates is read at link %d", link->link_index)___drm_dbg(((void *)0), DRM_UT_KMS, "128b/132b supported link rates is read at link %d" , link->link_index); | ||||
5554 | DC_LOG_DP2("\tmax 128b/132b link rate support is %d.%d GHz",___drm_dbg(((void *)0), DRM_UT_KMS, "\tmax 128b/132b link rate support is %d.%d GHz" , link->reported_link_cap.link_rate / 100, link->reported_link_cap .link_rate % 100) | ||||
5555 | link->reported_link_cap.link_rate / 100,___drm_dbg(((void *)0), DRM_UT_KMS, "\tmax 128b/132b link rate support is %d.%d GHz" , link->reported_link_cap.link_rate / 100, link->reported_link_cap .link_rate % 100) | ||||
5556 | link->reported_link_cap.link_rate % 100)___drm_dbg(((void *)0), DRM_UT_KMS, "\tmax 128b/132b link rate support is %d.%d GHz" , link->reported_link_cap.link_rate / 100, link->reported_link_cap .link_rate % 100); | ||||
5557 | |||||
5558 | core_link_read_dpcd(link, | ||||
5559 | DP_SINK_VIDEO_FALLBACK_FORMATS0x020, | ||||
5560 | &link->dpcd_caps.fallback_formats.raw, | ||||
5561 | sizeof(link->dpcd_caps.fallback_formats.raw)); | ||||
5562 | DC_LOG_DP2("sink video fallback format is read at link %d", link->link_index)___drm_dbg(((void *)0), DRM_UT_KMS, "sink video fallback format is read at link %d" , link->link_index); | ||||
5563 | if (link->dpcd_caps.fallback_formats.bits.dp_1920x1080_60Hz_24bpp_support) | ||||
5564 | DC_LOG_DP2("\t1920x1080@60Hz 24bpp fallback format supported")___drm_dbg(((void *)0), DRM_UT_KMS, "\t1920x1080@60Hz 24bpp fallback format supported" ); | ||||
5565 | if (link->dpcd_caps.fallback_formats.bits.dp_1280x720_60Hz_24bpp_support) | ||||
5566 | DC_LOG_DP2("\t1280x720@60Hz 24bpp fallback format supported")___drm_dbg(((void *)0), DRM_UT_KMS, "\t1280x720@60Hz 24bpp fallback format supported" ); | ||||
5567 | if (link->dpcd_caps.fallback_formats.bits.dp_1024x768_60Hz_24bpp_support) | ||||
5568 | DC_LOG_DP2("\t1024x768@60Hz 24bpp fallback format supported")___drm_dbg(((void *)0), DRM_UT_KMS, "\t1024x768@60Hz 24bpp fallback format supported" ); | ||||
5569 | if (link->dpcd_caps.fallback_formats.raw == 0) { | ||||
5570 | DC_LOG_DP2("\tno supported fallback formats, assume 1920x1080@60Hz 24bpp is supported")___drm_dbg(((void *)0), DRM_UT_KMS, "\tno supported fallback formats, assume 1920x1080@60Hz 24bpp is supported" ); | ||||
5571 | link->dpcd_caps.fallback_formats.bits.dp_1920x1080_60Hz_24bpp_support = 1; | ||||
5572 | } | ||||
5573 | |||||
5574 | core_link_read_dpcd(link, | ||||
5575 | DP_FEC_CAPABILITY_10x091, | ||||
5576 | &link->dpcd_caps.fec_cap1.raw, | ||||
5577 | sizeof(link->dpcd_caps.fec_cap1.raw)); | ||||
5578 | DC_LOG_DP2("FEC CAPABILITY 1 is read at link %d", link->link_index)___drm_dbg(((void *)0), DRM_UT_KMS, "FEC CAPABILITY 1 is read at link %d" , link->link_index); | ||||
5579 | if (link->dpcd_caps.fec_cap1.bits.AGGREGATED_ERROR_COUNTERS_CAPABLE) | ||||
5580 | DC_LOG_DP2("\tFEC aggregated error counters are supported")___drm_dbg(((void *)0), DRM_UT_KMS, "\tFEC aggregated error counters are supported" ); | ||||
5581 | } | ||||
5582 | |||||
5583 | retrieve_cable_id(link); | ||||
5584 | dpcd_write_cable_id_to_dprx(link); | ||||
5585 | |||||
5586 | /* Connectivity log: detection */ | ||||
5587 | CONN_DATA_DETECT(link, dpcd_data, sizeof(dpcd_data), "Rx Caps: ")do { (void)(link); ___drm_dbg(((void *)0), DRM_UT_KMS, "Rx Caps: " ); } while (0); | ||||
5588 | |||||
5589 | return true1; | ||||
5590 | } | ||||
5591 | |||||
5592 | bool_Bool dp_overwrite_extended_receiver_cap(struct dc_link *link) | ||||
5593 | { | ||||
5594 | uint8_t dpcd_data[16]; | ||||
5595 | uint32_t read_dpcd_retry_cnt = 3; | ||||
5596 | enum dc_status status = DC_ERROR_UNEXPECTED; | ||||
5597 | union dp_downstream_port_present ds_port = { 0 }; | ||||
5598 | union down_stream_port_count down_strm_port_count; | ||||
5599 | union edp_configuration_cap edp_config_cap; | ||||
5600 | |||||
5601 | int i; | ||||
5602 | |||||
5603 | for (i = 0; i < read_dpcd_retry_cnt; i++) { | ||||
5604 | status = core_link_read_dpcd( | ||||
5605 | link, | ||||
5606 | DP_DPCD_REV0x000, | ||||
5607 | dpcd_data, | ||||
5608 | sizeof(dpcd_data)); | ||||
5609 | if (status == DC_OK) | ||||
5610 | break; | ||||
5611 | } | ||||
5612 | |||||
5613 | link->dpcd_caps.dpcd_rev.raw = | ||||
5614 | dpcd_data[DP_DPCD_REV0x000 - DP_DPCD_REV0x000]; | ||||
5615 | |||||
5616 | if (dpcd_data[DP_MAX_LANE_COUNT0x002 - DP_DPCD_REV0x000] == 0) | ||||
5617 | return false0; | ||||
5618 | |||||
5619 | ds_port.byte = dpcd_data[DP_DOWNSTREAMPORT_PRESENT0x005 - | ||||
5620 | DP_DPCD_REV0x000]; | ||||
5621 | |||||
5622 | get_active_converter_info(ds_port.byte, link); | ||||
5623 | |||||
5624 | down_strm_port_count.raw = dpcd_data[DP_DOWN_STREAM_PORT_COUNT0x007 - | ||||
5625 | DP_DPCD_REV0x000]; | ||||
5626 | |||||
5627 | link->dpcd_caps.allow_invalid_MSA_timing_param = | ||||
5628 | down_strm_port_count.bits.IGNORE_MSA_TIMING_PARAM; | ||||
5629 | |||||
5630 | link->dpcd_caps.max_ln_count.raw = dpcd_data[ | ||||
5631 | DP_MAX_LANE_COUNT0x002 - DP_DPCD_REV0x000]; | ||||
5632 | |||||
5633 | link->dpcd_caps.max_down_spread.raw = dpcd_data[ | ||||
5634 | DP_MAX_DOWNSPREAD0x003 - DP_DPCD_REV0x000]; | ||||
5635 | |||||
5636 | link->reported_link_cap.lane_count = | ||||
5637 | link->dpcd_caps.max_ln_count.bits.MAX_LANE_COUNT; | ||||
5638 | link->reported_link_cap.link_rate = dpcd_data[ | ||||
5639 | DP_MAX_LINK_RATE0x001 - DP_DPCD_REV0x000]; | ||||
5640 | link->reported_link_cap.link_spread = | ||||
5641 | link->dpcd_caps.max_down_spread.bits.MAX_DOWN_SPREAD ? | ||||
5642 | LINK_SPREAD_05_DOWNSPREAD_30KHZ : LINK_SPREAD_DISABLED; | ||||
5643 | |||||
5644 | edp_config_cap.raw = dpcd_data[ | ||||
5645 | DP_EDP_CONFIGURATION_CAP0x00d - DP_DPCD_REV0x000]; | ||||
5646 | link->dpcd_caps.panel_mode_edp = | ||||
5647 | edp_config_cap.bits.ALT_SCRAMBLER_RESET; | ||||
5648 | link->dpcd_caps.dpcd_display_control_capable = | ||||
5649 | edp_config_cap.bits.DPCD_DISPLAY_CONTROL_CAPABLE; | ||||
5650 | |||||
5651 | return true1; | ||||
5652 | } | ||||
5653 | |||||
5654 | bool_Bool detect_dp_sink_caps(struct dc_link *link) | ||||
5655 | { | ||||
5656 | return retrieve_link_cap(link); | ||||
5657 | } | ||||
5658 | |||||
5659 | static enum dc_link_rate linkRateInKHzToLinkRateMultiplier(uint32_t link_rate_in_khz) | ||||
5660 | { | ||||
5661 | enum dc_link_rate link_rate; | ||||
5662 | // LinkRate is normally stored as a multiplier of 0.27 Gbps per lane. Do the translation. | ||||
5663 | switch (link_rate_in_khz) { | ||||
5664 | case 1620000: | ||||
5665 | link_rate = LINK_RATE_LOW; // Rate_1 (RBR) - 1.62 Gbps/Lane | ||||
5666 | break; | ||||
5667 | case 2160000: | ||||
5668 | link_rate = LINK_RATE_RATE_2; // Rate_2 - 2.16 Gbps/Lane | ||||
5669 | break; | ||||
5670 | case 2430000: | ||||
5671 | link_rate = LINK_RATE_RATE_3; // Rate_3 - 2.43 Gbps/Lane | ||||
5672 | break; | ||||
5673 | case 2700000: | ||||
5674 | link_rate = LINK_RATE_HIGH; // Rate_4 (HBR) - 2.70 Gbps/Lane | ||||
5675 | break; | ||||
5676 | case 3240000: | ||||
5677 | link_rate = LINK_RATE_RBR2; // Rate_5 (RBR2) - 3.24 Gbps/Lane | ||||
5678 | break; | ||||
5679 | case 4320000: | ||||
5680 | link_rate = LINK_RATE_RATE_6; // Rate_6 - 4.32 Gbps/Lane | ||||
5681 | break; | ||||
5682 | case 5400000: | ||||
5683 | link_rate = LINK_RATE_HIGH2; // Rate_7 (HBR2) - 5.40 Gbps/Lane | ||||
5684 | break; | ||||
5685 | case 8100000: | ||||
5686 | link_rate = LINK_RATE_HIGH3; // Rate_8 (HBR3) - 8.10 Gbps/Lane | ||||
5687 | break; | ||||
5688 | default: | ||||
5689 | link_rate = LINK_RATE_UNKNOWN; | ||||
5690 | break; | ||||
5691 | } | ||||
5692 | return link_rate; | ||||
5693 | } | ||||
5694 | |||||
5695 | void detect_edp_sink_caps(struct dc_link *link) | ||||
5696 | { | ||||
5697 | uint8_t supported_link_rates[16]; | ||||
5698 | uint32_t entry; | ||||
5699 | uint32_t link_rate_in_khz; | ||||
5700 | enum dc_link_rate link_rate = LINK_RATE_UNKNOWN; | ||||
5701 | uint8_t backlight_adj_cap; | ||||
5702 | uint8_t general_edp_cap; | ||||
5703 | |||||
5704 | retrieve_link_cap(link); | ||||
5705 | link->dpcd_caps.edp_supported_link_rates_count = 0; | ||||
5706 | memset(supported_link_rates, 0, sizeof(supported_link_rates))__builtin_memset((supported_link_rates), (0), (sizeof(supported_link_rates ))); | ||||
5707 | |||||
5708 | /* | ||||
5709 | * edp_supported_link_rates_count is only valid for eDP v1.4 or higher. | ||||
5710 | * Per VESA eDP spec, "The DPCD revision for eDP v1.4 is 13h" | ||||
5711 | */ | ||||
5712 | if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_13 && | ||||
5713 | (link->panel_config.ilr.optimize_edp_link_rate || | ||||
5714 | link->reported_link_cap.link_rate == LINK_RATE_UNKNOWN)) { | ||||
5715 | // Read DPCD 00010h - 0001Fh 16 bytes at one shot | ||||
5716 | core_link_read_dpcd(link, DP_SUPPORTED_LINK_RATES0x010, | ||||
5717 | supported_link_rates, sizeof(supported_link_rates)); | ||||
5718 | |||||
5719 | for (entry = 0; entry < 16; entry += 2) { | ||||
5720 | // DPCD register reports per-lane link rate = 16-bit link rate capability | ||||
5721 | // value X 200 kHz. Need multiplier to find link rate in kHz. | ||||
5722 | link_rate_in_khz = (supported_link_rates[entry+1] * 0x100 + | ||||
5723 | supported_link_rates[entry]) * 200; | ||||
5724 | |||||
5725 | if (link_rate_in_khz != 0) { | ||||
5726 | link_rate = linkRateInKHzToLinkRateMultiplier(link_rate_in_khz); | ||||
5727 | link->dpcd_caps.edp_supported_link_rates[link->dpcd_caps.edp_supported_link_rates_count] = link_rate; | ||||
5728 | link->dpcd_caps.edp_supported_link_rates_count++; | ||||
5729 | |||||
5730 | if (link->reported_link_cap.link_rate < link_rate) | ||||
5731 | link->reported_link_cap.link_rate = link_rate; | ||||
5732 | } | ||||
5733 | } | ||||
5734 | } | ||||
5735 | core_link_read_dpcd(link, DP_EDP_BACKLIGHT_ADJUSTMENT_CAP0x702, | ||||
5736 | &backlight_adj_cap, sizeof(backlight_adj_cap)); | ||||
5737 | |||||
5738 | link->dpcd_caps.dynamic_backlight_capable_edp = | ||||
5739 | (backlight_adj_cap & DP_EDP_DYNAMIC_BACKLIGHT_CAP(1 << 6)) ? true1:false0; | ||||
5740 | |||||
5741 | core_link_read_dpcd(link, DP_EDP_GENERAL_CAP_10x701, | ||||
5742 | &general_edp_cap, sizeof(general_edp_cap)); | ||||
5743 | |||||
5744 | link->dpcd_caps.set_power_state_capable_edp = | ||||
5745 | (general_edp_cap & DP_EDP_SET_POWER_CAP(1 << 7)) ? true1:false0; | ||||
5746 | |||||
5747 | dc_link_set_default_brightness_aux(link); | ||||
5748 | |||||
5749 | core_link_read_dpcd(link, DP_EDP_DPCD_REV0x700, | ||||
5750 | &link->dpcd_caps.edp_rev, | ||||
5751 | sizeof(link->dpcd_caps.edp_rev)); | ||||
5752 | /* | ||||
5753 | * PSR is only valid for eDP v1.3 or higher. | ||||
5754 | */ | ||||
5755 | if (link->dpcd_caps.edp_rev >= DP_EDP_130x02) { | ||||
5756 | core_link_read_dpcd(link, DP_PSR_SUPPORT0x070, | ||||
5757 | &link->dpcd_caps.psr_info.psr_version, | ||||
5758 | sizeof(link->dpcd_caps.psr_info.psr_version)); | ||||
5759 | if (link->dpcd_caps.sink_dev_id == DP_BRANCH_DEVICE_ID_001CF80x001CF8) | ||||
5760 | core_link_read_dpcd(link, DP_FORCE_PSRSU_CAPABILITY0x40F, | ||||
5761 | &link->dpcd_caps.psr_info.force_psrsu_cap, | ||||
5762 | sizeof(link->dpcd_caps.psr_info.force_psrsu_cap)); | ||||
5763 | core_link_read_dpcd(link, DP_PSR_CAPS0x071, | ||||
5764 | &link->dpcd_caps.psr_info.psr_dpcd_caps.raw, | ||||
5765 | sizeof(link->dpcd_caps.psr_info.psr_dpcd_caps.raw)); | ||||
5766 | if (link->dpcd_caps.psr_info.psr_dpcd_caps.bits.Y_COORDINATE_REQUIRED) { | ||||
5767 | core_link_read_dpcd(link, DP_PSR2_SU_Y_GRANULARITY0x074, | ||||
5768 | &link->dpcd_caps.psr_info.psr2_su_y_granularity_cap, | ||||
5769 | sizeof(link->dpcd_caps.psr_info.psr2_su_y_granularity_cap)); | ||||
5770 | } | ||||
5771 | } | ||||
5772 | |||||
5773 | /* | ||||
5774 | * ALPM is only valid for eDP v1.4 or higher. | ||||
5775 | */ | ||||
5776 | if (link->dpcd_caps.dpcd_rev.raw >= DP_EDP_140x03) | ||||
5777 | core_link_read_dpcd(link, DP_RECEIVER_ALPM_CAP0x02e, | ||||
5778 | &link->dpcd_caps.alpm_caps.raw, | ||||
5779 | sizeof(link->dpcd_caps.alpm_caps.raw)); | ||||
5780 | } | ||||
5781 | |||||
5782 | void dc_link_dp_enable_hpd(const struct dc_link *link) | ||||
5783 | { | ||||
5784 | struct link_encoder *encoder = link->link_enc; | ||||
5785 | |||||
5786 | if (encoder != NULL((void *)0) && encoder->funcs->enable_hpd != NULL((void *)0)) | ||||
5787 | encoder->funcs->enable_hpd(encoder); | ||||
5788 | } | ||||
5789 | |||||
5790 | void dc_link_dp_disable_hpd(const struct dc_link *link) | ||||
5791 | { | ||||
5792 | struct link_encoder *encoder = link->link_enc; | ||||
5793 | |||||
5794 | if (encoder != NULL((void *)0) && encoder->funcs->enable_hpd != NULL((void *)0)) | ||||
5795 | encoder->funcs->disable_hpd(encoder); | ||||
5796 | } | ||||
5797 | |||||
5798 | static bool_Bool is_dp_phy_pattern(enum dp_test_pattern test_pattern) | ||||
5799 | { | ||||
5800 | if ((DP_TEST_PATTERN_PHY_PATTERN_BEGIN <= test_pattern && | ||||
5801 | test_pattern <= DP_TEST_PATTERN_PHY_PATTERN_END) || | ||||
5802 | test_pattern == DP_TEST_PATTERN_VIDEO_MODE) | ||||
5803 | return true1; | ||||
5804 | else | ||||
5805 | return false0; | ||||
5806 | } | ||||
5807 | |||||
5808 | static void set_crtc_test_pattern(struct dc_link *link, | ||||
5809 | struct pipe_ctx *pipe_ctx, | ||||
5810 | enum dp_test_pattern test_pattern, | ||||
5811 | enum dp_test_pattern_color_space test_pattern_color_space) | ||||
5812 | { | ||||
5813 | enum controller_dp_test_pattern controller_test_pattern; | ||||
5814 | enum dc_color_depth color_depth = pipe_ctx-> | ||||
5815 | stream->timing.display_color_depth; | ||||
5816 | struct bit_depth_reduction_params params; | ||||
5817 | struct output_pixel_processor *opp = pipe_ctx->stream_res.opp; | ||||
5818 | int width = pipe_ctx->stream->timing.h_addressable + | ||||
5819 | pipe_ctx->stream->timing.h_border_left + | ||||
5820 | pipe_ctx->stream->timing.h_border_right; | ||||
5821 | int height = pipe_ctx->stream->timing.v_addressable + | ||||
5822 | pipe_ctx->stream->timing.v_border_bottom + | ||||
5823 | pipe_ctx->stream->timing.v_border_top; | ||||
5824 | |||||
5825 | memset(¶ms, 0, sizeof(params))__builtin_memset((¶ms), (0), (sizeof(params))); | ||||
5826 | |||||
5827 | switch (test_pattern) { | ||||
5828 | case DP_TEST_PATTERN_COLOR_SQUARES: | ||||
5829 | controller_test_pattern = | ||||
5830 | CONTROLLER_DP_TEST_PATTERN_COLORSQUARES; | ||||
5831 | break; | ||||
5832 | case DP_TEST_PATTERN_COLOR_SQUARES_CEA: | ||||
5833 | controller_test_pattern = | ||||
5834 | CONTROLLER_DP_TEST_PATTERN_COLORSQUARES_CEA; | ||||
5835 | break; | ||||
5836 | case DP_TEST_PATTERN_VERTICAL_BARS: | ||||
5837 | controller_test_pattern = | ||||
5838 | CONTROLLER_DP_TEST_PATTERN_VERTICALBARS; | ||||
5839 | break; | ||||
5840 | case DP_TEST_PATTERN_HORIZONTAL_BARS: | ||||
5841 | controller_test_pattern = | ||||
5842 | CONTROLLER_DP_TEST_PATTERN_HORIZONTALBARS; | ||||
5843 | break; | ||||
5844 | case DP_TEST_PATTERN_COLOR_RAMP: | ||||
5845 | controller_test_pattern = | ||||
5846 | CONTROLLER_DP_TEST_PATTERN_COLORRAMP; | ||||
5847 | break; | ||||
5848 | default: | ||||
5849 | controller_test_pattern = | ||||
5850 | CONTROLLER_DP_TEST_PATTERN_VIDEOMODE; | ||||
5851 | break; | ||||
5852 | } | ||||
5853 | |||||
5854 | switch (test_pattern) { | ||||
5855 | case DP_TEST_PATTERN_COLOR_SQUARES: | ||||
5856 | case DP_TEST_PATTERN_COLOR_SQUARES_CEA: | ||||
5857 | case DP_TEST_PATTERN_VERTICAL_BARS: | ||||
5858 | case DP_TEST_PATTERN_HORIZONTAL_BARS: | ||||
5859 | case DP_TEST_PATTERN_COLOR_RAMP: | ||||
5860 | { | ||||
5861 | /* disable bit depth reduction */ | ||||
5862 | pipe_ctx->stream->bit_depth_params = params; | ||||
5863 | opp->funcs->opp_program_bit_depth_reduction(opp, ¶ms); | ||||
5864 | if (pipe_ctx->stream_res.tg->funcs->set_test_pattern) | ||||
5865 | pipe_ctx->stream_res.tg->funcs->set_test_pattern(pipe_ctx->stream_res.tg, | ||||
5866 | controller_test_pattern, color_depth); | ||||
5867 | else if (link->dc->hwss.set_disp_pattern_generator) { | ||||
5868 | struct pipe_ctx *odm_pipe; | ||||
5869 | enum controller_dp_color_space controller_color_space; | ||||
5870 | int opp_cnt = 1; | ||||
5871 | int offset = 0; | ||||
5872 | int dpg_width = width; | ||||
5873 | |||||
5874 | switch (test_pattern_color_space) { | ||||
5875 | case DP_TEST_PATTERN_COLOR_SPACE_RGB: | ||||
5876 | controller_color_space = CONTROLLER_DP_COLOR_SPACE_RGB; | ||||
5877 | break; | ||||
5878 | case DP_TEST_PATTERN_COLOR_SPACE_YCBCR601: | ||||
5879 | controller_color_space = CONTROLLER_DP_COLOR_SPACE_YCBCR601; | ||||
5880 | break; | ||||
5881 | case DP_TEST_PATTERN_COLOR_SPACE_YCBCR709: | ||||
5882 | controller_color_space = CONTROLLER_DP_COLOR_SPACE_YCBCR709; | ||||
5883 | break; | ||||
5884 | case DP_TEST_PATTERN_COLOR_SPACE_UNDEFINED: | ||||
5885 | default: | ||||
5886 | controller_color_space = CONTROLLER_DP_COLOR_SPACE_UDEFINED; | ||||
5887 | DC_LOG_ERROR("%s: Color space must be defined for test pattern", __func__)__drm_err("%s: Color space must be defined for test pattern", __func__); | ||||
5888 | ASSERT(0)do { if (({ static int __warned; int __ret = !!(!(0)); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n" , "!(0)", "/usr/src/sys/dev/pci/drm/amd/display/dc/core/dc_link_dp.c" , 5888); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | ||||
5889 | break; | ||||
5890 | } | ||||
5891 | |||||
5892 | for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) | ||||
5893 | opp_cnt++; | ||||
5894 | dpg_width = width / opp_cnt; | ||||
5895 | offset = dpg_width; | ||||
5896 | |||||
5897 | link->dc->hwss.set_disp_pattern_generator(link->dc, | ||||
5898 | pipe_ctx, | ||||
5899 | controller_test_pattern, | ||||
5900 | controller_color_space, | ||||
5901 | color_depth, | ||||
5902 | NULL((void *)0), | ||||
5903 | dpg_width, | ||||
5904 | height, | ||||
5905 | 0); | ||||
5906 | |||||
5907 | for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { | ||||
5908 | struct output_pixel_processor *odm_opp = odm_pipe->stream_res.opp; | ||||
5909 | |||||
5910 | odm_opp->funcs->opp_program_bit_depth_reduction(odm_opp, ¶ms); | ||||
5911 | link->dc->hwss.set_disp_pattern_generator(link->dc, | ||||
5912 | odm_pipe, | ||||
5913 | controller_test_pattern, | ||||
5914 | controller_color_space, | ||||
5915 | color_depth, | ||||
5916 | NULL((void *)0), | ||||
5917 | dpg_width, | ||||
5918 | height, | ||||
5919 | offset); | ||||
5920 | offset += offset; | ||||
5921 | } | ||||
5922 | } | ||||
5923 | } | ||||
5924 | break; | ||||
5925 | case DP_TEST_PATTERN_VIDEO_MODE: | ||||
5926 | { | ||||
5927 | /* restore bitdepth reduction */ | ||||
5928 | resource_build_bit_depth_reduction_params(pipe_ctx->stream, ¶ms); | ||||
5929 | pipe_ctx->stream->bit_depth_params = params; | ||||
5930 | opp->funcs->opp_program_bit_depth_reduction(opp, ¶ms); | ||||
5931 | if (pipe_ctx->stream_res.tg->funcs->set_test_pattern) | ||||
5932 | pipe_ctx->stream_res.tg->funcs->set_test_pattern(pipe_ctx->stream_res.tg, | ||||
5933 | CONTROLLER_DP_TEST_PATTERN_VIDEOMODE, | ||||
5934 | color_depth); | ||||
5935 | else if (link->dc->hwss.set_disp_pattern_generator) { | ||||
5936 | struct pipe_ctx *odm_pipe; | ||||
5937 | int opp_cnt = 1; | ||||
5938 | int dpg_width; | ||||
5939 | |||||
5940 | for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) | ||||
5941 | opp_cnt++; | ||||
5942 | |||||
5943 | dpg_width = width / opp_cnt; | ||||
5944 | for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { | ||||
5945 | struct output_pixel_processor *odm_opp = odm_pipe->stream_res.opp; | ||||
5946 | |||||
5947 | odm_opp->funcs->opp_program_bit_depth_reduction(odm_opp, ¶ms); | ||||
5948 | link->dc->hwss.set_disp_pattern_generator(link->dc, | ||||
5949 | odm_pipe, | ||||
5950 | CONTROLLER_DP_TEST_PATTERN_VIDEOMODE, | ||||
5951 | CONTROLLER_DP_COLOR_SPACE_UDEFINED, | ||||
5952 | color_depth, | ||||
5953 | NULL((void *)0), | ||||
5954 | dpg_width, | ||||
5955 | height, | ||||
5956 | 0); | ||||
5957 | } | ||||
5958 | link->dc->hwss.set_disp_pattern_generator(link->dc, | ||||
5959 | pipe_ctx, | ||||
5960 | CONTROLLER_DP_TEST_PATTERN_VIDEOMODE, | ||||
5961 | CONTROLLER_DP_COLOR_SPACE_UDEFINED, | ||||
5962 | color_depth, | ||||
5963 | NULL((void *)0), | ||||
5964 | dpg_width, | ||||
5965 | height, | ||||
5966 | 0); | ||||
5967 | } | ||||
5968 | } | ||||
5969 | break; | ||||
5970 | |||||
5971 | default: | ||||
5972 | break; | ||||
5973 | } | ||||
5974 | } | ||||
5975 | |||||
5976 | bool_Bool dc_link_dp_set_test_pattern( | ||||
5977 | struct dc_link *link, | ||||
5978 | enum dp_test_pattern test_pattern, | ||||
5979 | enum dp_test_pattern_color_space test_pattern_color_space, | ||||
5980 | const struct link_training_settings *p_link_settings, | ||||
5981 | const unsigned char *p_custom_pattern, | ||||
5982 | unsigned int cust_pattern_size) | ||||
5983 | { | ||||
5984 | struct pipe_ctx *pipes = link->dc->current_state->res_ctx.pipe_ctx; | ||||
5985 | struct pipe_ctx *pipe_ctx = NULL((void *)0); | ||||
5986 | unsigned int lane; | ||||
5987 | unsigned int i; | ||||
5988 | unsigned char link_qual_pattern[LANE_COUNT_DP_MAX] = {0}; | ||||
5989 | union dpcd_training_pattern training_pattern; | ||||
5990 | enum dpcd_phy_test_patterns pattern; | ||||
5991 | |||||
5992 | memset(&training_pattern, 0, sizeof(training_pattern))__builtin_memset((&training_pattern), (0), (sizeof(training_pattern ))); | ||||
5993 | |||||
5994 | for (i = 0; i < MAX_PIPES6; i++) { | ||||
5995 | if (pipes[i].stream == NULL((void *)0)) | ||||
5996 | continue; | ||||
5997 | |||||
5998 | if (pipes[i].stream->link == link && !pipes[i].top_pipe && !pipes[i].prev_odm_pipe) { | ||||
5999 | pipe_ctx = &pipes[i]; | ||||
6000 | break; | ||||
6001 | } | ||||
6002 | } | ||||
6003 | |||||
6004 | if (pipe_ctx == NULL((void *)0)) | ||||
6005 | return false0; | ||||
6006 | |||||
6007 | /* Reset CRTC Test Pattern if it is currently running and request is VideoMode */ | ||||
6008 | if (link->test_pattern_enabled && test_pattern == | ||||
6009 | DP_TEST_PATTERN_VIDEO_MODE) { | ||||
6010 | /* Set CRTC Test Pattern */ | ||||
6011 | set_crtc_test_pattern(link, pipe_ctx, test_pattern, test_pattern_color_space); | ||||
6012 | dp_set_hw_test_pattern(link, &pipe_ctx->link_res, test_pattern, | ||||
6013 | (uint8_t *)p_custom_pattern, | ||||
6014 | (uint32_t)cust_pattern_size); | ||||
6015 | |||||
6016 | /* Unblank Stream */ | ||||
6017 | link->dc->hwss.unblank_stream( | ||||
6018 | pipe_ctx, | ||||
6019 | &link->verified_link_cap); | ||||
6020 | /* TODO:m_pHwss->MuteAudioEndpoint | ||||
6021 | * (pPathMode->pDisplayPath, false); | ||||
6022 | */ | ||||
6023 | |||||
6024 | /* Reset Test Pattern state */ | ||||
6025 | link->test_pattern_enabled = false0; | ||||
6026 | |||||
6027 | return true1; | ||||
6028 | } | ||||
6029 | |||||
6030 | /* Check for PHY Test Patterns */ | ||||
6031 | if (is_dp_phy_pattern(test_pattern)) { | ||||
6032 | /* Set DPCD Lane Settings before running test pattern */ | ||||
6033 | if (p_link_settings != NULL((void *)0)) { | ||||
6034 | if ((link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) && | ||||
6035 | p_link_settings->lttpr_mode == LTTPR_MODE_TRANSPARENT) { | ||||
6036 | dp_fixed_vs_pe_set_retimer_lane_settings( | ||||
6037 | link, | ||||
6038 | p_link_settings->dpcd_lane_settings, | ||||
6039 | p_link_settings->link_settings.lane_count); | ||||
6040 | } else { | ||||
6041 | dp_set_hw_lane_settings(link, &pipe_ctx->link_res, p_link_settings, DPRX); | ||||
6042 | } | ||||
6043 | dpcd_set_lane_settings(link, p_link_settings, DPRX); | ||||
6044 | } | ||||
6045 | |||||
6046 | /* Blank stream if running test pattern */ | ||||
6047 | if (test_pattern != DP_TEST_PATTERN_VIDEO_MODE) { | ||||
6048 | /*TODO: | ||||
6049 | * m_pHwss-> | ||||
6050 | * MuteAudioEndpoint(pPathMode->pDisplayPath, true); | ||||
6051 | */ | ||||
6052 | /* Blank stream */ | ||||
6053 | pipes->stream_res.stream_enc->funcs->dp_blank(link, pipe_ctx->stream_res.stream_enc); | ||||
6054 | } | ||||
6055 | |||||
6056 | dp_set_hw_test_pattern(link, &pipe_ctx->link_res, test_pattern, | ||||
6057 | (uint8_t *)p_custom_pattern, | ||||
6058 | (uint32_t)cust_pattern_size); | ||||
6059 | |||||
6060 | if (test_pattern != DP_TEST_PATTERN_VIDEO_MODE) { | ||||
6061 | /* Set Test Pattern state */ | ||||
6062 | link->test_pattern_enabled = true1; | ||||
6063 | if (p_link_settings != NULL((void *)0)) | ||||
6064 | dpcd_set_link_settings(link, | ||||
6065 | p_link_settings); | ||||
6066 | } | ||||
6067 | |||||
6068 | switch (test_pattern) { | ||||
6069 | case DP_TEST_PATTERN_VIDEO_MODE: | ||||
6070 | pattern = PHY_TEST_PATTERN_NONE; | ||||
6071 | break; | ||||
6072 | case DP_TEST_PATTERN_D102: | ||||
6073 | pattern = PHY_TEST_PATTERN_D10_2; | ||||
6074 | break; | ||||
6075 | case DP_TEST_PATTERN_SYMBOL_ERROR: | ||||
6076 | pattern = PHY_TEST_PATTERN_SYMBOL_ERROR; | ||||
6077 | break; | ||||
6078 | case DP_TEST_PATTERN_PRBS7: | ||||
6079 | pattern = PHY_TEST_PATTERN_PRBS7; | ||||
6080 | break; | ||||
6081 | case DP_TEST_PATTERN_80BIT_CUSTOM: | ||||
6082 | pattern = PHY_TEST_PATTERN_80BIT_CUSTOM; | ||||
6083 | break; | ||||
6084 | case DP_TEST_PATTERN_CP2520_1: | ||||
6085 | pattern = PHY_TEST_PATTERN_CP2520_1; | ||||
6086 | break; | ||||
6087 | case DP_TEST_PATTERN_CP2520_2: | ||||
6088 | pattern = PHY_TEST_PATTERN_CP2520_2; | ||||
6089 | break; | ||||
6090 | case DP_TEST_PATTERN_CP2520_3: | ||||
6091 | pattern = PHY_TEST_PATTERN_CP2520_3; | ||||
6092 | break; | ||||
6093 | case DP_TEST_PATTERN_128b_132b_TPS1: | ||||
6094 | pattern = PHY_TEST_PATTERN_128b_132b_TPS1; | ||||
6095 | break; | ||||
6096 | case DP_TEST_PATTERN_128b_132b_TPS2: | ||||
6097 | pattern = PHY_TEST_PATTERN_128b_132b_TPS2; | ||||
6098 | break; | ||||
6099 | case DP_TEST_PATTERN_PRBS9: | ||||
6100 | pattern = PHY_TEST_PATTERN_PRBS9; | ||||
6101 | break; | ||||
6102 | case DP_TEST_PATTERN_PRBS11: | ||||
6103 | pattern = PHY_TEST_PATTERN_PRBS11; | ||||
6104 | break; | ||||
6105 | case DP_TEST_PATTERN_PRBS15: | ||||
6106 | pattern = PHY_TEST_PATTERN_PRBS15; | ||||
6107 | break; | ||||
6108 | case DP_TEST_PATTERN_PRBS23: | ||||
6109 | pattern = PHY_TEST_PATTERN_PRBS23; | ||||
6110 | break; | ||||
6111 | case DP_TEST_PATTERN_PRBS31: | ||||
6112 | pattern = PHY_TEST_PATTERN_PRBS31; | ||||
6113 | break; | ||||
6114 | case DP_TEST_PATTERN_264BIT_CUSTOM: | ||||
6115 | pattern = PHY_TEST_PATTERN_264BIT_CUSTOM; | ||||
6116 | break; | ||||
6117 | case DP_TEST_PATTERN_SQUARE_PULSE: | ||||
6118 | pattern = PHY_TEST_PATTERN_SQUARE_PULSE; | ||||
6119 | break; | ||||
6120 | default: | ||||
6121 | return false0; | ||||
6122 | } | ||||
6123 | |||||
6124 | if (test_pattern == DP_TEST_PATTERN_VIDEO_MODE | ||||
6125 | /*TODO:&& !pPathMode->pDisplayPath->IsTargetPoweredOn()*/) | ||||
6126 | return false0; | ||||
6127 | |||||
6128 | if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_12) { | ||||
6129 | #if defined(CONFIG_DRM_AMD_DC_DCN1) | ||||
6130 | if (test_pattern == DP_TEST_PATTERN_SQUARE_PULSE) | ||||
6131 | core_link_write_dpcd(link, | ||||
6132 | DP_LINK_SQUARE_PATTERN0x10F, | ||||
6133 | p_custom_pattern, | ||||
6134 | 1); | ||||
6135 | |||||
6136 | #endif | ||||
6137 | /* tell receiver that we are sending qualification | ||||
6138 | * pattern DP 1.2 or later - DP receiver's link quality | ||||
6139 | * pattern is set using DPCD LINK_QUAL_LANEx_SET | ||||
6140 | * register (0x10B~0x10E)\ | ||||
6141 | */ | ||||
6142 | for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) | ||||
6143 | link_qual_pattern[lane] = | ||||
6144 | (unsigned char)(pattern); | ||||
6145 | |||||
6146 | core_link_write_dpcd(link, | ||||
6147 | DP_LINK_QUAL_LANE0_SET0x10b, | ||||
6148 | link_qual_pattern, | ||||
6149 | sizeof(link_qual_pattern)); | ||||
6150 | } else if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_10 || | ||||
6151 | link->dpcd_caps.dpcd_rev.raw == 0) { | ||||
6152 | /* tell receiver that we are sending qualification | ||||
6153 | * pattern DP 1.1a or earlier - DP receiver's link | ||||
6154 | * quality pattern is set using | ||||
6155 | * DPCD TRAINING_PATTERN_SET -> LINK_QUAL_PATTERN_SET | ||||
6156 | * register (0x102). We will use v_1.3 when we are | ||||
6157 | * setting test pattern for DP 1.1. | ||||
6158 | */ | ||||
6159 | core_link_read_dpcd(link, DP_TRAINING_PATTERN_SET0x102, | ||||
6160 | &training_pattern.raw, | ||||
6161 | sizeof(training_pattern)); | ||||
6162 | training_pattern.v1_3.LINK_QUAL_PATTERN_SET = pattern; | ||||
6163 | core_link_write_dpcd(link, DP_TRAINING_PATTERN_SET0x102, | ||||
6164 | &training_pattern.raw, | ||||
6165 | sizeof(training_pattern)); | ||||
6166 | } | ||||
6167 | } else { | ||||
6168 | enum dc_color_space color_space = COLOR_SPACE_UNKNOWN; | ||||
6169 | |||||
6170 | switch (test_pattern_color_space) { | ||||
6171 | case DP_TEST_PATTERN_COLOR_SPACE_RGB: | ||||
6172 | color_space = COLOR_SPACE_SRGB; | ||||
6173 | if (test_pattern == DP_TEST_PATTERN_COLOR_SQUARES_CEA) | ||||
6174 | color_space = COLOR_SPACE_SRGB_LIMITED; | ||||
6175 | break; | ||||
6176 | |||||
6177 | case DP_TEST_PATTERN_COLOR_SPACE_YCBCR601: | ||||
6178 | color_space = COLOR_SPACE_YCBCR601; | ||||
6179 | if (test_pattern == DP_TEST_PATTERN_COLOR_SQUARES_CEA) | ||||
6180 | color_space = COLOR_SPACE_YCBCR601_LIMITED; | ||||
6181 | break; | ||||
6182 | case DP_TEST_PATTERN_COLOR_SPACE_YCBCR709: | ||||
6183 | color_space = COLOR_SPACE_YCBCR709; | ||||
6184 | if (test_pattern == DP_TEST_PATTERN_COLOR_SQUARES_CEA) | ||||
6185 | color_space = COLOR_SPACE_YCBCR709_LIMITED; | ||||
6186 | break; | ||||
6187 | default: | ||||
6188 | break; | ||||
6189 | } | ||||
6190 | |||||
6191 | if (pipe_ctx->stream_res.tg->funcs->lock_doublebuffer_enable) { | ||||
6192 | if (pipe_ctx->stream && should_use_dmub_lock(pipe_ctx->stream->link)) { | ||||
6193 | union dmub_hw_lock_flags hw_locks = { 0 }; | ||||
6194 | struct dmub_hw_lock_inst_flags inst_flags = { 0 }; | ||||
6195 | |||||
6196 | hw_locks.bits.lock_dig = 1; | ||||
6197 | inst_flags.dig_inst = pipe_ctx->stream_res.tg->inst; | ||||
6198 | |||||
6199 | dmub_hw_lock_mgr_cmd(link->ctx->dmub_srv, | ||||
6200 | true1, | ||||
6201 | &hw_locks, | ||||
6202 | &inst_flags); | ||||
6203 | } else | ||||
6204 | pipe_ctx->stream_res.tg->funcs->lock_doublebuffer_enable( | ||||
6205 | pipe_ctx->stream_res.tg); | ||||
6206 | } | ||||
6207 | |||||
6208 | pipe_ctx->stream_res.tg->funcs->lock(pipe_ctx->stream_res.tg); | ||||
6209 | /* update MSA to requested color space */ | ||||
6210 | pipe_ctx->stream_res.stream_enc->funcs->dp_set_stream_attribute(pipe_ctx->stream_res.stream_enc, | ||||
6211 | &pipe_ctx->stream->timing, | ||||
6212 | color_space, | ||||
6213 | pipe_ctx->stream->use_vsc_sdp_for_colorimetry, | ||||
6214 | link->dpcd_caps.dprx_feature.bits.SST_SPLIT_SDP_CAP); | ||||
6215 | |||||
6216 | if (pipe_ctx->stream->use_vsc_sdp_for_colorimetry) { | ||||
6217 | if (test_pattern == DP_TEST_PATTERN_COLOR_SQUARES_CEA) | ||||
6218 | pipe_ctx->stream->vsc_infopacket.sb[17] |= (1 << 7); // sb17 bit 7 Dynamic Range: 0 = VESA range, 1 = CTA range | ||||
6219 | else | ||||
6220 | pipe_ctx->stream->vsc_infopacket.sb[17] &= ~(1 << 7); | ||||
6221 | resource_build_info_frame(pipe_ctx); | ||||
6222 | link->dc->hwss.update_info_frame(pipe_ctx); | ||||
6223 | } | ||||
6224 | |||||
6225 | /* CRTC Patterns */ | ||||
6226 | set_crtc_test_pattern(link, pipe_ctx, test_pattern, test_pattern_color_space); | ||||
6227 | pipe_ctx->stream_res.tg->funcs->unlock(pipe_ctx->stream_res.tg); | ||||
6228 | pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, | ||||
6229 | CRTC_STATE_VACTIVE); | ||||
6230 | pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, | ||||
6231 | CRTC_STATE_VBLANK); | ||||
6232 | pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, | ||||
6233 | CRTC_STATE_VACTIVE); | ||||
6234 | |||||
6235 | if (pipe_ctx->stream_res.tg->funcs->lock_doublebuffer_disable) { | ||||
6236 | if (pipe_ctx->stream && should_use_dmub_lock(pipe_ctx->stream->link)) { | ||||
6237 | union dmub_hw_lock_flags hw_locks = { 0 }; | ||||
6238 | struct dmub_hw_lock_inst_flags inst_flags = { 0 }; | ||||
6239 | |||||
6240 | hw_locks.bits.lock_dig = 1; | ||||
6241 | inst_flags.dig_inst = pipe_ctx->stream_res.tg->inst; | ||||
6242 | |||||
6243 | dmub_hw_lock_mgr_cmd(link->ctx->dmub_srv, | ||||
6244 | false0, | ||||
6245 | &hw_locks, | ||||
6246 | &inst_flags); | ||||
6247 | } else | ||||
6248 | pipe_ctx->stream_res.tg->funcs->lock_doublebuffer_disable( | ||||
6249 | pipe_ctx->stream_res.tg); | ||||
6250 | } | ||||
6251 | |||||
6252 | /* Set Test Pattern state */ | ||||
6253 | link->test_pattern_enabled = true1; | ||||
6254 | } | ||||
6255 | |||||
6256 | return true1; | ||||
6257 | } | ||||
6258 | |||||
6259 | void dp_enable_mst_on_sink(struct dc_link *link, bool_Bool enable) | ||||
6260 | { | ||||
6261 | unsigned char mstmCntl; | ||||
6262 | |||||
6263 | core_link_read_dpcd(link, DP_MSTM_CTRL0x111, &mstmCntl, 1); | ||||
6264 | if (enable) | ||||
6265 | mstmCntl |= DP_MST_EN(1 << 0); | ||||
6266 | else | ||||
6267 | mstmCntl &= (~DP_MST_EN(1 << 0)); | ||||
6268 | |||||
6269 | core_link_write_dpcd(link, DP_MSTM_CTRL0x111, &mstmCntl, 1); | ||||
6270 | } | ||||
6271 | |||||
6272 | void dp_set_panel_mode(struct dc_link *link, enum dp_panel_mode panel_mode) | ||||
6273 | { | ||||
6274 | union dpcd_edp_config edp_config_set; | ||||
6275 | bool_Bool panel_mode_edp = false0; | ||||
6276 | |||||
6277 | memset(&edp_config_set, '\0', sizeof(union dpcd_edp_config))__builtin_memset((&edp_config_set), ('\0'), (sizeof(union dpcd_edp_config))); | ||||
6278 | |||||
6279 | if (panel_mode != DP_PANEL_MODE_DEFAULT) { | ||||
6280 | |||||
6281 | switch (panel_mode) { | ||||
6282 | case DP_PANEL_MODE_EDP: | ||||
6283 | case DP_PANEL_MODE_SPECIAL: | ||||
6284 | panel_mode_edp = true1; | ||||
6285 | break; | ||||
6286 | |||||
6287 | default: | ||||
6288 | break; | ||||
6289 | } | ||||
6290 | |||||
6291 | /*set edp panel mode in receiver*/ | ||||
6292 | core_link_read_dpcd( | ||||
6293 | link, | ||||
6294 | DP_EDP_CONFIGURATION_SET0x10a, | ||||
6295 | &edp_config_set.raw, | ||||
6296 | sizeof(edp_config_set.raw)); | ||||
6297 | |||||
6298 | if (edp_config_set.bits.PANEL_MODE_EDP | ||||
6299 | != panel_mode_edp) { | ||||
6300 | enum dc_status result; | ||||
6301 | |||||
6302 | edp_config_set.bits.PANEL_MODE_EDP = | ||||
6303 | panel_mode_edp; | ||||
6304 | result = core_link_write_dpcd( | ||||
6305 | link, | ||||
6306 | DP_EDP_CONFIGURATION_SET0x10a, | ||||
6307 | &edp_config_set.raw, | ||||
6308 | sizeof(edp_config_set.raw)); | ||||
6309 | |||||
6310 | ASSERT(result == DC_OK)do { if (({ static int __warned; int __ret = !!(!(result == DC_OK )); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n" , "!(result == DC_OK)", "/usr/src/sys/dev/pci/drm/amd/display/dc/core/dc_link_dp.c" , 6310); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | ||||
6311 | } | ||||
6312 | } | ||||
6313 | DC_LOG_DETECTION_DP_CAPS("Link: %d eDP panel mode supported: %d "___drm_dbg(((void *)0), DRM_UT_KMS, "Link: %d eDP panel mode supported: %d " "eDP panel mode enabled: %d \n", link->link_index, link-> dpcd_caps.panel_mode_edp, panel_mode_edp) | ||||
6314 | "eDP panel mode enabled: %d \n",___drm_dbg(((void *)0), DRM_UT_KMS, "Link: %d eDP panel mode supported: %d " "eDP panel mode enabled: %d \n", link->link_index, link-> dpcd_caps.panel_mode_edp, panel_mode_edp) | ||||
6315 | link->link_index,___drm_dbg(((void *)0), DRM_UT_KMS, "Link: %d eDP panel mode supported: %d " "eDP panel mode enabled: %d \n", link->link_index, link-> dpcd_caps.panel_mode_edp, panel_mode_edp) | ||||
6316 | link->dpcd_caps.panel_mode_edp,___drm_dbg(((void *)0), DRM_UT_KMS, "Link: %d eDP panel mode supported: %d " "eDP panel mode enabled: %d \n", link->link_index, link-> dpcd_caps.panel_mode_edp, panel_mode_edp) | ||||
6317 | panel_mode_edp)___drm_dbg(((void *)0), DRM_UT_KMS, "Link: %d eDP panel mode supported: %d " "eDP panel mode enabled: %d \n", link->link_index, link-> dpcd_caps.panel_mode_edp, panel_mode_edp); | ||||
6318 | } | ||||
6319 | |||||
6320 | enum dp_panel_mode dp_get_panel_mode(struct dc_link *link) | ||||
6321 | { | ||||
6322 | /* We need to explicitly check that connector | ||||
6323 | * is not DP. Some Travis_VGA get reported | ||||
6324 | * by video bios as DP. | ||||
6325 | */ | ||||
6326 | if (link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT) { | ||||
6327 | |||||
6328 | switch (link->dpcd_caps.branch_dev_id) { | ||||
6329 | case DP_BRANCH_DEVICE_ID_0022B90x0022B9: | ||||
6330 | /* alternate scrambler reset is required for Travis | ||||
6331 | * for the case when external chip does not | ||||
6332 | * provide sink device id, alternate scrambler | ||||
6333 | * scheme will be overriden later by querying | ||||
6334 | * Encoder features | ||||
6335 | */ | ||||
6336 | if (strncmp( | ||||
6337 | link->dpcd_caps.branch_dev_name, | ||||
6338 | DP_VGA_LVDS_CONVERTER_ID_2, | ||||
6339 | sizeof( | ||||
6340 | link->dpcd_caps. | ||||
6341 | branch_dev_name)) == 0) { | ||||
6342 | return DP_PANEL_MODE_SPECIAL; | ||||
6343 | } | ||||
6344 | break; | ||||
6345 | case DP_BRANCH_DEVICE_ID_00001A0x00001A: | ||||
6346 | /* alternate scrambler reset is required for Travis | ||||
6347 | * for the case when external chip does not provide | ||||
6348 | * sink device id, alternate scrambler scheme will | ||||
6349 | * be overriden later by querying Encoder feature | ||||
6350 | */ | ||||
6351 | if (strncmp(link->dpcd_caps.branch_dev_name, | ||||
6352 | DP_VGA_LVDS_CONVERTER_ID_3, | ||||
6353 | sizeof( | ||||
6354 | link->dpcd_caps. | ||||
6355 | branch_dev_name)) == 0) { | ||||
6356 | return DP_PANEL_MODE_SPECIAL; | ||||
6357 | } | ||||
6358 | break; | ||||
6359 | default: | ||||
6360 | break; | ||||
6361 | } | ||||
6362 | } | ||||
6363 | |||||
6364 | if (link->dpcd_caps.panel_mode_edp && | ||||
6365 | (link->connector_signal == SIGNAL_TYPE_EDP || | ||||
6366 | (link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT && | ||||
6367 | link->is_internal_display))) { | ||||
6368 | return DP_PANEL_MODE_EDP; | ||||
6369 | } | ||||
6370 | |||||
6371 | return DP_PANEL_MODE_DEFAULT; | ||||
6372 | } | ||||
6373 | |||||
6374 | enum dc_status dp_set_fec_ready(struct dc_link *link, const struct link_resource *link_res, bool_Bool ready) | ||||
6375 | { | ||||
6376 | /* FEC has to be "set ready" before the link training. | ||||
6377 | * The policy is to always train with FEC | ||||
6378 | * if the sink supports it and leave it enabled on link. | ||||
6379 | * If FEC is not supported, disable it. | ||||
6380 | */ | ||||
6381 | struct link_encoder *link_enc = NULL((void *)0); | ||||
6382 | enum dc_status status = DC_OK; | ||||
6383 | uint8_t fec_config = 0; | ||||
6384 | |||||
6385 | link_enc = link_enc_cfg_get_link_enc(link); | ||||
6386 | ASSERT(link_enc)do { if (({ static int __warned; int __ret = !!(!(link_enc)); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n" , "!(link_enc)", "/usr/src/sys/dev/pci/drm/amd/display/dc/core/dc_link_dp.c" , 6386); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | ||||
6387 | |||||
6388 | if (!dc_link_should_enable_fec(link)) | ||||
6389 | return status; | ||||
6390 | |||||
6391 | if (link_enc->funcs->fec_set_ready && | ||||
6392 | link->dpcd_caps.fec_cap.bits.FEC_CAPABLE) { | ||||
6393 | if (ready) { | ||||
6394 | fec_config = 1; | ||||
6395 | status = core_link_write_dpcd(link, | ||||
6396 | DP_FEC_CONFIGURATION0x120, | ||||
6397 | &fec_config, | ||||
6398 | sizeof(fec_config)); | ||||
6399 | if (status == DC_OK) { | ||||
6400 | link_enc->funcs->fec_set_ready(link_enc, true1); | ||||
6401 | link->fec_state = dc_link_fec_ready; | ||||
6402 | } else { | ||||
6403 | link_enc->funcs->fec_set_ready(link_enc, false0); | ||||
6404 | link->fec_state = dc_link_fec_not_ready; | ||||
6405 | dm_error("dpcd write failed to set fec_ready")__drm_err("dpcd write failed to set fec_ready"); | ||||
6406 | } | ||||
6407 | } else if (link->fec_state == dc_link_fec_ready) { | ||||
6408 | fec_config = 0; | ||||
6409 | status = core_link_write_dpcd(link, | ||||
6410 | DP_FEC_CONFIGURATION0x120, | ||||
6411 | &fec_config, | ||||
6412 | sizeof(fec_config)); | ||||
6413 | link_enc->funcs->fec_set_ready(link_enc, false0); | ||||
6414 | link->fec_state = dc_link_fec_not_ready; | ||||
6415 | } | ||||
6416 | } | ||||
6417 | |||||
6418 | return status; | ||||
6419 | } | ||||
6420 | |||||
6421 | void dp_set_fec_enable(struct dc_link *link, bool_Bool enable) | ||||
6422 | { | ||||
6423 | struct link_encoder *link_enc = NULL((void *)0); | ||||
6424 | |||||
6425 | link_enc = link_enc_cfg_get_link_enc(link); | ||||
6426 | ASSERT(link_enc)do { if (({ static int __warned; int __ret = !!(!(link_enc)); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n" , "!(link_enc)", "/usr/src/sys/dev/pci/drm/amd/display/dc/core/dc_link_dp.c" , 6426); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | ||||
6427 | |||||
6428 | if (!dc_link_should_enable_fec(link)) | ||||
6429 | return; | ||||
6430 | |||||
6431 | if (link_enc->funcs->fec_set_enable && | ||||
6432 | link->dpcd_caps.fec_cap.bits.FEC_CAPABLE) { | ||||
6433 | if (link->fec_state == dc_link_fec_ready && enable) { | ||||
6434 | /* Accord to DP spec, FEC enable sequence can first | ||||
6435 | * be transmitted anytime after 1000 LL codes have | ||||
6436 | * been transmitted on the link after link training | ||||
6437 | * completion. Using 1 lane RBR should have the maximum | ||||
6438 | * time for transmitting 1000 LL codes which is 6.173 us. | ||||
6439 | * So use 7 microseconds delay instead. | ||||
6440 | */ | ||||
6441 | udelay(7); | ||||
6442 | link_enc->funcs->fec_set_enable(link_enc, true1); | ||||
6443 | link->fec_state = dc_link_fec_enabled; | ||||
6444 | } else if (link->fec_state == dc_link_fec_enabled && !enable) { | ||||
6445 | link_enc->funcs->fec_set_enable(link_enc, false0); | ||||
6446 | link->fec_state = dc_link_fec_ready; | ||||
6447 | } | ||||
6448 | } | ||||
6449 | } | ||||
6450 | |||||
6451 | void dpcd_set_source_specific_data(struct dc_link *link) | ||||
6452 | { | ||||
6453 | if (!link->dc->vendor_signature.is_valid) { | ||||
6454 | enum dc_status __maybe_unused__attribute__((__unused__)) result_write_min_hblank = DC_NOT_SUPPORTED; | ||||
6455 | struct dpcd_amd_signature amd_signature = {0}; | ||||
6456 | struct dpcd_amd_device_id amd_device_id = {0}; | ||||
6457 | |||||
6458 | amd_device_id.device_id_byte1 = | ||||
6459 | (uint8_t)(link->ctx->asic_id.chip_id); | ||||
6460 | amd_device_id.device_id_byte2 = | ||||
6461 | (uint8_t)(link->ctx->asic_id.chip_id >> 8); | ||||
6462 | amd_device_id.dce_version = | ||||
6463 | (uint8_t)(link->ctx->dce_version); | ||||
6464 | amd_device_id.dal_version_byte1 = 0x0; // needed? where to get? | ||||
6465 | amd_device_id.dal_version_byte2 = 0x0; // needed? where to get? | ||||
6466 | |||||
6467 | core_link_read_dpcd(link, DP_SOURCE_OUI0x300, | ||||
6468 | (uint8_t *)(&amd_signature), | ||||
6469 | sizeof(amd_signature)); | ||||
6470 | |||||
6471 | if (!((amd_signature.AMD_IEEE_TxSignature_byte1 == 0x0) && | ||||
6472 | (amd_signature.AMD_IEEE_TxSignature_byte2 == 0x0) && | ||||
6473 | (amd_signature.AMD_IEEE_TxSignature_byte3 == 0x1A))) { | ||||
6474 | |||||
6475 | amd_signature.AMD_IEEE_TxSignature_byte1 = 0x0; | ||||
6476 | amd_signature.AMD_IEEE_TxSignature_byte2 = 0x0; | ||||
6477 | amd_signature.AMD_IEEE_TxSignature_byte3 = 0x1A; | ||||
6478 | |||||
6479 | core_link_write_dpcd(link, DP_SOURCE_OUI0x300, | ||||
6480 | (uint8_t *)(&amd_signature), | ||||
6481 | sizeof(amd_signature)); | ||||
6482 | } | ||||
6483 | |||||
6484 | core_link_write_dpcd(link, DP_SOURCE_OUI0x300+0x03, | ||||
6485 | (uint8_t *)(&amd_device_id), | ||||
6486 | sizeof(amd_device_id)); | ||||
6487 | |||||
6488 | if (link->ctx->dce_version >= DCN_VERSION_2_0 && | ||||
6489 | link->dc->caps.min_horizontal_blanking_period != 0) { | ||||
6490 | |||||
6491 | uint8_t hblank_size = (uint8_t)link->dc->caps.min_horizontal_blanking_period; | ||||
6492 | |||||
6493 | result_write_min_hblank = core_link_write_dpcd(link, | ||||
6494 | DP_SOURCE_MINIMUM_HBLANK_SUPPORTED0x340, (uint8_t *)(&hblank_size), | ||||
6495 | sizeof(hblank_size)); | ||||
6496 | } | ||||
6497 | DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION, | ||||
6498 | WPP_BIT_FLAG_DC_DETECTION_DP_CAPS, | ||||
6499 | "result=%u link_index=%u enum dce_version=%d DPCD=0x%04X min_hblank=%u branch_dev_id=0x%x branch_dev_name='%c%c%c%c%c%c'", | ||||
6500 | result_write_min_hblank, | ||||
6501 | link->link_index, | ||||
6502 | link->ctx->dce_version, | ||||
6503 | DP_SOURCE_MINIMUM_HBLANK_SUPPORTED, | ||||
6504 | link->dc->caps.min_horizontal_blanking_period, | ||||
6505 | link->dpcd_caps.branch_dev_id, | ||||
6506 | link->dpcd_caps.branch_dev_name[0], | ||||
6507 | link->dpcd_caps.branch_dev_name[1], | ||||
6508 | link->dpcd_caps.branch_dev_name[2], | ||||
6509 | link->dpcd_caps.branch_dev_name[3], | ||||
6510 | link->dpcd_caps.branch_dev_name[4], | ||||
6511 | link->dpcd_caps.branch_dev_name[5]); | ||||
6512 | } else { | ||||
6513 | core_link_write_dpcd(link, DP_SOURCE_OUI0x300, | ||||
6514 | link->dc->vendor_signature.data.raw, | ||||
6515 | sizeof(link->dc->vendor_signature.data.raw)); | ||||
6516 | } | ||||
6517 | } | ||||
6518 | |||||
6519 | void dpcd_write_cable_id_to_dprx(struct dc_link *link) | ||||
6520 | { | ||||
6521 | if (!link->dpcd_caps.channel_coding_cap.bits.DP_128b_132b_SUPPORTED || | ||||
6522 | link->dpcd_caps.cable_id.raw == 0 || | ||||
6523 | link->dprx_states.cable_id_written) | ||||
6524 | return; | ||||
6525 | |||||
6526 | core_link_write_dpcd(link, DP_CABLE_ATTRIBUTES_UPDATED_BY_DPTX0x110, | ||||
6527 | &link->dpcd_caps.cable_id.raw, | ||||
6528 | sizeof(link->dpcd_caps.cable_id.raw)); | ||||
6529 | |||||
6530 | link->dprx_states.cable_id_written = 1; | ||||
6531 | } | ||||
6532 | |||||
6533 | bool_Bool dc_link_set_backlight_level_nits(struct dc_link *link, | ||||
6534 | bool_Bool isHDR, | ||||
6535 | uint32_t backlight_millinits, | ||||
6536 | uint32_t transition_time_in_ms) | ||||
6537 | { | ||||
6538 | struct dpcd_source_backlight_set dpcd_backlight_set; | ||||
6539 | uint8_t backlight_control = isHDR ? 1 : 0; | ||||
6540 | |||||
6541 | if (!link || (link->connector_signal != SIGNAL_TYPE_EDP && | ||||
6542 | link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT)) | ||||
6543 | return false0; | ||||
6544 | |||||
6545 | // OLEDs have no PWM, they can only use AUX | ||||
6546 | if (link->dpcd_sink_ext_caps.bits.oled == 1) | ||||
6547 | backlight_control = 1; | ||||
6548 | |||||
6549 | *(uint32_t *)&dpcd_backlight_set.backlight_level_millinits = backlight_millinits; | ||||
6550 | *(uint16_t *)&dpcd_backlight_set.backlight_transition_time_ms = (uint16_t)transition_time_in_ms; | ||||
6551 | |||||
6552 | |||||
6553 | if (core_link_write_dpcd(link, DP_SOURCE_BACKLIGHT_LEVEL0x320, | ||||
6554 | (uint8_t *)(&dpcd_backlight_set), | ||||
6555 | sizeof(dpcd_backlight_set)) != DC_OK) | ||||
6556 | return false0; | ||||
6557 | |||||
6558 | if (core_link_write_dpcd(link, DP_SOURCE_BACKLIGHT_CONTROL0x32E, | ||||
6559 | &backlight_control, 1) != DC_OK) | ||||
6560 | return false0; | ||||
6561 | |||||
6562 | return true1; | ||||
6563 | } | ||||
6564 | |||||
6565 | bool_Bool dc_link_get_backlight_level_nits(struct dc_link *link, | ||||
6566 | uint32_t *backlight_millinits_avg, | ||||
6567 | uint32_t *backlight_millinits_peak) | ||||
6568 | { | ||||
6569 | union dpcd_source_backlight_get dpcd_backlight_get; | ||||
6570 | |||||
6571 | memset(&dpcd_backlight_get, 0, sizeof(union dpcd_source_backlight_get))__builtin_memset((&dpcd_backlight_get), (0), (sizeof(union dpcd_source_backlight_get))); | ||||
6572 | |||||
6573 | if (!link || (link->connector_signal != SIGNAL_TYPE_EDP && | ||||
6574 | link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT)) | ||||
6575 | return false0; | ||||
6576 | |||||
6577 | if (core_link_read_dpcd(link, DP_SOURCE_BACKLIGHT_CURRENT_PEAK0x326, | ||||
6578 | dpcd_backlight_get.raw, | ||||
6579 | sizeof(union dpcd_source_backlight_get)) != DC_OK) | ||||
6580 | return false0; | ||||
6581 | |||||
6582 | *backlight_millinits_avg = | ||||
6583 | dpcd_backlight_get.bytes.backlight_millinits_avg; | ||||
6584 | *backlight_millinits_peak = | ||||
6585 | dpcd_backlight_get.bytes.backlight_millinits_peak; | ||||
6586 | |||||
6587 | /* On non-supported panels dpcd_read usually succeeds with 0 returned */ | ||||
6588 | if (*backlight_millinits_avg == 0 || | ||||
6589 | *backlight_millinits_avg > *backlight_millinits_peak) | ||||
6590 | return false0; | ||||
6591 | |||||
6592 | return true1; | ||||
6593 | } | ||||
6594 | |||||
6595 | bool_Bool dc_link_backlight_enable_aux(struct dc_link *link, bool_Bool enable) | ||||
6596 | { | ||||
6597 | uint8_t backlight_enable = enable ? 1 : 0; | ||||
6598 | |||||
6599 | if (!link || (link->connector_signal != SIGNAL_TYPE_EDP && | ||||
6600 | link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT)) | ||||
6601 | return false0; | ||||
6602 | |||||
6603 | if (core_link_write_dpcd(link, DP_SOURCE_BACKLIGHT_ENABLE0x32F, | ||||
6604 | &backlight_enable, 1) != DC_OK) | ||||
6605 | return false0; | ||||
6606 | |||||
6607 | return true1; | ||||
6608 | } | ||||
6609 | |||||
6610 | // we read default from 0x320 because we expect BIOS wrote it there | ||||
6611 | // regular get_backlight_nit reads from panel set at 0x326 | ||||
6612 | bool_Bool dc_link_read_default_bl_aux(struct dc_link *link, uint32_t *backlight_millinits) | ||||
6613 | { | ||||
6614 | if (!link || (link->connector_signal != SIGNAL_TYPE_EDP && | ||||
6615 | link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT)) | ||||
6616 | return false0; | ||||
6617 | |||||
6618 | if (core_link_read_dpcd(link, DP_SOURCE_BACKLIGHT_LEVEL0x320, | ||||
6619 | (uint8_t *) backlight_millinits, | ||||
6620 | sizeof(uint32_t)) != DC_OK) | ||||
6621 | return false0; | ||||
6622 | |||||
6623 | return true1; | ||||
6624 | } | ||||
6625 | |||||
6626 | bool_Bool dc_link_set_default_brightness_aux(struct dc_link *link) | ||||
6627 | { | ||||
6628 | uint32_t default_backlight; | ||||
6629 | |||||
6630 | if (link && link->dpcd_sink_ext_caps.bits.oled == 1) { | ||||
6631 | if (!dc_link_read_default_bl_aux(link, &default_backlight)) | ||||
6632 | default_backlight = 150000; | ||||
6633 | // if < 5 nits or > 5000, it might be wrong readback | ||||
6634 | if (default_backlight < 5000 || default_backlight > 5000000) | ||||
6635 | default_backlight = 150000; // | ||||
6636 | |||||
6637 | return dc_link_set_backlight_level_nits(link, true1, | ||||
6638 | default_backlight, 0); | ||||
6639 | } | ||||
6640 | return false0; | ||||
6641 | } | ||||
6642 | |||||
6643 | bool_Bool is_edp_ilr_optimization_required(struct dc_link *link, struct dc_crtc_timing *crtc_timing) | ||||
6644 | { | ||||
6645 | struct dc_link_settings link_setting; | ||||
6646 | uint8_t link_bw_set; | ||||
6647 | uint8_t link_rate_set; | ||||
6648 | uint32_t req_bw; | ||||
6649 | union lane_count_set lane_count_set = {0}; | ||||
6650 | |||||
6651 | ASSERT(link || crtc_timing)do { if (({ static int __warned; int __ret = !!(!(link || crtc_timing )); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n" , "!(link || crtc_timing)", "/usr/src/sys/dev/pci/drm/amd/display/dc/core/dc_link_dp.c" , 6651); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); // invalid input | ||||
6652 | |||||
6653 | if (link->dpcd_caps.edp_supported_link_rates_count == 0 || | ||||
6654 | !link->panel_config.ilr.optimize_edp_link_rate) | ||||
6655 | return false0; | ||||
6656 | |||||
6657 | |||||
6658 | // Read DPCD 00100h to find if standard link rates are set | ||||
6659 | core_link_read_dpcd(link, DP_LINK_BW_SET0x100, | ||||
6660 | &link_bw_set, sizeof(link_bw_set)); | ||||
6661 | |||||
6662 | if (link_bw_set) { | ||||
6663 | DC_LOG_EVENT_LINK_TRAINING("eDP ILR: Optimization required, VBIOS used link_bw_set\n")___drm_dbg(((void *)0), DRM_UT_KMS, "eDP ILR: Optimization required, VBIOS used link_bw_set\n" ); | ||||
6664 | return true1; | ||||
6665 | } | ||||
6666 | |||||
6667 | // Read DPCD 00115h to find the edp link rate set used | ||||
6668 | core_link_read_dpcd(link, DP_LINK_RATE_SET0x115, | ||||
6669 | &link_rate_set, sizeof(link_rate_set)); | ||||
6670 | |||||
6671 | // Read DPCD 00101h to find out the number of lanes currently set | ||||
6672 | core_link_read_dpcd(link, DP_LANE_COUNT_SET0x101, | ||||
6673 | &lane_count_set.raw, sizeof(lane_count_set)); | ||||
6674 | |||||
6675 | req_bw = dc_bandwidth_in_kbps_from_timing(crtc_timing); | ||||
6676 | |||||
6677 | if (!crtc_timing->flags.DSC) | ||||
6678 | decide_edp_link_settings(link, &link_setting, req_bw); | ||||
6679 | else | ||||
6680 | decide_edp_link_settings_with_dsc(link, &link_setting, req_bw, LINK_RATE_UNKNOWN); | ||||
6681 | |||||
6682 | if (link->dpcd_caps.edp_supported_link_rates[link_rate_set] != link_setting.link_rate || | ||||
6683 | lane_count_set.bits.LANE_COUNT_SET != link_setting.lane_count) { | ||||
6684 | DC_LOG_EVENT_LINK_TRAINING("eDP ILR: Optimization required, VBIOS link_rate_set not optimal\n")___drm_dbg(((void *)0), DRM_UT_KMS, "eDP ILR: Optimization required, VBIOS link_rate_set not optimal\n" ); | ||||
6685 | return true1; | ||||
6686 | } | ||||
6687 | |||||
6688 | DC_LOG_EVENT_LINK_TRAINING("eDP ILR: No optimization required, VBIOS set optimal link_rate_set\n")___drm_dbg(((void *)0), DRM_UT_KMS, "eDP ILR: No optimization required, VBIOS set optimal link_rate_set\n" ); | ||||
6689 | return false0; | ||||
6690 | } | ||||
6691 | |||||
6692 | enum dp_link_encoding dp_get_link_encoding_format(const struct dc_link_settings *link_settings) | ||||
6693 | { | ||||
6694 | if ((link_settings->link_rate >= LINK_RATE_LOW) && | ||||
6695 | (link_settings->link_rate <= LINK_RATE_HIGH3)) | ||||
6696 | return DP_8b_10b_ENCODING; | ||||
6697 | else if ((link_settings->link_rate >= LINK_RATE_UHBR10) && | ||||
6698 | (link_settings->link_rate <= LINK_RATE_UHBR20)) | ||||
6699 | return DP_128b_132b_ENCODING; | ||||
6700 | return DP_UNKNOWN_ENCODING; | ||||
6701 | } | ||||
6702 | |||||
6703 | enum dp_link_encoding dc_link_dp_mst_decide_link_encoding_format(const struct dc_link *link) | ||||
6704 | { | ||||
6705 | struct dc_link_settings link_settings = {0}; | ||||
6706 | |||||
6707 | if (!dc_is_dp_signal(link->connector_signal)) | ||||
6708 | return DP_UNKNOWN_ENCODING; | ||||
6709 | |||||
6710 | if (link->preferred_link_setting.lane_count != | ||||
6711 | LANE_COUNT_UNKNOWN && | ||||
6712 | link->preferred_link_setting.link_rate != | ||||
6713 | LINK_RATE_UNKNOWN) { | ||||
6714 | link_settings = link->preferred_link_setting; | ||||
6715 | } else { | ||||
6716 | decide_mst_link_settings(link, &link_settings); | ||||
6717 | } | ||||
6718 | |||||
6719 | return dp_get_link_encoding_format(&link_settings); | ||||
6720 | } | ||||
6721 | |||||
6722 | // TODO - DP2.0 Link: Fix get_lane_status to handle LTTPR offset (SST and MST) | ||||
6723 | static void get_lane_status( | ||||
6724 | struct dc_link *link, | ||||
6725 | uint32_t lane_count, | ||||
6726 | union lane_status *status, | ||||
6727 | union lane_align_status_updated *status_updated) | ||||
6728 | { | ||||
6729 | unsigned int lane; | ||||
6730 | uint8_t dpcd_buf[3] = {0}; | ||||
6731 | |||||
6732 | if (status
| ||||
6733 | return; | ||||
6734 | } | ||||
6735 | |||||
6736 | core_link_read_dpcd( | ||||
6737 | link, | ||||
6738 | DP_LANE0_1_STATUS0x202, | ||||
6739 | dpcd_buf, | ||||
6740 | sizeof(dpcd_buf)); | ||||
6741 | |||||
6742 | for (lane = 0; lane < lane_count; lane++) { | ||||
6743 | status[lane].raw = get_nibble_at_index(&dpcd_buf[0], lane); | ||||
6744 | } | ||||
6745 | |||||
6746 | status_updated->raw = dpcd_buf[2]; | ||||
6747 | } | ||||
6748 | |||||
6749 | bool_Bool dpcd_write_128b_132b_sst_payload_allocation_table( | ||||
6750 | const struct dc_stream_state *stream, | ||||
6751 | struct dc_link *link, | ||||
6752 | struct link_mst_stream_allocation_table *proposed_table, | ||||
6753 | bool_Bool allocate) | ||||
6754 | { | ||||
6755 | const uint8_t vc_id = 1; /// VC ID always 1 for SST | ||||
6756 | const uint8_t start_time_slot = 0; /// Always start at time slot 0 for SST | ||||
6757 | bool_Bool result = false0; | ||||
6758 | uint8_t req_slot_count = 0; | ||||
6759 | struct fixed31_32 avg_time_slots_per_mtp = { 0 }; | ||||
6760 | union payload_table_update_status update_status = { 0 }; | ||||
6761 | const uint32_t max_retries = 30; | ||||
6762 | uint32_t retries = 0; | ||||
6763 | |||||
6764 | if (allocate) { | ||||
6765 | avg_time_slots_per_mtp = calculate_sst_avg_time_slots_per_mtp(stream, link); | ||||
6766 | req_slot_count = dc_fixpt_ceil(avg_time_slots_per_mtp); | ||||
6767 | /// Validation should filter out modes that exceed link BW | ||||
6768 | ASSERT(req_slot_count <= MAX_MTP_SLOT_COUNT)do { if (({ static int __warned; int __ret = !!(!(req_slot_count <= 64)); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n" , "!(req_slot_count <= 64)", "/usr/src/sys/dev/pci/drm/amd/display/dc/core/dc_link_dp.c" , 6768); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | ||||
6769 | if (req_slot_count > MAX_MTP_SLOT_COUNT64) | ||||
6770 | return false0; | ||||
6771 | } else { | ||||
6772 | /// Leave req_slot_count = 0 if allocate is false. | ||||
6773 | } | ||||
6774 | |||||
6775 | proposed_table->stream_count = 1; /// Always 1 stream for SST | ||||
6776 | proposed_table->stream_allocations[0].slot_count = req_slot_count; | ||||
6777 | proposed_table->stream_allocations[0].vcp_id = vc_id; | ||||
6778 | |||||
6779 | if (link->aux_access_disabled) | ||||
6780 | return true1; | ||||
6781 | |||||
6782 | /// Write DPCD 2C0 = 1 to start updating | ||||
6783 | update_status.bits.VC_PAYLOAD_TABLE_UPDATED = 1; | ||||
6784 | core_link_write_dpcd( | ||||
6785 | link, | ||||
6786 | DP_PAYLOAD_TABLE_UPDATE_STATUS0x2c0, | ||||
6787 | &update_status.raw, | ||||
6788 | 1); | ||||
6789 | |||||
6790 | /// Program the changes in DPCD 1C0 - 1C2 | ||||
6791 | ASSERT(vc_id == 1)do { if (({ static int __warned; int __ret = !!(!(vc_id == 1) ); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n" , "!(vc_id == 1)", "/usr/src/sys/dev/pci/drm/amd/display/dc/core/dc_link_dp.c" , 6791); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | ||||
6792 | core_link_write_dpcd( | ||||
6793 | link, | ||||
6794 | DP_PAYLOAD_ALLOCATE_SET0x1c0, | ||||
6795 | &vc_id, | ||||
6796 | 1); | ||||
6797 | |||||
6798 | ASSERT(start_time_slot == 0)do { if (({ static int __warned; int __ret = !!(!(start_time_slot == 0)); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n" , "!(start_time_slot == 0)", "/usr/src/sys/dev/pci/drm/amd/display/dc/core/dc_link_dp.c" , 6798); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | ||||
6799 | core_link_write_dpcd( | ||||
6800 | link, | ||||
6801 | DP_PAYLOAD_ALLOCATE_START_TIME_SLOT0x1c1, | ||||
6802 | &start_time_slot, | ||||
6803 | 1); | ||||
6804 | |||||
6805 | core_link_write_dpcd( | ||||
6806 | link, | ||||
6807 | DP_PAYLOAD_ALLOCATE_TIME_SLOT_COUNT0x1c2, | ||||
6808 | &req_slot_count, | ||||
6809 | 1); | ||||
6810 | |||||
6811 | /// Poll till DPCD 2C0 read 1 | ||||
6812 | /// Try for at least 150ms (30 retries, with 5ms delay after each attempt) | ||||
6813 | |||||
6814 | while (retries < max_retries) { | ||||
6815 | if (core_link_read_dpcd( | ||||
6816 | link, | ||||
6817 | DP_PAYLOAD_TABLE_UPDATE_STATUS0x2c0, | ||||
6818 | &update_status.raw, | ||||
6819 | 1) == DC_OK) { | ||||
6820 | if (update_status.bits.VC_PAYLOAD_TABLE_UPDATED == 1) { | ||||
6821 | DC_LOG_DP2("SST Update Payload: downstream payload table updated.")___drm_dbg(((void *)0), DRM_UT_KMS, "SST Update Payload: downstream payload table updated." ); | ||||
6822 | result = true1; | ||||
6823 | break; | ||||
6824 | } | ||||
6825 | } else { | ||||
6826 | union dpcd_rev dpcdRev; | ||||
6827 | |||||
6828 | if (core_link_read_dpcd( | ||||
6829 | link, | ||||
6830 | DP_DPCD_REV0x000, | ||||
6831 | &dpcdRev.raw, | ||||
6832 | 1) != DC_OK) { | ||||
6833 | DC_LOG_ERROR("SST Update Payload: Unable to read DPCD revision "__drm_err("SST Update Payload: Unable to read DPCD revision " "of sink while polling payload table " "updated status bit." ) | ||||
6834 | "of sink while polling payload table "__drm_err("SST Update Payload: Unable to read DPCD revision " "of sink while polling payload table " "updated status bit." ) | ||||
6835 | "updated status bit.")__drm_err("SST Update Payload: Unable to read DPCD revision " "of sink while polling payload table " "updated status bit." ); | ||||
6836 | break; | ||||
6837 | } | ||||
6838 | } | ||||
6839 | retries++; | ||||
6840 | drm_msleep(5)mdelay(5); | ||||
6841 | } | ||||
6842 | |||||
6843 | if (!result && retries == max_retries) { | ||||
6844 | DC_LOG_ERROR("SST Update Payload: Payload table not updated after retries, "__drm_err("SST Update Payload: Payload table not updated after retries, " "continue on. Something is wrong with the branch.") | ||||
6845 | "continue on. Something is wrong with the branch.")__drm_err("SST Update Payload: Payload table not updated after retries, " "continue on. Something is wrong with the branch."); | ||||
6846 | // TODO - DP2.0 Payload: Read and log the payload table from downstream branch | ||||
6847 | } | ||||
6848 | |||||
6849 | return result; | ||||
6850 | } | ||||
6851 | |||||
6852 | bool_Bool dpcd_poll_for_allocation_change_trigger(struct dc_link *link) | ||||
6853 | { | ||||
6854 | /* | ||||
6855 | * wait for ACT handled | ||||
6856 | */ | ||||
6857 | int i; | ||||
6858 | const int act_retries = 30; | ||||
6859 | enum act_return_status result = ACT_FAILED; | ||||
6860 | union payload_table_update_status update_status = {0}; | ||||
6861 | union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX]; | ||||
6862 | union lane_align_status_updated lane_status_updated; | ||||
6863 | |||||
6864 | if (link->aux_access_disabled) | ||||
| |||||
6865 | return true1; | ||||
6866 | for (i = 0; i < act_retries; i++) { | ||||
6867 | get_lane_status(link, link->cur_link_settings.lane_count, dpcd_lane_status, &lane_status_updated); | ||||
6868 | |||||
6869 | if (!dp_is_cr_done(link->cur_link_settings.lane_count, dpcd_lane_status) || | ||||
6870 | !dp_is_ch_eq_done(link->cur_link_settings.lane_count, dpcd_lane_status) || | ||||
6871 | !dp_is_symbol_locked(link->cur_link_settings.lane_count, dpcd_lane_status) || | ||||
6872 | !dp_is_interlane_aligned(lane_status_updated)) { | ||||
6873 | DC_LOG_ERROR("SST Update Payload: Link loss occurred while "__drm_err("SST Update Payload: Link loss occurred while " "polling for ACT handled." ) | ||||
6874 | "polling for ACT handled.")__drm_err("SST Update Payload: Link loss occurred while " "polling for ACT handled." ); | ||||
6875 | result = ACT_LINK_LOST; | ||||
6876 | break; | ||||
6877 | } | ||||
6878 | core_link_read_dpcd( | ||||
6879 | link, | ||||
6880 | DP_PAYLOAD_TABLE_UPDATE_STATUS0x2c0, | ||||
6881 | &update_status.raw, | ||||
6882 | 1); | ||||
6883 | |||||
6884 | if (update_status.bits.ACT_HANDLED == 1) { | ||||
6885 | DC_LOG_DP2("SST Update Payload: ACT handled by downstream.")___drm_dbg(((void *)0), DRM_UT_KMS, "SST Update Payload: ACT handled by downstream." ); | ||||
6886 | result = ACT_SUCCESS; | ||||
6887 | break; | ||||
6888 | } | ||||
6889 | |||||
6890 | drm_msleep(5)mdelay(5); | ||||
6891 | } | ||||
6892 | |||||
6893 | if (result == ACT_FAILED) { | ||||
6894 | DC_LOG_ERROR("SST Update Payload: ACT still not handled after retries, "__drm_err("SST Update Payload: ACT still not handled after retries, " "continue on. Something is wrong with the branch.") | ||||
6895 | "continue on. Something is wrong with the branch.")__drm_err("SST Update Payload: ACT still not handled after retries, " "continue on. Something is wrong with the branch."); | ||||
6896 | } | ||||
6897 | |||||
6898 | return (result == ACT_SUCCESS); | ||||
6899 | } | ||||
6900 | |||||
6901 | struct fixed31_32 calculate_sst_avg_time_slots_per_mtp( | ||||
6902 | const struct dc_stream_state *stream, | ||||
6903 | const struct dc_link *link) | ||||
6904 | { | ||||
6905 | struct fixed31_32 link_bw_effective = | ||||
6906 | dc_fixpt_from_int( | ||||
6907 | dc_link_bandwidth_kbps(link, &link->cur_link_settings)); | ||||
6908 | struct fixed31_32 timeslot_bw_effective = | ||||
6909 | dc_fixpt_div_int(link_bw_effective, MAX_MTP_SLOT_COUNT64); | ||||
6910 | struct fixed31_32 timing_bw = | ||||
6911 | dc_fixpt_from_int( | ||||
6912 | dc_bandwidth_in_kbps_from_timing(&stream->timing)); | ||||
6913 | struct fixed31_32 avg_time_slots_per_mtp = | ||||
6914 | dc_fixpt_div(timing_bw, timeslot_bw_effective); | ||||
6915 | |||||
6916 | return avg_time_slots_per_mtp; | ||||
6917 | } | ||||
6918 | |||||
6919 | bool_Bool is_dp_128b_132b_signal(struct pipe_ctx *pipe_ctx) | ||||
6920 | { | ||||
6921 | /* If this assert is hit then we have a link encoder dynamic management issue */ | ||||
6922 | ASSERT(pipe_ctx->stream_res.hpo_dp_stream_enc ? pipe_ctx->link_res.hpo_dp_link_enc != NULL : true)do { if (({ static int __warned; int __ret = !!(!(pipe_ctx-> stream_res.hpo_dp_stream_enc ? pipe_ctx->link_res.hpo_dp_link_enc != ((void *)0) : 1)); if (__ret && !__warned) { printf ("WARNING %s failed at %s:%d\n", "!(pipe_ctx->stream_res.hpo_dp_stream_enc ? pipe_ctx->link_res.hpo_dp_link_enc != ((void *)0) : 1)" , "/usr/src/sys/dev/pci/drm/amd/display/dc/core/dc_link_dp.c" , 6922); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | ||||
6923 | return (pipe_ctx->stream_res.hpo_dp_stream_enc && | ||||
6924 | pipe_ctx->link_res.hpo_dp_link_enc && | ||||
6925 | dc_is_dp_signal(pipe_ctx->stream->signal)); | ||||
6926 | } | ||||
6927 | |||||
6928 | void edp_panel_backlight_power_on(struct dc_link *link, bool_Bool wait_for_hpd) | ||||
6929 | { | ||||
6930 | if (link->connector_signal != SIGNAL_TYPE_EDP) | ||||
6931 | return; | ||||
6932 | |||||
6933 | link->dc->hwss.edp_power_control(link, true1); | ||||
6934 | if (wait_for_hpd) | ||||
6935 | link->dc->hwss.edp_wait_for_hpd_ready(link, true1); | ||||
6936 | if (link->dc->hwss.edp_backlight_control) | ||||
6937 | link->dc->hwss.edp_backlight_control(link, true1); | ||||
6938 | } | ||||
6939 | |||||
6940 | void dc_link_clear_dprx_states(struct dc_link *link) | ||||
6941 | { | ||||
6942 | memset(&link->dprx_states, 0, sizeof(link->dprx_states))__builtin_memset((&link->dprx_states), (0), (sizeof(link ->dprx_states))); | ||||
6943 | } | ||||
6944 | |||||
6945 | void dp_receiver_power_ctrl(struct dc_link *link, bool_Bool on) | ||||
6946 | { | ||||
6947 | uint8_t state; | ||||
6948 | |||||
6949 | state = on ? DP_POWER_STATE_D0 : DP_POWER_STATE_D3; | ||||
6950 | |||||
6951 | if (link->sync_lt_in_progress) | ||||
6952 | return; | ||||
6953 | |||||
6954 | core_link_write_dpcd(link, DP_SET_POWER0x600, &state, | ||||
6955 | sizeof(state)); | ||||
6956 | |||||
6957 | } | ||||
6958 | |||||
6959 | void dp_source_sequence_trace(struct dc_link *link, uint8_t dp_test_mode) | ||||
6960 | { | ||||
6961 | if (link != NULL((void *)0) && link->dc->debug.enable_driver_sequence_debug) | ||||
6962 | core_link_write_dpcd(link, DP_SOURCE_SEQUENCE0x30c, | ||||
6963 | &dp_test_mode, sizeof(dp_test_mode)); | ||||
6964 | } | ||||
6965 | |||||
6966 | |||||
6967 | static uint8_t convert_to_count(uint8_t lttpr_repeater_count) | ||||
6968 | { | ||||
6969 | switch (lttpr_repeater_count) { | ||||
6970 | case 0x80: // 1 lttpr repeater | ||||
6971 | return 1; | ||||
6972 | case 0x40: // 2 lttpr repeaters | ||||
6973 | return 2; | ||||
6974 | case 0x20: // 3 lttpr repeaters | ||||
6975 | return 3; | ||||
6976 | case 0x10: // 4 lttpr repeaters | ||||
6977 | return 4; | ||||
6978 | case 0x08: // 5 lttpr repeaters | ||||
6979 | return 5; | ||||
6980 | case 0x04: // 6 lttpr repeaters | ||||
6981 | return 6; | ||||
6982 | case 0x02: // 7 lttpr repeaters | ||||
6983 | return 7; | ||||
6984 | case 0x01: // 8 lttpr repeaters | ||||
6985 | return 8; | ||||
6986 | default: | ||||
6987 | break; | ||||
6988 | } | ||||
6989 | return 0; // invalid value | ||||
6990 | } | ||||
6991 | |||||
6992 | static inline bool_Bool is_immediate_downstream(struct dc_link *link, uint32_t offset) | ||||
6993 | { | ||||
6994 | return (convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt) == offset); | ||||
6995 | } | ||||
6996 | |||||
6997 | void dp_enable_link_phy( | ||||
6998 | struct dc_link *link, | ||||
6999 | const struct link_resource *link_res, | ||||
7000 | enum amd_signal_type signal, | ||||
7001 | enum clock_source_id clock_source, | ||||
7002 | const struct dc_link_settings *link_settings) | ||||
7003 | { | ||||
7004 | link->cur_link_settings = *link_settings; | ||||
7005 | link->dc->hwss.enable_dp_link_output(link, link_res, signal, | ||||
7006 | clock_source, link_settings); | ||||
7007 | dp_receiver_power_ctrl(link, true1); | ||||
7008 | } | ||||
7009 | |||||
7010 | void edp_add_delay_for_T9(struct dc_link *link) | ||||
7011 | { | ||||
7012 | if (link && link->panel_config.pps.extra_delay_backlight_off > 0) | ||||
7013 | udelay(link->panel_config.pps.extra_delay_backlight_off * 1000); | ||||
7014 | } | ||||
7015 | |||||
7016 | bool_Bool edp_receiver_ready_T9(struct dc_link *link) | ||||
7017 | { | ||||
7018 | unsigned int tries = 0; | ||||
7019 | unsigned char sinkstatus = 0; | ||||
7020 | unsigned char edpRev = 0; | ||||
7021 | enum dc_status result = DC_OK; | ||||
7022 | |||||
7023 | result = core_link_read_dpcd(link, DP_EDP_DPCD_REV0x700, &edpRev, sizeof(edpRev)); | ||||
7024 | |||||
7025 | /* start from eDP version 1.2, SINK_STAUS indicate the sink is ready.*/ | ||||
7026 | if (result == DC_OK && edpRev >= DP_EDP_120x01) { | ||||
7027 | do { | ||||
7028 | sinkstatus = 1; | ||||
7029 | result = core_link_read_dpcd(link, DP_SINK_STATUS0x205, &sinkstatus, sizeof(sinkstatus)); | ||||
7030 | if (sinkstatus == 0) | ||||
7031 | break; | ||||
7032 | if (result != DC_OK) | ||||
7033 | break; | ||||
7034 | udelay(100); //MAx T9 | ||||
7035 | } while (++tries < 50); | ||||
7036 | } | ||||
7037 | |||||
7038 | return result; | ||||
7039 | } | ||||
7040 | bool_Bool edp_receiver_ready_T7(struct dc_link *link) | ||||
7041 | { | ||||
7042 | unsigned char sinkstatus = 0; | ||||
7043 | unsigned char edpRev = 0; | ||||
7044 | enum dc_status result = DC_OK; | ||||
7045 | |||||
7046 | /* use absolute time stamp to constrain max T7*/ | ||||
7047 | unsigned long long enter_timestamp = 0; | ||||
7048 | unsigned long long finish_timestamp = 0; | ||||
7049 | unsigned long long time_taken_in_ns = 0; | ||||
7050 | |||||
7051 | result = core_link_read_dpcd(link, DP_EDP_DPCD_REV0x700, &edpRev, sizeof(edpRev)); | ||||
7052 | |||||
7053 | if (result == DC_OK && edpRev >= DP_EDP_120x01) { | ||||
7054 | /* start from eDP version 1.2, SINK_STAUS indicate the sink is ready.*/ | ||||
7055 | enter_timestamp = dm_get_timestamp(link->ctx); | ||||
7056 | do { | ||||
7057 | sinkstatus = 0; | ||||
7058 | result = core_link_read_dpcd(link, DP_SINK_STATUS0x205, &sinkstatus, sizeof(sinkstatus)); | ||||
7059 | if (sinkstatus == 1) | ||||
7060 | break; | ||||
7061 | if (result != DC_OK) | ||||
7062 | break; | ||||
7063 | udelay(25); | ||||
7064 | finish_timestamp = dm_get_timestamp(link->ctx); | ||||
7065 | time_taken_in_ns = dm_get_elapse_time_in_ns(link->ctx, finish_timestamp, enter_timestamp); | ||||
7066 | } while (time_taken_in_ns < 50 * 1000000); //MAx T7 is 50ms | ||||
7067 | } | ||||
7068 | |||||
7069 | if (link && link->panel_config.pps.extra_t7_ms > 0) | ||||
7070 | udelay(link->panel_config.pps.extra_t7_ms * 1000); | ||||
7071 | |||||
7072 | return result; | ||||
7073 | } | ||||
7074 | |||||
7075 | void dp_disable_link_phy(struct dc_link *link, const struct link_resource *link_res, | ||||
7076 | enum amd_signal_type signal) | ||||
7077 | { | ||||
7078 | struct dc *dc = link->ctx->dc; | ||||
7079 | |||||
7080 | if (!link->wa_flags.dp_keep_receiver_powered) | ||||
7081 | dp_receiver_power_ctrl(link, false0); | ||||
7082 | |||||
7083 | dc->hwss.disable_link_output(link, link_res, signal); | ||||
7084 | /* Clear current link setting.*/ | ||||
7085 | memset(&link->cur_link_settings, 0,__builtin_memset((&link->cur_link_settings), (0), (sizeof (link->cur_link_settings))) | ||||
7086 | sizeof(link->cur_link_settings))__builtin_memset((&link->cur_link_settings), (0), (sizeof (link->cur_link_settings))); | ||||
7087 | |||||
7088 | if (dc->clk_mgr->funcs->notify_link_rate_change) | ||||
7089 | dc->clk_mgr->funcs->notify_link_rate_change(dc->clk_mgr, link); | ||||
7090 | } | ||||
7091 | |||||
7092 | void dp_disable_link_phy_mst(struct dc_link *link, const struct link_resource *link_res, | ||||
7093 | enum amd_signal_type signal) | ||||
7094 | { | ||||
7095 | /* MST disable link only when no stream use the link */ | ||||
7096 | if (link->mst_stream_alloc_table.stream_count > 0) | ||||
7097 | return; | ||||
7098 | |||||
7099 | dp_disable_link_phy(link, link_res, signal); | ||||
7100 | |||||
7101 | /* set the sink to SST mode after disabling the link */ | ||||
7102 | dp_enable_mst_on_sink(link, false0); | ||||
7103 | } | ||||
7104 | |||||
7105 | bool_Bool dp_set_hw_training_pattern( | ||||
7106 | struct dc_link *link, | ||||
7107 | const struct link_resource *link_res, | ||||
7108 | enum dc_dp_training_pattern pattern, | ||||
7109 | uint32_t offset) | ||||
7110 | { | ||||
7111 | enum dp_test_pattern test_pattern = DP_TEST_PATTERN_UNSUPPORTED; | ||||
7112 | |||||
7113 | switch (pattern) { | ||||
7114 | case DP_TRAINING_PATTERN_SEQUENCE_1: | ||||
7115 | test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN1; | ||||
7116 | break; | ||||
7117 | case DP_TRAINING_PATTERN_SEQUENCE_2: | ||||
7118 | test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN2; | ||||
7119 | break; | ||||
7120 | case DP_TRAINING_PATTERN_SEQUENCE_3: | ||||
7121 | test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN3; | ||||
7122 | break; | ||||
7123 | case DP_TRAINING_PATTERN_SEQUENCE_4: | ||||
7124 | test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN4; | ||||
7125 | break; | ||||
7126 | case DP_128b_132b_TPS1: | ||||
7127 | test_pattern = DP_TEST_PATTERN_128b_132b_TPS1_TRAINING_MODE; | ||||
7128 | break; | ||||
7129 | case DP_128b_132b_TPS2: | ||||
7130 | test_pattern = DP_TEST_PATTERN_128b_132b_TPS2_TRAINING_MODE; | ||||
7131 | break; | ||||
7132 | default: | ||||
7133 | break; | ||||
7134 | } | ||||
7135 | |||||
7136 | dp_set_hw_test_pattern(link, link_res, test_pattern, NULL((void *)0), 0); | ||||
7137 | |||||
7138 | return true1; | ||||
7139 | } | ||||
7140 | |||||
7141 | void dp_set_hw_lane_settings( | ||||
7142 | struct dc_link *link, | ||||
7143 | const struct link_resource *link_res, | ||||
7144 | const struct link_training_settings *link_settings, | ||||
7145 | uint32_t offset) | ||||
7146 | { | ||||
7147 | const struct link_hwss *link_hwss = get_link_hwss(link, link_res); | ||||
7148 | |||||
7149 | if ((link_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) && !is_immediate_downstream(link, offset)) | ||||
7150 | return; | ||||
7151 | |||||
7152 | if (link_hwss->ext.set_dp_lane_settings) | ||||
7153 | link_hwss->ext.set_dp_lane_settings(link, link_res, | ||||
7154 | &link_settings->link_settings, | ||||
7155 | link_settings->hw_lane_settings); | ||||
7156 | |||||
7157 | memmove(link->cur_lane_setting,__builtin_memmove((link->cur_lane_setting), (link_settings ->hw_lane_settings), (sizeof(link->cur_lane_setting))) | ||||
7158 | link_settings->hw_lane_settings,__builtin_memmove((link->cur_lane_setting), (link_settings ->hw_lane_settings), (sizeof(link->cur_lane_setting))) | ||||
7159 | sizeof(link->cur_lane_setting))__builtin_memmove((link->cur_lane_setting), (link_settings ->hw_lane_settings), (sizeof(link->cur_lane_setting))); | ||||
7160 | } | ||||
7161 | |||||
7162 | void dp_set_hw_test_pattern( | ||||
7163 | struct dc_link *link, | ||||
7164 | const struct link_resource *link_res, | ||||
7165 | enum dp_test_pattern test_pattern, | ||||
7166 | uint8_t *custom_pattern, | ||||
7167 | uint32_t custom_pattern_size) | ||||
7168 | { | ||||
7169 | const struct link_hwss *link_hwss = get_link_hwss(link, link_res); | ||||
7170 | struct encoder_set_dp_phy_pattern_param pattern_param = {0}; | ||||
7171 | |||||
7172 | pattern_param.dp_phy_pattern = test_pattern; | ||||
7173 | pattern_param.custom_pattern = custom_pattern; | ||||
7174 | pattern_param.custom_pattern_size = custom_pattern_size; | ||||
7175 | pattern_param.dp_panel_mode = dp_get_panel_mode(link); | ||||
7176 | |||||
7177 | if (link_hwss->ext.set_dp_link_test_pattern) | ||||
7178 | link_hwss->ext.set_dp_link_test_pattern(link, link_res, &pattern_param); | ||||
7179 | } | ||||
7180 | |||||
7181 | void dp_retrain_link_dp_test(struct dc_link *link, | ||||
7182 | struct dc_link_settings *link_setting, | ||||
7183 | bool_Bool skip_video_pattern) | ||||
7184 | { | ||||
7185 | struct pipe_ctx *pipes = | ||||
7186 | &link->dc->current_state->res_ctx.pipe_ctx[0]; | ||||
7187 | unsigned int i; | ||||
7188 | |||||
7189 | |||||
7190 | for (i = 0; i < MAX_PIPES6; i++) { | ||||
7191 | if (pipes[i].stream != NULL((void *)0) && | ||||
7192 | !pipes[i].top_pipe && !pipes[i].prev_odm_pipe && | ||||
7193 | pipes[i].stream->link != NULL((void *)0) && | ||||
7194 | pipes[i].stream_res.stream_enc != NULL((void *)0) && | ||||
7195 | pipes[i].stream->link == link) { | ||||
7196 | udelay(100); | ||||
7197 | |||||
7198 | pipes[i].stream_res.stream_enc->funcs->dp_blank(link, | ||||
7199 | pipes[i].stream_res.stream_enc); | ||||
7200 | |||||
7201 | /* disable any test pattern that might be active */ | ||||
7202 | dp_set_hw_test_pattern(link, &pipes[i].link_res, | ||||
7203 | DP_TEST_PATTERN_VIDEO_MODE, NULL((void *)0), 0); | ||||
7204 | |||||
7205 | dp_receiver_power_ctrl(link, false0); | ||||
7206 | |||||
7207 | link->dc->hwss.disable_stream(&pipes[i]); | ||||
7208 | if ((&pipes[i])->stream_res.audio && !link->dc->debug.az_endpoint_mute_only) | ||||
7209 | (&pipes[i])->stream_res.audio->funcs->az_disable((&pipes[i])->stream_res.audio); | ||||
7210 | |||||
7211 | if (link->link_enc) | ||||
7212 | link->link_enc->funcs->disable_output( | ||||
7213 | link->link_enc, | ||||
7214 | SIGNAL_TYPE_DISPLAY_PORT); | ||||
7215 | |||||
7216 | /* Clear current link setting. */ | ||||
7217 | memset(&link->cur_link_settings, 0,__builtin_memset((&link->cur_link_settings), (0), (sizeof (link->cur_link_settings))) | ||||
7218 | sizeof(link->cur_link_settings))__builtin_memset((&link->cur_link_settings), (0), (sizeof (link->cur_link_settings))); | ||||
7219 | |||||
7220 | perform_link_training_with_retries( | ||||
7221 | link_setting, | ||||
7222 | skip_video_pattern, | ||||
7223 | LINK_TRAINING_ATTEMPTS4, | ||||
7224 | &pipes[i], | ||||
7225 | SIGNAL_TYPE_DISPLAY_PORT, | ||||
7226 | false0); | ||||
7227 | |||||
7228 | link->dc->hwss.enable_stream(&pipes[i]); | ||||
7229 | |||||
7230 | link->dc->hwss.unblank_stream(&pipes[i], | ||||
7231 | link_setting); | ||||
7232 | |||||
7233 | if (pipes[i].stream_res.audio) { | ||||
7234 | /* notify audio driver for | ||||
7235 | * audio modes of monitor */ | ||||
7236 | pipes[i].stream_res.audio->funcs->az_enable( | ||||
7237 | pipes[i].stream_res.audio); | ||||
7238 | |||||
7239 | /* un-mute audio */ | ||||
7240 | /* TODO: audio should be per stream rather than | ||||
7241 | * per link */ | ||||
7242 | pipes[i].stream_res.stream_enc->funcs-> | ||||
7243 | audio_mute_control( | ||||
7244 | pipes[i].stream_res.stream_enc, false0); | ||||
7245 | } | ||||
7246 | } | ||||
7247 | } | ||||
7248 | } | ||||
7249 | |||||
7250 | #undef DC_LOGGERlink->ctx->logger | ||||
7251 | #define DC_LOGGERlink->ctx->logger \ | ||||
7252 | dsc->ctx->logger | ||||
7253 | static void dsc_optc_config_log(struct display_stream_compressor *dsc, | ||||
7254 | struct dsc_optc_config *config) | ||||
7255 | { | ||||
7256 | uint32_t precision = 1 << 28; | ||||
7257 | uint32_t bytes_per_pixel_int = config->bytes_per_pixel / precision; | ||||
7258 | uint32_t bytes_per_pixel_mod = config->bytes_per_pixel % precision; | ||||
7259 | uint64_t ll_bytes_per_pix_fraq = bytes_per_pixel_mod; | ||||
7260 | |||||
7261 | /* 7 fractional digits decimal precision for bytes per pixel is enough because DSC | ||||
7262 | * bits per pixel precision is 1/16th of a pixel, which means bytes per pixel precision is | ||||
7263 | * 1/16/8 = 1/128 of a byte, or 0.0078125 decimal | ||||
7264 | */ | ||||
7265 | ll_bytes_per_pix_fraq *= 10000000; | ||||
7266 | ll_bytes_per_pix_fraq /= precision; | ||||
7267 | |||||
7268 | DC_LOG_DSC("\tbytes_per_pixel 0x%08x (%d.%07d)",___drm_dbg(((void *)0), DRM_UT_KMS, "\tbytes_per_pixel 0x%08x (%d.%07d)" , config->bytes_per_pixel, bytes_per_pixel_int, (uint32_t) ll_bytes_per_pix_fraq) | ||||
7269 | config->bytes_per_pixel, bytes_per_pixel_int, (uint32_t)ll_bytes_per_pix_fraq)___drm_dbg(((void *)0), DRM_UT_KMS, "\tbytes_per_pixel 0x%08x (%d.%07d)" , config->bytes_per_pixel, bytes_per_pixel_int, (uint32_t) ll_bytes_per_pix_fraq); | ||||
7270 | DC_LOG_DSC("\tis_pixel_format_444 %d", config->is_pixel_format_444)___drm_dbg(((void *)0), DRM_UT_KMS, "\tis_pixel_format_444 %d" , config->is_pixel_format_444); | ||||
7271 | DC_LOG_DSC("\tslice_width %d", config->slice_width)___drm_dbg(((void *)0), DRM_UT_KMS, "\tslice_width %d", config ->slice_width); | ||||
7272 | } | ||||
7273 | |||||
7274 | bool_Bool dp_set_dsc_on_rx(struct pipe_ctx *pipe_ctx, bool_Bool enable) | ||||
7275 | { | ||||
7276 | struct dc *dc = pipe_ctx->stream->ctx->dc; | ||||
7277 | struct dc_stream_state *stream = pipe_ctx->stream; | ||||
7278 | bool_Bool result = false0; | ||||
7279 | |||||
7280 | if (dc_is_virtual_signal(stream->signal) || IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)(dc->ctx->dce_environment == DCE_ENV_FPGA_MAXIMUS)) | ||||
7281 | result = true1; | ||||
7282 | else | ||||
7283 | result = dm_helpers_dp_write_dsc_enable(dc->ctx, stream, enable); | ||||
7284 | return result; | ||||
7285 | } | ||||
7286 | |||||
7287 | /* The stream with these settings can be sent (unblanked) only after DSC was enabled on RX first, | ||||
7288 | * i.e. after dp_enable_dsc_on_rx() had been called | ||||
7289 | */ | ||||
7290 | void dp_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool_Bool enable) | ||||
7291 | { | ||||
7292 | struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc; | ||||
7293 | struct dc *dc = pipe_ctx->stream->ctx->dc; | ||||
7294 | struct dc_stream_state *stream = pipe_ctx->stream; | ||||
7295 | struct pipe_ctx *odm_pipe; | ||||
7296 | int opp_cnt = 1; | ||||
7297 | |||||
7298 | for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) | ||||
7299 | opp_cnt++; | ||||
7300 | |||||
7301 | if (enable) { | ||||
7302 | struct dsc_config dsc_cfg; | ||||
7303 | struct dsc_optc_config dsc_optc_cfg; | ||||
7304 | enum optc_dsc_mode optc_dsc_mode; | ||||
7305 | |||||
7306 | /* Enable DSC hw block */ | ||||
7307 | dsc_cfg.pic_width = (stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right) / opp_cnt; | ||||
7308 | dsc_cfg.pic_height = stream->timing.v_addressable + stream->timing.v_border_top + stream->timing.v_border_bottom; | ||||
7309 | dsc_cfg.pixel_encoding = stream->timing.pixel_encoding; | ||||
7310 | dsc_cfg.color_depth = stream->timing.display_color_depth; | ||||
7311 | dsc_cfg.is_odm = pipe_ctx->next_odm_pipe ? true1 : false0; | ||||
7312 | dsc_cfg.dc_dsc_cfg = stream->timing.dsc_cfg; | ||||
7313 | ASSERT(dsc_cfg.dc_dsc_cfg.num_slices_h % opp_cnt == 0)do { if (({ static int __warned; int __ret = !!(!(dsc_cfg.dc_dsc_cfg .num_slices_h % opp_cnt == 0)); if (__ret && !__warned ) { printf("WARNING %s failed at %s:%d\n", "!(dsc_cfg.dc_dsc_cfg.num_slices_h % opp_cnt == 0)" , "/usr/src/sys/dev/pci/drm/amd/display/dc/core/dc_link_dp.c" , 7313); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | ||||
7314 | dsc_cfg.dc_dsc_cfg.num_slices_h /= opp_cnt; | ||||
7315 | |||||
7316 | dsc->funcs->dsc_set_config(dsc, &dsc_cfg, &dsc_optc_cfg); | ||||
7317 | dsc->funcs->dsc_enable(dsc, pipe_ctx->stream_res.opp->inst); | ||||
7318 | for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { | ||||
7319 | struct display_stream_compressor *odm_dsc = odm_pipe->stream_res.dsc; | ||||
7320 | |||||
7321 | odm_dsc->funcs->dsc_set_config(odm_dsc, &dsc_cfg, &dsc_optc_cfg); | ||||
7322 | odm_dsc->funcs->dsc_enable(odm_dsc, odm_pipe->stream_res.opp->inst); | ||||
7323 | } | ||||
7324 | dsc_cfg.dc_dsc_cfg.num_slices_h *= opp_cnt; | ||||
7325 | dsc_cfg.pic_width *= opp_cnt; | ||||
7326 | |||||
7327 | optc_dsc_mode = dsc_optc_cfg.is_pixel_format_444 ? OPTC_DSC_ENABLED_444 : OPTC_DSC_ENABLED_NATIVE_SUBSAMPLED; | ||||
7328 | |||||
7329 | /* Enable DSC in encoder */ | ||||
7330 | if (dc_is_dp_signal(stream->signal) && !IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)(dc->ctx->dce_environment == DCE_ENV_FPGA_MAXIMUS) | ||||
7331 | && !is_dp_128b_132b_signal(pipe_ctx)) { | ||||
7332 | DC_LOG_DSC("Setting stream encoder DSC config for engine %d:", (int)pipe_ctx->stream_res.stream_enc->id)___drm_dbg(((void *)0), DRM_UT_KMS, "Setting stream encoder DSC config for engine %d:" , (int)pipe_ctx->stream_res.stream_enc->id); | ||||
7333 | dsc_optc_config_log(dsc, &dsc_optc_cfg); | ||||
7334 | pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_config(pipe_ctx->stream_res.stream_enc, | ||||
7335 | optc_dsc_mode, | ||||
7336 | dsc_optc_cfg.bytes_per_pixel, | ||||
7337 | dsc_optc_cfg.slice_width); | ||||
7338 | |||||
7339 | /* PPS SDP is set elsewhere because it has to be done after DIG FE is connected to DIG BE */ | ||||
7340 | } | ||||
7341 | |||||
7342 | /* Enable DSC in OPTC */ | ||||
7343 | DC_LOG_DSC("Setting optc DSC config for tg instance %d:", pipe_ctx->stream_res.tg->inst)___drm_dbg(((void *)0), DRM_UT_KMS, "Setting optc DSC config for tg instance %d:" , pipe_ctx->stream_res.tg->inst); | ||||
7344 | dsc_optc_config_log(dsc, &dsc_optc_cfg); | ||||
7345 | pipe_ctx->stream_res.tg->funcs->set_dsc_config(pipe_ctx->stream_res.tg, | ||||
7346 | optc_dsc_mode, | ||||
7347 | dsc_optc_cfg.bytes_per_pixel, | ||||
7348 | dsc_optc_cfg.slice_width); | ||||
7349 | } else { | ||||
7350 | /* disable DSC in OPTC */ | ||||
7351 | pipe_ctx->stream_res.tg->funcs->set_dsc_config( | ||||
7352 | pipe_ctx->stream_res.tg, | ||||
7353 | OPTC_DSC_DISABLED, 0, 0); | ||||
7354 | |||||
7355 | /* disable DSC in stream encoder */ | ||||
7356 | if (dc_is_dp_signal(stream->signal)) { | ||||
7357 | if (is_dp_128b_132b_signal(pipe_ctx)) | ||||
7358 | pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_set_dsc_pps_info_packet( | ||||
7359 | pipe_ctx->stream_res.hpo_dp_stream_enc, | ||||
7360 | false0, | ||||
7361 | NULL((void *)0), | ||||
7362 | true1); | ||||
7363 | else if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)(dc->ctx->dce_environment == DCE_ENV_FPGA_MAXIMUS)) { | ||||
7364 | pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_config( | ||||
7365 | pipe_ctx->stream_res.stream_enc, | ||||
7366 | OPTC_DSC_DISABLED, 0, 0); | ||||
7367 | pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_pps_info_packet( | ||||
7368 | pipe_ctx->stream_res.stream_enc, false0, NULL((void *)0), true1); | ||||
7369 | } | ||||
7370 | } | ||||
7371 | |||||
7372 | /* disable DSC block */ | ||||
7373 | pipe_ctx->stream_res.dsc->funcs->dsc_disable(pipe_ctx->stream_res.dsc); | ||||
7374 | for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) | ||||
7375 | odm_pipe->stream_res.dsc->funcs->dsc_disable(odm_pipe->stream_res.dsc); | ||||
7376 | } | ||||
7377 | } | ||||
7378 | |||||
7379 | bool_Bool dp_set_dsc_enable(struct pipe_ctx *pipe_ctx, bool_Bool enable) | ||||
7380 | { | ||||
7381 | struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc; | ||||
7382 | bool_Bool result = false0; | ||||
7383 | |||||
7384 | if (!pipe_ctx->stream->timing.flags.DSC) | ||||
7385 | goto out; | ||||
7386 | if (!dsc) | ||||
7387 | goto out; | ||||
7388 | |||||
7389 | if (enable) { | ||||
7390 | { | ||||
7391 | dp_set_dsc_on_stream(pipe_ctx, true1); | ||||
7392 | result = true1; | ||||
7393 | } | ||||
7394 | } else { | ||||
7395 | dp_set_dsc_on_rx(pipe_ctx, false0); | ||||
7396 | dp_set_dsc_on_stream(pipe_ctx, false0); | ||||
7397 | result = true1; | ||||
7398 | } | ||||
7399 | out: | ||||
7400 | return result; | ||||
7401 | } | ||||
7402 | |||||
7403 | /* | ||||
7404 | * For dynamic bpp change case, dsc is programmed with MASTER_UPDATE_LOCK enabled; | ||||
7405 | * hence PPS info packet update need to use frame update instead of immediate update. | ||||
7406 | * Added parameter immediate_update for this purpose. | ||||
7407 | * The decision to use frame update is hard-coded in function dp_update_dsc_config(), | ||||
7408 | * which is the only place where a "false" would be passed in for param immediate_update. | ||||
7409 | * | ||||
7410 | * immediate_update is only applicable when DSC is enabled. | ||||
7411 | */ | ||||
7412 | bool_Bool dp_set_dsc_pps_sdp(struct pipe_ctx *pipe_ctx, bool_Bool enable, bool_Bool immediate_update) | ||||
7413 | { | ||||
7414 | struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc; | ||||
7415 | struct dc_stream_state *stream = pipe_ctx->stream; | ||||
7416 | |||||
7417 | if (!pipe_ctx->stream->timing.flags.DSC || !dsc) | ||||
7418 | return false0; | ||||
7419 | |||||
7420 | if (enable) { | ||||
7421 | struct dsc_config dsc_cfg; | ||||
7422 | uint8_t dsc_packed_pps[128]; | ||||
7423 | |||||
7424 | memset(&dsc_cfg, 0, sizeof(dsc_cfg))__builtin_memset((&dsc_cfg), (0), (sizeof(dsc_cfg))); | ||||
7425 | memset(dsc_packed_pps, 0, 128)__builtin_memset((dsc_packed_pps), (0), (128)); | ||||
7426 | |||||
7427 | /* Enable DSC hw block */ | ||||
7428 | dsc_cfg.pic_width = stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right; | ||||
7429 | dsc_cfg.pic_height = stream->timing.v_addressable + stream->timing.v_border_top + stream->timing.v_border_bottom; | ||||
7430 | dsc_cfg.pixel_encoding = stream->timing.pixel_encoding; | ||||
7431 | dsc_cfg.color_depth = stream->timing.display_color_depth; | ||||
7432 | dsc_cfg.is_odm = pipe_ctx->next_odm_pipe ? true1 : false0; | ||||
7433 | dsc_cfg.dc_dsc_cfg = stream->timing.dsc_cfg; | ||||
7434 | |||||
7435 | DC_LOG_DSC(" ")___drm_dbg(((void *)0), DRM_UT_KMS, " "); | ||||
7436 | dsc->funcs->dsc_get_packed_pps(dsc, &dsc_cfg, &dsc_packed_pps[0]); | ||||
7437 | memcpy(&stream->dsc_packed_pps[0], &dsc_packed_pps[0], sizeof(stream->dsc_packed_pps))__builtin_memcpy((&stream->dsc_packed_pps[0]), (&dsc_packed_pps [0]), (sizeof(stream->dsc_packed_pps))); | ||||
7438 | if (dc_is_dp_signal(stream->signal)) { | ||||
7439 | DC_LOG_DSC("Setting stream encoder DSC PPS SDP for engine %d\n", (int)pipe_ctx->stream_res.stream_enc->id)___drm_dbg(((void *)0), DRM_UT_KMS, "Setting stream encoder DSC PPS SDP for engine %d\n" , (int)pipe_ctx->stream_res.stream_enc->id); | ||||
7440 | if (is_dp_128b_132b_signal(pipe_ctx)) | ||||
7441 | pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_set_dsc_pps_info_packet( | ||||
7442 | pipe_ctx->stream_res.hpo_dp_stream_enc, | ||||
7443 | true1, | ||||
7444 | &dsc_packed_pps[0], | ||||
7445 | immediate_update); | ||||
7446 | else | ||||
7447 | pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_pps_info_packet( | ||||
7448 | pipe_ctx->stream_res.stream_enc, | ||||
7449 | true1, | ||||
7450 | &dsc_packed_pps[0], | ||||
7451 | immediate_update); | ||||
7452 | } | ||||
7453 | } else { | ||||
7454 | /* disable DSC PPS in stream encoder */ | ||||
7455 | memset(&stream->dsc_packed_pps[0], 0, sizeof(stream->dsc_packed_pps))__builtin_memset((&stream->dsc_packed_pps[0]), (0), (sizeof (stream->dsc_packed_pps))); | ||||
7456 | if (dc_is_dp_signal(stream->signal)) { | ||||
7457 | if (is_dp_128b_132b_signal(pipe_ctx)) | ||||
7458 | pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_set_dsc_pps_info_packet( | ||||
7459 | pipe_ctx->stream_res.hpo_dp_stream_enc, | ||||
7460 | false0, | ||||
7461 | NULL((void *)0), | ||||
7462 | true1); | ||||
7463 | else | ||||
7464 | pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_pps_info_packet( | ||||
7465 | pipe_ctx->stream_res.stream_enc, false0, NULL((void *)0), true1); | ||||
7466 | } | ||||
7467 | } | ||||
7468 | |||||
7469 | return true1; | ||||
7470 | } | ||||
7471 | |||||
7472 | |||||
7473 | bool_Bool dp_update_dsc_config(struct pipe_ctx *pipe_ctx) | ||||
7474 | { | ||||
7475 | struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc; | ||||
7476 | |||||
7477 | if (!pipe_ctx->stream->timing.flags.DSC) | ||||
7478 | return false0; | ||||
7479 | if (!dsc) | ||||
7480 | return false0; | ||||
7481 | |||||
7482 | dp_set_dsc_on_stream(pipe_ctx, true1); | ||||
7483 | dp_set_dsc_pps_sdp(pipe_ctx, true1, false0); | ||||
7484 | return true1; | ||||
7485 | } | ||||
7486 | |||||
7487 | #undef DC_LOGGERlink->ctx->logger | ||||
7488 | #define DC_LOGGERlink->ctx->logger \ | ||||
7489 | link->ctx->logger |