1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
4*4882a593Smuzhiyun */
5*4882a593Smuzhiyun
6*4882a593Smuzhiyun #define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include <drm/drm_print.h>
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #include "dp_link.h"
11*4882a593Smuzhiyun #include "dp_panel.h"
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun #define DP_TEST_REQUEST_MASK 0x7F
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun enum audio_sample_rate {
16*4882a593Smuzhiyun AUDIO_SAMPLE_RATE_32_KHZ = 0x00,
17*4882a593Smuzhiyun AUDIO_SAMPLE_RATE_44_1_KHZ = 0x01,
18*4882a593Smuzhiyun AUDIO_SAMPLE_RATE_48_KHZ = 0x02,
19*4882a593Smuzhiyun AUDIO_SAMPLE_RATE_88_2_KHZ = 0x03,
20*4882a593Smuzhiyun AUDIO_SAMPLE_RATE_96_KHZ = 0x04,
21*4882a593Smuzhiyun AUDIO_SAMPLE_RATE_176_4_KHZ = 0x05,
22*4882a593Smuzhiyun AUDIO_SAMPLE_RATE_192_KHZ = 0x06,
23*4882a593Smuzhiyun };
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun enum audio_pattern_type {
26*4882a593Smuzhiyun AUDIO_TEST_PATTERN_OPERATOR_DEFINED = 0x00,
27*4882a593Smuzhiyun AUDIO_TEST_PATTERN_SAWTOOTH = 0x01,
28*4882a593Smuzhiyun };
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun struct dp_link_request {
31*4882a593Smuzhiyun u32 test_requested;
32*4882a593Smuzhiyun u32 test_link_rate;
33*4882a593Smuzhiyun u32 test_lane_count;
34*4882a593Smuzhiyun };
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun struct dp_link_private {
37*4882a593Smuzhiyun u32 prev_sink_count;
38*4882a593Smuzhiyun struct device *dev;
39*4882a593Smuzhiyun struct drm_dp_aux *aux;
40*4882a593Smuzhiyun struct dp_link dp_link;
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun struct dp_link_request request;
43*4882a593Smuzhiyun struct mutex psm_mutex;
44*4882a593Smuzhiyun u8 link_status[DP_LINK_STATUS_SIZE];
45*4882a593Smuzhiyun };
46*4882a593Smuzhiyun
dp_aux_link_power_up(struct drm_dp_aux * aux,struct dp_link_info * link)47*4882a593Smuzhiyun static int dp_aux_link_power_up(struct drm_dp_aux *aux,
48*4882a593Smuzhiyun struct dp_link_info *link)
49*4882a593Smuzhiyun {
50*4882a593Smuzhiyun u8 value;
51*4882a593Smuzhiyun int err;
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun if (link->revision < 0x11)
54*4882a593Smuzhiyun return 0;
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun err = drm_dp_dpcd_readb(aux, DP_SET_POWER, &value);
57*4882a593Smuzhiyun if (err < 0)
58*4882a593Smuzhiyun return err;
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun value &= ~DP_SET_POWER_MASK;
61*4882a593Smuzhiyun value |= DP_SET_POWER_D0;
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun err = drm_dp_dpcd_writeb(aux, DP_SET_POWER, value);
64*4882a593Smuzhiyun if (err < 0)
65*4882a593Smuzhiyun return err;
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun usleep_range(1000, 2000);
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun return 0;
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun
dp_aux_link_power_down(struct drm_dp_aux * aux,struct dp_link_info * link)72*4882a593Smuzhiyun static int dp_aux_link_power_down(struct drm_dp_aux *aux,
73*4882a593Smuzhiyun struct dp_link_info *link)
74*4882a593Smuzhiyun {
75*4882a593Smuzhiyun u8 value;
76*4882a593Smuzhiyun int err;
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun if (link->revision < 0x11)
79*4882a593Smuzhiyun return 0;
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun err = drm_dp_dpcd_readb(aux, DP_SET_POWER, &value);
82*4882a593Smuzhiyun if (err < 0)
83*4882a593Smuzhiyun return err;
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun value &= ~DP_SET_POWER_MASK;
86*4882a593Smuzhiyun value |= DP_SET_POWER_D3;
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun err = drm_dp_dpcd_writeb(aux, DP_SET_POWER, value);
89*4882a593Smuzhiyun if (err < 0)
90*4882a593Smuzhiyun return err;
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun return 0;
93*4882a593Smuzhiyun }
94*4882a593Smuzhiyun
dp_link_get_period(struct dp_link_private * link,int const addr)95*4882a593Smuzhiyun static int dp_link_get_period(struct dp_link_private *link, int const addr)
96*4882a593Smuzhiyun {
97*4882a593Smuzhiyun int ret = 0;
98*4882a593Smuzhiyun u8 data;
99*4882a593Smuzhiyun u32 const max_audio_period = 0xA;
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun /* TEST_AUDIO_PERIOD_CH_XX */
102*4882a593Smuzhiyun if (drm_dp_dpcd_readb(link->aux, addr, &data) < 0) {
103*4882a593Smuzhiyun DRM_ERROR("failed to read test_audio_period (0x%x)\n", addr);
104*4882a593Smuzhiyun ret = -EINVAL;
105*4882a593Smuzhiyun goto exit;
106*4882a593Smuzhiyun }
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun /* Period - Bits 3:0 */
109*4882a593Smuzhiyun data = data & 0xF;
110*4882a593Smuzhiyun if ((int)data > max_audio_period) {
111*4882a593Smuzhiyun DRM_ERROR("invalid test_audio_period_ch_1 = 0x%x\n", data);
112*4882a593Smuzhiyun ret = -EINVAL;
113*4882a593Smuzhiyun goto exit;
114*4882a593Smuzhiyun }
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun ret = data;
117*4882a593Smuzhiyun exit:
118*4882a593Smuzhiyun return ret;
119*4882a593Smuzhiyun }
120*4882a593Smuzhiyun
dp_link_parse_audio_channel_period(struct dp_link_private * link)121*4882a593Smuzhiyun static int dp_link_parse_audio_channel_period(struct dp_link_private *link)
122*4882a593Smuzhiyun {
123*4882a593Smuzhiyun int ret = 0;
124*4882a593Smuzhiyun struct dp_link_test_audio *req = &link->dp_link.test_audio;
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH1);
127*4882a593Smuzhiyun if (ret == -EINVAL)
128*4882a593Smuzhiyun goto exit;
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun req->test_audio_period_ch_1 = ret;
131*4882a593Smuzhiyun DRM_DEBUG_DP("test_audio_period_ch_1 = 0x%x\n", ret);
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH2);
134*4882a593Smuzhiyun if (ret == -EINVAL)
135*4882a593Smuzhiyun goto exit;
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun req->test_audio_period_ch_2 = ret;
138*4882a593Smuzhiyun DRM_DEBUG_DP("test_audio_period_ch_2 = 0x%x\n", ret);
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun /* TEST_AUDIO_PERIOD_CH_3 (Byte 0x275) */
141*4882a593Smuzhiyun ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH3);
142*4882a593Smuzhiyun if (ret == -EINVAL)
143*4882a593Smuzhiyun goto exit;
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun req->test_audio_period_ch_3 = ret;
146*4882a593Smuzhiyun DRM_DEBUG_DP("test_audio_period_ch_3 = 0x%x\n", ret);
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH4);
149*4882a593Smuzhiyun if (ret == -EINVAL)
150*4882a593Smuzhiyun goto exit;
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun req->test_audio_period_ch_4 = ret;
153*4882a593Smuzhiyun DRM_DEBUG_DP("test_audio_period_ch_4 = 0x%x\n", ret);
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH5);
156*4882a593Smuzhiyun if (ret == -EINVAL)
157*4882a593Smuzhiyun goto exit;
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun req->test_audio_period_ch_5 = ret;
160*4882a593Smuzhiyun DRM_DEBUG_DP("test_audio_period_ch_5 = 0x%x\n", ret);
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH6);
163*4882a593Smuzhiyun if (ret == -EINVAL)
164*4882a593Smuzhiyun goto exit;
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun req->test_audio_period_ch_6 = ret;
167*4882a593Smuzhiyun DRM_DEBUG_DP("test_audio_period_ch_6 = 0x%x\n", ret);
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH7);
170*4882a593Smuzhiyun if (ret == -EINVAL)
171*4882a593Smuzhiyun goto exit;
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun req->test_audio_period_ch_7 = ret;
174*4882a593Smuzhiyun DRM_DEBUG_DP("test_audio_period_ch_7 = 0x%x\n", ret);
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH8);
177*4882a593Smuzhiyun if (ret == -EINVAL)
178*4882a593Smuzhiyun goto exit;
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun req->test_audio_period_ch_8 = ret;
181*4882a593Smuzhiyun DRM_DEBUG_DP("test_audio_period_ch_8 = 0x%x\n", ret);
182*4882a593Smuzhiyun exit:
183*4882a593Smuzhiyun return ret;
184*4882a593Smuzhiyun }
185*4882a593Smuzhiyun
dp_link_parse_audio_pattern_type(struct dp_link_private * link)186*4882a593Smuzhiyun static int dp_link_parse_audio_pattern_type(struct dp_link_private *link)
187*4882a593Smuzhiyun {
188*4882a593Smuzhiyun int ret = 0;
189*4882a593Smuzhiyun u8 data;
190*4882a593Smuzhiyun ssize_t rlen;
191*4882a593Smuzhiyun int const max_audio_pattern_type = 0x1;
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun rlen = drm_dp_dpcd_readb(link->aux,
194*4882a593Smuzhiyun DP_TEST_AUDIO_PATTERN_TYPE, &data);
195*4882a593Smuzhiyun if (rlen < 0) {
196*4882a593Smuzhiyun DRM_ERROR("failed to read link audio mode. rlen=%zd\n", rlen);
197*4882a593Smuzhiyun return rlen;
198*4882a593Smuzhiyun }
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun /* Audio Pattern Type - Bits 7:0 */
201*4882a593Smuzhiyun if ((int)data > max_audio_pattern_type) {
202*4882a593Smuzhiyun DRM_ERROR("invalid audio pattern type = 0x%x\n", data);
203*4882a593Smuzhiyun ret = -EINVAL;
204*4882a593Smuzhiyun goto exit;
205*4882a593Smuzhiyun }
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun link->dp_link.test_audio.test_audio_pattern_type = data;
208*4882a593Smuzhiyun DRM_DEBUG_DP("audio pattern type = 0x%x\n", data);
209*4882a593Smuzhiyun exit:
210*4882a593Smuzhiyun return ret;
211*4882a593Smuzhiyun }
212*4882a593Smuzhiyun
dp_link_parse_audio_mode(struct dp_link_private * link)213*4882a593Smuzhiyun static int dp_link_parse_audio_mode(struct dp_link_private *link)
214*4882a593Smuzhiyun {
215*4882a593Smuzhiyun int ret = 0;
216*4882a593Smuzhiyun u8 data;
217*4882a593Smuzhiyun ssize_t rlen;
218*4882a593Smuzhiyun int const max_audio_sampling_rate = 0x6;
219*4882a593Smuzhiyun int const max_audio_channel_count = 0x8;
220*4882a593Smuzhiyun int sampling_rate = 0x0;
221*4882a593Smuzhiyun int channel_count = 0x0;
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun rlen = drm_dp_dpcd_readb(link->aux, DP_TEST_AUDIO_MODE, &data);
224*4882a593Smuzhiyun if (rlen < 0) {
225*4882a593Smuzhiyun DRM_ERROR("failed to read link audio mode. rlen=%zd\n", rlen);
226*4882a593Smuzhiyun return rlen;
227*4882a593Smuzhiyun }
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun /* Sampling Rate - Bits 3:0 */
230*4882a593Smuzhiyun sampling_rate = data & 0xF;
231*4882a593Smuzhiyun if (sampling_rate > max_audio_sampling_rate) {
232*4882a593Smuzhiyun DRM_ERROR("sampling rate (0x%x) greater than max (0x%x)\n",
233*4882a593Smuzhiyun sampling_rate, max_audio_sampling_rate);
234*4882a593Smuzhiyun ret = -EINVAL;
235*4882a593Smuzhiyun goto exit;
236*4882a593Smuzhiyun }
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun /* Channel Count - Bits 7:4 */
239*4882a593Smuzhiyun channel_count = ((data & 0xF0) >> 4) + 1;
240*4882a593Smuzhiyun if (channel_count > max_audio_channel_count) {
241*4882a593Smuzhiyun DRM_ERROR("channel_count (0x%x) greater than max (0x%x)\n",
242*4882a593Smuzhiyun channel_count, max_audio_channel_count);
243*4882a593Smuzhiyun ret = -EINVAL;
244*4882a593Smuzhiyun goto exit;
245*4882a593Smuzhiyun }
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun link->dp_link.test_audio.test_audio_sampling_rate = sampling_rate;
248*4882a593Smuzhiyun link->dp_link.test_audio.test_audio_channel_count = channel_count;
249*4882a593Smuzhiyun DRM_DEBUG_DP("sampling_rate = 0x%x, channel_count = 0x%x\n",
250*4882a593Smuzhiyun sampling_rate, channel_count);
251*4882a593Smuzhiyun exit:
252*4882a593Smuzhiyun return ret;
253*4882a593Smuzhiyun }
254*4882a593Smuzhiyun
dp_link_parse_audio_pattern_params(struct dp_link_private * link)255*4882a593Smuzhiyun static int dp_link_parse_audio_pattern_params(struct dp_link_private *link)
256*4882a593Smuzhiyun {
257*4882a593Smuzhiyun int ret = 0;
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun ret = dp_link_parse_audio_mode(link);
260*4882a593Smuzhiyun if (ret)
261*4882a593Smuzhiyun goto exit;
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun ret = dp_link_parse_audio_pattern_type(link);
264*4882a593Smuzhiyun if (ret)
265*4882a593Smuzhiyun goto exit;
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun ret = dp_link_parse_audio_channel_period(link);
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun exit:
270*4882a593Smuzhiyun return ret;
271*4882a593Smuzhiyun }
272*4882a593Smuzhiyun
dp_link_is_video_pattern_valid(u32 pattern)273*4882a593Smuzhiyun static bool dp_link_is_video_pattern_valid(u32 pattern)
274*4882a593Smuzhiyun {
275*4882a593Smuzhiyun switch (pattern) {
276*4882a593Smuzhiyun case DP_NO_TEST_PATTERN:
277*4882a593Smuzhiyun case DP_COLOR_RAMP:
278*4882a593Smuzhiyun case DP_BLACK_AND_WHITE_VERTICAL_LINES:
279*4882a593Smuzhiyun case DP_COLOR_SQUARE:
280*4882a593Smuzhiyun return true;
281*4882a593Smuzhiyun default:
282*4882a593Smuzhiyun return false;
283*4882a593Smuzhiyun }
284*4882a593Smuzhiyun }
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun /**
287*4882a593Smuzhiyun * dp_link_is_bit_depth_valid() - validates the bit depth requested
288*4882a593Smuzhiyun * @tbd: bit depth requested by the sink
289*4882a593Smuzhiyun *
290*4882a593Smuzhiyun * Returns true if the requested bit depth is supported.
291*4882a593Smuzhiyun */
dp_link_is_bit_depth_valid(u32 tbd)292*4882a593Smuzhiyun static bool dp_link_is_bit_depth_valid(u32 tbd)
293*4882a593Smuzhiyun {
294*4882a593Smuzhiyun /* DP_TEST_VIDEO_PATTERN_NONE is treated as invalid */
295*4882a593Smuzhiyun switch (tbd) {
296*4882a593Smuzhiyun case DP_TEST_BIT_DEPTH_6:
297*4882a593Smuzhiyun case DP_TEST_BIT_DEPTH_8:
298*4882a593Smuzhiyun case DP_TEST_BIT_DEPTH_10:
299*4882a593Smuzhiyun return true;
300*4882a593Smuzhiyun default:
301*4882a593Smuzhiyun return false;
302*4882a593Smuzhiyun }
303*4882a593Smuzhiyun }
304*4882a593Smuzhiyun
dp_link_parse_timing_params1(struct dp_link_private * link,int addr,int len,u32 * val)305*4882a593Smuzhiyun static int dp_link_parse_timing_params1(struct dp_link_private *link,
306*4882a593Smuzhiyun int addr, int len, u32 *val)
307*4882a593Smuzhiyun {
308*4882a593Smuzhiyun u8 bp[2];
309*4882a593Smuzhiyun int rlen;
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun if (len != 2)
312*4882a593Smuzhiyun return -EINVAL;
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun /* Read the requested video link pattern (Byte 0x221). */
315*4882a593Smuzhiyun rlen = drm_dp_dpcd_read(link->aux, addr, bp, len);
316*4882a593Smuzhiyun if (rlen < len) {
317*4882a593Smuzhiyun DRM_ERROR("failed to read 0x%x\n", addr);
318*4882a593Smuzhiyun return -EINVAL;
319*4882a593Smuzhiyun }
320*4882a593Smuzhiyun
321*4882a593Smuzhiyun *val = bp[1] | (bp[0] << 8);
322*4882a593Smuzhiyun
323*4882a593Smuzhiyun return 0;
324*4882a593Smuzhiyun }
325*4882a593Smuzhiyun
dp_link_parse_timing_params2(struct dp_link_private * link,int addr,int len,u32 * val1,u32 * val2)326*4882a593Smuzhiyun static int dp_link_parse_timing_params2(struct dp_link_private *link,
327*4882a593Smuzhiyun int addr, int len,
328*4882a593Smuzhiyun u32 *val1, u32 *val2)
329*4882a593Smuzhiyun {
330*4882a593Smuzhiyun u8 bp[2];
331*4882a593Smuzhiyun int rlen;
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun if (len != 2)
334*4882a593Smuzhiyun return -EINVAL;
335*4882a593Smuzhiyun
336*4882a593Smuzhiyun /* Read the requested video link pattern (Byte 0x221). */
337*4882a593Smuzhiyun rlen = drm_dp_dpcd_read(link->aux, addr, bp, len);
338*4882a593Smuzhiyun if (rlen < len) {
339*4882a593Smuzhiyun DRM_ERROR("failed to read 0x%x\n", addr);
340*4882a593Smuzhiyun return -EINVAL;
341*4882a593Smuzhiyun }
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun *val1 = (bp[0] & BIT(7)) >> 7;
344*4882a593Smuzhiyun *val2 = bp[1] | ((bp[0] & 0x7F) << 8);
345*4882a593Smuzhiyun
346*4882a593Smuzhiyun return 0;
347*4882a593Smuzhiyun }
348*4882a593Smuzhiyun
dp_link_parse_timing_params3(struct dp_link_private * link,int addr,u32 * val)349*4882a593Smuzhiyun static int dp_link_parse_timing_params3(struct dp_link_private *link,
350*4882a593Smuzhiyun int addr, u32 *val)
351*4882a593Smuzhiyun {
352*4882a593Smuzhiyun u8 bp;
353*4882a593Smuzhiyun u32 len = 1;
354*4882a593Smuzhiyun int rlen;
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun rlen = drm_dp_dpcd_read(link->aux, addr, &bp, len);
357*4882a593Smuzhiyun if (rlen < 1) {
358*4882a593Smuzhiyun DRM_ERROR("failed to read 0x%x\n", addr);
359*4882a593Smuzhiyun return -EINVAL;
360*4882a593Smuzhiyun }
361*4882a593Smuzhiyun *val = bp;
362*4882a593Smuzhiyun
363*4882a593Smuzhiyun return 0;
364*4882a593Smuzhiyun }
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun /**
367*4882a593Smuzhiyun * dp_parse_video_pattern_params() - parses video pattern parameters from DPCD
368*4882a593Smuzhiyun * @link: Display Port Driver data
369*4882a593Smuzhiyun *
370*4882a593Smuzhiyun * Returns 0 if it successfully parses the video link pattern and the link
371*4882a593Smuzhiyun * bit depth requested by the sink and, and if the values parsed are valid.
372*4882a593Smuzhiyun */
dp_link_parse_video_pattern_params(struct dp_link_private * link)373*4882a593Smuzhiyun static int dp_link_parse_video_pattern_params(struct dp_link_private *link)
374*4882a593Smuzhiyun {
375*4882a593Smuzhiyun int ret = 0;
376*4882a593Smuzhiyun ssize_t rlen;
377*4882a593Smuzhiyun u8 bp;
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun rlen = drm_dp_dpcd_readb(link->aux, DP_TEST_PATTERN, &bp);
380*4882a593Smuzhiyun if (rlen < 0) {
381*4882a593Smuzhiyun DRM_ERROR("failed to read link video pattern. rlen=%zd\n",
382*4882a593Smuzhiyun rlen);
383*4882a593Smuzhiyun return rlen;
384*4882a593Smuzhiyun }
385*4882a593Smuzhiyun
386*4882a593Smuzhiyun if (!dp_link_is_video_pattern_valid(bp)) {
387*4882a593Smuzhiyun DRM_ERROR("invalid link video pattern = 0x%x\n", bp);
388*4882a593Smuzhiyun ret = -EINVAL;
389*4882a593Smuzhiyun return ret;
390*4882a593Smuzhiyun }
391*4882a593Smuzhiyun
392*4882a593Smuzhiyun link->dp_link.test_video.test_video_pattern = bp;
393*4882a593Smuzhiyun
394*4882a593Smuzhiyun /* Read the requested color bit depth and dynamic range (Byte 0x232) */
395*4882a593Smuzhiyun rlen = drm_dp_dpcd_readb(link->aux, DP_TEST_MISC0, &bp);
396*4882a593Smuzhiyun if (rlen < 0) {
397*4882a593Smuzhiyun DRM_ERROR("failed to read link bit depth. rlen=%zd\n", rlen);
398*4882a593Smuzhiyun return rlen;
399*4882a593Smuzhiyun }
400*4882a593Smuzhiyun
401*4882a593Smuzhiyun /* Dynamic Range */
402*4882a593Smuzhiyun link->dp_link.test_video.test_dyn_range =
403*4882a593Smuzhiyun (bp & DP_TEST_DYNAMIC_RANGE_CEA);
404*4882a593Smuzhiyun
405*4882a593Smuzhiyun /* Color bit depth */
406*4882a593Smuzhiyun bp &= DP_TEST_BIT_DEPTH_MASK;
407*4882a593Smuzhiyun if (!dp_link_is_bit_depth_valid(bp)) {
408*4882a593Smuzhiyun DRM_ERROR("invalid link bit depth = 0x%x\n", bp);
409*4882a593Smuzhiyun ret = -EINVAL;
410*4882a593Smuzhiyun return ret;
411*4882a593Smuzhiyun }
412*4882a593Smuzhiyun
413*4882a593Smuzhiyun link->dp_link.test_video.test_bit_depth = bp;
414*4882a593Smuzhiyun
415*4882a593Smuzhiyun /* resolution timing params */
416*4882a593Smuzhiyun ret = dp_link_parse_timing_params1(link, DP_TEST_H_TOTAL_HI, 2,
417*4882a593Smuzhiyun &link->dp_link.test_video.test_h_total);
418*4882a593Smuzhiyun if (ret) {
419*4882a593Smuzhiyun DRM_ERROR("failed to parse test_htotal(DP_TEST_H_TOTAL_HI)\n");
420*4882a593Smuzhiyun return ret;
421*4882a593Smuzhiyun }
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun ret = dp_link_parse_timing_params1(link, DP_TEST_V_TOTAL_HI, 2,
424*4882a593Smuzhiyun &link->dp_link.test_video.test_v_total);
425*4882a593Smuzhiyun if (ret) {
426*4882a593Smuzhiyun DRM_ERROR("failed to parse test_v_total(DP_TEST_V_TOTAL_HI)\n");
427*4882a593Smuzhiyun return ret;
428*4882a593Smuzhiyun }
429*4882a593Smuzhiyun
430*4882a593Smuzhiyun ret = dp_link_parse_timing_params1(link, DP_TEST_H_START_HI, 2,
431*4882a593Smuzhiyun &link->dp_link.test_video.test_h_start);
432*4882a593Smuzhiyun if (ret) {
433*4882a593Smuzhiyun DRM_ERROR("failed to parse test_h_start(DP_TEST_H_START_HI)\n");
434*4882a593Smuzhiyun return ret;
435*4882a593Smuzhiyun }
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun ret = dp_link_parse_timing_params1(link, DP_TEST_V_START_HI, 2,
438*4882a593Smuzhiyun &link->dp_link.test_video.test_v_start);
439*4882a593Smuzhiyun if (ret) {
440*4882a593Smuzhiyun DRM_ERROR("failed to parse test_v_start(DP_TEST_V_START_HI)\n");
441*4882a593Smuzhiyun return ret;
442*4882a593Smuzhiyun }
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun ret = dp_link_parse_timing_params2(link, DP_TEST_HSYNC_HI, 2,
445*4882a593Smuzhiyun &link->dp_link.test_video.test_hsync_pol,
446*4882a593Smuzhiyun &link->dp_link.test_video.test_hsync_width);
447*4882a593Smuzhiyun if (ret) {
448*4882a593Smuzhiyun DRM_ERROR("failed to parse (DP_TEST_HSYNC_HI)\n");
449*4882a593Smuzhiyun return ret;
450*4882a593Smuzhiyun }
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun ret = dp_link_parse_timing_params2(link, DP_TEST_VSYNC_HI, 2,
453*4882a593Smuzhiyun &link->dp_link.test_video.test_vsync_pol,
454*4882a593Smuzhiyun &link->dp_link.test_video.test_vsync_width);
455*4882a593Smuzhiyun if (ret) {
456*4882a593Smuzhiyun DRM_ERROR("failed to parse (DP_TEST_VSYNC_HI)\n");
457*4882a593Smuzhiyun return ret;
458*4882a593Smuzhiyun }
459*4882a593Smuzhiyun
460*4882a593Smuzhiyun ret = dp_link_parse_timing_params1(link, DP_TEST_H_WIDTH_HI, 2,
461*4882a593Smuzhiyun &link->dp_link.test_video.test_h_width);
462*4882a593Smuzhiyun if (ret) {
463*4882a593Smuzhiyun DRM_ERROR("failed to parse test_h_width(DP_TEST_H_WIDTH_HI)\n");
464*4882a593Smuzhiyun return ret;
465*4882a593Smuzhiyun }
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun ret = dp_link_parse_timing_params1(link, DP_TEST_V_HEIGHT_HI, 2,
468*4882a593Smuzhiyun &link->dp_link.test_video.test_v_height);
469*4882a593Smuzhiyun if (ret) {
470*4882a593Smuzhiyun DRM_ERROR("failed to parse test_v_height\n");
471*4882a593Smuzhiyun return ret;
472*4882a593Smuzhiyun }
473*4882a593Smuzhiyun
474*4882a593Smuzhiyun ret = dp_link_parse_timing_params3(link, DP_TEST_MISC1,
475*4882a593Smuzhiyun &link->dp_link.test_video.test_rr_d);
476*4882a593Smuzhiyun link->dp_link.test_video.test_rr_d &= DP_TEST_REFRESH_DENOMINATOR;
477*4882a593Smuzhiyun if (ret) {
478*4882a593Smuzhiyun DRM_ERROR("failed to parse test_rr_d (DP_TEST_MISC1)\n");
479*4882a593Smuzhiyun return ret;
480*4882a593Smuzhiyun }
481*4882a593Smuzhiyun
482*4882a593Smuzhiyun ret = dp_link_parse_timing_params3(link, DP_TEST_REFRESH_RATE_NUMERATOR,
483*4882a593Smuzhiyun &link->dp_link.test_video.test_rr_n);
484*4882a593Smuzhiyun if (ret) {
485*4882a593Smuzhiyun DRM_ERROR("failed to parse test_rr_n\n");
486*4882a593Smuzhiyun return ret;
487*4882a593Smuzhiyun }
488*4882a593Smuzhiyun
489*4882a593Smuzhiyun DRM_DEBUG_DP("link video pattern = 0x%x\n"
490*4882a593Smuzhiyun "link dynamic range = 0x%x\n"
491*4882a593Smuzhiyun "link bit depth = 0x%x\n"
492*4882a593Smuzhiyun "TEST_H_TOTAL = %d, TEST_V_TOTAL = %d\n"
493*4882a593Smuzhiyun "TEST_H_START = %d, TEST_V_START = %d\n"
494*4882a593Smuzhiyun "TEST_HSYNC_POL = %d\n"
495*4882a593Smuzhiyun "TEST_HSYNC_WIDTH = %d\n"
496*4882a593Smuzhiyun "TEST_VSYNC_POL = %d\n"
497*4882a593Smuzhiyun "TEST_VSYNC_WIDTH = %d\n"
498*4882a593Smuzhiyun "TEST_H_WIDTH = %d\n"
499*4882a593Smuzhiyun "TEST_V_HEIGHT = %d\n"
500*4882a593Smuzhiyun "TEST_REFRESH_DENOMINATOR = %d\n"
501*4882a593Smuzhiyun "TEST_REFRESH_NUMERATOR = %d\n",
502*4882a593Smuzhiyun link->dp_link.test_video.test_video_pattern,
503*4882a593Smuzhiyun link->dp_link.test_video.test_dyn_range,
504*4882a593Smuzhiyun link->dp_link.test_video.test_bit_depth,
505*4882a593Smuzhiyun link->dp_link.test_video.test_h_total,
506*4882a593Smuzhiyun link->dp_link.test_video.test_v_total,
507*4882a593Smuzhiyun link->dp_link.test_video.test_h_start,
508*4882a593Smuzhiyun link->dp_link.test_video.test_v_start,
509*4882a593Smuzhiyun link->dp_link.test_video.test_hsync_pol,
510*4882a593Smuzhiyun link->dp_link.test_video.test_hsync_width,
511*4882a593Smuzhiyun link->dp_link.test_video.test_vsync_pol,
512*4882a593Smuzhiyun link->dp_link.test_video.test_vsync_width,
513*4882a593Smuzhiyun link->dp_link.test_video.test_h_width,
514*4882a593Smuzhiyun link->dp_link.test_video.test_v_height,
515*4882a593Smuzhiyun link->dp_link.test_video.test_rr_d,
516*4882a593Smuzhiyun link->dp_link.test_video.test_rr_n);
517*4882a593Smuzhiyun
518*4882a593Smuzhiyun return ret;
519*4882a593Smuzhiyun }
520*4882a593Smuzhiyun
521*4882a593Smuzhiyun /**
522*4882a593Smuzhiyun * dp_link_parse_link_training_params() - parses link training parameters from
523*4882a593Smuzhiyun * DPCD
524*4882a593Smuzhiyun * @link: Display Port Driver data
525*4882a593Smuzhiyun *
526*4882a593Smuzhiyun * Returns 0 if it successfully parses the link rate (Byte 0x219) and lane
527*4882a593Smuzhiyun * count (Byte 0x220), and if these values parse are valid.
528*4882a593Smuzhiyun */
dp_link_parse_link_training_params(struct dp_link_private * link)529*4882a593Smuzhiyun static int dp_link_parse_link_training_params(struct dp_link_private *link)
530*4882a593Smuzhiyun {
531*4882a593Smuzhiyun u8 bp;
532*4882a593Smuzhiyun ssize_t rlen;
533*4882a593Smuzhiyun
534*4882a593Smuzhiyun rlen = drm_dp_dpcd_readb(link->aux, DP_TEST_LINK_RATE, &bp);
535*4882a593Smuzhiyun if (rlen < 0) {
536*4882a593Smuzhiyun DRM_ERROR("failed to read link rate. rlen=%zd\n", rlen);
537*4882a593Smuzhiyun return rlen;
538*4882a593Smuzhiyun }
539*4882a593Smuzhiyun
540*4882a593Smuzhiyun if (!is_link_rate_valid(bp)) {
541*4882a593Smuzhiyun DRM_ERROR("invalid link rate = 0x%x\n", bp);
542*4882a593Smuzhiyun return -EINVAL;
543*4882a593Smuzhiyun }
544*4882a593Smuzhiyun
545*4882a593Smuzhiyun link->request.test_link_rate = bp;
546*4882a593Smuzhiyun DRM_DEBUG_DP("link rate = 0x%x\n", link->request.test_link_rate);
547*4882a593Smuzhiyun
548*4882a593Smuzhiyun rlen = drm_dp_dpcd_readb(link->aux, DP_TEST_LANE_COUNT, &bp);
549*4882a593Smuzhiyun if (rlen < 0) {
550*4882a593Smuzhiyun DRM_ERROR("failed to read lane count. rlen=%zd\n", rlen);
551*4882a593Smuzhiyun return rlen;
552*4882a593Smuzhiyun }
553*4882a593Smuzhiyun bp &= DP_MAX_LANE_COUNT_MASK;
554*4882a593Smuzhiyun
555*4882a593Smuzhiyun if (!is_lane_count_valid(bp)) {
556*4882a593Smuzhiyun DRM_ERROR("invalid lane count = 0x%x\n", bp);
557*4882a593Smuzhiyun return -EINVAL;
558*4882a593Smuzhiyun }
559*4882a593Smuzhiyun
560*4882a593Smuzhiyun link->request.test_lane_count = bp;
561*4882a593Smuzhiyun DRM_DEBUG_DP("lane count = 0x%x\n", link->request.test_lane_count);
562*4882a593Smuzhiyun return 0;
563*4882a593Smuzhiyun }
564*4882a593Smuzhiyun
565*4882a593Smuzhiyun /**
566*4882a593Smuzhiyun * dp_parse_phy_test_params() - parses the phy link parameters
567*4882a593Smuzhiyun * @link: Display Port Driver data
568*4882a593Smuzhiyun *
569*4882a593Smuzhiyun * Parses the DPCD (Byte 0x248) for the DP PHY link pattern that is being
570*4882a593Smuzhiyun * requested.
571*4882a593Smuzhiyun */
dp_link_parse_phy_test_params(struct dp_link_private * link)572*4882a593Smuzhiyun static int dp_link_parse_phy_test_params(struct dp_link_private *link)
573*4882a593Smuzhiyun {
574*4882a593Smuzhiyun u8 data;
575*4882a593Smuzhiyun ssize_t rlen;
576*4882a593Smuzhiyun
577*4882a593Smuzhiyun rlen = drm_dp_dpcd_readb(link->aux, DP_PHY_TEST_PATTERN,
578*4882a593Smuzhiyun &data);
579*4882a593Smuzhiyun if (rlen < 0) {
580*4882a593Smuzhiyun DRM_ERROR("failed to read phy link pattern. rlen=%zd\n", rlen);
581*4882a593Smuzhiyun return rlen;
582*4882a593Smuzhiyun }
583*4882a593Smuzhiyun
584*4882a593Smuzhiyun link->dp_link.phy_params.phy_test_pattern_sel = data & 0x07;
585*4882a593Smuzhiyun
586*4882a593Smuzhiyun DRM_DEBUG_DP("phy_test_pattern_sel = 0x%x\n", data);
587*4882a593Smuzhiyun
588*4882a593Smuzhiyun switch (data) {
589*4882a593Smuzhiyun case DP_PHY_TEST_PATTERN_SEL_MASK:
590*4882a593Smuzhiyun case DP_PHY_TEST_PATTERN_NONE:
591*4882a593Smuzhiyun case DP_PHY_TEST_PATTERN_D10_2:
592*4882a593Smuzhiyun case DP_PHY_TEST_PATTERN_ERROR_COUNT:
593*4882a593Smuzhiyun case DP_PHY_TEST_PATTERN_PRBS7:
594*4882a593Smuzhiyun case DP_PHY_TEST_PATTERN_80BIT_CUSTOM:
595*4882a593Smuzhiyun case DP_PHY_TEST_PATTERN_CP2520:
596*4882a593Smuzhiyun return 0;
597*4882a593Smuzhiyun default:
598*4882a593Smuzhiyun return -EINVAL;
599*4882a593Smuzhiyun }
600*4882a593Smuzhiyun }
601*4882a593Smuzhiyun
602*4882a593Smuzhiyun /**
603*4882a593Smuzhiyun * dp_link_is_video_audio_test_requested() - checks for audio/video link request
604*4882a593Smuzhiyun * @link: link requested by the sink
605*4882a593Smuzhiyun *
606*4882a593Smuzhiyun * Returns true if the requested link is a permitted audio/video link.
607*4882a593Smuzhiyun */
dp_link_is_video_audio_test_requested(u32 link)608*4882a593Smuzhiyun static bool dp_link_is_video_audio_test_requested(u32 link)
609*4882a593Smuzhiyun {
610*4882a593Smuzhiyun u8 video_audio_test = (DP_TEST_LINK_VIDEO_PATTERN |
611*4882a593Smuzhiyun DP_TEST_LINK_AUDIO_PATTERN |
612*4882a593Smuzhiyun DP_TEST_LINK_AUDIO_DISABLED_VIDEO);
613*4882a593Smuzhiyun
614*4882a593Smuzhiyun return ((link & video_audio_test) &&
615*4882a593Smuzhiyun !(link & ~video_audio_test));
616*4882a593Smuzhiyun }
617*4882a593Smuzhiyun
618*4882a593Smuzhiyun /**
619*4882a593Smuzhiyun * dp_link_parse_request() - parses link request parameters from sink
620*4882a593Smuzhiyun * @link: Display Port Driver data
621*4882a593Smuzhiyun *
622*4882a593Smuzhiyun * Parses the DPCD to check if an automated link is requested (Byte 0x201),
623*4882a593Smuzhiyun * and what type of link automation is being requested (Byte 0x218).
624*4882a593Smuzhiyun */
dp_link_parse_request(struct dp_link_private * link)625*4882a593Smuzhiyun static int dp_link_parse_request(struct dp_link_private *link)
626*4882a593Smuzhiyun {
627*4882a593Smuzhiyun int ret = 0;
628*4882a593Smuzhiyun u8 data;
629*4882a593Smuzhiyun ssize_t rlen;
630*4882a593Smuzhiyun
631*4882a593Smuzhiyun /**
632*4882a593Smuzhiyun * Read the device service IRQ vector (Byte 0x201) to determine
633*4882a593Smuzhiyun * whether an automated link has been requested by the sink.
634*4882a593Smuzhiyun */
635*4882a593Smuzhiyun rlen = drm_dp_dpcd_readb(link->aux,
636*4882a593Smuzhiyun DP_DEVICE_SERVICE_IRQ_VECTOR, &data);
637*4882a593Smuzhiyun if (rlen < 0) {
638*4882a593Smuzhiyun DRM_ERROR("aux read failed. rlen=%zd\n", rlen);
639*4882a593Smuzhiyun return rlen;
640*4882a593Smuzhiyun }
641*4882a593Smuzhiyun
642*4882a593Smuzhiyun DRM_DEBUG_DP("device service irq vector = 0x%x\n", data);
643*4882a593Smuzhiyun
644*4882a593Smuzhiyun if (!(data & DP_AUTOMATED_TEST_REQUEST)) {
645*4882a593Smuzhiyun DRM_DEBUG_DP("no test requested\n");
646*4882a593Smuzhiyun return 0;
647*4882a593Smuzhiyun }
648*4882a593Smuzhiyun
649*4882a593Smuzhiyun /**
650*4882a593Smuzhiyun * Read the link request byte (Byte 0x218) to determine what type
651*4882a593Smuzhiyun * of automated link has been requested by the sink.
652*4882a593Smuzhiyun */
653*4882a593Smuzhiyun rlen = drm_dp_dpcd_readb(link->aux, DP_TEST_REQUEST, &data);
654*4882a593Smuzhiyun if (rlen < 0) {
655*4882a593Smuzhiyun DRM_ERROR("aux read failed. rlen=%zd\n", rlen);
656*4882a593Smuzhiyun return rlen;
657*4882a593Smuzhiyun }
658*4882a593Smuzhiyun
659*4882a593Smuzhiyun if (!data || (data == DP_TEST_LINK_FAUX_PATTERN)) {
660*4882a593Smuzhiyun DRM_DEBUG_DP("link 0x%x not supported\n", data);
661*4882a593Smuzhiyun goto end;
662*4882a593Smuzhiyun }
663*4882a593Smuzhiyun
664*4882a593Smuzhiyun DRM_DEBUG_DP("Test:(0x%x) requested\n", data);
665*4882a593Smuzhiyun link->request.test_requested = data;
666*4882a593Smuzhiyun if (link->request.test_requested == DP_TEST_LINK_PHY_TEST_PATTERN) {
667*4882a593Smuzhiyun ret = dp_link_parse_phy_test_params(link);
668*4882a593Smuzhiyun if (ret)
669*4882a593Smuzhiyun goto end;
670*4882a593Smuzhiyun ret = dp_link_parse_link_training_params(link);
671*4882a593Smuzhiyun if (ret)
672*4882a593Smuzhiyun goto end;
673*4882a593Smuzhiyun }
674*4882a593Smuzhiyun
675*4882a593Smuzhiyun if (link->request.test_requested == DP_TEST_LINK_TRAINING) {
676*4882a593Smuzhiyun ret = dp_link_parse_link_training_params(link);
677*4882a593Smuzhiyun if (ret)
678*4882a593Smuzhiyun goto end;
679*4882a593Smuzhiyun }
680*4882a593Smuzhiyun
681*4882a593Smuzhiyun if (dp_link_is_video_audio_test_requested(
682*4882a593Smuzhiyun link->request.test_requested)) {
683*4882a593Smuzhiyun ret = dp_link_parse_video_pattern_params(link);
684*4882a593Smuzhiyun if (ret)
685*4882a593Smuzhiyun goto end;
686*4882a593Smuzhiyun
687*4882a593Smuzhiyun ret = dp_link_parse_audio_pattern_params(link);
688*4882a593Smuzhiyun }
689*4882a593Smuzhiyun end:
690*4882a593Smuzhiyun /*
691*4882a593Smuzhiyun * Send a DP_TEST_ACK if all link parameters are valid, otherwise send
692*4882a593Smuzhiyun * a DP_TEST_NAK.
693*4882a593Smuzhiyun */
694*4882a593Smuzhiyun if (ret) {
695*4882a593Smuzhiyun link->dp_link.test_response = DP_TEST_NAK;
696*4882a593Smuzhiyun } else {
697*4882a593Smuzhiyun if (link->request.test_requested != DP_TEST_LINK_EDID_READ)
698*4882a593Smuzhiyun link->dp_link.test_response = DP_TEST_ACK;
699*4882a593Smuzhiyun else
700*4882a593Smuzhiyun link->dp_link.test_response =
701*4882a593Smuzhiyun DP_TEST_EDID_CHECKSUM_WRITE;
702*4882a593Smuzhiyun }
703*4882a593Smuzhiyun
704*4882a593Smuzhiyun return ret;
705*4882a593Smuzhiyun }
706*4882a593Smuzhiyun
707*4882a593Smuzhiyun /**
708*4882a593Smuzhiyun * dp_link_parse_sink_count() - parses the sink count
709*4882a593Smuzhiyun * @dp_link: pointer to link module data
710*4882a593Smuzhiyun *
711*4882a593Smuzhiyun * Parses the DPCD to check if there is an update to the sink count
712*4882a593Smuzhiyun * (Byte 0x200), and whether all the sink devices connected have Content
713*4882a593Smuzhiyun * Protection enabled.
714*4882a593Smuzhiyun */
dp_link_parse_sink_count(struct dp_link * dp_link)715*4882a593Smuzhiyun static int dp_link_parse_sink_count(struct dp_link *dp_link)
716*4882a593Smuzhiyun {
717*4882a593Smuzhiyun ssize_t rlen;
718*4882a593Smuzhiyun bool cp_ready;
719*4882a593Smuzhiyun
720*4882a593Smuzhiyun struct dp_link_private *link = container_of(dp_link,
721*4882a593Smuzhiyun struct dp_link_private, dp_link);
722*4882a593Smuzhiyun
723*4882a593Smuzhiyun rlen = drm_dp_dpcd_readb(link->aux, DP_SINK_COUNT,
724*4882a593Smuzhiyun &link->dp_link.sink_count);
725*4882a593Smuzhiyun if (rlen < 0) {
726*4882a593Smuzhiyun DRM_ERROR("sink count read failed. rlen=%zd\n", rlen);
727*4882a593Smuzhiyun return rlen;
728*4882a593Smuzhiyun }
729*4882a593Smuzhiyun
730*4882a593Smuzhiyun cp_ready = link->dp_link.sink_count & DP_SINK_CP_READY;
731*4882a593Smuzhiyun
732*4882a593Smuzhiyun link->dp_link.sink_count =
733*4882a593Smuzhiyun DP_GET_SINK_COUNT(link->dp_link.sink_count);
734*4882a593Smuzhiyun
735*4882a593Smuzhiyun DRM_DEBUG_DP("sink_count = 0x%x, cp_ready = 0x%x\n",
736*4882a593Smuzhiyun link->dp_link.sink_count, cp_ready);
737*4882a593Smuzhiyun return 0;
738*4882a593Smuzhiyun }
739*4882a593Smuzhiyun
dp_link_parse_sink_status_field(struct dp_link_private * link)740*4882a593Smuzhiyun static void dp_link_parse_sink_status_field(struct dp_link_private *link)
741*4882a593Smuzhiyun {
742*4882a593Smuzhiyun int len = 0;
743*4882a593Smuzhiyun
744*4882a593Smuzhiyun link->prev_sink_count = link->dp_link.sink_count;
745*4882a593Smuzhiyun dp_link_parse_sink_count(&link->dp_link);
746*4882a593Smuzhiyun
747*4882a593Smuzhiyun len = drm_dp_dpcd_read_link_status(link->aux,
748*4882a593Smuzhiyun link->link_status);
749*4882a593Smuzhiyun if (len < DP_LINK_STATUS_SIZE)
750*4882a593Smuzhiyun DRM_ERROR("DP link status read failed\n");
751*4882a593Smuzhiyun dp_link_parse_request(link);
752*4882a593Smuzhiyun }
753*4882a593Smuzhiyun
754*4882a593Smuzhiyun /**
755*4882a593Smuzhiyun * dp_link_process_link_training_request() - processes new training requests
756*4882a593Smuzhiyun * @link: Display Port link data
757*4882a593Smuzhiyun *
758*4882a593Smuzhiyun * This function will handle new link training requests that are initiated by
759*4882a593Smuzhiyun * the sink. In particular, it will update the requested lane count and link
760*4882a593Smuzhiyun * rate, and then trigger the link retraining procedure.
761*4882a593Smuzhiyun *
762*4882a593Smuzhiyun * The function will return 0 if a link training request has been processed,
763*4882a593Smuzhiyun * otherwise it will return -EINVAL.
764*4882a593Smuzhiyun */
dp_link_process_link_training_request(struct dp_link_private * link)765*4882a593Smuzhiyun static int dp_link_process_link_training_request(struct dp_link_private *link)
766*4882a593Smuzhiyun {
767*4882a593Smuzhiyun if (link->request.test_requested != DP_TEST_LINK_TRAINING)
768*4882a593Smuzhiyun return -EINVAL;
769*4882a593Smuzhiyun
770*4882a593Smuzhiyun DRM_DEBUG_DP("Test:0x%x link rate = 0x%x, lane count = 0x%x\n",
771*4882a593Smuzhiyun DP_TEST_LINK_TRAINING,
772*4882a593Smuzhiyun link->request.test_link_rate,
773*4882a593Smuzhiyun link->request.test_lane_count);
774*4882a593Smuzhiyun
775*4882a593Smuzhiyun link->dp_link.link_params.num_lanes = link->request.test_lane_count;
776*4882a593Smuzhiyun link->dp_link.link_params.rate =
777*4882a593Smuzhiyun drm_dp_bw_code_to_link_rate(link->request.test_link_rate);
778*4882a593Smuzhiyun
779*4882a593Smuzhiyun return 0;
780*4882a593Smuzhiyun }
781*4882a593Smuzhiyun
dp_link_send_test_response(struct dp_link * dp_link)782*4882a593Smuzhiyun bool dp_link_send_test_response(struct dp_link *dp_link)
783*4882a593Smuzhiyun {
784*4882a593Smuzhiyun struct dp_link_private *link = NULL;
785*4882a593Smuzhiyun int ret = 0;
786*4882a593Smuzhiyun
787*4882a593Smuzhiyun if (!dp_link) {
788*4882a593Smuzhiyun DRM_ERROR("invalid input\n");
789*4882a593Smuzhiyun return false;
790*4882a593Smuzhiyun }
791*4882a593Smuzhiyun
792*4882a593Smuzhiyun link = container_of(dp_link, struct dp_link_private, dp_link);
793*4882a593Smuzhiyun
794*4882a593Smuzhiyun ret = drm_dp_dpcd_writeb(link->aux, DP_TEST_RESPONSE,
795*4882a593Smuzhiyun dp_link->test_response);
796*4882a593Smuzhiyun
797*4882a593Smuzhiyun return ret == 1;
798*4882a593Smuzhiyun }
799*4882a593Smuzhiyun
dp_link_psm_config(struct dp_link * dp_link,struct dp_link_info * link_info,bool enable)800*4882a593Smuzhiyun int dp_link_psm_config(struct dp_link *dp_link,
801*4882a593Smuzhiyun struct dp_link_info *link_info, bool enable)
802*4882a593Smuzhiyun {
803*4882a593Smuzhiyun struct dp_link_private *link = NULL;
804*4882a593Smuzhiyun int ret = 0;
805*4882a593Smuzhiyun
806*4882a593Smuzhiyun if (!dp_link) {
807*4882a593Smuzhiyun DRM_ERROR("invalid params\n");
808*4882a593Smuzhiyun return -EINVAL;
809*4882a593Smuzhiyun }
810*4882a593Smuzhiyun
811*4882a593Smuzhiyun link = container_of(dp_link, struct dp_link_private, dp_link);
812*4882a593Smuzhiyun
813*4882a593Smuzhiyun mutex_lock(&link->psm_mutex);
814*4882a593Smuzhiyun if (enable)
815*4882a593Smuzhiyun ret = dp_aux_link_power_down(link->aux, link_info);
816*4882a593Smuzhiyun else
817*4882a593Smuzhiyun ret = dp_aux_link_power_up(link->aux, link_info);
818*4882a593Smuzhiyun
819*4882a593Smuzhiyun if (ret)
820*4882a593Smuzhiyun DRM_ERROR("Failed to %s low power mode\n", enable ?
821*4882a593Smuzhiyun "enter" : "exit");
822*4882a593Smuzhiyun else
823*4882a593Smuzhiyun dp_link->psm_enabled = enable;
824*4882a593Smuzhiyun
825*4882a593Smuzhiyun mutex_unlock(&link->psm_mutex);
826*4882a593Smuzhiyun return ret;
827*4882a593Smuzhiyun }
828*4882a593Smuzhiyun
dp_link_send_edid_checksum(struct dp_link * dp_link,u8 checksum)829*4882a593Smuzhiyun bool dp_link_send_edid_checksum(struct dp_link *dp_link, u8 checksum)
830*4882a593Smuzhiyun {
831*4882a593Smuzhiyun struct dp_link_private *link = NULL;
832*4882a593Smuzhiyun int ret = 0;
833*4882a593Smuzhiyun
834*4882a593Smuzhiyun if (!dp_link) {
835*4882a593Smuzhiyun DRM_ERROR("invalid input\n");
836*4882a593Smuzhiyun return false;
837*4882a593Smuzhiyun }
838*4882a593Smuzhiyun
839*4882a593Smuzhiyun link = container_of(dp_link, struct dp_link_private, dp_link);
840*4882a593Smuzhiyun
841*4882a593Smuzhiyun ret = drm_dp_dpcd_writeb(link->aux, DP_TEST_EDID_CHECKSUM,
842*4882a593Smuzhiyun checksum);
843*4882a593Smuzhiyun return ret == 1;
844*4882a593Smuzhiyun }
845*4882a593Smuzhiyun
dp_link_parse_vx_px(struct dp_link_private * link)846*4882a593Smuzhiyun static int dp_link_parse_vx_px(struct dp_link_private *link)
847*4882a593Smuzhiyun {
848*4882a593Smuzhiyun int ret = 0;
849*4882a593Smuzhiyun
850*4882a593Smuzhiyun DRM_DEBUG_DP("vx: 0=%d, 1=%d, 2=%d, 3=%d\n",
851*4882a593Smuzhiyun drm_dp_get_adjust_request_voltage(link->link_status, 0),
852*4882a593Smuzhiyun drm_dp_get_adjust_request_voltage(link->link_status, 1),
853*4882a593Smuzhiyun drm_dp_get_adjust_request_voltage(link->link_status, 2),
854*4882a593Smuzhiyun drm_dp_get_adjust_request_voltage(link->link_status, 3));
855*4882a593Smuzhiyun
856*4882a593Smuzhiyun DRM_DEBUG_DP("px: 0=%d, 1=%d, 2=%d, 3=%d\n",
857*4882a593Smuzhiyun drm_dp_get_adjust_request_pre_emphasis(link->link_status, 0),
858*4882a593Smuzhiyun drm_dp_get_adjust_request_pre_emphasis(link->link_status, 1),
859*4882a593Smuzhiyun drm_dp_get_adjust_request_pre_emphasis(link->link_status, 2),
860*4882a593Smuzhiyun drm_dp_get_adjust_request_pre_emphasis(link->link_status, 3));
861*4882a593Smuzhiyun
862*4882a593Smuzhiyun /**
863*4882a593Smuzhiyun * Update the voltage and pre-emphasis levels as per DPCD request
864*4882a593Smuzhiyun * vector.
865*4882a593Smuzhiyun */
866*4882a593Smuzhiyun DRM_DEBUG_DP("Current: v_level = 0x%x, p_level = 0x%x\n",
867*4882a593Smuzhiyun link->dp_link.phy_params.v_level,
868*4882a593Smuzhiyun link->dp_link.phy_params.p_level);
869*4882a593Smuzhiyun link->dp_link.phy_params.v_level =
870*4882a593Smuzhiyun drm_dp_get_adjust_request_voltage(link->link_status, 0);
871*4882a593Smuzhiyun link->dp_link.phy_params.p_level =
872*4882a593Smuzhiyun drm_dp_get_adjust_request_pre_emphasis(link->link_status, 0);
873*4882a593Smuzhiyun
874*4882a593Smuzhiyun link->dp_link.phy_params.p_level >>= DP_TRAIN_PRE_EMPHASIS_SHIFT;
875*4882a593Smuzhiyun
876*4882a593Smuzhiyun DRM_DEBUG_DP("Requested: v_level = 0x%x, p_level = 0x%x\n",
877*4882a593Smuzhiyun link->dp_link.phy_params.v_level,
878*4882a593Smuzhiyun link->dp_link.phy_params.p_level);
879*4882a593Smuzhiyun
880*4882a593Smuzhiyun return ret;
881*4882a593Smuzhiyun }
882*4882a593Smuzhiyun
883*4882a593Smuzhiyun /**
884*4882a593Smuzhiyun * dp_link_process_phy_test_pattern_request() - process new phy link requests
885*4882a593Smuzhiyun * @link: Display Port Driver data
886*4882a593Smuzhiyun *
887*4882a593Smuzhiyun * This function will handle new phy link pattern requests that are initiated
888*4882a593Smuzhiyun * by the sink. The function will return 0 if a phy link pattern has been
889*4882a593Smuzhiyun * processed, otherwise it will return -EINVAL.
890*4882a593Smuzhiyun */
dp_link_process_phy_test_pattern_request(struct dp_link_private * link)891*4882a593Smuzhiyun static int dp_link_process_phy_test_pattern_request(
892*4882a593Smuzhiyun struct dp_link_private *link)
893*4882a593Smuzhiyun {
894*4882a593Smuzhiyun int ret = 0;
895*4882a593Smuzhiyun
896*4882a593Smuzhiyun if (!(link->request.test_requested & DP_TEST_LINK_PHY_TEST_PATTERN)) {
897*4882a593Smuzhiyun DRM_DEBUG_DP("no phy test\n");
898*4882a593Smuzhiyun return -EINVAL;
899*4882a593Smuzhiyun }
900*4882a593Smuzhiyun
901*4882a593Smuzhiyun if (!is_link_rate_valid(link->request.test_link_rate) ||
902*4882a593Smuzhiyun !is_lane_count_valid(link->request.test_lane_count)) {
903*4882a593Smuzhiyun DRM_ERROR("Invalid: link rate = 0x%x,lane count = 0x%x\n",
904*4882a593Smuzhiyun link->request.test_link_rate,
905*4882a593Smuzhiyun link->request.test_lane_count);
906*4882a593Smuzhiyun return -EINVAL;
907*4882a593Smuzhiyun }
908*4882a593Smuzhiyun
909*4882a593Smuzhiyun DRM_DEBUG_DP("Current: rate = 0x%x, lane count = 0x%x\n",
910*4882a593Smuzhiyun link->dp_link.link_params.rate,
911*4882a593Smuzhiyun link->dp_link.link_params.num_lanes);
912*4882a593Smuzhiyun
913*4882a593Smuzhiyun DRM_DEBUG_DP("Requested: rate = 0x%x, lane count = 0x%x\n",
914*4882a593Smuzhiyun link->request.test_link_rate,
915*4882a593Smuzhiyun link->request.test_lane_count);
916*4882a593Smuzhiyun
917*4882a593Smuzhiyun link->dp_link.link_params.num_lanes = link->request.test_lane_count;
918*4882a593Smuzhiyun link->dp_link.link_params.rate =
919*4882a593Smuzhiyun drm_dp_bw_code_to_link_rate(link->request.test_link_rate);
920*4882a593Smuzhiyun
921*4882a593Smuzhiyun ret = dp_link_parse_vx_px(link);
922*4882a593Smuzhiyun
923*4882a593Smuzhiyun if (ret)
924*4882a593Smuzhiyun DRM_ERROR("parse_vx_px failed. ret=%d\n", ret);
925*4882a593Smuzhiyun
926*4882a593Smuzhiyun return ret;
927*4882a593Smuzhiyun }
928*4882a593Smuzhiyun
get_link_status(const u8 link_status[DP_LINK_STATUS_SIZE],int r)929*4882a593Smuzhiyun static u8 get_link_status(const u8 link_status[DP_LINK_STATUS_SIZE], int r)
930*4882a593Smuzhiyun {
931*4882a593Smuzhiyun return link_status[r - DP_LANE0_1_STATUS];
932*4882a593Smuzhiyun }
933*4882a593Smuzhiyun
934*4882a593Smuzhiyun /**
935*4882a593Smuzhiyun * dp_link_process_link_status_update() - processes link status updates
936*4882a593Smuzhiyun * @link: Display Port link module data
937*4882a593Smuzhiyun *
938*4882a593Smuzhiyun * This function will check for changes in the link status, e.g. clock
939*4882a593Smuzhiyun * recovery done on all lanes, and trigger link training if there is a
940*4882a593Smuzhiyun * failure/error on the link.
941*4882a593Smuzhiyun *
942*4882a593Smuzhiyun * The function will return 0 if the a link status update has been processed,
943*4882a593Smuzhiyun * otherwise it will return -EINVAL.
944*4882a593Smuzhiyun */
dp_link_process_link_status_update(struct dp_link_private * link)945*4882a593Smuzhiyun static int dp_link_process_link_status_update(struct dp_link_private *link)
946*4882a593Smuzhiyun {
947*4882a593Smuzhiyun bool channel_eq_done = drm_dp_channel_eq_ok(link->link_status,
948*4882a593Smuzhiyun link->dp_link.link_params.num_lanes);
949*4882a593Smuzhiyun
950*4882a593Smuzhiyun bool clock_recovery_done = drm_dp_clock_recovery_ok(link->link_status,
951*4882a593Smuzhiyun link->dp_link.link_params.num_lanes);
952*4882a593Smuzhiyun
953*4882a593Smuzhiyun DRM_DEBUG_DP("channel_eq_done = %d, clock_recovery_done = %d\n",
954*4882a593Smuzhiyun channel_eq_done, clock_recovery_done);
955*4882a593Smuzhiyun
956*4882a593Smuzhiyun if (channel_eq_done && clock_recovery_done)
957*4882a593Smuzhiyun return -EINVAL;
958*4882a593Smuzhiyun
959*4882a593Smuzhiyun
960*4882a593Smuzhiyun return 0;
961*4882a593Smuzhiyun }
962*4882a593Smuzhiyun
963*4882a593Smuzhiyun /**
964*4882a593Smuzhiyun * dp_link_process_downstream_port_status_change() - process port status changes
965*4882a593Smuzhiyun * @link: Display Port Driver data
966*4882a593Smuzhiyun *
967*4882a593Smuzhiyun * This function will handle downstream port updates that are initiated by
968*4882a593Smuzhiyun * the sink. If the downstream port status has changed, the EDID is read via
969*4882a593Smuzhiyun * AUX.
970*4882a593Smuzhiyun *
971*4882a593Smuzhiyun * The function will return 0 if a downstream port update has been
972*4882a593Smuzhiyun * processed, otherwise it will return -EINVAL.
973*4882a593Smuzhiyun */
dp_link_process_ds_port_status_change(struct dp_link_private * link)974*4882a593Smuzhiyun static int dp_link_process_ds_port_status_change(struct dp_link_private *link)
975*4882a593Smuzhiyun {
976*4882a593Smuzhiyun if (get_link_status(link->link_status, DP_LANE_ALIGN_STATUS_UPDATED) &
977*4882a593Smuzhiyun DP_DOWNSTREAM_PORT_STATUS_CHANGED)
978*4882a593Smuzhiyun goto reset;
979*4882a593Smuzhiyun
980*4882a593Smuzhiyun if (link->prev_sink_count == link->dp_link.sink_count)
981*4882a593Smuzhiyun return -EINVAL;
982*4882a593Smuzhiyun
983*4882a593Smuzhiyun reset:
984*4882a593Smuzhiyun /* reset prev_sink_count */
985*4882a593Smuzhiyun link->prev_sink_count = link->dp_link.sink_count;
986*4882a593Smuzhiyun
987*4882a593Smuzhiyun return 0;
988*4882a593Smuzhiyun }
989*4882a593Smuzhiyun
dp_link_is_video_pattern_requested(struct dp_link_private * link)990*4882a593Smuzhiyun static bool dp_link_is_video_pattern_requested(struct dp_link_private *link)
991*4882a593Smuzhiyun {
992*4882a593Smuzhiyun return (link->request.test_requested & DP_TEST_LINK_VIDEO_PATTERN)
993*4882a593Smuzhiyun && !(link->request.test_requested &
994*4882a593Smuzhiyun DP_TEST_LINK_AUDIO_DISABLED_VIDEO);
995*4882a593Smuzhiyun }
996*4882a593Smuzhiyun
dp_link_is_audio_pattern_requested(struct dp_link_private * link)997*4882a593Smuzhiyun static bool dp_link_is_audio_pattern_requested(struct dp_link_private *link)
998*4882a593Smuzhiyun {
999*4882a593Smuzhiyun return (link->request.test_requested & DP_TEST_LINK_AUDIO_PATTERN);
1000*4882a593Smuzhiyun }
1001*4882a593Smuzhiyun
dp_link_reset_data(struct dp_link_private * link)1002*4882a593Smuzhiyun static void dp_link_reset_data(struct dp_link_private *link)
1003*4882a593Smuzhiyun {
1004*4882a593Smuzhiyun link->request = (const struct dp_link_request){ 0 };
1005*4882a593Smuzhiyun link->dp_link.test_video = (const struct dp_link_test_video){ 0 };
1006*4882a593Smuzhiyun link->dp_link.test_video.test_bit_depth = DP_TEST_BIT_DEPTH_UNKNOWN;
1007*4882a593Smuzhiyun link->dp_link.test_audio = (const struct dp_link_test_audio){ 0 };
1008*4882a593Smuzhiyun link->dp_link.phy_params.phy_test_pattern_sel = 0;
1009*4882a593Smuzhiyun link->dp_link.sink_request = 0;
1010*4882a593Smuzhiyun link->dp_link.test_response = 0;
1011*4882a593Smuzhiyun }
1012*4882a593Smuzhiyun
1013*4882a593Smuzhiyun /**
1014*4882a593Smuzhiyun * dp_link_process_request() - handle HPD IRQ transition to HIGH
1015*4882a593Smuzhiyun * @dp_link: pointer to link module data
1016*4882a593Smuzhiyun *
1017*4882a593Smuzhiyun * This function will handle the HPD IRQ state transitions from LOW to HIGH
1018*4882a593Smuzhiyun * (including cases when there are back to back HPD IRQ HIGH) indicating
1019*4882a593Smuzhiyun * the start of a new link training request or sink status update.
1020*4882a593Smuzhiyun */
dp_link_process_request(struct dp_link * dp_link)1021*4882a593Smuzhiyun int dp_link_process_request(struct dp_link *dp_link)
1022*4882a593Smuzhiyun {
1023*4882a593Smuzhiyun int ret = 0;
1024*4882a593Smuzhiyun struct dp_link_private *link;
1025*4882a593Smuzhiyun
1026*4882a593Smuzhiyun if (!dp_link) {
1027*4882a593Smuzhiyun DRM_ERROR("invalid input\n");
1028*4882a593Smuzhiyun return -EINVAL;
1029*4882a593Smuzhiyun }
1030*4882a593Smuzhiyun
1031*4882a593Smuzhiyun link = container_of(dp_link, struct dp_link_private, dp_link);
1032*4882a593Smuzhiyun
1033*4882a593Smuzhiyun dp_link_reset_data(link);
1034*4882a593Smuzhiyun
1035*4882a593Smuzhiyun dp_link_parse_sink_status_field(link);
1036*4882a593Smuzhiyun
1037*4882a593Smuzhiyun if (link->request.test_requested == DP_TEST_LINK_EDID_READ) {
1038*4882a593Smuzhiyun dp_link->sink_request |= DP_TEST_LINK_EDID_READ;
1039*4882a593Smuzhiyun return ret;
1040*4882a593Smuzhiyun }
1041*4882a593Smuzhiyun
1042*4882a593Smuzhiyun ret = dp_link_process_ds_port_status_change(link);
1043*4882a593Smuzhiyun if (!ret) {
1044*4882a593Smuzhiyun dp_link->sink_request |= DS_PORT_STATUS_CHANGED;
1045*4882a593Smuzhiyun return ret;
1046*4882a593Smuzhiyun }
1047*4882a593Smuzhiyun
1048*4882a593Smuzhiyun ret = dp_link_process_link_training_request(link);
1049*4882a593Smuzhiyun if (!ret) {
1050*4882a593Smuzhiyun dp_link->sink_request |= DP_TEST_LINK_TRAINING;
1051*4882a593Smuzhiyun return ret;
1052*4882a593Smuzhiyun }
1053*4882a593Smuzhiyun
1054*4882a593Smuzhiyun ret = dp_link_process_phy_test_pattern_request(link);
1055*4882a593Smuzhiyun if (!ret) {
1056*4882a593Smuzhiyun dp_link->sink_request |= DP_TEST_LINK_PHY_TEST_PATTERN;
1057*4882a593Smuzhiyun return ret;
1058*4882a593Smuzhiyun }
1059*4882a593Smuzhiyun
1060*4882a593Smuzhiyun ret = dp_link_process_link_status_update(link);
1061*4882a593Smuzhiyun if (!ret) {
1062*4882a593Smuzhiyun dp_link->sink_request |= DP_LINK_STATUS_UPDATED;
1063*4882a593Smuzhiyun return ret;
1064*4882a593Smuzhiyun }
1065*4882a593Smuzhiyun
1066*4882a593Smuzhiyun if (dp_link_is_video_pattern_requested(link)) {
1067*4882a593Smuzhiyun ret = 0;
1068*4882a593Smuzhiyun dp_link->sink_request |= DP_TEST_LINK_VIDEO_PATTERN;
1069*4882a593Smuzhiyun }
1070*4882a593Smuzhiyun
1071*4882a593Smuzhiyun if (dp_link_is_audio_pattern_requested(link)) {
1072*4882a593Smuzhiyun dp_link->sink_request |= DP_TEST_LINK_AUDIO_PATTERN;
1073*4882a593Smuzhiyun return -EINVAL;
1074*4882a593Smuzhiyun }
1075*4882a593Smuzhiyun
1076*4882a593Smuzhiyun return ret;
1077*4882a593Smuzhiyun }
1078*4882a593Smuzhiyun
dp_link_get_colorimetry_config(struct dp_link * dp_link)1079*4882a593Smuzhiyun int dp_link_get_colorimetry_config(struct dp_link *dp_link)
1080*4882a593Smuzhiyun {
1081*4882a593Smuzhiyun u32 cc;
1082*4882a593Smuzhiyun struct dp_link_private *link;
1083*4882a593Smuzhiyun
1084*4882a593Smuzhiyun if (!dp_link) {
1085*4882a593Smuzhiyun DRM_ERROR("invalid input\n");
1086*4882a593Smuzhiyun return -EINVAL;
1087*4882a593Smuzhiyun }
1088*4882a593Smuzhiyun
1089*4882a593Smuzhiyun link = container_of(dp_link, struct dp_link_private, dp_link);
1090*4882a593Smuzhiyun
1091*4882a593Smuzhiyun /*
1092*4882a593Smuzhiyun * Unless a video pattern CTS test is ongoing, use RGB_VESA
1093*4882a593Smuzhiyun * Only RGB_VESA and RGB_CEA supported for now
1094*4882a593Smuzhiyun */
1095*4882a593Smuzhiyun if (dp_link_is_video_pattern_requested(link))
1096*4882a593Smuzhiyun cc = link->dp_link.test_video.test_dyn_range;
1097*4882a593Smuzhiyun else
1098*4882a593Smuzhiyun cc = DP_TEST_DYNAMIC_RANGE_VESA;
1099*4882a593Smuzhiyun
1100*4882a593Smuzhiyun return cc;
1101*4882a593Smuzhiyun }
1102*4882a593Smuzhiyun
dp_link_adjust_levels(struct dp_link * dp_link,u8 * link_status)1103*4882a593Smuzhiyun int dp_link_adjust_levels(struct dp_link *dp_link, u8 *link_status)
1104*4882a593Smuzhiyun {
1105*4882a593Smuzhiyun int i;
1106*4882a593Smuzhiyun int v_max = 0, p_max = 0;
1107*4882a593Smuzhiyun
1108*4882a593Smuzhiyun if (!dp_link) {
1109*4882a593Smuzhiyun DRM_ERROR("invalid input\n");
1110*4882a593Smuzhiyun return -EINVAL;
1111*4882a593Smuzhiyun }
1112*4882a593Smuzhiyun
1113*4882a593Smuzhiyun /* use the max level across lanes */
1114*4882a593Smuzhiyun for (i = 0; i < dp_link->link_params.num_lanes; i++) {
1115*4882a593Smuzhiyun u8 data_v = drm_dp_get_adjust_request_voltage(link_status, i);
1116*4882a593Smuzhiyun u8 data_p = drm_dp_get_adjust_request_pre_emphasis(link_status,
1117*4882a593Smuzhiyun i);
1118*4882a593Smuzhiyun DRM_DEBUG_DP("lane=%d req_vol_swing=%d req_pre_emphasis=%d\n",
1119*4882a593Smuzhiyun i, data_v, data_p);
1120*4882a593Smuzhiyun if (v_max < data_v)
1121*4882a593Smuzhiyun v_max = data_v;
1122*4882a593Smuzhiyun if (p_max < data_p)
1123*4882a593Smuzhiyun p_max = data_p;
1124*4882a593Smuzhiyun }
1125*4882a593Smuzhiyun
1126*4882a593Smuzhiyun dp_link->phy_params.v_level = v_max >> DP_TRAIN_VOLTAGE_SWING_SHIFT;
1127*4882a593Smuzhiyun dp_link->phy_params.p_level = p_max >> DP_TRAIN_PRE_EMPHASIS_SHIFT;
1128*4882a593Smuzhiyun
1129*4882a593Smuzhiyun /**
1130*4882a593Smuzhiyun * Adjust the voltage swing and pre-emphasis level combination to within
1131*4882a593Smuzhiyun * the allowable range.
1132*4882a593Smuzhiyun */
1133*4882a593Smuzhiyun if (dp_link->phy_params.v_level > DP_TRAIN_VOLTAGE_SWING_MAX) {
1134*4882a593Smuzhiyun DRM_DEBUG_DP("Requested vSwingLevel=%d, change to %d\n",
1135*4882a593Smuzhiyun dp_link->phy_params.v_level,
1136*4882a593Smuzhiyun DP_TRAIN_VOLTAGE_SWING_MAX);
1137*4882a593Smuzhiyun dp_link->phy_params.v_level = DP_TRAIN_VOLTAGE_SWING_MAX;
1138*4882a593Smuzhiyun }
1139*4882a593Smuzhiyun
1140*4882a593Smuzhiyun if (dp_link->phy_params.p_level > DP_TRAIN_PRE_EMPHASIS_MAX) {
1141*4882a593Smuzhiyun DRM_DEBUG_DP("Requested preEmphasisLevel=%d, change to %d\n",
1142*4882a593Smuzhiyun dp_link->phy_params.p_level,
1143*4882a593Smuzhiyun DP_TRAIN_PRE_EMPHASIS_MAX);
1144*4882a593Smuzhiyun dp_link->phy_params.p_level = DP_TRAIN_PRE_EMPHASIS_MAX;
1145*4882a593Smuzhiyun }
1146*4882a593Smuzhiyun
1147*4882a593Smuzhiyun if ((dp_link->phy_params.p_level > DP_TRAIN_PRE_EMPHASIS_LVL_1)
1148*4882a593Smuzhiyun && (dp_link->phy_params.v_level ==
1149*4882a593Smuzhiyun DP_TRAIN_VOLTAGE_SWING_LVL_2)) {
1150*4882a593Smuzhiyun DRM_DEBUG_DP("Requested preEmphasisLevel=%d, change to %d\n",
1151*4882a593Smuzhiyun dp_link->phy_params.p_level,
1152*4882a593Smuzhiyun DP_TRAIN_PRE_EMPHASIS_LVL_1);
1153*4882a593Smuzhiyun dp_link->phy_params.p_level = DP_TRAIN_PRE_EMPHASIS_LVL_1;
1154*4882a593Smuzhiyun }
1155*4882a593Smuzhiyun
1156*4882a593Smuzhiyun DRM_DEBUG_DP("adjusted: v_level=%d, p_level=%d\n",
1157*4882a593Smuzhiyun dp_link->phy_params.v_level, dp_link->phy_params.p_level);
1158*4882a593Smuzhiyun
1159*4882a593Smuzhiyun return 0;
1160*4882a593Smuzhiyun }
1161*4882a593Smuzhiyun
dp_link_reset_phy_params_vx_px(struct dp_link * dp_link)1162*4882a593Smuzhiyun void dp_link_reset_phy_params_vx_px(struct dp_link *dp_link)
1163*4882a593Smuzhiyun {
1164*4882a593Smuzhiyun dp_link->phy_params.v_level = 0;
1165*4882a593Smuzhiyun dp_link->phy_params.p_level = 0;
1166*4882a593Smuzhiyun }
1167*4882a593Smuzhiyun
dp_link_get_test_bits_depth(struct dp_link * dp_link,u32 bpp)1168*4882a593Smuzhiyun u32 dp_link_get_test_bits_depth(struct dp_link *dp_link, u32 bpp)
1169*4882a593Smuzhiyun {
1170*4882a593Smuzhiyun u32 tbd;
1171*4882a593Smuzhiyun
1172*4882a593Smuzhiyun /*
1173*4882a593Smuzhiyun * Few simplistic rules and assumptions made here:
1174*4882a593Smuzhiyun * 1. Test bit depth is bit depth per color component
1175*4882a593Smuzhiyun * 2. Assume 3 color components
1176*4882a593Smuzhiyun */
1177*4882a593Smuzhiyun switch (bpp) {
1178*4882a593Smuzhiyun case 18:
1179*4882a593Smuzhiyun tbd = DP_TEST_BIT_DEPTH_6;
1180*4882a593Smuzhiyun break;
1181*4882a593Smuzhiyun case 24:
1182*4882a593Smuzhiyun tbd = DP_TEST_BIT_DEPTH_8;
1183*4882a593Smuzhiyun break;
1184*4882a593Smuzhiyun case 30:
1185*4882a593Smuzhiyun tbd = DP_TEST_BIT_DEPTH_10;
1186*4882a593Smuzhiyun break;
1187*4882a593Smuzhiyun default:
1188*4882a593Smuzhiyun tbd = DP_TEST_BIT_DEPTH_UNKNOWN;
1189*4882a593Smuzhiyun break;
1190*4882a593Smuzhiyun }
1191*4882a593Smuzhiyun
1192*4882a593Smuzhiyun if (tbd != DP_TEST_BIT_DEPTH_UNKNOWN)
1193*4882a593Smuzhiyun tbd = (tbd >> DP_TEST_BIT_DEPTH_SHIFT);
1194*4882a593Smuzhiyun
1195*4882a593Smuzhiyun return tbd;
1196*4882a593Smuzhiyun }
1197*4882a593Smuzhiyun
dp_link_get(struct device * dev,struct drm_dp_aux * aux)1198*4882a593Smuzhiyun struct dp_link *dp_link_get(struct device *dev, struct drm_dp_aux *aux)
1199*4882a593Smuzhiyun {
1200*4882a593Smuzhiyun struct dp_link_private *link;
1201*4882a593Smuzhiyun struct dp_link *dp_link;
1202*4882a593Smuzhiyun
1203*4882a593Smuzhiyun if (!dev || !aux) {
1204*4882a593Smuzhiyun DRM_ERROR("invalid input\n");
1205*4882a593Smuzhiyun return ERR_PTR(-EINVAL);
1206*4882a593Smuzhiyun }
1207*4882a593Smuzhiyun
1208*4882a593Smuzhiyun link = devm_kzalloc(dev, sizeof(*link), GFP_KERNEL);
1209*4882a593Smuzhiyun if (!link)
1210*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
1211*4882a593Smuzhiyun
1212*4882a593Smuzhiyun link->dev = dev;
1213*4882a593Smuzhiyun link->aux = aux;
1214*4882a593Smuzhiyun
1215*4882a593Smuzhiyun mutex_init(&link->psm_mutex);
1216*4882a593Smuzhiyun dp_link = &link->dp_link;
1217*4882a593Smuzhiyun
1218*4882a593Smuzhiyun return dp_link;
1219*4882a593Smuzhiyun }
1220