projects/linux·blob master · refs

820 lines · 19.7 KiB

1// SPDX-License-Identifier: MIT
2/*
3 * Copyright (C) 2013-2019 NVIDIA Corporation
4 * Copyright (C) 2015 Rob Clark
5 */
6
7#include <linux/string_choices.h>
8
9#include <drm/display/drm_dp_helper.h>
10#include <drm/drm_crtc.h>
11#include <drm/drm_print.h>
12
13#include "dp.h"
14
15static const u8 drm_dp_edp_revisions[] = { 0x11, 0x12, 0x13, 0x14 };
16
17static void drm_dp_link_caps_reset(struct drm_dp_link_caps *caps)
18{
19 caps->enhanced_framing = false;
20 caps->tps3_supported = false;
21 caps->fast_training = false;
22 caps->channel_coding = false;
23 caps->alternate_scrambler_reset = false;
24}
25
26void drm_dp_link_caps_copy(struct drm_dp_link_caps *dest,
27 const struct drm_dp_link_caps *src)
28{
29 dest->enhanced_framing = src->enhanced_framing;
30 dest->tps3_supported = src->tps3_supported;
31 dest->fast_training = src->fast_training;
32 dest->channel_coding = src->channel_coding;
33 dest->alternate_scrambler_reset = src->alternate_scrambler_reset;
34}
35
36static void drm_dp_link_reset(struct drm_dp_link *link)
37{
38 unsigned int i;
39
40 if (!link)
41 return;
42
43 link->revision = 0;
44 link->max_rate = 0;
45 link->max_lanes = 0;
46
47 drm_dp_link_caps_reset(&link->caps);
48 link->aux_rd_interval.cr = 0;
49 link->aux_rd_interval.ce = 0;
50 link->edp = 0;
51
52 link->rate = 0;
53 link->lanes = 0;
54
55 for (i = 0; i < DP_MAX_SUPPORTED_RATES; i++)
56 link->rates[i] = 0;
57
58 link->num_rates = 0;
59}
60
61/**
62 * drm_dp_link_add_rate() - add a rate to the list of supported rates
63 * @link: the link to add the rate to
64 * @rate: the rate to add
65 *
66 * Add a link rate to the list of supported link rates.
67 *
68 * Returns:
69 * 0 on success or one of the following negative error codes on failure:
70 * - ENOSPC if the maximum number of supported rates has been reached
71 * - EEXISTS if the link already supports this rate
72 *
73 * See also:
74 * drm_dp_link_remove_rate()
75 */
76int drm_dp_link_add_rate(struct drm_dp_link *link, unsigned long rate)
77{
78 unsigned int i, pivot;
79
80 if (link->num_rates == DP_MAX_SUPPORTED_RATES)
81 return -ENOSPC;
82
83 for (pivot = 0; pivot < link->num_rates; pivot++)
84 if (rate <= link->rates[pivot])
85 break;
86
87 if (pivot != link->num_rates && rate == link->rates[pivot])
88 return -EEXIST;
89
90 for (i = link->num_rates; i > pivot; i--)
91 link->rates[i] = link->rates[i - 1];
92
93 link->rates[pivot] = rate;
94 link->num_rates++;
95
96 return 0;
97}
98
99/**
100 * drm_dp_link_remove_rate() - remove a rate from the list of supported rates
101 * @link: the link from which to remove the rate
102 * @rate: the rate to remove
103 *
104 * Removes a link rate from the list of supported link rates.
105 *
106 * Returns:
107 * 0 on success or one of the following negative error codes on failure:
108 * - EINVAL if the specified rate is not among the supported rates
109 *
110 * See also:
111 * drm_dp_link_add_rate()
112 */
113int drm_dp_link_remove_rate(struct drm_dp_link *link, unsigned long rate)
114{
115 unsigned int i;
116
117 for (i = 0; i < link->num_rates; i++)
118 if (rate == link->rates[i])
119 break;
120
121 if (i == link->num_rates)
122 return -EINVAL;
123
124 link->num_rates--;
125
126 while (i < link->num_rates) {
127 link->rates[i] = link->rates[i + 1];
128 i++;
129 }
130
131 return 0;
132}
133
134/**
135 * drm_dp_link_update_rates() - normalize the supported link rates array
136 * @link: the link for which to normalize the supported link rates
137 *
138 * Users should call this function after they've manually modified the array
139 * of supported link rates. This function removes any stale entries, compacts
140 * the array and updates the supported link rate count. Note that calling the
141 * drm_dp_link_remove_rate() function already does this janitorial work.
142 *
143 * See also:
144 * drm_dp_link_add_rate(), drm_dp_link_remove_rate()
145 */
146void drm_dp_link_update_rates(struct drm_dp_link *link)
147{
148 unsigned int i, count = 0;
149
150 for (i = 0; i < link->num_rates; i++) {
151 if (link->rates[i] != 0)
152 link->rates[count++] = link->rates[i];
153 }
154
155 for (i = count; i < link->num_rates; i++)
156 link->rates[i] = 0;
157
158 link->num_rates = count;
159}
160
161/**
162 * drm_dp_link_probe() - probe a DisplayPort link for capabilities
163 * @aux: DisplayPort AUX channel
164 * @link: pointer to structure in which to return link capabilities
165 *
166 * The structure filled in by this function can usually be passed directly
167 * into drm_dp_link_power_up() and drm_dp_link_configure() to power up and
168 * configure the link based on the link's capabilities.
169 *
170 * Returns 0 on success or a negative error code on failure.
171 */
172int drm_dp_link_probe(struct drm_dp_aux *aux, struct drm_dp_link *link)
173{
174 u8 dpcd[DP_RECEIVER_CAP_SIZE], value;
175 unsigned int rd_interval;
176 int err;
177
178 drm_dp_link_reset(link);
179
180 err = drm_dp_dpcd_read(aux, DP_DPCD_REV, dpcd, sizeof(dpcd));
181 if (err < 0)
182 return err;
183
184 link->revision = dpcd[DP_DPCD_REV];
185 link->max_rate = drm_dp_max_link_rate(dpcd);
186 link->max_lanes = drm_dp_max_lane_count(dpcd);
187
188 link->caps.enhanced_framing = drm_dp_enhanced_frame_cap(dpcd);
189 link->caps.tps3_supported = drm_dp_tps3_supported(dpcd);
190 link->caps.fast_training = drm_dp_fast_training_cap(dpcd);
191 link->caps.channel_coding = drm_dp_channel_coding_supported(dpcd);
192
193 if (drm_dp_alternate_scrambler_reset_cap(dpcd)) {
194 link->caps.alternate_scrambler_reset = true;
195
196 err = drm_dp_dpcd_readb(aux, DP_EDP_DPCD_REV, &value);
197 if (err < 0)
198 return err;
199
200 if (value >= ARRAY_SIZE(drm_dp_edp_revisions))
201 DRM_ERROR("unsupported eDP version: %02x\n", value);
202 else
203 link->edp = drm_dp_edp_revisions[value];
204 }
205
206 /*
207 * The DPCD stores the AUX read interval in units of 4 ms. There are
208 * two special cases:
209 *
210 * 1) if the TRAINING_AUX_RD_INTERVAL field is 0, the clock recovery
211 * and channel equalization should use 100 us or 400 us AUX read
212 * intervals, respectively
213 *
214 * 2) for DP v1.4 and above, clock recovery should always use 100 us
215 * AUX read intervals
216 */
217 rd_interval = dpcd[DP_TRAINING_AUX_RD_INTERVAL] &
218 DP_TRAINING_AUX_RD_MASK;
219
220 if (rd_interval > 4) {
221 DRM_DEBUG_KMS("AUX interval %u out of range (max. 4)\n",
222 rd_interval);
223 rd_interval = 4;
224 }
225
226 rd_interval *= 4 * USEC_PER_MSEC;
227
228 if (rd_interval == 0 || link->revision >= DP_DPCD_REV_14)
229 link->aux_rd_interval.cr = 100;
230
231 if (rd_interval == 0)
232 link->aux_rd_interval.ce = 400;
233
234 link->rate = link->max_rate;
235 link->lanes = link->max_lanes;
236
237 /* Parse SUPPORTED_LINK_RATES from eDP 1.4 */
238 if (link->edp >= 0x14) {
239 u8 supported_rates[DP_MAX_SUPPORTED_RATES * 2];
240 unsigned int i;
241 u16 rate;
242
243 err = drm_dp_dpcd_read(aux, DP_SUPPORTED_LINK_RATES,
244 supported_rates,
245 sizeof(supported_rates));
246 if (err < 0)
247 return err;
248
249 for (i = 0; i < DP_MAX_SUPPORTED_RATES; i++) {
250 rate = supported_rates[i * 2 + 1] << 8 |
251 supported_rates[i * 2 + 0];
252
253 drm_dp_link_add_rate(link, rate * 200);
254 }
255 }
256
257 return 0;
258}
259
260/**
261 * drm_dp_link_configure() - configure a DisplayPort link
262 * @aux: DisplayPort AUX channel
263 * @link: pointer to a structure containing the link configuration
264 *
265 * Returns 0 on success or a negative error code on failure.
266 */
267int drm_dp_link_configure(struct drm_dp_aux *aux, struct drm_dp_link *link)
268{
269 u8 values[2], value;
270 int err;
271
272 if (link->ops && link->ops->configure) {
273 err = link->ops->configure(link);
274 if (err < 0) {
275 DRM_ERROR("failed to configure DP link: %d\n", err);
276 return err;
277 }
278 }
279
280 values[0] = drm_dp_link_rate_to_bw_code(link->rate);
281 values[1] = link->lanes;
282
283 if (link->caps.enhanced_framing)
284 values[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
285
286 err = drm_dp_dpcd_write(aux, DP_LINK_BW_SET, values, sizeof(values));
287 if (err < 0)
288 return err;
289
290 if (link->caps.channel_coding)
291 value = DP_SET_ANSI_8B10B;
292 else
293 value = 0;
294
295 err = drm_dp_dpcd_writeb(aux, DP_MAIN_LINK_CHANNEL_CODING_SET, value);
296 if (err < 0)
297 return err;
298
299 if (link->caps.alternate_scrambler_reset) {
300 err = drm_dp_dpcd_writeb(aux, DP_EDP_CONFIGURATION_SET,
301 DP_ALTERNATE_SCRAMBLER_RESET_ENABLE);
302 if (err < 0)
303 return err;
304 }
305
306 return 0;
307}
308
309/**
310 * drm_dp_link_choose() - choose the lowest possible configuration for a mode
311 * @link: DRM DP link object
312 * @mode: DRM display mode
313 * @info: DRM display information
314 *
315 * According to the eDP specification, a source should select a configuration
316 * with the lowest number of lanes and the lowest possible link rate that can
317 * match the bitrate requirements of a video mode. However it must ensure not
318 * to exceed the capabilities of the sink.
319 *
320 * Returns: 0 on success or a negative error code on failure.
321 */
322int drm_dp_link_choose(struct drm_dp_link *link,
323 const struct drm_display_mode *mode,
324 const struct drm_display_info *info)
325{
326 /* available link symbol clock rates */
327 static const unsigned int rates[3] = { 162000, 270000, 540000 };
328 /* available number of lanes */
329 static const unsigned int lanes[3] = { 1, 2, 4 };
330 unsigned long requirement, capacity;
331 unsigned int rate = link->max_rate;
332 unsigned int i, j;
333
334 /* bandwidth requirement */
335 requirement = mode->clock * info->bpc * 3;
336
337 for (i = 0; i < ARRAY_SIZE(lanes) && lanes[i] <= link->max_lanes; i++) {
338 for (j = 0; j < ARRAY_SIZE(rates) && rates[j] <= rate; j++) {
339 /*
340 * Capacity for this combination of lanes and rate,
341 * factoring in the ANSI 8B/10B encoding.
342 *
343 * Link rates in the DRM DP helpers are really link
344 * symbol frequencies, so a tenth of the actual rate
345 * of the link.
346 */
347 capacity = lanes[i] * (rates[j] * 10) * 8 / 10;
348
349 if (capacity >= requirement) {
350 DRM_DEBUG_KMS("using %u lanes at %u kHz (%lu/%lu kbps)\n",
351 lanes[i], rates[j], requirement,
352 capacity);
353 link->lanes = lanes[i];
354 link->rate = rates[j];
355 return 0;
356 }
357 }
358 }
359
360 return -ERANGE;
361}
362
363/**
364 * DOC: Link training
365 *
366 * These functions contain common logic and helpers to implement DisplayPort
367 * link training.
368 */
369
370/**
371 * drm_dp_link_train_init() - initialize DisplayPort link training state
372 * @train: DisplayPort link training state
373 */
374void drm_dp_link_train_init(struct drm_dp_link_train *train)
375{
376 struct drm_dp_link_train_set *request = &train->request;
377 struct drm_dp_link_train_set *adjust = &train->adjust;
378 unsigned int i;
379
380 for (i = 0; i < 4; i++) {
381 request->voltage_swing[i] = 0;
382 adjust->voltage_swing[i] = 0;
383
384 request->pre_emphasis[i] = 0;
385 adjust->pre_emphasis[i] = 0;
386
387 request->post_cursor[i] = 0;
388 adjust->post_cursor[i] = 0;
389 }
390
391 train->pattern = DP_TRAINING_PATTERN_DISABLE;
392 train->clock_recovered = false;
393 train->channel_equalized = false;
394}
395
396static bool drm_dp_link_train_valid(const struct drm_dp_link_train *train)
397{
398 return train->clock_recovered && train->channel_equalized;
399}
400
401static int drm_dp_link_apply_training(struct drm_dp_link *link)
402{
403 struct drm_dp_link_train_set *request = &link->train.request;
404 unsigned int lanes = link->lanes, *vs, *pe, *pc, i;
405 struct drm_dp_aux *aux = link->aux;
406 u8 values[4], pattern = 0;
407 int err;
408
409 err = link->ops->apply_training(link);
410 if (err < 0) {
411 DRM_ERROR("failed to apply link training: %d\n", err);
412 return err;
413 }
414
415 vs = request->voltage_swing;
416 pe = request->pre_emphasis;
417 pc = request->post_cursor;
418
419 /* write currently selected voltage-swing and pre-emphasis levels */
420 for (i = 0; i < lanes; i++)
421 values[i] = DP_TRAIN_VOLTAGE_SWING_LEVEL(vs[i]) |
422 DP_TRAIN_PRE_EMPHASIS_LEVEL(pe[i]);
423
424 err = drm_dp_dpcd_write(aux, DP_TRAINING_LANE0_SET, values, lanes);
425 if (err < 0) {
426 DRM_ERROR("failed to set training parameters: %d\n", err);
427 return err;
428 }
429
430 /* write currently selected post-cursor level (if supported) */
431 if (link->revision >= 0x12 && link->rate == 540000) {
432 values[0] = values[1] = 0;
433
434 for (i = 0; i < lanes; i++)
435 values[i / 2] |= DP_LANE_POST_CURSOR(i, pc[i]);
436
437 err = drm_dp_dpcd_write(aux, DP_TRAINING_LANE0_1_SET2, values,
438 DIV_ROUND_UP(lanes, 2));
439 if (err < 0) {
440 DRM_ERROR("failed to set post-cursor: %d\n", err);
441 return err;
442 }
443 }
444
445 /* write link pattern */
446 if (link->train.pattern != DP_TRAINING_PATTERN_DISABLE)
447 pattern |= DP_LINK_SCRAMBLING_DISABLE;
448
449 pattern |= link->train.pattern;
450
451 err = drm_dp_dpcd_writeb(aux, DP_TRAINING_PATTERN_SET, pattern);
452 if (err < 0) {
453 DRM_ERROR("failed to set training pattern: %d\n", err);
454 return err;
455 }
456
457 return 0;
458}
459
460static void drm_dp_link_train_wait(struct drm_dp_link *link)
461{
462 unsigned long min = 0;
463
464 switch (link->train.pattern) {
465 case DP_TRAINING_PATTERN_1:
466 min = link->aux_rd_interval.cr;
467 break;
468
469 case DP_TRAINING_PATTERN_2:
470 case DP_TRAINING_PATTERN_3:
471 min = link->aux_rd_interval.ce;
472 break;
473
474 default:
475 break;
476 }
477
478 if (min > 0)
479 usleep_range(min, 2 * min);
480}
481
482static void drm_dp_link_get_adjustments(struct drm_dp_link *link,
483 u8 status[DP_LINK_STATUS_SIZE])
484{
485 struct drm_dp_link_train_set *adjust = &link->train.adjust;
486 unsigned int i;
487 u8 post_cursor;
488 int err;
489
490 err = drm_dp_dpcd_read(link->aux, DP_ADJUST_REQUEST_POST_CURSOR2,
491 &post_cursor, sizeof(post_cursor));
492 if (err < 0) {
493 DRM_ERROR("failed to read post_cursor2: %d\n", err);
494 post_cursor = 0;
495 }
496
497 for (i = 0; i < link->lanes; i++) {
498 adjust->voltage_swing[i] =
499 drm_dp_get_adjust_request_voltage(status, i) >>
500 DP_TRAIN_VOLTAGE_SWING_SHIFT;
501
502 adjust->pre_emphasis[i] =
503 drm_dp_get_adjust_request_pre_emphasis(status, i) >>
504 DP_TRAIN_PRE_EMPHASIS_SHIFT;
505
506 adjust->post_cursor[i] =
507 (post_cursor >> (i << 1)) & 0x3;
508 }
509}
510
511static void drm_dp_link_train_adjust(struct drm_dp_link_train *train)
512{
513 struct drm_dp_link_train_set *request = &train->request;
514 struct drm_dp_link_train_set *adjust = &train->adjust;
515 unsigned int i;
516
517 for (i = 0; i < 4; i++)
518 if (request->voltage_swing[i] != adjust->voltage_swing[i])
519 request->voltage_swing[i] = adjust->voltage_swing[i];
520
521 for (i = 0; i < 4; i++)
522 if (request->pre_emphasis[i] != adjust->pre_emphasis[i])
523 request->pre_emphasis[i] = adjust->pre_emphasis[i];
524
525 for (i = 0; i < 4; i++)
526 if (request->post_cursor[i] != adjust->post_cursor[i])
527 request->post_cursor[i] = adjust->post_cursor[i];
528}
529
530static int drm_dp_link_recover_clock(struct drm_dp_link *link)
531{
532 u8 status[DP_LINK_STATUS_SIZE];
533 int err;
534
535 err = drm_dp_link_apply_training(link);
536 if (err < 0)
537 return err;
538
539 drm_dp_link_train_wait(link);
540
541 err = drm_dp_dpcd_read_link_status(link->aux, status);
542 if (err < 0) {
543 DRM_ERROR("failed to read link status: %d\n", err);
544 return err;
545 }
546
547 if (!drm_dp_clock_recovery_ok(status, link->lanes))
548 drm_dp_link_get_adjustments(link, status);
549 else
550 link->train.clock_recovered = true;
551
552 return 0;
553}
554
555static int drm_dp_link_clock_recovery(struct drm_dp_link *link)
556{
557 unsigned int repeat;
558 int err;
559
560 /* start clock recovery using training pattern 1 */
561 link->train.pattern = DP_TRAINING_PATTERN_1;
562
563 for (repeat = 1; repeat < 5; repeat++) {
564 err = drm_dp_link_recover_clock(link);
565 if (err < 0) {
566 DRM_ERROR("failed to recover clock: %d\n", err);
567 return err;
568 }
569
570 if (link->train.clock_recovered)
571 break;
572
573 drm_dp_link_train_adjust(&link->train);
574 }
575
576 return 0;
577}
578
579static int drm_dp_link_equalize_channel(struct drm_dp_link *link)
580{
581 struct drm_dp_aux *aux = link->aux;
582 u8 status[DP_LINK_STATUS_SIZE];
583 int err;
584
585 err = drm_dp_link_apply_training(link);
586 if (err < 0)
587 return err;
588
589 drm_dp_link_train_wait(link);
590
591 err = drm_dp_dpcd_read_link_status(aux, status);
592 if (err < 0) {
593 DRM_ERROR("failed to read link status: %d\n", err);
594 return err;
595 }
596
597 if (!drm_dp_clock_recovery_ok(status, link->lanes)) {
598 DRM_ERROR("clock recovery lost while equalizing channel\n");
599 link->train.clock_recovered = false;
600 return 0;
601 }
602
603 if (!drm_dp_channel_eq_ok(status, link->lanes))
604 drm_dp_link_get_adjustments(link, status);
605 else
606 link->train.channel_equalized = true;
607
608 return 0;
609}
610
611static int drm_dp_link_channel_equalization(struct drm_dp_link *link)
612{
613 unsigned int repeat;
614 int err;
615
616 /* start channel equalization using pattern 2 or 3 */
617 if (link->caps.tps3_supported)
618 link->train.pattern = DP_TRAINING_PATTERN_3;
619 else
620 link->train.pattern = DP_TRAINING_PATTERN_2;
621
622 for (repeat = 1; repeat < 5; repeat++) {
623 err = drm_dp_link_equalize_channel(link);
624 if (err < 0) {
625 DRM_ERROR("failed to equalize channel: %d\n", err);
626 return err;
627 }
628
629 if (link->train.channel_equalized)
630 break;
631
632 drm_dp_link_train_adjust(&link->train);
633 }
634
635 return 0;
636}
637
638static int drm_dp_link_downgrade(struct drm_dp_link *link)
639{
640 switch (link->rate) {
641 case 162000:
642 return -EINVAL;
643
644 case 270000:
645 link->rate = 162000;
646 break;
647
648 case 540000:
649 link->rate = 270000;
650 return 0;
651 }
652
653 return 0;
654}
655
656static void drm_dp_link_train_disable(struct drm_dp_link *link)
657{
658 int err;
659
660 link->train.pattern = DP_TRAINING_PATTERN_DISABLE;
661
662 err = drm_dp_link_apply_training(link);
663 if (err < 0)
664 DRM_ERROR("failed to disable link training: %d\n", err);
665}
666
667static int drm_dp_link_train_full(struct drm_dp_link *link)
668{
669 int err;
670
671retry:
672 DRM_DEBUG_KMS("full-training link: %u lane%s at %u MHz\n",
673 link->lanes, str_plural(link->lanes),
674 link->rate / 100);
675
676 err = drm_dp_link_configure(link->aux, link);
677 if (err < 0) {
678 DRM_ERROR("failed to configure DP link: %d\n", err);
679 return err;
680 }
681
682 err = drm_dp_link_clock_recovery(link);
683 if (err < 0) {
684 DRM_ERROR("clock recovery failed: %d\n", err);
685 goto out;
686 }
687
688 if (!link->train.clock_recovered) {
689 DRM_ERROR("clock recovery failed, downgrading link\n");
690
691 err = drm_dp_link_downgrade(link);
692 if (err < 0)
693 goto out;
694
695 goto retry;
696 }
697
698 DRM_DEBUG_KMS("clock recovery succeeded\n");
699
700 err = drm_dp_link_channel_equalization(link);
701 if (err < 0) {
702 DRM_ERROR("channel equalization failed: %d\n", err);
703 goto out;
704 }
705
706 if (!link->train.channel_equalized) {
707 DRM_ERROR("channel equalization failed, downgrading link\n");
708
709 err = drm_dp_link_downgrade(link);
710 if (err < 0)
711 goto out;
712
713 goto retry;
714 }
715
716 DRM_DEBUG_KMS("channel equalization succeeded\n");
717
718out:
719 drm_dp_link_train_disable(link);
720 return err;
721}
722
723static int drm_dp_link_train_fast(struct drm_dp_link *link)
724{
725 u8 status[DP_LINK_STATUS_SIZE];
726 int err;
727
728 DRM_DEBUG_KMS("fast-training link: %u lane%s at %u MHz\n",
729 link->lanes, str_plural(link->lanes),
730 link->rate / 100);
731
732 err = drm_dp_link_configure(link->aux, link);
733 if (err < 0) {
734 DRM_ERROR("failed to configure DP link: %d\n", err);
735 return err;
736 }
737
738 /* transmit training pattern 1 for 500 microseconds */
739 link->train.pattern = DP_TRAINING_PATTERN_1;
740
741 err = drm_dp_link_apply_training(link);
742 if (err < 0)
743 goto out;
744
745 usleep_range(500, 1000);
746
747 /* transmit training pattern 2 or 3 for 500 microseconds */
748 if (link->caps.tps3_supported)
749 link->train.pattern = DP_TRAINING_PATTERN_3;
750 else
751 link->train.pattern = DP_TRAINING_PATTERN_2;
752
753 err = drm_dp_link_apply_training(link);
754 if (err < 0)
755 goto out;
756
757 usleep_range(500, 1000);
758
759 err = drm_dp_dpcd_read_link_status(link->aux, status);
760 if (err < 0) {
761 DRM_ERROR("failed to read link status: %d\n", err);
762 goto out;
763 }
764
765 if (!drm_dp_clock_recovery_ok(status, link->lanes)) {
766 DRM_ERROR("clock recovery failed\n");
767 err = -EIO;
768 }
769
770 if (!drm_dp_channel_eq_ok(status, link->lanes)) {
771 DRM_ERROR("channel equalization failed\n");
772 err = -EIO;
773 }
774
775out:
776 drm_dp_link_train_disable(link);
777 return err;
778}
779
780/**
781 * drm_dp_link_train() - perform DisplayPort link training
782 * @link: a DP link object
783 *
784 * Uses the context stored in the DP link object to perform link training. It
785 * is expected that drivers will call drm_dp_link_probe() to obtain the link
786 * capabilities before performing link training.
787 *
788 * If the sink supports fast link training (no AUX CH handshake) and valid
789 * training settings are available, this function will try to perform fast
790 * link training and fall back to full link training on failure.
791 *
792 * Returns: 0 on success or a negative error code on failure.
793 */
794int drm_dp_link_train(struct drm_dp_link *link)
795{
796 int err;
797
798 drm_dp_link_train_init(&link->train);
799
800 if (link->caps.fast_training) {
801 if (drm_dp_link_train_valid(&link->train)) {
802 err = drm_dp_link_train_fast(link);
803 if (err < 0)
804 DRM_ERROR("fast link training failed: %d\n",
805 err);
806 else
807 return 0;
808 } else {
809 DRM_DEBUG_KMS("training parameters not available\n");
810 }
811 } else {
812 DRM_DEBUG_KMS("fast link training not supported\n");
813 }
814
815 err = drm_dp_link_train_full(link);
816 if (err < 0)
817 DRM_ERROR("full link training failed: %d\n", err);
818
819 return err;
820}