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