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