]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/gpu/drm/tegra/dp.c
drm/tegra: dp: Read alternate scrambler reset capability from sink
[linux.git] / drivers / gpu / drm / tegra / dp.c
1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright (C) 2013-2019 NVIDIA Corporation
4  * Copyright (C) 2015 Rob Clark
5  */
6
7 #include <drm/drm_dp_helper.h>
8
9 #include "dp.h"
10
11 static void drm_dp_link_caps_reset(struct drm_dp_link_caps *caps)
12 {
13         caps->enhanced_framing = false;
14         caps->tps3_supported = false;
15         caps->fast_training = false;
16         caps->channel_coding = false;
17         caps->alternate_scrambler_reset = false;
18 }
19
20 void drm_dp_link_caps_copy(struct drm_dp_link_caps *dest,
21                            const struct drm_dp_link_caps *src)
22 {
23         dest->enhanced_framing = src->enhanced_framing;
24         dest->tps3_supported = src->tps3_supported;
25         dest->fast_training = src->fast_training;
26         dest->channel_coding = src->channel_coding;
27         dest->alternate_scrambler_reset = src->alternate_scrambler_reset;
28 }
29
30 static void drm_dp_link_reset(struct drm_dp_link *link)
31 {
32         if (!link)
33                 return;
34
35         link->revision = 0;
36         link->max_rate = 0;
37         link->max_lanes = 0;
38
39         drm_dp_link_caps_reset(&link->caps);
40
41         link->rate = 0;
42         link->lanes = 0;
43 }
44
45 /**
46  * drm_dp_link_probe() - probe a DisplayPort link for capabilities
47  * @aux: DisplayPort AUX channel
48  * @link: pointer to structure in which to return link capabilities
49  *
50  * The structure filled in by this function can usually be passed directly
51  * into drm_dp_link_power_up() and drm_dp_link_configure() to power up and
52  * configure the link based on the link's capabilities.
53  *
54  * Returns 0 on success or a negative error code on failure.
55  */
56 int drm_dp_link_probe(struct drm_dp_aux *aux, struct drm_dp_link *link)
57 {
58         u8 dpcd[DP_RECEIVER_CAP_SIZE];
59         int err;
60
61         drm_dp_link_reset(link);
62
63         err = drm_dp_dpcd_read(aux, DP_DPCD_REV, dpcd, sizeof(dpcd));
64         if (err < 0)
65                 return err;
66
67         link->revision = dpcd[DP_DPCD_REV];
68         link->max_rate = drm_dp_max_link_rate(dpcd);
69         link->max_lanes = drm_dp_max_lane_count(dpcd);
70
71         link->caps.enhanced_framing = drm_dp_enhanced_frame_cap(dpcd);
72         link->caps.tps3_supported = drm_dp_tps3_supported(dpcd);
73         link->caps.fast_training = drm_dp_fast_training_cap(dpcd);
74         link->caps.channel_coding = drm_dp_channel_coding_supported(dpcd);
75
76         if (drm_dp_alternate_scrambler_reset_cap(dpcd))
77                 link->caps.alternate_scrambler_reset = true;
78
79         link->rate = link->max_rate;
80         link->lanes = link->max_lanes;
81
82         return 0;
83 }
84
85 /**
86  * drm_dp_link_power_up() - power up a DisplayPort link
87  * @aux: DisplayPort AUX channel
88  * @link: pointer to a structure containing the link configuration
89  *
90  * Returns 0 on success or a negative error code on failure.
91  */
92 int drm_dp_link_power_up(struct drm_dp_aux *aux, struct drm_dp_link *link)
93 {
94         u8 value;
95         int err;
96
97         /* DP_SET_POWER register is only available on DPCD v1.1 and later */
98         if (link->revision < 0x11)
99                 return 0;
100
101         err = drm_dp_dpcd_readb(aux, DP_SET_POWER, &value);
102         if (err < 0)
103                 return err;
104
105         value &= ~DP_SET_POWER_MASK;
106         value |= DP_SET_POWER_D0;
107
108         err = drm_dp_dpcd_writeb(aux, DP_SET_POWER, value);
109         if (err < 0)
110                 return err;
111
112         /*
113          * According to the DP 1.1 specification, a "Sink Device must exit the
114          * power saving state within 1 ms" (Section 2.5.3.1, Table 5-52, "Sink
115          * Control Field" (register 0x600).
116          */
117         usleep_range(1000, 2000);
118
119         return 0;
120 }
121
122 /**
123  * drm_dp_link_power_down() - power down a DisplayPort link
124  * @aux: DisplayPort AUX channel
125  * @link: pointer to a structure containing the link configuration
126  *
127  * Returns 0 on success or a negative error code on failure.
128  */
129 int drm_dp_link_power_down(struct drm_dp_aux *aux, struct drm_dp_link *link)
130 {
131         u8 value;
132         int err;
133
134         /* DP_SET_POWER register is only available on DPCD v1.1 and later */
135         if (link->revision < 0x11)
136                 return 0;
137
138         err = drm_dp_dpcd_readb(aux, DP_SET_POWER, &value);
139         if (err < 0)
140                 return err;
141
142         value &= ~DP_SET_POWER_MASK;
143         value |= DP_SET_POWER_D3;
144
145         err = drm_dp_dpcd_writeb(aux, DP_SET_POWER, value);
146         if (err < 0)
147                 return err;
148
149         return 0;
150 }
151
152 /**
153  * drm_dp_link_configure() - configure a DisplayPort link
154  * @aux: DisplayPort AUX channel
155  * @link: pointer to a structure containing the link configuration
156  *
157  * Returns 0 on success or a negative error code on failure.
158  */
159 int drm_dp_link_configure(struct drm_dp_aux *aux, struct drm_dp_link *link)
160 {
161         u8 values[2];
162         int err;
163
164         values[0] = drm_dp_link_rate_to_bw_code(link->rate);
165         values[1] = link->lanes;
166
167         if (link->caps.enhanced_framing)
168                 values[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
169
170         err = drm_dp_dpcd_write(aux, DP_LINK_BW_SET, values, sizeof(values));
171         if (err < 0)
172                 return err;
173
174         return 0;
175 }