Lines Matching +full:link +full:- +full:rate

1 // SPDX-License-Identifier: MIT
3 * Copyright (C) 2013-2019 NVIDIA Corporation
17 caps->enhanced_framing = false; in drm_dp_link_caps_reset()
18 caps->tps3_supported = false; in drm_dp_link_caps_reset()
19 caps->fast_training = false; in drm_dp_link_caps_reset()
20 caps->channel_coding = false; in drm_dp_link_caps_reset()
21 caps->alternate_scrambler_reset = false; in drm_dp_link_caps_reset()
27 dest->enhanced_framing = src->enhanced_framing; in drm_dp_link_caps_copy()
28 dest->tps3_supported = src->tps3_supported; in drm_dp_link_caps_copy()
29 dest->fast_training = src->fast_training; in drm_dp_link_caps_copy()
30 dest->channel_coding = src->channel_coding; in drm_dp_link_caps_copy()
31 dest->alternate_scrambler_reset = src->alternate_scrambler_reset; in drm_dp_link_caps_copy()
34 static void drm_dp_link_reset(struct drm_dp_link *link) in drm_dp_link_reset() argument
38 if (!link) in drm_dp_link_reset()
41 link->revision = 0; in drm_dp_link_reset()
42 link->max_rate = 0; in drm_dp_link_reset()
43 link->max_lanes = 0; in drm_dp_link_reset()
45 drm_dp_link_caps_reset(&link->caps); in drm_dp_link_reset()
46 link->aux_rd_interval.cr = 0; in drm_dp_link_reset()
47 link->aux_rd_interval.ce = 0; in drm_dp_link_reset()
48 link->edp = 0; in drm_dp_link_reset()
50 link->rate = 0; in drm_dp_link_reset()
51 link->lanes = 0; in drm_dp_link_reset()
54 link->rates[i] = 0; in drm_dp_link_reset()
56 link->num_rates = 0; in drm_dp_link_reset()
60 * drm_dp_link_add_rate() - add a rate to the list of supported rates
61 * @link: the link to add the rate to
62 * @rate: the rate to add
64 * Add a link rate to the list of supported link rates.
68 * - ENOSPC if the maximum number of supported rates has been reached
69 * - EEXISTS if the link already supports this rate
74 int drm_dp_link_add_rate(struct drm_dp_link *link, unsigned long rate) in drm_dp_link_add_rate() argument
78 if (link->num_rates == DP_MAX_SUPPORTED_RATES) in drm_dp_link_add_rate()
79 return -ENOSPC; in drm_dp_link_add_rate()
81 for (pivot = 0; pivot < link->num_rates; pivot++) in drm_dp_link_add_rate()
82 if (rate <= link->rates[pivot]) in drm_dp_link_add_rate()
85 if (pivot != link->num_rates && rate == link->rates[pivot]) in drm_dp_link_add_rate()
86 return -EEXIST; in drm_dp_link_add_rate()
88 for (i = link->num_rates; i > pivot; i--) in drm_dp_link_add_rate()
89 link->rates[i] = link->rates[i - 1]; in drm_dp_link_add_rate()
91 link->rates[pivot] = rate; in drm_dp_link_add_rate()
92 link->num_rates++; in drm_dp_link_add_rate()
98 * drm_dp_link_remove_rate() - remove a rate from the list of supported rates
99 * @link: the link from which to remove the rate
100 * @rate: the rate to remove
102 * Removes a link rate from the list of supported link rates.
106 * - EINVAL if the specified rate is not among the supported rates
111 int drm_dp_link_remove_rate(struct drm_dp_link *link, unsigned long rate) in drm_dp_link_remove_rate() argument
115 for (i = 0; i < link->num_rates; i++) in drm_dp_link_remove_rate()
116 if (rate == link->rates[i]) in drm_dp_link_remove_rate()
119 if (i == link->num_rates) in drm_dp_link_remove_rate()
120 return -EINVAL; in drm_dp_link_remove_rate()
122 link->num_rates--; in drm_dp_link_remove_rate()
124 while (i < link->num_rates) { in drm_dp_link_remove_rate()
125 link->rates[i] = link->rates[i + 1]; in drm_dp_link_remove_rate()
133 * drm_dp_link_update_rates() - normalize the supported link rates array
134 * @link: the link for which to normalize the supported link rates
137 * of supported link rates. This function removes any stale entries, compacts
138 * the array and updates the supported link rate count. Note that calling the
144 void drm_dp_link_update_rates(struct drm_dp_link *link) in drm_dp_link_update_rates() argument
148 for (i = 0; i < link->num_rates; i++) { in drm_dp_link_update_rates()
149 if (link->rates[i] != 0) in drm_dp_link_update_rates()
150 link->rates[count++] = link->rates[i]; in drm_dp_link_update_rates()
153 for (i = count; i < link->num_rates; i++) in drm_dp_link_update_rates()
154 link->rates[i] = 0; in drm_dp_link_update_rates()
156 link->num_rates = count; in drm_dp_link_update_rates()
160 * drm_dp_link_probe() - probe a DisplayPort link for capabilities
162 * @link: pointer to structure in which to return link capabilities
166 * configure the link based on the link's capabilities.
170 int drm_dp_link_probe(struct drm_dp_aux *aux, struct drm_dp_link *link) in drm_dp_link_probe() argument
176 drm_dp_link_reset(link); in drm_dp_link_probe()
182 link->revision = dpcd[DP_DPCD_REV]; in drm_dp_link_probe()
183 link->max_rate = drm_dp_max_link_rate(dpcd); in drm_dp_link_probe()
184 link->max_lanes = drm_dp_max_lane_count(dpcd); in drm_dp_link_probe()
186 link->caps.enhanced_framing = drm_dp_enhanced_frame_cap(dpcd); in drm_dp_link_probe()
187 link->caps.tps3_supported = drm_dp_tps3_supported(dpcd); in drm_dp_link_probe()
188 link->caps.fast_training = drm_dp_fast_training_cap(dpcd); in drm_dp_link_probe()
189 link->caps.channel_coding = drm_dp_channel_coding_supported(dpcd); in drm_dp_link_probe()
192 link->caps.alternate_scrambler_reset = true; in drm_dp_link_probe()
201 link->edp = drm_dp_edp_revisions[value]; in drm_dp_link_probe()
226 if (rd_interval == 0 || link->revision >= DP_DPCD_REV_14) in drm_dp_link_probe()
227 link->aux_rd_interval.cr = 100; in drm_dp_link_probe()
230 link->aux_rd_interval.ce = 400; in drm_dp_link_probe()
232 link->rate = link->max_rate; in drm_dp_link_probe()
233 link->lanes = link->max_lanes; in drm_dp_link_probe()
236 if (link->edp >= 0x14) { in drm_dp_link_probe()
239 u16 rate; in drm_dp_link_probe() local
248 rate = supported_rates[i * 2 + 1] << 8 | in drm_dp_link_probe()
251 drm_dp_link_add_rate(link, rate * 200); in drm_dp_link_probe()
259 * drm_dp_link_power_up() - power up a DisplayPort link
261 * @link: pointer to a structure containing the link configuration
265 int drm_dp_link_power_up(struct drm_dp_aux *aux, struct drm_dp_link *link) in drm_dp_link_power_up() argument
271 if (link->revision < 0x11) in drm_dp_link_power_up()
287 * power saving state within 1 ms" (Section 2.5.3.1, Table 5-52, "Sink in drm_dp_link_power_up()
296 * drm_dp_link_power_down() - power down a DisplayPort link
298 * @link: pointer to a structure containing the link configuration
302 int drm_dp_link_power_down(struct drm_dp_aux *aux, struct drm_dp_link *link) in drm_dp_link_power_down() argument
308 if (link->revision < 0x11) in drm_dp_link_power_down()
326 * drm_dp_link_configure() - configure a DisplayPort link
328 * @link: pointer to a structure containing the link configuration
332 int drm_dp_link_configure(struct drm_dp_aux *aux, struct drm_dp_link *link) in drm_dp_link_configure() argument
337 if (link->ops && link->ops->configure) { in drm_dp_link_configure()
338 err = link->ops->configure(link); in drm_dp_link_configure()
340 DRM_ERROR("failed to configure DP link: %d\n", err); in drm_dp_link_configure()
345 values[0] = drm_dp_link_rate_to_bw_code(link->rate); in drm_dp_link_configure()
346 values[1] = link->lanes; in drm_dp_link_configure()
348 if (link->caps.enhanced_framing) in drm_dp_link_configure()
355 if (link->caps.channel_coding) in drm_dp_link_configure()
364 if (link->caps.alternate_scrambler_reset) { in drm_dp_link_configure()
375 * drm_dp_link_choose() - choose the lowest possible configuration for a mode
376 * @link: DRM DP link object
381 * with the lowest number of lanes and the lowest possible link rate that can
387 int drm_dp_link_choose(struct drm_dp_link *link, in drm_dp_link_choose() argument
391 /* available link symbol clock rates */ in drm_dp_link_choose()
396 unsigned int rate = link->max_rate; in drm_dp_link_choose() local
400 requirement = mode->clock * info->bpc * 3; in drm_dp_link_choose()
402 for (i = 0; i < ARRAY_SIZE(lanes) && lanes[i] <= link->max_lanes; i++) { in drm_dp_link_choose()
403 for (j = 0; j < ARRAY_SIZE(rates) && rates[j] <= rate; j++) { in drm_dp_link_choose()
405 * Capacity for this combination of lanes and rate, in drm_dp_link_choose()
408 * Link rates in the DRM DP helpers are really link in drm_dp_link_choose()
409 * symbol frequencies, so a tenth of the actual rate in drm_dp_link_choose()
410 * of the link. in drm_dp_link_choose()
418 link->lanes = lanes[i]; in drm_dp_link_choose()
419 link->rate = rates[j]; in drm_dp_link_choose()
425 return -ERANGE; in drm_dp_link_choose()
429 * DOC: Link training
432 * link training.
436 * drm_dp_link_train_init() - initialize DisplayPort link training state
437 * @train: DisplayPort link training state
441 struct drm_dp_link_train_set *request = &train->request; in drm_dp_link_train_init()
442 struct drm_dp_link_train_set *adjust = &train->adjust; in drm_dp_link_train_init()
446 request->voltage_swing[i] = 0; in drm_dp_link_train_init()
447 adjust->voltage_swing[i] = 0; in drm_dp_link_train_init()
449 request->pre_emphasis[i] = 0; in drm_dp_link_train_init()
450 adjust->pre_emphasis[i] = 0; in drm_dp_link_train_init()
452 request->post_cursor[i] = 0; in drm_dp_link_train_init()
453 adjust->post_cursor[i] = 0; in drm_dp_link_train_init()
456 train->pattern = DP_TRAINING_PATTERN_DISABLE; in drm_dp_link_train_init()
457 train->clock_recovered = false; in drm_dp_link_train_init()
458 train->channel_equalized = false; in drm_dp_link_train_init()
463 return train->clock_recovered && train->channel_equalized; in drm_dp_link_train_valid()
466 static int drm_dp_link_apply_training(struct drm_dp_link *link) in drm_dp_link_apply_training() argument
468 struct drm_dp_link_train_set *request = &link->train.request; in drm_dp_link_apply_training()
469 unsigned int lanes = link->lanes, *vs, *pe, *pc, i; in drm_dp_link_apply_training()
470 struct drm_dp_aux *aux = link->aux; in drm_dp_link_apply_training()
474 err = link->ops->apply_training(link); in drm_dp_link_apply_training()
476 DRM_ERROR("failed to apply link training: %d\n", err); in drm_dp_link_apply_training()
480 vs = request->voltage_swing; in drm_dp_link_apply_training()
481 pe = request->pre_emphasis; in drm_dp_link_apply_training()
482 pc = request->post_cursor; in drm_dp_link_apply_training()
484 /* write currently selected voltage-swing and pre-emphasis levels */ in drm_dp_link_apply_training()
495 /* write currently selected post-cursor level (if supported) */ in drm_dp_link_apply_training()
496 if (link->revision >= 0x12 && link->rate == 540000) { in drm_dp_link_apply_training()
505 DRM_ERROR("failed to set post-cursor: %d\n", err); in drm_dp_link_apply_training()
510 /* write link pattern */ in drm_dp_link_apply_training()
511 if (link->train.pattern != DP_TRAINING_PATTERN_DISABLE) in drm_dp_link_apply_training()
514 pattern |= link->train.pattern; in drm_dp_link_apply_training()
525 static void drm_dp_link_train_wait(struct drm_dp_link *link) in drm_dp_link_train_wait() argument
529 switch (link->train.pattern) { in drm_dp_link_train_wait()
531 min = link->aux_rd_interval.cr; in drm_dp_link_train_wait()
536 min = link->aux_rd_interval.ce; in drm_dp_link_train_wait()
547 static void drm_dp_link_get_adjustments(struct drm_dp_link *link, in drm_dp_link_get_adjustments() argument
550 struct drm_dp_link_train_set *adjust = &link->train.adjust; in drm_dp_link_get_adjustments()
555 err = drm_dp_dpcd_read(link->aux, DP_ADJUST_REQUEST_POST_CURSOR2, in drm_dp_link_get_adjustments()
562 for (i = 0; i < link->lanes; i++) { in drm_dp_link_get_adjustments()
563 adjust->voltage_swing[i] = in drm_dp_link_get_adjustments()
567 adjust->pre_emphasis[i] = in drm_dp_link_get_adjustments()
571 adjust->post_cursor[i] = in drm_dp_link_get_adjustments()
578 struct drm_dp_link_train_set *request = &train->request; in drm_dp_link_train_adjust()
579 struct drm_dp_link_train_set *adjust = &train->adjust; in drm_dp_link_train_adjust()
583 if (request->voltage_swing[i] != adjust->voltage_swing[i]) in drm_dp_link_train_adjust()
584 request->voltage_swing[i] = adjust->voltage_swing[i]; in drm_dp_link_train_adjust()
587 if (request->pre_emphasis[i] != adjust->pre_emphasis[i]) in drm_dp_link_train_adjust()
588 request->pre_emphasis[i] = adjust->pre_emphasis[i]; in drm_dp_link_train_adjust()
591 if (request->post_cursor[i] != adjust->post_cursor[i]) in drm_dp_link_train_adjust()
592 request->post_cursor[i] = adjust->post_cursor[i]; in drm_dp_link_train_adjust()
595 static int drm_dp_link_recover_clock(struct drm_dp_link *link) in drm_dp_link_recover_clock() argument
600 err = drm_dp_link_apply_training(link); in drm_dp_link_recover_clock()
604 drm_dp_link_train_wait(link); in drm_dp_link_recover_clock()
606 err = drm_dp_dpcd_read_link_status(link->aux, status); in drm_dp_link_recover_clock()
608 DRM_ERROR("failed to read link status: %d\n", err); in drm_dp_link_recover_clock()
612 if (!drm_dp_clock_recovery_ok(status, link->lanes)) in drm_dp_link_recover_clock()
613 drm_dp_link_get_adjustments(link, status); in drm_dp_link_recover_clock()
615 link->train.clock_recovered = true; in drm_dp_link_recover_clock()
620 static int drm_dp_link_clock_recovery(struct drm_dp_link *link) in drm_dp_link_clock_recovery() argument
626 link->train.pattern = DP_TRAINING_PATTERN_1; in drm_dp_link_clock_recovery()
629 err = drm_dp_link_recover_clock(link); in drm_dp_link_clock_recovery()
635 if (link->train.clock_recovered) in drm_dp_link_clock_recovery()
638 drm_dp_link_train_adjust(&link->train); in drm_dp_link_clock_recovery()
644 static int drm_dp_link_equalize_channel(struct drm_dp_link *link) in drm_dp_link_equalize_channel() argument
646 struct drm_dp_aux *aux = link->aux; in drm_dp_link_equalize_channel()
650 err = drm_dp_link_apply_training(link); in drm_dp_link_equalize_channel()
654 drm_dp_link_train_wait(link); in drm_dp_link_equalize_channel()
658 DRM_ERROR("failed to read link status: %d\n", err); in drm_dp_link_equalize_channel()
662 if (!drm_dp_clock_recovery_ok(status, link->lanes)) { in drm_dp_link_equalize_channel()
664 link->train.clock_recovered = false; in drm_dp_link_equalize_channel()
668 if (!drm_dp_channel_eq_ok(status, link->lanes)) in drm_dp_link_equalize_channel()
669 drm_dp_link_get_adjustments(link, status); in drm_dp_link_equalize_channel()
671 link->train.channel_equalized = true; in drm_dp_link_equalize_channel()
676 static int drm_dp_link_channel_equalization(struct drm_dp_link *link) in drm_dp_link_channel_equalization() argument
682 if (link->caps.tps3_supported) in drm_dp_link_channel_equalization()
683 link->train.pattern = DP_TRAINING_PATTERN_3; in drm_dp_link_channel_equalization()
685 link->train.pattern = DP_TRAINING_PATTERN_2; in drm_dp_link_channel_equalization()
688 err = drm_dp_link_equalize_channel(link); in drm_dp_link_channel_equalization()
694 if (link->train.channel_equalized) in drm_dp_link_channel_equalization()
697 drm_dp_link_train_adjust(&link->train); in drm_dp_link_channel_equalization()
703 static int drm_dp_link_downgrade(struct drm_dp_link *link) in drm_dp_link_downgrade() argument
705 switch (link->rate) { in drm_dp_link_downgrade()
707 return -EINVAL; in drm_dp_link_downgrade()
710 link->rate = 162000; in drm_dp_link_downgrade()
714 link->rate = 270000; in drm_dp_link_downgrade()
721 static void drm_dp_link_train_disable(struct drm_dp_link *link) in drm_dp_link_train_disable() argument
725 link->train.pattern = DP_TRAINING_PATTERN_DISABLE; in drm_dp_link_train_disable()
727 err = drm_dp_link_apply_training(link); in drm_dp_link_train_disable()
729 DRM_ERROR("failed to disable link training: %d\n", err); in drm_dp_link_train_disable()
732 static int drm_dp_link_train_full(struct drm_dp_link *link) in drm_dp_link_train_full() argument
737 DRM_DEBUG_KMS("full-training link: %u lane%s at %u MHz\n", in drm_dp_link_train_full()
738 link->lanes, (link->lanes > 1) ? "s" : "", in drm_dp_link_train_full()
739 link->rate / 100); in drm_dp_link_train_full()
741 err = drm_dp_link_configure(link->aux, link); in drm_dp_link_train_full()
743 DRM_ERROR("failed to configure DP link: %d\n", err); in drm_dp_link_train_full()
747 err = drm_dp_link_clock_recovery(link); in drm_dp_link_train_full()
753 if (!link->train.clock_recovered) { in drm_dp_link_train_full()
754 DRM_ERROR("clock recovery failed, downgrading link\n"); in drm_dp_link_train_full()
756 err = drm_dp_link_downgrade(link); in drm_dp_link_train_full()
765 err = drm_dp_link_channel_equalization(link); in drm_dp_link_train_full()
771 if (!link->train.channel_equalized) { in drm_dp_link_train_full()
772 DRM_ERROR("channel equalization failed, downgrading link\n"); in drm_dp_link_train_full()
774 err = drm_dp_link_downgrade(link); in drm_dp_link_train_full()
784 drm_dp_link_train_disable(link); in drm_dp_link_train_full()
788 static int drm_dp_link_train_fast(struct drm_dp_link *link) in drm_dp_link_train_fast() argument
793 DRM_DEBUG_KMS("fast-training link: %u lane%s at %u MHz\n", in drm_dp_link_train_fast()
794 link->lanes, (link->lanes > 1) ? "s" : "", in drm_dp_link_train_fast()
795 link->rate / 100); in drm_dp_link_train_fast()
797 err = drm_dp_link_configure(link->aux, link); in drm_dp_link_train_fast()
799 DRM_ERROR("failed to configure DP link: %d\n", err); in drm_dp_link_train_fast()
804 link->train.pattern = DP_TRAINING_PATTERN_1; in drm_dp_link_train_fast()
806 err = drm_dp_link_apply_training(link); in drm_dp_link_train_fast()
813 if (link->caps.tps3_supported) in drm_dp_link_train_fast()
814 link->train.pattern = DP_TRAINING_PATTERN_3; in drm_dp_link_train_fast()
816 link->train.pattern = DP_TRAINING_PATTERN_2; in drm_dp_link_train_fast()
818 err = drm_dp_link_apply_training(link); in drm_dp_link_train_fast()
824 err = drm_dp_dpcd_read_link_status(link->aux, status); in drm_dp_link_train_fast()
826 DRM_ERROR("failed to read link status: %d\n", err); in drm_dp_link_train_fast()
830 if (!drm_dp_clock_recovery_ok(status, link->lanes)) { in drm_dp_link_train_fast()
832 err = -EIO; in drm_dp_link_train_fast()
835 if (!drm_dp_channel_eq_ok(status, link->lanes)) { in drm_dp_link_train_fast()
837 err = -EIO; in drm_dp_link_train_fast()
841 drm_dp_link_train_disable(link); in drm_dp_link_train_fast()
846 * drm_dp_link_train() - perform DisplayPort link training
847 * @link: a DP link object
849 * Uses the context stored in the DP link object to perform link training. It
850 * is expected that drivers will call drm_dp_link_probe() to obtain the link
851 * capabilities before performing link training.
853 * If the sink supports fast link training (no AUX CH handshake) and valid
855 * link training and fall back to full link training on failure.
859 int drm_dp_link_train(struct drm_dp_link *link) in drm_dp_link_train() argument
863 drm_dp_link_train_init(&link->train); in drm_dp_link_train()
865 if (link->caps.fast_training) { in drm_dp_link_train()
866 if (drm_dp_link_train_valid(&link->train)) { in drm_dp_link_train()
867 err = drm_dp_link_train_fast(link); in drm_dp_link_train()
869 DRM_ERROR("fast link training failed: %d\n", in drm_dp_link_train()
877 DRM_DEBUG_KMS("fast link training not supported\n"); in drm_dp_link_train()
880 err = drm_dp_link_train_full(link); in drm_dp_link_train()
882 DRM_ERROR("full link training failed: %d\n", err); in drm_dp_link_train()