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