xref: /linux/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_audio.c (revision 67f8bc848ee31831336bd478e57d2f993551902e)
1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright 2026 Advanced Micro Devices, Inc.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
19  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21  * OTHER DEALINGS IN THE SOFTWARE.
22  *
23  * Authors: AMD
24  */
25 
26 #include "amdgpu.h"
27 #include "amdgpu_dm.h"
28 #include "amdgpu_dm_audio.h"
29 #include "dm_helpers.h"
30 #include "dc.h"
31 
32 #include <linux/component.h>
33 #include <drm/drm_atomic.h>
34 #include <drm/drm_audio_component.h>
35 #include <drm/drm_connector.h>
36 #include <drm/drm_edid.h>
37 #include <drm/drm_eld.h>
38 
39 #include "dc/inc/core_types.h"
40 
41 static int amdgpu_dm_audio_component_get_eld(struct device *kdev, int port,
42 					  int pipe, bool *enabled,
43 					  unsigned char *buf, int max_bytes)
44 {
45 	struct drm_device *dev = dev_get_drvdata(kdev);
46 	struct amdgpu_device *adev = drm_to_adev(dev);
47 	struct drm_connector *connector;
48 	struct drm_connector_list_iter conn_iter;
49 	struct amdgpu_dm_connector *aconnector;
50 	int ret = 0;
51 
52 	*enabled = false;
53 
54 	mutex_lock(&adev->dm.audio_lock);
55 
56 	drm_connector_list_iter_begin(dev, &conn_iter);
57 	drm_for_each_connector_iter(connector, &conn_iter) {
58 
59 		if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
60 			continue;
61 
62 		aconnector = to_amdgpu_dm_connector(connector);
63 		if (aconnector->audio_inst != port)
64 			continue;
65 
66 		*enabled = true;
67 		mutex_lock(&connector->eld_mutex);
68 		ret = drm_eld_size(connector->eld);
69 		memcpy(buf, connector->eld, min(max_bytes, ret));
70 		mutex_unlock(&connector->eld_mutex);
71 
72 		break;
73 	}
74 	drm_connector_list_iter_end(&conn_iter);
75 
76 	mutex_unlock(&adev->dm.audio_lock);
77 
78 	drm_dbg_kms(adev_to_drm(adev), "Get ELD : idx=%d ret=%d en=%d\n", port, ret, *enabled);
79 
80 	return ret;
81 }
82 
83 static const struct drm_audio_component_ops amdgpu_dm_audio_component_ops = {
84 	.get_eld = amdgpu_dm_audio_component_get_eld,
85 };
86 
87 STATIC_IFN_KUNIT int amdgpu_dm_audio_component_bind(struct device *kdev,
88 				       struct device *hda_kdev, void *data)
89 {
90 	struct drm_device *dev = dev_get_drvdata(kdev);
91 	struct amdgpu_device *adev = drm_to_adev(dev);
92 	struct drm_audio_component *acomp = data;
93 
94 	acomp->ops = &amdgpu_dm_audio_component_ops;
95 	acomp->dev = kdev;
96 	adev->dm.audio_component = acomp;
97 
98 	return 0;
99 }
100 EXPORT_IF_KUNIT(amdgpu_dm_audio_component_bind);
101 
102 STATIC_IFN_KUNIT void amdgpu_dm_audio_component_unbind(struct device *kdev,
103 					  struct device *hda_kdev, void *data)
104 {
105 	struct amdgpu_device *adev = drm_to_adev(dev_get_drvdata(kdev));
106 	struct drm_audio_component *acomp = data;
107 
108 	acomp->ops = NULL;
109 	acomp->dev = NULL;
110 	adev->dm.audio_component = NULL;
111 }
112 EXPORT_IF_KUNIT(amdgpu_dm_audio_component_unbind);
113 
114 static const struct component_ops amdgpu_dm_audio_component_bind_ops = {
115 	.bind	= amdgpu_dm_audio_component_bind,
116 	.unbind	= amdgpu_dm_audio_component_unbind,
117 };
118 
119 STATIC_IFN_KUNIT
120 void amdgpu_dm_audio_init_pins(struct amdgpu_device *adev, int audio_count,
121 			       const unsigned int *inst_array)
122 {
123 	int i;
124 
125 	adev->mode_info.audio.num_pins = audio_count;
126 
127 	for (i = 0; i < audio_count; i++) {
128 		adev->mode_info.audio.pin[i].channels = -1;
129 		adev->mode_info.audio.pin[i].rate = -1;
130 		adev->mode_info.audio.pin[i].bits_per_sample = -1;
131 		adev->mode_info.audio.pin[i].status_bits = 0;
132 		adev->mode_info.audio.pin[i].category_code = 0;
133 		adev->mode_info.audio.pin[i].connected = false;
134 		adev->mode_info.audio.pin[i].id = inst_array[i];
135 		adev->mode_info.audio.pin[i].offset = 0;
136 	}
137 }
138 EXPORT_IF_KUNIT(amdgpu_dm_audio_init_pins);
139 
140 int amdgpu_dm_audio_init(struct amdgpu_device *adev)
141 {
142 	unsigned int inst_array[MAX_AUDIOS];
143 	int audio_count;
144 	int i, ret;
145 
146 	if (!amdgpu_audio)
147 		return 0;
148 
149 	adev->mode_info.audio.enabled = true;
150 
151 	audio_count = adev->dm.dc->res_pool->audio_count;
152 	for (i = 0; i < audio_count; i++)
153 		inst_array[i] = adev->dm.dc->res_pool->audios[i]->inst;
154 	amdgpu_dm_audio_init_pins(adev, audio_count, inst_array);
155 
156 	ret = component_add(adev->dev, &amdgpu_dm_audio_component_bind_ops);
157 	if (ret < 0)
158 		return ret;
159 
160 	adev->dm.audio_registered = true;
161 
162 	return 0;
163 }
164 EXPORT_IF_KUNIT(amdgpu_dm_audio_init);
165 
166 void amdgpu_dm_audio_fini(struct amdgpu_device *adev)
167 {
168 	if (!amdgpu_audio)
169 		return;
170 
171 	if (!adev->mode_info.audio.enabled)
172 		return;
173 
174 	if (adev->dm.audio_registered) {
175 		component_del(adev->dev, &amdgpu_dm_audio_component_bind_ops);
176 		adev->dm.audio_registered = false;
177 	}
178 
179 	/* TODO: Disable audio? */
180 
181 	adev->mode_info.audio.enabled = false;
182 }
183 EXPORT_IF_KUNIT(amdgpu_dm_audio_fini);
184 
185 void amdgpu_dm_audio_eld_notify(struct amdgpu_device *adev, int pin)
186 {
187 	struct drm_audio_component *acomp = adev->dm.audio_component;
188 
189 	if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify) {
190 		drm_dbg_kms(adev_to_drm(adev), "Notify ELD: %d\n", pin);
191 
192 		acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr,
193 						 pin, -1);
194 	}
195 }
196 EXPORT_IF_KUNIT(amdgpu_dm_audio_eld_notify);
197 
198 void amdgpu_dm_fill_audio_info(struct audio_info *audio_info,
199 		     const struct drm_connector *drm_connector,
200 		     const struct dc_sink *dc_sink)
201 {
202 	int i = 0;
203 	int cea_revision = 0;
204 	const struct dc_edid_caps *edid_caps = &dc_sink->edid_caps;
205 
206 	audio_info->manufacture_id = edid_caps->manufacturer_id;
207 	audio_info->product_id = edid_caps->product_id;
208 
209 	cea_revision = drm_connector->display_info.cea_rev;
210 
211 	strscpy(audio_info->display_name,
212 		edid_caps->display_name,
213 		AUDIO_INFO_DISPLAY_NAME_SIZE_IN_CHARS);
214 
215 	if (cea_revision >= 3) {
216 		audio_info->mode_count = edid_caps->audio_mode_count;
217 
218 		for (i = 0; i < audio_info->mode_count; ++i) {
219 			audio_info->modes[i].format_code =
220 					(enum audio_format_code)
221 					(edid_caps->audio_modes[i].format_code);
222 			audio_info->modes[i].channel_count =
223 					edid_caps->audio_modes[i].channel_count;
224 			audio_info->modes[i].sample_rates.all =
225 					edid_caps->audio_modes[i].sample_rate;
226 			audio_info->modes[i].sample_size =
227 					edid_caps->audio_modes[i].sample_size;
228 		}
229 	}
230 
231 	audio_info->flags.all = edid_caps->speaker_flags;
232 
233 	/* TODO: We only check for the progressive mode, check for interlace mode too */
234 	if (drm_connector->latency_present[0]) {
235 		audio_info->video_latency = drm_connector->video_latency[0];
236 		audio_info->audio_latency = drm_connector->audio_latency[0];
237 	}
238 
239 	/* TODO: For DP, video and audio latency should be calculated from DPCD caps */
240 
241 }
242 EXPORT_IF_KUNIT(amdgpu_dm_fill_audio_info);
243 
244 void amdgpu_dm_commit_audio(struct drm_device *dev,
245 			    struct drm_atomic_commit *state)
246 {
247 	struct amdgpu_device *adev = drm_to_adev(dev);
248 	struct amdgpu_dm_connector *aconnector;
249 	struct drm_connector *connector;
250 	struct drm_connector_state *old_con_state, *new_con_state;
251 	struct drm_crtc_state *new_crtc_state;
252 	struct dm_crtc_state *new_dm_crtc_state;
253 	const struct dc_stream_status *status;
254 	int i, inst;
255 
256 	/* Notify device removals. */
257 	for_each_oldnew_connector_in_state(state, connector, old_con_state, new_con_state, i) {
258 		if (old_con_state->crtc != new_con_state->crtc) {
259 			/* CRTC changes require notification. */
260 			goto notify;
261 		}
262 
263 		if (!new_con_state->crtc)
264 			continue;
265 
266 		new_crtc_state = drm_atomic_get_new_crtc_state(
267 			state, new_con_state->crtc);
268 
269 		if (!new_crtc_state)
270 			continue;
271 
272 		if (!drm_atomic_crtc_needs_modeset(new_crtc_state))
273 			continue;
274 
275 notify:
276 		if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
277 			continue;
278 
279 		aconnector = to_amdgpu_dm_connector(connector);
280 
281 		mutex_lock(&adev->dm.audio_lock);
282 		inst = aconnector->audio_inst;
283 		aconnector->audio_inst = -1;
284 		mutex_unlock(&adev->dm.audio_lock);
285 
286 		amdgpu_dm_audio_eld_notify(adev, inst);
287 	}
288 
289 	/* Notify audio device additions. */
290 	for_each_new_connector_in_state(state, connector, new_con_state, i) {
291 		if (!new_con_state->crtc)
292 			continue;
293 
294 		new_crtc_state = drm_atomic_get_new_crtc_state(
295 			state, new_con_state->crtc);
296 
297 		if (!new_crtc_state)
298 			continue;
299 
300 		if (!drm_atomic_crtc_needs_modeset(new_crtc_state))
301 			continue;
302 
303 		new_dm_crtc_state = to_dm_crtc_state(new_crtc_state);
304 		if (!new_dm_crtc_state->stream)
305 			continue;
306 
307 		status = dc_stream_get_status(new_dm_crtc_state->stream);
308 		if (!status)
309 			continue;
310 
311 		if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
312 			continue;
313 
314 		aconnector = to_amdgpu_dm_connector(connector);
315 
316 		mutex_lock(&adev->dm.audio_lock);
317 		inst = status->audio_inst;
318 		aconnector->audio_inst = inst;
319 		mutex_unlock(&adev->dm.audio_lock);
320 
321 		amdgpu_dm_audio_eld_notify(adev, inst);
322 	}
323 }
324 EXPORT_IF_KUNIT(amdgpu_dm_commit_audio);
325 
326 #if IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST)
327 int amdgpu_dm_audio_get_param(void)
328 {
329 	return amdgpu_audio;
330 }
331 EXPORT_IF_KUNIT(amdgpu_dm_audio_get_param);
332 
333 void amdgpu_dm_audio_set_param(int val)
334 {
335 	amdgpu_audio = val;
336 }
337 EXPORT_IF_KUNIT(amdgpu_dm_audio_set_param);
338 #endif
339