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