1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27#include "dc.h"
28#include "dc_link_dpia.h"
29#include "inc/core_status.h"
30#include "dc_link.h"
31#include "dc_link_dp.h"
32#include "dpcd_defs.h"
33#include "link_hwss.h"
34#include "dm_helpers.h"
35#include "dmub/inc/dmub_cmd.h"
36#include "inc/link_dpcd.h"
37#include "dc_dmub_srv.h"
38
39#define DC_LOGGER \
40 link->ctx->logger
41
42enum dc_status dpcd_get_tunneling_device_data(struct dc_link *link)
43{
44 enum dc_status status = DC_OK;
45 uint8_t dpcd_dp_tun_data[3] = {0};
46 uint8_t dpcd_topology_data[DPCD_USB4_TOPOLOGY_ID_LEN] = {0};
47 uint8_t i = 0;
48
49 status = core_link_read_dpcd(link,
50 DP_TUNNELING_CAPABILITIES_SUPPORT,
51 dpcd_dp_tun_data,
52 sizeof(dpcd_dp_tun_data));
53
54 status = core_link_read_dpcd(link,
55 DP_USB4_ROUTER_TOPOLOGY_ID,
56 dpcd_topology_data,
57 sizeof(dpcd_topology_data));
58
59 link->dpcd_caps.usb4_dp_tun_info.dp_tun_cap.raw =
60 dpcd_dp_tun_data[DP_TUNNELING_CAPABILITIES_SUPPORT -
61 DP_TUNNELING_CAPABILITIES_SUPPORT];
62 link->dpcd_caps.usb4_dp_tun_info.dpia_info.raw =
63 dpcd_dp_tun_data[DP_IN_ADAPTER_INFO - DP_TUNNELING_CAPABILITIES_SUPPORT];
64 link->dpcd_caps.usb4_dp_tun_info.usb4_driver_id =
65 dpcd_dp_tun_data[DP_USB4_DRIVER_ID - DP_TUNNELING_CAPABILITIES_SUPPORT];
66
67 for (i = 0; i < DPCD_USB4_TOPOLOGY_ID_LEN; i++)
68 link->dpcd_caps.usb4_dp_tun_info.usb4_topology_id[i] = dpcd_topology_data[i];
69
70 return status;
71}
72
73bool dc_link_dpia_query_hpd_status(struct dc_link *link)
74{
75 union dmub_rb_cmd cmd = {0};
76 struct dc_dmub_srv *dmub_srv = link->ctx->dmub_srv;
77 bool is_hpd_high = false;
78
79
80 cmd.query_hpd.header.type = DMUB_CMD__QUERY_HPD_STATE;
81 cmd.query_hpd.data.instance = link->link_id.enum_id - ENUM_ID_1;
82 cmd.query_hpd.data.ch_type = AUX_CHANNEL_DPIA;
83
84
85 if (dc_dmub_srv_cmd_with_reply_data(dmub_srv, &cmd) && cmd.query_hpd.data.status == AUX_RET_SUCCESS)
86 is_hpd_high = cmd.query_hpd.data.result;
87
88 return is_hpd_high;
89}
90
91
92
93
94
95
96
97
98
99static enum link_training_result dpia_configure_link(
100 struct dc_link *link,
101 const struct link_resource *link_res,
102 const struct dc_link_settings *link_setting,
103 struct link_training_settings *lt_settings)
104{
105 enum dc_status status;
106 bool fec_enable;
107
108 DC_LOG_HW_LINK_TRAINING("%s\n DPIA(%d) configuring\n - LTTPR mode(%d)\n",
109 __func__,
110 link->link_id.enum_id - ENUM_ID_1,
111 link->lttpr_mode);
112
113 dp_decide_training_settings(link,
114 link_setting,
115 lt_settings);
116
117 status = dpcd_configure_channel_coding(link, lt_settings);
118 if (status != DC_OK && link->is_hpd_pending)
119 return LINK_TRAINING_ABORT;
120
121
122 status = dpcd_configure_lttpr_mode(link, lt_settings);
123 if (status != DC_OK && link->is_hpd_pending)
124 return LINK_TRAINING_ABORT;
125
126
127 status = dpcd_set_link_settings(link, lt_settings);
128 if (status != DC_OK && link->is_hpd_pending)
129 return LINK_TRAINING_ABORT;
130
131 if (link->preferred_training_settings.fec_enable)
132 fec_enable = *link->preferred_training_settings.fec_enable;
133 else
134 fec_enable = true;
135 status = dp_set_fec_ready(link, link_res, fec_enable);
136 if (status != DC_OK && link->is_hpd_pending)
137 return LINK_TRAINING_ABORT;
138
139 return LINK_TRAINING_SUCCESS;
140}
141
142static enum dc_status core_link_send_set_config(struct dc_link *link,
143 uint8_t msg_type,
144 uint8_t msg_data)
145{
146 struct set_config_cmd_payload payload;
147 enum set_config_status set_config_result = SET_CONFIG_PENDING;
148
149
150 payload.msg_type = msg_type;
151 payload.msg_data = msg_data;
152
153 if (!link->ddc->ddc_pin && !link->aux_access_disabled &&
154 (dm_helpers_dmub_set_config_sync(link->ctx, link,
155 &payload, &set_config_result) == -1)) {
156 return DC_ERROR_UNEXPECTED;
157 }
158
159
160 return (set_config_result == SET_CONFIG_ACK_RECEIVED) ? DC_OK : DC_ERROR_UNEXPECTED;
161}
162
163
164static uint8_t dpia_build_set_config_data(enum dpia_set_config_type type,
165 struct dc_link *link,
166 struct link_training_settings *lt_settings)
167{
168 union dpia_set_config_data data;
169
170 data.raw = 0;
171
172 switch (type) {
173 case DPIA_SET_CFG_SET_LINK:
174 data.set_link.mode = link->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT ? 1 : 0;
175 break;
176 case DPIA_SET_CFG_SET_PHY_TEST_MODE:
177 break;
178 case DPIA_SET_CFG_SET_VSPE:
179
180 data.set_vspe.swing = lt_settings->lane_settings[0].VOLTAGE_SWING;
181 data.set_vspe.pre_emph = lt_settings->lane_settings[0].PRE_EMPHASIS;
182 data.set_vspe.max_swing_reached =
183 lt_settings->lane_settings[0].VOLTAGE_SWING ==
184 VOLTAGE_SWING_MAX_LEVEL ? 1 : 0;
185 data.set_vspe.max_pre_emph_reached =
186 lt_settings->lane_settings[0].PRE_EMPHASIS ==
187 PRE_EMPHASIS_MAX_LEVEL ? 1 : 0;
188 break;
189 default:
190 ASSERT(false);
191 break;
192 }
193
194 return data.raw;
195}
196
197
198static enum dpia_set_config_ts convert_trng_ptn_to_trng_stg(enum dc_dp_training_pattern tps)
199{
200 enum dpia_set_config_ts ts;
201
202 switch (tps) {
203 case DP_TRAINING_PATTERN_SEQUENCE_1:
204 ts = DPIA_TS_TPS1;
205 break;
206 case DP_TRAINING_PATTERN_SEQUENCE_2:
207 ts = DPIA_TS_TPS2;
208 break;
209 case DP_TRAINING_PATTERN_SEQUENCE_3:
210 ts = DPIA_TS_TPS3;
211 break;
212 case DP_TRAINING_PATTERN_SEQUENCE_4:
213 ts = DPIA_TS_TPS4;
214 break;
215 default:
216 ts = DPIA_TS_DPRX_DONE;
217 ASSERT(false);
218 break;
219 }
220
221 return ts;
222}
223
224
225static enum dc_status dpcd_set_lt_pattern(struct dc_link *link,
226 enum dc_dp_training_pattern pattern,
227 uint32_t hop)
228{
229 union dpcd_training_pattern dpcd_pattern = { {0} };
230 uint32_t dpcd_tps_offset = DP_TRAINING_PATTERN_SET;
231 enum dc_status status;
232
233 if (hop != DPRX)
234 dpcd_tps_offset = DP_TRAINING_PATTERN_SET_PHY_REPEATER1 +
235 ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (hop - 1));
236
237
238 dpcd_pattern.v1_4.TRAINING_PATTERN_SET =
239 dc_dp_training_pattern_to_dpcd_training_pattern(link, pattern);
240
241 dpcd_pattern.v1_4.SCRAMBLING_DISABLE =
242 dc_dp_initialize_scrambling_data_symbols(link, pattern);
243
244 if (hop != DPRX) {
245 DC_LOG_HW_LINK_TRAINING("%s\n LTTPR Repeater ID: %d\n 0x%X pattern = %x\n",
246 __func__,
247 hop,
248 dpcd_tps_offset,
249 dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
250 } else {
251 DC_LOG_HW_LINK_TRAINING("%s\n 0x%X pattern = %x\n",
252 __func__,
253 dpcd_tps_offset,
254 dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
255 }
256
257 status = core_link_write_dpcd(link,
258 dpcd_tps_offset,
259 &dpcd_pattern.raw,
260 sizeof(dpcd_pattern.raw));
261
262 return status;
263}
264
265
266
267
268
269
270
271
272
273
274
275
276static enum link_training_result dpia_training_cr_non_transparent(
277 struct dc_link *link,
278 const struct link_resource *link_res,
279 struct link_training_settings *lt_settings,
280 uint32_t hop)
281{
282 enum link_training_result result = LINK_TRAINING_CR_FAIL_LANE0;
283 uint8_t repeater_cnt = 0;
284 enum dc_status status;
285 uint32_t retries_cr = 0;
286 uint32_t retry_count = 0;
287
288 uint32_t wait_time_microsec = TRAINING_AUX_RD_INTERVAL;
289 enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
290 union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = { { {0} } };
291 union lane_align_status_updated dpcd_lane_status_updated = { {0} };
292 union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = { { {0} } };
293 uint8_t set_cfg_data;
294 enum dpia_set_config_ts ts;
295
296 repeater_cnt = dp_convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
297
298
299
300
301
302
303
304
305 while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) &&
306 (retry_count < LINK_TRAINING_MAX_CR_RETRY)) {
307
308 if (hop == repeater_cnt) {
309
310
311
312
313 set_cfg_data = dpia_build_set_config_data(DPIA_SET_CFG_SET_LINK,
314 link,
315 lt_settings);
316 status = core_link_send_set_config(link,
317 DPIA_SET_CFG_SET_LINK,
318 set_cfg_data);
319
320
321
322 if (status == DC_OK)
323 result = LINK_TRAINING_SUCCESS;
324 else
325 result = LINK_TRAINING_ABORT;
326 break;
327 }
328
329
330
331 if (retry_count == 0) {
332 ts = convert_trng_ptn_to_trng_stg(lt_settings->pattern_for_cr);
333 status = core_link_send_set_config(link,
334 DPIA_SET_CFG_SET_TRAINING,
335 ts);
336 if (status != DC_OK) {
337 result = LINK_TRAINING_ABORT;
338 break;
339 }
340 status = dpcd_set_lt_pattern(link, lt_settings->pattern_for_cr, hop);
341 if (status != DC_OK) {
342 result = LINK_TRAINING_ABORT;
343 break;
344 }
345 }
346
347
348
349
350 if (hop == repeater_cnt - 1) {
351 set_cfg_data = dpia_build_set_config_data(DPIA_SET_CFG_SET_VSPE,
352 link,
353 lt_settings);
354 status = core_link_send_set_config(link,
355 DPIA_SET_CFG_SET_VSPE,
356 set_cfg_data);
357 if (status != DC_OK) {
358 result = LINK_TRAINING_ABORT;
359 break;
360 }
361 }
362 status = dpcd_set_lane_settings(link, lt_settings, hop);
363 if (status != DC_OK) {
364 result = LINK_TRAINING_ABORT;
365 break;
366 }
367
368 dp_wait_for_training_aux_rd_interval(link, wait_time_microsec);
369
370
371 status = dp_get_lane_status_and_lane_adjust(
372 link,
373 lt_settings,
374 dpcd_lane_status,
375 &dpcd_lane_status_updated,
376 dpcd_lane_adjust,
377 hop);
378 if (status != DC_OK) {
379 result = LINK_TRAINING_ABORT;
380 break;
381 }
382
383
384 if (dp_is_cr_done(lane_count, dpcd_lane_status)) {
385 result = LINK_TRAINING_SUCCESS;
386 break;
387 }
388
389 result = dp_get_cr_failure(lane_count, dpcd_lane_status);
390
391 if (dp_is_max_vs_reached(lt_settings))
392 break;
393
394
395
396
397
398 if ((lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET ==
399 dpcd_lane_adjust[0].bits.VOLTAGE_SWING_LANE)
400 && (lt_settings->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET ==
401 dpcd_lane_adjust[0].bits.PRE_EMPHASIS_LANE))
402 retries_cr++;
403 else
404 retries_cr = 0;
405
406
407 dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
408 lt_settings->lane_settings,
409 lt_settings->dpcd_lane_settings);
410 retry_count++;
411 }
412
413
414 if (link->is_hpd_pending)
415 result = LINK_TRAINING_ABORT;
416
417 DC_LOG_HW_LINK_TRAINING("%s\n DPIA(%d) clock recovery\n"
418 " -hop(%d)\n - result(%d)\n - retries(%d)\n",
419 __func__,
420 link->link_id.enum_id - ENUM_ID_1,
421 hop,
422 result,
423 retry_count);
424
425 return result;
426}
427
428
429
430
431
432
433
434
435
436
437static enum link_training_result dpia_training_cr_transparent(
438 struct dc_link *link,
439 const struct link_resource *link_res,
440 struct link_training_settings *lt_settings)
441{
442 enum link_training_result result = LINK_TRAINING_CR_FAIL_LANE0;
443 enum dc_status status;
444 uint32_t retries_cr = 0;
445 uint32_t retry_count = 0;
446 uint32_t wait_time_microsec = lt_settings->cr_pattern_time;
447 enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
448 union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = { { {0} } };
449 union lane_align_status_updated dpcd_lane_status_updated = { {0} };
450 union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = { { {0} } };
451
452
453
454
455
456
457
458
459 while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) &&
460 (retry_count < LINK_TRAINING_MAX_CR_RETRY)) {
461
462
463
464
465 if (retry_count == 0) {
466 status = dpcd_set_lt_pattern(link, lt_settings->pattern_for_cr, DPRX);
467 if (status != DC_OK) {
468 result = LINK_TRAINING_ABORT;
469 break;
470 }
471 }
472
473 dp_wait_for_training_aux_rd_interval(link, wait_time_microsec);
474
475
476 status = dp_get_lane_status_and_lane_adjust(
477 link,
478 lt_settings,
479 dpcd_lane_status,
480 &dpcd_lane_status_updated,
481 dpcd_lane_adjust,
482 DPRX);
483 if (status != DC_OK) {
484 result = LINK_TRAINING_ABORT;
485 break;
486 }
487
488
489 if (dp_is_cr_done(lane_count, dpcd_lane_status)) {
490 result = LINK_TRAINING_SUCCESS;
491 break;
492 }
493
494 result = dp_get_cr_failure(lane_count, dpcd_lane_status);
495
496 if (dp_is_max_vs_reached(lt_settings))
497 break;
498
499
500
501
502
503 if ((lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET ==
504 dpcd_lane_adjust[0].bits.VOLTAGE_SWING_LANE)
505 && (lt_settings->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET ==
506 dpcd_lane_adjust[0].bits.PRE_EMPHASIS_LANE))
507 retries_cr++;
508 else
509 retries_cr = 0;
510
511
512 dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
513 lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
514 retry_count++;
515 }
516
517
518 if (link->is_hpd_pending)
519 result = LINK_TRAINING_ABORT;
520
521 DC_LOG_HW_LINK_TRAINING("%s\n DPIA(%d) clock recovery\n"
522 " -hop(%d)\n - result(%d)\n - retries(%d)\n",
523 __func__,
524 link->link_id.enum_id - ENUM_ID_1,
525 DPRX,
526 result,
527 retry_count);
528
529 return result;
530}
531
532
533
534
535
536
537
538
539static enum link_training_result dpia_training_cr_phase(
540 struct dc_link *link,
541 const struct link_resource *link_res,
542 struct link_training_settings *lt_settings,
543 uint32_t hop)
544{
545 enum link_training_result result = LINK_TRAINING_CR_FAIL_LANE0;
546
547 if (link->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT)
548 result = dpia_training_cr_non_transparent(link, link_res, lt_settings, hop);
549 else
550 result = dpia_training_cr_transparent(link, link_res, lt_settings);
551
552 return result;
553}
554
555
556static uint32_t dpia_get_eq_aux_rd_interval(const struct dc_link *link,
557 const struct link_training_settings *lt_settings,
558 uint32_t hop)
559{
560 uint32_t wait_time_microsec;
561
562 if (hop == DPRX)
563 wait_time_microsec = lt_settings->eq_pattern_time;
564 else
565 wait_time_microsec =
566 dp_translate_training_aux_read_interval(
567 link->dpcd_caps.lttpr_caps.aux_rd_interval[hop - 1]);
568
569
570 if (link->dc->debug.dpia_debug.bits.extend_aux_rd_interval)
571 wait_time_microsec = DPIA_DEBUG_EXTENDED_AUX_RD_INTERVAL_US;
572
573 return wait_time_microsec;
574}
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589static enum link_training_result dpia_training_eq_non_transparent(
590 struct dc_link *link,
591 const struct link_resource *link_res,
592 struct link_training_settings *lt_settings,
593 uint32_t hop)
594{
595 enum link_training_result result = LINK_TRAINING_EQ_FAIL_EQ;
596 uint8_t repeater_cnt = 0;
597 uint32_t retries_eq = 0;
598 enum dc_status status;
599 enum dc_dp_training_pattern tr_pattern;
600 uint32_t wait_time_microsec;
601 enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
602 union lane_align_status_updated dpcd_lane_status_updated = { {0} };
603 union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = { { {0} } };
604 union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = { { {0} } };
605 uint8_t set_cfg_data;
606 enum dpia_set_config_ts ts;
607
608
609
610
611 if (hop == DPRX)
612 tr_pattern = lt_settings->pattern_for_eq;
613 else
614 tr_pattern = DP_TRAINING_PATTERN_SEQUENCE_4;
615
616 repeater_cnt = dp_convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
617
618 for (retries_eq = 0; retries_eq < LINK_TRAINING_MAX_RETRY_COUNT; retries_eq++) {
619
620 if (hop == repeater_cnt) {
621 result = LINK_TRAINING_SUCCESS;
622 break;
623 }
624
625
626 if (retries_eq == 0) {
627 ts = convert_trng_ptn_to_trng_stg(tr_pattern);
628 status = core_link_send_set_config(link,
629 DPIA_SET_CFG_SET_TRAINING,
630 ts);
631 if (status != DC_OK) {
632 result = LINK_TRAINING_ABORT;
633 break;
634 }
635 status = dpcd_set_lt_pattern(link, tr_pattern, hop);
636 if (status != DC_OK) {
637 result = LINK_TRAINING_ABORT;
638 break;
639 }
640 }
641
642
643
644
645 if (hop == repeater_cnt - 1) {
646 set_cfg_data = dpia_build_set_config_data(DPIA_SET_CFG_SET_VSPE,
647 link,
648 lt_settings);
649 status = core_link_send_set_config(link,
650 DPIA_SET_CFG_SET_VSPE,
651 set_cfg_data);
652 if (status != DC_OK) {
653 result = LINK_TRAINING_ABORT;
654 break;
655 }
656 }
657 status = dpcd_set_lane_settings(link, lt_settings, hop);
658 if (status != DC_OK) {
659 result = LINK_TRAINING_ABORT;
660 break;
661 }
662
663
664
665
666 if (hop == DPRX && retries_eq == 1)
667 wait_time_microsec = max(wait_time_microsec, (uint32_t)DPIA_CLK_SYNC_DELAY);
668 else
669 wait_time_microsec = dpia_get_eq_aux_rd_interval(link, lt_settings, hop);
670
671 dp_wait_for_training_aux_rd_interval(link, wait_time_microsec);
672
673
674 status = dp_get_lane_status_and_lane_adjust(
675 link,
676 lt_settings,
677 dpcd_lane_status,
678 &dpcd_lane_status_updated,
679 dpcd_lane_adjust,
680 hop);
681 if (status != DC_OK) {
682 result = LINK_TRAINING_ABORT;
683 break;
684 }
685
686
687 if (!dp_is_cr_done(lane_count, dpcd_lane_status)) {
688 result = LINK_TRAINING_EQ_FAIL_CR;
689 break;
690 }
691
692 if (dp_is_ch_eq_done(lane_count, dpcd_lane_status) &&
693 dp_is_symbol_locked(link->cur_link_settings.lane_count, dpcd_lane_status) &&
694 dp_is_interlane_aligned(dpcd_lane_status_updated)) {
695 result = LINK_TRAINING_SUCCESS;
696 break;
697 }
698
699
700 dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
701 lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
702 }
703
704
705 if (link->is_hpd_pending)
706 result = LINK_TRAINING_ABORT;
707
708 DC_LOG_HW_LINK_TRAINING("%s\n DPIA(%d) equalization\n"
709 " - hop(%d)\n - result(%d)\n - retries(%d)\n",
710 __func__,
711 link->link_id.enum_id - ENUM_ID_1,
712 hop,
713 result,
714 retries_eq);
715
716 return result;
717}
718
719
720
721
722
723
724
725
726
727
728
729
730static enum link_training_result dpia_training_eq_transparent(
731 struct dc_link *link,
732 const struct link_resource *link_res,
733 struct link_training_settings *lt_settings)
734{
735 enum link_training_result result = LINK_TRAINING_EQ_FAIL_EQ;
736 uint32_t retries_eq = 0;
737 enum dc_status status;
738 enum dc_dp_training_pattern tr_pattern = lt_settings->pattern_for_eq;
739 uint32_t wait_time_microsec;
740 enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
741 union lane_align_status_updated dpcd_lane_status_updated = { {0} };
742 union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = { { {0} } };
743 union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = { { {0} } };
744
745 wait_time_microsec = dpia_get_eq_aux_rd_interval(link, lt_settings, DPRX);
746
747 for (retries_eq = 0; retries_eq < LINK_TRAINING_MAX_RETRY_COUNT; retries_eq++) {
748 if (retries_eq == 0) {
749 status = dpcd_set_lt_pattern(link, tr_pattern, DPRX);
750 if (status != DC_OK) {
751 result = LINK_TRAINING_ABORT;
752 break;
753 }
754 }
755
756 dp_wait_for_training_aux_rd_interval(link, wait_time_microsec);
757
758
759 status = dp_get_lane_status_and_lane_adjust(
760 link,
761 lt_settings,
762 dpcd_lane_status,
763 &dpcd_lane_status_updated,
764 dpcd_lane_adjust,
765 DPRX);
766 if (status != DC_OK) {
767 result = LINK_TRAINING_ABORT;
768 break;
769 }
770
771
772 if (!dp_is_cr_done(lane_count, dpcd_lane_status)) {
773 result = LINK_TRAINING_EQ_FAIL_CR;
774 break;
775 }
776
777 if (dp_is_ch_eq_done(lane_count, dpcd_lane_status) &&
778 dp_is_symbol_locked(link->cur_link_settings.lane_count, dpcd_lane_status) &&
779 dp_is_interlane_aligned(dpcd_lane_status_updated)) {
780 result = LINK_TRAINING_SUCCESS;
781 break;
782 }
783
784
785 dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
786 lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
787 }
788
789
790 if (link->is_hpd_pending)
791 result = LINK_TRAINING_ABORT;
792
793 DC_LOG_HW_LINK_TRAINING("%s\n DPIA(%d) equalization\n"
794 " - hop(%d)\n - result(%d)\n - retries(%d)\n",
795 __func__,
796 link->link_id.enum_id - ENUM_ID_1,
797 DPRX,
798 result,
799 retries_eq);
800
801 return result;
802}
803
804
805
806
807
808
809
810
811static enum link_training_result dpia_training_eq_phase(
812 struct dc_link *link,
813 const struct link_resource *link_res,
814 struct link_training_settings *lt_settings,
815 uint32_t hop)
816{
817 enum link_training_result result;
818
819 if (link->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT)
820 result = dpia_training_eq_non_transparent(link, link_res, lt_settings, hop);
821 else
822 result = dpia_training_eq_transparent(link, link_res, lt_settings);
823
824 return result;
825}
826
827
828static enum dc_status dpcd_clear_lt_pattern(struct dc_link *link, uint32_t hop)
829{
830 union dpcd_training_pattern dpcd_pattern = { {0} };
831 uint32_t dpcd_tps_offset = DP_TRAINING_PATTERN_SET;
832 enum dc_status status;
833
834 if (hop != DPRX)
835 dpcd_tps_offset = DP_TRAINING_PATTERN_SET_PHY_REPEATER1 +
836 ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (hop - 1));
837
838 status = core_link_write_dpcd(link,
839 dpcd_tps_offset,
840 &dpcd_pattern.raw,
841 sizeof(dpcd_pattern.raw));
842
843 return status;
844}
845
846
847
848
849
850
851
852
853
854
855
856
857
858static enum link_training_result dpia_training_end(struct dc_link *link,
859 uint32_t hop)
860{
861 enum link_training_result result = LINK_TRAINING_SUCCESS;
862 uint8_t repeater_cnt = 0;
863 enum dc_status status;
864
865 if (link->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) {
866 repeater_cnt = dp_convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
867
868 if (hop == repeater_cnt) {
869
870
871
872 status = core_link_send_set_config(link,
873 DPIA_SET_CFG_SET_TRAINING,
874 DPIA_TS_UFP_DONE);
875 if (status != DC_OK)
876 result = LINK_TRAINING_ABORT;
877 } else {
878
879 status = dpcd_clear_lt_pattern(link, hop);
880 if (status != DC_OK)
881 result = LINK_TRAINING_ABORT;
882 }
883
884
885 if (hop == DPRX && result != LINK_TRAINING_ABORT) {
886 status = core_link_send_set_config(link,
887 DPIA_SET_CFG_SET_TRAINING,
888 DPIA_TS_DPRX_DONE);
889 if (status != DC_OK)
890 result = LINK_TRAINING_ABORT;
891 }
892
893 } else {
894
895 status = dpcd_clear_lt_pattern(link, hop);
896 if (status != DC_OK)
897 result = LINK_TRAINING_ABORT;
898 }
899
900 DC_LOG_HW_LINK_TRAINING("%s\n DPIA(%d) end\n - hop(%d)\n - result(%d)\n - LTTPR mode(%d)\n",
901 __func__,
902 link->link_id.enum_id - ENUM_ID_1,
903 hop,
904 result,
905 link->lttpr_mode);
906
907 return result;
908}
909
910
911
912
913
914
915
916
917static void dpia_training_abort(struct dc_link *link, uint32_t hop)
918{
919 uint8_t data = 0;
920 uint32_t dpcd_tps_offset = DP_TRAINING_PATTERN_SET;
921
922 DC_LOG_HW_LINK_TRAINING("%s\n DPIA(%d) aborting\n - LTTPR mode(%d)\n - HPD(%d)\n",
923 __func__,
924 link->link_id.enum_id - ENUM_ID_1,
925 link->lttpr_mode,
926 link->is_hpd_pending);
927
928
929 if (link->is_hpd_pending)
930 return;
931
932 if (hop != DPRX)
933 dpcd_tps_offset = DP_TRAINING_PATTERN_SET_PHY_REPEATER1 +
934 ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (hop - 1));
935
936 core_link_write_dpcd(link, dpcd_tps_offset, &data, 1);
937 core_link_write_dpcd(link, DP_LINK_BW_SET, &data, 1);
938 core_link_write_dpcd(link, DP_LANE_COUNT_SET, &data, 1);
939 core_link_send_set_config(link, DPIA_SET_CFG_SET_LINK, data);
940}
941
942enum link_training_result dc_link_dpia_perform_link_training(
943 struct dc_link *link,
944 const struct link_resource *link_res,
945 const struct dc_link_settings *link_setting,
946 bool skip_video_pattern)
947{
948 enum link_training_result result;
949 struct link_training_settings lt_settings;
950 uint8_t repeater_cnt = 0;
951 int8_t repeater_id;
952
953
954 result = dpia_configure_link(link, link_res, link_setting, <_settings);
955 if (result != LINK_TRAINING_SUCCESS)
956 return result;
957
958 if (link->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT)
959 repeater_cnt = dp_convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
960
961
962
963
964 for (repeater_id = repeater_cnt; repeater_id >= 0; repeater_id--) {
965
966 result = dpia_training_cr_phase(link, link_res, <_settings, repeater_id);
967 if (result != LINK_TRAINING_SUCCESS)
968 break;
969
970
971 result = dpia_training_eq_phase(link, link_res, <_settings, repeater_id);
972 if (result != LINK_TRAINING_SUCCESS)
973 break;
974
975
976 result = dpia_training_end(link, repeater_id);
977 if (result != LINK_TRAINING_SUCCESS)
978 break;
979 }
980
981
982
983
984
985
986 if (result == LINK_TRAINING_SUCCESS) {
987 msleep(5);
988 result = dp_check_link_loss_status(link, <_settings);
989 } else if (result == LINK_TRAINING_ABORT) {
990 dpia_training_abort(link, repeater_id);
991 } else {
992 dpia_training_end(link, repeater_id);
993 }
994 return result;
995}
996