xref: /openbmc/linux/sound/soc/sof/ipc4-control.c (revision a957cbc0)
1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
2 //
3 // This file is provided under a dual BSD/GPLv2 license.  When using or
4 // redistributing this file, you may do so under either license.
5 //
6 // Copyright(c) 2022 Intel Corporation. All rights reserved.
7 //
8 //
9 
10 #include "sof-priv.h"
11 #include "sof-audio.h"
12 #include "ipc4-priv.h"
13 #include "ipc4-topology.h"
14 
15 static int sof_ipc4_set_get_kcontrol_data(struct snd_sof_control *scontrol,
16 					  bool set, bool lock)
17 {
18 	struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
19 	struct snd_soc_component *scomp = scontrol->scomp;
20 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
21 	const struct sof_ipc_ops *iops = sdev->ipc->ops;
22 	struct sof_ipc4_msg *msg = &cdata->msg;
23 	struct snd_sof_widget *swidget;
24 	bool widget_found = false;
25 	int ret = 0;
26 
27 	/* find widget associated with the control */
28 	list_for_each_entry(swidget, &sdev->widget_list, list) {
29 		if (swidget->comp_id == scontrol->comp_id) {
30 			widget_found = true;
31 			break;
32 		}
33 	}
34 
35 	if (!widget_found) {
36 		dev_err(scomp->dev, "Failed to find widget for kcontrol %s\n", scontrol->name);
37 		return -ENOENT;
38 	}
39 
40 	if (lock)
41 		mutex_lock(&swidget->setup_mutex);
42 	else
43 		lockdep_assert_held(&swidget->setup_mutex);
44 
45 	/*
46 	 * Volatile controls should always be part of static pipelines and the
47 	 * widget use_count would always be > 0 in this case. For the others,
48 	 * just return the cached value if the widget is not set up.
49 	 */
50 	if (!swidget->use_count)
51 		goto unlock;
52 
53 	msg->primary &= ~SOF_IPC4_MOD_INSTANCE_MASK;
54 	msg->primary |= SOF_IPC4_MOD_INSTANCE(swidget->instance_id);
55 
56 	ret = iops->set_get_data(sdev, msg, msg->data_size, set);
57 
58 unlock:
59 	if (lock)
60 		mutex_unlock(&swidget->setup_mutex);
61 
62 	return ret;
63 }
64 
65 static int
66 sof_ipc4_set_volume_data(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
67 			 struct snd_sof_control *scontrol, bool lock)
68 {
69 	struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
70 	struct sof_ipc4_gain *gain = swidget->private;
71 	struct sof_ipc4_msg *msg = &cdata->msg;
72 	struct sof_ipc4_gain_data data;
73 	bool all_channels_equal = true;
74 	u32 value;
75 	int ret, i;
76 
77 	/* check if all channel values are equal */
78 	value = cdata->chanv[0].value;
79 	for (i = 1; i < scontrol->num_channels; i++) {
80 		if (cdata->chanv[i].value != value) {
81 			all_channels_equal = false;
82 			break;
83 		}
84 	}
85 
86 	/*
87 	 * notify DSP with a single IPC message if all channel values are equal. Otherwise send
88 	 * a separate IPC for each channel.
89 	 */
90 	for (i = 0; i < scontrol->num_channels; i++) {
91 		if (all_channels_equal) {
92 			data.channels = SOF_IPC4_GAIN_ALL_CHANNELS_MASK;
93 			data.init_val = cdata->chanv[0].value;
94 		} else {
95 			data.channels = cdata->chanv[i].channel;
96 			data.init_val = cdata->chanv[i].value;
97 		}
98 
99 		/* set curve type and duration from topology */
100 		data.curve_duration_l = gain->data.curve_duration_l;
101 		data.curve_duration_h = gain->data.curve_duration_h;
102 		data.curve_type = gain->data.curve_type;
103 
104 		msg->data_ptr = &data;
105 		msg->data_size = sizeof(data);
106 
107 		ret = sof_ipc4_set_get_kcontrol_data(scontrol, true, lock);
108 		msg->data_ptr = NULL;
109 		msg->data_size = 0;
110 		if (ret < 0) {
111 			dev_err(sdev->dev, "Failed to set volume update for %s\n",
112 				scontrol->name);
113 			return ret;
114 		}
115 
116 		if (all_channels_equal)
117 			break;
118 	}
119 
120 	return 0;
121 }
122 
123 static bool sof_ipc4_volume_put(struct snd_sof_control *scontrol,
124 				struct snd_ctl_elem_value *ucontrol)
125 {
126 	struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
127 	struct snd_soc_component *scomp = scontrol->scomp;
128 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
129 	unsigned int channels = scontrol->num_channels;
130 	struct snd_sof_widget *swidget;
131 	bool widget_found = false;
132 	bool change = false;
133 	unsigned int i;
134 	int ret;
135 
136 	/* update each channel */
137 	for (i = 0; i < channels; i++) {
138 		u32 value = mixer_to_ipc(ucontrol->value.integer.value[i],
139 					 scontrol->volume_table, scontrol->max + 1);
140 
141 		change = change || (value != cdata->chanv[i].value);
142 		cdata->chanv[i].channel = i;
143 		cdata->chanv[i].value = value;
144 	}
145 
146 	if (!pm_runtime_active(scomp->dev))
147 		return change;
148 
149 	/* find widget associated with the control */
150 	list_for_each_entry(swidget, &sdev->widget_list, list) {
151 		if (swidget->comp_id == scontrol->comp_id) {
152 			widget_found = true;
153 			break;
154 		}
155 	}
156 
157 	if (!widget_found) {
158 		dev_err(scomp->dev, "Failed to find widget for kcontrol %s\n", scontrol->name);
159 		return false;
160 	}
161 
162 	ret = sof_ipc4_set_volume_data(sdev, swidget, scontrol, true);
163 	if (ret < 0)
164 		return false;
165 
166 	return change;
167 }
168 
169 static int sof_ipc4_volume_get(struct snd_sof_control *scontrol,
170 			       struct snd_ctl_elem_value *ucontrol)
171 {
172 	struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
173 	unsigned int channels = scontrol->num_channels;
174 	unsigned int i;
175 
176 	for (i = 0; i < channels; i++)
177 		ucontrol->value.integer.value[i] = ipc_to_mixer(cdata->chanv[i].value,
178 								scontrol->volume_table,
179 								scontrol->max + 1);
180 
181 	return 0;
182 }
183 
184 static int sof_ipc4_set_get_bytes_data(struct snd_sof_dev *sdev,
185 				       struct snd_sof_control *scontrol,
186 				       bool set, bool lock)
187 {
188 	struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
189 	struct sof_abi_hdr *data = cdata->data;
190 	struct sof_ipc4_msg *msg = &cdata->msg;
191 	int ret = 0;
192 
193 	/* Send the new data to the firmware only if it is powered up */
194 	if (set && !pm_runtime_active(sdev->dev))
195 		return 0;
196 
197 	msg->extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(data->type);
198 
199 	msg->data_ptr = data->data;
200 	msg->data_size = data->size;
201 
202 	ret = sof_ipc4_set_get_kcontrol_data(scontrol, set, lock);
203 	if (ret < 0)
204 		dev_err(sdev->dev, "Failed to %s for %s\n",
205 			set ? "set bytes update" : "get bytes",
206 			scontrol->name);
207 
208 	msg->data_ptr = NULL;
209 	msg->data_size = 0;
210 
211 	return ret;
212 }
213 
214 static int sof_ipc4_bytes_put(struct snd_sof_control *scontrol,
215 			      struct snd_ctl_elem_value *ucontrol)
216 {
217 	struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
218 	struct snd_soc_component *scomp = scontrol->scomp;
219 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
220 	struct sof_abi_hdr *data = cdata->data;
221 	size_t size;
222 
223 	if (scontrol->max_size > sizeof(ucontrol->value.bytes.data)) {
224 		dev_err_ratelimited(scomp->dev,
225 				    "data max %zu exceeds ucontrol data array size\n",
226 				    scontrol->max_size);
227 		return -EINVAL;
228 	}
229 
230 	/* scontrol->max_size has been verified to be >= sizeof(struct sof_abi_hdr) */
231 	if (data->size > scontrol->max_size - sizeof(*data)) {
232 		dev_err_ratelimited(scomp->dev,
233 				    "data size too big %u bytes max is %zu\n",
234 				    data->size, scontrol->max_size - sizeof(*data));
235 		return -EINVAL;
236 	}
237 
238 	size = data->size + sizeof(*data);
239 
240 	/* copy from kcontrol */
241 	memcpy(data, ucontrol->value.bytes.data, size);
242 
243 	sof_ipc4_set_get_bytes_data(sdev, scontrol, true, true);
244 
245 	return 0;
246 }
247 
248 static int sof_ipc4_bytes_get(struct snd_sof_control *scontrol,
249 			      struct snd_ctl_elem_value *ucontrol)
250 {
251 	struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
252 	struct snd_soc_component *scomp = scontrol->scomp;
253 	struct sof_abi_hdr *data = cdata->data;
254 	size_t size;
255 
256 	if (scontrol->max_size > sizeof(ucontrol->value.bytes.data)) {
257 		dev_err_ratelimited(scomp->dev, "data max %zu exceeds ucontrol data array size\n",
258 				    scontrol->max_size);
259 		return -EINVAL;
260 	}
261 
262 	if (data->size > scontrol->max_size - sizeof(*data)) {
263 		dev_err_ratelimited(scomp->dev,
264 				    "%u bytes of control data is invalid, max is %zu\n",
265 				    data->size, scontrol->max_size - sizeof(*data));
266 		return -EINVAL;
267 	}
268 
269 	size = data->size + sizeof(*data);
270 
271 	/* copy back to kcontrol */
272 	memcpy(ucontrol->value.bytes.data, data, size);
273 
274 	return 0;
275 }
276 
277 static int sof_ipc4_bytes_ext_put(struct snd_sof_control *scontrol,
278 				  const unsigned int __user *binary_data,
279 				  unsigned int size)
280 {
281 	struct snd_ctl_tlv __user *tlvd = (struct snd_ctl_tlv __user *)binary_data;
282 	struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
283 	struct snd_soc_component *scomp = scontrol->scomp;
284 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
285 	struct sof_abi_hdr *data = cdata->data;
286 	struct sof_abi_hdr abi_hdr;
287 	struct snd_ctl_tlv header;
288 
289 	/*
290 	 * The beginning of bytes data contains a header from where
291 	 * the length (as bytes) is needed to know the correct copy
292 	 * length of data from tlvd->tlv.
293 	 */
294 	if (copy_from_user(&header, tlvd, sizeof(struct snd_ctl_tlv)))
295 		return -EFAULT;
296 
297 	/* make sure TLV info is consistent */
298 	if (header.length + sizeof(struct snd_ctl_tlv) > size) {
299 		dev_err_ratelimited(scomp->dev,
300 				    "Inconsistent TLV, data %d + header %zu > %d\n",
301 				    header.length, sizeof(struct snd_ctl_tlv), size);
302 		return -EINVAL;
303 	}
304 
305 	/* be->max is coming from topology */
306 	if (header.length > scontrol->max_size) {
307 		dev_err_ratelimited(scomp->dev,
308 				    "Bytes data size %d exceeds max %zu\n",
309 				    header.length, scontrol->max_size);
310 		return -EINVAL;
311 	}
312 
313 	/* Verify the ABI header first */
314 	if (copy_from_user(&abi_hdr, tlvd->tlv, sizeof(abi_hdr)))
315 		return -EFAULT;
316 
317 	if (abi_hdr.magic != SOF_IPC4_ABI_MAGIC) {
318 		dev_err_ratelimited(scomp->dev, "Wrong ABI magic 0x%08x\n",
319 				    abi_hdr.magic);
320 		return -EINVAL;
321 	}
322 
323 	if (abi_hdr.size > scontrol->max_size - sizeof(abi_hdr)) {
324 		dev_err_ratelimited(scomp->dev,
325 				    "%u bytes of control data is invalid, max is %zu\n",
326 				    abi_hdr.size, scontrol->max_size - sizeof(abi_hdr));
327 		return -EINVAL;
328 	}
329 
330 	/* Copy the whole binary data which includes the ABI header and the payload */
331 	if (copy_from_user(data, tlvd->tlv, header.length))
332 		return -EFAULT;
333 
334 	sof_ipc4_set_get_bytes_data(sdev, scontrol, true, true);
335 
336 	return 0;
337 }
338 
339 static int _sof_ipc4_bytes_ext_get(struct snd_sof_control *scontrol,
340 				   const unsigned int __user *binary_data,
341 				   unsigned int size, bool from_dsp)
342 {
343 	struct snd_ctl_tlv __user *tlvd = (struct snd_ctl_tlv __user *)binary_data;
344 	struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
345 	struct snd_soc_component *scomp = scontrol->scomp;
346 	struct sof_abi_hdr *data = cdata->data;
347 	struct snd_ctl_tlv header;
348 	size_t data_size;
349 
350 	/*
351 	 * Decrement the limit by ext bytes header size to ensure the user space
352 	 * buffer is not exceeded.
353 	 */
354 	if (size < sizeof(struct snd_ctl_tlv))
355 		return -ENOSPC;
356 
357 	size -= sizeof(struct snd_ctl_tlv);
358 
359 	/* get all the component data from DSP */
360 	if (from_dsp) {
361 		struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
362 		int ret = sof_ipc4_set_get_bytes_data(sdev, scontrol, false, true);
363 
364 		if (ret < 0)
365 			return ret;
366 
367 		/* Set the ABI magic (if the control is not initialized) */
368 		data->magic = SOF_IPC4_ABI_MAGIC;
369 	}
370 
371 	if (data->size > scontrol->max_size - sizeof(*data)) {
372 		dev_err_ratelimited(scomp->dev,
373 				    "%u bytes of control data is invalid, max is %zu\n",
374 				    data->size, scontrol->max_size - sizeof(*data));
375 		return -EINVAL;
376 	}
377 
378 	data_size = data->size + sizeof(struct sof_abi_hdr);
379 
380 	/* make sure we don't exceed size provided by user space for data */
381 	if (data_size > size)
382 		return -ENOSPC;
383 
384 	header.numid = scontrol->comp_id;
385 	header.length = data_size;
386 
387 	if (copy_to_user(tlvd, &header, sizeof(struct snd_ctl_tlv)))
388 		return -EFAULT;
389 
390 	if (copy_to_user(tlvd->tlv, data, data_size))
391 		return -EFAULT;
392 
393 	return 0;
394 }
395 
396 static int sof_ipc4_bytes_ext_get(struct snd_sof_control *scontrol,
397 				  const unsigned int __user *binary_data,
398 				  unsigned int size)
399 {
400 	return _sof_ipc4_bytes_ext_get(scontrol, binary_data, size, false);
401 }
402 
403 static int sof_ipc4_bytes_ext_volatile_get(struct snd_sof_control *scontrol,
404 					   const unsigned int __user *binary_data,
405 					   unsigned int size)
406 {
407 	return _sof_ipc4_bytes_ext_get(scontrol, binary_data, size, true);
408 }
409 
410 /* set up all controls for the widget */
411 static int sof_ipc4_widget_kcontrol_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
412 {
413 	struct snd_sof_control *scontrol;
414 	int ret = 0;
415 
416 	list_for_each_entry(scontrol, &sdev->kcontrol_list, list) {
417 		if (scontrol->comp_id == swidget->comp_id) {
418 			switch (scontrol->info_type) {
419 			case SND_SOC_TPLG_CTL_VOLSW:
420 			case SND_SOC_TPLG_CTL_VOLSW_SX:
421 			case SND_SOC_TPLG_CTL_VOLSW_XR_SX:
422 				ret = sof_ipc4_set_volume_data(sdev, swidget,
423 							       scontrol, false);
424 				break;
425 			case SND_SOC_TPLG_CTL_BYTES:
426 				ret = sof_ipc4_set_get_bytes_data(sdev, scontrol,
427 								  true, false);
428 				break;
429 			default:
430 				break;
431 			}
432 
433 			if (ret < 0) {
434 				dev_err(sdev->dev,
435 					"kcontrol %d set up failed for widget %s\n",
436 					scontrol->comp_id, swidget->widget->name);
437 				return ret;
438 			}
439 		}
440 	}
441 
442 	return 0;
443 }
444 
445 static int
446 sof_ipc4_set_up_volume_table(struct snd_sof_control *scontrol, int tlv[SOF_TLV_ITEMS], int size)
447 {
448 	int i;
449 
450 	/* init the volume table */
451 	scontrol->volume_table = kcalloc(size, sizeof(u32), GFP_KERNEL);
452 	if (!scontrol->volume_table)
453 		return -ENOMEM;
454 
455 	/* populate the volume table */
456 	for (i = 0; i < size ; i++) {
457 		u32 val = vol_compute_gain(i, tlv);
458 		u64 q31val = ((u64)val) << 15; /* Can be over Q1.31, need to saturate */
459 
460 		scontrol->volume_table[i] = q31val > SOF_IPC4_VOL_ZERO_DB ?
461 						SOF_IPC4_VOL_ZERO_DB : q31val;
462 	}
463 
464 	return 0;
465 }
466 
467 const struct sof_ipc_tplg_control_ops tplg_ipc4_control_ops = {
468 	.volume_put = sof_ipc4_volume_put,
469 	.volume_get = sof_ipc4_volume_get,
470 	.bytes_put = sof_ipc4_bytes_put,
471 	.bytes_get = sof_ipc4_bytes_get,
472 	.bytes_ext_put = sof_ipc4_bytes_ext_put,
473 	.bytes_ext_get = sof_ipc4_bytes_ext_get,
474 	.bytes_ext_volatile_get = sof_ipc4_bytes_ext_volatile_get,
475 	.widget_kcontrol_setup = sof_ipc4_widget_kcontrol_setup,
476 	.set_up_volume_table = sof_ipc4_set_up_volume_table,
477 };
478