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 #include <linux/bitfield.h>
10 #include <uapi/sound/sof/tokens.h>
11 #include <sound/pcm_params.h>
12 #include <sound/sof/ext_manifest4.h>
13 #include <sound/intel-nhlt.h>
14 #include "sof-priv.h"
15 #include "sof-audio.h"
16 #include "ipc4-priv.h"
17 #include "ipc4-topology.h"
18 #include "ops.h"
19
20 /*
21 * The ignore_cpc flag can be used to ignore the CPC value for all modules by
22 * using 0 instead.
23 * The CPC is sent to the firmware along with the SOF_IPC4_MOD_INIT_INSTANCE
24 * message and it is used for clock scaling.
25 * 0 as CPC value will instruct the firmware to use maximum frequency, thus
26 * deactivating the clock scaling.
27 */
28 static bool ignore_cpc;
29 module_param_named(ipc4_ignore_cpc, ignore_cpc, bool, 0444);
30 MODULE_PARM_DESC(ipc4_ignore_cpc,
31 "Ignore CPC values. This option will disable clock scaling in firmware.");
32
33 #define SOF_IPC4_GAIN_PARAM_ID 0
34 #define SOF_IPC4_TPLG_ABI_SIZE 6
35 #define SOF_IPC4_CHAIN_DMA_BUF_SIZE_MS 2
36
37 static DEFINE_IDA(alh_group_ida);
38 static DEFINE_IDA(pipeline_ida);
39
40 static const struct sof_topology_token ipc4_sched_tokens[] = {
41 {SOF_TKN_SCHED_LP_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
42 offsetof(struct sof_ipc4_pipeline, lp_mode)},
43 {SOF_TKN_SCHED_USE_CHAIN_DMA, SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16,
44 offsetof(struct sof_ipc4_pipeline, use_chain_dma)},
45 {SOF_TKN_SCHED_CORE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
46 offsetof(struct sof_ipc4_pipeline, core_id)},
47 {SOF_TKN_SCHED_PRIORITY, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
48 offsetof(struct sof_ipc4_pipeline, priority)},
49 };
50
51 static const struct sof_topology_token pipeline_tokens[] = {
52 {SOF_TKN_SCHED_DYNAMIC_PIPELINE, SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16,
53 offsetof(struct snd_sof_widget, dynamic_pipeline_widget)},
54 };
55
56 static const struct sof_topology_token ipc4_comp_tokens[] = {
57 {SOF_TKN_COMP_IS_PAGES, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
58 offsetof(struct sof_ipc4_base_module_cfg, is_pages)},
59 };
60
61 static const struct sof_topology_token ipc4_in_audio_format_tokens[] = {
62 {SOF_TKN_CAVS_AUDIO_FORMAT_IN_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
63 offsetof(struct sof_ipc4_pin_format, audio_fmt.sampling_frequency)},
64 {SOF_TKN_CAVS_AUDIO_FORMAT_IN_BIT_DEPTH, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
65 offsetof(struct sof_ipc4_pin_format, audio_fmt.bit_depth)},
66 {SOF_TKN_CAVS_AUDIO_FORMAT_IN_CH_MAP, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
67 offsetof(struct sof_ipc4_pin_format, audio_fmt.ch_map)},
68 {SOF_TKN_CAVS_AUDIO_FORMAT_IN_CH_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
69 offsetof(struct sof_ipc4_pin_format, audio_fmt.ch_cfg)},
70 {SOF_TKN_CAVS_AUDIO_FORMAT_IN_INTERLEAVING_STYLE, SND_SOC_TPLG_TUPLE_TYPE_WORD,
71 get_token_u32, offsetof(struct sof_ipc4_pin_format,
72 audio_fmt.interleaving_style)},
73 {SOF_TKN_CAVS_AUDIO_FORMAT_IN_FMT_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
74 offsetof(struct sof_ipc4_pin_format, audio_fmt.fmt_cfg)},
75 {SOF_TKN_CAVS_AUDIO_FORMAT_INPUT_PIN_INDEX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
76 offsetof(struct sof_ipc4_pin_format, pin_index)},
77 {SOF_TKN_CAVS_AUDIO_FORMAT_IBS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
78 offsetof(struct sof_ipc4_pin_format, buffer_size)},
79 };
80
81 static const struct sof_topology_token ipc4_out_audio_format_tokens[] = {
82 {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
83 offsetof(struct sof_ipc4_pin_format, audio_fmt.sampling_frequency)},
84 {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_BIT_DEPTH, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
85 offsetof(struct sof_ipc4_pin_format, audio_fmt.bit_depth)},
86 {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_CH_MAP, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
87 offsetof(struct sof_ipc4_pin_format, audio_fmt.ch_map)},
88 {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_CH_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
89 offsetof(struct sof_ipc4_pin_format, audio_fmt.ch_cfg)},
90 {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_INTERLEAVING_STYLE, SND_SOC_TPLG_TUPLE_TYPE_WORD,
91 get_token_u32, offsetof(struct sof_ipc4_pin_format,
92 audio_fmt.interleaving_style)},
93 {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_FMT_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
94 offsetof(struct sof_ipc4_pin_format, audio_fmt.fmt_cfg)},
95 {SOF_TKN_CAVS_AUDIO_FORMAT_OUTPUT_PIN_INDEX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
96 offsetof(struct sof_ipc4_pin_format, pin_index)},
97 {SOF_TKN_CAVS_AUDIO_FORMAT_OBS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
98 offsetof(struct sof_ipc4_pin_format, buffer_size)},
99 };
100
101 static const struct sof_topology_token ipc4_copier_deep_buffer_tokens[] = {
102 {SOF_TKN_INTEL_COPIER_DEEP_BUFFER_DMA_MS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 0},
103 };
104
105 static const struct sof_topology_token ipc4_copier_tokens[] = {
106 {SOF_TKN_INTEL_COPIER_NODE_TYPE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 0},
107 };
108
109 static const struct sof_topology_token ipc4_audio_fmt_num_tokens[] = {
110 {SOF_TKN_COMP_NUM_INPUT_AUDIO_FORMATS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
111 offsetof(struct sof_ipc4_available_audio_format, num_input_formats)},
112 {SOF_TKN_COMP_NUM_OUTPUT_AUDIO_FORMATS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
113 offsetof(struct sof_ipc4_available_audio_format, num_output_formats)},
114 };
115
116 static const struct sof_topology_token dai_tokens[] = {
117 {SOF_TKN_DAI_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_dai_type,
118 offsetof(struct sof_ipc4_copier, dai_type)},
119 {SOF_TKN_DAI_INDEX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
120 offsetof(struct sof_ipc4_copier, dai_index)},
121 };
122
123 /* Component extended tokens */
124 static const struct sof_topology_token comp_ext_tokens[] = {
125 {SOF_TKN_COMP_UUID, SND_SOC_TPLG_TUPLE_TYPE_UUID, get_token_uuid,
126 offsetof(struct snd_sof_widget, uuid)},
127 {SOF_TKN_COMP_CORE_ID, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
128 offsetof(struct snd_sof_widget, core)},
129 };
130
131 static const struct sof_topology_token gain_tokens[] = {
132 {SOF_TKN_GAIN_RAMP_TYPE, SND_SOC_TPLG_TUPLE_TYPE_WORD,
133 get_token_u32, offsetof(struct sof_ipc4_gain_params, curve_type)},
134 {SOF_TKN_GAIN_RAMP_DURATION,
135 SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
136 offsetof(struct sof_ipc4_gain_params, curve_duration_l)},
137 {SOF_TKN_GAIN_VAL, SND_SOC_TPLG_TUPLE_TYPE_WORD,
138 get_token_u32, offsetof(struct sof_ipc4_gain_params, init_val)},
139 };
140
141 /* SRC */
142 static const struct sof_topology_token src_tokens[] = {
143 {SOF_TKN_SRC_RATE_OUT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
144 offsetof(struct sof_ipc4_src_data, sink_rate)},
145 };
146
147 static const struct sof_token_info ipc4_token_list[SOF_TOKEN_COUNT] = {
148 [SOF_DAI_TOKENS] = {"DAI tokens", dai_tokens, ARRAY_SIZE(dai_tokens)},
149 [SOF_PIPELINE_TOKENS] = {"Pipeline tokens", pipeline_tokens, ARRAY_SIZE(pipeline_tokens)},
150 [SOF_SCHED_TOKENS] = {"Scheduler tokens", ipc4_sched_tokens,
151 ARRAY_SIZE(ipc4_sched_tokens)},
152 [SOF_COMP_EXT_TOKENS] = {"Comp extended tokens", comp_ext_tokens,
153 ARRAY_SIZE(comp_ext_tokens)},
154 [SOF_COMP_TOKENS] = {"IPC4 Component tokens",
155 ipc4_comp_tokens, ARRAY_SIZE(ipc4_comp_tokens)},
156 [SOF_IN_AUDIO_FORMAT_TOKENS] = {"IPC4 Input Audio format tokens",
157 ipc4_in_audio_format_tokens, ARRAY_SIZE(ipc4_in_audio_format_tokens)},
158 [SOF_OUT_AUDIO_FORMAT_TOKENS] = {"IPC4 Output Audio format tokens",
159 ipc4_out_audio_format_tokens, ARRAY_SIZE(ipc4_out_audio_format_tokens)},
160 [SOF_COPIER_DEEP_BUFFER_TOKENS] = {"IPC4 Copier deep buffer tokens",
161 ipc4_copier_deep_buffer_tokens, ARRAY_SIZE(ipc4_copier_deep_buffer_tokens)},
162 [SOF_COPIER_TOKENS] = {"IPC4 Copier tokens", ipc4_copier_tokens,
163 ARRAY_SIZE(ipc4_copier_tokens)},
164 [SOF_AUDIO_FMT_NUM_TOKENS] = {"IPC4 Audio format number tokens",
165 ipc4_audio_fmt_num_tokens, ARRAY_SIZE(ipc4_audio_fmt_num_tokens)},
166 [SOF_GAIN_TOKENS] = {"Gain tokens", gain_tokens, ARRAY_SIZE(gain_tokens)},
167 [SOF_SRC_TOKENS] = {"SRC tokens", src_tokens, ARRAY_SIZE(src_tokens)},
168 };
169
sof_ipc4_find_swidget_by_ids(struct snd_sof_dev * sdev,u32 module_id,int instance_id)170 struct snd_sof_widget *sof_ipc4_find_swidget_by_ids(struct snd_sof_dev *sdev,
171 u32 module_id, int instance_id)
172 {
173 struct snd_sof_widget *swidget;
174
175 list_for_each_entry(swidget, &sdev->widget_list, list) {
176 struct sof_ipc4_fw_module *fw_module = swidget->module_info;
177
178 /* Only active module instances have valid instance_id */
179 if (!swidget->use_count)
180 continue;
181
182 if (fw_module && fw_module->man4_module_entry.id == module_id &&
183 swidget->instance_id == instance_id)
184 return swidget;
185 }
186
187 return NULL;
188 }
189
sof_ipc4_dbg_audio_format(struct device * dev,struct sof_ipc4_pin_format * pin_fmt,int num_formats)190 static void sof_ipc4_dbg_audio_format(struct device *dev, struct sof_ipc4_pin_format *pin_fmt,
191 int num_formats)
192 {
193 int i;
194
195 for (i = 0; i < num_formats; i++) {
196 struct sof_ipc4_audio_format *fmt = &pin_fmt[i].audio_fmt;
197 dev_dbg(dev,
198 "Pin index #%d: %uHz, %ubit (ch_map %#x ch_cfg %u interleaving_style %u fmt_cfg %#x) buffer size %d\n",
199 pin_fmt[i].pin_index, fmt->sampling_frequency, fmt->bit_depth, fmt->ch_map,
200 fmt->ch_cfg, fmt->interleaving_style, fmt->fmt_cfg,
201 pin_fmt[i].buffer_size);
202 }
203 }
204
205 static const struct sof_ipc4_audio_format *
sof_ipc4_get_input_pin_audio_fmt(struct snd_sof_widget * swidget,int pin_index)206 sof_ipc4_get_input_pin_audio_fmt(struct snd_sof_widget *swidget, int pin_index)
207 {
208 struct sof_ipc4_base_module_cfg_ext *base_cfg_ext;
209 struct sof_ipc4_process *process;
210 int i;
211
212 if (swidget->id != snd_soc_dapm_effect) {
213 struct sof_ipc4_base_module_cfg *base = swidget->private;
214
215 /* For non-process modules, base module config format is used for all input pins */
216 return &base->audio_fmt;
217 }
218
219 process = swidget->private;
220 base_cfg_ext = process->base_config_ext;
221
222 /*
223 * If there are multiple input formats available for a pin, the first available format
224 * is chosen.
225 */
226 for (i = 0; i < base_cfg_ext->num_input_pin_fmts; i++) {
227 struct sof_ipc4_pin_format *pin_format = &base_cfg_ext->pin_formats[i];
228
229 if (pin_format->pin_index == pin_index)
230 return &pin_format->audio_fmt;
231 }
232
233 return NULL;
234 }
235
236 /**
237 * sof_ipc4_get_audio_fmt - get available audio formats from swidget->tuples
238 * @scomp: pointer to pointer to SOC component
239 * @swidget: pointer to struct snd_sof_widget containing tuples
240 * @available_fmt: pointer to struct sof_ipc4_available_audio_format being filling in
241 * @module_base_cfg: Pointer to the base_config in the module init IPC payload
242 *
243 * Return: 0 if successful
244 */
sof_ipc4_get_audio_fmt(struct snd_soc_component * scomp,struct snd_sof_widget * swidget,struct sof_ipc4_available_audio_format * available_fmt,struct sof_ipc4_base_module_cfg * module_base_cfg)245 static int sof_ipc4_get_audio_fmt(struct snd_soc_component *scomp,
246 struct snd_sof_widget *swidget,
247 struct sof_ipc4_available_audio_format *available_fmt,
248 struct sof_ipc4_base_module_cfg *module_base_cfg)
249 {
250 struct sof_ipc4_pin_format *in_format = NULL;
251 struct sof_ipc4_pin_format *out_format;
252 int ret;
253
254 ret = sof_update_ipc_object(scomp, available_fmt,
255 SOF_AUDIO_FMT_NUM_TOKENS, swidget->tuples,
256 swidget->num_tuples, sizeof(*available_fmt), 1);
257 if (ret) {
258 dev_err(scomp->dev, "Failed to parse audio format token count\n");
259 return ret;
260 }
261
262 if (!available_fmt->num_input_formats && !available_fmt->num_output_formats) {
263 dev_err(scomp->dev, "No input/output pin formats set in topology\n");
264 return -EINVAL;
265 }
266
267 dev_dbg(scomp->dev,
268 "Number of input audio formats: %d. Number of output audio formats: %d\n",
269 available_fmt->num_input_formats, available_fmt->num_output_formats);
270
271 /* set is_pages in the module's base_config */
272 ret = sof_update_ipc_object(scomp, module_base_cfg, SOF_COMP_TOKENS, swidget->tuples,
273 swidget->num_tuples, sizeof(*module_base_cfg), 1);
274 if (ret) {
275 dev_err(scomp->dev, "parse comp tokens for %s failed, error: %d\n",
276 swidget->widget->name, ret);
277 return ret;
278 }
279
280 dev_dbg(scomp->dev, "widget %s: is_pages: %d\n", swidget->widget->name,
281 module_base_cfg->is_pages);
282
283 if (available_fmt->num_input_formats) {
284 in_format = kcalloc(available_fmt->num_input_formats,
285 sizeof(*in_format), GFP_KERNEL);
286 if (!in_format)
287 return -ENOMEM;
288 available_fmt->input_pin_fmts = in_format;
289
290 ret = sof_update_ipc_object(scomp, in_format,
291 SOF_IN_AUDIO_FORMAT_TOKENS, swidget->tuples,
292 swidget->num_tuples, sizeof(*in_format),
293 available_fmt->num_input_formats);
294 if (ret) {
295 dev_err(scomp->dev, "parse input audio fmt tokens failed %d\n", ret);
296 goto err_in;
297 }
298
299 dev_dbg(scomp->dev, "Input audio formats for %s\n", swidget->widget->name);
300 sof_ipc4_dbg_audio_format(scomp->dev, in_format,
301 available_fmt->num_input_formats);
302 }
303
304 if (available_fmt->num_output_formats) {
305 out_format = kcalloc(available_fmt->num_output_formats, sizeof(*out_format),
306 GFP_KERNEL);
307 if (!out_format) {
308 ret = -ENOMEM;
309 goto err_in;
310 }
311
312 ret = sof_update_ipc_object(scomp, out_format,
313 SOF_OUT_AUDIO_FORMAT_TOKENS, swidget->tuples,
314 swidget->num_tuples, sizeof(*out_format),
315 available_fmt->num_output_formats);
316 if (ret) {
317 dev_err(scomp->dev, "parse output audio fmt tokens failed\n");
318 goto err_out;
319 }
320
321 available_fmt->output_pin_fmts = out_format;
322 dev_dbg(scomp->dev, "Output audio formats for %s\n", swidget->widget->name);
323 sof_ipc4_dbg_audio_format(scomp->dev, out_format,
324 available_fmt->num_output_formats);
325 }
326
327 return 0;
328
329 err_out:
330 kfree(out_format);
331 err_in:
332 kfree(in_format);
333 available_fmt->input_pin_fmts = NULL;
334 return ret;
335 }
336
337 /* release the memory allocated in sof_ipc4_get_audio_fmt */
sof_ipc4_free_audio_fmt(struct sof_ipc4_available_audio_format * available_fmt)338 static void sof_ipc4_free_audio_fmt(struct sof_ipc4_available_audio_format *available_fmt)
339
340 {
341 kfree(available_fmt->output_pin_fmts);
342 available_fmt->output_pin_fmts = NULL;
343 kfree(available_fmt->input_pin_fmts);
344 available_fmt->input_pin_fmts = NULL;
345 }
346
sof_ipc4_widget_free_comp_pipeline(struct snd_sof_widget * swidget)347 static void sof_ipc4_widget_free_comp_pipeline(struct snd_sof_widget *swidget)
348 {
349 kfree(swidget->private);
350 }
351
sof_ipc4_widget_set_module_info(struct snd_sof_widget * swidget)352 static int sof_ipc4_widget_set_module_info(struct snd_sof_widget *swidget)
353 {
354 struct snd_soc_component *scomp = swidget->scomp;
355 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
356
357 swidget->module_info = sof_ipc4_find_module_by_uuid(sdev, &swidget->uuid);
358
359 if (swidget->module_info)
360 return 0;
361
362 dev_err(sdev->dev, "failed to find module info for widget %s with UUID %pUL\n",
363 swidget->widget->name, &swidget->uuid);
364 return -EINVAL;
365 }
366
sof_ipc4_widget_setup_msg(struct snd_sof_widget * swidget,struct sof_ipc4_msg * msg)367 static int sof_ipc4_widget_setup_msg(struct snd_sof_widget *swidget, struct sof_ipc4_msg *msg)
368 {
369 struct sof_ipc4_fw_module *fw_module;
370 uint32_t type;
371 int ret;
372
373 ret = sof_ipc4_widget_set_module_info(swidget);
374 if (ret)
375 return ret;
376
377 fw_module = swidget->module_info;
378
379 msg->primary = fw_module->man4_module_entry.id;
380 msg->primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_INIT_INSTANCE);
381 msg->primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
382 msg->primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
383
384 msg->extension = SOF_IPC4_MOD_EXT_CORE_ID(swidget->core);
385
386 type = (fw_module->man4_module_entry.type & SOF_IPC4_MODULE_DP) ? 1 : 0;
387 msg->extension |= SOF_IPC4_MOD_EXT_DOMAIN(type);
388
389 return 0;
390 }
391
sof_ipc4_widget_update_kcontrol_module_id(struct snd_sof_widget * swidget)392 static void sof_ipc4_widget_update_kcontrol_module_id(struct snd_sof_widget *swidget)
393 {
394 struct snd_soc_component *scomp = swidget->scomp;
395 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
396 struct sof_ipc4_fw_module *fw_module = swidget->module_info;
397 struct snd_sof_control *scontrol;
398
399 /* update module ID for all kcontrols for this widget */
400 list_for_each_entry(scontrol, &sdev->kcontrol_list, list) {
401 if (scontrol->comp_id == swidget->comp_id) {
402 struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
403 struct sof_ipc4_msg *msg = &cdata->msg;
404
405 msg->primary |= fw_module->man4_module_entry.id;
406 }
407 }
408 }
409
sof_ipc4_widget_setup_pcm(struct snd_sof_widget * swidget)410 static int sof_ipc4_widget_setup_pcm(struct snd_sof_widget *swidget)
411 {
412 struct sof_ipc4_available_audio_format *available_fmt;
413 struct snd_soc_component *scomp = swidget->scomp;
414 struct sof_ipc4_copier *ipc4_copier;
415 int node_type = 0;
416 int ret;
417
418 ipc4_copier = kzalloc(sizeof(*ipc4_copier), GFP_KERNEL);
419 if (!ipc4_copier)
420 return -ENOMEM;
421
422 swidget->private = ipc4_copier;
423 available_fmt = &ipc4_copier->available_fmt;
424
425 dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name);
426
427 ret = sof_ipc4_get_audio_fmt(scomp, swidget, available_fmt,
428 &ipc4_copier->data.base_config);
429 if (ret)
430 goto free_copier;
431
432 /*
433 * This callback is used by host copier and module-to-module copier,
434 * and only host copier needs to set gtw_cfg.
435 */
436 if (!WIDGET_IS_AIF(swidget->id))
437 goto skip_gtw_cfg;
438
439 ret = sof_update_ipc_object(scomp, &node_type,
440 SOF_COPIER_TOKENS, swidget->tuples,
441 swidget->num_tuples, sizeof(node_type), 1);
442
443 if (ret) {
444 dev_err(scomp->dev, "parse host copier node type token failed %d\n",
445 ret);
446 goto free_available_fmt;
447 }
448 dev_dbg(scomp->dev, "host copier '%s' node_type %u\n", swidget->widget->name, node_type);
449
450 skip_gtw_cfg:
451 ipc4_copier->gtw_attr = kzalloc(sizeof(*ipc4_copier->gtw_attr), GFP_KERNEL);
452 if (!ipc4_copier->gtw_attr) {
453 ret = -ENOMEM;
454 goto free_available_fmt;
455 }
456
457 ipc4_copier->copier_config = (uint32_t *)ipc4_copier->gtw_attr;
458 ipc4_copier->data.gtw_cfg.config_length =
459 sizeof(struct sof_ipc4_gtw_attributes) >> 2;
460
461 switch (swidget->id) {
462 case snd_soc_dapm_aif_in:
463 case snd_soc_dapm_aif_out:
464 ipc4_copier->data.gtw_cfg.node_id = SOF_IPC4_NODE_TYPE(node_type);
465 break;
466 case snd_soc_dapm_buffer:
467 ipc4_copier->data.gtw_cfg.node_id = SOF_IPC4_INVALID_NODE_ID;
468 ipc4_copier->ipc_config_size = 0;
469 break;
470 default:
471 dev_err(scomp->dev, "invalid widget type %d\n", swidget->id);
472 ret = -EINVAL;
473 goto free_gtw_attr;
474 }
475
476 /* set up module info and message header */
477 ret = sof_ipc4_widget_setup_msg(swidget, &ipc4_copier->msg);
478 if (ret)
479 goto free_gtw_attr;
480
481 return 0;
482
483 free_gtw_attr:
484 kfree(ipc4_copier->gtw_attr);
485 free_available_fmt:
486 sof_ipc4_free_audio_fmt(available_fmt);
487 free_copier:
488 kfree(ipc4_copier);
489 swidget->private = NULL;
490 return ret;
491 }
492
sof_ipc4_widget_free_comp_pcm(struct snd_sof_widget * swidget)493 static void sof_ipc4_widget_free_comp_pcm(struct snd_sof_widget *swidget)
494 {
495 struct sof_ipc4_copier *ipc4_copier = swidget->private;
496 struct sof_ipc4_available_audio_format *available_fmt;
497
498 if (!ipc4_copier)
499 return;
500
501 available_fmt = &ipc4_copier->available_fmt;
502 kfree(available_fmt->output_pin_fmts);
503 kfree(ipc4_copier->gtw_attr);
504 kfree(ipc4_copier);
505 swidget->private = NULL;
506 }
507
sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget * swidget)508 static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget)
509 {
510 struct sof_ipc4_available_audio_format *available_fmt;
511 struct snd_soc_component *scomp = swidget->scomp;
512 struct snd_sof_dai *dai = swidget->private;
513 struct sof_ipc4_copier *ipc4_copier;
514 struct snd_sof_widget *pipe_widget;
515 struct sof_ipc4_pipeline *pipeline;
516 int node_type = 0;
517 int ret;
518
519 ipc4_copier = kzalloc(sizeof(*ipc4_copier), GFP_KERNEL);
520 if (!ipc4_copier)
521 return -ENOMEM;
522
523 available_fmt = &ipc4_copier->available_fmt;
524
525 dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name);
526
527 ret = sof_ipc4_get_audio_fmt(scomp, swidget, available_fmt,
528 &ipc4_copier->data.base_config);
529 if (ret)
530 goto free_copier;
531
532 ret = sof_update_ipc_object(scomp, &node_type,
533 SOF_COPIER_TOKENS, swidget->tuples,
534 swidget->num_tuples, sizeof(node_type), 1);
535 if (ret) {
536 dev_err(scomp->dev, "parse dai node type failed %d\n", ret);
537 goto free_available_fmt;
538 }
539
540 ret = sof_update_ipc_object(scomp, ipc4_copier,
541 SOF_DAI_TOKENS, swidget->tuples,
542 swidget->num_tuples, sizeof(u32), 1);
543 if (ret) {
544 dev_err(scomp->dev, "parse dai copier node token failed %d\n", ret);
545 goto free_available_fmt;
546 }
547
548 dev_dbg(scomp->dev, "dai %s node_type %u dai_type %u dai_index %d\n", swidget->widget->name,
549 node_type, ipc4_copier->dai_type, ipc4_copier->dai_index);
550
551 ipc4_copier->data.gtw_cfg.node_id = SOF_IPC4_NODE_TYPE(node_type);
552
553 pipe_widget = swidget->spipe->pipe_widget;
554 pipeline = pipe_widget->private;
555 if (pipeline->use_chain_dma && ipc4_copier->dai_type != SOF_DAI_INTEL_HDA) {
556 dev_err(scomp->dev,
557 "Bad DAI type '%d', Chained DMA is only supported by HDA DAIs (%d).\n",
558 ipc4_copier->dai_type, SOF_DAI_INTEL_HDA);
559 ret = -ENODEV;
560 goto free_available_fmt;
561 }
562
563 switch (ipc4_copier->dai_type) {
564 case SOF_DAI_INTEL_ALH:
565 {
566 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
567 struct sof_ipc4_alh_configuration_blob *blob;
568 struct snd_soc_dapm_path *p;
569 struct snd_sof_widget *w;
570 int src_num = 0;
571
572 snd_soc_dapm_widget_for_each_source_path(swidget->widget, p)
573 src_num++;
574
575 if (swidget->id == snd_soc_dapm_dai_in && src_num == 0) {
576 /*
577 * The blob will not be used if the ALH copier is playback direction
578 * and doesn't connect to any source.
579 * It is fine to call kfree(ipc4_copier->copier_config) since
580 * ipc4_copier->copier_config is null.
581 */
582 ret = 0;
583 break;
584 }
585
586 blob = kzalloc(sizeof(*blob), GFP_KERNEL);
587 if (!blob) {
588 ret = -ENOMEM;
589 goto free_available_fmt;
590 }
591
592 list_for_each_entry(w, &sdev->widget_list, list) {
593 if (w->widget->sname &&
594 strcmp(w->widget->sname, swidget->widget->sname))
595 continue;
596
597 blob->alh_cfg.device_count++;
598 }
599
600 ipc4_copier->copier_config = (uint32_t *)blob;
601 ipc4_copier->data.gtw_cfg.config_length = sizeof(*blob) >> 2;
602 break;
603 }
604 case SOF_DAI_INTEL_SSP:
605 /* set SSP DAI index as the node_id */
606 ipc4_copier->data.gtw_cfg.node_id |=
607 SOF_IPC4_NODE_INDEX_INTEL_SSP(ipc4_copier->dai_index);
608 break;
609 case SOF_DAI_INTEL_DMIC:
610 /* set DMIC DAI index as the node_id */
611 ipc4_copier->data.gtw_cfg.node_id |=
612 SOF_IPC4_NODE_INDEX_INTEL_DMIC(ipc4_copier->dai_index);
613 break;
614 default:
615 ipc4_copier->gtw_attr = kzalloc(sizeof(*ipc4_copier->gtw_attr), GFP_KERNEL);
616 if (!ipc4_copier->gtw_attr) {
617 ret = -ENOMEM;
618 goto free_available_fmt;
619 }
620
621 ipc4_copier->copier_config = (uint32_t *)ipc4_copier->gtw_attr;
622 ipc4_copier->data.gtw_cfg.config_length =
623 sizeof(struct sof_ipc4_gtw_attributes) >> 2;
624 break;
625 }
626
627 dai->scomp = scomp;
628 dai->private = ipc4_copier;
629
630 /* set up module info and message header */
631 ret = sof_ipc4_widget_setup_msg(swidget, &ipc4_copier->msg);
632 if (ret)
633 goto free_copier_config;
634
635 return 0;
636
637 free_copier_config:
638 kfree(ipc4_copier->copier_config);
639 free_available_fmt:
640 sof_ipc4_free_audio_fmt(available_fmt);
641 free_copier:
642 kfree(ipc4_copier);
643 dai->private = NULL;
644 dai->scomp = NULL;
645 return ret;
646 }
647
sof_ipc4_widget_free_comp_dai(struct snd_sof_widget * swidget)648 static void sof_ipc4_widget_free_comp_dai(struct snd_sof_widget *swidget)
649 {
650 struct sof_ipc4_available_audio_format *available_fmt;
651 struct snd_sof_dai *dai = swidget->private;
652 struct sof_ipc4_copier *ipc4_copier;
653
654 if (!dai)
655 return;
656
657 if (!dai->private) {
658 kfree(dai);
659 swidget->private = NULL;
660 return;
661 }
662
663 ipc4_copier = dai->private;
664 available_fmt = &ipc4_copier->available_fmt;
665
666 kfree(available_fmt->output_pin_fmts);
667 if (ipc4_copier->dai_type != SOF_DAI_INTEL_SSP &&
668 ipc4_copier->dai_type != SOF_DAI_INTEL_DMIC)
669 kfree(ipc4_copier->copier_config);
670 kfree(dai->private);
671 kfree(dai);
672 swidget->private = NULL;
673 }
674
sof_ipc4_widget_setup_comp_pipeline(struct snd_sof_widget * swidget)675 static int sof_ipc4_widget_setup_comp_pipeline(struct snd_sof_widget *swidget)
676 {
677 struct snd_soc_component *scomp = swidget->scomp;
678 struct sof_ipc4_pipeline *pipeline;
679 struct snd_sof_pipeline *spipe = swidget->spipe;
680 int ret;
681
682 pipeline = kzalloc(sizeof(*pipeline), GFP_KERNEL);
683 if (!pipeline)
684 return -ENOMEM;
685
686 ret = sof_update_ipc_object(scomp, pipeline, SOF_SCHED_TOKENS, swidget->tuples,
687 swidget->num_tuples, sizeof(*pipeline), 1);
688 if (ret) {
689 dev_err(scomp->dev, "parsing scheduler tokens failed\n");
690 goto err;
691 }
692
693 swidget->core = pipeline->core_id;
694 spipe->core_mask |= BIT(pipeline->core_id);
695
696 if (pipeline->use_chain_dma) {
697 dev_dbg(scomp->dev, "Set up chain DMA for %s\n", swidget->widget->name);
698 swidget->private = pipeline;
699 return 0;
700 }
701
702 /* parse one set of pipeline tokens */
703 ret = sof_update_ipc_object(scomp, swidget, SOF_PIPELINE_TOKENS, swidget->tuples,
704 swidget->num_tuples, sizeof(*swidget), 1);
705 if (ret) {
706 dev_err(scomp->dev, "parsing pipeline tokens failed\n");
707 goto err;
708 }
709
710 dev_dbg(scomp->dev, "pipeline '%s': id %d, pri %d, core_id %u, lp mode %d\n",
711 swidget->widget->name, swidget->pipeline_id,
712 pipeline->priority, pipeline->core_id, pipeline->lp_mode);
713
714 swidget->private = pipeline;
715
716 pipeline->msg.primary = SOF_IPC4_GLB_PIPE_PRIORITY(pipeline->priority);
717 pipeline->msg.primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_CREATE_PIPELINE);
718 pipeline->msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
719 pipeline->msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG);
720
721 pipeline->msg.extension = pipeline->lp_mode;
722 pipeline->msg.extension |= SOF_IPC4_GLB_PIPE_EXT_CORE_ID(pipeline->core_id);
723 pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED;
724
725 return 0;
726 err:
727 kfree(pipeline);
728 return ret;
729 }
730
sof_ipc4_widget_setup_comp_pga(struct snd_sof_widget * swidget)731 static int sof_ipc4_widget_setup_comp_pga(struct snd_sof_widget *swidget)
732 {
733 struct snd_soc_component *scomp = swidget->scomp;
734 struct sof_ipc4_gain *gain;
735 int ret;
736
737 gain = kzalloc(sizeof(*gain), GFP_KERNEL);
738 if (!gain)
739 return -ENOMEM;
740
741 swidget->private = gain;
742
743 gain->data.params.channels = SOF_IPC4_GAIN_ALL_CHANNELS_MASK;
744 gain->data.params.init_val = SOF_IPC4_VOL_ZERO_DB;
745
746 ret = sof_ipc4_get_audio_fmt(scomp, swidget, &gain->available_fmt, &gain->data.base_config);
747 if (ret)
748 goto err;
749
750 ret = sof_update_ipc_object(scomp, &gain->data.params, SOF_GAIN_TOKENS,
751 swidget->tuples, swidget->num_tuples, sizeof(gain->data), 1);
752 if (ret) {
753 dev_err(scomp->dev, "Parsing gain tokens failed\n");
754 goto err;
755 }
756
757 dev_dbg(scomp->dev,
758 "pga widget %s: ramp type: %d, ramp duration %d, initial gain value: %#x\n",
759 swidget->widget->name, gain->data.params.curve_type,
760 gain->data.params.curve_duration_l, gain->data.params.init_val);
761
762 ret = sof_ipc4_widget_setup_msg(swidget, &gain->msg);
763 if (ret)
764 goto err;
765
766 sof_ipc4_widget_update_kcontrol_module_id(swidget);
767
768 return 0;
769 err:
770 sof_ipc4_free_audio_fmt(&gain->available_fmt);
771 kfree(gain);
772 swidget->private = NULL;
773 return ret;
774 }
775
sof_ipc4_widget_free_comp_pga(struct snd_sof_widget * swidget)776 static void sof_ipc4_widget_free_comp_pga(struct snd_sof_widget *swidget)
777 {
778 struct sof_ipc4_gain *gain = swidget->private;
779
780 if (!gain)
781 return;
782
783 sof_ipc4_free_audio_fmt(&gain->available_fmt);
784 kfree(swidget->private);
785 swidget->private = NULL;
786 }
787
sof_ipc4_widget_setup_comp_mixer(struct snd_sof_widget * swidget)788 static int sof_ipc4_widget_setup_comp_mixer(struct snd_sof_widget *swidget)
789 {
790 struct snd_soc_component *scomp = swidget->scomp;
791 struct sof_ipc4_mixer *mixer;
792 int ret;
793
794 dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name);
795
796 mixer = kzalloc(sizeof(*mixer), GFP_KERNEL);
797 if (!mixer)
798 return -ENOMEM;
799
800 swidget->private = mixer;
801
802 ret = sof_ipc4_get_audio_fmt(scomp, swidget, &mixer->available_fmt,
803 &mixer->base_config);
804 if (ret)
805 goto err;
806
807 ret = sof_ipc4_widget_setup_msg(swidget, &mixer->msg);
808 if (ret)
809 goto err;
810
811 return 0;
812 err:
813 sof_ipc4_free_audio_fmt(&mixer->available_fmt);
814 kfree(mixer);
815 swidget->private = NULL;
816 return ret;
817 }
818
sof_ipc4_widget_setup_comp_src(struct snd_sof_widget * swidget)819 static int sof_ipc4_widget_setup_comp_src(struct snd_sof_widget *swidget)
820 {
821 struct snd_soc_component *scomp = swidget->scomp;
822 struct snd_sof_pipeline *spipe = swidget->spipe;
823 struct sof_ipc4_src *src;
824 int ret;
825
826 dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name);
827
828 src = kzalloc(sizeof(*src), GFP_KERNEL);
829 if (!src)
830 return -ENOMEM;
831
832 swidget->private = src;
833
834 ret = sof_ipc4_get_audio_fmt(scomp, swidget, &src->available_fmt,
835 &src->data.base_config);
836 if (ret)
837 goto err;
838
839 ret = sof_update_ipc_object(scomp, &src->data, SOF_SRC_TOKENS, swidget->tuples,
840 swidget->num_tuples, sizeof(*src), 1);
841 if (ret) {
842 dev_err(scomp->dev, "Parsing SRC tokens failed\n");
843 goto err;
844 }
845
846 spipe->core_mask |= BIT(swidget->core);
847
848 dev_dbg(scomp->dev, "SRC sink rate %d\n", src->data.sink_rate);
849
850 ret = sof_ipc4_widget_setup_msg(swidget, &src->msg);
851 if (ret)
852 goto err;
853
854 return 0;
855 err:
856 sof_ipc4_free_audio_fmt(&src->available_fmt);
857 kfree(src);
858 swidget->private = NULL;
859 return ret;
860 }
861
sof_ipc4_widget_free_comp_src(struct snd_sof_widget * swidget)862 static void sof_ipc4_widget_free_comp_src(struct snd_sof_widget *swidget)
863 {
864 struct sof_ipc4_src *src = swidget->private;
865
866 if (!src)
867 return;
868
869 sof_ipc4_free_audio_fmt(&src->available_fmt);
870 kfree(swidget->private);
871 swidget->private = NULL;
872 }
873
sof_ipc4_widget_free_comp_mixer(struct snd_sof_widget * swidget)874 static void sof_ipc4_widget_free_comp_mixer(struct snd_sof_widget *swidget)
875 {
876 struct sof_ipc4_mixer *mixer = swidget->private;
877
878 if (!mixer)
879 return;
880
881 sof_ipc4_free_audio_fmt(&mixer->available_fmt);
882 kfree(swidget->private);
883 swidget->private = NULL;
884 }
885
886 /*
887 * Add the process modules support. The process modules are defined as snd_soc_dapm_effect modules.
888 */
sof_ipc4_widget_setup_comp_process(struct snd_sof_widget * swidget)889 static int sof_ipc4_widget_setup_comp_process(struct snd_sof_widget *swidget)
890 {
891 struct snd_soc_component *scomp = swidget->scomp;
892 struct sof_ipc4_fw_module *fw_module;
893 struct snd_sof_pipeline *spipe = swidget->spipe;
894 struct sof_ipc4_process *process;
895 void *cfg;
896 int ret;
897
898 process = kzalloc(sizeof(*process), GFP_KERNEL);
899 if (!process)
900 return -ENOMEM;
901
902 swidget->private = process;
903
904 ret = sof_ipc4_get_audio_fmt(scomp, swidget, &process->available_fmt,
905 &process->base_config);
906 if (ret)
907 goto err;
908
909 ret = sof_ipc4_widget_setup_msg(swidget, &process->msg);
910 if (ret)
911 goto err;
912
913 /* parse process init module payload config type from module info */
914 fw_module = swidget->module_info;
915 process->init_config = FIELD_GET(SOF_IPC4_MODULE_INIT_CONFIG_MASK,
916 fw_module->man4_module_entry.type);
917
918 process->ipc_config_size = sizeof(struct sof_ipc4_base_module_cfg);
919
920 /* allocate memory for base config extension if needed */
921 if (process->init_config == SOF_IPC4_MODULE_INIT_CONFIG_TYPE_BASE_CFG_WITH_EXT) {
922 struct sof_ipc4_base_module_cfg_ext *base_cfg_ext;
923 u32 ext_size = struct_size(base_cfg_ext, pin_formats,
924 size_add(swidget->num_input_pins,
925 swidget->num_output_pins));
926
927 base_cfg_ext = kzalloc(ext_size, GFP_KERNEL);
928 if (!base_cfg_ext) {
929 ret = -ENOMEM;
930 goto free_available_fmt;
931 }
932
933 base_cfg_ext->num_input_pin_fmts = swidget->num_input_pins;
934 base_cfg_ext->num_output_pin_fmts = swidget->num_output_pins;
935 process->base_config_ext = base_cfg_ext;
936 process->base_config_ext_size = ext_size;
937 process->ipc_config_size += ext_size;
938 }
939
940 cfg = kzalloc(process->ipc_config_size, GFP_KERNEL);
941 if (!cfg) {
942 ret = -ENOMEM;
943 goto free_base_cfg_ext;
944 }
945
946 process->ipc_config_data = cfg;
947
948 sof_ipc4_widget_update_kcontrol_module_id(swidget);
949
950 /* set pipeline core mask to keep track of the core the module is scheduled to run on */
951 spipe->core_mask |= BIT(swidget->core);
952
953 return 0;
954 free_base_cfg_ext:
955 kfree(process->base_config_ext);
956 process->base_config_ext = NULL;
957 free_available_fmt:
958 sof_ipc4_free_audio_fmt(&process->available_fmt);
959 err:
960 kfree(process);
961 swidget->private = NULL;
962 return ret;
963 }
964
sof_ipc4_widget_free_comp_process(struct snd_sof_widget * swidget)965 static void sof_ipc4_widget_free_comp_process(struct snd_sof_widget *swidget)
966 {
967 struct sof_ipc4_process *process = swidget->private;
968
969 if (!process)
970 return;
971
972 kfree(process->ipc_config_data);
973 kfree(process->base_config_ext);
974 sof_ipc4_free_audio_fmt(&process->available_fmt);
975 kfree(swidget->private);
976 swidget->private = NULL;
977 }
978
979 static void
sof_ipc4_update_resource_usage(struct snd_sof_dev * sdev,struct snd_sof_widget * swidget,struct sof_ipc4_base_module_cfg * base_config)980 sof_ipc4_update_resource_usage(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
981 struct sof_ipc4_base_module_cfg *base_config)
982 {
983 struct sof_ipc4_fw_module *fw_module = swidget->module_info;
984 struct snd_sof_widget *pipe_widget;
985 struct sof_ipc4_pipeline *pipeline;
986 int task_mem, queue_mem;
987 int ibs, bss, total;
988
989 ibs = base_config->ibs;
990 bss = base_config->is_pages;
991
992 task_mem = SOF_IPC4_PIPELINE_OBJECT_SIZE;
993 task_mem += SOF_IPC4_MODULE_INSTANCE_LIST_ITEM_SIZE + bss;
994
995 if (fw_module->man4_module_entry.type & SOF_IPC4_MODULE_LL) {
996 task_mem += SOF_IPC4_FW_ROUNDUP(SOF_IPC4_LL_TASK_OBJECT_SIZE);
997 task_mem += SOF_IPC4_FW_MAX_QUEUE_COUNT * SOF_IPC4_MODULE_INSTANCE_LIST_ITEM_SIZE;
998 task_mem += SOF_IPC4_LL_TASK_LIST_ITEM_SIZE;
999 } else {
1000 task_mem += SOF_IPC4_FW_ROUNDUP(SOF_IPC4_DP_TASK_OBJECT_SIZE);
1001 task_mem += SOF_IPC4_DP_TASK_LIST_SIZE;
1002 }
1003
1004 ibs = SOF_IPC4_FW_ROUNDUP(ibs);
1005 queue_mem = SOF_IPC4_FW_MAX_QUEUE_COUNT * (SOF_IPC4_DATA_QUEUE_OBJECT_SIZE + ibs);
1006
1007 total = SOF_IPC4_FW_PAGE(task_mem + queue_mem);
1008
1009 pipe_widget = swidget->spipe->pipe_widget;
1010 pipeline = pipe_widget->private;
1011 pipeline->mem_usage += total;
1012
1013 /* Update base_config->cpc from the module manifest */
1014 sof_ipc4_update_cpc_from_manifest(sdev, fw_module, base_config);
1015
1016 if (ignore_cpc) {
1017 dev_dbg(sdev->dev, "%s: ibs / obs: %u / %u, forcing cpc to 0 from %u\n",
1018 swidget->widget->name, base_config->ibs, base_config->obs,
1019 base_config->cpc);
1020 base_config->cpc = 0;
1021 } else {
1022 dev_dbg(sdev->dev, "%s: ibs / obs / cpc: %u / %u / %u\n",
1023 swidget->widget->name, base_config->ibs, base_config->obs,
1024 base_config->cpc);
1025 }
1026 }
1027
sof_ipc4_widget_assign_instance_id(struct snd_sof_dev * sdev,struct snd_sof_widget * swidget)1028 static int sof_ipc4_widget_assign_instance_id(struct snd_sof_dev *sdev,
1029 struct snd_sof_widget *swidget)
1030 {
1031 struct sof_ipc4_fw_module *fw_module = swidget->module_info;
1032 int max_instances = fw_module->man4_module_entry.instance_max_count;
1033
1034 swidget->instance_id = ida_alloc_max(&fw_module->m_ida, max_instances, GFP_KERNEL);
1035 if (swidget->instance_id < 0) {
1036 dev_err(sdev->dev, "failed to assign instance id for widget %s",
1037 swidget->widget->name);
1038 return swidget->instance_id;
1039 }
1040
1041 return 0;
1042 }
1043
1044 /* update hw_params based on the audio stream format */
sof_ipc4_update_hw_params(struct snd_sof_dev * sdev,struct snd_pcm_hw_params * params,struct sof_ipc4_audio_format * fmt)1045 static int sof_ipc4_update_hw_params(struct snd_sof_dev *sdev, struct snd_pcm_hw_params *params,
1046 struct sof_ipc4_audio_format *fmt)
1047 {
1048 snd_pcm_format_t snd_fmt;
1049 struct snd_interval *i;
1050 struct snd_mask *m;
1051 int valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
1052 unsigned int channels, rate;
1053
1054 switch (valid_bits) {
1055 case 16:
1056 snd_fmt = SNDRV_PCM_FORMAT_S16_LE;
1057 break;
1058 case 24:
1059 snd_fmt = SNDRV_PCM_FORMAT_S24_LE;
1060 break;
1061 case 32:
1062 snd_fmt = SNDRV_PCM_FORMAT_S32_LE;
1063 break;
1064 default:
1065 dev_err(sdev->dev, "invalid PCM valid_bits %d\n", valid_bits);
1066 return -EINVAL;
1067 }
1068
1069 m = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
1070 snd_mask_none(m);
1071 snd_mask_set_format(m, snd_fmt);
1072
1073 rate = fmt->sampling_frequency;
1074 i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
1075 i->min = rate;
1076 i->max = rate;
1077
1078 channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg);
1079 i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
1080 i->min = channels;
1081 i->max = channels;
1082
1083 return 0;
1084 }
1085
sof_ipc4_is_single_format(struct snd_sof_dev * sdev,struct sof_ipc4_pin_format * pin_fmts,u32 pin_fmts_size)1086 static bool sof_ipc4_is_single_format(struct snd_sof_dev *sdev,
1087 struct sof_ipc4_pin_format *pin_fmts, u32 pin_fmts_size)
1088 {
1089 struct sof_ipc4_audio_format *fmt;
1090 u32 rate, channels, valid_bits;
1091 int i;
1092
1093 fmt = &pin_fmts[0].audio_fmt;
1094 rate = fmt->sampling_frequency;
1095 channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg);
1096 valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
1097
1098 /* check if all output formats in topology are the same */
1099 for (i = 1; i < pin_fmts_size; i++) {
1100 u32 _rate, _channels, _valid_bits;
1101
1102 fmt = &pin_fmts[i].audio_fmt;
1103 _rate = fmt->sampling_frequency;
1104 _channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg);
1105 _valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
1106
1107 if (_rate != rate || _channels != channels || _valid_bits != valid_bits)
1108 return false;
1109 }
1110
1111 return true;
1112 }
1113
sof_ipc4_init_output_audio_fmt(struct snd_sof_dev * sdev,struct sof_ipc4_base_module_cfg * base_config,struct sof_ipc4_available_audio_format * available_fmt,u32 out_ref_rate,u32 out_ref_channels,u32 out_ref_valid_bits)1114 static int sof_ipc4_init_output_audio_fmt(struct snd_sof_dev *sdev,
1115 struct sof_ipc4_base_module_cfg *base_config,
1116 struct sof_ipc4_available_audio_format *available_fmt,
1117 u32 out_ref_rate, u32 out_ref_channels,
1118 u32 out_ref_valid_bits)
1119 {
1120 struct sof_ipc4_audio_format *out_fmt;
1121 bool single_format;
1122 int i;
1123
1124 if (!available_fmt->num_output_formats)
1125 return -EINVAL;
1126
1127 single_format = sof_ipc4_is_single_format(sdev, available_fmt->output_pin_fmts,
1128 available_fmt->num_output_formats);
1129
1130 /* pick the first format if there's only one available or if all formats are the same */
1131 if (single_format) {
1132 base_config->obs = available_fmt->output_pin_fmts[0].buffer_size;
1133 return 0;
1134 }
1135
1136 /*
1137 * if there are multiple output formats, then choose the output format that matches
1138 * the reference params
1139 */
1140 for (i = 0; i < available_fmt->num_output_formats; i++) {
1141 u32 _out_rate, _out_channels, _out_valid_bits;
1142
1143 out_fmt = &available_fmt->output_pin_fmts[i].audio_fmt;
1144 _out_rate = out_fmt->sampling_frequency;
1145 _out_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(out_fmt->fmt_cfg);
1146 _out_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(out_fmt->fmt_cfg);
1147
1148 if (_out_rate == out_ref_rate && _out_channels == out_ref_channels &&
1149 _out_valid_bits == out_ref_valid_bits) {
1150 base_config->obs = available_fmt->output_pin_fmts[i].buffer_size;
1151 return i;
1152 }
1153 }
1154
1155 return -EINVAL;
1156 }
1157
sof_ipc4_get_valid_bits(struct snd_sof_dev * sdev,struct snd_pcm_hw_params * params)1158 static int sof_ipc4_get_valid_bits(struct snd_sof_dev *sdev, struct snd_pcm_hw_params *params)
1159 {
1160 switch (params_format(params)) {
1161 case SNDRV_PCM_FORMAT_S16_LE:
1162 return 16;
1163 case SNDRV_PCM_FORMAT_S24_LE:
1164 return 24;
1165 case SNDRV_PCM_FORMAT_S32_LE:
1166 return 32;
1167 default:
1168 dev_err(sdev->dev, "invalid pcm frame format %d\n", params_format(params));
1169 return -EINVAL;
1170 }
1171 }
1172
sof_ipc4_init_input_audio_fmt(struct snd_sof_dev * sdev,struct snd_sof_widget * swidget,struct sof_ipc4_base_module_cfg * base_config,struct snd_pcm_hw_params * params,struct sof_ipc4_available_audio_format * available_fmt)1173 static int sof_ipc4_init_input_audio_fmt(struct snd_sof_dev *sdev,
1174 struct snd_sof_widget *swidget,
1175 struct sof_ipc4_base_module_cfg *base_config,
1176 struct snd_pcm_hw_params *params,
1177 struct sof_ipc4_available_audio_format *available_fmt)
1178 {
1179 struct sof_ipc4_pin_format *pin_fmts = available_fmt->input_pin_fmts;
1180 u32 pin_fmts_size = available_fmt->num_input_formats;
1181 u32 valid_bits;
1182 u32 channels;
1183 u32 rate;
1184 bool single_format;
1185 int sample_valid_bits;
1186 int i = 0;
1187
1188 if (!available_fmt->num_input_formats) {
1189 dev_err(sdev->dev, "no input formats for %s\n", swidget->widget->name);
1190 return -EINVAL;
1191 }
1192
1193 single_format = sof_ipc4_is_single_format(sdev, available_fmt->input_pin_fmts,
1194 available_fmt->num_input_formats);
1195 if (single_format)
1196 goto in_fmt;
1197
1198 sample_valid_bits = sof_ipc4_get_valid_bits(sdev, params);
1199 if (sample_valid_bits < 0)
1200 return sample_valid_bits;
1201
1202 /*
1203 * Search supported input audio formats with pin index 0 to match rate, channels and
1204 * sample_valid_bits from reference params
1205 */
1206 for (i = 0; i < pin_fmts_size; i++) {
1207 struct sof_ipc4_audio_format *fmt = &pin_fmts[i].audio_fmt;
1208
1209 if (pin_fmts[i].pin_index)
1210 continue;
1211
1212 rate = fmt->sampling_frequency;
1213 channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg);
1214 valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
1215 if (params_rate(params) == rate && params_channels(params) == channels &&
1216 sample_valid_bits == valid_bits) {
1217 dev_dbg(sdev->dev, "matched audio format index for %uHz, %ubit, %u channels: %d\n",
1218 rate, valid_bits, channels, i);
1219 break;
1220 }
1221 }
1222
1223 if (i == pin_fmts_size) {
1224 dev_err(sdev->dev, "%s: Unsupported audio format: %uHz, %ubit, %u channels\n",
1225 __func__, params_rate(params), sample_valid_bits, params_channels(params));
1226 return -EINVAL;
1227 }
1228
1229 in_fmt:
1230 /* copy input format */
1231 if (available_fmt->num_input_formats && i < available_fmt->num_input_formats) {
1232 memcpy(&base_config->audio_fmt, &available_fmt->input_pin_fmts[i].audio_fmt,
1233 sizeof(struct sof_ipc4_audio_format));
1234
1235 /* set base_cfg ibs/obs */
1236 base_config->ibs = available_fmt->input_pin_fmts[i].buffer_size;
1237
1238 dev_dbg(sdev->dev, "Init input audio formats for %s\n", swidget->widget->name);
1239 sof_ipc4_dbg_audio_format(sdev->dev, &available_fmt->input_pin_fmts[i], 1);
1240 }
1241
1242 return i;
1243 }
1244
sof_ipc4_unprepare_copier_module(struct snd_sof_widget * swidget)1245 static void sof_ipc4_unprepare_copier_module(struct snd_sof_widget *swidget)
1246 {
1247 struct sof_ipc4_copier *ipc4_copier = NULL;
1248 struct snd_sof_widget *pipe_widget;
1249 struct sof_ipc4_pipeline *pipeline;
1250
1251 /* reset pipeline memory usage */
1252 pipe_widget = swidget->spipe->pipe_widget;
1253 pipeline = pipe_widget->private;
1254 pipeline->mem_usage = 0;
1255
1256 if (WIDGET_IS_AIF(swidget->id) || swidget->id == snd_soc_dapm_buffer) {
1257 if (pipeline->use_chain_dma) {
1258 pipeline->msg.primary = 0;
1259 pipeline->msg.extension = 0;
1260 }
1261 ipc4_copier = swidget->private;
1262 } else if (WIDGET_IS_DAI(swidget->id)) {
1263 struct snd_sof_dai *dai = swidget->private;
1264
1265 ipc4_copier = dai->private;
1266
1267 if (pipeline->use_chain_dma) {
1268 pipeline->msg.primary = 0;
1269 pipeline->msg.extension = 0;
1270 }
1271
1272 if (ipc4_copier->dai_type == SOF_DAI_INTEL_ALH) {
1273 struct sof_ipc4_copier_data *copier_data = &ipc4_copier->data;
1274 struct sof_ipc4_alh_configuration_blob *blob;
1275 unsigned int group_id;
1276
1277 blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config;
1278 if (blob->alh_cfg.device_count > 1) {
1279 group_id = SOF_IPC4_NODE_INDEX(ipc4_copier->data.gtw_cfg.node_id) -
1280 ALH_MULTI_GTW_BASE;
1281 ida_free(&alh_group_ida, group_id);
1282 }
1283
1284 /* clear the node ID */
1285 copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
1286 }
1287 }
1288
1289 if (ipc4_copier) {
1290 kfree(ipc4_copier->ipc_config_data);
1291 ipc4_copier->ipc_config_data = NULL;
1292 ipc4_copier->ipc_config_size = 0;
1293 }
1294 }
1295
1296 #if IS_ENABLED(CONFIG_ACPI) && IS_ENABLED(CONFIG_SND_INTEL_NHLT)
snd_sof_get_hw_config_params(struct snd_sof_dev * sdev,struct snd_sof_dai * dai,int * sample_rate,int * channel_count,int * bit_depth)1297 static int snd_sof_get_hw_config_params(struct snd_sof_dev *sdev, struct snd_sof_dai *dai,
1298 int *sample_rate, int *channel_count, int *bit_depth)
1299 {
1300 struct snd_soc_tplg_hw_config *hw_config;
1301 struct snd_sof_dai_link *slink;
1302 bool dai_link_found = false;
1303 bool hw_cfg_found = false;
1304 int i;
1305
1306 /* get current hw_config from link */
1307 list_for_each_entry(slink, &sdev->dai_link_list, list) {
1308 if (!strcmp(slink->link->name, dai->name)) {
1309 dai_link_found = true;
1310 break;
1311 }
1312 }
1313
1314 if (!dai_link_found) {
1315 dev_err(sdev->dev, "%s: no DAI link found for DAI %s\n", __func__, dai->name);
1316 return -EINVAL;
1317 }
1318
1319 for (i = 0; i < slink->num_hw_configs; i++) {
1320 hw_config = &slink->hw_configs[i];
1321 if (dai->current_config == le32_to_cpu(hw_config->id)) {
1322 hw_cfg_found = true;
1323 break;
1324 }
1325 }
1326
1327 if (!hw_cfg_found) {
1328 dev_err(sdev->dev, "%s: no matching hw_config found for DAI %s\n", __func__,
1329 dai->name);
1330 return -EINVAL;
1331 }
1332
1333 *bit_depth = le32_to_cpu(hw_config->tdm_slot_width);
1334 *channel_count = le32_to_cpu(hw_config->tdm_slots);
1335 *sample_rate = le32_to_cpu(hw_config->fsync_rate);
1336
1337 dev_dbg(sdev->dev, "sample rate: %d sample width: %d channels: %d\n",
1338 *sample_rate, *bit_depth, *channel_count);
1339
1340 return 0;
1341 }
1342
snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev * sdev,struct snd_sof_dai * dai,struct snd_pcm_hw_params * params,u32 dai_index,u32 linktype,u8 dir,u32 ** dst,u32 * len)1343 static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai,
1344 struct snd_pcm_hw_params *params, u32 dai_index,
1345 u32 linktype, u8 dir, u32 **dst, u32 *len)
1346 {
1347 struct sof_ipc4_fw_data *ipc4_data = sdev->private;
1348 struct nhlt_specific_cfg *cfg;
1349 int sample_rate, channel_count;
1350 int bit_depth, ret;
1351 u32 nhlt_type;
1352
1353 /* convert to NHLT type */
1354 switch (linktype) {
1355 case SOF_DAI_INTEL_DMIC:
1356 nhlt_type = NHLT_LINK_DMIC;
1357 bit_depth = params_width(params);
1358 channel_count = params_channels(params);
1359 sample_rate = params_rate(params);
1360 break;
1361 case SOF_DAI_INTEL_SSP:
1362 nhlt_type = NHLT_LINK_SSP;
1363 ret = snd_sof_get_hw_config_params(sdev, dai, &sample_rate, &channel_count,
1364 &bit_depth);
1365 if (ret < 0)
1366 return ret;
1367 break;
1368 default:
1369 return 0;
1370 }
1371
1372 dev_dbg(sdev->dev, "dai index %d nhlt type %d direction %d\n",
1373 dai_index, nhlt_type, dir);
1374
1375 /* find NHLT blob with matching params */
1376 cfg = intel_nhlt_get_endpoint_blob(sdev->dev, ipc4_data->nhlt, dai_index, nhlt_type,
1377 bit_depth, bit_depth, channel_count, sample_rate,
1378 dir, 0);
1379
1380 if (!cfg) {
1381 dev_err(sdev->dev,
1382 "no matching blob for sample rate: %d sample width: %d channels: %d\n",
1383 sample_rate, bit_depth, channel_count);
1384 return -EINVAL;
1385 }
1386
1387 /* config length should be in dwords */
1388 *len = cfg->size >> 2;
1389 *dst = (u32 *)cfg->caps;
1390
1391 return 0;
1392 }
1393 #else
snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev * sdev,struct snd_sof_dai * dai,struct snd_pcm_hw_params * params,u32 dai_index,u32 linktype,u8 dir,u32 ** dst,u32 * len)1394 static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai,
1395 struct snd_pcm_hw_params *params, u32 dai_index,
1396 u32 linktype, u8 dir, u32 **dst, u32 *len)
1397 {
1398 return 0;
1399 }
1400 #endif
1401
sof_ipc4_copier_is_single_format(struct snd_sof_dev * sdev,struct sof_ipc4_pin_format * pin_fmts,u32 pin_fmts_size)1402 bool sof_ipc4_copier_is_single_format(struct snd_sof_dev *sdev,
1403 struct sof_ipc4_pin_format *pin_fmts,
1404 u32 pin_fmts_size)
1405 {
1406 struct sof_ipc4_audio_format *fmt;
1407 u32 valid_bits;
1408 int i;
1409
1410 fmt = &pin_fmts[0].audio_fmt;
1411 valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
1412
1413 /* check if all formats in topology are the same */
1414 for (i = 1; i < pin_fmts_size; i++) {
1415 u32 _valid_bits;
1416
1417 fmt = &pin_fmts[i].audio_fmt;
1418 _valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
1419
1420 if (_valid_bits != valid_bits)
1421 return false;
1422 }
1423
1424 return true;
1425 }
1426
1427 static int
sof_ipc4_prepare_copier_module(struct snd_sof_widget * swidget,struct snd_pcm_hw_params * fe_params,struct snd_sof_platform_stream_params * platform_params,struct snd_pcm_hw_params * pipeline_params,int dir)1428 sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
1429 struct snd_pcm_hw_params *fe_params,
1430 struct snd_sof_platform_stream_params *platform_params,
1431 struct snd_pcm_hw_params *pipeline_params, int dir)
1432 {
1433 struct sof_ipc4_available_audio_format *available_fmt;
1434 struct snd_soc_component *scomp = swidget->scomp;
1435 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1436 struct sof_ipc4_copier_data *copier_data;
1437 struct snd_pcm_hw_params *ref_params;
1438 struct sof_ipc4_copier *ipc4_copier;
1439 struct snd_sof_dai *dai;
1440 u32 gtw_cfg_config_length;
1441 u32 dma_config_tlv_size = 0;
1442 void **ipc_config_data;
1443 int *ipc_config_size;
1444 u32 **data;
1445 int ipc_size, ret, out_ref_valid_bits;
1446 u32 out_ref_rate, out_ref_channels;
1447 u32 deep_buffer_dma_ms = 0;
1448 int output_fmt_index;
1449 bool single_output_format;
1450
1451 dev_dbg(sdev->dev, "copier %s, type %d", swidget->widget->name, swidget->id);
1452
1453 switch (swidget->id) {
1454 case snd_soc_dapm_aif_in:
1455 case snd_soc_dapm_aif_out:
1456 {
1457 struct sof_ipc4_gtw_attributes *gtw_attr;
1458 struct snd_sof_widget *pipe_widget;
1459 struct sof_ipc4_pipeline *pipeline;
1460
1461 /* parse the deep buffer dma size */
1462 ret = sof_update_ipc_object(scomp, &deep_buffer_dma_ms,
1463 SOF_COPIER_DEEP_BUFFER_TOKENS, swidget->tuples,
1464 swidget->num_tuples, sizeof(u32), 1);
1465 if (ret) {
1466 dev_err(scomp->dev, "Failed to parse deep buffer dma size for %s\n",
1467 swidget->widget->name);
1468 return ret;
1469 }
1470
1471 ipc4_copier = (struct sof_ipc4_copier *)swidget->private;
1472 gtw_attr = ipc4_copier->gtw_attr;
1473 copier_data = &ipc4_copier->data;
1474 available_fmt = &ipc4_copier->available_fmt;
1475
1476 pipe_widget = swidget->spipe->pipe_widget;
1477 pipeline = pipe_widget->private;
1478
1479 if (pipeline->use_chain_dma) {
1480 u32 host_dma_id;
1481 u32 fifo_size;
1482
1483 host_dma_id = platform_params->stream_tag - 1;
1484 pipeline->msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_HOST_ID(host_dma_id);
1485
1486 /* Set SCS bit for S16_LE format only */
1487 if (params_format(fe_params) == SNDRV_PCM_FORMAT_S16_LE)
1488 pipeline->msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_SCS_MASK;
1489
1490 /*
1491 * Despite its name the bitfield 'fifo_size' is used to define DMA buffer
1492 * size. The expression calculates 2ms buffer size.
1493 */
1494 fifo_size = DIV_ROUND_UP((SOF_IPC4_CHAIN_DMA_BUF_SIZE_MS *
1495 params_rate(fe_params) *
1496 params_channels(fe_params) *
1497 params_physical_width(fe_params)), 8000);
1498 pipeline->msg.extension |= SOF_IPC4_GLB_EXT_CHAIN_DMA_FIFO_SIZE(fifo_size);
1499
1500 /*
1501 * Chain DMA does not support stream timestamping, set node_id to invalid
1502 * to skip the code in sof_ipc4_get_stream_start_offset().
1503 */
1504 copier_data->gtw_cfg.node_id = SOF_IPC4_INVALID_NODE_ID;
1505
1506 return 0;
1507 }
1508
1509 /*
1510 * Use the input_pin_fmts to match pcm params for playback and the output_pin_fmts
1511 * for capture.
1512 */
1513 if (dir == SNDRV_PCM_STREAM_PLAYBACK)
1514 ref_params = fe_params;
1515 else
1516 ref_params = pipeline_params;
1517
1518 copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
1519 copier_data->gtw_cfg.node_id |=
1520 SOF_IPC4_NODE_INDEX(platform_params->stream_tag - 1);
1521
1522 /* set gateway attributes */
1523 gtw_attr->lp_buffer_alloc = pipeline->lp_mode;
1524 break;
1525 }
1526 case snd_soc_dapm_dai_in:
1527 case snd_soc_dapm_dai_out:
1528 {
1529 struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
1530 struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
1531
1532 if (pipeline->use_chain_dma)
1533 return 0;
1534
1535 dai = swidget->private;
1536
1537 ipc4_copier = (struct sof_ipc4_copier *)dai->private;
1538 copier_data = &ipc4_copier->data;
1539 available_fmt = &ipc4_copier->available_fmt;
1540
1541 /*
1542 * When there is format conversion within a pipeline, the number of supported
1543 * output formats is typically limited to just 1 for the DAI copiers. But when there
1544 * is no format conversion, the DAI copiers input format must match that of the
1545 * FE hw_params for capture and the pipeline params for playback.
1546 */
1547 if (dir == SNDRV_PCM_STREAM_PLAYBACK)
1548 ref_params = pipeline_params;
1549 else
1550 ref_params = fe_params;
1551
1552 ret = snd_sof_get_nhlt_endpoint_data(sdev, dai, fe_params, ipc4_copier->dai_index,
1553 ipc4_copier->dai_type, dir,
1554 &ipc4_copier->copier_config,
1555 &copier_data->gtw_cfg.config_length);
1556 if (ret < 0)
1557 return ret;
1558
1559 break;
1560 }
1561 case snd_soc_dapm_buffer:
1562 {
1563 ipc4_copier = (struct sof_ipc4_copier *)swidget->private;
1564 copier_data = &ipc4_copier->data;
1565 available_fmt = &ipc4_copier->available_fmt;
1566 ref_params = pipeline_params;
1567
1568 break;
1569 }
1570 default:
1571 dev_err(sdev->dev, "unsupported type %d for copier %s",
1572 swidget->id, swidget->widget->name);
1573 return -EINVAL;
1574 }
1575
1576 /* set input and output audio formats */
1577 ret = sof_ipc4_init_input_audio_fmt(sdev, swidget, &copier_data->base_config, ref_params,
1578 available_fmt);
1579 if (ret < 0)
1580 return ret;
1581
1582 /* set the reference params for output format selection */
1583 single_output_format = sof_ipc4_copier_is_single_format(sdev,
1584 available_fmt->output_pin_fmts,
1585 available_fmt->num_output_formats);
1586 switch (swidget->id) {
1587 case snd_soc_dapm_aif_in:
1588 case snd_soc_dapm_dai_out:
1589 case snd_soc_dapm_buffer:
1590 {
1591 struct sof_ipc4_audio_format *in_fmt;
1592
1593 in_fmt = &available_fmt->input_pin_fmts[ret].audio_fmt;
1594 out_ref_rate = in_fmt->sampling_frequency;
1595 out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg);
1596
1597 if (!single_output_format)
1598 out_ref_valid_bits =
1599 SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg);
1600 break;
1601 }
1602 case snd_soc_dapm_aif_out:
1603 case snd_soc_dapm_dai_in:
1604 out_ref_rate = params_rate(fe_params);
1605 out_ref_channels = params_channels(fe_params);
1606 if (!single_output_format) {
1607 out_ref_valid_bits = sof_ipc4_get_valid_bits(sdev, fe_params);
1608 if (out_ref_valid_bits < 0)
1609 return out_ref_valid_bits;
1610 }
1611 break;
1612 default:
1613 /*
1614 * Unsupported type should be caught by the former switch default
1615 * case, this should never happen in reality.
1616 */
1617 return -EINVAL;
1618 }
1619
1620 /*
1621 * if the output format is the same across all available output formats, choose
1622 * that as the reference.
1623 */
1624 if (single_output_format) {
1625 struct sof_ipc4_audio_format *out_fmt;
1626
1627 out_fmt = &available_fmt->output_pin_fmts[0].audio_fmt;
1628 out_ref_valid_bits =
1629 SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(out_fmt->fmt_cfg);
1630 }
1631
1632 dev_dbg(sdev->dev, "copier %s: reference output rate %d, channels %d valid_bits %d\n",
1633 swidget->widget->name, out_ref_rate, out_ref_channels, out_ref_valid_bits);
1634
1635 output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, &copier_data->base_config,
1636 available_fmt, out_ref_rate,
1637 out_ref_channels, out_ref_valid_bits);
1638 if (output_fmt_index < 0) {
1639 dev_err(sdev->dev, "Failed to initialize output format for %s",
1640 swidget->widget->name);
1641 return output_fmt_index;
1642 }
1643
1644 /*
1645 * Set the output format. Current topology defines pin 0 input and output formats in pairs.
1646 * This assumes that the pin 0 formats are defined before all other pins.
1647 * So pick the output audio format with the same index as the chosen
1648 * input format. This logic will need to be updated when the format definitions
1649 * in topology change.
1650 */
1651 memcpy(&copier_data->out_format,
1652 &available_fmt->output_pin_fmts[output_fmt_index].audio_fmt,
1653 sizeof(struct sof_ipc4_audio_format));
1654 dev_dbg(sdev->dev, "Output audio format for %s\n", swidget->widget->name);
1655 sof_ipc4_dbg_audio_format(sdev->dev, &available_fmt->output_pin_fmts[output_fmt_index], 1);
1656
1657 switch (swidget->id) {
1658 case snd_soc_dapm_dai_in:
1659 case snd_soc_dapm_dai_out:
1660 {
1661 /*
1662 * Only SOF_DAI_INTEL_ALH needs copier_data to set blob.
1663 * That's why only ALH dai's blob is set after sof_ipc4_init_input_audio_fmt
1664 */
1665 if (ipc4_copier->dai_type == SOF_DAI_INTEL_ALH) {
1666 struct sof_ipc4_alh_configuration_blob *blob;
1667 struct sof_ipc4_copier_data *alh_data;
1668 struct sof_ipc4_copier *alh_copier;
1669 struct snd_sof_widget *w;
1670 u32 ch_count = 0;
1671 u32 ch_mask = 0;
1672 u32 ch_map;
1673 u32 step;
1674 u32 mask;
1675 int i;
1676
1677 blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config;
1678
1679 blob->gw_attr.lp_buffer_alloc = 0;
1680
1681 /* Get channel_mask from ch_map */
1682 ch_map = copier_data->base_config.audio_fmt.ch_map;
1683 for (i = 0; ch_map; i++) {
1684 if ((ch_map & 0xf) != 0xf) {
1685 ch_mask |= BIT(i);
1686 ch_count++;
1687 }
1688 ch_map >>= 4;
1689 }
1690
1691 step = ch_count / blob->alh_cfg.device_count;
1692 mask = GENMASK(step - 1, 0);
1693 /*
1694 * Set each gtw_cfg.node_id to blob->alh_cfg.mapping[]
1695 * for all widgets with the same stream name
1696 */
1697 i = 0;
1698 list_for_each_entry(w, &sdev->widget_list, list) {
1699 if (w->widget->sname &&
1700 strcmp(w->widget->sname, swidget->widget->sname))
1701 continue;
1702
1703 dai = w->private;
1704 alh_copier = (struct sof_ipc4_copier *)dai->private;
1705 alh_data = &alh_copier->data;
1706 blob->alh_cfg.mapping[i].device = alh_data->gtw_cfg.node_id;
1707 /*
1708 * Set the same channel mask for playback as the audio data is
1709 * duplicated for all speakers. For capture, split the channels
1710 * among the aggregated DAIs. For example, with 4 channels on 2
1711 * aggregated DAIs, the channel_mask should be 0x3 and 0xc for the
1712 * two DAI's.
1713 * The channel masks used depend on the cpu_dais used in the
1714 * dailink at the machine driver level, which actually comes from
1715 * the tables in soc_acpi files depending on the _ADR and devID
1716 * registers for each codec.
1717 */
1718 if (w->id == snd_soc_dapm_dai_in)
1719 blob->alh_cfg.mapping[i].channel_mask = ch_mask;
1720 else
1721 blob->alh_cfg.mapping[i].channel_mask = mask << (step * i);
1722
1723 i++;
1724 }
1725 if (blob->alh_cfg.device_count > 1) {
1726 int group_id;
1727
1728 group_id = ida_alloc_max(&alh_group_ida, ALH_MULTI_GTW_COUNT - 1,
1729 GFP_KERNEL);
1730
1731 if (group_id < 0)
1732 return group_id;
1733
1734 /* add multi-gateway base */
1735 group_id += ALH_MULTI_GTW_BASE;
1736 copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
1737 copier_data->gtw_cfg.node_id |= SOF_IPC4_NODE_INDEX(group_id);
1738 }
1739 }
1740 }
1741 }
1742
1743 /* modify the input params for the next widget */
1744 ret = sof_ipc4_update_hw_params(sdev, pipeline_params, &copier_data->out_format);
1745 if (ret)
1746 return ret;
1747
1748 /*
1749 * Set the gateway dma_buffer_size to 2ms buffer size to meet the FW expectation. In the
1750 * deep buffer case, set the dma_buffer_size depending on the deep_buffer_dma_ms set
1751 * in topology.
1752 */
1753 switch (swidget->id) {
1754 case snd_soc_dapm_dai_in:
1755 copier_data->gtw_cfg.dma_buffer_size =
1756 SOF_IPC4_MIN_DMA_BUFFER_SIZE * copier_data->base_config.ibs;
1757 break;
1758 case snd_soc_dapm_aif_in:
1759 copier_data->gtw_cfg.dma_buffer_size =
1760 max((u32)SOF_IPC4_MIN_DMA_BUFFER_SIZE, deep_buffer_dma_ms) *
1761 copier_data->base_config.ibs;
1762 dev_dbg(sdev->dev, "copier %s, dma buffer%s: %u ms (%u bytes)",
1763 swidget->widget->name,
1764 deep_buffer_dma_ms ? " (using Deep Buffer)" : "",
1765 max((u32)SOF_IPC4_MIN_DMA_BUFFER_SIZE, deep_buffer_dma_ms),
1766 copier_data->gtw_cfg.dma_buffer_size);
1767 break;
1768 case snd_soc_dapm_dai_out:
1769 case snd_soc_dapm_aif_out:
1770 copier_data->gtw_cfg.dma_buffer_size =
1771 SOF_IPC4_MIN_DMA_BUFFER_SIZE * copier_data->base_config.obs;
1772 break;
1773 default:
1774 break;
1775 }
1776
1777 data = &ipc4_copier->copier_config;
1778 ipc_config_size = &ipc4_copier->ipc_config_size;
1779 ipc_config_data = &ipc4_copier->ipc_config_data;
1780
1781 /* config_length is DWORD based */
1782 gtw_cfg_config_length = copier_data->gtw_cfg.config_length * 4;
1783 ipc_size = sizeof(*copier_data) + gtw_cfg_config_length;
1784
1785 if (ipc4_copier->dma_config_tlv.type == SOF_IPC4_GTW_DMA_CONFIG_ID &&
1786 ipc4_copier->dma_config_tlv.length) {
1787 dma_config_tlv_size = sizeof(ipc4_copier->dma_config_tlv) +
1788 ipc4_copier->dma_config_tlv.dma_config.dma_priv_config_size;
1789
1790 /* paranoia check on TLV size/length */
1791 if (dma_config_tlv_size != ipc4_copier->dma_config_tlv.length +
1792 sizeof(uint32_t) * 2) {
1793 dev_err(sdev->dev, "Invalid configuration, TLV size %d length %d\n",
1794 dma_config_tlv_size, ipc4_copier->dma_config_tlv.length);
1795 return -EINVAL;
1796 }
1797
1798 ipc_size += dma_config_tlv_size;
1799
1800 /* we also need to increase the size at the gtw level */
1801 copier_data->gtw_cfg.config_length += dma_config_tlv_size / 4;
1802 }
1803
1804 dev_dbg(sdev->dev, "copier %s, IPC size is %d", swidget->widget->name, ipc_size);
1805
1806 *ipc_config_data = kzalloc(ipc_size, GFP_KERNEL);
1807 if (!*ipc_config_data)
1808 return -ENOMEM;
1809
1810 *ipc_config_size = ipc_size;
1811
1812 /* update pipeline memory usage */
1813 sof_ipc4_update_resource_usage(sdev, swidget, &copier_data->base_config);
1814
1815 /* copy IPC data */
1816 memcpy(*ipc_config_data, (void *)copier_data, sizeof(*copier_data));
1817 if (gtw_cfg_config_length)
1818 memcpy(*ipc_config_data + sizeof(*copier_data),
1819 *data, gtw_cfg_config_length);
1820
1821 /* add DMA Config TLV, if configured */
1822 if (dma_config_tlv_size)
1823 memcpy(*ipc_config_data + sizeof(*copier_data) +
1824 gtw_cfg_config_length,
1825 &ipc4_copier->dma_config_tlv, dma_config_tlv_size);
1826
1827 /*
1828 * Restore gateway config length now that IPC payload is prepared. This avoids
1829 * counting the DMA CONFIG TLV multiple times
1830 */
1831 copier_data->gtw_cfg.config_length = gtw_cfg_config_length / 4;
1832
1833 return 0;
1834 }
1835
sof_ipc4_prepare_gain_module(struct snd_sof_widget * swidget,struct snd_pcm_hw_params * fe_params,struct snd_sof_platform_stream_params * platform_params,struct snd_pcm_hw_params * pipeline_params,int dir)1836 static int sof_ipc4_prepare_gain_module(struct snd_sof_widget *swidget,
1837 struct snd_pcm_hw_params *fe_params,
1838 struct snd_sof_platform_stream_params *platform_params,
1839 struct snd_pcm_hw_params *pipeline_params, int dir)
1840 {
1841 struct snd_soc_component *scomp = swidget->scomp;
1842 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1843 struct sof_ipc4_gain *gain = swidget->private;
1844 struct sof_ipc4_available_audio_format *available_fmt = &gain->available_fmt;
1845 struct sof_ipc4_audio_format *in_fmt;
1846 u32 out_ref_rate, out_ref_channels, out_ref_valid_bits;
1847 int ret;
1848
1849 ret = sof_ipc4_init_input_audio_fmt(sdev, swidget, &gain->data.base_config,
1850 pipeline_params, available_fmt);
1851 if (ret < 0)
1852 return ret;
1853
1854 in_fmt = &available_fmt->input_pin_fmts[ret].audio_fmt;
1855 out_ref_rate = in_fmt->sampling_frequency;
1856 out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg);
1857 out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg);
1858
1859 ret = sof_ipc4_init_output_audio_fmt(sdev, &gain->data.base_config, available_fmt,
1860 out_ref_rate, out_ref_channels, out_ref_valid_bits);
1861 if (ret < 0) {
1862 dev_err(sdev->dev, "Failed to initialize output format for %s",
1863 swidget->widget->name);
1864 return ret;
1865 }
1866
1867 /* update pipeline memory usage */
1868 sof_ipc4_update_resource_usage(sdev, swidget, &gain->data.base_config);
1869
1870 return 0;
1871 }
1872
sof_ipc4_prepare_mixer_module(struct snd_sof_widget * swidget,struct snd_pcm_hw_params * fe_params,struct snd_sof_platform_stream_params * platform_params,struct snd_pcm_hw_params * pipeline_params,int dir)1873 static int sof_ipc4_prepare_mixer_module(struct snd_sof_widget *swidget,
1874 struct snd_pcm_hw_params *fe_params,
1875 struct snd_sof_platform_stream_params *platform_params,
1876 struct snd_pcm_hw_params *pipeline_params, int dir)
1877 {
1878 struct snd_soc_component *scomp = swidget->scomp;
1879 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1880 struct sof_ipc4_mixer *mixer = swidget->private;
1881 struct sof_ipc4_available_audio_format *available_fmt = &mixer->available_fmt;
1882 struct sof_ipc4_audio_format *in_fmt;
1883 u32 out_ref_rate, out_ref_channels, out_ref_valid_bits;
1884 int ret;
1885
1886 ret = sof_ipc4_init_input_audio_fmt(sdev, swidget, &mixer->base_config,
1887 pipeline_params, available_fmt);
1888 if (ret < 0)
1889 return ret;
1890
1891 in_fmt = &available_fmt->input_pin_fmts[ret].audio_fmt;
1892 out_ref_rate = in_fmt->sampling_frequency;
1893 out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg);
1894 out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg);
1895
1896 ret = sof_ipc4_init_output_audio_fmt(sdev, &mixer->base_config, available_fmt,
1897 out_ref_rate, out_ref_channels, out_ref_valid_bits);
1898 if (ret < 0) {
1899 dev_err(sdev->dev, "Failed to initialize output format for %s",
1900 swidget->widget->name);
1901 return ret;
1902 }
1903
1904 /* update pipeline memory usage */
1905 sof_ipc4_update_resource_usage(sdev, swidget, &mixer->base_config);
1906
1907 return 0;
1908 }
1909
sof_ipc4_prepare_src_module(struct snd_sof_widget * swidget,struct snd_pcm_hw_params * fe_params,struct snd_sof_platform_stream_params * platform_params,struct snd_pcm_hw_params * pipeline_params,int dir)1910 static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget,
1911 struct snd_pcm_hw_params *fe_params,
1912 struct snd_sof_platform_stream_params *platform_params,
1913 struct snd_pcm_hw_params *pipeline_params, int dir)
1914 {
1915 struct snd_soc_component *scomp = swidget->scomp;
1916 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1917 struct sof_ipc4_src *src = swidget->private;
1918 struct sof_ipc4_available_audio_format *available_fmt = &src->available_fmt;
1919 struct sof_ipc4_audio_format *out_audio_fmt;
1920 struct sof_ipc4_audio_format *in_audio_fmt;
1921 u32 out_ref_rate, out_ref_channels, out_ref_valid_bits;
1922 int output_format_index, input_format_index;
1923
1924 input_format_index = sof_ipc4_init_input_audio_fmt(sdev, swidget, &src->data.base_config,
1925 pipeline_params, available_fmt);
1926 if (input_format_index < 0)
1927 return input_format_index;
1928
1929 /*
1930 * For playback, the SRC sink rate will be configured based on the requested output
1931 * format, which is restricted to only deal with DAI's with a single format for now.
1932 */
1933 if (dir == SNDRV_PCM_STREAM_PLAYBACK && available_fmt->num_output_formats > 1) {
1934 dev_err(sdev->dev, "Invalid number of output formats: %d for SRC %s\n",
1935 available_fmt->num_output_formats, swidget->widget->name);
1936 return -EINVAL;
1937 }
1938
1939 /*
1940 * SRC does not perform format conversion, so the output channels and valid bit depth must
1941 * be the same as that of the input.
1942 */
1943 in_audio_fmt = &available_fmt->input_pin_fmts[input_format_index].audio_fmt;
1944 out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_audio_fmt->fmt_cfg);
1945 out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_audio_fmt->fmt_cfg);
1946
1947 /*
1948 * For capture, the SRC module should convert the rate to match the rate requested by the
1949 * PCM hw_params. Set the reference params based on the fe_params unconditionally as it
1950 * will be ignored for playback anyway.
1951 */
1952 out_ref_rate = params_rate(fe_params);
1953
1954 output_format_index = sof_ipc4_init_output_audio_fmt(sdev, &src->data.base_config,
1955 available_fmt, out_ref_rate,
1956 out_ref_channels, out_ref_valid_bits);
1957 if (output_format_index < 0) {
1958 dev_err(sdev->dev, "Failed to initialize output format for %s",
1959 swidget->widget->name);
1960 return output_format_index;
1961 }
1962
1963 /* update pipeline memory usage */
1964 sof_ipc4_update_resource_usage(sdev, swidget, &src->data.base_config);
1965
1966 out_audio_fmt = &available_fmt->output_pin_fmts[output_format_index].audio_fmt;
1967 src->data.sink_rate = out_audio_fmt->sampling_frequency;
1968
1969 /* update pipeline_params for sink widgets */
1970 return sof_ipc4_update_hw_params(sdev, pipeline_params, out_audio_fmt);
1971 }
1972
1973 static int
sof_ipc4_process_set_pin_formats(struct snd_sof_widget * swidget,int pin_type)1974 sof_ipc4_process_set_pin_formats(struct snd_sof_widget *swidget, int pin_type)
1975 {
1976 struct sof_ipc4_process *process = swidget->private;
1977 struct sof_ipc4_base_module_cfg_ext *base_cfg_ext = process->base_config_ext;
1978 struct sof_ipc4_available_audio_format *available_fmt = &process->available_fmt;
1979 struct sof_ipc4_pin_format *pin_format, *format_list_to_search;
1980 struct snd_soc_component *scomp = swidget->scomp;
1981 int num_pins, format_list_count;
1982 int pin_format_offset = 0;
1983 int i, j;
1984
1985 /* set number of pins, offset of pin format and format list to search based on pin type */
1986 if (pin_type == SOF_PIN_TYPE_INPUT) {
1987 num_pins = swidget->num_input_pins;
1988 format_list_to_search = available_fmt->input_pin_fmts;
1989 format_list_count = available_fmt->num_input_formats;
1990 } else {
1991 num_pins = swidget->num_output_pins;
1992 pin_format_offset = swidget->num_input_pins;
1993 format_list_to_search = available_fmt->output_pin_fmts;
1994 format_list_count = available_fmt->num_output_formats;
1995 }
1996
1997 for (i = pin_format_offset; i < num_pins + pin_format_offset; i++) {
1998 pin_format = &base_cfg_ext->pin_formats[i];
1999
2000 /* Pin 0 audio formats are derived from the base config input/output format */
2001 if (i == pin_format_offset) {
2002 if (pin_type == SOF_PIN_TYPE_INPUT) {
2003 pin_format->buffer_size = process->base_config.ibs;
2004 pin_format->audio_fmt = process->base_config.audio_fmt;
2005 } else {
2006 pin_format->buffer_size = process->base_config.obs;
2007 pin_format->audio_fmt = process->output_format;
2008 }
2009 continue;
2010 }
2011
2012 /*
2013 * For all other pins, find the pin formats from those set in topology. If there
2014 * is more than one format specified for a pin, this will pick the first available
2015 * one.
2016 */
2017 for (j = 0; j < format_list_count; j++) {
2018 struct sof_ipc4_pin_format *pin_format_item = &format_list_to_search[j];
2019
2020 if (pin_format_item->pin_index == i - pin_format_offset) {
2021 *pin_format = *pin_format_item;
2022 break;
2023 }
2024 }
2025
2026 if (j == format_list_count) {
2027 dev_err(scomp->dev, "%s pin %d format not found for %s\n",
2028 (pin_type == SOF_PIN_TYPE_INPUT) ? "input" : "output",
2029 i - pin_format_offset, swidget->widget->name);
2030 return -EINVAL;
2031 }
2032 }
2033
2034 return 0;
2035 }
2036
sof_ipc4_process_add_base_cfg_extn(struct snd_sof_widget * swidget)2037 static int sof_ipc4_process_add_base_cfg_extn(struct snd_sof_widget *swidget)
2038 {
2039 int ret, i;
2040
2041 /* copy input and output pin formats */
2042 for (i = 0; i <= SOF_PIN_TYPE_OUTPUT; i++) {
2043 ret = sof_ipc4_process_set_pin_formats(swidget, i);
2044 if (ret < 0)
2045 return ret;
2046 }
2047
2048 return 0;
2049 }
2050
sof_ipc4_prepare_process_module(struct snd_sof_widget * swidget,struct snd_pcm_hw_params * fe_params,struct snd_sof_platform_stream_params * platform_params,struct snd_pcm_hw_params * pipeline_params,int dir)2051 static int sof_ipc4_prepare_process_module(struct snd_sof_widget *swidget,
2052 struct snd_pcm_hw_params *fe_params,
2053 struct snd_sof_platform_stream_params *platform_params,
2054 struct snd_pcm_hw_params *pipeline_params, int dir)
2055 {
2056 struct snd_soc_component *scomp = swidget->scomp;
2057 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
2058 struct sof_ipc4_process *process = swidget->private;
2059 struct sof_ipc4_available_audio_format *available_fmt = &process->available_fmt;
2060 struct sof_ipc4_audio_format *in_fmt;
2061 u32 out_ref_rate, out_ref_channels, out_ref_valid_bits;
2062 void *cfg = process->ipc_config_data;
2063 int output_fmt_index;
2064 int ret;
2065
2066 ret = sof_ipc4_init_input_audio_fmt(sdev, swidget, &process->base_config,
2067 pipeline_params, available_fmt);
2068 if (ret < 0)
2069 return ret;
2070
2071 in_fmt = &available_fmt->input_pin_fmts[ret].audio_fmt;
2072 out_ref_rate = in_fmt->sampling_frequency;
2073 out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg);
2074 out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg);
2075
2076 output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, &process->base_config,
2077 available_fmt, out_ref_rate,
2078 out_ref_channels, out_ref_valid_bits);
2079 if (output_fmt_index < 0 && available_fmt->num_output_formats) {
2080 dev_err(sdev->dev, "Failed to initialize output format for %s",
2081 swidget->widget->name);
2082 return output_fmt_index;
2083 }
2084
2085 /* copy Pin 0 output format */
2086 if (available_fmt->num_output_formats &&
2087 output_fmt_index < available_fmt->num_output_formats &&
2088 !available_fmt->output_pin_fmts[output_fmt_index].pin_index) {
2089 memcpy(&process->output_format,
2090 &available_fmt->output_pin_fmts[output_fmt_index].audio_fmt,
2091 sizeof(struct sof_ipc4_audio_format));
2092
2093 /* modify the pipeline params with the pin 0 output format */
2094 ret = sof_ipc4_update_hw_params(sdev, pipeline_params, &process->output_format);
2095 if (ret)
2096 return ret;
2097 }
2098
2099 /* update pipeline memory usage */
2100 sof_ipc4_update_resource_usage(sdev, swidget, &process->base_config);
2101
2102 /* ipc_config_data is composed of the base_config followed by an optional extension */
2103 memcpy(cfg, &process->base_config, sizeof(struct sof_ipc4_base_module_cfg));
2104 cfg += sizeof(struct sof_ipc4_base_module_cfg);
2105
2106 if (process->init_config == SOF_IPC4_MODULE_INIT_CONFIG_TYPE_BASE_CFG_WITH_EXT) {
2107 struct sof_ipc4_base_module_cfg_ext *base_cfg_ext = process->base_config_ext;
2108
2109 ret = sof_ipc4_process_add_base_cfg_extn(swidget);
2110 if (ret < 0)
2111 return ret;
2112
2113 memcpy(cfg, base_cfg_ext, process->base_config_ext_size);
2114 }
2115
2116 return 0;
2117 }
2118
sof_ipc4_control_load_volume(struct snd_sof_dev * sdev,struct snd_sof_control * scontrol)2119 static int sof_ipc4_control_load_volume(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
2120 {
2121 struct sof_ipc4_control_data *control_data;
2122 struct sof_ipc4_msg *msg;
2123 int i;
2124
2125 scontrol->size = struct_size(control_data, chanv, scontrol->num_channels);
2126
2127 /* scontrol->ipc_control_data will be freed in sof_control_unload */
2128 scontrol->ipc_control_data = kzalloc(scontrol->size, GFP_KERNEL);
2129 if (!scontrol->ipc_control_data)
2130 return -ENOMEM;
2131
2132 control_data = scontrol->ipc_control_data;
2133 control_data->index = scontrol->index;
2134
2135 msg = &control_data->msg;
2136 msg->primary = SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_LARGE_CONFIG_SET);
2137 msg->primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
2138 msg->primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
2139
2140 /* volume controls with range 0-1 (off/on) are switch controls */
2141 if (scontrol->max == 1)
2142 msg->extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_SWITCH_CONTROL_PARAM_ID);
2143 else
2144 msg->extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_GAIN_PARAM_ID);
2145
2146 for (i = 0; i < scontrol->num_channels; i++) {
2147 control_data->chanv[i].channel = i;
2148 /*
2149 * Default, initial values:
2150 * - 0dB for volume controls
2151 * - off (0) for switch controls - value already zero after
2152 * memory allocation
2153 */
2154 if (scontrol->max > 1)
2155 control_data->chanv[i].value = SOF_IPC4_VOL_ZERO_DB;
2156 }
2157
2158 return 0;
2159 }
2160
sof_ipc4_control_load_enum(struct snd_sof_dev * sdev,struct snd_sof_control * scontrol)2161 static int sof_ipc4_control_load_enum(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
2162 {
2163 struct sof_ipc4_control_data *control_data;
2164 struct sof_ipc4_msg *msg;
2165 int i;
2166
2167 scontrol->size = struct_size(control_data, chanv, scontrol->num_channels);
2168
2169 /* scontrol->ipc_control_data will be freed in sof_control_unload */
2170 scontrol->ipc_control_data = kzalloc(scontrol->size, GFP_KERNEL);
2171 if (!scontrol->ipc_control_data)
2172 return -ENOMEM;
2173
2174 control_data = scontrol->ipc_control_data;
2175 control_data->index = scontrol->index;
2176
2177 msg = &control_data->msg;
2178 msg->primary = SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_LARGE_CONFIG_SET);
2179 msg->primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
2180 msg->primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
2181
2182 msg->extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_ENUM_CONTROL_PARAM_ID);
2183
2184 /* Default, initial value for enums: first enum entry is selected (0) */
2185 for (i = 0; i < scontrol->num_channels; i++)
2186 control_data->chanv[i].channel = i;
2187
2188 return 0;
2189 }
2190
sof_ipc4_control_load_bytes(struct snd_sof_dev * sdev,struct snd_sof_control * scontrol)2191 static int sof_ipc4_control_load_bytes(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
2192 {
2193 struct sof_ipc4_control_data *control_data;
2194 struct sof_ipc4_msg *msg;
2195 int ret;
2196
2197 if (scontrol->max_size < (sizeof(*control_data) + sizeof(struct sof_abi_hdr))) {
2198 dev_err(sdev->dev, "insufficient size for a bytes control %s: %zu.\n",
2199 scontrol->name, scontrol->max_size);
2200 return -EINVAL;
2201 }
2202
2203 if (scontrol->priv_size > scontrol->max_size - sizeof(*control_data)) {
2204 dev_err(sdev->dev, "scontrol %s bytes data size %zu exceeds max %zu.\n",
2205 scontrol->name, scontrol->priv_size,
2206 scontrol->max_size - sizeof(*control_data));
2207 return -EINVAL;
2208 }
2209
2210 scontrol->size = sizeof(struct sof_ipc4_control_data) + scontrol->priv_size;
2211
2212 scontrol->ipc_control_data = kzalloc(scontrol->max_size, GFP_KERNEL);
2213 if (!scontrol->ipc_control_data)
2214 return -ENOMEM;
2215
2216 control_data = scontrol->ipc_control_data;
2217 control_data->index = scontrol->index;
2218 if (scontrol->priv_size > 0) {
2219 memcpy(control_data->data, scontrol->priv, scontrol->priv_size);
2220 kfree(scontrol->priv);
2221 scontrol->priv = NULL;
2222
2223 if (control_data->data->magic != SOF_IPC4_ABI_MAGIC) {
2224 dev_err(sdev->dev, "Wrong ABI magic (%#x) for control: %s\n",
2225 control_data->data->magic, scontrol->name);
2226 ret = -EINVAL;
2227 goto err;
2228 }
2229
2230 /* TODO: check the ABI version */
2231
2232 if (control_data->data->size + sizeof(struct sof_abi_hdr) !=
2233 scontrol->priv_size) {
2234 dev_err(sdev->dev, "Control %s conflict in bytes %zu vs. priv size %zu.\n",
2235 scontrol->name,
2236 control_data->data->size + sizeof(struct sof_abi_hdr),
2237 scontrol->priv_size);
2238 ret = -EINVAL;
2239 goto err;
2240 }
2241 }
2242
2243 msg = &control_data->msg;
2244 msg->primary = SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_LARGE_CONFIG_SET);
2245 msg->primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
2246 msg->primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
2247
2248 return 0;
2249
2250 err:
2251 kfree(scontrol->ipc_control_data);
2252 scontrol->ipc_control_data = NULL;
2253 return ret;
2254 }
2255
sof_ipc4_control_setup(struct snd_sof_dev * sdev,struct snd_sof_control * scontrol)2256 static int sof_ipc4_control_setup(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
2257 {
2258 switch (scontrol->info_type) {
2259 case SND_SOC_TPLG_CTL_VOLSW:
2260 case SND_SOC_TPLG_CTL_VOLSW_SX:
2261 case SND_SOC_TPLG_CTL_VOLSW_XR_SX:
2262 return sof_ipc4_control_load_volume(sdev, scontrol);
2263 case SND_SOC_TPLG_CTL_BYTES:
2264 return sof_ipc4_control_load_bytes(sdev, scontrol);
2265 case SND_SOC_TPLG_CTL_ENUM:
2266 case SND_SOC_TPLG_CTL_ENUM_VALUE:
2267 return sof_ipc4_control_load_enum(sdev, scontrol);
2268 default:
2269 break;
2270 }
2271
2272 return 0;
2273 }
2274
sof_ipc4_widget_setup(struct snd_sof_dev * sdev,struct snd_sof_widget * swidget)2275 static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
2276 {
2277 struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
2278 struct sof_ipc4_fw_data *ipc4_data = sdev->private;
2279 struct sof_ipc4_pipeline *pipeline;
2280 struct sof_ipc4_msg *msg;
2281 void *ipc_data = NULL;
2282 u32 ipc_size = 0;
2283 int ret;
2284
2285 switch (swidget->id) {
2286 case snd_soc_dapm_scheduler:
2287 pipeline = swidget->private;
2288
2289 if (pipeline->use_chain_dma) {
2290 dev_warn(sdev->dev, "use_chain_dma set for scheduler %s",
2291 swidget->widget->name);
2292 return 0;
2293 }
2294
2295 dev_dbg(sdev->dev, "pipeline: %d memory pages: %d\n", swidget->pipeline_id,
2296 pipeline->mem_usage);
2297
2298 msg = &pipeline->msg;
2299 msg->primary |= pipeline->mem_usage;
2300
2301 swidget->instance_id = ida_alloc_max(&pipeline_ida, ipc4_data->max_num_pipelines,
2302 GFP_KERNEL);
2303 if (swidget->instance_id < 0) {
2304 dev_err(sdev->dev, "failed to assign pipeline id for %s: %d\n",
2305 swidget->widget->name, swidget->instance_id);
2306 return swidget->instance_id;
2307 }
2308 msg->primary &= ~SOF_IPC4_GLB_PIPE_INSTANCE_MASK;
2309 msg->primary |= SOF_IPC4_GLB_PIPE_INSTANCE_ID(swidget->instance_id);
2310 break;
2311 case snd_soc_dapm_aif_in:
2312 case snd_soc_dapm_aif_out:
2313 case snd_soc_dapm_buffer:
2314 {
2315 struct sof_ipc4_copier *ipc4_copier = swidget->private;
2316
2317 pipeline = pipe_widget->private;
2318 if (pipeline->use_chain_dma)
2319 return 0;
2320
2321 ipc_size = ipc4_copier->ipc_config_size;
2322 ipc_data = ipc4_copier->ipc_config_data;
2323
2324 msg = &ipc4_copier->msg;
2325 break;
2326 }
2327 case snd_soc_dapm_dai_in:
2328 case snd_soc_dapm_dai_out:
2329 {
2330 struct snd_sof_dai *dai = swidget->private;
2331 struct sof_ipc4_copier *ipc4_copier = dai->private;
2332
2333 pipeline = pipe_widget->private;
2334 if (pipeline->use_chain_dma)
2335 return 0;
2336
2337 ipc_size = ipc4_copier->ipc_config_size;
2338 ipc_data = ipc4_copier->ipc_config_data;
2339
2340 msg = &ipc4_copier->msg;
2341 break;
2342 }
2343 case snd_soc_dapm_pga:
2344 {
2345 struct sof_ipc4_gain *gain = swidget->private;
2346
2347 ipc_size = sizeof(gain->data);
2348 ipc_data = &gain->data;
2349
2350 msg = &gain->msg;
2351 break;
2352 }
2353 case snd_soc_dapm_mixer:
2354 {
2355 struct sof_ipc4_mixer *mixer = swidget->private;
2356
2357 ipc_size = sizeof(mixer->base_config);
2358 ipc_data = &mixer->base_config;
2359
2360 msg = &mixer->msg;
2361 break;
2362 }
2363 case snd_soc_dapm_src:
2364 {
2365 struct sof_ipc4_src *src = swidget->private;
2366
2367 ipc_size = sizeof(src->data);
2368 ipc_data = &src->data;
2369
2370 msg = &src->msg;
2371 break;
2372 }
2373 case snd_soc_dapm_effect:
2374 {
2375 struct sof_ipc4_process *process = swidget->private;
2376
2377 if (!process->ipc_config_size) {
2378 dev_err(sdev->dev, "module %s has no config data!\n",
2379 swidget->widget->name);
2380 return -EINVAL;
2381 }
2382
2383 ipc_size = process->ipc_config_size;
2384 ipc_data = process->ipc_config_data;
2385
2386 msg = &process->msg;
2387 break;
2388 }
2389 default:
2390 dev_err(sdev->dev, "widget type %d not supported", swidget->id);
2391 return -EINVAL;
2392 }
2393
2394 if (swidget->id != snd_soc_dapm_scheduler) {
2395 int module_id = msg->primary & SOF_IPC4_MOD_ID_MASK;
2396
2397 ret = sof_ipc4_widget_assign_instance_id(sdev, swidget);
2398 if (ret < 0) {
2399 dev_err(sdev->dev, "failed to assign instance id for %s\n",
2400 swidget->widget->name);
2401 return ret;
2402 }
2403
2404 msg->primary &= ~SOF_IPC4_MOD_INSTANCE_MASK;
2405 msg->primary |= SOF_IPC4_MOD_INSTANCE(swidget->instance_id);
2406
2407 msg->extension &= ~SOF_IPC4_MOD_EXT_PARAM_SIZE_MASK;
2408 msg->extension |= ipc_size >> 2;
2409
2410 msg->extension &= ~SOF_IPC4_MOD_EXT_PPL_ID_MASK;
2411 msg->extension |= SOF_IPC4_MOD_EXT_PPL_ID(pipe_widget->instance_id);
2412
2413 dev_dbg(sdev->dev, "Create widget %s (pipe %d) - ID %d, instance %d, core %d\n",
2414 swidget->widget->name, swidget->pipeline_id, module_id,
2415 swidget->instance_id, swidget->core);
2416 } else {
2417 dev_dbg(sdev->dev, "Create pipeline %s (pipe %d) - instance %d, core %d\n",
2418 swidget->widget->name, swidget->pipeline_id,
2419 swidget->instance_id, swidget->core);
2420 }
2421
2422 msg->data_size = ipc_size;
2423 msg->data_ptr = ipc_data;
2424
2425 ret = sof_ipc_tx_message_no_reply(sdev->ipc, msg, ipc_size);
2426 if (ret < 0) {
2427 dev_err(sdev->dev, "failed to create module %s\n", swidget->widget->name);
2428
2429 if (swidget->id != snd_soc_dapm_scheduler) {
2430 struct sof_ipc4_fw_module *fw_module = swidget->module_info;
2431
2432 ida_free(&fw_module->m_ida, swidget->instance_id);
2433 } else {
2434 ida_free(&pipeline_ida, swidget->instance_id);
2435 }
2436 }
2437
2438 return ret;
2439 }
2440
sof_ipc4_widget_free(struct snd_sof_dev * sdev,struct snd_sof_widget * swidget)2441 static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
2442 {
2443 struct sof_ipc4_fw_module *fw_module = swidget->module_info;
2444 struct sof_ipc4_fw_data *ipc4_data = sdev->private;
2445 int ret = 0;
2446
2447 mutex_lock(&ipc4_data->pipeline_state_mutex);
2448
2449 /* freeing a pipeline frees all the widgets associated with it */
2450 if (swidget->id == snd_soc_dapm_scheduler) {
2451 struct sof_ipc4_pipeline *pipeline = swidget->private;
2452 struct sof_ipc4_msg msg = {{ 0 }};
2453 u32 header;
2454
2455 if (pipeline->use_chain_dma) {
2456 dev_warn(sdev->dev, "use_chain_dma set for scheduler %s",
2457 swidget->widget->name);
2458 mutex_unlock(&ipc4_data->pipeline_state_mutex);
2459 return 0;
2460 }
2461
2462 header = SOF_IPC4_GLB_PIPE_INSTANCE_ID(swidget->instance_id);
2463 header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_DELETE_PIPELINE);
2464 header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
2465 header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG);
2466
2467 msg.primary = header;
2468
2469 ret = sof_ipc_tx_message_no_reply(sdev->ipc, &msg, 0);
2470 if (ret < 0)
2471 dev_err(sdev->dev, "failed to free pipeline widget %s\n",
2472 swidget->widget->name);
2473
2474 pipeline->mem_usage = 0;
2475 pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED;
2476 ida_free(&pipeline_ida, swidget->instance_id);
2477 swidget->instance_id = -EINVAL;
2478 } else {
2479 struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
2480 struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
2481
2482 if (!pipeline->use_chain_dma)
2483 ida_free(&fw_module->m_ida, swidget->instance_id);
2484 }
2485
2486 mutex_unlock(&ipc4_data->pipeline_state_mutex);
2487
2488 return ret;
2489 }
2490
sof_ipc4_get_queue_id(struct snd_sof_widget * src_widget,struct snd_sof_widget * sink_widget,bool pin_type)2491 static int sof_ipc4_get_queue_id(struct snd_sof_widget *src_widget,
2492 struct snd_sof_widget *sink_widget, bool pin_type)
2493 {
2494 struct snd_sof_widget *current_swidget;
2495 struct snd_soc_component *scomp;
2496 struct ida *queue_ida;
2497 const char *buddy_name;
2498 char **pin_binding;
2499 u32 num_pins;
2500 int i;
2501
2502 if (pin_type == SOF_PIN_TYPE_OUTPUT) {
2503 current_swidget = src_widget;
2504 pin_binding = src_widget->output_pin_binding;
2505 queue_ida = &src_widget->output_queue_ida;
2506 num_pins = src_widget->num_output_pins;
2507 buddy_name = sink_widget->widget->name;
2508 } else {
2509 current_swidget = sink_widget;
2510 pin_binding = sink_widget->input_pin_binding;
2511 queue_ida = &sink_widget->input_queue_ida;
2512 num_pins = sink_widget->num_input_pins;
2513 buddy_name = src_widget->widget->name;
2514 }
2515
2516 scomp = current_swidget->scomp;
2517
2518 if (num_pins < 1) {
2519 dev_err(scomp->dev, "invalid %s num_pins: %d for queue allocation for %s\n",
2520 (pin_type == SOF_PIN_TYPE_OUTPUT ? "output" : "input"),
2521 num_pins, current_swidget->widget->name);
2522 return -EINVAL;
2523 }
2524
2525 /* If there is only one input/output pin, queue id must be 0 */
2526 if (num_pins == 1)
2527 return 0;
2528
2529 /* Allocate queue ID from pin binding array if it is defined in topology. */
2530 if (pin_binding) {
2531 for (i = 0; i < num_pins; i++) {
2532 if (!strcmp(pin_binding[i], buddy_name))
2533 return i;
2534 }
2535 /*
2536 * Fail if no queue ID found from pin binding array, so that we don't
2537 * mixed use pin binding array and ida for queue ID allocation.
2538 */
2539 dev_err(scomp->dev, "no %s queue id found from pin binding array for %s\n",
2540 (pin_type == SOF_PIN_TYPE_OUTPUT ? "output" : "input"),
2541 current_swidget->widget->name);
2542 return -EINVAL;
2543 }
2544
2545 /* If no pin binding array specified in topology, use ida to allocate one */
2546 return ida_alloc_max(queue_ida, num_pins, GFP_KERNEL);
2547 }
2548
sof_ipc4_put_queue_id(struct snd_sof_widget * swidget,int queue_id,bool pin_type)2549 static void sof_ipc4_put_queue_id(struct snd_sof_widget *swidget, int queue_id,
2550 bool pin_type)
2551 {
2552 struct ida *queue_ida;
2553 char **pin_binding;
2554 int num_pins;
2555
2556 if (pin_type == SOF_PIN_TYPE_OUTPUT) {
2557 pin_binding = swidget->output_pin_binding;
2558 queue_ida = &swidget->output_queue_ida;
2559 num_pins = swidget->num_output_pins;
2560 } else {
2561 pin_binding = swidget->input_pin_binding;
2562 queue_ida = &swidget->input_queue_ida;
2563 num_pins = swidget->num_input_pins;
2564 }
2565
2566 /* Nothing to free if queue ID is not allocated with ida. */
2567 if (num_pins == 1 || pin_binding)
2568 return;
2569
2570 ida_free(queue_ida, queue_id);
2571 }
2572
sof_ipc4_set_copier_sink_format(struct snd_sof_dev * sdev,struct snd_sof_widget * src_widget,struct snd_sof_widget * sink_widget,int sink_id)2573 static int sof_ipc4_set_copier_sink_format(struct snd_sof_dev *sdev,
2574 struct snd_sof_widget *src_widget,
2575 struct snd_sof_widget *sink_widget,
2576 int sink_id)
2577 {
2578 struct sof_ipc4_copier_config_set_sink_format format;
2579 const struct sof_ipc_ops *iops = sdev->ipc->ops;
2580 struct sof_ipc4_base_module_cfg *src_config;
2581 const struct sof_ipc4_audio_format *pin_fmt;
2582 struct sof_ipc4_fw_module *fw_module;
2583 struct sof_ipc4_msg msg = {{ 0 }};
2584
2585 dev_dbg(sdev->dev, "%s set copier sink %d format\n",
2586 src_widget->widget->name, sink_id);
2587
2588 if (WIDGET_IS_DAI(src_widget->id)) {
2589 struct snd_sof_dai *dai = src_widget->private;
2590
2591 src_config = dai->private;
2592 } else {
2593 src_config = src_widget->private;
2594 }
2595
2596 fw_module = src_widget->module_info;
2597
2598 format.sink_id = sink_id;
2599 memcpy(&format.source_fmt, &src_config->audio_fmt, sizeof(format.source_fmt));
2600
2601 pin_fmt = sof_ipc4_get_input_pin_audio_fmt(sink_widget, sink_id);
2602 if (!pin_fmt) {
2603 dev_err(sdev->dev, "Unable to get pin %d format for %s",
2604 sink_id, sink_widget->widget->name);
2605 return -EINVAL;
2606 }
2607
2608 memcpy(&format.sink_fmt, pin_fmt, sizeof(format.sink_fmt));
2609
2610 msg.data_size = sizeof(format);
2611 msg.data_ptr = &format;
2612
2613 msg.primary = fw_module->man4_module_entry.id;
2614 msg.primary |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id);
2615 msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
2616 msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
2617
2618 msg.extension =
2619 SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_COPIER_MODULE_CFG_PARAM_SET_SINK_FORMAT);
2620
2621 return iops->set_get_data(sdev, &msg, msg.data_size, true);
2622 }
2623
sof_ipc4_route_setup(struct snd_sof_dev * sdev,struct snd_sof_route * sroute)2624 static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route *sroute)
2625 {
2626 struct snd_sof_widget *src_widget = sroute->src_widget;
2627 struct snd_sof_widget *sink_widget = sroute->sink_widget;
2628 struct snd_sof_widget *src_pipe_widget = src_widget->spipe->pipe_widget;
2629 struct snd_sof_widget *sink_pipe_widget = sink_widget->spipe->pipe_widget;
2630 struct sof_ipc4_fw_module *src_fw_module = src_widget->module_info;
2631 struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info;
2632 struct sof_ipc4_pipeline *src_pipeline = src_pipe_widget->private;
2633 struct sof_ipc4_pipeline *sink_pipeline = sink_pipe_widget->private;
2634 struct sof_ipc4_msg msg = {{ 0 }};
2635 u32 header, extension;
2636 int ret;
2637
2638 /* no route set up if chain DMA is used */
2639 if (src_pipeline->use_chain_dma || sink_pipeline->use_chain_dma) {
2640 if (!src_pipeline->use_chain_dma || !sink_pipeline->use_chain_dma) {
2641 dev_err(sdev->dev,
2642 "use_chain_dma must be set for both src %s and sink %s pipelines\n",
2643 src_widget->widget->name, sink_widget->widget->name);
2644 return -EINVAL;
2645 }
2646 return 0;
2647 }
2648
2649 if (!src_fw_module || !sink_fw_module) {
2650 dev_err(sdev->dev,
2651 "cannot bind %s -> %s, no firmware module for: %s%s\n",
2652 src_widget->widget->name, sink_widget->widget->name,
2653 src_fw_module ? "" : " source",
2654 sink_fw_module ? "" : " sink");
2655
2656 return -ENODEV;
2657 }
2658
2659 sroute->src_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget,
2660 SOF_PIN_TYPE_OUTPUT);
2661 if (sroute->src_queue_id < 0) {
2662 dev_err(sdev->dev, "failed to get queue ID for source widget: %s\n",
2663 src_widget->widget->name);
2664 return sroute->src_queue_id;
2665 }
2666
2667 sroute->dst_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget,
2668 SOF_PIN_TYPE_INPUT);
2669 if (sroute->dst_queue_id < 0) {
2670 dev_err(sdev->dev, "failed to get queue ID for sink widget: %s\n",
2671 sink_widget->widget->name);
2672 sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id,
2673 SOF_PIN_TYPE_OUTPUT);
2674 return sroute->dst_queue_id;
2675 }
2676
2677 /* Pin 0 format is already set during copier module init */
2678 if (sroute->src_queue_id > 0 && WIDGET_IS_COPIER(src_widget->id)) {
2679 ret = sof_ipc4_set_copier_sink_format(sdev, src_widget, sink_widget,
2680 sroute->src_queue_id);
2681 if (ret < 0) {
2682 dev_err(sdev->dev, "failed to set sink format for %s source queue ID %d\n",
2683 src_widget->widget->name, sroute->src_queue_id);
2684 goto out;
2685 }
2686 }
2687
2688 dev_dbg(sdev->dev, "bind %s:%d -> %s:%d\n",
2689 src_widget->widget->name, sroute->src_queue_id,
2690 sink_widget->widget->name, sroute->dst_queue_id);
2691
2692 header = src_fw_module->man4_module_entry.id;
2693 header |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id);
2694 header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_BIND);
2695 header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
2696 header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
2697
2698 extension = sink_fw_module->man4_module_entry.id;
2699 extension |= SOF_IPC4_MOD_EXT_DST_MOD_INSTANCE(sink_widget->instance_id);
2700 extension |= SOF_IPC4_MOD_EXT_DST_MOD_QUEUE_ID(sroute->dst_queue_id);
2701 extension |= SOF_IPC4_MOD_EXT_SRC_MOD_QUEUE_ID(sroute->src_queue_id);
2702
2703 msg.primary = header;
2704 msg.extension = extension;
2705
2706 ret = sof_ipc_tx_message_no_reply(sdev->ipc, &msg, 0);
2707 if (ret < 0) {
2708 dev_err(sdev->dev, "failed to bind modules %s:%d -> %s:%d\n",
2709 src_widget->widget->name, sroute->src_queue_id,
2710 sink_widget->widget->name, sroute->dst_queue_id);
2711 goto out;
2712 }
2713
2714 return ret;
2715
2716 out:
2717 sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id, SOF_PIN_TYPE_OUTPUT);
2718 sof_ipc4_put_queue_id(sink_widget, sroute->dst_queue_id, SOF_PIN_TYPE_INPUT);
2719 return ret;
2720 }
2721
sof_ipc4_route_free(struct snd_sof_dev * sdev,struct snd_sof_route * sroute)2722 static int sof_ipc4_route_free(struct snd_sof_dev *sdev, struct snd_sof_route *sroute)
2723 {
2724 struct snd_sof_widget *src_widget = sroute->src_widget;
2725 struct snd_sof_widget *sink_widget = sroute->sink_widget;
2726 struct sof_ipc4_fw_module *src_fw_module = src_widget->module_info;
2727 struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info;
2728 struct sof_ipc4_msg msg = {{ 0 }};
2729 struct snd_sof_widget *src_pipe_widget = src_widget->spipe->pipe_widget;
2730 struct snd_sof_widget *sink_pipe_widget = sink_widget->spipe->pipe_widget;
2731 struct sof_ipc4_pipeline *src_pipeline = src_pipe_widget->private;
2732 struct sof_ipc4_pipeline *sink_pipeline = sink_pipe_widget->private;
2733 u32 header, extension;
2734 int ret = 0;
2735
2736 /* no route is set up if chain DMA is used */
2737 if (src_pipeline->use_chain_dma || sink_pipeline->use_chain_dma)
2738 return 0;
2739
2740 dev_dbg(sdev->dev, "unbind modules %s:%d -> %s:%d\n",
2741 src_widget->widget->name, sroute->src_queue_id,
2742 sink_widget->widget->name, sroute->dst_queue_id);
2743
2744 /*
2745 * routes belonging to the same pipeline will be disconnected by the FW when the pipeline
2746 * is freed. So avoid sending this IPC which will be ignored by the FW anyway.
2747 */
2748 if (src_widget->spipe->pipe_widget == sink_widget->spipe->pipe_widget)
2749 goto out;
2750
2751 header = src_fw_module->man4_module_entry.id;
2752 header |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id);
2753 header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_UNBIND);
2754 header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
2755 header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
2756
2757 extension = sink_fw_module->man4_module_entry.id;
2758 extension |= SOF_IPC4_MOD_EXT_DST_MOD_INSTANCE(sink_widget->instance_id);
2759 extension |= SOF_IPC4_MOD_EXT_DST_MOD_QUEUE_ID(sroute->dst_queue_id);
2760 extension |= SOF_IPC4_MOD_EXT_SRC_MOD_QUEUE_ID(sroute->src_queue_id);
2761
2762 msg.primary = header;
2763 msg.extension = extension;
2764
2765 ret = sof_ipc_tx_message_no_reply(sdev->ipc, &msg, 0);
2766 if (ret < 0)
2767 dev_err(sdev->dev, "failed to unbind modules %s:%d -> %s:%d\n",
2768 src_widget->widget->name, sroute->src_queue_id,
2769 sink_widget->widget->name, sroute->dst_queue_id);
2770 out:
2771 sof_ipc4_put_queue_id(sink_widget, sroute->dst_queue_id, SOF_PIN_TYPE_INPUT);
2772 sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id, SOF_PIN_TYPE_OUTPUT);
2773
2774 return ret;
2775 }
2776
sof_ipc4_dai_config(struct snd_sof_dev * sdev,struct snd_sof_widget * swidget,unsigned int flags,struct snd_sof_dai_config_data * data)2777 static int sof_ipc4_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
2778 unsigned int flags, struct snd_sof_dai_config_data *data)
2779 {
2780 struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
2781 struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
2782 struct snd_sof_dai *dai = swidget->private;
2783 struct sof_ipc4_gtw_attributes *gtw_attr;
2784 struct sof_ipc4_copier_data *copier_data;
2785 struct sof_ipc4_copier *ipc4_copier;
2786
2787 if (!dai || !dai->private) {
2788 dev_err(sdev->dev, "Invalid DAI or DAI private data for %s\n",
2789 swidget->widget->name);
2790 return -EINVAL;
2791 }
2792
2793 ipc4_copier = (struct sof_ipc4_copier *)dai->private;
2794 copier_data = &ipc4_copier->data;
2795
2796 if (!data)
2797 return 0;
2798
2799 switch (ipc4_copier->dai_type) {
2800 case SOF_DAI_INTEL_HDA:
2801 if (pipeline->use_chain_dma) {
2802 pipeline->msg.primary &= ~SOF_IPC4_GLB_CHAIN_DMA_LINK_ID_MASK;
2803 pipeline->msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_LINK_ID(data->dai_data);
2804 break;
2805 }
2806 gtw_attr = ipc4_copier->gtw_attr;
2807 gtw_attr->lp_buffer_alloc = pipeline->lp_mode;
2808 fallthrough;
2809 case SOF_DAI_INTEL_ALH:
2810 /*
2811 * Do not clear the node ID when this op is invoked with
2812 * SOF_DAI_CONFIG_FLAGS_HW_FREE. It is needed to free the group_ida during
2813 * unprepare.
2814 */
2815 if (flags & SOF_DAI_CONFIG_FLAGS_HW_PARAMS) {
2816 copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
2817 copier_data->gtw_cfg.node_id |= SOF_IPC4_NODE_INDEX(data->dai_data);
2818 }
2819 break;
2820 case SOF_DAI_INTEL_DMIC:
2821 case SOF_DAI_INTEL_SSP:
2822 /* nothing to do for SSP/DMIC */
2823 break;
2824 default:
2825 dev_err(sdev->dev, "%s: unsupported dai type %d\n", __func__,
2826 ipc4_copier->dai_type);
2827 return -EINVAL;
2828 }
2829
2830 return 0;
2831 }
2832
sof_ipc4_parse_manifest(struct snd_soc_component * scomp,int index,struct snd_soc_tplg_manifest * man)2833 static int sof_ipc4_parse_manifest(struct snd_soc_component *scomp, int index,
2834 struct snd_soc_tplg_manifest *man)
2835 {
2836 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
2837 struct sof_ipc4_fw_data *ipc4_data = sdev->private;
2838 struct sof_manifest_tlv *manifest_tlv;
2839 struct sof_manifest *manifest;
2840 u32 size = le32_to_cpu(man->priv.size);
2841 u8 *man_ptr = man->priv.data;
2842 u32 len_check;
2843 int i;
2844
2845 if (!size || size < SOF_IPC4_TPLG_ABI_SIZE) {
2846 dev_err(scomp->dev, "%s: Invalid topology ABI size: %u\n",
2847 __func__, size);
2848 return -EINVAL;
2849 }
2850
2851 manifest = (struct sof_manifest *)man_ptr;
2852
2853 dev_info(scomp->dev,
2854 "Topology: ABI %d:%d:%d Kernel ABI %u:%u:%u\n",
2855 le16_to_cpu(manifest->abi_major), le16_to_cpu(manifest->abi_minor),
2856 le16_to_cpu(manifest->abi_patch),
2857 SOF_ABI_MAJOR, SOF_ABI_MINOR, SOF_ABI_PATCH);
2858
2859 /* TODO: Add ABI compatibility check */
2860
2861 /* no more data after the ABI version */
2862 if (size <= SOF_IPC4_TPLG_ABI_SIZE)
2863 return 0;
2864
2865 manifest_tlv = manifest->items;
2866 len_check = sizeof(struct sof_manifest);
2867 for (i = 0; i < le16_to_cpu(manifest->count); i++) {
2868 len_check += sizeof(struct sof_manifest_tlv) + le32_to_cpu(manifest_tlv->size);
2869 if (len_check > size)
2870 return -EINVAL;
2871
2872 switch (le32_to_cpu(manifest_tlv->type)) {
2873 case SOF_MANIFEST_DATA_TYPE_NHLT:
2874 /* no NHLT in BIOS, so use the one from topology manifest */
2875 if (ipc4_data->nhlt)
2876 break;
2877 ipc4_data->nhlt = devm_kmemdup(sdev->dev, manifest_tlv->data,
2878 le32_to_cpu(manifest_tlv->size), GFP_KERNEL);
2879 if (!ipc4_data->nhlt)
2880 return -ENOMEM;
2881 break;
2882 default:
2883 dev_warn(scomp->dev, "Skipping unknown manifest data type %d\n",
2884 manifest_tlv->type);
2885 break;
2886 }
2887 man_ptr += sizeof(struct sof_manifest_tlv) + le32_to_cpu(manifest_tlv->size);
2888 manifest_tlv = (struct sof_manifest_tlv *)man_ptr;
2889 }
2890
2891 return 0;
2892 }
2893
sof_ipc4_dai_get_clk(struct snd_sof_dev * sdev,struct snd_sof_dai * dai,int clk_type)2894 static int sof_ipc4_dai_get_clk(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, int clk_type)
2895 {
2896 struct sof_ipc4_copier *ipc4_copier = dai->private;
2897 struct snd_soc_tplg_hw_config *hw_config;
2898 struct snd_sof_dai_link *slink;
2899 bool dai_link_found = false;
2900 bool hw_cfg_found = false;
2901 int i;
2902
2903 if (!ipc4_copier)
2904 return 0;
2905
2906 list_for_each_entry(slink, &sdev->dai_link_list, list) {
2907 if (!strcmp(slink->link->name, dai->name)) {
2908 dai_link_found = true;
2909 break;
2910 }
2911 }
2912
2913 if (!dai_link_found) {
2914 dev_err(sdev->dev, "no DAI link found for DAI %s\n", dai->name);
2915 return -EINVAL;
2916 }
2917
2918 for (i = 0; i < slink->num_hw_configs; i++) {
2919 hw_config = &slink->hw_configs[i];
2920 if (dai->current_config == le32_to_cpu(hw_config->id)) {
2921 hw_cfg_found = true;
2922 break;
2923 }
2924 }
2925
2926 if (!hw_cfg_found) {
2927 dev_err(sdev->dev, "no matching hw_config found for DAI %s\n", dai->name);
2928 return -EINVAL;
2929 }
2930
2931 switch (ipc4_copier->dai_type) {
2932 case SOF_DAI_INTEL_SSP:
2933 switch (clk_type) {
2934 case SOF_DAI_CLK_INTEL_SSP_MCLK:
2935 return le32_to_cpu(hw_config->mclk_rate);
2936 case SOF_DAI_CLK_INTEL_SSP_BCLK:
2937 return le32_to_cpu(hw_config->bclk_rate);
2938 default:
2939 dev_err(sdev->dev, "Invalid clk type for SSP %d\n", clk_type);
2940 break;
2941 }
2942 break;
2943 default:
2944 dev_err(sdev->dev, "DAI type %d not supported yet!\n", ipc4_copier->dai_type);
2945 break;
2946 }
2947
2948 return -EINVAL;
2949 }
2950
sof_ipc4_tear_down_all_pipelines(struct snd_sof_dev * sdev,bool verify)2951 static int sof_ipc4_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verify)
2952 {
2953 struct snd_sof_pcm *spcm;
2954 int dir, ret;
2955
2956 /*
2957 * This function is called during system suspend, we need to make sure
2958 * that all streams have been freed up.
2959 * Freeing might have been skipped when xrun happened just at the start
2960 * of the suspend and it sent a SNDRV_PCM_TRIGGER_STOP to the active
2961 * stream. This will call sof_pcm_stream_free() with
2962 * free_widget_list = false which will leave the kernel and firmware out
2963 * of sync during suspend/resume.
2964 *
2965 * This will also make sure that paused streams handled correctly.
2966 */
2967 list_for_each_entry(spcm, &sdev->pcm_list, list) {
2968 for_each_pcm_streams(dir) {
2969 struct snd_pcm_substream *substream = spcm->stream[dir].substream;
2970
2971 if (!substream || !substream->runtime || spcm->stream[dir].suspend_ignored)
2972 continue;
2973
2974 if (spcm->stream[dir].list) {
2975 ret = sof_pcm_stream_free(sdev, substream, spcm, dir, true);
2976 if (ret < 0)
2977 return ret;
2978 }
2979 }
2980 }
2981 return 0;
2982 }
2983
sof_ipc4_link_setup(struct snd_sof_dev * sdev,struct snd_soc_dai_link * link)2984 static int sof_ipc4_link_setup(struct snd_sof_dev *sdev, struct snd_soc_dai_link *link)
2985 {
2986 if (link->no_pcm)
2987 return 0;
2988
2989 /*
2990 * set default trigger order for all links. Exceptions to
2991 * the rule will be handled in sof_pcm_dai_link_fixup()
2992 * For playback, the sequence is the following: start BE,
2993 * start FE, stop FE, stop BE; for Capture the sequence is
2994 * inverted start FE, start BE, stop BE, stop FE
2995 */
2996 link->trigger[SNDRV_PCM_STREAM_PLAYBACK] = SND_SOC_DPCM_TRIGGER_POST;
2997 link->trigger[SNDRV_PCM_STREAM_CAPTURE] = SND_SOC_DPCM_TRIGGER_PRE;
2998
2999 return 0;
3000 }
3001
3002 static enum sof_tokens common_copier_token_list[] = {
3003 SOF_COMP_TOKENS,
3004 SOF_AUDIO_FMT_NUM_TOKENS,
3005 SOF_IN_AUDIO_FORMAT_TOKENS,
3006 SOF_OUT_AUDIO_FORMAT_TOKENS,
3007 SOF_COPIER_DEEP_BUFFER_TOKENS,
3008 SOF_COPIER_TOKENS,
3009 SOF_COMP_EXT_TOKENS,
3010 };
3011
3012 static enum sof_tokens pipeline_token_list[] = {
3013 SOF_SCHED_TOKENS,
3014 SOF_PIPELINE_TOKENS,
3015 };
3016
3017 static enum sof_tokens dai_token_list[] = {
3018 SOF_COMP_TOKENS,
3019 SOF_AUDIO_FMT_NUM_TOKENS,
3020 SOF_IN_AUDIO_FORMAT_TOKENS,
3021 SOF_OUT_AUDIO_FORMAT_TOKENS,
3022 SOF_COPIER_TOKENS,
3023 SOF_DAI_TOKENS,
3024 SOF_COMP_EXT_TOKENS,
3025 };
3026
3027 static enum sof_tokens pga_token_list[] = {
3028 SOF_COMP_TOKENS,
3029 SOF_GAIN_TOKENS,
3030 SOF_AUDIO_FMT_NUM_TOKENS,
3031 SOF_IN_AUDIO_FORMAT_TOKENS,
3032 SOF_OUT_AUDIO_FORMAT_TOKENS,
3033 SOF_COMP_EXT_TOKENS,
3034 };
3035
3036 static enum sof_tokens mixer_token_list[] = {
3037 SOF_COMP_TOKENS,
3038 SOF_AUDIO_FMT_NUM_TOKENS,
3039 SOF_IN_AUDIO_FORMAT_TOKENS,
3040 SOF_OUT_AUDIO_FORMAT_TOKENS,
3041 SOF_COMP_EXT_TOKENS,
3042 };
3043
3044 static enum sof_tokens src_token_list[] = {
3045 SOF_COMP_TOKENS,
3046 SOF_SRC_TOKENS,
3047 SOF_AUDIO_FMT_NUM_TOKENS,
3048 SOF_IN_AUDIO_FORMAT_TOKENS,
3049 SOF_OUT_AUDIO_FORMAT_TOKENS,
3050 SOF_COMP_EXT_TOKENS,
3051 };
3052
3053 static enum sof_tokens process_token_list[] = {
3054 SOF_COMP_TOKENS,
3055 SOF_AUDIO_FMT_NUM_TOKENS,
3056 SOF_IN_AUDIO_FORMAT_TOKENS,
3057 SOF_OUT_AUDIO_FORMAT_TOKENS,
3058 SOF_COMP_EXT_TOKENS,
3059 };
3060
3061 static const struct sof_ipc_tplg_widget_ops tplg_ipc4_widget_ops[SND_SOC_DAPM_TYPE_COUNT] = {
3062 [snd_soc_dapm_aif_in] = {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm,
3063 common_copier_token_list, ARRAY_SIZE(common_copier_token_list),
3064 NULL, sof_ipc4_prepare_copier_module,
3065 sof_ipc4_unprepare_copier_module},
3066 [snd_soc_dapm_aif_out] = {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm,
3067 common_copier_token_list, ARRAY_SIZE(common_copier_token_list),
3068 NULL, sof_ipc4_prepare_copier_module,
3069 sof_ipc4_unprepare_copier_module},
3070 [snd_soc_dapm_dai_in] = {sof_ipc4_widget_setup_comp_dai, sof_ipc4_widget_free_comp_dai,
3071 dai_token_list, ARRAY_SIZE(dai_token_list), NULL,
3072 sof_ipc4_prepare_copier_module,
3073 sof_ipc4_unprepare_copier_module},
3074 [snd_soc_dapm_dai_out] = {sof_ipc4_widget_setup_comp_dai, sof_ipc4_widget_free_comp_dai,
3075 dai_token_list, ARRAY_SIZE(dai_token_list), NULL,
3076 sof_ipc4_prepare_copier_module,
3077 sof_ipc4_unprepare_copier_module},
3078 [snd_soc_dapm_buffer] = {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm,
3079 common_copier_token_list, ARRAY_SIZE(common_copier_token_list),
3080 NULL, sof_ipc4_prepare_copier_module,
3081 sof_ipc4_unprepare_copier_module},
3082 [snd_soc_dapm_scheduler] = {sof_ipc4_widget_setup_comp_pipeline,
3083 sof_ipc4_widget_free_comp_pipeline,
3084 pipeline_token_list, ARRAY_SIZE(pipeline_token_list), NULL,
3085 NULL, NULL},
3086 [snd_soc_dapm_pga] = {sof_ipc4_widget_setup_comp_pga, sof_ipc4_widget_free_comp_pga,
3087 pga_token_list, ARRAY_SIZE(pga_token_list), NULL,
3088 sof_ipc4_prepare_gain_module,
3089 NULL},
3090 [snd_soc_dapm_mixer] = {sof_ipc4_widget_setup_comp_mixer, sof_ipc4_widget_free_comp_mixer,
3091 mixer_token_list, ARRAY_SIZE(mixer_token_list),
3092 NULL, sof_ipc4_prepare_mixer_module,
3093 NULL},
3094 [snd_soc_dapm_src] = {sof_ipc4_widget_setup_comp_src, sof_ipc4_widget_free_comp_src,
3095 src_token_list, ARRAY_SIZE(src_token_list),
3096 NULL, sof_ipc4_prepare_src_module,
3097 NULL},
3098 [snd_soc_dapm_effect] = {sof_ipc4_widget_setup_comp_process,
3099 sof_ipc4_widget_free_comp_process,
3100 process_token_list, ARRAY_SIZE(process_token_list),
3101 NULL, sof_ipc4_prepare_process_module,
3102 NULL},
3103 };
3104
3105 const struct sof_ipc_tplg_ops ipc4_tplg_ops = {
3106 .widget = tplg_ipc4_widget_ops,
3107 .token_list = ipc4_token_list,
3108 .control_setup = sof_ipc4_control_setup,
3109 .control = &tplg_ipc4_control_ops,
3110 .widget_setup = sof_ipc4_widget_setup,
3111 .widget_free = sof_ipc4_widget_free,
3112 .route_setup = sof_ipc4_route_setup,
3113 .route_free = sof_ipc4_route_free,
3114 .dai_config = sof_ipc4_dai_config,
3115 .parse_manifest = sof_ipc4_parse_manifest,
3116 .dai_get_clk = sof_ipc4_dai_get_clk,
3117 .tear_down_all_pipelines = sof_ipc4_tear_down_all_pipelines,
3118 .link_setup = sof_ipc4_link_setup,
3119 };
3120