]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/gpu/drm/tegra/dp.c
drm/tegra: dp: Track link capabilities alongside settings
[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_reset(struct drm_dp_link *link)
12 {
13         if (!link)
14                 return;
15
16         link->revision = 0;
17         link->max_rate = 0;
18         link->max_lanes = 0;
19         link->capabilities = 0;
20
21         link->rate = 0;
22         link->lanes = 0;
23 }
24
25 /**
26  * drm_dp_link_probe() - probe a DisplayPort link for capabilities
27  * @aux: DisplayPort AUX channel
28  * @link: pointer to structure in which to return link capabilities
29  *
30  * The structure filled in by this function can usually be passed directly
31  * into drm_dp_link_power_up() and drm_dp_link_configure() to power up and
32  * configure the link based on the link's capabilities.
33  *
34  * Returns 0 on success or a negative error code on failure.
35  */
36 int drm_dp_link_probe(struct drm_dp_aux *aux, struct drm_dp_link *link)
37 {
38         u8 values[3];
39         int err;
40
41         drm_dp_link_reset(link);
42
43         err = drm_dp_dpcd_read(aux, DP_DPCD_REV, values, sizeof(values));
44         if (err < 0)
45                 return err;
46
47         link->revision = values[0];
48         link->max_rate = drm_dp_bw_code_to_link_rate(values[1]);
49         link->max_lanes = values[2] & DP_MAX_LANE_COUNT_MASK;
50
51         if (values[2] & DP_ENHANCED_FRAME_CAP)
52                 link->capabilities |= DP_LINK_CAP_ENHANCED_FRAMING;
53
54         link->rate = link->max_rate;
55         link->lanes = link->max_lanes;
56
57         return 0;
58 }
59
60 /**
61  * drm_dp_link_power_up() - power up a DisplayPort link
62  * @aux: DisplayPort AUX channel
63  * @link: pointer to a structure containing the link configuration
64  *
65  * Returns 0 on success or a negative error code on failure.
66  */
67 int drm_dp_link_power_up(struct drm_dp_aux *aux, struct drm_dp_link *link)
68 {
69         u8 value;
70         int err;
71
72         /* DP_SET_POWER register is only available on DPCD v1.1 and later */
73         if (link->revision < 0x11)
74                 return 0;
75
76         err = drm_dp_dpcd_readb(aux, DP_SET_POWER, &value);
77         if (err < 0)
78                 return err;
79
80         value &= ~DP_SET_POWER_MASK;
81         value |= DP_SET_POWER_D0;
82
83         err = drm_dp_dpcd_writeb(aux, DP_SET_POWER, value);
84         if (err < 0)
85                 return err;
86
87         /*
88          * According to the DP 1.1 specification, a "Sink Device must exit the
89          * power saving state within 1 ms" (Section 2.5.3.1, Table 5-52, "Sink
90          * Control Field" (register 0x600).
91          */
92         usleep_range(1000, 2000);
93
94         return 0;
95 }
96
97 /**
98  * drm_dp_link_power_down() - power down a DisplayPort link
99  * @aux: DisplayPort AUX channel
100  * @link: pointer to a structure containing the link configuration
101  *
102  * Returns 0 on success or a negative error code on failure.
103  */
104 int drm_dp_link_power_down(struct drm_dp_aux *aux, struct drm_dp_link *link)
105 {
106         u8 value;
107         int err;
108
109         /* DP_SET_POWER register is only available on DPCD v1.1 and later */
110         if (link->revision < 0x11)
111                 return 0;
112
113         err = drm_dp_dpcd_readb(aux, DP_SET_POWER, &value);
114         if (err < 0)
115                 return err;
116
117         value &= ~DP_SET_POWER_MASK;
118         value |= DP_SET_POWER_D3;
119
120         err = drm_dp_dpcd_writeb(aux, DP_SET_POWER, value);
121         if (err < 0)
122                 return err;
123
124         return 0;
125 }
126
127 /**
128  * drm_dp_link_configure() - configure a DisplayPort link
129  * @aux: DisplayPort AUX channel
130  * @link: pointer to a structure containing the link configuration
131  *
132  * Returns 0 on success or a negative error code on failure.
133  */
134 int drm_dp_link_configure(struct drm_dp_aux *aux, struct drm_dp_link *link)
135 {
136         u8 values[2];
137         int err;
138
139         values[0] = drm_dp_link_rate_to_bw_code(link->rate);
140         values[1] = link->lanes;
141
142         if (link->capabilities & DP_LINK_CAP_ENHANCED_FRAMING)
143                 values[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
144
145         err = drm_dp_dpcd_write(aux, DP_LINK_BW_SET, values, sizeof(values));
146         if (err < 0)
147                 return err;
148
149         return 0;
150 }