1 // SPDX-License-Identifier: MIT
3 * Copyright (C) 2013-2019 NVIDIA Corporation
4 * Copyright (C) 2015 Rob Clark
7 #include <drm/drm_dp_helper.h>
8 #include <drm/drm_print.h>
12 static const u8 drm_dp_edp_revisions[] = { 0x11, 0x12, 0x13, 0x14 };
14 static void drm_dp_link_caps_reset(struct drm_dp_link_caps *caps)
16 caps->enhanced_framing = false;
17 caps->tps3_supported = false;
18 caps->fast_training = false;
19 caps->channel_coding = false;
20 caps->alternate_scrambler_reset = false;
23 void drm_dp_link_caps_copy(struct drm_dp_link_caps *dest,
24 const struct drm_dp_link_caps *src)
26 dest->enhanced_framing = src->enhanced_framing;
27 dest->tps3_supported = src->tps3_supported;
28 dest->fast_training = src->fast_training;
29 dest->channel_coding = src->channel_coding;
30 dest->alternate_scrambler_reset = src->alternate_scrambler_reset;
33 static void drm_dp_link_reset(struct drm_dp_link *link)
42 drm_dp_link_caps_reset(&link->caps);
43 link->aux_rd_interval.cr = 0;
44 link->aux_rd_interval.ce = 0;
52 * drm_dp_link_probe() - probe a DisplayPort link for capabilities
53 * @aux: DisplayPort AUX channel
54 * @link: pointer to structure in which to return link capabilities
56 * The structure filled in by this function can usually be passed directly
57 * into drm_dp_link_power_up() and drm_dp_link_configure() to power up and
58 * configure the link based on the link's capabilities.
60 * Returns 0 on success or a negative error code on failure.
62 int drm_dp_link_probe(struct drm_dp_aux *aux, struct drm_dp_link *link)
64 u8 dpcd[DP_RECEIVER_CAP_SIZE], value;
65 unsigned int rd_interval;
68 drm_dp_link_reset(link);
70 err = drm_dp_dpcd_read(aux, DP_DPCD_REV, dpcd, sizeof(dpcd));
74 link->revision = dpcd[DP_DPCD_REV];
75 link->max_rate = drm_dp_max_link_rate(dpcd);
76 link->max_lanes = drm_dp_max_lane_count(dpcd);
78 link->caps.enhanced_framing = drm_dp_enhanced_frame_cap(dpcd);
79 link->caps.tps3_supported = drm_dp_tps3_supported(dpcd);
80 link->caps.fast_training = drm_dp_fast_training_cap(dpcd);
81 link->caps.channel_coding = drm_dp_channel_coding_supported(dpcd);
83 if (drm_dp_alternate_scrambler_reset_cap(dpcd)) {
84 link->caps.alternate_scrambler_reset = true;
86 err = drm_dp_dpcd_readb(aux, DP_EDP_DPCD_REV, &value);
90 if (value >= ARRAY_SIZE(drm_dp_edp_revisions))
91 DRM_ERROR("unsupported eDP version: %02x\n", value);
93 link->edp = drm_dp_edp_revisions[value];
97 * The DPCD stores the AUX read interval in units of 4 ms. There are
100 * 1) if the TRAINING_AUX_RD_INTERVAL field is 0, the clock recovery
101 * and channel equalization should use 100 us or 400 us AUX read
102 * intervals, respectively
104 * 2) for DP v1.4 and above, clock recovery should always use 100 us
107 rd_interval = dpcd[DP_TRAINING_AUX_RD_INTERVAL] &
108 DP_TRAINING_AUX_RD_MASK;
110 if (rd_interval > 4) {
111 DRM_DEBUG_KMS("AUX interval %u out of range (max. 4)\n",
116 rd_interval *= 4 * USEC_PER_MSEC;
118 if (rd_interval == 0 || link->revision >= DP_DPCD_REV_14)
119 link->aux_rd_interval.cr = 100;
121 if (rd_interval == 0)
122 link->aux_rd_interval.ce = 400;
124 link->rate = link->max_rate;
125 link->lanes = link->max_lanes;
131 * drm_dp_link_power_up() - power up a DisplayPort link
132 * @aux: DisplayPort AUX channel
133 * @link: pointer to a structure containing the link configuration
135 * Returns 0 on success or a negative error code on failure.
137 int drm_dp_link_power_up(struct drm_dp_aux *aux, struct drm_dp_link *link)
142 /* DP_SET_POWER register is only available on DPCD v1.1 and later */
143 if (link->revision < 0x11)
146 err = drm_dp_dpcd_readb(aux, DP_SET_POWER, &value);
150 value &= ~DP_SET_POWER_MASK;
151 value |= DP_SET_POWER_D0;
153 err = drm_dp_dpcd_writeb(aux, DP_SET_POWER, value);
158 * According to the DP 1.1 specification, a "Sink Device must exit the
159 * power saving state within 1 ms" (Section 2.5.3.1, Table 5-52, "Sink
160 * Control Field" (register 0x600).
162 usleep_range(1000, 2000);
168 * drm_dp_link_power_down() - power down a DisplayPort link
169 * @aux: DisplayPort AUX channel
170 * @link: pointer to a structure containing the link configuration
172 * Returns 0 on success or a negative error code on failure.
174 int drm_dp_link_power_down(struct drm_dp_aux *aux, struct drm_dp_link *link)
179 /* DP_SET_POWER register is only available on DPCD v1.1 and later */
180 if (link->revision < 0x11)
183 err = drm_dp_dpcd_readb(aux, DP_SET_POWER, &value);
187 value &= ~DP_SET_POWER_MASK;
188 value |= DP_SET_POWER_D3;
190 err = drm_dp_dpcd_writeb(aux, DP_SET_POWER, value);
198 * drm_dp_link_configure() - configure a DisplayPort link
199 * @aux: DisplayPort AUX channel
200 * @link: pointer to a structure containing the link configuration
202 * Returns 0 on success or a negative error code on failure.
204 int drm_dp_link_configure(struct drm_dp_aux *aux, struct drm_dp_link *link)
209 values[0] = drm_dp_link_rate_to_bw_code(link->rate);
210 values[1] = link->lanes;
212 if (link->caps.enhanced_framing)
213 values[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
215 err = drm_dp_dpcd_write(aux, DP_LINK_BW_SET, values, sizeof(values));
219 if (link->caps.channel_coding)
220 value = DP_SET_ANSI_8B10B;
224 err = drm_dp_dpcd_writeb(aux, DP_MAIN_LINK_CHANNEL_CODING_SET, value);