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