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