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