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