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