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