Merge tag 'amd-drm-next-5.8-2020-05-12' of git://people.freedesktop.org/~agd5f/linux...
[linux-block.git] / drivers / gpu / drm / amd / display / dc / core / dc_link_dp.c
CommitLineData
4562236b
HW
1/* Copyright 2015 Advanced Micro Devices, Inc. */
2#include "dm_services.h"
3#include "dc.h"
4#include "dc_link_dp.h"
5#include "dm_helpers.h"
7f93c1de 6#include "opp.h"
97bda032 7#include "dsc.h"
6fbefb84 8#include "resource.h"
4562236b
HW
9
10#include "inc/core_types.h"
11#include "link_hwss.h"
12#include "dc_link_ddc.h"
13#include "core_status.h"
14#include "dpcd_defs.h"
15
1296423b
BL
16#define DC_LOGGER \
17 link->ctx->logger
4562236b 18
8e5100a5 19
64c12b73 20#define DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE 0x50
8e5100a5 21
4562236b
HW
22/* maximum pre emphasis level allowed for each voltage swing level*/
23static const enum dc_pre_emphasis voltage_swing_to_pre_emphasis[] = {
24 PRE_EMPHASIS_LEVEL3,
25 PRE_EMPHASIS_LEVEL2,
26 PRE_EMPHASIS_LEVEL1,
27 PRE_EMPHASIS_DISABLED };
28
29enum {
30 POST_LT_ADJ_REQ_LIMIT = 6,
31 POST_LT_ADJ_REQ_TIMEOUT = 200
32};
33
34enum {
35 LINK_TRAINING_MAX_RETRY_COUNT = 5,
36 /* to avoid infinite loop where-in the receiver
37 * switches between different VS
38 */
39 LINK_TRAINING_MAX_CR_RETRY = 100
40};
41
04e21292
DA
42static bool decide_fallback_link_setting(
43 struct dc_link_settings initial_link_settings,
44 struct dc_link_settings *current_link_setting,
45 enum link_training_result training_result);
9a6a8075 46static struct dc_link_settings get_common_supported_link_settings(
04e21292
DA
47 struct dc_link_settings link_setting_a,
48 struct dc_link_settings link_setting_b);
49
e0a6440a 50static uint32_t get_training_aux_rd_interval(
d0778ebf 51 struct dc_link *link,
4562236b
HW
52 uint32_t default_wait_in_micro_secs)
53{
d6d36b55
NC
54 union training_aux_rd_interval training_rd_interval;
55
56 memset(&training_rd_interval, 0, sizeof(training_rd_interval));
4562236b
HW
57
58 /* overwrite the delay if rev > 1.1*/
59 if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_12) {
60 /* DP 1.2 or later - retrieve delay through
61 * "DPCD_ADDR_TRAINING_AUX_RD_INTERVAL" register */
62 core_link_read_dpcd(
63 link,
3a340294 64 DP_TRAINING_AUX_RD_INTERVAL,
4562236b
HW
65 (uint8_t *)&training_rd_interval,
66 sizeof(training_rd_interval));
67
68 if (training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL)
e0a6440a 69 default_wait_in_micro_secs = training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL * 4000;
4562236b
HW
70 }
71
e0a6440a
DG
72 return default_wait_in_micro_secs;
73}
74
75static void wait_for_training_aux_rd_interval(
76 struct dc_link *link,
77 uint32_t wait_in_micro_secs)
78{
79 udelay(wait_in_micro_secs);
4562236b 80
1296423b 81 DC_LOG_HW_LINK_TRAINING("%s:\n wait = %d\n",
4562236b 82 __func__,
e0a6440a 83 wait_in_micro_secs);
4562236b
HW
84}
85
86static void dpcd_set_training_pattern(
d0778ebf 87 struct dc_link *link,
4562236b
HW
88 union dpcd_training_pattern dpcd_pattern)
89{
90 core_link_write_dpcd(
91 link,
3a340294 92 DP_TRAINING_PATTERN_SET,
4562236b
HW
93 &dpcd_pattern.raw,
94 1);
95
1296423b 96 DC_LOG_HW_LINK_TRAINING("%s\n %x pattern = %x\n",
4562236b 97 __func__,
3a340294 98 DP_TRAINING_PATTERN_SET,
4562236b
HW
99 dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
100}
101
e0a6440a 102static enum dc_dp_training_pattern get_supported_tp(struct dc_link *link)
16b6253a 103{
e0a6440a 104 enum dc_dp_training_pattern highest_tp = DP_TRAINING_PATTERN_SEQUENCE_2;
16b6253a 105 struct encoder_feature_support *features = &link->link_enc->features;
106 struct dpcd_caps *dpcd_caps = &link->dpcd_caps;
107
108 if (features->flags.bits.IS_TPS3_CAPABLE)
e0a6440a 109 highest_tp = DP_TRAINING_PATTERN_SEQUENCE_3;
16b6253a 110
111 if (features->flags.bits.IS_TPS4_CAPABLE)
e0a6440a 112 highest_tp = DP_TRAINING_PATTERN_SEQUENCE_4;
16b6253a 113
114 if (dpcd_caps->max_down_spread.bits.TPS4_SUPPORTED &&
e0a6440a
DG
115 highest_tp >= DP_TRAINING_PATTERN_SEQUENCE_4)
116 return DP_TRAINING_PATTERN_SEQUENCE_4;
16b6253a 117
118 if (dpcd_caps->max_ln_count.bits.TPS3_SUPPORTED &&
e0a6440a
DG
119 highest_tp >= DP_TRAINING_PATTERN_SEQUENCE_3)
120 return DP_TRAINING_PATTERN_SEQUENCE_3;
16b6253a 121
e0a6440a 122 return DP_TRAINING_PATTERN_SEQUENCE_2;
16b6253a 123}
124
4562236b 125static void dpcd_set_link_settings(
d0778ebf 126 struct dc_link *link,
4562236b
HW
127 const struct link_training_settings *lt_settings)
128{
8628d02f 129 uint8_t rate;
4562236b 130
9a6a8075
HW
131 union down_spread_ctrl downspread = { {0} };
132 union lane_count_set lane_count_set = { {0} };
e0a6440a 133 enum dc_dp_training_pattern dp_tr_pattern;
4562236b
HW
134
135 downspread.raw = (uint8_t)
136 (lt_settings->link_settings.link_spread);
137
138 lane_count_set.bits.LANE_COUNT_SET =
139 lt_settings->link_settings.lane_count;
140
e0a6440a 141 lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing;
16b6253a 142 lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0;
143
e0a6440a
DG
144 dp_tr_pattern = get_supported_tp(link);
145
146 if (dp_tr_pattern != DP_TRAINING_PATTERN_SEQUENCE_4) {
16b6253a 147 lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED =
148 link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED;
149 }
4562236b 150
3a340294 151 core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL,
e0a6440a 152 &downspread.raw, sizeof(downspread));
4562236b 153
8628d02f 154 core_link_write_dpcd(link, DP_LANE_COUNT_SET,
e0a6440a 155 &lane_count_set.raw, 1);
8628d02f 156
b03a599b 157 if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_14 &&
8628d02f
JP
158 lt_settings->link_settings.use_link_rate_set == true) {
159 rate = 0;
160 core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1);
b03a599b 161 core_link_write_dpcd(link, DP_LINK_RATE_SET,
8628d02f
JP
162 &lt_settings->link_settings.link_rate_set, 1);
163 } else {
164 rate = (uint8_t) (lt_settings->link_settings.link_rate);
165 core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1);
b03a599b
DL
166 }
167
8628d02f 168 if (rate) {
e0a6440a 169 DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x framing = %x\n %x spread = %x\n",
8628d02f
JP
170 __func__,
171 DP_LINK_BW_SET,
172 lt_settings->link_settings.link_rate,
173 DP_LANE_COUNT_SET,
174 lt_settings->link_settings.lane_count,
e0a6440a 175 lt_settings->enhanced_framing,
8628d02f
JP
176 DP_DOWNSPREAD_CTRL,
177 lt_settings->link_settings.link_spread);
178 } else {
e0a6440a 179 DC_LOG_HW_LINK_TRAINING("%s\n %x rate set = %x\n %x lane = %x framing = %x\n %x spread = %x\n",
8628d02f
JP
180 __func__,
181 DP_LINK_RATE_SET,
182 lt_settings->link_settings.link_rate_set,
183 DP_LANE_COUNT_SET,
184 lt_settings->link_settings.lane_count,
e0a6440a 185 lt_settings->enhanced_framing,
8628d02f
JP
186 DP_DOWNSPREAD_CTRL,
187 lt_settings->link_settings.link_spread);
188 }
4562236b
HW
189}
190
191static enum dpcd_training_patterns
e0a6440a 192 dc_dp_training_pattern_to_dpcd_training_pattern(
d0778ebf 193 struct dc_link *link,
e0a6440a 194 enum dc_dp_training_pattern pattern)
4562236b
HW
195{
196 enum dpcd_training_patterns dpcd_tr_pattern =
197 DPCD_TRAINING_PATTERN_VIDEOIDLE;
198
199 switch (pattern) {
e0a6440a 200 case DP_TRAINING_PATTERN_SEQUENCE_1:
4562236b
HW
201 dpcd_tr_pattern = DPCD_TRAINING_PATTERN_1;
202 break;
e0a6440a 203 case DP_TRAINING_PATTERN_SEQUENCE_2:
4562236b
HW
204 dpcd_tr_pattern = DPCD_TRAINING_PATTERN_2;
205 break;
e0a6440a 206 case DP_TRAINING_PATTERN_SEQUENCE_3:
4562236b
HW
207 dpcd_tr_pattern = DPCD_TRAINING_PATTERN_3;
208 break;
e0a6440a 209 case DP_TRAINING_PATTERN_SEQUENCE_4:
4562236b
HW
210 dpcd_tr_pattern = DPCD_TRAINING_PATTERN_4;
211 break;
212 default:
213 ASSERT(0);
1296423b 214 DC_LOG_HW_LINK_TRAINING("%s: Invalid HW Training pattern: %d\n",
4562236b
HW
215 __func__, pattern);
216 break;
217 }
218
219 return dpcd_tr_pattern;
4562236b
HW
220}
221
64c12b73 222static inline bool is_repeater(struct dc_link *link, uint32_t offset)
223{
224 return (!link->is_lttpr_mode_transparent && offset != 0);
225}
226
4562236b 227static void dpcd_set_lt_pattern_and_lane_settings(
d0778ebf 228 struct dc_link *link,
4562236b 229 const struct link_training_settings *lt_settings,
64c12b73 230 enum dc_dp_training_pattern pattern,
231 uint32_t offset)
4562236b 232{
9a6a8075 233 union dpcd_training_lane dpcd_lane[LANE_COUNT_DP_MAX] = { { {0} } };
64c12b73 234
235 uint32_t dpcd_base_lt_offset;
236
4562236b 237 uint8_t dpcd_lt_buffer[5] = {0};
9a6a8075 238 union dpcd_training_pattern dpcd_pattern = { {0} };
4562236b
HW
239 uint32_t lane;
240 uint32_t size_in_bytes;
241 bool edp_workaround = false; /* TODO link_prop.INTERNAL */
64c12b73 242 dpcd_base_lt_offset = DP_TRAINING_PATTERN_SET;
243
244 if (is_repeater(link, offset))
245 dpcd_base_lt_offset = DP_TRAINING_PATTERN_SET_PHY_REPEATER1 +
246 ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
4562236b
HW
247
248 /*****************************************************************
249 * DpcdAddress_TrainingPatternSet
250 *****************************************************************/
251 dpcd_pattern.v1_4.TRAINING_PATTERN_SET =
e0a6440a 252 dc_dp_training_pattern_to_dpcd_training_pattern(link, pattern);
4562236b 253
64c12b73 254 dpcd_lt_buffer[DP_TRAINING_PATTERN_SET - DP_TRAINING_PATTERN_SET]
4562236b
HW
255 = dpcd_pattern.raw;
256
460adc6b 257 if (is_repeater(link, offset)) {
258 DC_LOG_HW_LINK_TRAINING("%s\n LTTPR Repeater ID: %d\n 0x%X pattern = %x\n",
259 __func__,
260 offset,
261 dpcd_base_lt_offset,
262 dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
263 } else {
264 DC_LOG_HW_LINK_TRAINING("%s\n 0x%X pattern = %x\n",
265 __func__,
266 dpcd_base_lt_offset,
267 dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
268 }
4562236b
HW
269 /*****************************************************************
270 * DpcdAddress_Lane0Set -> DpcdAddress_Lane3Set
271 *****************************************************************/
272 for (lane = 0; lane <
273 (uint32_t)(lt_settings->link_settings.lane_count); lane++) {
274
275 dpcd_lane[lane].bits.VOLTAGE_SWING_SET =
276 (uint8_t)(lt_settings->lane_settings[lane].VOLTAGE_SWING);
277 dpcd_lane[lane].bits.PRE_EMPHASIS_SET =
278 (uint8_t)(lt_settings->lane_settings[lane].PRE_EMPHASIS);
279
280 dpcd_lane[lane].bits.MAX_SWING_REACHED =
281 (lt_settings->lane_settings[lane].VOLTAGE_SWING ==
282 VOLTAGE_SWING_MAX_LEVEL ? 1 : 0);
283 dpcd_lane[lane].bits.MAX_PRE_EMPHASIS_REACHED =
284 (lt_settings->lane_settings[lane].PRE_EMPHASIS ==
285 PRE_EMPHASIS_MAX_LEVEL ? 1 : 0);
286 }
287
64c12b73 288 /* concatenate everything into one buffer*/
4562236b
HW
289
290 size_in_bytes = lt_settings->link_settings.lane_count * sizeof(dpcd_lane[0]);
291
292 // 0x00103 - 0x00102
293 memmove(
64c12b73 294 &dpcd_lt_buffer[DP_TRAINING_LANE0_SET - DP_TRAINING_PATTERN_SET],
4562236b
HW
295 dpcd_lane,
296 size_in_bytes);
297
460adc6b 298 if (is_repeater(link, offset)) {
299 DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n"
300 " 0x%X VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n",
301 __func__,
302 offset,
303 dpcd_base_lt_offset,
304 dpcd_lane[0].bits.VOLTAGE_SWING_SET,
305 dpcd_lane[0].bits.PRE_EMPHASIS_SET,
306 dpcd_lane[0].bits.MAX_SWING_REACHED,
307 dpcd_lane[0].bits.MAX_PRE_EMPHASIS_REACHED);
308 } else {
309 DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n",
310 __func__,
311 dpcd_base_lt_offset,
312 dpcd_lane[0].bits.VOLTAGE_SWING_SET,
313 dpcd_lane[0].bits.PRE_EMPHASIS_SET,
314 dpcd_lane[0].bits.MAX_SWING_REACHED,
315 dpcd_lane[0].bits.MAX_PRE_EMPHASIS_REACHED);
316 }
4562236b
HW
317 if (edp_workaround) {
318 /* for eDP write in 2 parts because the 5-byte burst is
319 * causing issues on some eDP panels (EPR#366724)
320 */
321 core_link_write_dpcd(
322 link,
3a340294 323 DP_TRAINING_PATTERN_SET,
4562236b 324 &dpcd_pattern.raw,
9a6a8075 325 sizeof(dpcd_pattern.raw));
4562236b
HW
326
327 core_link_write_dpcd(
328 link,
3a340294 329 DP_TRAINING_LANE0_SET,
4562236b
HW
330 (uint8_t *)(dpcd_lane),
331 size_in_bytes);
332
333 } else
334 /* write it all in (1 + number-of-lanes)-byte burst*/
335 core_link_write_dpcd(
336 link,
337 dpcd_base_lt_offset,
338 dpcd_lt_buffer,
9a6a8075 339 size_in_bytes + sizeof(dpcd_pattern.raw));
4562236b 340
d0778ebf 341 link->cur_lane_setting = lt_settings->lane_settings[0];
4562236b
HW
342}
343
344static bool is_cr_done(enum dc_lane_count ln_count,
345 union lane_status *dpcd_lane_status)
346{
347 bool done = true;
348 uint32_t lane;
349 /*LANEx_CR_DONE bits All 1's?*/
350 for (lane = 0; lane < (uint32_t)(ln_count); lane++) {
351 if (!dpcd_lane_status[lane].bits.CR_DONE_0)
352 done = false;
353 }
354 return done;
355
356}
357
358static bool is_ch_eq_done(enum dc_lane_count ln_count,
359 union lane_status *dpcd_lane_status,
360 union lane_align_status_updated *lane_status_updated)
361{
362 bool done = true;
363 uint32_t lane;
364 if (!lane_status_updated->bits.INTERLANE_ALIGN_DONE)
365 done = false;
366 else {
367 for (lane = 0; lane < (uint32_t)(ln_count); lane++) {
368 if (!dpcd_lane_status[lane].bits.SYMBOL_LOCKED_0 ||
369 !dpcd_lane_status[lane].bits.CHANNEL_EQ_DONE_0)
370 done = false;
371 }
372 }
373 return done;
374
375}
376
377static void update_drive_settings(
378 struct link_training_settings *dest,
379 struct link_training_settings src)
380{
381 uint32_t lane;
382 for (lane = 0; lane < src.link_settings.lane_count; lane++) {
e0a6440a
DG
383 if (dest->voltage_swing == NULL)
384 dest->lane_settings[lane].VOLTAGE_SWING = src.lane_settings[lane].VOLTAGE_SWING;
385 else
386 dest->lane_settings[lane].VOLTAGE_SWING = *dest->voltage_swing;
387
388 if (dest->pre_emphasis == NULL)
389 dest->lane_settings[lane].PRE_EMPHASIS = src.lane_settings[lane].PRE_EMPHASIS;
390 else
391 dest->lane_settings[lane].PRE_EMPHASIS = *dest->pre_emphasis;
392
393 if (dest->post_cursor2 == NULL)
394 dest->lane_settings[lane].POST_CURSOR2 = src.lane_settings[lane].POST_CURSOR2;
395 else
396 dest->lane_settings[lane].POST_CURSOR2 = *dest->post_cursor2;
4562236b
HW
397 }
398}
399
400static uint8_t get_nibble_at_index(const uint8_t *buf,
401 uint32_t index)
402{
403 uint8_t nibble;
404 nibble = buf[index / 2];
405
406 if (index % 2)
407 nibble >>= 4;
408 else
409 nibble &= 0x0F;
410
411 return nibble;
412}
413
414static enum dc_pre_emphasis get_max_pre_emphasis_for_voltage_swing(
415 enum dc_voltage_swing voltage)
416{
417 enum dc_pre_emphasis pre_emphasis;
418 pre_emphasis = PRE_EMPHASIS_MAX_LEVEL;
419
420 if (voltage <= VOLTAGE_SWING_MAX_LEVEL)
421 pre_emphasis = voltage_swing_to_pre_emphasis[voltage];
422
423 return pre_emphasis;
424
425}
426
427static void find_max_drive_settings(
428 const struct link_training_settings *link_training_setting,
429 struct link_training_settings *max_lt_setting)
430{
431 uint32_t lane;
432 struct dc_lane_settings max_requested;
433
434 max_requested.VOLTAGE_SWING =
435 link_training_setting->
436 lane_settings[0].VOLTAGE_SWING;
437 max_requested.PRE_EMPHASIS =
438 link_training_setting->
439 lane_settings[0].PRE_EMPHASIS;
440 /*max_requested.postCursor2 =
441 * link_training_setting->laneSettings[0].postCursor2;*/
442
443 /* Determine what the maximum of the requested settings are*/
444 for (lane = 1; lane < link_training_setting->link_settings.lane_count;
445 lane++) {
446 if (link_training_setting->lane_settings[lane].VOLTAGE_SWING >
447 max_requested.VOLTAGE_SWING)
448
449 max_requested.VOLTAGE_SWING =
450 link_training_setting->
451 lane_settings[lane].VOLTAGE_SWING;
452
453 if (link_training_setting->lane_settings[lane].PRE_EMPHASIS >
454 max_requested.PRE_EMPHASIS)
455 max_requested.PRE_EMPHASIS =
456 link_training_setting->
457 lane_settings[lane].PRE_EMPHASIS;
458
459 /*
460 if (link_training_setting->laneSettings[lane].postCursor2 >
461 max_requested.postCursor2)
462 {
463 max_requested.postCursor2 =
464 link_training_setting->laneSettings[lane].postCursor2;
465 }
466 */
467 }
468
469 /* make sure the requested settings are
470 * not higher than maximum settings*/
471 if (max_requested.VOLTAGE_SWING > VOLTAGE_SWING_MAX_LEVEL)
472 max_requested.VOLTAGE_SWING = VOLTAGE_SWING_MAX_LEVEL;
473
474 if (max_requested.PRE_EMPHASIS > PRE_EMPHASIS_MAX_LEVEL)
475 max_requested.PRE_EMPHASIS = PRE_EMPHASIS_MAX_LEVEL;
476 /*
477 if (max_requested.postCursor2 > PostCursor2_MaxLevel)
478 max_requested.postCursor2 = PostCursor2_MaxLevel;
479 */
480
481 /* make sure the pre-emphasis matches the voltage swing*/
482 if (max_requested.PRE_EMPHASIS >
483 get_max_pre_emphasis_for_voltage_swing(
484 max_requested.VOLTAGE_SWING))
485 max_requested.PRE_EMPHASIS =
486 get_max_pre_emphasis_for_voltage_swing(
487 max_requested.VOLTAGE_SWING);
488
489 /*
490 * Post Cursor2 levels are completely independent from
491 * pre-emphasis (Post Cursor1) levels. But Post Cursor2 levels
492 * can only be applied to each allowable combination of voltage
493 * swing and pre-emphasis levels */
494 /* if ( max_requested.postCursor2 >
495 * getMaxPostCursor2ForVoltageSwing(max_requested.voltageSwing))
496 * max_requested.postCursor2 =
497 * getMaxPostCursor2ForVoltageSwing(max_requested.voltageSwing);
498 */
499
500 max_lt_setting->link_settings.link_rate =
501 link_training_setting->link_settings.link_rate;
502 max_lt_setting->link_settings.lane_count =
503 link_training_setting->link_settings.lane_count;
504 max_lt_setting->link_settings.link_spread =
505 link_training_setting->link_settings.link_spread;
506
507 for (lane = 0; lane <
508 link_training_setting->link_settings.lane_count;
509 lane++) {
510 max_lt_setting->lane_settings[lane].VOLTAGE_SWING =
511 max_requested.VOLTAGE_SWING;
512 max_lt_setting->lane_settings[lane].PRE_EMPHASIS =
513 max_requested.PRE_EMPHASIS;
514 /*max_lt_setting->laneSettings[lane].postCursor2 =
515 * max_requested.postCursor2;
516 */
517 }
518
519}
520
521static void get_lane_status_and_drive_settings(
d0778ebf 522 struct dc_link *link,
4562236b
HW
523 const struct link_training_settings *link_training_setting,
524 union lane_status *ln_status,
525 union lane_align_status_updated *ln_status_updated,
64c12b73 526 struct link_training_settings *req_settings,
527 uint32_t offset)
4562236b 528{
64c12b73 529 unsigned int lane01_status_address = DP_LANE0_1_STATUS;
530 uint8_t lane_adjust_offset = 4;
531 unsigned int lane01_adjust_address;
4562236b 532 uint8_t dpcd_buf[6] = {0};
9a6a8075
HW
533 union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = { { {0} } };
534 struct link_training_settings request_settings = { {0} };
4562236b
HW
535 uint32_t lane;
536
537 memset(req_settings, '\0', sizeof(struct link_training_settings));
538
64c12b73 539 if (is_repeater(link, offset)) {
540 lane01_status_address =
541 DP_LANE0_1_STATUS_PHY_REPEATER1 +
542 ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
543 lane_adjust_offset = 3;
544 }
545
4562236b
HW
546 core_link_read_dpcd(
547 link,
64c12b73 548 lane01_status_address,
4562236b
HW
549 (uint8_t *)(dpcd_buf),
550 sizeof(dpcd_buf));
551
552 for (lane = 0; lane <
553 (uint32_t)(link_training_setting->link_settings.lane_count);
554 lane++) {
555
556 ln_status[lane].raw =
557 get_nibble_at_index(&dpcd_buf[0], lane);
558 dpcd_lane_adjust[lane].raw =
64c12b73 559 get_nibble_at_index(&dpcd_buf[lane_adjust_offset], lane);
4562236b
HW
560 }
561
562 ln_status_updated->raw = dpcd_buf[2];
563
460adc6b 564 if (is_repeater(link, offset)) {
565 DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n"
566 " 0x%X Lane01Status = %x\n 0x%X Lane23Status = %x\n ",
567 __func__,
568 offset,
569 lane01_status_address, dpcd_buf[0],
570 lane01_status_address + 1, dpcd_buf[1]);
571 } else {
572 DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X Lane01Status = %x\n 0x%X Lane23Status = %x\n ",
573 __func__,
574 lane01_status_address, dpcd_buf[0],
575 lane01_status_address + 1, dpcd_buf[1]);
576 }
64c12b73 577 lane01_adjust_address = DP_ADJUST_REQUEST_LANE0_1;
578
579 if (is_repeater(link, offset))
580 lane01_adjust_address = DP_ADJUST_REQUEST_LANE0_1_PHY_REPEATER1 +
581 ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
4562236b 582
460adc6b 583 if (is_repeater(link, offset)) {
584 DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n"
585 " 0x%X Lane01AdjustRequest = %x\n 0x%X Lane23AdjustRequest = %x\n",
586 __func__,
587 offset,
588 lane01_adjust_address,
589 dpcd_buf[lane_adjust_offset],
590 lane01_adjust_address + 1,
591 dpcd_buf[lane_adjust_offset + 1]);
592 } else {
593 DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X Lane01AdjustRequest = %x\n 0x%X Lane23AdjustRequest = %x\n",
594 __func__,
595 lane01_adjust_address,
596 dpcd_buf[lane_adjust_offset],
597 lane01_adjust_address + 1,
598 dpcd_buf[lane_adjust_offset + 1]);
599 }
4562236b
HW
600
601 /*copy to req_settings*/
602 request_settings.link_settings.lane_count =
603 link_training_setting->link_settings.lane_count;
604 request_settings.link_settings.link_rate =
605 link_training_setting->link_settings.link_rate;
606 request_settings.link_settings.link_spread =
607 link_training_setting->link_settings.link_spread;
608
609 for (lane = 0; lane <
610 (uint32_t)(link_training_setting->link_settings.lane_count);
611 lane++) {
612
613 request_settings.lane_settings[lane].VOLTAGE_SWING =
614 (enum dc_voltage_swing)(dpcd_lane_adjust[lane].bits.
615 VOLTAGE_SWING_LANE);
616 request_settings.lane_settings[lane].PRE_EMPHASIS =
617 (enum dc_pre_emphasis)(dpcd_lane_adjust[lane].bits.
618 PRE_EMPHASIS_LANE);
619 }
620
621 /*Note: for postcursor2, read adjusted
622 * postcursor2 settings from*/
623 /*DpcdAddress_AdjustRequestPostCursor2 =
624 *0x020C (not implemented yet)*/
625
626 /* we find the maximum of the requested settings across all lanes*/
627 /* and set this maximum for all lanes*/
628 find_max_drive_settings(&request_settings, req_settings);
629
630 /* if post cursor 2 is needed in the future,
631 * read DpcdAddress_AdjustRequestPostCursor2 = 0x020C
632 */
633
634}
635
636static void dpcd_set_lane_settings(
d0778ebf 637 struct dc_link *link,
64c12b73 638 const struct link_training_settings *link_training_setting,
639 uint32_t offset)
4562236b
HW
640{
641 union dpcd_training_lane dpcd_lane[LANE_COUNT_DP_MAX] = {{{0}}};
642 uint32_t lane;
64c12b73 643 unsigned int lane0_set_address;
644
645 lane0_set_address = DP_TRAINING_LANE0_SET;
646
647 if (is_repeater(link, offset))
648 lane0_set_address = DP_TRAINING_LANE0_SET_PHY_REPEATER1 +
649 ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
4562236b
HW
650
651 for (lane = 0; lane <
652 (uint32_t)(link_training_setting->
653 link_settings.lane_count);
654 lane++) {
655 dpcd_lane[lane].bits.VOLTAGE_SWING_SET =
656 (uint8_t)(link_training_setting->
657 lane_settings[lane].VOLTAGE_SWING);
658 dpcd_lane[lane].bits.PRE_EMPHASIS_SET =
659 (uint8_t)(link_training_setting->
660 lane_settings[lane].PRE_EMPHASIS);
661 dpcd_lane[lane].bits.MAX_SWING_REACHED =
662 (link_training_setting->
663 lane_settings[lane].VOLTAGE_SWING ==
664 VOLTAGE_SWING_MAX_LEVEL ? 1 : 0);
665 dpcd_lane[lane].bits.MAX_PRE_EMPHASIS_REACHED =
666 (link_training_setting->
667 lane_settings[lane].PRE_EMPHASIS ==
668 PRE_EMPHASIS_MAX_LEVEL ? 1 : 0);
669 }
670
671 core_link_write_dpcd(link,
64c12b73 672 lane0_set_address,
4562236b
HW
673 (uint8_t *)(dpcd_lane),
674 link_training_setting->link_settings.lane_count);
675
676 /*
677 if (LTSettings.link.rate == LinkRate_High2)
678 {
679 DpcdTrainingLaneSet2 dpcd_lane2[lane_count_DPMax] = {0};
680 for ( uint32_t lane = 0;
681 lane < lane_count_DPMax; lane++)
682 {
683 dpcd_lane2[lane].bits.post_cursor2_set =
684 static_cast<unsigned char>(
685 LTSettings.laneSettings[lane].postCursor2);
686 dpcd_lane2[lane].bits.max_post_cursor2_reached = 0;
687 }
688 m_pDpcdAccessSrv->WriteDpcdData(
689 DpcdAddress_Lane0Set2,
690 reinterpret_cast<unsigned char*>(dpcd_lane2),
691 LTSettings.link.lanes);
692 }
693 */
694
460adc6b 695 if (is_repeater(link, offset)) {
696 DC_LOG_HW_LINK_TRAINING("%s\n LTTPR Repeater ID: %d\n"
697 " 0x%X VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n",
698 __func__,
699 offset,
700 lane0_set_address,
701 dpcd_lane[0].bits.VOLTAGE_SWING_SET,
702 dpcd_lane[0].bits.PRE_EMPHASIS_SET,
703 dpcd_lane[0].bits.MAX_SWING_REACHED,
704 dpcd_lane[0].bits.MAX_PRE_EMPHASIS_REACHED);
4562236b 705
460adc6b 706 } else {
707 DC_LOG_HW_LINK_TRAINING("%s\n 0x%X VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n",
708 __func__,
709 lane0_set_address,
710 dpcd_lane[0].bits.VOLTAGE_SWING_SET,
711 dpcd_lane[0].bits.PRE_EMPHASIS_SET,
712 dpcd_lane[0].bits.MAX_SWING_REACHED,
713 dpcd_lane[0].bits.MAX_PRE_EMPHASIS_REACHED);
714 }
d0778ebf 715 link->cur_lane_setting = link_training_setting->lane_settings[0];
4562236b
HW
716
717}
718
719static bool is_max_vs_reached(
720 const struct link_training_settings *lt_settings)
721{
722 uint32_t lane;
723 for (lane = 0; lane <
724 (uint32_t)(lt_settings->link_settings.lane_count);
725 lane++) {
726 if (lt_settings->lane_settings[lane].VOLTAGE_SWING
727 == VOLTAGE_SWING_MAX_LEVEL)
728 return true;
729 }
730 return false;
731
732}
733
4562236b 734static bool perform_post_lt_adj_req_sequence(
d0778ebf 735 struct dc_link *link,
4562236b
HW
736 struct link_training_settings *lt_settings)
737{
738 enum dc_lane_count lane_count =
739 lt_settings->link_settings.lane_count;
740
741 uint32_t adj_req_count;
742 uint32_t adj_req_timer;
743 bool req_drv_setting_changed;
744 uint32_t lane;
745
746 req_drv_setting_changed = false;
747 for (adj_req_count = 0; adj_req_count < POST_LT_ADJ_REQ_LIMIT;
748 adj_req_count++) {
749
750 req_drv_setting_changed = false;
751
752 for (adj_req_timer = 0;
753 adj_req_timer < POST_LT_ADJ_REQ_TIMEOUT;
754 adj_req_timer++) {
755
756 struct link_training_settings req_settings;
757 union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX];
758 union lane_align_status_updated
759 dpcd_lane_status_updated;
760
761 get_lane_status_and_drive_settings(
762 link,
763 lt_settings,
764 dpcd_lane_status,
765 &dpcd_lane_status_updated,
64c12b73 766 &req_settings,
767 DPRX);
4562236b
HW
768
769 if (dpcd_lane_status_updated.bits.
770 POST_LT_ADJ_REQ_IN_PROGRESS == 0)
771 return true;
772
773 if (!is_cr_done(lane_count, dpcd_lane_status))
774 return false;
775
776 if (!is_ch_eq_done(
777 lane_count,
778 dpcd_lane_status,
779 &dpcd_lane_status_updated))
780 return false;
781
782 for (lane = 0; lane < (uint32_t)(lane_count); lane++) {
783
784 if (lt_settings->
785 lane_settings[lane].VOLTAGE_SWING !=
786 req_settings.lane_settings[lane].
787 VOLTAGE_SWING ||
788 lt_settings->lane_settings[lane].PRE_EMPHASIS !=
789 req_settings.lane_settings[lane].PRE_EMPHASIS) {
790
791 req_drv_setting_changed = true;
792 break;
793 }
794 }
795
796 if (req_drv_setting_changed) {
797 update_drive_settings(
9a6a8075 798 lt_settings, req_settings);
4562236b 799
d0778ebf 800 dc_link_dp_set_drive_settings(link,
4562236b
HW
801 lt_settings);
802 break;
803 }
804
805 msleep(1);
806 }
807
808 if (!req_drv_setting_changed) {
1296423b 809 DC_LOG_WARNING("%s: Post Link Training Adjust Request Timed out\n",
4562236b
HW
810 __func__);
811
812 ASSERT(0);
813 return true;
814 }
815 }
1296423b 816 DC_LOG_WARNING("%s: Post Link Training Adjust Request limit reached\n",
4562236b
HW
817 __func__);
818
819 ASSERT(0);
820 return true;
821
822}
823
64c12b73 824/* Only used for channel equalization */
825static uint32_t translate_training_aux_read_interval(uint32_t dpcd_aux_read_interval)
826{
827 unsigned int aux_rd_interval_us = 400;
828
829 switch (dpcd_aux_read_interval) {
830 case 0x01:
831 aux_rd_interval_us = 400;
832 break;
833 case 0x02:
834 aux_rd_interval_us = 4000;
835 break;
836 case 0x03:
837 aux_rd_interval_us = 8000;
838 break;
839 case 0x04:
840 aux_rd_interval_us = 16000;
841 break;
842 default:
843 break;
844 }
845
846 return aux_rd_interval_us;
847}
848
94405cf6
WL
849static enum link_training_result get_cr_failure(enum dc_lane_count ln_count,
850 union lane_status *dpcd_lane_status)
851{
852 enum link_training_result result = LINK_TRAINING_SUCCESS;
853
854 if (ln_count >= LANE_COUNT_ONE && !dpcd_lane_status[0].bits.CR_DONE_0)
855 result = LINK_TRAINING_CR_FAIL_LANE0;
856 else if (ln_count >= LANE_COUNT_TWO && !dpcd_lane_status[1].bits.CR_DONE_0)
857 result = LINK_TRAINING_CR_FAIL_LANE1;
858 else if (ln_count >= LANE_COUNT_FOUR && !dpcd_lane_status[2].bits.CR_DONE_0)
859 result = LINK_TRAINING_CR_FAIL_LANE23;
860 else if (ln_count >= LANE_COUNT_FOUR && !dpcd_lane_status[3].bits.CR_DONE_0)
861 result = LINK_TRAINING_CR_FAIL_LANE23;
862 return result;
863}
864
820e3935 865static enum link_training_result perform_channel_equalization_sequence(
d0778ebf 866 struct dc_link *link,
64c12b73 867 struct link_training_settings *lt_settings,
868 uint32_t offset)
4562236b
HW
869{
870 struct link_training_settings req_settings;
e0a6440a 871 enum dc_dp_training_pattern tr_pattern;
4562236b 872 uint32_t retries_ch_eq;
64c12b73 873 uint32_t wait_time_microsec;
4562236b 874 enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
9a6a8075
HW
875 union lane_align_status_updated dpcd_lane_status_updated = { {0} };
876 union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = { { {0} } };
4562236b 877
64c12b73 878 /* Note: also check that TPS4 is a supported feature*/
879
e0a6440a 880 tr_pattern = lt_settings->pattern_for_eq;
4562236b 881
64c12b73 882 if (is_repeater(link, offset))
883 tr_pattern = DP_TRAINING_PATTERN_SEQUENCE_4;
884
885 dp_set_hw_training_pattern(link, tr_pattern, offset);
4562236b
HW
886
887 for (retries_ch_eq = 0; retries_ch_eq <= LINK_TRAINING_MAX_RETRY_COUNT;
888 retries_ch_eq++) {
889
64c12b73 890 dp_set_hw_lane_settings(link, lt_settings, offset);
4562236b
HW
891
892 /* 2. update DPCD*/
893 if (!retries_ch_eq)
894 /* EPR #361076 - write as a 5-byte burst,
64c12b73 895 * but only for the 1-st iteration
896 */
897
4562236b
HW
898 dpcd_set_lt_pattern_and_lane_settings(
899 link,
900 lt_settings,
64c12b73 901 tr_pattern, offset);
4562236b 902 else
64c12b73 903 dpcd_set_lane_settings(link, lt_settings, offset);
4562236b
HW
904
905 /* 3. wait for receiver to lock-on*/
64c12b73 906 wait_time_microsec = lt_settings->eq_pattern_time;
907
5fd21b39 908 if (is_repeater(link, offset))
64c12b73 909 wait_time_microsec =
910 translate_training_aux_read_interval(
5fd21b39 911 link->dpcd_caps.lttpr_caps.aux_rd_interval[offset - 1]);
64c12b73 912
913 wait_for_training_aux_rd_interval(
914 link,
915 wait_time_microsec);
4562236b
HW
916
917 /* 4. Read lane status and requested
918 * drive settings as set by the sink*/
919
920 get_lane_status_and_drive_settings(
921 link,
922 lt_settings,
923 dpcd_lane_status,
924 &dpcd_lane_status_updated,
64c12b73 925 &req_settings,
926 offset);
4562236b
HW
927
928 /* 5. check CR done*/
929 if (!is_cr_done(lane_count, dpcd_lane_status))
820e3935 930 return LINK_TRAINING_EQ_FAIL_CR;
4562236b
HW
931
932 /* 6. check CHEQ done*/
933 if (is_ch_eq_done(lane_count,
934 dpcd_lane_status,
935 &dpcd_lane_status_updated))
820e3935 936 return LINK_TRAINING_SUCCESS;
4562236b
HW
937
938 /* 7. update VS/PE/PC2 in lt_settings*/
939 update_drive_settings(lt_settings, req_settings);
940 }
941
820e3935 942 return LINK_TRAINING_EQ_FAIL_EQ;
4562236b
HW
943
944}
64c12b73 945#define TRAINING_AUX_RD_INTERVAL 100 //us
4562236b 946
b01f22ec
DG
947static void start_clock_recovery_pattern_early(struct dc_link *link,
948 struct link_training_settings *lt_settings,
949 uint32_t offset)
950{
951 DC_LOG_HW_LINK_TRAINING("%s\n GPU sends TPS1. Wait 400us.\n",
952 __func__);
953 dp_set_hw_training_pattern(link, DP_TRAINING_PATTERN_SEQUENCE_1, offset);
954 dp_set_hw_lane_settings(link, lt_settings, offset);
955 udelay(400);
956}
957
94405cf6 958static enum link_training_result perform_clock_recovery_sequence(
d0778ebf 959 struct dc_link *link,
64c12b73 960 struct link_training_settings *lt_settings,
961 uint32_t offset)
4562236b
HW
962{
963 uint32_t retries_cr;
964 uint32_t retry_count;
64c12b73 965 uint32_t wait_time_microsec;
4562236b 966 struct link_training_settings req_settings;
e0a6440a
DG
967 enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
968 enum dc_dp_training_pattern tr_pattern = DP_TRAINING_PATTERN_SEQUENCE_1;
4562236b
HW
969 union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX];
970 union lane_align_status_updated dpcd_lane_status_updated;
971
972 retries_cr = 0;
973 retry_count = 0;
4562236b 974
82054678 975 if (!link->ctx->dc->work_arounds.lt_early_cr_pattern)
b01f22ec 976 dp_set_hw_training_pattern(link, tr_pattern, offset);
4562236b
HW
977
978 /* najeeb - The synaptics MST hub can put the LT in
979 * infinite loop by switching the VS
980 */
981 /* between level 0 and level 1 continuously, here
982 * we try for CR lock for LinkTrainingMaxCRRetry count*/
983 while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) &&
e0a6440a 984 (retry_count < LINK_TRAINING_MAX_CR_RETRY)) {
4562236b
HW
985
986 memset(&dpcd_lane_status, '\0', sizeof(dpcd_lane_status));
987 memset(&dpcd_lane_status_updated, '\0',
988 sizeof(dpcd_lane_status_updated));
989
990 /* 1. call HWSS to set lane settings*/
991 dp_set_hw_lane_settings(
992 link,
64c12b73 993 lt_settings,
994 offset);
4562236b
HW
995
996 /* 2. update DPCD of the receiver*/
50d2c602 997 if (!retry_count)
4562236b
HW
998 /* EPR #361076 - write as a 5-byte burst,
999 * but only for the 1-st iteration.*/
1000 dpcd_set_lt_pattern_and_lane_settings(
1001 link,
1002 lt_settings,
64c12b73 1003 tr_pattern,
1004 offset);
4562236b
HW
1005 else
1006 dpcd_set_lane_settings(
1007 link,
64c12b73 1008 lt_settings,
1009 offset);
4562236b
HW
1010
1011 /* 3. wait receiver to lock-on*/
64c12b73 1012 wait_time_microsec = lt_settings->cr_pattern_time;
1013
1014 if (!link->is_lttpr_mode_transparent)
1015 wait_time_microsec = TRAINING_AUX_RD_INTERVAL;
1016
4562236b
HW
1017 wait_for_training_aux_rd_interval(
1018 link,
64c12b73 1019 wait_time_microsec);
4562236b
HW
1020
1021 /* 4. Read lane status and requested drive
1022 * settings as set by the sink
1023 */
1024 get_lane_status_and_drive_settings(
1025 link,
1026 lt_settings,
1027 dpcd_lane_status,
1028 &dpcd_lane_status_updated,
64c12b73 1029 &req_settings,
1030 offset);
4562236b
HW
1031
1032 /* 5. check CR done*/
1033 if (is_cr_done(lane_count, dpcd_lane_status))
94405cf6 1034 return LINK_TRAINING_SUCCESS;
4562236b
HW
1035
1036 /* 6. max VS reached*/
1037 if (is_max_vs_reached(lt_settings))
94405cf6 1038 break;
4562236b
HW
1039
1040 /* 7. same voltage*/
1041 /* Note: VS same for all lanes,
1042 * so comparing first lane is sufficient*/
1043 if (lt_settings->lane_settings[0].VOLTAGE_SWING ==
1044 req_settings.lane_settings[0].VOLTAGE_SWING)
1045 retries_cr++;
1046 else
1047 retries_cr = 0;
1048
1049 /* 8. update VS/PE/PC2 in lt_settings*/
1050 update_drive_settings(lt_settings, req_settings);
1051
1052 retry_count++;
1053 }
1054
1055 if (retry_count >= LINK_TRAINING_MAX_CR_RETRY) {
1056 ASSERT(0);
1296423b 1057 DC_LOG_ERROR("%s: Link Training Error, could not get CR after %d tries. Possibly voltage swing issue",
4f42a2dd 1058 __func__,
4562236b
HW
1059 LINK_TRAINING_MAX_CR_RETRY);
1060
1061 }
1062
94405cf6 1063 return get_cr_failure(lane_count, dpcd_lane_status);
4562236b
HW
1064}
1065
94405cf6 1066static inline enum link_training_result perform_link_training_int(
d0778ebf 1067 struct dc_link *link,
4562236b 1068 struct link_training_settings *lt_settings,
94405cf6 1069 enum link_training_result status)
4562236b
HW
1070{
1071 union lane_count_set lane_count_set = { {0} };
1072 union dpcd_training_pattern dpcd_pattern = { {0} };
1073
1074 /* 3. set training not in progress*/
1075 dpcd_pattern.v1_4.TRAINING_PATTERN_SET = DPCD_TRAINING_PATTERN_VIDEOIDLE;
1076 dpcd_set_training_pattern(link, dpcd_pattern);
1077
1078 /* 4. mainlink output idle pattern*/
1079 dp_set_hw_test_pattern(link, DP_TEST_PATTERN_VIDEO_MODE, NULL, 0);
1080
1081 /*
1082 * 5. post training adjust if required
1083 * If the upstream DPTX and downstream DPRX both support TPS4,
1084 * TPS4 must be used instead of POST_LT_ADJ_REQ.
1085 */
c30267f5 1086 if (link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED != 1 ||
e0a6440a 1087 get_supported_tp(link) == DP_TRAINING_PATTERN_SEQUENCE_4)
4562236b
HW
1088 return status;
1089
94405cf6 1090 if (status == LINK_TRAINING_SUCCESS &&
4562236b 1091 perform_post_lt_adj_req_sequence(link, lt_settings) == false)
94405cf6 1092 status = LINK_TRAINING_LQA_FAIL;
4562236b
HW
1093
1094 lane_count_set.bits.LANE_COUNT_SET = lt_settings->link_settings.lane_count;
e0a6440a 1095 lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing;
4562236b
HW
1096 lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0;
1097
1098 core_link_write_dpcd(
1099 link,
3a340294 1100 DP_LANE_COUNT_SET,
4562236b
HW
1101 &lane_count_set.raw,
1102 sizeof(lane_count_set));
1103
1104 return status;
1105}
1106
e0a6440a
DG
1107static void initialize_training_settings(
1108 struct dc_link *link,
4562236b 1109 const struct dc_link_settings *link_setting,
0b226322 1110 const struct dc_link_training_overrides *overrides,
e0a6440a 1111 struct link_training_settings *lt_settings)
4562236b 1112{
e0a6440a 1113 uint32_t lane;
4562236b 1114
e0a6440a 1115 memset(lt_settings, '\0', sizeof(struct link_training_settings));
94405cf6 1116
e0a6440a
DG
1117 /* Initialize link settings */
1118 lt_settings->link_settings.use_link_rate_set = link_setting->use_link_rate_set;
1119 lt_settings->link_settings.link_rate_set = link_setting->link_rate_set;
4562236b 1120
e0a6440a
DG
1121 if (link->preferred_link_setting.link_rate != LINK_RATE_UNKNOWN)
1122 lt_settings->link_settings.link_rate = link->preferred_link_setting.link_rate;
1123 else
1124 lt_settings->link_settings.link_rate = link_setting->link_rate;
4562236b 1125
e0a6440a
DG
1126 if (link->preferred_link_setting.lane_count != LANE_COUNT_UNKNOWN)
1127 lt_settings->link_settings.lane_count = link->preferred_link_setting.lane_count;
1128 else
1129 lt_settings->link_settings.lane_count = link_setting->lane_count;
4562236b
HW
1130
1131 /*@todo[vdevulap] move SS to LS, should not be handled by displaypath*/
1132
1133 /* TODO hard coded to SS for now
1134 * lt_settings.link_settings.link_spread =
1135 * dal_display_path_is_ss_supported(
1136 * path_mode->display_path) ?
1137 * LINK_SPREAD_05_DOWNSPREAD_30KHZ :
1138 * LINK_SPREAD_DISABLED;
1139 */
e0a6440a 1140 /* Initialize link spread */
ad830e7a 1141 if (link->dp_ss_off)
e0a6440a 1142 lt_settings->link_settings.link_spread = LINK_SPREAD_DISABLED;
0b226322 1143 else if (overrides->downspread != NULL)
e0a6440a 1144 lt_settings->link_settings.link_spread
0b226322 1145 = *overrides->downspread
e0a6440a
DG
1146 ? LINK_SPREAD_05_DOWNSPREAD_30KHZ
1147 : LINK_SPREAD_DISABLED;
ad830e7a 1148 else
e0a6440a 1149 lt_settings->link_settings.link_spread = LINK_SPREAD_05_DOWNSPREAD_30KHZ;
4562236b 1150
e0a6440a 1151 /* Initialize lane settings overrides */
0b226322
DG
1152 if (overrides->voltage_swing != NULL)
1153 lt_settings->voltage_swing = overrides->voltage_swing;
4562236b 1154
0b226322
DG
1155 if (overrides->pre_emphasis != NULL)
1156 lt_settings->pre_emphasis = overrides->pre_emphasis;
4562236b 1157
0b226322
DG
1158 if (overrides->post_cursor2 != NULL)
1159 lt_settings->post_cursor2 = overrides->post_cursor2;
e0a6440a
DG
1160
1161 /* Initialize lane settings (VS/PE/PC2) */
1162 for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
1163 lt_settings->lane_settings[lane].VOLTAGE_SWING =
1164 lt_settings->voltage_swing != NULL ?
1165 *lt_settings->voltage_swing :
1166 VOLTAGE_SWING_LEVEL0;
1167 lt_settings->lane_settings[lane].PRE_EMPHASIS =
1168 lt_settings->pre_emphasis != NULL ?
1169 *lt_settings->pre_emphasis
1170 : PRE_EMPHASIS_DISABLED;
1171 lt_settings->lane_settings[lane].POST_CURSOR2 =
1172 lt_settings->post_cursor2 != NULL ?
1173 *lt_settings->post_cursor2
1174 : POST_CURSOR2_DISABLED;
820e3935 1175 }
4562236b 1176
e0a6440a 1177 /* Initialize training timings */
0b226322
DG
1178 if (overrides->cr_pattern_time != NULL)
1179 lt_settings->cr_pattern_time = *overrides->cr_pattern_time;
e0a6440a 1180 else
0b226322 1181 lt_settings->cr_pattern_time = get_training_aux_rd_interval(link, 100);
e0a6440a 1182
0b226322
DG
1183 if (overrides->eq_pattern_time != NULL)
1184 lt_settings->eq_pattern_time = *overrides->eq_pattern_time;
e0a6440a
DG
1185 else
1186 lt_settings->eq_pattern_time = get_training_aux_rd_interval(link, 400);
1187
0b226322
DG
1188 if (overrides->pattern_for_eq != NULL)
1189 lt_settings->pattern_for_eq = *overrides->pattern_for_eq;
e0a6440a
DG
1190 else
1191 lt_settings->pattern_for_eq = get_supported_tp(link);
1192
0b226322
DG
1193 if (overrides->enhanced_framing != NULL)
1194 lt_settings->enhanced_framing = *overrides->enhanced_framing;
e0a6440a
DG
1195 else
1196 lt_settings->enhanced_framing = 1;
1197}
1198
64c12b73 1199static uint8_t convert_to_count(uint8_t lttpr_repeater_count)
1200{
1201 switch (lttpr_repeater_count) {
1202 case 0x80: // 1 lttpr repeater
1203 return 1;
1204 case 0x40: // 2 lttpr repeaters
1205 return 2;
1206 case 0x20: // 3 lttpr repeaters
1207 return 3;
1208 case 0x10: // 4 lttpr repeaters
1209 return 4;
1210 case 0x08: // 5 lttpr repeaters
1211 return 5;
1212 case 0x04: // 6 lttpr repeaters
1213 return 6;
1214 case 0x02: // 7 lttpr repeaters
1215 return 7;
1216 case 0x01: // 8 lttpr repeaters
1217 return 8;
1218 default:
1219 break;
1220 }
1221 return 0; // invalid value
1222}
1223
bad7ab0b 1224static void configure_lttpr_mode(struct dc_link *link)
1225{
1226 /* aux timeout is already set to extended */
1227 /* RESET/SET lttpr mode to enable non transparent mode */
64c12b73 1228 uint8_t repeater_cnt;
1229 uint32_t aux_interval_address;
1230 uint8_t repeater_id;
a166f86e 1231 enum dc_status result = DC_ERROR_UNEXPECTED;
61aa7a6f 1232 uint8_t repeater_mode = DP_PHY_REPEATER_MODE_TRANSPARENT;
bad7ab0b 1233
c14f2507 1234 DC_LOG_HW_LINK_TRAINING("%s\n Set LTTPR to Transparent Mode\n", __func__);
a166f86e 1235 result = core_link_write_dpcd(link,
bad7ab0b 1236 DP_PHY_REPEATER_MODE,
1237 (uint8_t *)&repeater_mode,
1238 sizeof(repeater_mode));
1239
a166f86e 1240 if (result == DC_OK) {
1241 link->dpcd_caps.lttpr_caps.mode = repeater_mode;
1242 }
1243
bad7ab0b 1244 if (!link->is_lttpr_mode_transparent) {
460adc6b 1245
c14f2507 1246 DC_LOG_HW_LINK_TRAINING("%s\n Set LTTPR to Non Transparent Mode\n", __func__);
460adc6b 1247
61aa7a6f 1248 repeater_mode = DP_PHY_REPEATER_MODE_NON_TRANSPARENT;
a166f86e 1249 result = core_link_write_dpcd(link,
bad7ab0b 1250 DP_PHY_REPEATER_MODE,
1251 (uint8_t *)&repeater_mode,
1252 sizeof(repeater_mode));
64c12b73 1253
a166f86e 1254 if (result == DC_OK) {
1255 link->dpcd_caps.lttpr_caps.mode = repeater_mode;
1256 }
1257
64c12b73 1258 repeater_cnt = convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
1259 for (repeater_id = repeater_cnt; repeater_id > 0; repeater_id--) {
1260 aux_interval_address = DP_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER1 +
1261 ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (repeater_id - 1));
1262 core_link_read_dpcd(
1263 link,
1264 aux_interval_address,
1265 (uint8_t *)&link->dpcd_caps.lttpr_caps.aux_rd_interval[repeater_id - 1],
1266 sizeof(link->dpcd_caps.lttpr_caps.aux_rd_interval[repeater_id - 1]));
1267 link->dpcd_caps.lttpr_caps.aux_rd_interval[repeater_id - 1] &= 0x7F;
1268 }
bad7ab0b 1269 }
1270}
1271
64c12b73 1272static void repeater_training_done(struct dc_link *link, uint32_t offset)
1273{
1274 union dpcd_training_pattern dpcd_pattern = { {0} };
1275
1276 const uint32_t dpcd_base_lt_offset =
1277 DP_TRAINING_PATTERN_SET_PHY_REPEATER1 +
1278 ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
1279 /* Set training not in progress*/
1280 dpcd_pattern.v1_4.TRAINING_PATTERN_SET = DPCD_TRAINING_PATTERN_VIDEOIDLE;
1281
1282 core_link_write_dpcd(
1283 link,
1284 dpcd_base_lt_offset,
1285 &dpcd_pattern.raw,
1286 1);
1287
460adc6b 1288 DC_LOG_HW_LINK_TRAINING("%s\n LTTPR Id: %d 0x%X pattern = %x\n",
64c12b73 1289 __func__,
460adc6b 1290 offset,
64c12b73 1291 dpcd_base_lt_offset,
1292 dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
1293}
1294
e0a6440a
DG
1295static void print_status_message(
1296 struct dc_link *link,
1297 const struct link_training_settings *lt_settings,
1298 enum link_training_result status)
1299{
1300 char *link_rate = "Unknown";
1301 char *lt_result = "Unknown";
1302 char *lt_spread = "Disabled";
4562236b 1303
e0a6440a 1304 switch (lt_settings->link_settings.link_rate) {
4562236b
HW
1305 case LINK_RATE_LOW:
1306 link_rate = "RBR";
1307 break;
1308 case LINK_RATE_HIGH:
1309 link_rate = "HBR";
1310 break;
1311 case LINK_RATE_HIGH2:
1312 link_rate = "HBR2";
1313 break;
1314 case LINK_RATE_RBR2:
1315 link_rate = "RBR2";
1316 break;
1317 case LINK_RATE_HIGH3:
1318 link_rate = "HBR3";
1319 break;
1320 default:
1321 break;
1322 }
1323
94405cf6
WL
1324 switch (status) {
1325 case LINK_TRAINING_SUCCESS:
1326 lt_result = "pass";
1327 break;
1328 case LINK_TRAINING_CR_FAIL_LANE0:
1329 lt_result = "CR failed lane0";
1330 break;
1331 case LINK_TRAINING_CR_FAIL_LANE1:
1332 lt_result = "CR failed lane1";
1333 break;
1334 case LINK_TRAINING_CR_FAIL_LANE23:
1335 lt_result = "CR failed lane23";
1336 break;
1337 case LINK_TRAINING_EQ_FAIL_CR:
1338 lt_result = "CR failed in EQ";
1339 break;
1340 case LINK_TRAINING_EQ_FAIL_EQ:
1341 lt_result = "EQ failed";
1342 break;
1343 case LINK_TRAINING_LQA_FAIL:
1344 lt_result = "LQA failed";
1345 break;
1346 default:
1347 break;
1348 }
1349
e0a6440a
DG
1350 switch (lt_settings->link_settings.link_spread) {
1351 case LINK_SPREAD_DISABLED:
1352 lt_spread = "Disabled";
1353 break;
1354 case LINK_SPREAD_05_DOWNSPREAD_30KHZ:
1355 lt_spread = "0.5% 30KHz";
1356 break;
1357 case LINK_SPREAD_05_DOWNSPREAD_33KHZ:
1358 lt_spread = "0.5% 33KHz";
1359 break;
1360 default:
1361 break;
1362 }
1363
4562236b 1364 /* Connectivity log: link training */
e0a6440a
DG
1365 CONN_MSG_LT(link, "%sx%d %s VS=%d, PE=%d, DS=%s",
1366 link_rate,
1367 lt_settings->link_settings.lane_count,
1368 lt_result,
1369 lt_settings->lane_settings[0].VOLTAGE_SWING,
1370 lt_settings->lane_settings[0].PRE_EMPHASIS,
1371 lt_spread);
1372}
1373
64c12b73 1374void dc_link_dp_set_drive_settings(
1375 struct dc_link *link,
1376 struct link_training_settings *lt_settings)
1377{
1378 /* program ASIC PHY settings*/
1379 dp_set_hw_lane_settings(link, lt_settings, DPRX);
1380
1381 /* Notify DP sink the PHY settings from source */
1382 dpcd_set_lane_settings(link, lt_settings, DPRX);
1383}
1384
e0a6440a
DG
1385bool dc_link_dp_perform_link_training_skip_aux(
1386 struct dc_link *link,
1387 const struct dc_link_settings *link_setting)
1388{
1389 struct link_training_settings lt_settings;
1390 enum dc_dp_training_pattern pattern_for_cr = DP_TRAINING_PATTERN_SEQUENCE_1;
1391
0b226322
DG
1392 initialize_training_settings(
1393 link,
1394 link_setting,
1395 &link->preferred_training_settings,
1396 &lt_settings);
e0a6440a
DG
1397
1398 /* 1. Perform_clock_recovery_sequence. */
1399
1400 /* transmit training pattern for clock recovery */
64c12b73 1401 dp_set_hw_training_pattern(link, pattern_for_cr, DPRX);
e0a6440a
DG
1402
1403 /* call HWSS to set lane settings*/
64c12b73 1404 dp_set_hw_lane_settings(link, &lt_settings, DPRX);
e0a6440a
DG
1405
1406 /* wait receiver to lock-on*/
1407 wait_for_training_aux_rd_interval(link, lt_settings.cr_pattern_time);
1408
1409 /* 2. Perform_channel_equalization_sequence. */
1410
1411 /* transmit training pattern for channel equalization. */
64c12b73 1412 dp_set_hw_training_pattern(link, lt_settings.pattern_for_eq, DPRX);
e0a6440a
DG
1413
1414 /* call HWSS to set lane settings*/
64c12b73 1415 dp_set_hw_lane_settings(link, &lt_settings, DPRX);
e0a6440a
DG
1416
1417 /* wait receiver to lock-on. */
1418 wait_for_training_aux_rd_interval(link, lt_settings.eq_pattern_time);
1419
1420 /* 3. Perform_link_training_int. */
1421
1422 /* Mainlink output idle pattern. */
1423 dp_set_hw_test_pattern(link, DP_TEST_PATTERN_VIDEO_MODE, NULL, 0);
1424
1425 print_status_message(link, &lt_settings, LINK_TRAINING_SUCCESS);
1426
1427 return true;
1428}
1429
1430enum link_training_result dc_link_dp_perform_link_training(
1431 struct dc_link *link,
1432 const struct dc_link_settings *link_setting,
1433 bool skip_video_pattern)
1434{
1435 enum link_training_result status = LINK_TRAINING_SUCCESS;
e0a6440a 1436 struct link_training_settings lt_settings;
64c12b73 1437
008a4016 1438 bool fec_enable;
64c12b73 1439 uint8_t repeater_cnt;
1440 uint8_t repeater_id;
e0a6440a 1441
0b226322
DG
1442 initialize_training_settings(
1443 link,
1444 link_setting,
1445 &link->preferred_training_settings,
1446 &lt_settings);
e0a6440a 1447
bcc5042a 1448 /* Configure lttpr mode */
1449 if (!link->is_lttpr_mode_transparent)
1450 configure_lttpr_mode(link);
1451
82054678
ML
1452 if (link->ctx->dc->work_arounds.lt_early_cr_pattern)
1453 start_clock_recovery_pattern_early(link, &lt_settings, DPRX);
834a9a9f
ML
1454
1455 /* 1. set link rate, lane count and spread. */
1456 dpcd_set_link_settings(link, &lt_settings);
e0a6440a 1457
008a4016
NC
1458 if (link->preferred_training_settings.fec_enable != NULL)
1459 fec_enable = *link->preferred_training_settings.fec_enable;
1460 else
1461 fec_enable = true;
1462
1463 dp_set_fec_ready(link, fec_enable);
008a4016 1464
64c12b73 1465 if (!link->is_lttpr_mode_transparent) {
008a4016 1466
64c12b73 1467 /* 2. perform link training (set link training done
1468 * to false is done as well)
1469 */
1470 repeater_cnt = convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
1471
1472 for (repeater_id = repeater_cnt; (repeater_id > 0 && status == LINK_TRAINING_SUCCESS);
1473 repeater_id--) {
1474 status = perform_clock_recovery_sequence(link, &lt_settings, repeater_id);
1475
1476 if (status != LINK_TRAINING_SUCCESS)
1477 break;
1478
1479 status = perform_channel_equalization_sequence(link,
1480 &lt_settings,
1481 repeater_id);
1482
1483 if (status != LINK_TRAINING_SUCCESS)
1484 break;
1485
1486 repeater_training_done(link, repeater_id);
1487 }
1488 }
1489
1490 if (status == LINK_TRAINING_SUCCESS) {
1491 status = perform_clock_recovery_sequence(link, &lt_settings, DPRX);
e0a6440a
DG
1492 if (status == LINK_TRAINING_SUCCESS) {
1493 status = perform_channel_equalization_sequence(link,
64c12b73 1494 &lt_settings,
1495 DPRX);
1496 }
e0a6440a
DG
1497 }
1498
1499 if ((status == LINK_TRAINING_SUCCESS) || !skip_video_pattern) {
1500 status = perform_link_training_int(link,
1501 &lt_settings,
1502 status);
1503 }
1504
1505 /* 6. print status message*/
1506 print_status_message(link, &lt_settings, status);
4562236b 1507
d6e75df4 1508 if (status != LINK_TRAINING_SUCCESS)
cfd84fd3 1509 link->ctx->dc->debug_data.ltFailCount++;
d6e75df4 1510
4562236b
HW
1511 return status;
1512}
1513
4562236b 1514bool perform_link_training_with_retries(
4562236b
HW
1515 const struct dc_link_settings *link_setting,
1516 bool skip_video_pattern,
832aa63b
PH
1517 int attempts,
1518 struct pipe_ctx *pipe_ctx,
1519 enum signal_type signal)
4562236b
HW
1520{
1521 uint8_t j;
1522 uint8_t delay_between_attempts = LINK_TRAINING_RETRY_DELAY;
832aa63b
PH
1523 struct dc_stream_state *stream = pipe_ctx->stream;
1524 struct dc_link *link = stream->link;
1525 enum dp_panel_mode panel_mode = dp_get_panel_mode(link);
4562236b
HW
1526
1527 for (j = 0; j < attempts; ++j) {
1528
832aa63b
PH
1529 dp_enable_link_phy(
1530 link,
1531 signal,
1532 pipe_ctx->clock_source->id,
1533 link_setting);
1534
1535 if (stream->sink_patches.dppowerup_delay > 0) {
1536 int delay_dp_power_up_in_ms = stream->sink_patches.dppowerup_delay;
1537
1538 msleep(delay_dp_power_up_in_ms);
1539 }
1540
1541 dp_set_panel_mode(link, panel_mode);
1542
1543 /* We need to do this before the link training to ensure the idle pattern in SST
1544 * mode will be sent right after the link training
1545 */
1546 link->link_enc->funcs->connect_dig_be_to_fe(link->link_enc,
1547 pipe_ctx->stream_res.stream_enc->id, true);
1548
1549 if (link->aux_access_disabled) {
1550 dc_link_dp_perform_link_training_skip_aux(link, link_setting);
1551 return true;
1552 } else if (dc_link_dp_perform_link_training(
d0778ebf 1553 link,
4562236b 1554 link_setting,
820e3935 1555 skip_video_pattern) == LINK_TRAINING_SUCCESS)
4562236b
HW
1556 return true;
1557
832aa63b
PH
1558 /* latest link training still fail, skip delay and keep PHY on
1559 */
1560 if (j == (attempts - 1))
1561 break;
1562
1563 dp_disable_link_phy(link, signal);
1564
4562236b 1565 msleep(delay_between_attempts);
832aa63b 1566
4562236b
HW
1567 delay_between_attempts += LINK_TRAINING_RETRY_DELAY;
1568 }
1569
1570 return false;
1571}
1572
0b226322
DG
1573static enum clock_source_id get_clock_source_id(struct dc_link *link)
1574{
1575 enum clock_source_id dp_cs_id = CLOCK_SOURCE_ID_UNDEFINED;
1576 struct clock_source *dp_cs = link->dc->res_pool->dp_clock_source;
1577
1578 if (dp_cs != NULL) {
1579 dp_cs_id = dp_cs->id;
1580 } else {
1581 /*
1582 * dp clock source is not initialized for some reason.
1583 * Should not happen, CLOCK_SOURCE_ID_EXTERNAL will be used
1584 */
1585 ASSERT(dp_cs);
1586 }
1587
1588 return dp_cs_id;
1589}
1590
1591static void set_dp_mst_mode(struct dc_link *link, bool mst_enable)
1592{
1593 if (mst_enable == false &&
1594 link->type == dc_connection_mst_branch) {
1595 /* Disable MST on link. Use only local sink. */
1596 dp_disable_link_phy_mst(link, link->connector_signal);
1597
1598 link->type = dc_connection_single;
1599 link->local_sink = link->remote_sinks[0];
1600 link->local_sink->sink_signal = SIGNAL_TYPE_DISPLAY_PORT;
1601 } else if (mst_enable == true &&
1602 link->type == dc_connection_single &&
1603 link->remote_sinks[0] != NULL) {
1604 /* Re-enable MST on link. */
1605 dp_disable_link_phy(link, link->connector_signal);
1606 dp_enable_mst_on_sink(link, true);
1607
1608 link->type = dc_connection_mst_branch;
1609 link->local_sink->sink_signal = SIGNAL_TYPE_DISPLAY_PORT_MST;
1610 }
1611}
1612
1613bool dc_link_dp_sync_lt_begin(struct dc_link *link)
1614{
1615 /* Begin Sync LT. During this time,
1616 * DPCD:600h must not be powered down.
1617 */
1618 link->sync_lt_in_progress = true;
1619
1620 /*Clear any existing preferred settings.*/
1621 memset(&link->preferred_training_settings, 0,
1622 sizeof(struct dc_link_training_overrides));
1623 memset(&link->preferred_link_setting, 0,
1624 sizeof(struct dc_link_settings));
1625
1626 return true;
1627}
1628
1629enum link_training_result dc_link_dp_sync_lt_attempt(
1630 struct dc_link *link,
1631 struct dc_link_settings *link_settings,
1632 struct dc_link_training_overrides *lt_overrides)
1633{
1634 struct link_training_settings lt_settings;
1635 enum link_training_result lt_status = LINK_TRAINING_SUCCESS;
1636 enum dp_panel_mode panel_mode = DP_PANEL_MODE_DEFAULT;
1637 enum clock_source_id dp_cs_id = CLOCK_SOURCE_ID_EXTERNAL;
0b226322 1638 bool fec_enable = false;
0b226322
DG
1639
1640 initialize_training_settings(
1641 link,
1642 link_settings,
1643 lt_overrides,
1644 &lt_settings);
1645
1646 /* Setup MST Mode */
1647 if (lt_overrides->mst_enable)
1648 set_dp_mst_mode(link, *lt_overrides->mst_enable);
1649
1650 /* Disable link */
1651 dp_disable_link_phy(link, link->connector_signal);
1652
1653 /* Enable link */
1654 dp_cs_id = get_clock_source_id(link);
1655 dp_enable_link_phy(link, link->connector_signal,
1656 dp_cs_id, link_settings);
1657
0b226322
DG
1658 /* Set FEC enable */
1659 fec_enable = lt_overrides->fec_enable && *lt_overrides->fec_enable;
1660 dp_set_fec_ready(link, fec_enable);
0b226322
DG
1661
1662 if (lt_overrides->alternate_scrambler_reset) {
1663 if (*lt_overrides->alternate_scrambler_reset)
1664 panel_mode = DP_PANEL_MODE_EDP;
1665 else
1666 panel_mode = DP_PANEL_MODE_DEFAULT;
1667 } else
1668 panel_mode = dp_get_panel_mode(link);
1669
1670 dp_set_panel_mode(link, panel_mode);
1671
1672 /* Attempt to train with given link training settings */
82054678
ML
1673 if (link->ctx->dc->work_arounds.lt_early_cr_pattern)
1674 start_clock_recovery_pattern_early(link, &lt_settings, DPRX);
834a9a9f
ML
1675
1676 /* Set link rate, lane count and spread. */
1677 dpcd_set_link_settings(link, &lt_settings);
0b226322
DG
1678
1679 /* 2. perform link training (set link training done
1680 * to false is done as well)
1681 */
64c12b73 1682 lt_status = perform_clock_recovery_sequence(link, &lt_settings, DPRX);
0b226322
DG
1683 if (lt_status == LINK_TRAINING_SUCCESS) {
1684 lt_status = perform_channel_equalization_sequence(link,
64c12b73 1685 &lt_settings,
1686 DPRX);
0b226322
DG
1687 }
1688
1689 /* 3. Sync LT must skip TRAINING_PATTERN_SET:0 (video pattern)*/
1690 /* 4. print status message*/
1691 print_status_message(link, &lt_settings, lt_status);
1692
1693 return lt_status;
1694}
1695
1696bool dc_link_dp_sync_lt_end(struct dc_link *link, bool link_down)
1697{
1698 /* If input parameter is set, shut down phy.
1699 * Still shouldn't turn off dp_receiver (DPCD:600h)
1700 */
1701 if (link_down == true) {
1702 dp_disable_link_phy(link, link->connector_signal);
0b226322 1703 dp_set_fec_ready(link, false);
0b226322
DG
1704 }
1705
1706 link->sync_lt_in_progress = false;
1707 return true;
1708}
1709
d0778ebf 1710static struct dc_link_settings get_max_link_cap(struct dc_link *link)
4562236b 1711{
8ccf0e20 1712 struct dc_link_settings max_link_cap = {0};
4562236b 1713
8ccf0e20
WL
1714 /* get max link encoder capability */
1715 link->link_enc->funcs->get_max_link_cap(link->link_enc, &max_link_cap);
f537d474 1716
4562236b 1717 /* Lower link settings based on sink's link cap */
d0778ebf 1718 if (link->reported_link_cap.lane_count < max_link_cap.lane_count)
4562236b 1719 max_link_cap.lane_count =
d0778ebf
HW
1720 link->reported_link_cap.lane_count;
1721 if (link->reported_link_cap.link_rate < max_link_cap.link_rate)
4562236b 1722 max_link_cap.link_rate =
d0778ebf
HW
1723 link->reported_link_cap.link_rate;
1724 if (link->reported_link_cap.link_spread <
4562236b
HW
1725 max_link_cap.link_spread)
1726 max_link_cap.link_spread =
d0778ebf 1727 link->reported_link_cap.link_spread;
bad7ab0b 1728 /*
1729 * account for lttpr repeaters cap
1730 * notes: repeaters do not snoop in the DPRX Capabilities addresses (3.6.3).
1731 */
1732 if (!link->is_lttpr_mode_transparent) {
1733 if (link->dpcd_caps.lttpr_caps.max_lane_count < max_link_cap.lane_count)
1734 max_link_cap.lane_count = link->dpcd_caps.lttpr_caps.max_lane_count;
1735
1736 if (link->dpcd_caps.lttpr_caps.max_link_rate < max_link_cap.link_rate)
1737 max_link_cap.link_rate = link->dpcd_caps.lttpr_caps.max_link_rate;
460adc6b 1738
1739 DC_LOG_HW_LINK_TRAINING("%s\n Training with LTTPR, max_lane count %d max_link rate %d \n",
1740 __func__,
1741 max_link_cap.lane_count,
1742 max_link_cap.link_rate);
bad7ab0b 1743 }
4562236b
HW
1744 return max_link_cap;
1745}
1746
1ae62f31
WL
1747static enum dc_status read_hpd_rx_irq_data(
1748 struct dc_link *link,
1749 union hpd_irq_data *irq_data)
1750{
1751 static enum dc_status retval;
1752
1753 /* The HW reads 16 bytes from 200h on HPD,
1754 * but if we get an AUX_DEFER, the HW cannot retry
1755 * and this causes the CTS tests 4.3.2.1 - 3.2.4 to
1756 * fail, so we now explicitly read 6 bytes which is
1757 * the req from the above mentioned test cases.
1758 *
1759 * For DP 1.4 we need to read those from 2002h range.
1760 */
1761 if (link->dpcd_caps.dpcd_rev.raw < DPCD_REV_14)
1762 retval = core_link_read_dpcd(
1763 link,
1764 DP_SINK_COUNT,
1765 irq_data->raw,
1766 sizeof(union hpd_irq_data));
1767 else {
1768 /* Read 14 bytes in a single read and then copy only the required fields.
1769 * This is more efficient than doing it in two separate AUX reads. */
1770
1771 uint8_t tmp[DP_SINK_STATUS_ESI - DP_SINK_COUNT_ESI + 1];
1772
1773 retval = core_link_read_dpcd(
1774 link,
1775 DP_SINK_COUNT_ESI,
1776 tmp,
1777 sizeof(tmp));
1778
1779 if (retval != DC_OK)
1780 return retval;
1781
1782 irq_data->bytes.sink_cnt.raw = tmp[DP_SINK_COUNT_ESI - DP_SINK_COUNT_ESI];
1783 irq_data->bytes.device_service_irq.raw = tmp[DP_DEVICE_SERVICE_IRQ_VECTOR_ESI0 - DP_SINK_COUNT_ESI];
1784 irq_data->bytes.lane01_status.raw = tmp[DP_LANE0_1_STATUS_ESI - DP_SINK_COUNT_ESI];
1785 irq_data->bytes.lane23_status.raw = tmp[DP_LANE2_3_STATUS_ESI - DP_SINK_COUNT_ESI];
1786 irq_data->bytes.lane_status_updated.raw = tmp[DP_LANE_ALIGN_STATUS_UPDATED_ESI - DP_SINK_COUNT_ESI];
1787 irq_data->bytes.sink_status.raw = tmp[DP_SINK_STATUS_ESI - DP_SINK_COUNT_ESI];
1788 }
1789
1790 return retval;
1791}
1792
1793static bool hpd_rx_irq_check_link_loss_status(
1794 struct dc_link *link,
1795 union hpd_irq_data *hpd_irq_dpcd_data)
1796{
1797 uint8_t irq_reg_rx_power_state = 0;
1798 enum dc_status dpcd_result = DC_ERROR_UNEXPECTED;
1799 union lane_status lane_status;
1800 uint32_t lane;
1801 bool sink_status_changed;
1802 bool return_code;
1803
1804 sink_status_changed = false;
1805 return_code = false;
1806
1807 if (link->cur_link_settings.lane_count == 0)
1808 return return_code;
1809
1810 /*1. Check that Link Status changed, before re-training.*/
1811
1812 /*parse lane status*/
1813 for (lane = 0; lane < link->cur_link_settings.lane_count; lane++) {
1814 /* check status of lanes 0,1
1815 * changed DpcdAddress_Lane01Status (0x202)
1816 */
1817 lane_status.raw = get_nibble_at_index(
1818 &hpd_irq_dpcd_data->bytes.lane01_status.raw,
1819 lane);
1820
1821 if (!lane_status.bits.CHANNEL_EQ_DONE_0 ||
1822 !lane_status.bits.CR_DONE_0 ||
1823 !lane_status.bits.SYMBOL_LOCKED_0) {
1824 /* if one of the channel equalization, clock
1825 * recovery or symbol lock is dropped
1826 * consider it as (link has been
1827 * dropped) dp sink status has changed
1828 */
1829 sink_status_changed = true;
1830 break;
1831 }
1832 }
1833
1834 /* Check interlane align.*/
1835 if (sink_status_changed ||
1836 !hpd_irq_dpcd_data->bytes.lane_status_updated.bits.INTERLANE_ALIGN_DONE) {
1837
1838 DC_LOG_HW_HPD_IRQ("%s: Link Status changed.\n", __func__);
1839
1840 return_code = true;
1841
1842 /*2. Check that we can handle interrupt: Not in FS DOS,
1843 * Not in "Display Timeout" state, Link is trained.
1844 */
1845 dpcd_result = core_link_read_dpcd(link,
1846 DP_SET_POWER,
1847 &irq_reg_rx_power_state,
1848 sizeof(irq_reg_rx_power_state));
1849
1850 if (dpcd_result != DC_OK) {
1851 DC_LOG_HW_HPD_IRQ("%s: DPCD read failed to obtain power state.\n",
1852 __func__);
1853 } else {
1854 if (irq_reg_rx_power_state != DP_SET_POWER_D0)
1855 return_code = false;
1856 }
1857 }
1858
1859 return return_code;
1860}
1861
aafded88 1862bool dp_verify_link_cap(
d0778ebf 1863 struct dc_link *link,
824474ba
BL
1864 struct dc_link_settings *known_limit_link_setting,
1865 int *fail_count)
4562236b
HW
1866{
1867 struct dc_link_settings max_link_cap = {0};
820e3935
DW
1868 struct dc_link_settings cur_link_setting = {0};
1869 struct dc_link_settings *cur = &cur_link_setting;
1870 struct dc_link_settings initial_link_settings = {0};
4562236b
HW
1871 bool success;
1872 bool skip_link_training;
4562236b 1873 bool skip_video_pattern;
4562236b 1874 enum clock_source_id dp_cs_id = CLOCK_SOURCE_ID_EXTERNAL;
820e3935 1875 enum link_training_result status;
1ae62f31 1876 union hpd_irq_data irq_data;
4562236b 1877
aafded88
TC
1878 if (link->dc->debug.skip_detection_link_training) {
1879 link->verified_link_cap = *known_limit_link_setting;
1880 return true;
1881 }
1882
1ae62f31 1883 memset(&irq_data, 0, sizeof(irq_data));
4562236b
HW
1884 success = false;
1885 skip_link_training = false;
1886
1887 max_link_cap = get_max_link_cap(link);
1888
bad7ab0b 1889 /* Grant extended timeout request */
1890 if (!link->is_lttpr_mode_transparent && link->dpcd_caps.lttpr_caps.max_ext_timeout > 0) {
1891 uint8_t grant = link->dpcd_caps.lttpr_caps.max_ext_timeout & 0x80;
1892
1893 core_link_write_dpcd(link, DP_PHY_REPEATER_EXTENDED_WAIT_TIMEOUT, &grant, sizeof(grant));
1894 }
1895
4562236b
HW
1896 /* TODO implement override and monitor patch later */
1897
1898 /* try to train the link from high to low to
1899 * find the physical link capability
1900 */
1901 /* disable PHY done possible by BIOS, will be done by driver itself */
d0778ebf 1902 dp_disable_link_phy(link, link->connector_signal);
4562236b 1903
b3282738
GS
1904 dp_cs_id = get_clock_source_id(link);
1905
1906 /* link training starts with the maximum common settings
1907 * supported by both sink and ASIC.
1908 */
1909 initial_link_settings = get_common_supported_link_settings(
1910 *known_limit_link_setting,
1911 max_link_cap);
1912 cur_link_setting = initial_link_settings;
1913
ee765924
GS
1914 /* Temporary Renoir-specific workaround for SWDEV-215184;
1915 * PHY will sometimes be in bad state on hotplugging display from certain USB-C dongle,
1916 * so add extra cycle of enabling and disabling the PHY before first link training.
1917 */
1918 if (link->link_enc->features.flags.bits.DP_IS_USB_C &&
1919 link->dc->debug.usbc_combo_phy_reset_wa) {
1920 dp_enable_link_phy(link, link->connector_signal, dp_cs_id, cur);
1921 dp_disable_link_phy(link, link->connector_signal);
1922 }
1923
820e3935 1924 do {
4562236b 1925 skip_video_pattern = true;
820e3935 1926
4562236b
HW
1927 if (cur->link_rate == LINK_RATE_LOW)
1928 skip_video_pattern = false;
1929
1930 dp_enable_link_phy(
1931 link,
d0778ebf 1932 link->connector_signal,
4562236b
HW
1933 dp_cs_id,
1934 cur);
1935
94405cf6 1936
4562236b
HW
1937 if (skip_link_training)
1938 success = true;
1939 else {
820e3935 1940 status = dc_link_dp_perform_link_training(
d0778ebf 1941 link,
4562236b
HW
1942 cur,
1943 skip_video_pattern);
820e3935
DW
1944 if (status == LINK_TRAINING_SUCCESS)
1945 success = true;
824474ba
BL
1946 else
1947 (*fail_count)++;
4562236b
HW
1948 }
1949
1ae62f31 1950 if (success) {
d0778ebf 1951 link->verified_link_cap = *cur;
1ae62f31
WL
1952 udelay(1000);
1953 if (read_hpd_rx_irq_data(link, &irq_data) == DC_OK)
1954 if (hpd_rx_irq_check_link_loss_status(
1955 link,
1956 &irq_data))
1957 (*fail_count)++;
1958 }
4562236b
HW
1959 /* always disable the link before trying another
1960 * setting or before returning we'll enable it later
1961 * based on the actual mode we're driving
1962 */
d0778ebf 1963 dp_disable_link_phy(link, link->connector_signal);
820e3935
DW
1964 } while (!success && decide_fallback_link_setting(
1965 initial_link_settings, cur, status));
4562236b
HW
1966
1967 /* Link Training failed for all Link Settings
1968 * (Lane Count is still unknown)
1969 */
1970 if (!success) {
1971 /* If all LT fails for all settings,
1972 * set verified = failed safe (1 lane low)
1973 */
d0778ebf
HW
1974 link->verified_link_cap.lane_count = LANE_COUNT_ONE;
1975 link->verified_link_cap.link_rate = LINK_RATE_LOW;
4562236b 1976
d0778ebf 1977 link->verified_link_cap.link_spread =
4562236b
HW
1978 LINK_SPREAD_DISABLED;
1979 }
1980
4562236b
HW
1981
1982 return success;
1983}
1984
e7f2c80c
WL
1985bool dp_verify_link_cap_with_retries(
1986 struct dc_link *link,
1987 struct dc_link_settings *known_limit_link_setting,
1988 int attempts)
1989{
1990 uint8_t i = 0;
1991 bool success = false;
1992
1993 for (i = 0; i < attempts; i++) {
1994 int fail_count = 0;
82db2e3c 1995 enum dc_connection_type type = dc_connection_none;
e7f2c80c
WL
1996
1997 memset(&link->verified_link_cap, 0,
1998 sizeof(struct dc_link_settings));
82db2e3c
SK
1999 if (!dc_link_detect_sink(link, &type) || type == dc_connection_none) {
2000 link->verified_link_cap.lane_count = LANE_COUNT_ONE;
2001 link->verified_link_cap.link_rate = LINK_RATE_LOW;
2002 link->verified_link_cap.link_spread = LINK_SPREAD_DISABLED;
e7f2c80c
WL
2003 break;
2004 } else if (dp_verify_link_cap(link,
2005 &link->reported_link_cap,
2006 &fail_count) && fail_count == 0) {
2007 success = true;
2008 break;
2009 }
2010 msleep(10);
2011 }
2012 return success;
2013}
2014
f537d474
LH
2015bool dp_verify_mst_link_cap(
2016 struct dc_link *link)
2017{
2018 struct dc_link_settings max_link_cap = {0};
2019
2020 max_link_cap = get_max_link_cap(link);
2021 link->verified_link_cap = get_common_supported_link_settings(
2022 link->reported_link_cap,
2023 max_link_cap);
2024
2025 return true;
2026}
2027
9a6a8075 2028static struct dc_link_settings get_common_supported_link_settings(
820e3935
DW
2029 struct dc_link_settings link_setting_a,
2030 struct dc_link_settings link_setting_b)
2031{
2032 struct dc_link_settings link_settings = {0};
2033
2034 link_settings.lane_count =
2035 (link_setting_a.lane_count <=
2036 link_setting_b.lane_count) ?
2037 link_setting_a.lane_count :
2038 link_setting_b.lane_count;
2039 link_settings.link_rate =
2040 (link_setting_a.link_rate <=
2041 link_setting_b.link_rate) ?
2042 link_setting_a.link_rate :
2043 link_setting_b.link_rate;
2044 link_settings.link_spread = LINK_SPREAD_DISABLED;
2045
2046 /* in DP compliance test, DPR-120 may have
2047 * a random value in its MAX_LINK_BW dpcd field.
2048 * We map it to the maximum supported link rate that
2049 * is smaller than MAX_LINK_BW in this case.
2050 */
2051 if (link_settings.link_rate > LINK_RATE_HIGH3) {
2052 link_settings.link_rate = LINK_RATE_HIGH3;
2053 } else if (link_settings.link_rate < LINK_RATE_HIGH3
2054 && link_settings.link_rate > LINK_RATE_HIGH2) {
2055 link_settings.link_rate = LINK_RATE_HIGH2;
2056 } else if (link_settings.link_rate < LINK_RATE_HIGH2
2057 && link_settings.link_rate > LINK_RATE_HIGH) {
2058 link_settings.link_rate = LINK_RATE_HIGH;
2059 } else if (link_settings.link_rate < LINK_RATE_HIGH
2060 && link_settings.link_rate > LINK_RATE_LOW) {
2061 link_settings.link_rate = LINK_RATE_LOW;
2062 } else if (link_settings.link_rate < LINK_RATE_LOW) {
2063 link_settings.link_rate = LINK_RATE_UNKNOWN;
2064 }
2065
2066 return link_settings;
2067}
2068
450619d3 2069static inline bool reached_minimum_lane_count(enum dc_lane_count lane_count)
820e3935
DW
2070{
2071 return lane_count <= LANE_COUNT_ONE;
2072}
2073
450619d3 2074static inline bool reached_minimum_link_rate(enum dc_link_rate link_rate)
820e3935
DW
2075{
2076 return link_rate <= LINK_RATE_LOW;
2077}
2078
44858055 2079static enum dc_lane_count reduce_lane_count(enum dc_lane_count lane_count)
820e3935
DW
2080{
2081 switch (lane_count) {
2082 case LANE_COUNT_FOUR:
2083 return LANE_COUNT_TWO;
2084 case LANE_COUNT_TWO:
2085 return LANE_COUNT_ONE;
2086 case LANE_COUNT_ONE:
2087 return LANE_COUNT_UNKNOWN;
2088 default:
2089 return LANE_COUNT_UNKNOWN;
2090 }
2091}
2092
04e21292 2093static enum dc_link_rate reduce_link_rate(enum dc_link_rate link_rate)
820e3935
DW
2094{
2095 switch (link_rate) {
2096 case LINK_RATE_HIGH3:
2097 return LINK_RATE_HIGH2;
2098 case LINK_RATE_HIGH2:
2099 return LINK_RATE_HIGH;
2100 case LINK_RATE_HIGH:
2101 return LINK_RATE_LOW;
2102 case LINK_RATE_LOW:
2103 return LINK_RATE_UNKNOWN;
2104 default:
2105 return LINK_RATE_UNKNOWN;
2106 }
2107}
2108
04e21292 2109static enum dc_lane_count increase_lane_count(enum dc_lane_count lane_count)
8c4abe0b
DW
2110{
2111 switch (lane_count) {
2112 case LANE_COUNT_ONE:
2113 return LANE_COUNT_TWO;
2114 case LANE_COUNT_TWO:
2115 return LANE_COUNT_FOUR;
2116 default:
2117 return LANE_COUNT_UNKNOWN;
2118 }
2119}
2120
04e21292 2121static enum dc_link_rate increase_link_rate(enum dc_link_rate link_rate)
8c4abe0b
DW
2122{
2123 switch (link_rate) {
2124 case LINK_RATE_LOW:
2125 return LINK_RATE_HIGH;
2126 case LINK_RATE_HIGH:
2127 return LINK_RATE_HIGH2;
2128 case LINK_RATE_HIGH2:
2129 return LINK_RATE_HIGH3;
2130 default:
2131 return LINK_RATE_UNKNOWN;
2132 }
2133}
2134
820e3935
DW
2135/*
2136 * function: set link rate and lane count fallback based
2137 * on current link setting and last link training result
2138 * return value:
2139 * true - link setting could be set
2140 * false - has reached minimum setting
2141 * and no further fallback could be done
2142 */
04e21292 2143static bool decide_fallback_link_setting(
820e3935
DW
2144 struct dc_link_settings initial_link_settings,
2145 struct dc_link_settings *current_link_setting,
2146 enum link_training_result training_result)
2147{
2148 if (!current_link_setting)
2149 return false;
2150
2151 switch (training_result) {
94405cf6
WL
2152 case LINK_TRAINING_CR_FAIL_LANE0:
2153 case LINK_TRAINING_CR_FAIL_LANE1:
2154 case LINK_TRAINING_CR_FAIL_LANE23:
2155 case LINK_TRAINING_LQA_FAIL:
820e3935
DW
2156 {
2157 if (!reached_minimum_link_rate
2158 (current_link_setting->link_rate)) {
2159 current_link_setting->link_rate =
2160 reduce_link_rate(
2161 current_link_setting->link_rate);
2162 } else if (!reached_minimum_lane_count
2163 (current_link_setting->lane_count)) {
2164 current_link_setting->link_rate =
2165 initial_link_settings.link_rate;
94405cf6
WL
2166 if (training_result == LINK_TRAINING_CR_FAIL_LANE0)
2167 return false;
2168 else if (training_result == LINK_TRAINING_CR_FAIL_LANE1)
2169 current_link_setting->lane_count =
2170 LANE_COUNT_ONE;
2171 else if (training_result ==
2172 LINK_TRAINING_CR_FAIL_LANE23)
2173 current_link_setting->lane_count =
2174 LANE_COUNT_TWO;
2175 else
2176 current_link_setting->lane_count =
2177 reduce_lane_count(
820e3935
DW
2178 current_link_setting->lane_count);
2179 } else {
2180 return false;
2181 }
2182 break;
2183 }
2184 case LINK_TRAINING_EQ_FAIL_EQ:
2185 {
2186 if (!reached_minimum_lane_count
2187 (current_link_setting->lane_count)) {
2188 current_link_setting->lane_count =
2189 reduce_lane_count(
2190 current_link_setting->lane_count);
2191 } else if (!reached_minimum_link_rate
2192 (current_link_setting->link_rate)) {
820e3935
DW
2193 current_link_setting->link_rate =
2194 reduce_link_rate(
2195 current_link_setting->link_rate);
2196 } else {
2197 return false;
2198 }
2199 break;
2200 }
2201 case LINK_TRAINING_EQ_FAIL_CR:
2202 {
2203 if (!reached_minimum_link_rate
2204 (current_link_setting->link_rate)) {
2205 current_link_setting->link_rate =
2206 reduce_link_rate(
2207 current_link_setting->link_rate);
2208 } else {
2209 return false;
2210 }
2211 break;
2212 }
2213 default:
2214 return false;
2215 }
2216 return true;
2217}
2218
4562236b 2219bool dp_validate_mode_timing(
d0778ebf 2220 struct dc_link *link,
4562236b
HW
2221 const struct dc_crtc_timing *timing)
2222{
2223 uint32_t req_bw;
2224 uint32_t max_bw;
2225
2226 const struct dc_link_settings *link_setting;
2227
2228 /*always DP fail safe mode*/
380604e2 2229 if ((timing->pix_clk_100hz / 10) == (uint32_t) 25175 &&
9a6a8075
HW
2230 timing->h_addressable == (uint32_t) 640 &&
2231 timing->v_addressable == (uint32_t) 480)
4562236b
HW
2232 return true;
2233
5ac4619b 2234 link_setting = dc_link_get_link_cap(link);
4562236b
HW
2235
2236 /* TODO: DYNAMIC_VALIDATION needs to be implemented */
2237 /*if (flags.DYNAMIC_VALIDATION == 1 &&
d0778ebf
HW
2238 link->verified_link_cap.lane_count != LANE_COUNT_UNKNOWN)
2239 link_setting = &link->verified_link_cap;
4562236b
HW
2240 */
2241
e49f6936 2242 req_bw = dc_bandwidth_in_kbps_from_timing(timing);
332c1191 2243 max_bw = dc_link_bandwidth_kbps(link, link_setting);
4562236b
HW
2244
2245 if (req_bw <= max_bw) {
2246 /* remember the biggest mode here, during
2247 * initial link training (to get
2248 * verified_link_cap), LS sends event about
2249 * cannot train at reported cap to upper
2250 * layer and upper layer will re-enumerate modes.
2251 * this is not necessary if the lower
2252 * verified_link_cap is enough to drive
2253 * all the modes */
2254
2255 /* TODO: DYNAMIC_VALIDATION needs to be implemented */
2256 /* if (flags.DYNAMIC_VALIDATION == 1)
2257 dpsst->max_req_bw_for_verified_linkcap = dal_max(
2258 dpsst->max_req_bw_for_verified_linkcap, req_bw); */
2259 return true;
2260 } else
2261 return false;
2262}
2263
8628d02f 2264static bool decide_dp_link_settings(struct dc_link *link, struct dc_link_settings *link_setting, uint32_t req_bw)
4562236b 2265{
8c4abe0b 2266 struct dc_link_settings initial_link_setting = {
8628d02f 2267 LANE_COUNT_ONE, LINK_RATE_LOW, LINK_SPREAD_DISABLED, false, 0};
8c4abe0b
DW
2268 struct dc_link_settings current_link_setting =
2269 initial_link_setting;
4562236b 2270 uint32_t link_bw;
4562236b 2271
8628d02f
JP
2272 /* search for the minimum link setting that:
2273 * 1. is supported according to the link training result
2274 * 2. could support the b/w requested by the timing
4562236b 2275 */
8628d02f
JP
2276 while (current_link_setting.link_rate <=
2277 link->verified_link_cap.link_rate) {
332c1191
NC
2278 link_bw = dc_link_bandwidth_kbps(
2279 link,
8628d02f
JP
2280 &current_link_setting);
2281 if (req_bw <= link_bw) {
2282 *link_setting = current_link_setting;
2283 return true;
2284 }
4562236b 2285
8628d02f
JP
2286 if (current_link_setting.lane_count <
2287 link->verified_link_cap.lane_count) {
2288 current_link_setting.lane_count =
2289 increase_lane_count(
2290 current_link_setting.lane_count);
2291 } else {
2292 current_link_setting.link_rate =
2293 increase_link_rate(
2294 current_link_setting.link_rate);
2295 current_link_setting.lane_count =
2296 initial_link_setting.lane_count;
2297 }
3f1f74f4
JZ
2298 }
2299
8628d02f
JP
2300 return false;
2301}
2302
2303static bool decide_edp_link_settings(struct dc_link *link, struct dc_link_settings *link_setting, uint32_t req_bw)
2304{
2305 struct dc_link_settings initial_link_setting;
2306 struct dc_link_settings current_link_setting;
2307 uint32_t link_bw;
2308
2309 if (link->dpcd_caps.dpcd_rev.raw < DPCD_REV_14 ||
53c81fc7 2310 link->dpcd_caps.edp_supported_link_rates_count == 0) {
4d2f22d1 2311 *link_setting = link->verified_link_cap;
8628d02f 2312 return true;
4d2f22d1
HH
2313 }
2314
8628d02f
JP
2315 memset(&initial_link_setting, 0, sizeof(initial_link_setting));
2316 initial_link_setting.lane_count = LANE_COUNT_ONE;
2317 initial_link_setting.link_rate = link->dpcd_caps.edp_supported_link_rates[0];
2318 initial_link_setting.link_spread = LINK_SPREAD_DISABLED;
2319 initial_link_setting.use_link_rate_set = true;
2320 initial_link_setting.link_rate_set = 0;
2321 current_link_setting = initial_link_setting;
2322
5667ff5c
DA
2323 /* search for the minimum link setting that:
2324 * 1. is supported according to the link training result
2325 * 2. could support the b/w requested by the timing
2326 */
8c4abe0b 2327 while (current_link_setting.link_rate <=
4654a2f7 2328 link->verified_link_cap.link_rate) {
332c1191
NC
2329 link_bw = dc_link_bandwidth_kbps(
2330 link,
8c4abe0b
DW
2331 &current_link_setting);
2332 if (req_bw <= link_bw) {
2333 *link_setting = current_link_setting;
8628d02f 2334 return true;
4562236b 2335 }
4562236b 2336
8c4abe0b 2337 if (current_link_setting.lane_count <
4654a2f7 2338 link->verified_link_cap.lane_count) {
8c4abe0b
DW
2339 current_link_setting.lane_count =
2340 increase_lane_count(
2341 current_link_setting.lane_count);
2342 } else {
8628d02f
JP
2343 if (current_link_setting.link_rate_set < link->dpcd_caps.edp_supported_link_rates_count) {
2344 current_link_setting.link_rate_set++;
2345 current_link_setting.link_rate =
2346 link->dpcd_caps.edp_supported_link_rates[current_link_setting.link_rate_set];
2347 current_link_setting.lane_count =
2348 initial_link_setting.lane_count;
2349 } else
2350 break;
4562236b
HW
2351 }
2352 }
8628d02f
JP
2353 return false;
2354}
2355
2356void decide_link_settings(struct dc_stream_state *stream,
2357 struct dc_link_settings *link_setting)
2358{
2359 struct dc_link *link;
2360 uint32_t req_bw;
2361
e49f6936 2362 req_bw = dc_bandwidth_in_kbps_from_timing(&stream->timing);
8628d02f
JP
2363
2364 link = stream->link;
2365
2366 /* if preferred is specified through AMDDP, use it, if it's enough
2367 * to drive the mode
2368 */
2369 if (link->preferred_link_setting.lane_count !=
2370 LANE_COUNT_UNKNOWN &&
2371 link->preferred_link_setting.link_rate !=
2372 LINK_RATE_UNKNOWN) {
2373 *link_setting = link->preferred_link_setting;
2374 return;
2375 }
2376
2377 /* MST doesn't perform link training for now
2378 * TODO: add MST specific link training routine
2379 */
2380 if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
2381 *link_setting = link->verified_link_cap;
2382 return;
2383 }
2384
2385 if (link->connector_signal == SIGNAL_TYPE_EDP) {
2386 if (decide_edp_link_settings(link, link_setting, req_bw))
2387 return;
2388 } else if (decide_dp_link_settings(link, link_setting, req_bw))
2389 return;
4562236b
HW
2390
2391 BREAK_TO_DEBUGGER();
d0778ebf 2392 ASSERT(link->verified_link_cap.lane_count != LANE_COUNT_UNKNOWN);
4562236b 2393
d0778ebf 2394 *link_setting = link->verified_link_cap;
4562236b
HW
2395}
2396
2397/*************************Short Pulse IRQ***************************/
d0778ebf 2398static bool allow_hpd_rx_irq(const struct dc_link *link)
4562236b
HW
2399{
2400 /*
2401 * Don't handle RX IRQ unless one of following is met:
2402 * 1) The link is established (cur_link_settings != unknown)
2403 * 2) We kicked off MST detection
2404 * 3) We know we're dealing with an active dongle
2405 */
2406
d0778ebf
HW
2407 if ((link->cur_link_settings.lane_count != LANE_COUNT_UNKNOWN) ||
2408 (link->type == dc_connection_mst_branch) ||
4562236b
HW
2409 is_dp_active_dongle(link))
2410 return true;
2411
2412 return false;
2413}
2414
ab4a4072 2415static bool handle_hpd_irq_psr_sink(struct dc_link *link)
4562236b
HW
2416{
2417 union dpcd_psr_configuration psr_configuration;
2418
d1ebfdd8 2419 if (!link->psr_settings.psr_feature_enabled)
4562236b
HW
2420 return false;
2421
7c7f5b15
AG
2422 dm_helpers_dp_read_dpcd(
2423 link->ctx,
d0778ebf 2424 link,
7c7f5b15
AG
2425 368,/*DpcdAddress_PSR_Enable_Cfg*/
2426 &psr_configuration.raw,
2427 sizeof(psr_configuration.raw));
2428
4562236b
HW
2429
2430 if (psr_configuration.bits.ENABLE) {
2431 unsigned char dpcdbuf[3] = {0};
2432 union psr_error_status psr_error_status;
2433 union psr_sink_psr_status psr_sink_psr_status;
2434
7c7f5b15
AG
2435 dm_helpers_dp_read_dpcd(
2436 link->ctx,
d0778ebf 2437 link,
7c7f5b15
AG
2438 0x2006, /*DpcdAddress_PSR_Error_Status*/
2439 (unsigned char *) dpcdbuf,
2440 sizeof(dpcdbuf));
4562236b
HW
2441
2442 /*DPCD 2006h ERROR STATUS*/
2443 psr_error_status.raw = dpcdbuf[0];
2444 /*DPCD 2008h SINK PANEL SELF REFRESH STATUS*/
2445 psr_sink_psr_status.raw = dpcdbuf[2];
2446
2447 if (psr_error_status.bits.LINK_CRC_ERROR ||
2448 psr_error_status.bits.RFB_STORAGE_ERROR) {
2449 /* Acknowledge and clear error bits */
7c7f5b15
AG
2450 dm_helpers_dp_write_dpcd(
2451 link->ctx,
d0778ebf 2452 link,
7c7f5b15 2453 8198,/*DpcdAddress_PSR_Error_Status*/
4562236b
HW
2454 &psr_error_status.raw,
2455 sizeof(psr_error_status.raw));
2456
2457 /* PSR error, disable and re-enable PSR */
ab4a4072
EY
2458 dc_link_set_psr_allow_active(link, false, true);
2459 dc_link_set_psr_allow_active(link, true, true);
4562236b
HW
2460
2461 return true;
2462 } else if (psr_sink_psr_status.bits.SINK_SELF_REFRESH_STATUS ==
2463 PSR_SINK_STATE_ACTIVE_DISPLAY_FROM_SINK_RFB){
2464 /* No error is detect, PSR is active.
2465 * We should return with IRQ_HPD handled without
2466 * checking for loss of sync since PSR would have
2467 * powered down main link.
2468 */
2469 return true;
2470 }
2471 }
2472 return false;
2473}
2474
d0778ebf 2475static void dp_test_send_link_training(struct dc_link *link)
4562236b 2476{
73c72602 2477 struct dc_link_settings link_settings = {0};
4562236b
HW
2478
2479 core_link_read_dpcd(
2480 link,
3a340294 2481 DP_TEST_LANE_COUNT,
4562236b
HW
2482 (unsigned char *)(&link_settings.lane_count),
2483 1);
2484 core_link_read_dpcd(
2485 link,
3a340294 2486 DP_TEST_LINK_RATE,
4562236b
HW
2487 (unsigned char *)(&link_settings.link_rate),
2488 1);
2489
2490 /* Set preferred link settings */
d0778ebf
HW
2491 link->verified_link_cap.lane_count = link_settings.lane_count;
2492 link->verified_link_cap.link_rate = link_settings.link_rate;
4562236b 2493
73c72602 2494 dp_retrain_link_dp_test(link, &link_settings, false);
4562236b
HW
2495}
2496
9315e239 2497/* TODO Raven hbr2 compliance eye output is unstable
25bab0da
WL
2498 * (toggling on and off) with debugger break
2499 * This caueses intermittent PHY automation failure
2500 * Need to look into the root cause */
d0778ebf 2501static void dp_test_send_phy_test_pattern(struct dc_link *link)
4562236b
HW
2502{
2503 union phy_test_pattern dpcd_test_pattern;
2504 union lane_adjust dpcd_lane_adjustment[2];
2505 unsigned char dpcd_post_cursor_2_adjustment = 0;
2506 unsigned char test_80_bit_pattern[
3a340294
DA
2507 (DP_TEST_80BIT_CUSTOM_PATTERN_79_72 -
2508 DP_TEST_80BIT_CUSTOM_PATTERN_7_0)+1] = {0};
4562236b
HW
2509 enum dp_test_pattern test_pattern;
2510 struct dc_link_training_settings link_settings;
2511 union lane_adjust dpcd_lane_adjust;
2512 unsigned int lane;
2513 struct link_training_settings link_training_settings;
2514 int i = 0;
2515
2516 dpcd_test_pattern.raw = 0;
2517 memset(dpcd_lane_adjustment, 0, sizeof(dpcd_lane_adjustment));
2518 memset(&link_settings, 0, sizeof(link_settings));
2519
2520 /* get phy test pattern and pattern parameters from DP receiver */
2521 core_link_read_dpcd(
2522 link,
8811d9eb 2523 DP_PHY_TEST_PATTERN,
4562236b
HW
2524 &dpcd_test_pattern.raw,
2525 sizeof(dpcd_test_pattern));
2526 core_link_read_dpcd(
2527 link,
3a340294 2528 DP_ADJUST_REQUEST_LANE0_1,
4562236b
HW
2529 &dpcd_lane_adjustment[0].raw,
2530 sizeof(dpcd_lane_adjustment));
2531
2532 /*get post cursor 2 parameters
2533 * For DP 1.1a or eariler, this DPCD register's value is 0
2534 * For DP 1.2 or later:
2535 * Bits 1:0 = POST_CURSOR2_LANE0; Bits 3:2 = POST_CURSOR2_LANE1
2536 * Bits 5:4 = POST_CURSOR2_LANE2; Bits 7:6 = POST_CURSOR2_LANE3
2537 */
2538 core_link_read_dpcd(
2539 link,
3a340294 2540 DP_ADJUST_REQUEST_POST_CURSOR2,
4562236b
HW
2541 &dpcd_post_cursor_2_adjustment,
2542 sizeof(dpcd_post_cursor_2_adjustment));
2543
2544 /* translate request */
2545 switch (dpcd_test_pattern.bits.PATTERN) {
2546 case PHY_TEST_PATTERN_D10_2:
2547 test_pattern = DP_TEST_PATTERN_D102;
0e19401f 2548 break;
4562236b
HW
2549 case PHY_TEST_PATTERN_SYMBOL_ERROR:
2550 test_pattern = DP_TEST_PATTERN_SYMBOL_ERROR;
0e19401f 2551 break;
4562236b
HW
2552 case PHY_TEST_PATTERN_PRBS7:
2553 test_pattern = DP_TEST_PATTERN_PRBS7;
0e19401f 2554 break;
4562236b
HW
2555 case PHY_TEST_PATTERN_80BIT_CUSTOM:
2556 test_pattern = DP_TEST_PATTERN_80BIT_CUSTOM;
0e19401f
TC
2557 break;
2558 case PHY_TEST_PATTERN_CP2520_1:
25bab0da 2559 /* CP2520 pattern is unstable, temporarily use TPS4 instead */
9315e239 2560 test_pattern = (link->dc->caps.force_dp_tps4_for_cp2520 == 1) ?
25bab0da
WL
2561 DP_TEST_PATTERN_TRAINING_PATTERN4 :
2562 DP_TEST_PATTERN_HBR2_COMPLIANCE_EYE;
0e19401f
TC
2563 break;
2564 case PHY_TEST_PATTERN_CP2520_2:
25bab0da 2565 /* CP2520 pattern is unstable, temporarily use TPS4 instead */
9315e239 2566 test_pattern = (link->dc->caps.force_dp_tps4_for_cp2520 == 1) ?
25bab0da
WL
2567 DP_TEST_PATTERN_TRAINING_PATTERN4 :
2568 DP_TEST_PATTERN_HBR2_COMPLIANCE_EYE;
0e19401f
TC
2569 break;
2570 case PHY_TEST_PATTERN_CP2520_3:
78e685f9 2571 test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN4;
0e19401f 2572 break;
4562236b
HW
2573 default:
2574 test_pattern = DP_TEST_PATTERN_VIDEO_MODE;
2575 break;
2576 }
2577
2578 if (test_pattern == DP_TEST_PATTERN_80BIT_CUSTOM)
2579 core_link_read_dpcd(
2580 link,
3a340294 2581 DP_TEST_80BIT_CUSTOM_PATTERN_7_0,
4562236b
HW
2582 test_80_bit_pattern,
2583 sizeof(test_80_bit_pattern));
2584
2585 /* prepare link training settings */
d0778ebf 2586 link_settings.link = link->cur_link_settings;
4562236b
HW
2587
2588 for (lane = 0; lane <
d0778ebf 2589 (unsigned int)(link->cur_link_settings.lane_count);
4562236b
HW
2590 lane++) {
2591 dpcd_lane_adjust.raw =
2592 get_nibble_at_index(&dpcd_lane_adjustment[0].raw, lane);
2593 link_settings.lane_settings[lane].VOLTAGE_SWING =
2594 (enum dc_voltage_swing)
2595 (dpcd_lane_adjust.bits.VOLTAGE_SWING_LANE);
2596 link_settings.lane_settings[lane].PRE_EMPHASIS =
2597 (enum dc_pre_emphasis)
2598 (dpcd_lane_adjust.bits.PRE_EMPHASIS_LANE);
2599 link_settings.lane_settings[lane].POST_CURSOR2 =
2600 (enum dc_post_cursor2)
2601 ((dpcd_post_cursor_2_adjustment >> (lane * 2)) & 0x03);
2602 }
2603
2604 for (i = 0; i < 4; i++)
2605 link_training_settings.lane_settings[i] =
2606 link_settings.lane_settings[i];
2607 link_training_settings.link_settings = link_settings.link;
2608 link_training_settings.allow_invalid_msa_timing_param = false;
2609 /*Usage: Measure DP physical lane signal
2610 * by DP SI test equipment automatically.
2611 * PHY test pattern request is generated by equipment via HPD interrupt.
2612 * HPD needs to be active all the time. HPD should be active
2613 * all the time. Do not touch it.
2614 * forward request to DS
2615 */
2616 dc_link_dp_set_test_pattern(
d0778ebf 2617 link,
4562236b 2618 test_pattern,
2057b7e1 2619 DP_TEST_PATTERN_COLOR_SPACE_UNDEFINED,
4562236b
HW
2620 &link_training_settings,
2621 test_80_bit_pattern,
3a340294
DA
2622 (DP_TEST_80BIT_CUSTOM_PATTERN_79_72 -
2623 DP_TEST_80BIT_CUSTOM_PATTERN_7_0)+1);
4562236b
HW
2624}
2625
d0778ebf 2626static void dp_test_send_link_test_pattern(struct dc_link *link)
4562236b
HW
2627{
2628 union link_test_pattern dpcd_test_pattern;
2629 union test_misc dpcd_test_params;
2630 enum dp_test_pattern test_pattern;
2057b7e1
WL
2631 enum dp_test_pattern_color_space test_pattern_color_space =
2632 DP_TEST_PATTERN_COLOR_SPACE_UNDEFINED;
4562236b
HW
2633
2634 memset(&dpcd_test_pattern, 0, sizeof(dpcd_test_pattern));
2635 memset(&dpcd_test_params, 0, sizeof(dpcd_test_params));
2636
2637 /* get link test pattern and pattern parameters */
2638 core_link_read_dpcd(
2639 link,
3a340294 2640 DP_TEST_PATTERN,
4562236b
HW
2641 &dpcd_test_pattern.raw,
2642 sizeof(dpcd_test_pattern));
2643 core_link_read_dpcd(
2644 link,
3a340294 2645 DP_TEST_MISC0,
4562236b
HW
2646 &dpcd_test_params.raw,
2647 sizeof(dpcd_test_params));
2648
2649 switch (dpcd_test_pattern.bits.PATTERN) {
2650 case LINK_TEST_PATTERN_COLOR_RAMP:
2651 test_pattern = DP_TEST_PATTERN_COLOR_RAMP;
2652 break;
2653 case LINK_TEST_PATTERN_VERTICAL_BARS:
2654 test_pattern = DP_TEST_PATTERN_VERTICAL_BARS;
2655 break; /* black and white */
2656 case LINK_TEST_PATTERN_COLOR_SQUARES:
2657 test_pattern = (dpcd_test_params.bits.DYN_RANGE ==
2658 TEST_DYN_RANGE_VESA ?
2659 DP_TEST_PATTERN_COLOR_SQUARES :
2660 DP_TEST_PATTERN_COLOR_SQUARES_CEA);
2661 break;
2662 default:
2663 test_pattern = DP_TEST_PATTERN_VIDEO_MODE;
2664 break;
2665 }
2666
ef65c702
JFZ
2667 if (dpcd_test_params.bits.CLR_FORMAT == 0)
2668 test_pattern_color_space = DP_TEST_PATTERN_COLOR_SPACE_RGB;
2669 else
2670 test_pattern_color_space = dpcd_test_params.bits.YCBCR_COEFS ?
2671 DP_TEST_PATTERN_COLOR_SPACE_YCBCR709 :
2672 DP_TEST_PATTERN_COLOR_SPACE_YCBCR601;
2057b7e1 2673
4562236b 2674 dc_link_dp_set_test_pattern(
d0778ebf 2675 link,
4562236b 2676 test_pattern,
2057b7e1 2677 test_pattern_color_space,
4562236b
HW
2678 NULL,
2679 NULL,
2680 0);
2681}
2682
8c8048f2 2683static void dp_test_get_audio_test_data(struct dc_link *link, bool disable_video)
2684{
2685 union audio_test_mode dpcd_test_mode = {0};
2686 struct audio_test_pattern_type dpcd_pattern_type = {0};
2687 union audio_test_pattern_period dpcd_pattern_period[AUDIO_CHANNELS_COUNT] = {0};
2688 enum dp_test_pattern test_pattern = DP_TEST_PATTERN_AUDIO_OPERATOR_DEFINED;
2689
2690 struct pipe_ctx *pipes = link->dc->current_state->res_ctx.pipe_ctx;
2691 struct pipe_ctx *pipe_ctx = &pipes[0];
2692 unsigned int channel_count;
2693 unsigned int channel = 0;
2694 unsigned int modes = 0;
2695 unsigned int sampling_rate_in_hz = 0;
2696
2697 // get audio test mode and test pattern parameters
2698 core_link_read_dpcd(
2699 link,
2700 DP_TEST_AUDIO_MODE,
2701 &dpcd_test_mode.raw,
2702 sizeof(dpcd_test_mode));
2703
2704 core_link_read_dpcd(
2705 link,
2706 DP_TEST_AUDIO_PATTERN_TYPE,
2707 &dpcd_pattern_type.value,
2708 sizeof(dpcd_pattern_type));
2709
2710 channel_count = dpcd_test_mode.bits.channel_count + 1;
2711
2712 // read pattern periods for requested channels when sawTooth pattern is requested
2713 if (dpcd_pattern_type.value == AUDIO_TEST_PATTERN_SAWTOOTH ||
2714 dpcd_pattern_type.value == AUDIO_TEST_PATTERN_OPERATOR_DEFINED) {
2715
2716 test_pattern = (dpcd_pattern_type.value == AUDIO_TEST_PATTERN_SAWTOOTH) ?
2717 DP_TEST_PATTERN_AUDIO_SAWTOOTH : DP_TEST_PATTERN_AUDIO_OPERATOR_DEFINED;
2718 // read period for each channel
2719 for (channel = 0; channel < channel_count; channel++) {
2720 core_link_read_dpcd(
2721 link,
2722 DP_TEST_AUDIO_PERIOD_CH1 + channel,
2723 &dpcd_pattern_period[channel].raw,
2724 sizeof(dpcd_pattern_period[channel]));
2725 }
2726 }
2727
2728 // translate sampling rate
2729 switch (dpcd_test_mode.bits.sampling_rate) {
2730 case AUDIO_SAMPLING_RATE_32KHZ:
2731 sampling_rate_in_hz = 32000;
2732 break;
2733 case AUDIO_SAMPLING_RATE_44_1KHZ:
2734 sampling_rate_in_hz = 44100;
2735 break;
2736 case AUDIO_SAMPLING_RATE_48KHZ:
2737 sampling_rate_in_hz = 48000;
2738 break;
2739 case AUDIO_SAMPLING_RATE_88_2KHZ:
2740 sampling_rate_in_hz = 88200;
2741 break;
2742 case AUDIO_SAMPLING_RATE_96KHZ:
2743 sampling_rate_in_hz = 96000;
2744 break;
2745 case AUDIO_SAMPLING_RATE_176_4KHZ:
2746 sampling_rate_in_hz = 176400;
2747 break;
2748 case AUDIO_SAMPLING_RATE_192KHZ:
2749 sampling_rate_in_hz = 192000;
2750 break;
2751 default:
2752 sampling_rate_in_hz = 0;
2753 break;
2754 }
2755
2756 link->audio_test_data.flags.test_requested = 1;
2757 link->audio_test_data.flags.disable_video = disable_video;
2758 link->audio_test_data.sampling_rate = sampling_rate_in_hz;
2759 link->audio_test_data.channel_count = channel_count;
2760 link->audio_test_data.pattern_type = test_pattern;
2761
2762 if (test_pattern == DP_TEST_PATTERN_AUDIO_SAWTOOTH) {
2763 for (modes = 0; modes < pipe_ctx->stream->audio_info.mode_count; modes++) {
2764 link->audio_test_data.pattern_period[modes] = dpcd_pattern_period[modes].bits.pattern_period;
2765 }
2766 }
2767}
2768
d0778ebf 2769static void handle_automated_test(struct dc_link *link)
4562236b
HW
2770{
2771 union test_request test_request;
2772 union test_response test_response;
2773
2774 memset(&test_request, 0, sizeof(test_request));
2775 memset(&test_response, 0, sizeof(test_response));
2776
2777 core_link_read_dpcd(
2778 link,
3a340294 2779 DP_TEST_REQUEST,
4562236b
HW
2780 &test_request.raw,
2781 sizeof(union test_request));
2782 if (test_request.bits.LINK_TRAINING) {
2783 /* ACK first to let DP RX test box monitor LT sequence */
2784 test_response.bits.ACK = 1;
2785 core_link_write_dpcd(
2786 link,
3a340294 2787 DP_TEST_RESPONSE,
4562236b
HW
2788 &test_response.raw,
2789 sizeof(test_response));
2790 dp_test_send_link_training(link);
2791 /* no acknowledge request is needed again */
2792 test_response.bits.ACK = 0;
2793 }
2794 if (test_request.bits.LINK_TEST_PATTRN) {
2795 dp_test_send_link_test_pattern(link);
75a74755 2796 test_response.bits.ACK = 1;
4562236b 2797 }
8c8048f2 2798
2799 if (test_request.bits.AUDIO_TEST_PATTERN) {
2800 dp_test_get_audio_test_data(link, test_request.bits.TEST_AUDIO_DISABLED_VIDEO);
2801 test_response.bits.ACK = 1;
2802 }
2803
4562236b
HW
2804 if (test_request.bits.PHY_TEST_PATTERN) {
2805 dp_test_send_phy_test_pattern(link);
2806 test_response.bits.ACK = 1;
2807 }
a6729a5a 2808
4562236b
HW
2809 /* send request acknowledgment */
2810 if (test_response.bits.ACK)
2811 core_link_write_dpcd(
2812 link,
3a340294 2813 DP_TEST_RESPONSE,
4562236b
HW
2814 &test_response.raw,
2815 sizeof(test_response));
2816}
2817
4e18814e 2818bool dc_link_handle_hpd_rx_irq(struct dc_link *link, union hpd_irq_data *out_hpd_irq_dpcd_data, bool *out_link_loss)
4562236b 2819{
9a6a8075 2820 union hpd_irq_data hpd_irq_dpcd_data = { { { {0} } } };
c2e218dd 2821 union device_service_irq device_service_clear = { { 0 } };
d6258eaa 2822 enum dc_status result;
4562236b 2823 bool status = false;
48af9b91 2824 struct pipe_ctx *pipe_ctx;
99218d12 2825 struct dc_link_settings previous_link_settings;
48af9b91 2826 int i;
4e18814e
FD
2827
2828 if (out_link_loss)
2829 *out_link_loss = false;
4562236b
HW
2830 /* For use cases related to down stream connection status change,
2831 * PSR and device auto test, refer to function handle_sst_hpd_irq
2832 * in DAL2.1*/
2833
1296423b 2834 DC_LOG_HW_HPD_IRQ("%s: Got short pulse HPD on link %d\n",
d0778ebf 2835 __func__, link->link_index);
4562236b 2836
8ee65d7c 2837
4562236b
HW
2838 /* All the "handle_hpd_irq_xxx()" methods
2839 * should be called only after
2840 * dal_dpsst_ls_read_hpd_irq_data
2841 * Order of calls is important too
2842 */
2843 result = read_hpd_rx_irq_data(link, &hpd_irq_dpcd_data);
8ee65d7c
WL
2844 if (out_hpd_irq_dpcd_data)
2845 *out_hpd_irq_dpcd_data = hpd_irq_dpcd_data;
4562236b
HW
2846
2847 if (result != DC_OK) {
1296423b 2848 DC_LOG_HW_HPD_IRQ("%s: DPCD read failed to obtain irq data\n",
4562236b
HW
2849 __func__);
2850 return false;
2851 }
2852
2853 if (hpd_irq_dpcd_data.bytes.device_service_irq.bits.AUTOMATED_TEST) {
2854 device_service_clear.bits.AUTOMATED_TEST = 1;
2855 core_link_write_dpcd(
2856 link,
3a340294 2857 DP_DEVICE_SERVICE_IRQ_VECTOR,
4562236b
HW
2858 &device_service_clear.raw,
2859 sizeof(device_service_clear.raw));
2860 device_service_clear.raw = 0;
2861 handle_automated_test(link);
2862 return false;
2863 }
2864
2865 if (!allow_hpd_rx_irq(link)) {
1296423b 2866 DC_LOG_HW_HPD_IRQ("%s: skipping HPD handling on %d\n",
d0778ebf 2867 __func__, link->link_index);
4562236b
HW
2868 return false;
2869 }
2870
2871 if (handle_hpd_irq_psr_sink(link))
2872 /* PSR-related error was detected and handled */
2873 return true;
2874
2875 /* If PSR-related error handled, Main link may be off,
2876 * so do not handle as a normal sink status change interrupt.
2877 */
2878
aaa15026
WL
2879 if (hpd_irq_dpcd_data.bytes.device_service_irq.bits.UP_REQ_MSG_RDY)
2880 return true;
2881
4562236b 2882 /* check if we have MST msg and return since we poll for it */
aaa15026 2883 if (hpd_irq_dpcd_data.bytes.device_service_irq.bits.DOWN_REP_MSG_RDY)
4562236b
HW
2884 return false;
2885
2886 /* For now we only handle 'Downstream port status' case.
2887 * If we got sink count changed it means
2888 * Downstream port status changed,
e97ed496
AK
2889 * then DM should call DC to do the detection.
2890 * NOTE: Do not handle link loss on eDP since it is internal link*/
2891 if ((link->connector_signal != SIGNAL_TYPE_EDP) &&
2892 hpd_rx_irq_check_link_loss_status(
2893 link,
2894 &hpd_irq_dpcd_data)) {
4562236b
HW
2895 /* Connectivity log: link loss */
2896 CONN_DATA_LINK_LOSS(link,
2897 hpd_irq_dpcd_data.raw,
2898 sizeof(hpd_irq_dpcd_data),
2899 "Status: ");
2900
422d9091
XY
2901 for (i = 0; i < MAX_PIPES; i++) {
2902 pipe_ctx = &link->dc->current_state->res_ctx.pipe_ctx[i];
2903 if (pipe_ctx && pipe_ctx->stream && pipe_ctx->stream->link == link)
2904 link->dc->hwss.blank_stream(pipe_ctx);
2905 }
2906
48af9b91
AL
2907 for (i = 0; i < MAX_PIPES; i++) {
2908 pipe_ctx = &link->dc->current_state->res_ctx.pipe_ctx[i];
832aa63b
PH
2909 if (pipe_ctx && pipe_ctx->stream && pipe_ctx->stream->link == link)
2910 break;
2911 }
2912
2913 if (pipe_ctx == NULL || pipe_ctx->stream == NULL)
2914 return false;
2915
99218d12 2916 previous_link_settings = link->cur_link_settings;
832aa63b 2917
99218d12 2918 perform_link_training_with_retries(&previous_link_settings,
832aa63b
PH
2919 true, LINK_TRAINING_ATTEMPTS,
2920 pipe_ctx,
2921 pipe_ctx->stream->signal);
2922
ffdaeb1f
PH
2923 if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST)
2924 dc_link_reallocate_mst_payload(link);
48af9b91 2925
422d9091
XY
2926 for (i = 0; i < MAX_PIPES; i++) {
2927 pipe_ctx = &link->dc->current_state->res_ctx.pipe_ctx[i];
2928 if (pipe_ctx && pipe_ctx->stream && pipe_ctx->stream->link == link)
2929 link->dc->hwss.unblank_stream(pipe_ctx, &previous_link_settings);
2930 }
2931
4562236b 2932 status = false;
4e18814e
FD
2933 if (out_link_loss)
2934 *out_link_loss = true;
4562236b
HW
2935 }
2936
d0778ebf 2937 if (link->type == dc_connection_active_dongle &&
4562236b
HW
2938 hpd_irq_dpcd_data.bytes.sink_cnt.bits.SINK_COUNT
2939 != link->dpcd_sink_count)
2940 status = true;
2941
2942 /* reasons for HPD RX:
2943 * 1. Link Loss - ie Re-train the Link
2944 * 2. MST sideband message
2945 * 3. Automated Test - ie. Internal Commit
2946 * 4. CP (copy protection) - (not interesting for DM???)
2947 * 5. DRR
2948 * 6. Downstream Port status changed
2949 * -ie. Detect - this the only one
2950 * which is interesting for DM because
2951 * it must call dc_link_detect.
2952 */
2953 return status;
2954}
2955
2956/*query dpcd for version and mst cap addresses*/
d0778ebf 2957bool is_mst_supported(struct dc_link *link)
4562236b
HW
2958{
2959 bool mst = false;
2960 enum dc_status st = DC_OK;
2961 union dpcd_rev rev;
2962 union mstm_cap cap;
2963
0b226322
DG
2964 if (link->preferred_training_settings.mst_enable &&
2965 *link->preferred_training_settings.mst_enable == false) {
2966 return false;
2967 }
2968
4562236b
HW
2969 rev.raw = 0;
2970 cap.raw = 0;
2971
3a340294 2972 st = core_link_read_dpcd(link, DP_DPCD_REV, &rev.raw,
4562236b
HW
2973 sizeof(rev));
2974
2975 if (st == DC_OK && rev.raw >= DPCD_REV_12) {
2976
3a340294 2977 st = core_link_read_dpcd(link, DP_MSTM_CAP,
4562236b
HW
2978 &cap.raw, sizeof(cap));
2979 if (st == DC_OK && cap.bits.MST_CAP == 1)
2980 mst = true;
2981 }
2982 return mst;
2983
2984}
2985
d0778ebf 2986bool is_dp_active_dongle(const struct dc_link *link)
4562236b 2987{
a504ad26 2988 return link->dpcd_caps.is_branch_dev;
4562236b
HW
2989}
2990
6bffebc9
EY
2991static int translate_dpcd_max_bpc(enum dpcd_downstream_port_max_bpc bpc)
2992{
2993 switch (bpc) {
2994 case DOWN_STREAM_MAX_8BPC:
2995 return 8;
2996 case DOWN_STREAM_MAX_10BPC:
2997 return 10;
2998 case DOWN_STREAM_MAX_12BPC:
2999 return 12;
3000 case DOWN_STREAM_MAX_16BPC:
3001 return 16;
3002 default:
3003 break;
3004 }
3005
3006 return -1;
3007}
3008
ee13cea9
JB
3009static void read_dp_device_vendor_id(struct dc_link *link)
3010{
3011 struct dp_device_vendor_id dp_id;
3012
3013 /* read IEEE branch device id */
3014 core_link_read_dpcd(
3015 link,
3016 DP_BRANCH_OUI,
3017 (uint8_t *)&dp_id,
3018 sizeof(dp_id));
3019
3020 link->dpcd_caps.branch_dev_id =
3021 (dp_id.ieee_oui[0] << 16) +
3022 (dp_id.ieee_oui[1] << 8) +
3023 dp_id.ieee_oui[2];
3024
3025 memmove(
3026 link->dpcd_caps.branch_dev_name,
3027 dp_id.ieee_device_id,
3028 sizeof(dp_id.ieee_device_id));
3029}
3030
3031
3032
4562236b 3033static void get_active_converter_info(
d0778ebf 3034 uint8_t data, struct dc_link *link)
4562236b
HW
3035{
3036 union dp_downstream_port_present ds_port = { .byte = data };
dd998291 3037 memset(&link->dpcd_caps.dongle_caps, 0, sizeof(link->dpcd_caps.dongle_caps));
4562236b
HW
3038
3039 /* decode converter info*/
3040 if (!ds_port.fields.PORT_PRESENT) {
3041 link->dpcd_caps.dongle_type = DISPLAY_DONGLE_NONE;
d0778ebf 3042 ddc_service_set_dongle_type(link->ddc,
4562236b 3043 link->dpcd_caps.dongle_type);
ac3d76e0 3044 link->dpcd_caps.is_branch_dev = false;
4562236b
HW
3045 return;
3046 }
3047
a504ad26 3048 /* DPCD 0x5 bit 0 = 1, it indicate it's branch device */
ac3d76e0
HT
3049 if (ds_port.fields.PORT_TYPE == DOWNSTREAM_DP) {
3050 link->dpcd_caps.is_branch_dev = false;
3051 }
3052
3053 else {
3054 link->dpcd_caps.is_branch_dev = ds_port.fields.PORT_PRESENT;
3055 }
a504ad26 3056
4562236b
HW
3057 switch (ds_port.fields.PORT_TYPE) {
3058 case DOWNSTREAM_VGA:
3059 link->dpcd_caps.dongle_type = DISPLAY_DONGLE_DP_VGA_CONVERTER;
3060 break;
7a83645a
DZ
3061 case DOWNSTREAM_DVI_HDMI_DP_PLUS_PLUS:
3062 /* At this point we don't know is it DVI or HDMI or DP++,
4562236b
HW
3063 * assume DVI.*/
3064 link->dpcd_caps.dongle_type = DISPLAY_DONGLE_DP_DVI_CONVERTER;
3065 break;
3066 default:
3067 link->dpcd_caps.dongle_type = DISPLAY_DONGLE_NONE;
3068 break;
3069 }
3070
ac0e562c 3071 if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_11) {
242b0c8f 3072 uint8_t det_caps[16]; /* CTS 4.2.2.7 expects source to read Detailed Capabilities Info : 00080h-0008F.*/
4562236b
HW
3073 union dwnstream_port_caps_byte0 *port_caps =
3074 (union dwnstream_port_caps_byte0 *)det_caps;
3a340294 3075 core_link_read_dpcd(link, DP_DOWNSTREAM_PORT_0,
4562236b
HW
3076 det_caps, sizeof(det_caps));
3077
3078 switch (port_caps->bits.DWN_STRM_PORTX_TYPE) {
7a83645a
DZ
3079 /*Handle DP case as DONGLE_NONE*/
3080 case DOWN_STREAM_DETAILED_DP:
3081 link->dpcd_caps.dongle_type = DISPLAY_DONGLE_NONE;
3082 break;
4562236b
HW
3083 case DOWN_STREAM_DETAILED_VGA:
3084 link->dpcd_caps.dongle_type =
3085 DISPLAY_DONGLE_DP_VGA_CONVERTER;
3086 break;
3087 case DOWN_STREAM_DETAILED_DVI:
3088 link->dpcd_caps.dongle_type =
3089 DISPLAY_DONGLE_DP_DVI_CONVERTER;
3090 break;
3091 case DOWN_STREAM_DETAILED_HDMI:
7a83645a
DZ
3092 case DOWN_STREAM_DETAILED_DP_PLUS_PLUS:
3093 /*Handle DP++ active converter case, process DP++ case as HDMI case according DP1.4 spec*/
4562236b
HW
3094 link->dpcd_caps.dongle_type =
3095 DISPLAY_DONGLE_DP_HDMI_CONVERTER;
3096
03f5c686 3097 link->dpcd_caps.dongle_caps.dongle_type = link->dpcd_caps.dongle_type;
4562236b
HW
3098 if (ds_port.fields.DETAILED_CAPS) {
3099
3100 union dwnstream_port_caps_byte3_hdmi
3101 hdmi_caps = {.raw = det_caps[3] };
7d8d90d8 3102 union dwnstream_port_caps_byte2
03f5c686 3103 hdmi_color_caps = {.raw = det_caps[2] };
e5490464
S
3104 link->dpcd_caps.dongle_caps.dp_hdmi_max_pixel_clk_in_khz =
3105 det_caps[1] * 2500;
4562236b 3106
03f5c686 3107 link->dpcd_caps.dongle_caps.is_dp_hdmi_s3d_converter =
4562236b 3108 hdmi_caps.bits.FRAME_SEQ_TO_FRAME_PACK;
7a83645a
DZ
3109 /*YCBCR capability only for HDMI case*/
3110 if (port_caps->bits.DWN_STRM_PORTX_TYPE
3111 == DOWN_STREAM_DETAILED_HDMI) {
3112 link->dpcd_caps.dongle_caps.is_dp_hdmi_ycbcr422_pass_through =
3113 hdmi_caps.bits.YCrCr422_PASS_THROUGH;
3114 link->dpcd_caps.dongle_caps.is_dp_hdmi_ycbcr420_pass_through =
3115 hdmi_caps.bits.YCrCr420_PASS_THROUGH;
3116 link->dpcd_caps.dongle_caps.is_dp_hdmi_ycbcr422_converter =
3117 hdmi_caps.bits.YCrCr422_CONVERSION;
3118 link->dpcd_caps.dongle_caps.is_dp_hdmi_ycbcr420_converter =
3119 hdmi_caps.bits.YCrCr420_CONVERSION;
3120 }
03f5c686
CL
3121
3122 link->dpcd_caps.dongle_caps.dp_hdmi_max_bpc =
6bffebc9
EY
3123 translate_dpcd_max_bpc(
3124 hdmi_color_caps.bits.MAX_BITS_PER_COLOR_COMPONENT);
03f5c686 3125
e5490464 3126 if (link->dpcd_caps.dongle_caps.dp_hdmi_max_pixel_clk_in_khz != 0)
99b922f9 3127 link->dpcd_caps.dongle_caps.extendedCapValid = true;
4562236b 3128 }
03f5c686 3129
4562236b
HW
3130 break;
3131 }
3132 }
3133
d0778ebf 3134 ddc_service_set_dongle_type(link->ddc, link->dpcd_caps.dongle_type);
4562236b 3135
4562236b
HW
3136 {
3137 struct dp_sink_hw_fw_revision dp_hw_fw_revision;
3138
3139 core_link_read_dpcd(
3140 link,
3a340294 3141 DP_BRANCH_REVISION_START,
4562236b
HW
3142 (uint8_t *)&dp_hw_fw_revision,
3143 sizeof(dp_hw_fw_revision));
3144
3145 link->dpcd_caps.branch_hw_revision =
3146 dp_hw_fw_revision.ieee_hw_rev;
4b99affb
A
3147
3148 memmove(
3149 link->dpcd_caps.branch_fw_revision,
3150 dp_hw_fw_revision.ieee_fw_rev,
3151 sizeof(dp_hw_fw_revision.ieee_fw_rev));
4562236b
HW
3152 }
3153}
3154
d0778ebf 3155static void dp_wa_power_up_0010FA(struct dc_link *link, uint8_t *dpcd_data,
4562236b
HW
3156 int length)
3157{
3158 int retry = 0;
4562236b
HW
3159
3160 if (!link->dpcd_caps.dpcd_rev.raw) {
3161 do {
3162 dp_receiver_power_ctrl(link, true);
3a340294 3163 core_link_read_dpcd(link, DP_DPCD_REV,
4562236b
HW
3164 dpcd_data, length);
3165 link->dpcd_caps.dpcd_rev.raw = dpcd_data[
3a340294
DA
3166 DP_DPCD_REV -
3167 DP_DPCD_REV];
4562236b
HW
3168 } while (retry++ < 4 && !link->dpcd_caps.dpcd_rev.raw);
3169 }
3170
4562236b
HW
3171 if (link->dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_VGA_CONVERTER) {
3172 switch (link->dpcd_caps.branch_dev_id) {
df3b7e32 3173 /* 0010FA active dongles (DP-VGA, DP-DLDVI converters) power down
4562236b
HW
3174 * all internal circuits including AUX communication preventing
3175 * reading DPCD table and EDID (spec violation).
3176 * Encoder will skip DP RX power down on disable_output to
3177 * keep receiver powered all the time.*/
df3b7e32
QZ
3178 case DP_BRANCH_DEVICE_ID_0010FA:
3179 case DP_BRANCH_DEVICE_ID_0080E1:
566b4252 3180 case DP_BRANCH_DEVICE_ID_00E04C:
4562236b
HW
3181 link->wa_flags.dp_keep_receiver_powered = true;
3182 break;
3183
3184 /* TODO: May need work around for other dongles. */
3185 default:
3186 link->wa_flags.dp_keep_receiver_powered = false;
3187 break;
3188 }
3189 } else
3190 link->wa_flags.dp_keep_receiver_powered = false;
3191}
3192
96577cf8
HW
3193/* Read additional sink caps defined in source specific DPCD area
3194 * This function currently only reads from SinkCapability address (DP_SOURCE_SINK_CAP)
3195 */
3196static bool dpcd_read_sink_ext_caps(struct dc_link *link)
3197{
3198 uint8_t dpcd_data;
3199
3200 if (!link)
3201 return false;
3202
3203 if (core_link_read_dpcd(link, DP_SOURCE_SINK_CAP, &dpcd_data, 1) != DC_OK)
3204 return false;
3205
3206 link->dpcd_sink_ext_caps.raw = dpcd_data;
3207 return true;
3208}
3209
cdb39798 3210static bool retrieve_link_cap(struct dc_link *link)
4562236b 3211{
61aa7a6f 3212 /* DP_ADAPTER_CAP - DP_DPCD_REV + 1 == 16 and also DP_DSC_BITS_PER_PIXEL_INC - DP_DSC_SUPPORT + 1 == 16,
3213 * which means size 16 will be good for both of those DPCD register block reads
3214 */
3215 uint8_t dpcd_data[16];
3216 uint8_t lttpr_dpcd_data[6];
4562236b 3217
3c7dd2cb
HT
3218 /*Only need to read 1 byte starting from DP_DPRX_FEATURE_ENUMERATION_LIST.
3219 */
3220 uint8_t dpcd_dprx_data = '\0';
8633d96d 3221 uint8_t dpcd_power_state = '\0';
3c7dd2cb 3222
8ca80900 3223 struct dp_device_vendor_id sink_id;
4562236b
HW
3224 union down_stream_port_count down_strm_port_count;
3225 union edp_configuration_cap edp_config_cap;
3226 union dp_downstream_port_present ds_port = { 0 };
cdb39798 3227 enum dc_status status = DC_ERROR_UNEXPECTED;
3c1a312a
YS
3228 uint32_t read_dpcd_retry_cnt = 3;
3229 int i;
4b99affb 3230 struct dp_sink_hw_fw_revision dp_hw_fw_revision;
4562236b 3231
8e5100a5 3232 /* Set default timeout to 3.2ms and read LTTPR capabilities */
3233 bool ext_timeout_support = link->dc->caps.extended_aux_timeout_support &&
3234 !link->dc->config.disable_extended_timeout_support;
bad7ab0b 3235
903e859b 3236 link->is_lttpr_mode_transparent = true;
3237
8e5100a5 3238 if (ext_timeout_support) {
61aa7a6f 3239 dc_link_aux_configure_timeout(link->ddc,
3240 LINK_AUX_DEFAULT_EXTENDED_TIMEOUT_PERIOD);
8e5100a5 3241 }
3242
4562236b 3243 memset(dpcd_data, '\0', sizeof(dpcd_data));
61aa7a6f 3244 memset(lttpr_dpcd_data, '\0', sizeof(lttpr_dpcd_data));
4562236b
HW
3245 memset(&down_strm_port_count,
3246 '\0', sizeof(union down_stream_port_count));
3247 memset(&edp_config_cap, '\0',
3248 sizeof(union edp_configuration_cap));
3249
8633d96d
AK
3250 status = core_link_read_dpcd(link, DP_SET_POWER,
3251 &dpcd_power_state, sizeof(dpcd_power_state));
3252
3253 /* Delay 1 ms if AUX CH is in power down state. Based on spec
3254 * section 2.3.1.2, if AUX CH may be powered down due to
3255 * write to DPCD 600h = 2. Sink AUX CH is monitoring differential
3256 * signal and may need up to 1 ms before being able to reply.
3257 */
3258 if (status != DC_OK || dpcd_power_state == DP_SET_POWER_D3)
3259 udelay(1000);
3260
3c1a312a
YS
3261 for (i = 0; i < read_dpcd_retry_cnt; i++) {
3262 status = core_link_read_dpcd(
3263 link,
3264 DP_DPCD_REV,
3265 dpcd_data,
3266 sizeof(dpcd_data));
3267 if (status == DC_OK)
3268 break;
3269 }
cdb39798
YS
3270
3271 if (status != DC_OK) {
3272 dm_error("%s: Read dpcd data failed.\n", __func__);
3273 return false;
3274 }
4562236b 3275
9bffd080 3276 if (ext_timeout_support) {
61aa7a6f 3277
8e5100a5 3278 status = core_link_read_dpcd(
3279 link,
61aa7a6f 3280 DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV,
3281 lttpr_dpcd_data,
3282 sizeof(lttpr_dpcd_data));
3283
3284 link->dpcd_caps.lttpr_caps.revision.raw =
3285 lttpr_dpcd_data[DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV -
3286 DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV];
3287
3288 link->dpcd_caps.lttpr_caps.max_link_rate =
3289 lttpr_dpcd_data[DP_MAX_LINK_RATE_PHY_REPEATER -
3290 DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV];
3291
3292 link->dpcd_caps.lttpr_caps.phy_repeater_cnt =
3293 lttpr_dpcd_data[DP_PHY_REPEATER_CNT -
3294 DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV];
3295
3296 link->dpcd_caps.lttpr_caps.max_lane_count =
3297 lttpr_dpcd_data[DP_MAX_LANE_COUNT_PHY_REPEATER -
3298 DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV];
3299
3300 link->dpcd_caps.lttpr_caps.mode =
3301 lttpr_dpcd_data[DP_PHY_REPEATER_MODE -
3302 DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV];
3303
3304 link->dpcd_caps.lttpr_caps.max_ext_timeout =
3305 lttpr_dpcd_data[DP_PHY_REPEATER_EXTENDED_WAIT_TIMEOUT -
3306 DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV];
3307
3308 if (link->dpcd_caps.lttpr_caps.phy_repeater_cnt > 0 &&
3309 link->dpcd_caps.lttpr_caps.max_lane_count > 0 &&
3310 link->dpcd_caps.lttpr_caps.max_lane_count <= 4 &&
3311 link->dpcd_caps.lttpr_caps.revision.raw >= 0x14) {
8e5100a5 3312 link->is_lttpr_mode_transparent = false;
8e5100a5 3313 } else {
61aa7a6f 3314 /*No lttpr reset timeout to its default value*/
3315 link->is_lttpr_mode_transparent = true;
3316 dc_link_aux_configure_timeout(link->ddc, LINK_AUX_DEFAULT_TIMEOUT_PERIOD);
8e5100a5 3317 }
460adc6b 3318
3319 CONN_DATA_DETECT(link, lttpr_dpcd_data, sizeof(lttpr_dpcd_data), "LTTPR Caps: ");
8e5100a5 3320 }
3321
4562236b
HW
3322 {
3323 union training_aux_rd_interval aux_rd_interval;
3324
3325 aux_rd_interval.raw =
3a340294 3326 dpcd_data[DP_TRAINING_AUX_RD_INTERVAL];
4562236b 3327
3c7dd2cb 3328 link->dpcd_caps.ext_receiver_cap_field_present =
b239b59b 3329 aux_rd_interval.bits.EXT_RECEIVER_CAP_FIELD_PRESENT == 1;
3c7dd2cb
HT
3330
3331 if (aux_rd_interval.bits.EXT_RECEIVER_CAP_FIELD_PRESENT == 1) {
818832bf
XY
3332 uint8_t ext_cap_data[16];
3333
3334 memset(ext_cap_data, '\0', sizeof(ext_cap_data));
3335 for (i = 0; i < read_dpcd_retry_cnt; i++) {
3336 status = core_link_read_dpcd(
4562236b 3337 link,
3a340294 3338 DP_DP13_DPCD_REV,
818832bf
XY
3339 ext_cap_data,
3340 sizeof(ext_cap_data));
3341 if (status == DC_OK) {
3342 memcpy(dpcd_data, ext_cap_data, sizeof(dpcd_data));
3343 break;
3344 }
3345 }
3346 if (status != DC_OK)
3347 dm_error("%s: Read extend caps data failed, use cap from dpcd 0.\n", __func__);
4562236b
HW
3348 }
3349 }
3350
3c7dd2cb
HT
3351 link->dpcd_caps.dpcd_rev.raw =
3352 dpcd_data[DP_DPCD_REV - DP_DPCD_REV];
3353
3354 if (link->dpcd_caps.dpcd_rev.raw >= 0x14) {
3355 for (i = 0; i < read_dpcd_retry_cnt; i++) {
3356 status = core_link_read_dpcd(
3357 link,
3358 DP_DPRX_FEATURE_ENUMERATION_LIST,
3359 &dpcd_dprx_data,
3360 sizeof(dpcd_dprx_data));
3361 if (status == DC_OK)
3362 break;
3363 }
3364
3365 link->dpcd_caps.dprx_feature.raw = dpcd_dprx_data;
3366
3367 if (status != DC_OK)
3368 dm_error("%s: Read DPRX caps data failed.\n", __func__);
3369 }
3370
3371 else {
3372 link->dpcd_caps.dprx_feature.raw = 0;
3373 }
3374
3375
07d6a199
AK
3376 /* Error condition checking...
3377 * It is impossible for Sink to report Max Lane Count = 0.
3378 * It is possible for Sink to report Max Link Rate = 0, if it is
3379 * an eDP device that is reporting specialized link rates in the
3380 * SUPPORTED_LINK_RATE table.
3381 */
3382 if (dpcd_data[DP_MAX_LANE_COUNT - DP_DPCD_REV] == 0)
3383 return false;
3384
3a340294
DA
3385 ds_port.byte = dpcd_data[DP_DOWNSTREAMPORT_PRESENT -
3386 DP_DPCD_REV];
4562236b 3387
ee13cea9
JB
3388 read_dp_device_vendor_id(link);
3389
4562236b
HW
3390 get_active_converter_info(ds_port.byte, link);
3391
3392 dp_wa_power_up_0010FA(link, dpcd_data, sizeof(dpcd_data));
3393
98e6436d
AK
3394 down_strm_port_count.raw = dpcd_data[DP_DOWN_STREAM_PORT_COUNT -
3395 DP_DPCD_REV];
3396
4562236b
HW
3397 link->dpcd_caps.allow_invalid_MSA_timing_param =
3398 down_strm_port_count.bits.IGNORE_MSA_TIMING_PARAM;
3399
3400 link->dpcd_caps.max_ln_count.raw = dpcd_data[
3a340294 3401 DP_MAX_LANE_COUNT - DP_DPCD_REV];
4562236b
HW
3402
3403 link->dpcd_caps.max_down_spread.raw = dpcd_data[
3a340294 3404 DP_MAX_DOWNSPREAD - DP_DPCD_REV];
4562236b 3405
d0778ebf 3406 link->reported_link_cap.lane_count =
4562236b 3407 link->dpcd_caps.max_ln_count.bits.MAX_LANE_COUNT;
d0778ebf 3408 link->reported_link_cap.link_rate = dpcd_data[
3a340294 3409 DP_MAX_LINK_RATE - DP_DPCD_REV];
d0778ebf 3410 link->reported_link_cap.link_spread =
4562236b
HW
3411 link->dpcd_caps.max_down_spread.bits.MAX_DOWN_SPREAD ?
3412 LINK_SPREAD_05_DOWNSPREAD_30KHZ : LINK_SPREAD_DISABLED;
3413
3414 edp_config_cap.raw = dpcd_data[
3a340294 3415 DP_EDP_CONFIGURATION_CAP - DP_DPCD_REV];
4562236b
HW
3416 link->dpcd_caps.panel_mode_edp =
3417 edp_config_cap.bits.ALT_SCRAMBLER_RESET;
9799624a
WL
3418 link->dpcd_caps.dpcd_display_control_capable =
3419 edp_config_cap.bits.DPCD_DISPLAY_CONTROL_CAPABLE;
4562236b 3420
d0778ebf
HW
3421 link->test_pattern_enabled = false;
3422 link->compliance_test_state.raw = 0;
4562236b 3423
4562236b
HW
3424 /* read sink count */
3425 core_link_read_dpcd(link,
3a340294 3426 DP_SINK_COUNT,
4562236b
HW
3427 &link->dpcd_caps.sink_count.raw,
3428 sizeof(link->dpcd_caps.sink_count.raw));
3429
8ca80900
AK
3430 /* read sink ieee oui */
3431 core_link_read_dpcd(link,
3432 DP_SINK_OUI,
3433 (uint8_t *)(&sink_id),
3434 sizeof(sink_id));
3435
3436 link->dpcd_caps.sink_dev_id =
3437 (sink_id.ieee_oui[0] << 16) +
3438 (sink_id.ieee_oui[1] << 8) +
3439 (sink_id.ieee_oui[2]);
3440
4b99affb
A
3441 memmove(
3442 link->dpcd_caps.sink_dev_id_str,
3443 sink_id.ieee_device_id,
3444 sizeof(sink_id.ieee_device_id));
3445
473e3f77
MK
3446 /* Quirk Apple MBP 2017 15" Retina panel: Wrong DP_MAX_LINK_RATE */
3447 {
3448 uint8_t str_mbp_2017[] = { 101, 68, 21, 101, 98, 97 };
3449
3450 if ((link->dpcd_caps.sink_dev_id == 0x0010fa) &&
3451 !memcmp(link->dpcd_caps.sink_dev_id_str, str_mbp_2017,
3452 sizeof(str_mbp_2017))) {
3453 link->reported_link_cap.link_rate = 0x0c;
3454 }
3455 }
3456
4b99affb
A
3457 core_link_read_dpcd(
3458 link,
3459 DP_SINK_HW_REVISION_START,
3460 (uint8_t *)&dp_hw_fw_revision,
3461 sizeof(dp_hw_fw_revision));
3462
3463 link->dpcd_caps.sink_hw_revision =
3464 dp_hw_fw_revision.ieee_hw_rev;
3465
3466 memmove(
3467 link->dpcd_caps.sink_fw_revision,
3468 dp_hw_fw_revision.ieee_fw_rev,
3469 sizeof(dp_hw_fw_revision.ieee_fw_rev));
3470
39a4eb85
WL
3471 memset(&link->dpcd_caps.dsc_caps, '\0',
3472 sizeof(link->dpcd_caps.dsc_caps));
97bda032
HW
3473 memset(&link->dpcd_caps.fec_cap, '\0', sizeof(link->dpcd_caps.fec_cap));
3474 /* Read DSC and FEC sink capabilities if DP revision is 1.4 and up */
3475 if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_14) {
97bda032
HW
3476 status = core_link_read_dpcd(
3477 link,
3478 DP_FEC_CAPABILITY,
3479 &link->dpcd_caps.fec_cap.raw,
3480 sizeof(link->dpcd_caps.fec_cap.raw));
39a4eb85
WL
3481 status = core_link_read_dpcd(
3482 link,
3483 DP_DSC_SUPPORT,
3484 link->dpcd_caps.dsc_caps.dsc_basic_caps.raw,
3485 sizeof(link->dpcd_caps.dsc_caps.dsc_basic_caps.raw));
3486 status = core_link_read_dpcd(
3487 link,
3488 DP_DSC_BRANCH_OVERALL_THROUGHPUT_0,
3489 link->dpcd_caps.dsc_caps.dsc_ext_caps.raw,
3490 sizeof(link->dpcd_caps.dsc_caps.dsc_ext_caps.raw));
97bda032 3491 }
6fbefb84 3492
96577cf8
HW
3493 if (!dpcd_read_sink_ext_caps(link))
3494 link->dpcd_sink_ext_caps.raw = 0;
3495
4562236b
HW
3496 /* Connectivity log: detection */
3497 CONN_DATA_DETECT(link, dpcd_data, sizeof(dpcd_data), "Rx Caps: ");
cdb39798
YS
3498
3499 return true;
4562236b
HW
3500}
3501
8547058b
LH
3502bool dp_overwrite_extended_receiver_cap(struct dc_link *link)
3503{
3504 uint8_t dpcd_data[16];
3505 uint32_t read_dpcd_retry_cnt = 3;
3506 enum dc_status status = DC_ERROR_UNEXPECTED;
3507 union dp_downstream_port_present ds_port = { 0 };
3508 union down_stream_port_count down_strm_port_count;
3509 union edp_configuration_cap edp_config_cap;
3510
3511 int i;
3512
3513 for (i = 0; i < read_dpcd_retry_cnt; i++) {
3514 status = core_link_read_dpcd(
3515 link,
3516 DP_DPCD_REV,
3517 dpcd_data,
3518 sizeof(dpcd_data));
3519 if (status == DC_OK)
3520 break;
3521 }
3522
3523 link->dpcd_caps.dpcd_rev.raw =
3524 dpcd_data[DP_DPCD_REV - DP_DPCD_REV];
3525
3526 if (dpcd_data[DP_MAX_LANE_COUNT - DP_DPCD_REV] == 0)
3527 return false;
3528
3529 ds_port.byte = dpcd_data[DP_DOWNSTREAMPORT_PRESENT -
3530 DP_DPCD_REV];
3531
3532 get_active_converter_info(ds_port.byte, link);
3533
3534 down_strm_port_count.raw = dpcd_data[DP_DOWN_STREAM_PORT_COUNT -
3535 DP_DPCD_REV];
3536
3537 link->dpcd_caps.allow_invalid_MSA_timing_param =
3538 down_strm_port_count.bits.IGNORE_MSA_TIMING_PARAM;
3539
3540 link->dpcd_caps.max_ln_count.raw = dpcd_data[
3541 DP_MAX_LANE_COUNT - DP_DPCD_REV];
3542
3543 link->dpcd_caps.max_down_spread.raw = dpcd_data[
3544 DP_MAX_DOWNSPREAD - DP_DPCD_REV];
3545
3546 link->reported_link_cap.lane_count =
3547 link->dpcd_caps.max_ln_count.bits.MAX_LANE_COUNT;
3548 link->reported_link_cap.link_rate = dpcd_data[
3549 DP_MAX_LINK_RATE - DP_DPCD_REV];
3550 link->reported_link_cap.link_spread =
3551 link->dpcd_caps.max_down_spread.bits.MAX_DOWN_SPREAD ?
3552 LINK_SPREAD_05_DOWNSPREAD_30KHZ : LINK_SPREAD_DISABLED;
3553
3554 edp_config_cap.raw = dpcd_data[
3555 DP_EDP_CONFIGURATION_CAP - DP_DPCD_REV];
3556 link->dpcd_caps.panel_mode_edp =
3557 edp_config_cap.bits.ALT_SCRAMBLER_RESET;
3558 link->dpcd_caps.dpcd_display_control_capable =
3559 edp_config_cap.bits.DPCD_DISPLAY_CONTROL_CAPABLE;
3560
3561 return true;
3562}
3563
cdb39798 3564bool detect_dp_sink_caps(struct dc_link *link)
4562236b 3565{
cdb39798 3566 return retrieve_link_cap(link);
4562236b
HW
3567
3568 /* dc init_hw has power encoder using default
3569 * signal for connector. For native DP, no
3570 * need to power up encoder again. If not native
3571 * DP, hw_init may need check signal or power up
3572 * encoder here.
3573 */
4562236b
HW
3574 /* TODO save sink caps in link->sink */
3575}
3576
b03a599b
DL
3577enum dc_link_rate linkRateInKHzToLinkRateMultiplier(uint32_t link_rate_in_khz)
3578{
3579 enum dc_link_rate link_rate;
3580 // LinkRate is normally stored as a multiplier of 0.27 Gbps per lane. Do the translation.
3581 switch (link_rate_in_khz) {
3582 case 1620000:
3583 link_rate = LINK_RATE_LOW; // Rate_1 (RBR) - 1.62 Gbps/Lane
3584 break;
3585 case 2160000:
3586 link_rate = LINK_RATE_RATE_2; // Rate_2 - 2.16 Gbps/Lane
3587 break;
3588 case 2430000:
3589 link_rate = LINK_RATE_RATE_3; // Rate_3 - 2.43 Gbps/Lane
3590 break;
3591 case 2700000:
3592 link_rate = LINK_RATE_HIGH; // Rate_4 (HBR) - 2.70 Gbps/Lane
3593 break;
3594 case 3240000:
3595 link_rate = LINK_RATE_RBR2; // Rate_5 (RBR2) - 3.24 Gbps/Lane
3596 break;
3597 case 4320000:
3598 link_rate = LINK_RATE_RATE_6; // Rate_6 - 4.32 Gbps/Lane
3599 break;
3600 case 5400000:
3601 link_rate = LINK_RATE_HIGH2; // Rate_7 (HBR2) - 5.40 Gbps/Lane
3602 break;
3603 case 8100000:
3604 link_rate = LINK_RATE_HIGH3; // Rate_8 (HBR3) - 8.10 Gbps/Lane
3605 break;
3606 default:
3607 link_rate = LINK_RATE_UNKNOWN;
3608 break;
3609 }
3610 return link_rate;
3611}
3612
4654a2f7
RL
3613void detect_edp_sink_caps(struct dc_link *link)
3614{
8628d02f 3615 uint8_t supported_link_rates[16];
b03a599b
DL
3616 uint32_t entry;
3617 uint32_t link_rate_in_khz;
3618 enum dc_link_rate link_rate = LINK_RATE_UNKNOWN;
48231fd5 3619
b03a599b 3620 retrieve_link_cap(link);
8628d02f
JP
3621 link->dpcd_caps.edp_supported_link_rates_count = 0;
3622 memset(supported_link_rates, 0, sizeof(supported_link_rates));
48231fd5 3623
8628d02f 3624 if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_14 &&
53c81fc7
WC
3625 (link->dc->config.optimize_edp_link_rate ||
3626 link->reported_link_cap.link_rate == LINK_RATE_UNKNOWN)) {
b03a599b
DL
3627 // Read DPCD 00010h - 0001Fh 16 bytes at one shot
3628 core_link_read_dpcd(link, DP_SUPPORTED_LINK_RATES,
3629 supported_link_rates, sizeof(supported_link_rates));
3630
b03a599b
DL
3631 for (entry = 0; entry < 16; entry += 2) {
3632 // DPCD register reports per-lane link rate = 16-bit link rate capability
8628d02f 3633 // value X 200 kHz. Need multiplier to find link rate in kHz.
b03a599b
DL
3634 link_rate_in_khz = (supported_link_rates[entry+1] * 0x100 +
3635 supported_link_rates[entry]) * 200;
3636
3637 if (link_rate_in_khz != 0) {
3638 link_rate = linkRateInKHzToLinkRateMultiplier(link_rate_in_khz);
8628d02f
JP
3639 link->dpcd_caps.edp_supported_link_rates[link->dpcd_caps.edp_supported_link_rates_count] = link_rate;
3640 link->dpcd_caps.edp_supported_link_rates_count++;
53c81fc7
WC
3641
3642 if (link->reported_link_cap.link_rate < link_rate)
3643 link->reported_link_cap.link_rate = link_rate;
b03a599b
DL
3644 }
3645 }
3646 }
4654a2f7 3647 link->verified_link_cap = link->reported_link_cap;
96577cf8
HW
3648
3649 dc_link_set_default_brightness_aux(link);
4654a2f7
RL
3650}
3651
4562236b
HW
3652void dc_link_dp_enable_hpd(const struct dc_link *link)
3653{
d0778ebf 3654 struct link_encoder *encoder = link->link_enc;
4562236b
HW
3655
3656 if (encoder != NULL && encoder->funcs->enable_hpd != NULL)
3657 encoder->funcs->enable_hpd(encoder);
3658}
3659
3660void dc_link_dp_disable_hpd(const struct dc_link *link)
3661{
d0778ebf 3662 struct link_encoder *encoder = link->link_enc;
4562236b
HW
3663
3664 if (encoder != NULL && encoder->funcs->enable_hpd != NULL)
3665 encoder->funcs->disable_hpd(encoder);
3666}
3667
3668static bool is_dp_phy_pattern(enum dp_test_pattern test_pattern)
3669{
0e19401f
TC
3670 if ((DP_TEST_PATTERN_PHY_PATTERN_BEGIN <= test_pattern &&
3671 test_pattern <= DP_TEST_PATTERN_PHY_PATTERN_END) ||
3672 test_pattern == DP_TEST_PATTERN_VIDEO_MODE)
4562236b
HW
3673 return true;
3674 else
3675 return false;
3676}
3677
d0778ebf 3678static void set_crtc_test_pattern(struct dc_link *link,
4562236b 3679 struct pipe_ctx *pipe_ctx,
2057b7e1
WL
3680 enum dp_test_pattern test_pattern,
3681 enum dp_test_pattern_color_space test_pattern_color_space)
4562236b
HW
3682{
3683 enum controller_dp_test_pattern controller_test_pattern;
3684 enum dc_color_depth color_depth = pipe_ctx->
4fa086b9 3685 stream->timing.display_color_depth;
4562236b 3686 struct bit_depth_reduction_params params;
661a8cd9 3687 struct output_pixel_processor *opp = pipe_ctx->stream_res.opp;
6fbefb84
HW
3688 int width = pipe_ctx->stream->timing.h_addressable +
3689 pipe_ctx->stream->timing.h_border_left +
3690 pipe_ctx->stream->timing.h_border_right;
3691 int height = pipe_ctx->stream->timing.v_addressable +
3692 pipe_ctx->stream->timing.v_border_bottom +
3693 pipe_ctx->stream->timing.v_border_top;
4562236b
HW
3694
3695 memset(&params, 0, sizeof(params));
3696
3697 switch (test_pattern) {
3698 case DP_TEST_PATTERN_COLOR_SQUARES:
3699 controller_test_pattern =
3700 CONTROLLER_DP_TEST_PATTERN_COLORSQUARES;
3701 break;
3702 case DP_TEST_PATTERN_COLOR_SQUARES_CEA:
3703 controller_test_pattern =
3704 CONTROLLER_DP_TEST_PATTERN_COLORSQUARES_CEA;
3705 break;
3706 case DP_TEST_PATTERN_VERTICAL_BARS:
3707 controller_test_pattern =
3708 CONTROLLER_DP_TEST_PATTERN_VERTICALBARS;
3709 break;
3710 case DP_TEST_PATTERN_HORIZONTAL_BARS:
3711 controller_test_pattern =
3712 CONTROLLER_DP_TEST_PATTERN_HORIZONTALBARS;
3713 break;
3714 case DP_TEST_PATTERN_COLOR_RAMP:
3715 controller_test_pattern =
3716 CONTROLLER_DP_TEST_PATTERN_COLORRAMP;
3717 break;
3718 default:
3719 controller_test_pattern =
3720 CONTROLLER_DP_TEST_PATTERN_VIDEOMODE;
3721 break;
3722 }
3723
3724 switch (test_pattern) {
3725 case DP_TEST_PATTERN_COLOR_SQUARES:
3726 case DP_TEST_PATTERN_COLOR_SQUARES_CEA:
3727 case DP_TEST_PATTERN_VERTICAL_BARS:
3728 case DP_TEST_PATTERN_HORIZONTAL_BARS:
3729 case DP_TEST_PATTERN_COLOR_RAMP:
3730 {
3731 /* disable bit depth reduction */
3732 pipe_ctx->stream->bit_depth_params = params;
661a8cd9 3733 opp->funcs->opp_program_bit_depth_reduction(opp, &params);
7f93c1de
CL
3734 if (pipe_ctx->stream_res.tg->funcs->set_test_pattern)
3735 pipe_ctx->stream_res.tg->funcs->set_test_pattern(pipe_ctx->stream_res.tg,
4562236b 3736 controller_test_pattern, color_depth);
6fbefb84 3737 else if (opp->funcs->opp_set_disp_pattern_generator) {
b1f6d01c 3738 struct pipe_ctx *odm_pipe;
2057b7e1 3739 enum controller_dp_color_space controller_color_space;
b1f6d01c 3740 int opp_cnt = 1;
10b4e64e
WL
3741 int offset = 0;
3742 int dpg_width = width;
6fbefb84 3743
2057b7e1
WL
3744 switch (test_pattern_color_space) {
3745 case DP_TEST_PATTERN_COLOR_SPACE_RGB:
3746 controller_color_space = CONTROLLER_DP_COLOR_SPACE_RGB;
3747 break;
3748 case DP_TEST_PATTERN_COLOR_SPACE_YCBCR601:
3749 controller_color_space = CONTROLLER_DP_COLOR_SPACE_YCBCR601;
3750 break;
3751 case DP_TEST_PATTERN_COLOR_SPACE_YCBCR709:
3752 controller_color_space = CONTROLLER_DP_COLOR_SPACE_YCBCR709;
3753 break;
3754 case DP_TEST_PATTERN_COLOR_SPACE_UNDEFINED:
3755 default:
3756 controller_color_space = CONTROLLER_DP_COLOR_SPACE_UDEFINED;
3757 DC_LOG_ERROR("%s: Color space must be defined for test pattern", __func__);
3758 ASSERT(0);
3759 break;
3760 }
3761
b1f6d01c
DL
3762 for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
3763 opp_cnt++;
10b4e64e
WL
3764 dpg_width = width / opp_cnt;
3765 offset = dpg_width;
6fbefb84 3766
10b4e64e
WL
3767 opp->funcs->opp_set_disp_pattern_generator(opp,
3768 controller_test_pattern,
3769 controller_color_space,
3770 color_depth,
3771 NULL,
3772 dpg_width,
3773 height,
3774 0);
b1f6d01c
DL
3775
3776 for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
3777 struct output_pixel_processor *odm_opp = odm_pipe->stream_res.opp;
b1f6d01c
DL
3778 odm_opp->funcs->opp_program_bit_depth_reduction(odm_opp, &params);
3779 odm_opp->funcs->opp_set_disp_pattern_generator(odm_opp,
6fbefb84 3780 controller_test_pattern,
2057b7e1 3781 controller_color_space,
6fbefb84
HW
3782 color_depth,
3783 NULL,
10b4e64e
WL
3784 dpg_width,
3785 height,
3786 offset);
3787 offset += offset;
6fbefb84 3788 }
6fbefb84 3789 }
4562236b
HW
3790 }
3791 break;
3792 case DP_TEST_PATTERN_VIDEO_MODE:
3793 {
3794 /* restore bitdepth reduction */
661a8cd9 3795 resource_build_bit_depth_reduction_params(pipe_ctx->stream, &params);
4562236b 3796 pipe_ctx->stream->bit_depth_params = params;
661a8cd9 3797 opp->funcs->opp_program_bit_depth_reduction(opp, &params);
7f93c1de
CL
3798 if (pipe_ctx->stream_res.tg->funcs->set_test_pattern)
3799 pipe_ctx->stream_res.tg->funcs->set_test_pattern(pipe_ctx->stream_res.tg,
4562236b
HW
3800 CONTROLLER_DP_TEST_PATTERN_VIDEOMODE,
3801 color_depth);
6fbefb84 3802 else if (opp->funcs->opp_set_disp_pattern_generator) {
b1f6d01c
DL
3803 struct pipe_ctx *odm_pipe;
3804 int opp_cnt = 1;
10b4e64e 3805 int dpg_width = width;
b1f6d01c
DL
3806
3807 for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
3808 opp_cnt++;
6fbefb84 3809
10b4e64e 3810 dpg_width = width / opp_cnt;
b1f6d01c
DL
3811 for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
3812 struct output_pixel_processor *odm_opp = odm_pipe->stream_res.opp;
6fbefb84 3813
b1f6d01c
DL
3814 odm_opp->funcs->opp_program_bit_depth_reduction(odm_opp, &params);
3815 odm_opp->funcs->opp_set_disp_pattern_generator(odm_opp,
6fbefb84 3816 CONTROLLER_DP_TEST_PATTERN_VIDEOMODE,
2057b7e1 3817 CONTROLLER_DP_COLOR_SPACE_UDEFINED,
6fbefb84
HW
3818 color_depth,
3819 NULL,
10b4e64e
WL
3820 dpg_width,
3821 height,
3822 0);
6fbefb84
HW
3823 }
3824 opp->funcs->opp_set_disp_pattern_generator(opp,
3825 CONTROLLER_DP_TEST_PATTERN_VIDEOMODE,
2057b7e1 3826 CONTROLLER_DP_COLOR_SPACE_UDEFINED,
6fbefb84
HW
3827 color_depth,
3828 NULL,
10b4e64e
WL
3829 dpg_width,
3830 height,
3831 0);
6fbefb84 3832 }
4562236b
HW
3833 }
3834 break;
3835
3836 default:
3837 break;
3838 }
3839}
3840
3841bool dc_link_dp_set_test_pattern(
d0778ebf 3842 struct dc_link *link,
4562236b 3843 enum dp_test_pattern test_pattern,
2057b7e1 3844 enum dp_test_pattern_color_space test_pattern_color_space,
4562236b
HW
3845 const struct link_training_settings *p_link_settings,
3846 const unsigned char *p_custom_pattern,
3847 unsigned int cust_pattern_size)
3848{
608ac7bb 3849 struct pipe_ctx *pipes = link->dc->current_state->res_ctx.pipe_ctx;
0a8f43ff 3850 struct pipe_ctx *pipe_ctx = &pipes[0];
4562236b
HW
3851 unsigned int lane;
3852 unsigned int i;
3853 unsigned char link_qual_pattern[LANE_COUNT_DP_MAX] = {0};
3854 union dpcd_training_pattern training_pattern;
4562236b
HW
3855 enum dpcd_phy_test_patterns pattern;
3856
3857 memset(&training_pattern, 0, sizeof(training_pattern));
4562236b
HW
3858
3859 for (i = 0; i < MAX_PIPES; i++) {
24d01c9b 3860 if (pipes[i].stream->link == link && !pipes[i].top_pipe && !pipes[i].prev_odm_pipe) {
0a8f43ff 3861 pipe_ctx = &pipes[i];
4562236b
HW
3862 break;
3863 }
3864 }
3865
3866 /* Reset CRTC Test Pattern if it is currently running and request
3867 * is VideoMode Reset DP Phy Test Pattern if it is currently running
3868 * and request is VideoMode
3869 */
d0778ebf 3870 if (link->test_pattern_enabled && test_pattern ==
4562236b
HW
3871 DP_TEST_PATTERN_VIDEO_MODE) {
3872 /* Set CRTC Test Pattern */
2057b7e1 3873 set_crtc_test_pattern(link, pipe_ctx, test_pattern, test_pattern_color_space);
d0778ebf 3874 dp_set_hw_test_pattern(link, test_pattern,
4562236b
HW
3875 (uint8_t *)p_custom_pattern,
3876 (uint32_t)cust_pattern_size);
3877
3878 /* Unblank Stream */
d0778ebf 3879 link->dc->hwss.unblank_stream(
0a8f43ff 3880 pipe_ctx,
d0778ebf 3881 &link->verified_link_cap);
4562236b
HW
3882 /* TODO:m_pHwss->MuteAudioEndpoint
3883 * (pPathMode->pDisplayPath, false);
3884 */
3885
3886 /* Reset Test Pattern state */
d0778ebf 3887 link->test_pattern_enabled = false;
4562236b
HW
3888
3889 return true;
3890 }
3891
3892 /* Check for PHY Test Patterns */
3893 if (is_dp_phy_pattern(test_pattern)) {
3894 /* Set DPCD Lane Settings before running test pattern */
3895 if (p_link_settings != NULL) {
64c12b73 3896 dp_set_hw_lane_settings(link, p_link_settings, DPRX);
3897 dpcd_set_lane_settings(link, p_link_settings, DPRX);
4562236b
HW
3898 }
3899
3900 /* Blank stream if running test pattern */
3901 if (test_pattern != DP_TEST_PATTERN_VIDEO_MODE) {
3902 /*TODO:
3903 * m_pHwss->
3904 * MuteAudioEndpoint(pPathMode->pDisplayPath, true);
3905 */
3906 /* Blank stream */
8e9c4c8c 3907 pipes->stream_res.stream_enc->funcs->dp_blank(pipe_ctx->stream_res.stream_enc);
4562236b
HW
3908 }
3909
d0778ebf 3910 dp_set_hw_test_pattern(link, test_pattern,
4562236b
HW
3911 (uint8_t *)p_custom_pattern,
3912 (uint32_t)cust_pattern_size);
3913
3914 if (test_pattern != DP_TEST_PATTERN_VIDEO_MODE) {
3915 /* Set Test Pattern state */
d0778ebf 3916 link->test_pattern_enabled = true;
4562236b 3917 if (p_link_settings != NULL)
d0778ebf 3918 dpcd_set_link_settings(link,
4562236b
HW
3919 p_link_settings);
3920 }
3921
3922 switch (test_pattern) {
3923 case DP_TEST_PATTERN_VIDEO_MODE:
3924 pattern = PHY_TEST_PATTERN_NONE;
0e19401f 3925 break;
4562236b
HW
3926 case DP_TEST_PATTERN_D102:
3927 pattern = PHY_TEST_PATTERN_D10_2;
0e19401f 3928 break;
4562236b
HW
3929 case DP_TEST_PATTERN_SYMBOL_ERROR:
3930 pattern = PHY_TEST_PATTERN_SYMBOL_ERROR;
0e19401f 3931 break;
4562236b
HW
3932 case DP_TEST_PATTERN_PRBS7:
3933 pattern = PHY_TEST_PATTERN_PRBS7;
0e19401f 3934 break;
4562236b
HW
3935 case DP_TEST_PATTERN_80BIT_CUSTOM:
3936 pattern = PHY_TEST_PATTERN_80BIT_CUSTOM;
0e19401f
TC
3937 break;
3938 case DP_TEST_PATTERN_CP2520_1:
3939 pattern = PHY_TEST_PATTERN_CP2520_1;
3940 break;
3941 case DP_TEST_PATTERN_CP2520_2:
3942 pattern = PHY_TEST_PATTERN_CP2520_2;
3943 break;
3944 case DP_TEST_PATTERN_CP2520_3:
3945 pattern = PHY_TEST_PATTERN_CP2520_3;
3946 break;
4562236b
HW
3947 default:
3948 return false;
3949 }
3950
3951 if (test_pattern == DP_TEST_PATTERN_VIDEO_MODE
3952 /*TODO:&& !pPathMode->pDisplayPath->IsTargetPoweredOn()*/)
3953 return false;
3954
d0778ebf 3955 if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_12) {
4562236b
HW
3956 /* tell receiver that we are sending qualification
3957 * pattern DP 1.2 or later - DP receiver's link quality
3958 * pattern is set using DPCD LINK_QUAL_LANEx_SET
3959 * register (0x10B~0x10E)\
3960 */
3961 for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++)
3962 link_qual_pattern[lane] =
3963 (unsigned char)(pattern);
3964
d0778ebf 3965 core_link_write_dpcd(link,
3a340294 3966 DP_LINK_QUAL_LANE0_SET,
4562236b
HW
3967 link_qual_pattern,
3968 sizeof(link_qual_pattern));
d0778ebf
HW
3969 } else if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_10 ||
3970 link->dpcd_caps.dpcd_rev.raw == 0) {
4562236b
HW
3971 /* tell receiver that we are sending qualification
3972 * pattern DP 1.1a or earlier - DP receiver's link
3973 * quality pattern is set using
3974 * DPCD TRAINING_PATTERN_SET -> LINK_QUAL_PATTERN_SET
3975 * register (0x102). We will use v_1.3 when we are
3976 * setting test pattern for DP 1.1.
3977 */
d0778ebf
HW
3978 core_link_read_dpcd(link, DP_TRAINING_PATTERN_SET,
3979 &training_pattern.raw,
3980 sizeof(training_pattern));
4562236b 3981 training_pattern.v1_3.LINK_QUAL_PATTERN_SET = pattern;
d0778ebf
HW
3982 core_link_write_dpcd(link, DP_TRAINING_PATTERN_SET,
3983 &training_pattern.raw,
3984 sizeof(training_pattern));
4562236b
HW
3985 }
3986 } else {
43563bc2 3987 enum dc_color_space color_space = COLOR_SPACE_UNKNOWN;
43563bc2
WL
3988
3989 switch (test_pattern_color_space) {
3990 case DP_TEST_PATTERN_COLOR_SPACE_RGB:
3991 color_space = COLOR_SPACE_SRGB;
3992 if (test_pattern == DP_TEST_PATTERN_COLOR_SQUARES_CEA)
3993 color_space = COLOR_SPACE_SRGB_LIMITED;
3994 break;
3995
3996 case DP_TEST_PATTERN_COLOR_SPACE_YCBCR601:
3997 color_space = COLOR_SPACE_YCBCR601;
3998 if (test_pattern == DP_TEST_PATTERN_COLOR_SQUARES_CEA)
3999 color_space = COLOR_SPACE_YCBCR601_LIMITED;
4000 break;
4001 case DP_TEST_PATTERN_COLOR_SPACE_YCBCR709:
4002 color_space = COLOR_SPACE_YCBCR709;
4003 if (test_pattern == DP_TEST_PATTERN_COLOR_SQUARES_CEA)
4004 color_space = COLOR_SPACE_YCBCR709_LIMITED;
4005 break;
4006 default:
4007 break;
4008 }
e8f9ecf2
WL
4009
4010 if (pipe_ctx->stream_res.tg->funcs->lock_doublebuffer_enable)
4011 pipe_ctx->stream_res.tg->funcs->lock_doublebuffer_enable(
4012 pipe_ctx->stream_res.tg);
4013 pipe_ctx->stream_res.tg->funcs->lock(pipe_ctx->stream_res.tg);
43563bc2
WL
4014 /* update MSA to requested color space */
4015 pipe_ctx->stream_res.stream_enc->funcs->dp_set_stream_attribute(pipe_ctx->stream_res.stream_enc,
4016 &pipe_ctx->stream->timing,
23bc5f34
WL
4017 color_space,
4018 pipe_ctx->stream->use_vsc_sdp_for_colorimetry,
4019 link->dpcd_caps.dprx_feature.bits.SST_SPLIT_SDP_CAP);
43563bc2 4020
e8f9ecf2
WL
4021 if (pipe_ctx->stream->use_vsc_sdp_for_colorimetry) {
4022 if (test_pattern == DP_TEST_PATTERN_COLOR_SQUARES_CEA)
4023 pipe_ctx->stream->vsc_infopacket.sb[17] |= (1 << 7); // sb17 bit 7 Dynamic Range: 0 = VESA range, 1 = CTA range
4024 else
4025 pipe_ctx->stream->vsc_infopacket.sb[17] &= ~(1 << 7);
4026 resource_build_info_frame(pipe_ctx);
4027 link->dc->hwss.update_info_frame(pipe_ctx);
4028 }
4029
43563bc2 4030 /* CRTC Patterns */
2057b7e1 4031 set_crtc_test_pattern(link, pipe_ctx, test_pattern, test_pattern_color_space);
e8f9ecf2
WL
4032 pipe_ctx->stream_res.tg->funcs->unlock(pipe_ctx->stream_res.tg);
4033 pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg,
4034 CRTC_STATE_VACTIVE);
4035 pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg,
4036 CRTC_STATE_VBLANK);
4037 pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg,
4038 CRTC_STATE_VACTIVE);
4039 if (pipe_ctx->stream_res.tg->funcs->lock_doublebuffer_disable)
4040 pipe_ctx->stream_res.tg->funcs->lock_doublebuffer_disable(
4041 pipe_ctx->stream_res.tg);
4562236b 4042 /* Set Test Pattern state */
d0778ebf 4043 link->test_pattern_enabled = true;
4562236b
HW
4044 }
4045
4046 return true;
4047}
07c84c7a 4048
d0778ebf 4049void dp_enable_mst_on_sink(struct dc_link *link, bool enable)
07c84c7a
DW
4050{
4051 unsigned char mstmCntl;
4052
4053 core_link_read_dpcd(link, DP_MSTM_CTRL, &mstmCntl, 1);
4054 if (enable)
4055 mstmCntl |= DP_MST_EN;
4056 else
4057 mstmCntl &= (~DP_MST_EN);
4058
4059 core_link_write_dpcd(link, DP_MSTM_CTRL, &mstmCntl, 1);
4060}
6fbefb84 4061
0b226322
DG
4062void dp_set_panel_mode(struct dc_link *link, enum dp_panel_mode panel_mode)
4063{
4064 union dpcd_edp_config edp_config_set;
4065 bool panel_mode_edp = false;
4066
4067 memset(&edp_config_set, '\0', sizeof(union dpcd_edp_config));
4068
4069 if (panel_mode != DP_PANEL_MODE_DEFAULT) {
4070
4071 switch (panel_mode) {
4072 case DP_PANEL_MODE_EDP:
4073 case DP_PANEL_MODE_SPECIAL:
4074 panel_mode_edp = true;
4075 break;
4076
4077 default:
4078 break;
4079 }
4080
4081 /*set edp panel mode in receiver*/
4082 core_link_read_dpcd(
4083 link,
4084 DP_EDP_CONFIGURATION_SET,
4085 &edp_config_set.raw,
4086 sizeof(edp_config_set.raw));
4087
4088 if (edp_config_set.bits.PANEL_MODE_EDP
4089 != panel_mode_edp) {
4090 enum ddc_result result = DDC_RESULT_UNKNOWN;
4091
4092 edp_config_set.bits.PANEL_MODE_EDP =
4093 panel_mode_edp;
4094 result = core_link_write_dpcd(
4095 link,
4096 DP_EDP_CONFIGURATION_SET,
4097 &edp_config_set.raw,
4098 sizeof(edp_config_set.raw));
4099
4100 ASSERT(result == DDC_RESULT_SUCESSFULL);
4101 }
4102 }
4103 DC_LOG_DETECTION_DP_CAPS("Link: %d eDP panel mode supported: %d "
4104 "eDP panel mode enabled: %d \n",
4105 link->link_index,
4106 link->dpcd_caps.panel_mode_edp,
4107 panel_mode_edp);
4108}
4109
4110enum dp_panel_mode dp_get_panel_mode(struct dc_link *link)
4111{
4112 /* We need to explicitly check that connector
4113 * is not DP. Some Travis_VGA get reported
4114 * by video bios as DP.
4115 */
4116 if (link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT) {
4117
4118 switch (link->dpcd_caps.branch_dev_id) {
df3b7e32
QZ
4119 case DP_BRANCH_DEVICE_ID_0022B9:
4120 /* alternate scrambler reset is required for Travis
4121 * for the case when external chip does not
4122 * provide sink device id, alternate scrambler
4123 * scheme will be overriden later by querying
4124 * Encoder features
4125 */
0b226322
DG
4126 if (strncmp(
4127 link->dpcd_caps.branch_dev_name,
4128 DP_VGA_LVDS_CONVERTER_ID_2,
4129 sizeof(
4130 link->dpcd_caps.
4131 branch_dev_name)) == 0) {
4132 return DP_PANEL_MODE_SPECIAL;
4133 }
4134 break;
df3b7e32
QZ
4135 case DP_BRANCH_DEVICE_ID_00001A:
4136 /* alternate scrambler reset is required for Travis
4137 * for the case when external chip does not provide
4138 * sink device id, alternate scrambler scheme will
4139 * be overriden later by querying Encoder feature
4140 */
0b226322
DG
4141 if (strncmp(link->dpcd_caps.branch_dev_name,
4142 DP_VGA_LVDS_CONVERTER_ID_3,
4143 sizeof(
4144 link->dpcd_caps.
4145 branch_dev_name)) == 0) {
4146 return DP_PANEL_MODE_SPECIAL;
4147 }
4148 break;
4149 default:
4150 break;
4151 }
4152 }
4153
4154 if (link->dpcd_caps.panel_mode_edp) {
4155 return DP_PANEL_MODE_EDP;
4156 }
4157
4158 return DP_PANEL_MODE_DEFAULT;
4159}
4160
97bda032
HW
4161void dp_set_fec_ready(struct dc_link *link, bool ready)
4162{
4163 /* FEC has to be "set ready" before the link training.
4164 * The policy is to always train with FEC
4165 * if the sink supports it and leave it enabled on link.
4166 * If FEC is not supported, disable it.
4167 */
4168 struct link_encoder *link_enc = link->link_enc;
4169 uint8_t fec_config = 0;
4170
e6b11b43 4171 if (!dc_link_is_fec_supported(link) || link->dc->debug.disable_fec)
97bda032
HW
4172 return;
4173
4174 if (link_enc->funcs->fec_set_ready &&
4175 link->dpcd_caps.fec_cap.bits.FEC_CAPABLE) {
008a4016 4176 if (ready) {
97bda032
HW
4177 fec_config = 1;
4178 if (core_link_write_dpcd(link,
4179 DP_FEC_CONFIGURATION,
4180 &fec_config,
4181 sizeof(fec_config)) == DC_OK) {
4182 link_enc->funcs->fec_set_ready(link_enc, true);
4183 link->fec_state = dc_link_fec_ready;
4184 } else {
d68a7454
NC
4185 link->link_enc->funcs->fec_set_ready(link->link_enc, false);
4186 link->fec_state = dc_link_fec_not_ready;
97bda032
HW
4187 dm_error("dpcd write failed to set fec_ready");
4188 }
008a4016 4189 } else if (link->fec_state == dc_link_fec_ready) {
97bda032
HW
4190 fec_config = 0;
4191 core_link_write_dpcd(link,
4192 DP_FEC_CONFIGURATION,
4193 &fec_config,
4194 sizeof(fec_config));
4195 link->link_enc->funcs->fec_set_ready(
4196 link->link_enc, false);
4197 link->fec_state = dc_link_fec_not_ready;
4198 }
4199 }
4200}
4201
4202void dp_set_fec_enable(struct dc_link *link, bool enable)
4203{
4204 struct link_encoder *link_enc = link->link_enc;
4205
e6b11b43 4206 if (!dc_link_is_fec_supported(link) || link->dc->debug.disable_fec)
97bda032
HW
4207 return;
4208
4209 if (link_enc->funcs->fec_set_enable &&
4210 link->dpcd_caps.fec_cap.bits.FEC_CAPABLE) {
4211 if (link->fec_state == dc_link_fec_ready && enable) {
fa11d3c9
LHM
4212 /* Accord to DP spec, FEC enable sequence can first
4213 * be transmitted anytime after 1000 LL codes have
4214 * been transmitted on the link after link training
4215 * completion. Using 1 lane RBR should have the maximum
4216 * time for transmitting 1000 LL codes which is 6.173 us.
4217 * So use 7 microseconds delay instead.
4218 */
4219 udelay(7);
97bda032
HW
4220 link_enc->funcs->fec_set_enable(link_enc, true);
4221 link->fec_state = dc_link_fec_enabled;
4222 } else if (link->fec_state == dc_link_fec_enabled && !enable) {
4223 link_enc->funcs->fec_set_enable(link_enc, false);
4224 link->fec_state = dc_link_fec_ready;
4225 }
4226 }
4227}
6fbefb84 4228
96577cf8
HW
4229void dpcd_set_source_specific_data(struct dc_link *link)
4230{
96577cf8 4231 const uint32_t post_oui_delay = 30; // 30ms
96772702 4232 uint8_t dspc = 0;
a96f661a 4233 enum dc_status ret;
96772702
AP
4234
4235 ret = core_link_read_dpcd(link, DP_DOWN_STREAM_PORT_COUNT, &dspc,
4236 sizeof(dspc));
4237
4238 if (ret != DC_OK) {
4239 DC_LOG_ERROR("Error in DP aux read transaction,"
4240 " not writing source specific data\n");
4241 return;
4242 }
4243
4244 /* Return if OUI unsupported */
4245 if (!(dspc & DP_OUI_SUPPORT))
4246 return;
96577cf8 4247
0136684f
CH
4248 if (!link->dc->vendor_signature.is_valid) {
4249 struct dpcd_amd_signature amd_signature;
4250 amd_signature.AMD_IEEE_TxSignature_byte1 = 0x0;
4251 amd_signature.AMD_IEEE_TxSignature_byte2 = 0x0;
4252 amd_signature.AMD_IEEE_TxSignature_byte3 = 0x1A;
4253 amd_signature.device_id_byte1 =
4254 (uint8_t)(link->ctx->asic_id.chip_id);
4255 amd_signature.device_id_byte2 =
4256 (uint8_t)(link->ctx->asic_id.chip_id >> 8);
4257 memset(&amd_signature.zero, 0, 4);
4258 amd_signature.dce_version =
4259 (uint8_t)(link->ctx->dce_version);
4260 amd_signature.dal_version_byte1 = 0x0; // needed? where to get?
4261 amd_signature.dal_version_byte2 = 0x0; // needed? where to get?
4262
4263 core_link_write_dpcd(link, DP_SOURCE_OUI,
4264 (uint8_t *)(&amd_signature),
4265 sizeof(amd_signature));
4266
4267 } else {
4268 core_link_write_dpcd(link, DP_SOURCE_OUI,
4269 link->dc->vendor_signature.data.raw,
4270 sizeof(link->dc->vendor_signature.data.raw));
4271 }
96577cf8
HW
4272
4273 // Sink may need to configure internals based on vendor, so allow some
4274 // time before proceeding with possibly vendor specific transactions
4275 msleep(post_oui_delay);
4276}
4277
4278bool dc_link_set_backlight_level_nits(struct dc_link *link,
4279 bool isHDR,
4280 uint32_t backlight_millinits,
4281 uint32_t transition_time_in_ms)
4282{
4283 struct dpcd_source_backlight_set dpcd_backlight_set;
4284 uint8_t backlight_control = isHDR ? 1 : 0;
4285
4286 if (!link || (link->connector_signal != SIGNAL_TYPE_EDP &&
4287 link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT))
4288 return false;
4289
4290 // OLEDs have no PWM, they can only use AUX
4291 if (link->dpcd_sink_ext_caps.bits.oled == 1)
4292 backlight_control = 1;
4293
4294 *(uint32_t *)&dpcd_backlight_set.backlight_level_millinits = backlight_millinits;
4295 *(uint16_t *)&dpcd_backlight_set.backlight_transition_time_ms = (uint16_t)transition_time_in_ms;
4296
4297
4298 if (core_link_write_dpcd(link, DP_SOURCE_BACKLIGHT_LEVEL,
4299 (uint8_t *)(&dpcd_backlight_set),
4300 sizeof(dpcd_backlight_set)) != DC_OK)
4301 return false;
4302
4303 if (core_link_write_dpcd(link, DP_SOURCE_BACKLIGHT_CONTROL,
4304 &backlight_control, 1) != DC_OK)
4305 return false;
4306
4307 return true;
4308}
4309
4310bool dc_link_get_backlight_level_nits(struct dc_link *link,
4311 uint32_t *backlight_millinits_avg,
4312 uint32_t *backlight_millinits_peak)
4313{
4314 union dpcd_source_backlight_get dpcd_backlight_get;
4315
4316 memset(&dpcd_backlight_get, 0, sizeof(union dpcd_source_backlight_get));
4317
4318 if (!link || (link->connector_signal != SIGNAL_TYPE_EDP &&
4319 link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT))
4320 return false;
4321
4322 if (!core_link_read_dpcd(link, DP_SOURCE_BACKLIGHT_CURRENT_PEAK,
4323 dpcd_backlight_get.raw,
4324 sizeof(union dpcd_source_backlight_get)))
4325 return false;
4326
4327 *backlight_millinits_avg =
4328 dpcd_backlight_get.bytes.backlight_millinits_avg;
4329 *backlight_millinits_peak =
4330 dpcd_backlight_get.bytes.backlight_millinits_peak;
4331
4332 /* On non-supported panels dpcd_read usually succeeds with 0 returned */
4333 if (*backlight_millinits_avg == 0 ||
4334 *backlight_millinits_avg > *backlight_millinits_peak)
4335 return false;
4336
4337 return true;
4338}
4339
4340bool dc_link_backlight_enable_aux(struct dc_link *link, bool enable)
4341{
4342 uint8_t backlight_enable = enable ? 1 : 0;
4343
4344 if (!link || (link->connector_signal != SIGNAL_TYPE_EDP &&
4345 link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT))
4346 return false;
4347
4348 if (core_link_write_dpcd(link, DP_SOURCE_BACKLIGHT_ENABLE,
4349 &backlight_enable, 1) != DC_OK)
4350 return false;
4351
4352 return true;
4353}
4354
4355// we read default from 0x320 because we expect BIOS wrote it there
4356// regular get_backlight_nit reads from panel set at 0x326
4357bool dc_link_read_default_bl_aux(struct dc_link *link, uint32_t *backlight_millinits)
4358{
4359 if (!link || (link->connector_signal != SIGNAL_TYPE_EDP &&
4360 link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT))
4361 return false;
4362
4363 if (!core_link_read_dpcd(link, DP_SOURCE_BACKLIGHT_LEVEL,
4364 (uint8_t *) backlight_millinits,
4365 sizeof(uint32_t)))
4366 return false;
4367
4368 return true;
4369}
4370
4371bool dc_link_set_default_brightness_aux(struct dc_link *link)
4372{
4373 uint32_t default_backlight;
4374
4375 if (link &&
4376 (link->dpcd_sink_ext_caps.bits.hdr_aux_backlight_control == 1 ||
4377 link->dpcd_sink_ext_caps.bits.sdr_aux_backlight_control == 1)) {
4378 if (!dc_link_read_default_bl_aux(link, &default_backlight))
4379 default_backlight = 150000;
4380 // if < 5 nits or > 5000, it might be wrong readback
4381 if (default_backlight < 5000 || default_backlight > 5000000)
4382 default_backlight = 150000; //
4383
4384 return dc_link_set_backlight_level_nits(link, true,
4385 default_backlight, 0);
4386 }
4387 return false;
4388}