1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
4 */
5
6
7 #define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__
8
9 #include <linux/platform_device.h>
10
11 #include <drm/display/drm_dp_helper.h>
12 #include <drm/drm_edid.h>
13
14 #include "dp_catalog.h"
15 #include "dp_audio.h"
16 #include "dp_panel.h"
17 #include "dp_reg.h"
18 #include "dp_display.h"
19 #include "dp_utils.h"
20
21 struct msm_dp_audio_private {
22 struct platform_device *audio_pdev;
23 struct platform_device *pdev;
24 struct drm_device *drm_dev;
25 struct msm_dp_catalog *catalog;
26
27 u32 channels;
28
29 struct msm_dp_audio msm_dp_audio;
30 };
31
msm_dp_audio_stream_sdp(struct msm_dp_audio_private * audio)32 static void msm_dp_audio_stream_sdp(struct msm_dp_audio_private *audio)
33 {
34 struct dp_sdp_header sdp_hdr = {
35 .HB0 = 0x00,
36 .HB1 = 0x02,
37 .HB2 = 0x00,
38 .HB3 = audio->channels - 1,
39 };
40
41 msm_dp_catalog_write_audio_stream(audio->catalog, &sdp_hdr);
42 }
43
msm_dp_audio_timestamp_sdp(struct msm_dp_audio_private * audio)44 static void msm_dp_audio_timestamp_sdp(struct msm_dp_audio_private *audio)
45 {
46 struct dp_sdp_header sdp_hdr = {
47 .HB0 = 0x00,
48 .HB1 = 0x01,
49 .HB2 = 0x17,
50 .HB3 = 0x0 | (0x11 << 2),
51 };
52
53 msm_dp_catalog_write_audio_timestamp(audio->catalog, &sdp_hdr);
54 }
55
msm_dp_audio_infoframe_sdp(struct msm_dp_audio_private * audio)56 static void msm_dp_audio_infoframe_sdp(struct msm_dp_audio_private *audio)
57 {
58 struct dp_sdp_header sdp_hdr = {
59 .HB0 = 0x00,
60 .HB1 = 0x84,
61 .HB2 = 0x1b,
62 .HB3 = 0x0 | (0x11 << 2),
63 };
64
65 msm_dp_catalog_write_audio_infoframe(audio->catalog, &sdp_hdr);
66 }
67
msm_dp_audio_copy_management_sdp(struct msm_dp_audio_private * audio)68 static void msm_dp_audio_copy_management_sdp(struct msm_dp_audio_private *audio)
69 {
70 struct dp_sdp_header sdp_hdr = {
71 .HB0 = 0x00,
72 .HB1 = 0x05,
73 .HB2 = 0x0f,
74 .HB3 = 0x00,
75 };
76
77 msm_dp_catalog_write_audio_copy_mgmt(audio->catalog, &sdp_hdr);
78 }
79
msm_dp_audio_isrc_sdp(struct msm_dp_audio_private * audio)80 static void msm_dp_audio_isrc_sdp(struct msm_dp_audio_private *audio)
81 {
82 struct dp_sdp_header sdp_hdr = {
83 .HB0 = 0x00,
84 .HB1 = 0x06,
85 .HB2 = 0x0f,
86 .HB3 = 0x00,
87 };
88
89 msm_dp_catalog_write_audio_isrc(audio->catalog, &sdp_hdr);
90 }
91
msm_dp_audio_setup_sdp(struct msm_dp_audio_private * audio)92 static void msm_dp_audio_setup_sdp(struct msm_dp_audio_private *audio)
93 {
94 msm_dp_catalog_audio_config_sdp(audio->catalog);
95
96 msm_dp_audio_stream_sdp(audio);
97 msm_dp_audio_timestamp_sdp(audio);
98 msm_dp_audio_infoframe_sdp(audio);
99 msm_dp_audio_copy_management_sdp(audio);
100 msm_dp_audio_isrc_sdp(audio);
101 }
102
msm_dp_audio_setup_acr(struct msm_dp_audio_private * audio)103 static void msm_dp_audio_setup_acr(struct msm_dp_audio_private *audio)
104 {
105 u32 select = 0;
106 struct msm_dp_catalog *catalog = audio->catalog;
107
108 switch (audio->msm_dp_audio.bw_code) {
109 case DP_LINK_BW_1_62:
110 select = 0;
111 break;
112 case DP_LINK_BW_2_7:
113 select = 1;
114 break;
115 case DP_LINK_BW_5_4:
116 select = 2;
117 break;
118 case DP_LINK_BW_8_1:
119 select = 3;
120 break;
121 default:
122 drm_dbg_dp(audio->drm_dev, "Unknown link rate\n");
123 select = 0;
124 break;
125 }
126
127 msm_dp_catalog_audio_config_acr(catalog, select);
128 }
129
msm_dp_audio_safe_to_exit_level(struct msm_dp_audio_private * audio)130 static void msm_dp_audio_safe_to_exit_level(struct msm_dp_audio_private *audio)
131 {
132 struct msm_dp_catalog *catalog = audio->catalog;
133 u32 safe_to_exit_level = 0;
134
135 switch (audio->msm_dp_audio.lane_count) {
136 case 1:
137 safe_to_exit_level = 14;
138 break;
139 case 2:
140 safe_to_exit_level = 8;
141 break;
142 case 4:
143 safe_to_exit_level = 5;
144 break;
145 default:
146 safe_to_exit_level = 14;
147 drm_dbg_dp(audio->drm_dev,
148 "setting the default safe_to_exit_level = %u\n",
149 safe_to_exit_level);
150 break;
151 }
152
153 msm_dp_catalog_audio_sfe_level(catalog, safe_to_exit_level);
154 }
155
msm_dp_audio_enable(struct msm_dp_audio_private * audio,bool enable)156 static void msm_dp_audio_enable(struct msm_dp_audio_private *audio, bool enable)
157 {
158 struct msm_dp_catalog *catalog = audio->catalog;
159
160 msm_dp_catalog_audio_enable(catalog, enable);
161 }
162
msm_dp_audio_get_data(struct platform_device * pdev)163 static struct msm_dp_audio_private *msm_dp_audio_get_data(struct platform_device *pdev)
164 {
165 struct msm_dp_audio *msm_dp_audio;
166 struct msm_dp *msm_dp_display;
167
168 if (!pdev) {
169 DRM_ERROR("invalid input\n");
170 return ERR_PTR(-ENODEV);
171 }
172
173 msm_dp_display = platform_get_drvdata(pdev);
174 if (!msm_dp_display) {
175 DRM_ERROR("invalid input\n");
176 return ERR_PTR(-ENODEV);
177 }
178
179 msm_dp_audio = msm_dp_display->msm_dp_audio;
180
181 if (!msm_dp_audio) {
182 DRM_ERROR("invalid msm_dp_audio data\n");
183 return ERR_PTR(-EINVAL);
184 }
185
186 return container_of(msm_dp_audio, struct msm_dp_audio_private, msm_dp_audio);
187 }
188
msm_dp_audio_hook_plugged_cb(struct device * dev,void * data,hdmi_codec_plugged_cb fn,struct device * codec_dev)189 static int msm_dp_audio_hook_plugged_cb(struct device *dev, void *data,
190 hdmi_codec_plugged_cb fn,
191 struct device *codec_dev)
192 {
193
194 struct platform_device *pdev;
195 struct msm_dp *msm_dp_display;
196
197 pdev = to_platform_device(dev);
198 if (!pdev) {
199 pr_err("invalid input\n");
200 return -ENODEV;
201 }
202
203 msm_dp_display = platform_get_drvdata(pdev);
204 if (!msm_dp_display) {
205 pr_err("invalid input\n");
206 return -ENODEV;
207 }
208
209 return msm_dp_display_set_plugged_cb(msm_dp_display, fn, codec_dev);
210 }
211
msm_dp_audio_get_eld(struct device * dev,void * data,uint8_t * buf,size_t len)212 static int msm_dp_audio_get_eld(struct device *dev,
213 void *data, uint8_t *buf, size_t len)
214 {
215 struct platform_device *pdev;
216 struct msm_dp *msm_dp_display;
217
218 pdev = to_platform_device(dev);
219
220 if (!pdev) {
221 DRM_ERROR("invalid input\n");
222 return -ENODEV;
223 }
224
225 msm_dp_display = platform_get_drvdata(pdev);
226 if (!msm_dp_display) {
227 DRM_ERROR("invalid input\n");
228 return -ENODEV;
229 }
230
231 mutex_lock(&msm_dp_display->connector->eld_mutex);
232 memcpy(buf, msm_dp_display->connector->eld,
233 min(sizeof(msm_dp_display->connector->eld), len));
234 mutex_unlock(&msm_dp_display->connector->eld_mutex);
235
236 return 0;
237 }
238
msm_dp_audio_hw_params(struct device * dev,void * data,struct hdmi_codec_daifmt * daifmt,struct hdmi_codec_params * params)239 int msm_dp_audio_hw_params(struct device *dev,
240 void *data,
241 struct hdmi_codec_daifmt *daifmt,
242 struct hdmi_codec_params *params)
243 {
244 int rc = 0;
245 struct msm_dp_audio_private *audio;
246 struct platform_device *pdev;
247 struct msm_dp *msm_dp_display;
248
249 pdev = to_platform_device(dev);
250 msm_dp_display = platform_get_drvdata(pdev);
251
252 /*
253 * there could be cases where sound card can be opened even
254 * before OR even when DP is not connected . This can cause
255 * unclocked access as the audio subsystem relies on the DP
256 * driver to maintain the correct state of clocks. To protect
257 * such cases check for connection status and bail out if not
258 * connected.
259 */
260 if (!msm_dp_display->power_on) {
261 rc = -EINVAL;
262 goto end;
263 }
264
265 audio = msm_dp_audio_get_data(pdev);
266 if (IS_ERR(audio)) {
267 rc = PTR_ERR(audio);
268 goto end;
269 }
270
271 audio->channels = params->channels;
272
273 msm_dp_audio_setup_sdp(audio);
274 msm_dp_audio_setup_acr(audio);
275 msm_dp_audio_safe_to_exit_level(audio);
276 msm_dp_audio_enable(audio, true);
277 msm_dp_display_signal_audio_start(msm_dp_display);
278 msm_dp_display->audio_enabled = true;
279
280 end:
281 return rc;
282 }
283
msm_dp_audio_shutdown(struct device * dev,void * data)284 static void msm_dp_audio_shutdown(struct device *dev, void *data)
285 {
286 struct msm_dp_audio_private *audio;
287 struct platform_device *pdev;
288 struct msm_dp *msm_dp_display;
289
290 pdev = to_platform_device(dev);
291 msm_dp_display = platform_get_drvdata(pdev);
292 audio = msm_dp_audio_get_data(pdev);
293 if (IS_ERR(audio)) {
294 DRM_ERROR("failed to get audio data\n");
295 return;
296 }
297
298 /*
299 * if audio was not enabled there is no need
300 * to execute the shutdown and we can bail out early.
301 * This also makes sure that we dont cause an unclocked
302 * access when audio subsystem calls this without DP being
303 * connected. is_connected cannot be used here as its set
304 * to false earlier than this call
305 */
306 if (!msm_dp_display->audio_enabled)
307 return;
308
309 msm_dp_audio_enable(audio, false);
310 /* signal the dp display to safely shutdown clocks */
311 msm_dp_display_signal_audio_complete(msm_dp_display);
312 }
313
314 static const struct hdmi_codec_ops msm_dp_audio_codec_ops = {
315 .hw_params = msm_dp_audio_hw_params,
316 .audio_shutdown = msm_dp_audio_shutdown,
317 .get_eld = msm_dp_audio_get_eld,
318 .hook_plugged_cb = msm_dp_audio_hook_plugged_cb,
319 };
320
321 static struct hdmi_codec_pdata codec_data = {
322 .ops = &msm_dp_audio_codec_ops,
323 .max_i2s_channels = 8,
324 .i2s = 1,
325 };
326
msm_dp_unregister_audio_driver(struct device * dev,struct msm_dp_audio * msm_dp_audio)327 void msm_dp_unregister_audio_driver(struct device *dev, struct msm_dp_audio *msm_dp_audio)
328 {
329 struct msm_dp_audio_private *audio_priv;
330
331 audio_priv = container_of(msm_dp_audio, struct msm_dp_audio_private, msm_dp_audio);
332
333 if (audio_priv->audio_pdev) {
334 platform_device_unregister(audio_priv->audio_pdev);
335 audio_priv->audio_pdev = NULL;
336 }
337 }
338
msm_dp_register_audio_driver(struct device * dev,struct msm_dp_audio * msm_dp_audio)339 int msm_dp_register_audio_driver(struct device *dev,
340 struct msm_dp_audio *msm_dp_audio)
341 {
342 struct msm_dp_audio_private *audio_priv;
343
344 audio_priv = container_of(msm_dp_audio,
345 struct msm_dp_audio_private, msm_dp_audio);
346
347 audio_priv->audio_pdev = platform_device_register_data(dev,
348 HDMI_CODEC_DRV_NAME,
349 PLATFORM_DEVID_AUTO,
350 &codec_data,
351 sizeof(codec_data));
352 return PTR_ERR_OR_ZERO(audio_priv->audio_pdev);
353 }
354
msm_dp_audio_get(struct platform_device * pdev,struct msm_dp_catalog * catalog)355 struct msm_dp_audio *msm_dp_audio_get(struct platform_device *pdev,
356 struct msm_dp_catalog *catalog)
357 {
358 int rc = 0;
359 struct msm_dp_audio_private *audio;
360 struct msm_dp_audio *msm_dp_audio;
361
362 if (!pdev || !catalog) {
363 DRM_ERROR("invalid input\n");
364 rc = -EINVAL;
365 goto error;
366 }
367
368 audio = devm_kzalloc(&pdev->dev, sizeof(*audio), GFP_KERNEL);
369 if (!audio) {
370 rc = -ENOMEM;
371 goto error;
372 }
373
374 audio->pdev = pdev;
375 audio->catalog = catalog;
376
377 msm_dp_audio = &audio->msm_dp_audio;
378
379 return msm_dp_audio;
380 error:
381 return ERR_PTR(rc);
382 }
383
msm_dp_audio_put(struct msm_dp_audio * msm_dp_audio)384 void msm_dp_audio_put(struct msm_dp_audio *msm_dp_audio)
385 {
386 struct msm_dp_audio_private *audio;
387
388 if (!msm_dp_audio)
389 return;
390
391 audio = container_of(msm_dp_audio, struct msm_dp_audio_private, msm_dp_audio);
392
393 devm_kfree(&audio->pdev->dev, audio);
394 }
395