xref: /linux/drivers/gpu/drm/msm/dp/dp_audio.c (revision 0ce92d548b44649a8de706f9bb9e74a4ed2f18a7)
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_drm.h"
17 #include "dp_panel.h"
18 #include "dp_reg.h"
19 #include "dp_display.h"
20 #include "dp_utils.h"
21 
22 struct msm_dp_audio_private {
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
163 static struct msm_dp_audio_private *msm_dp_audio_get_data(struct msm_dp *msm_dp_display)
164 {
165 	struct msm_dp_audio *msm_dp_audio;
166 
167 	msm_dp_audio = msm_dp_display->msm_dp_audio;
168 	if (!msm_dp_audio) {
169 		DRM_ERROR("invalid msm_dp_audio data\n");
170 		return ERR_PTR(-EINVAL);
171 	}
172 
173 	return container_of(msm_dp_audio, struct msm_dp_audio_private, msm_dp_audio);
174 }
175 
176 int msm_dp_audio_prepare(struct drm_connector *connector,
177 			 struct drm_bridge *bridge,
178 			 struct hdmi_codec_daifmt *daifmt,
179 			 struct hdmi_codec_params *params)
180 {
181 	int rc = 0;
182 	struct msm_dp_audio_private *audio;
183 	struct msm_dp *msm_dp_display;
184 
185 	msm_dp_display = to_dp_bridge(bridge)->msm_dp_display;
186 
187 	/*
188 	 * there could be cases where sound card can be opened even
189 	 * before OR even when DP is not connected . This can cause
190 	 * unclocked access as the audio subsystem relies on the DP
191 	 * driver to maintain the correct state of clocks. To protect
192 	 * such cases check for connection status and bail out if not
193 	 * connected.
194 	 */
195 	if (!msm_dp_display->power_on) {
196 		rc = -EINVAL;
197 		goto end;
198 	}
199 
200 	audio = msm_dp_audio_get_data(msm_dp_display);
201 	if (IS_ERR(audio)) {
202 		rc = PTR_ERR(audio);
203 		goto end;
204 	}
205 
206 	audio->channels = params->channels;
207 
208 	msm_dp_audio_setup_sdp(audio);
209 	msm_dp_audio_setup_acr(audio);
210 	msm_dp_audio_safe_to_exit_level(audio);
211 	msm_dp_audio_enable(audio, true);
212 	msm_dp_display_signal_audio_start(msm_dp_display);
213 	msm_dp_display->audio_enabled = true;
214 
215 end:
216 	return rc;
217 }
218 
219 void msm_dp_audio_shutdown(struct drm_connector *connector,
220 			   struct drm_bridge *bridge)
221 {
222 	struct msm_dp_audio_private *audio;
223 	struct msm_dp *msm_dp_display;
224 
225 	msm_dp_display = to_dp_bridge(bridge)->msm_dp_display;
226 	audio = msm_dp_audio_get_data(msm_dp_display);
227 	if (IS_ERR(audio)) {
228 		DRM_ERROR("failed to get audio data\n");
229 		return;
230 	}
231 
232 	/*
233 	 * if audio was not enabled there is no need
234 	 * to execute the shutdown and we can bail out early.
235 	 * This also makes sure that we dont cause an unclocked
236 	 * access when audio subsystem calls this without DP being
237 	 * connected. is_connected cannot be used here as its set
238 	 * to false earlier than this call
239 	 */
240 	if (!msm_dp_display->audio_enabled)
241 		return;
242 
243 	msm_dp_audio_enable(audio, false);
244 	/* signal the dp display to safely shutdown clocks */
245 	msm_dp_display_signal_audio_complete(msm_dp_display);
246 }
247 
248 struct msm_dp_audio *msm_dp_audio_get(struct platform_device *pdev,
249 			struct msm_dp_catalog *catalog)
250 {
251 	int rc = 0;
252 	struct msm_dp_audio_private *audio;
253 	struct msm_dp_audio *msm_dp_audio;
254 
255 	if (!pdev || !catalog) {
256 		DRM_ERROR("invalid input\n");
257 		rc = -EINVAL;
258 		goto error;
259 	}
260 
261 	audio = devm_kzalloc(&pdev->dev, sizeof(*audio), GFP_KERNEL);
262 	if (!audio) {
263 		rc = -ENOMEM;
264 		goto error;
265 	}
266 
267 	audio->pdev = pdev;
268 	audio->catalog = catalog;
269 
270 	msm_dp_audio = &audio->msm_dp_audio;
271 
272 	return msm_dp_audio;
273 error:
274 	return ERR_PTR(rc);
275 }
276 
277 void msm_dp_audio_put(struct msm_dp_audio *msm_dp_audio)
278 {
279 	struct msm_dp_audio_private *audio;
280 
281 	if (!msm_dp_audio)
282 		return;
283 
284 	audio = container_of(msm_dp_audio, struct msm_dp_audio_private, msm_dp_audio);
285 
286 	devm_kfree(&audio->pdev->dev, audio);
287 }
288