1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
4*4882a593Smuzhiyun */
5*4882a593Smuzhiyun
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun #define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun #include <linux/of_platform.h>
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun #include <drm/drm_dp_helper.h>
12*4882a593Smuzhiyun #include <drm/drm_edid.h>
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun #include "dp_catalog.h"
15*4882a593Smuzhiyun #include "dp_audio.h"
16*4882a593Smuzhiyun #include "dp_panel.h"
17*4882a593Smuzhiyun #include "dp_display.h"
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun #define HEADER_BYTE_2_BIT 0
20*4882a593Smuzhiyun #define PARITY_BYTE_2_BIT 8
21*4882a593Smuzhiyun #define HEADER_BYTE_1_BIT 16
22*4882a593Smuzhiyun #define PARITY_BYTE_1_BIT 24
23*4882a593Smuzhiyun #define HEADER_BYTE_3_BIT 16
24*4882a593Smuzhiyun #define PARITY_BYTE_3_BIT 24
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun struct dp_audio_private {
27*4882a593Smuzhiyun struct platform_device *audio_pdev;
28*4882a593Smuzhiyun struct platform_device *pdev;
29*4882a593Smuzhiyun struct dp_catalog *catalog;
30*4882a593Smuzhiyun struct dp_panel *panel;
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun bool engine_on;
33*4882a593Smuzhiyun u32 channels;
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun struct dp_audio dp_audio;
36*4882a593Smuzhiyun };
37*4882a593Smuzhiyun
dp_audio_get_g0_value(u8 data)38*4882a593Smuzhiyun static u8 dp_audio_get_g0_value(u8 data)
39*4882a593Smuzhiyun {
40*4882a593Smuzhiyun u8 c[4];
41*4882a593Smuzhiyun u8 g[4];
42*4882a593Smuzhiyun u8 ret_data = 0;
43*4882a593Smuzhiyun u8 i;
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun for (i = 0; i < 4; i++)
46*4882a593Smuzhiyun c[i] = (data >> i) & 0x01;
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun g[0] = c[3];
49*4882a593Smuzhiyun g[1] = c[0] ^ c[3];
50*4882a593Smuzhiyun g[2] = c[1];
51*4882a593Smuzhiyun g[3] = c[2];
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun for (i = 0; i < 4; i++)
54*4882a593Smuzhiyun ret_data = ((g[i] & 0x01) << i) | ret_data;
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun return ret_data;
57*4882a593Smuzhiyun }
58*4882a593Smuzhiyun
dp_audio_get_g1_value(u8 data)59*4882a593Smuzhiyun static u8 dp_audio_get_g1_value(u8 data)
60*4882a593Smuzhiyun {
61*4882a593Smuzhiyun u8 c[4];
62*4882a593Smuzhiyun u8 g[4];
63*4882a593Smuzhiyun u8 ret_data = 0;
64*4882a593Smuzhiyun u8 i;
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun for (i = 0; i < 4; i++)
67*4882a593Smuzhiyun c[i] = (data >> i) & 0x01;
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun g[0] = c[0] ^ c[3];
70*4882a593Smuzhiyun g[1] = c[0] ^ c[1] ^ c[3];
71*4882a593Smuzhiyun g[2] = c[1] ^ c[2];
72*4882a593Smuzhiyun g[3] = c[2] ^ c[3];
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun for (i = 0; i < 4; i++)
75*4882a593Smuzhiyun ret_data = ((g[i] & 0x01) << i) | ret_data;
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun return ret_data;
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun
dp_audio_calculate_parity(u32 data)80*4882a593Smuzhiyun static u8 dp_audio_calculate_parity(u32 data)
81*4882a593Smuzhiyun {
82*4882a593Smuzhiyun u8 x0 = 0;
83*4882a593Smuzhiyun u8 x1 = 0;
84*4882a593Smuzhiyun u8 ci = 0;
85*4882a593Smuzhiyun u8 iData = 0;
86*4882a593Smuzhiyun u8 i = 0;
87*4882a593Smuzhiyun u8 parity_byte;
88*4882a593Smuzhiyun u8 num_byte = (data & 0xFF00) > 0 ? 8 : 2;
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun for (i = 0; i < num_byte; i++) {
91*4882a593Smuzhiyun iData = (data >> i*4) & 0xF;
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun ci = iData ^ x1;
94*4882a593Smuzhiyun x1 = x0 ^ dp_audio_get_g1_value(ci);
95*4882a593Smuzhiyun x0 = dp_audio_get_g0_value(ci);
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun parity_byte = x1 | (x0 << 4);
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun return parity_byte;
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun
dp_audio_get_header(struct dp_catalog * catalog,enum dp_catalog_audio_sdp_type sdp,enum dp_catalog_audio_header_type header)103*4882a593Smuzhiyun static u32 dp_audio_get_header(struct dp_catalog *catalog,
104*4882a593Smuzhiyun enum dp_catalog_audio_sdp_type sdp,
105*4882a593Smuzhiyun enum dp_catalog_audio_header_type header)
106*4882a593Smuzhiyun {
107*4882a593Smuzhiyun catalog->sdp_type = sdp;
108*4882a593Smuzhiyun catalog->sdp_header = header;
109*4882a593Smuzhiyun dp_catalog_audio_get_header(catalog);
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun return catalog->audio_data;
112*4882a593Smuzhiyun }
113*4882a593Smuzhiyun
dp_audio_set_header(struct dp_catalog * catalog,u32 data,enum dp_catalog_audio_sdp_type sdp,enum dp_catalog_audio_header_type header)114*4882a593Smuzhiyun static void dp_audio_set_header(struct dp_catalog *catalog,
115*4882a593Smuzhiyun u32 data,
116*4882a593Smuzhiyun enum dp_catalog_audio_sdp_type sdp,
117*4882a593Smuzhiyun enum dp_catalog_audio_header_type header)
118*4882a593Smuzhiyun {
119*4882a593Smuzhiyun catalog->sdp_type = sdp;
120*4882a593Smuzhiyun catalog->sdp_header = header;
121*4882a593Smuzhiyun catalog->audio_data = data;
122*4882a593Smuzhiyun dp_catalog_audio_set_header(catalog);
123*4882a593Smuzhiyun }
124*4882a593Smuzhiyun
dp_audio_stream_sdp(struct dp_audio_private * audio)125*4882a593Smuzhiyun static void dp_audio_stream_sdp(struct dp_audio_private *audio)
126*4882a593Smuzhiyun {
127*4882a593Smuzhiyun struct dp_catalog *catalog = audio->catalog;
128*4882a593Smuzhiyun u32 value, new_value;
129*4882a593Smuzhiyun u8 parity_byte;
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun /* Config header and parity byte 1 */
132*4882a593Smuzhiyun value = dp_audio_get_header(catalog,
133*4882a593Smuzhiyun DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_1);
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun new_value = 0x02;
136*4882a593Smuzhiyun parity_byte = dp_audio_calculate_parity(new_value);
137*4882a593Smuzhiyun value |= ((new_value << HEADER_BYTE_1_BIT)
138*4882a593Smuzhiyun | (parity_byte << PARITY_BYTE_1_BIT));
139*4882a593Smuzhiyun DRM_DEBUG_DP("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",
140*4882a593Smuzhiyun value, parity_byte);
141*4882a593Smuzhiyun dp_audio_set_header(catalog, value,
142*4882a593Smuzhiyun DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_1);
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun /* Config header and parity byte 2 */
145*4882a593Smuzhiyun value = dp_audio_get_header(catalog,
146*4882a593Smuzhiyun DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_2);
147*4882a593Smuzhiyun new_value = value;
148*4882a593Smuzhiyun parity_byte = dp_audio_calculate_parity(new_value);
149*4882a593Smuzhiyun value |= ((new_value << HEADER_BYTE_2_BIT)
150*4882a593Smuzhiyun | (parity_byte << PARITY_BYTE_2_BIT));
151*4882a593Smuzhiyun DRM_DEBUG_DP("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",
152*4882a593Smuzhiyun value, parity_byte);
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun dp_audio_set_header(catalog, value,
155*4882a593Smuzhiyun DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_2);
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun /* Config header and parity byte 3 */
158*4882a593Smuzhiyun value = dp_audio_get_header(catalog,
159*4882a593Smuzhiyun DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_3);
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun new_value = audio->channels - 1;
162*4882a593Smuzhiyun parity_byte = dp_audio_calculate_parity(new_value);
163*4882a593Smuzhiyun value |= ((new_value << HEADER_BYTE_3_BIT)
164*4882a593Smuzhiyun | (parity_byte << PARITY_BYTE_3_BIT));
165*4882a593Smuzhiyun DRM_DEBUG_DP("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n",
166*4882a593Smuzhiyun value, parity_byte);
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun dp_audio_set_header(catalog, value,
169*4882a593Smuzhiyun DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_3);
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun
dp_audio_timestamp_sdp(struct dp_audio_private * audio)172*4882a593Smuzhiyun static void dp_audio_timestamp_sdp(struct dp_audio_private *audio)
173*4882a593Smuzhiyun {
174*4882a593Smuzhiyun struct dp_catalog *catalog = audio->catalog;
175*4882a593Smuzhiyun u32 value, new_value;
176*4882a593Smuzhiyun u8 parity_byte;
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun /* Config header and parity byte 1 */
179*4882a593Smuzhiyun value = dp_audio_get_header(catalog,
180*4882a593Smuzhiyun DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_1);
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun new_value = 0x1;
183*4882a593Smuzhiyun parity_byte = dp_audio_calculate_parity(new_value);
184*4882a593Smuzhiyun value |= ((new_value << HEADER_BYTE_1_BIT)
185*4882a593Smuzhiyun | (parity_byte << PARITY_BYTE_1_BIT));
186*4882a593Smuzhiyun DRM_DEBUG_DP("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",
187*4882a593Smuzhiyun value, parity_byte);
188*4882a593Smuzhiyun dp_audio_set_header(catalog, value,
189*4882a593Smuzhiyun DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_1);
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun /* Config header and parity byte 2 */
192*4882a593Smuzhiyun value = dp_audio_get_header(catalog,
193*4882a593Smuzhiyun DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_2);
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun new_value = 0x17;
196*4882a593Smuzhiyun parity_byte = dp_audio_calculate_parity(new_value);
197*4882a593Smuzhiyun value |= ((new_value << HEADER_BYTE_2_BIT)
198*4882a593Smuzhiyun | (parity_byte << PARITY_BYTE_2_BIT));
199*4882a593Smuzhiyun DRM_DEBUG_DP("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",
200*4882a593Smuzhiyun value, parity_byte);
201*4882a593Smuzhiyun dp_audio_set_header(catalog, value,
202*4882a593Smuzhiyun DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_2);
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun /* Config header and parity byte 3 */
205*4882a593Smuzhiyun value = dp_audio_get_header(catalog,
206*4882a593Smuzhiyun DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_3);
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun new_value = (0x0 | (0x11 << 2));
209*4882a593Smuzhiyun parity_byte = dp_audio_calculate_parity(new_value);
210*4882a593Smuzhiyun value |= ((new_value << HEADER_BYTE_3_BIT)
211*4882a593Smuzhiyun | (parity_byte << PARITY_BYTE_3_BIT));
212*4882a593Smuzhiyun DRM_DEBUG_DP("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n",
213*4882a593Smuzhiyun value, parity_byte);
214*4882a593Smuzhiyun dp_audio_set_header(catalog, value,
215*4882a593Smuzhiyun DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_3);
216*4882a593Smuzhiyun }
217*4882a593Smuzhiyun
dp_audio_infoframe_sdp(struct dp_audio_private * audio)218*4882a593Smuzhiyun static void dp_audio_infoframe_sdp(struct dp_audio_private *audio)
219*4882a593Smuzhiyun {
220*4882a593Smuzhiyun struct dp_catalog *catalog = audio->catalog;
221*4882a593Smuzhiyun u32 value, new_value;
222*4882a593Smuzhiyun u8 parity_byte;
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun /* Config header and parity byte 1 */
225*4882a593Smuzhiyun value = dp_audio_get_header(catalog,
226*4882a593Smuzhiyun DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_1);
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun new_value = 0x84;
229*4882a593Smuzhiyun parity_byte = dp_audio_calculate_parity(new_value);
230*4882a593Smuzhiyun value |= ((new_value << HEADER_BYTE_1_BIT)
231*4882a593Smuzhiyun | (parity_byte << PARITY_BYTE_1_BIT));
232*4882a593Smuzhiyun DRM_DEBUG_DP("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",
233*4882a593Smuzhiyun value, parity_byte);
234*4882a593Smuzhiyun dp_audio_set_header(catalog, value,
235*4882a593Smuzhiyun DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_1);
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun /* Config header and parity byte 2 */
238*4882a593Smuzhiyun value = dp_audio_get_header(catalog,
239*4882a593Smuzhiyun DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_2);
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun new_value = 0x1b;
242*4882a593Smuzhiyun parity_byte = dp_audio_calculate_parity(new_value);
243*4882a593Smuzhiyun value |= ((new_value << HEADER_BYTE_2_BIT)
244*4882a593Smuzhiyun | (parity_byte << PARITY_BYTE_2_BIT));
245*4882a593Smuzhiyun DRM_DEBUG_DP("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",
246*4882a593Smuzhiyun value, parity_byte);
247*4882a593Smuzhiyun dp_audio_set_header(catalog, value,
248*4882a593Smuzhiyun DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_2);
249*4882a593Smuzhiyun
250*4882a593Smuzhiyun /* Config header and parity byte 3 */
251*4882a593Smuzhiyun value = dp_audio_get_header(catalog,
252*4882a593Smuzhiyun DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_3);
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun new_value = (0x0 | (0x11 << 2));
255*4882a593Smuzhiyun parity_byte = dp_audio_calculate_parity(new_value);
256*4882a593Smuzhiyun value |= ((new_value << HEADER_BYTE_3_BIT)
257*4882a593Smuzhiyun | (parity_byte << PARITY_BYTE_3_BIT));
258*4882a593Smuzhiyun DRM_DEBUG_DP("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n",
259*4882a593Smuzhiyun new_value, parity_byte);
260*4882a593Smuzhiyun dp_audio_set_header(catalog, value,
261*4882a593Smuzhiyun DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_3);
262*4882a593Smuzhiyun }
263*4882a593Smuzhiyun
dp_audio_copy_management_sdp(struct dp_audio_private * audio)264*4882a593Smuzhiyun static void dp_audio_copy_management_sdp(struct dp_audio_private *audio)
265*4882a593Smuzhiyun {
266*4882a593Smuzhiyun struct dp_catalog *catalog = audio->catalog;
267*4882a593Smuzhiyun u32 value, new_value;
268*4882a593Smuzhiyun u8 parity_byte;
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun /* Config header and parity byte 1 */
271*4882a593Smuzhiyun value = dp_audio_get_header(catalog,
272*4882a593Smuzhiyun DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_1);
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun new_value = 0x05;
275*4882a593Smuzhiyun parity_byte = dp_audio_calculate_parity(new_value);
276*4882a593Smuzhiyun value |= ((new_value << HEADER_BYTE_1_BIT)
277*4882a593Smuzhiyun | (parity_byte << PARITY_BYTE_1_BIT));
278*4882a593Smuzhiyun DRM_DEBUG_DP("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",
279*4882a593Smuzhiyun value, parity_byte);
280*4882a593Smuzhiyun dp_audio_set_header(catalog, value,
281*4882a593Smuzhiyun DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_1);
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun /* Config header and parity byte 2 */
284*4882a593Smuzhiyun value = dp_audio_get_header(catalog,
285*4882a593Smuzhiyun DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_2);
286*4882a593Smuzhiyun
287*4882a593Smuzhiyun new_value = 0x0F;
288*4882a593Smuzhiyun parity_byte = dp_audio_calculate_parity(new_value);
289*4882a593Smuzhiyun value |= ((new_value << HEADER_BYTE_2_BIT)
290*4882a593Smuzhiyun | (parity_byte << PARITY_BYTE_2_BIT));
291*4882a593Smuzhiyun DRM_DEBUG_DP("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",
292*4882a593Smuzhiyun value, parity_byte);
293*4882a593Smuzhiyun dp_audio_set_header(catalog, value,
294*4882a593Smuzhiyun DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_2);
295*4882a593Smuzhiyun
296*4882a593Smuzhiyun /* Config header and parity byte 3 */
297*4882a593Smuzhiyun value = dp_audio_get_header(catalog,
298*4882a593Smuzhiyun DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_3);
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun new_value = 0x0;
301*4882a593Smuzhiyun parity_byte = dp_audio_calculate_parity(new_value);
302*4882a593Smuzhiyun value |= ((new_value << HEADER_BYTE_3_BIT)
303*4882a593Smuzhiyun | (parity_byte << PARITY_BYTE_3_BIT));
304*4882a593Smuzhiyun DRM_DEBUG_DP("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n",
305*4882a593Smuzhiyun value, parity_byte);
306*4882a593Smuzhiyun dp_audio_set_header(catalog, value,
307*4882a593Smuzhiyun DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_3);
308*4882a593Smuzhiyun }
309*4882a593Smuzhiyun
dp_audio_isrc_sdp(struct dp_audio_private * audio)310*4882a593Smuzhiyun static void dp_audio_isrc_sdp(struct dp_audio_private *audio)
311*4882a593Smuzhiyun {
312*4882a593Smuzhiyun struct dp_catalog *catalog = audio->catalog;
313*4882a593Smuzhiyun u32 value, new_value;
314*4882a593Smuzhiyun u8 parity_byte;
315*4882a593Smuzhiyun
316*4882a593Smuzhiyun /* Config header and parity byte 1 */
317*4882a593Smuzhiyun value = dp_audio_get_header(catalog,
318*4882a593Smuzhiyun DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_1);
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun new_value = 0x06;
321*4882a593Smuzhiyun parity_byte = dp_audio_calculate_parity(new_value);
322*4882a593Smuzhiyun value |= ((new_value << HEADER_BYTE_1_BIT)
323*4882a593Smuzhiyun | (parity_byte << PARITY_BYTE_1_BIT));
324*4882a593Smuzhiyun DRM_DEBUG_DP("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",
325*4882a593Smuzhiyun value, parity_byte);
326*4882a593Smuzhiyun dp_audio_set_header(catalog, value,
327*4882a593Smuzhiyun DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_1);
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun /* Config header and parity byte 2 */
330*4882a593Smuzhiyun value = dp_audio_get_header(catalog,
331*4882a593Smuzhiyun DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_2);
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun new_value = 0x0F;
334*4882a593Smuzhiyun parity_byte = dp_audio_calculate_parity(new_value);
335*4882a593Smuzhiyun value |= ((new_value << HEADER_BYTE_2_BIT)
336*4882a593Smuzhiyun | (parity_byte << PARITY_BYTE_2_BIT));
337*4882a593Smuzhiyun DRM_DEBUG_DP("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",
338*4882a593Smuzhiyun value, parity_byte);
339*4882a593Smuzhiyun dp_audio_set_header(catalog, value,
340*4882a593Smuzhiyun DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_2);
341*4882a593Smuzhiyun }
342*4882a593Smuzhiyun
dp_audio_setup_sdp(struct dp_audio_private * audio)343*4882a593Smuzhiyun static void dp_audio_setup_sdp(struct dp_audio_private *audio)
344*4882a593Smuzhiyun {
345*4882a593Smuzhiyun dp_catalog_audio_config_sdp(audio->catalog);
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun dp_audio_stream_sdp(audio);
348*4882a593Smuzhiyun dp_audio_timestamp_sdp(audio);
349*4882a593Smuzhiyun dp_audio_infoframe_sdp(audio);
350*4882a593Smuzhiyun dp_audio_copy_management_sdp(audio);
351*4882a593Smuzhiyun dp_audio_isrc_sdp(audio);
352*4882a593Smuzhiyun }
353*4882a593Smuzhiyun
dp_audio_setup_acr(struct dp_audio_private * audio)354*4882a593Smuzhiyun static void dp_audio_setup_acr(struct dp_audio_private *audio)
355*4882a593Smuzhiyun {
356*4882a593Smuzhiyun u32 select = 0;
357*4882a593Smuzhiyun struct dp_catalog *catalog = audio->catalog;
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun switch (audio->dp_audio.bw_code) {
360*4882a593Smuzhiyun case DP_LINK_BW_1_62:
361*4882a593Smuzhiyun select = 0;
362*4882a593Smuzhiyun break;
363*4882a593Smuzhiyun case DP_LINK_BW_2_7:
364*4882a593Smuzhiyun select = 1;
365*4882a593Smuzhiyun break;
366*4882a593Smuzhiyun case DP_LINK_BW_5_4:
367*4882a593Smuzhiyun select = 2;
368*4882a593Smuzhiyun break;
369*4882a593Smuzhiyun case DP_LINK_BW_8_1:
370*4882a593Smuzhiyun select = 3;
371*4882a593Smuzhiyun break;
372*4882a593Smuzhiyun default:
373*4882a593Smuzhiyun DRM_DEBUG_DP("Unknown link rate\n");
374*4882a593Smuzhiyun select = 0;
375*4882a593Smuzhiyun break;
376*4882a593Smuzhiyun }
377*4882a593Smuzhiyun
378*4882a593Smuzhiyun catalog->audio_data = select;
379*4882a593Smuzhiyun dp_catalog_audio_config_acr(catalog);
380*4882a593Smuzhiyun }
381*4882a593Smuzhiyun
dp_audio_safe_to_exit_level(struct dp_audio_private * audio)382*4882a593Smuzhiyun static void dp_audio_safe_to_exit_level(struct dp_audio_private *audio)
383*4882a593Smuzhiyun {
384*4882a593Smuzhiyun struct dp_catalog *catalog = audio->catalog;
385*4882a593Smuzhiyun u32 safe_to_exit_level = 0;
386*4882a593Smuzhiyun
387*4882a593Smuzhiyun switch (audio->dp_audio.lane_count) {
388*4882a593Smuzhiyun case 1:
389*4882a593Smuzhiyun safe_to_exit_level = 14;
390*4882a593Smuzhiyun break;
391*4882a593Smuzhiyun case 2:
392*4882a593Smuzhiyun safe_to_exit_level = 8;
393*4882a593Smuzhiyun break;
394*4882a593Smuzhiyun case 4:
395*4882a593Smuzhiyun safe_to_exit_level = 5;
396*4882a593Smuzhiyun break;
397*4882a593Smuzhiyun default:
398*4882a593Smuzhiyun DRM_DEBUG_DP("setting the default safe_to_exit_level = %u\n",
399*4882a593Smuzhiyun safe_to_exit_level);
400*4882a593Smuzhiyun safe_to_exit_level = 14;
401*4882a593Smuzhiyun break;
402*4882a593Smuzhiyun }
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun catalog->audio_data = safe_to_exit_level;
405*4882a593Smuzhiyun dp_catalog_audio_sfe_level(catalog);
406*4882a593Smuzhiyun }
407*4882a593Smuzhiyun
dp_audio_enable(struct dp_audio_private * audio,bool enable)408*4882a593Smuzhiyun static void dp_audio_enable(struct dp_audio_private *audio, bool enable)
409*4882a593Smuzhiyun {
410*4882a593Smuzhiyun struct dp_catalog *catalog = audio->catalog;
411*4882a593Smuzhiyun
412*4882a593Smuzhiyun catalog->audio_data = enable;
413*4882a593Smuzhiyun dp_catalog_audio_enable(catalog);
414*4882a593Smuzhiyun
415*4882a593Smuzhiyun audio->engine_on = enable;
416*4882a593Smuzhiyun }
417*4882a593Smuzhiyun
dp_audio_get_data(struct platform_device * pdev)418*4882a593Smuzhiyun static struct dp_audio_private *dp_audio_get_data(struct platform_device *pdev)
419*4882a593Smuzhiyun {
420*4882a593Smuzhiyun struct dp_audio *dp_audio;
421*4882a593Smuzhiyun struct msm_dp *dp_display;
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun if (!pdev) {
424*4882a593Smuzhiyun DRM_ERROR("invalid input\n");
425*4882a593Smuzhiyun return ERR_PTR(-ENODEV);
426*4882a593Smuzhiyun }
427*4882a593Smuzhiyun
428*4882a593Smuzhiyun dp_display = platform_get_drvdata(pdev);
429*4882a593Smuzhiyun if (!dp_display) {
430*4882a593Smuzhiyun DRM_ERROR("invalid input\n");
431*4882a593Smuzhiyun return ERR_PTR(-ENODEV);
432*4882a593Smuzhiyun }
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun dp_audio = dp_display->dp_audio;
435*4882a593Smuzhiyun
436*4882a593Smuzhiyun if (!dp_audio) {
437*4882a593Smuzhiyun DRM_ERROR("invalid dp_audio data\n");
438*4882a593Smuzhiyun return ERR_PTR(-EINVAL);
439*4882a593Smuzhiyun }
440*4882a593Smuzhiyun
441*4882a593Smuzhiyun return container_of(dp_audio, struct dp_audio_private, dp_audio);
442*4882a593Smuzhiyun }
443*4882a593Smuzhiyun
dp_audio_hook_plugged_cb(struct device * dev,void * data,hdmi_codec_plugged_cb fn,struct device * codec_dev)444*4882a593Smuzhiyun static int dp_audio_hook_plugged_cb(struct device *dev, void *data,
445*4882a593Smuzhiyun hdmi_codec_plugged_cb fn,
446*4882a593Smuzhiyun struct device *codec_dev)
447*4882a593Smuzhiyun {
448*4882a593Smuzhiyun
449*4882a593Smuzhiyun struct platform_device *pdev;
450*4882a593Smuzhiyun struct msm_dp *dp_display;
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun pdev = to_platform_device(dev);
453*4882a593Smuzhiyun if (!pdev) {
454*4882a593Smuzhiyun pr_err("invalid input\n");
455*4882a593Smuzhiyun return -ENODEV;
456*4882a593Smuzhiyun }
457*4882a593Smuzhiyun
458*4882a593Smuzhiyun dp_display = platform_get_drvdata(pdev);
459*4882a593Smuzhiyun if (!dp_display) {
460*4882a593Smuzhiyun pr_err("invalid input\n");
461*4882a593Smuzhiyun return -ENODEV;
462*4882a593Smuzhiyun }
463*4882a593Smuzhiyun
464*4882a593Smuzhiyun return dp_display_set_plugged_cb(dp_display, fn, codec_dev);
465*4882a593Smuzhiyun }
466*4882a593Smuzhiyun
dp_audio_get_eld(struct device * dev,void * data,uint8_t * buf,size_t len)467*4882a593Smuzhiyun static int dp_audio_get_eld(struct device *dev,
468*4882a593Smuzhiyun void *data, uint8_t *buf, size_t len)
469*4882a593Smuzhiyun {
470*4882a593Smuzhiyun struct platform_device *pdev;
471*4882a593Smuzhiyun struct msm_dp *dp_display;
472*4882a593Smuzhiyun
473*4882a593Smuzhiyun pdev = to_platform_device(dev);
474*4882a593Smuzhiyun
475*4882a593Smuzhiyun if (!pdev) {
476*4882a593Smuzhiyun DRM_ERROR("invalid input\n");
477*4882a593Smuzhiyun return -ENODEV;
478*4882a593Smuzhiyun }
479*4882a593Smuzhiyun
480*4882a593Smuzhiyun dp_display = platform_get_drvdata(pdev);
481*4882a593Smuzhiyun if (!dp_display) {
482*4882a593Smuzhiyun DRM_ERROR("invalid input\n");
483*4882a593Smuzhiyun return -ENODEV;
484*4882a593Smuzhiyun }
485*4882a593Smuzhiyun
486*4882a593Smuzhiyun memcpy(buf, dp_display->connector->eld,
487*4882a593Smuzhiyun min(sizeof(dp_display->connector->eld), len));
488*4882a593Smuzhiyun
489*4882a593Smuzhiyun return 0;
490*4882a593Smuzhiyun }
491*4882a593Smuzhiyun
dp_audio_hw_params(struct device * dev,void * data,struct hdmi_codec_daifmt * daifmt,struct hdmi_codec_params * params)492*4882a593Smuzhiyun int dp_audio_hw_params(struct device *dev,
493*4882a593Smuzhiyun void *data,
494*4882a593Smuzhiyun struct hdmi_codec_daifmt *daifmt,
495*4882a593Smuzhiyun struct hdmi_codec_params *params)
496*4882a593Smuzhiyun {
497*4882a593Smuzhiyun int rc = 0;
498*4882a593Smuzhiyun struct dp_audio_private *audio;
499*4882a593Smuzhiyun struct platform_device *pdev;
500*4882a593Smuzhiyun struct msm_dp *dp_display;
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun pdev = to_platform_device(dev);
503*4882a593Smuzhiyun dp_display = platform_get_drvdata(pdev);
504*4882a593Smuzhiyun
505*4882a593Smuzhiyun /*
506*4882a593Smuzhiyun * there could be cases where sound card can be opened even
507*4882a593Smuzhiyun * before OR even when DP is not connected . This can cause
508*4882a593Smuzhiyun * unclocked access as the audio subsystem relies on the DP
509*4882a593Smuzhiyun * driver to maintain the correct state of clocks. To protect
510*4882a593Smuzhiyun * such cases check for connection status and bail out if not
511*4882a593Smuzhiyun * connected.
512*4882a593Smuzhiyun */
513*4882a593Smuzhiyun if (!dp_display->power_on) {
514*4882a593Smuzhiyun rc = -EINVAL;
515*4882a593Smuzhiyun goto end;
516*4882a593Smuzhiyun }
517*4882a593Smuzhiyun
518*4882a593Smuzhiyun audio = dp_audio_get_data(pdev);
519*4882a593Smuzhiyun if (IS_ERR(audio)) {
520*4882a593Smuzhiyun rc = PTR_ERR(audio);
521*4882a593Smuzhiyun goto end;
522*4882a593Smuzhiyun }
523*4882a593Smuzhiyun
524*4882a593Smuzhiyun audio->channels = params->channels;
525*4882a593Smuzhiyun
526*4882a593Smuzhiyun dp_audio_setup_sdp(audio);
527*4882a593Smuzhiyun dp_audio_setup_acr(audio);
528*4882a593Smuzhiyun dp_audio_safe_to_exit_level(audio);
529*4882a593Smuzhiyun dp_audio_enable(audio, true);
530*4882a593Smuzhiyun dp_display_signal_audio_start(dp_display);
531*4882a593Smuzhiyun dp_display->audio_enabled = true;
532*4882a593Smuzhiyun
533*4882a593Smuzhiyun end:
534*4882a593Smuzhiyun return rc;
535*4882a593Smuzhiyun }
536*4882a593Smuzhiyun
dp_audio_shutdown(struct device * dev,void * data)537*4882a593Smuzhiyun static void dp_audio_shutdown(struct device *dev, void *data)
538*4882a593Smuzhiyun {
539*4882a593Smuzhiyun struct dp_audio_private *audio;
540*4882a593Smuzhiyun struct platform_device *pdev;
541*4882a593Smuzhiyun struct msm_dp *dp_display;
542*4882a593Smuzhiyun
543*4882a593Smuzhiyun pdev = to_platform_device(dev);
544*4882a593Smuzhiyun dp_display = platform_get_drvdata(pdev);
545*4882a593Smuzhiyun audio = dp_audio_get_data(pdev);
546*4882a593Smuzhiyun if (IS_ERR(audio)) {
547*4882a593Smuzhiyun DRM_ERROR("failed to get audio data\n");
548*4882a593Smuzhiyun return;
549*4882a593Smuzhiyun }
550*4882a593Smuzhiyun
551*4882a593Smuzhiyun /*
552*4882a593Smuzhiyun * if audio was not enabled there is no need
553*4882a593Smuzhiyun * to execute the shutdown and we can bail out early.
554*4882a593Smuzhiyun * This also makes sure that we dont cause an unclocked
555*4882a593Smuzhiyun * access when audio subsystem calls this without DP being
556*4882a593Smuzhiyun * connected. is_connected cannot be used here as its set
557*4882a593Smuzhiyun * to false earlier than this call
558*4882a593Smuzhiyun */
559*4882a593Smuzhiyun if (!dp_display->audio_enabled)
560*4882a593Smuzhiyun return;
561*4882a593Smuzhiyun
562*4882a593Smuzhiyun dp_audio_enable(audio, false);
563*4882a593Smuzhiyun /* signal the dp display to safely shutdown clocks */
564*4882a593Smuzhiyun dp_display_signal_audio_complete(dp_display);
565*4882a593Smuzhiyun }
566*4882a593Smuzhiyun
567*4882a593Smuzhiyun static const struct hdmi_codec_ops dp_audio_codec_ops = {
568*4882a593Smuzhiyun .hw_params = dp_audio_hw_params,
569*4882a593Smuzhiyun .audio_shutdown = dp_audio_shutdown,
570*4882a593Smuzhiyun .get_eld = dp_audio_get_eld,
571*4882a593Smuzhiyun .hook_plugged_cb = dp_audio_hook_plugged_cb,
572*4882a593Smuzhiyun };
573*4882a593Smuzhiyun
574*4882a593Smuzhiyun static struct hdmi_codec_pdata codec_data = {
575*4882a593Smuzhiyun .ops = &dp_audio_codec_ops,
576*4882a593Smuzhiyun .max_i2s_channels = 8,
577*4882a593Smuzhiyun .i2s = 1,
578*4882a593Smuzhiyun };
579*4882a593Smuzhiyun
dp_register_audio_driver(struct device * dev,struct dp_audio * dp_audio)580*4882a593Smuzhiyun int dp_register_audio_driver(struct device *dev,
581*4882a593Smuzhiyun struct dp_audio *dp_audio)
582*4882a593Smuzhiyun {
583*4882a593Smuzhiyun struct dp_audio_private *audio_priv;
584*4882a593Smuzhiyun
585*4882a593Smuzhiyun audio_priv = container_of(dp_audio,
586*4882a593Smuzhiyun struct dp_audio_private, dp_audio);
587*4882a593Smuzhiyun
588*4882a593Smuzhiyun audio_priv->audio_pdev = platform_device_register_data(dev,
589*4882a593Smuzhiyun HDMI_CODEC_DRV_NAME,
590*4882a593Smuzhiyun PLATFORM_DEVID_AUTO,
591*4882a593Smuzhiyun &codec_data,
592*4882a593Smuzhiyun sizeof(codec_data));
593*4882a593Smuzhiyun return PTR_ERR_OR_ZERO(audio_priv->audio_pdev);
594*4882a593Smuzhiyun }
595*4882a593Smuzhiyun
dp_audio_get(struct platform_device * pdev,struct dp_panel * panel,struct dp_catalog * catalog)596*4882a593Smuzhiyun struct dp_audio *dp_audio_get(struct platform_device *pdev,
597*4882a593Smuzhiyun struct dp_panel *panel,
598*4882a593Smuzhiyun struct dp_catalog *catalog)
599*4882a593Smuzhiyun {
600*4882a593Smuzhiyun int rc = 0;
601*4882a593Smuzhiyun struct dp_audio_private *audio;
602*4882a593Smuzhiyun struct dp_audio *dp_audio;
603*4882a593Smuzhiyun
604*4882a593Smuzhiyun if (!pdev || !panel || !catalog) {
605*4882a593Smuzhiyun DRM_ERROR("invalid input\n");
606*4882a593Smuzhiyun rc = -EINVAL;
607*4882a593Smuzhiyun goto error;
608*4882a593Smuzhiyun }
609*4882a593Smuzhiyun
610*4882a593Smuzhiyun audio = devm_kzalloc(&pdev->dev, sizeof(*audio), GFP_KERNEL);
611*4882a593Smuzhiyun if (!audio) {
612*4882a593Smuzhiyun rc = -ENOMEM;
613*4882a593Smuzhiyun goto error;
614*4882a593Smuzhiyun }
615*4882a593Smuzhiyun
616*4882a593Smuzhiyun audio->pdev = pdev;
617*4882a593Smuzhiyun audio->panel = panel;
618*4882a593Smuzhiyun audio->catalog = catalog;
619*4882a593Smuzhiyun
620*4882a593Smuzhiyun dp_audio = &audio->dp_audio;
621*4882a593Smuzhiyun
622*4882a593Smuzhiyun dp_catalog_audio_init(catalog);
623*4882a593Smuzhiyun
624*4882a593Smuzhiyun return dp_audio;
625*4882a593Smuzhiyun error:
626*4882a593Smuzhiyun return ERR_PTR(rc);
627*4882a593Smuzhiyun }
628*4882a593Smuzhiyun
dp_audio_put(struct dp_audio * dp_audio)629*4882a593Smuzhiyun void dp_audio_put(struct dp_audio *dp_audio)
630*4882a593Smuzhiyun {
631*4882a593Smuzhiyun struct dp_audio_private *audio;
632*4882a593Smuzhiyun
633*4882a593Smuzhiyun if (!dp_audio)
634*4882a593Smuzhiyun return;
635*4882a593Smuzhiyun
636*4882a593Smuzhiyun audio = container_of(dp_audio, struct dp_audio_private, dp_audio);
637*4882a593Smuzhiyun
638*4882a593Smuzhiyun devm_kfree(&audio->pdev->dev, audio);
639*4882a593Smuzhiyun }
640