xref: /openbmc/linux/sound/soc/sof/ipc4-topology.c (revision ed354c69dd370ebac8c438d3570aade296afce05)
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. All rights reserved.
7 //
8 //
9 #include <linux/bitfield.h>
10 #include <uapi/sound/sof/tokens.h>
11 #include <sound/pcm_params.h>
12 #include <sound/sof/ext_manifest4.h>
13 #include <sound/intel-nhlt.h>
14 #include "sof-priv.h"
15 #include "sof-audio.h"
16 #include "ipc4-priv.h"
17 #include "ipc4-topology.h"
18 #include "ops.h"
19 
20 #define SOF_IPC4_GAIN_PARAM_ID  0
21 #define SOF_IPC4_TPLG_ABI_SIZE 6
22 
23 static DEFINE_IDA(alh_group_ida);
24 static DEFINE_IDA(pipeline_ida);
25 
26 static const struct sof_topology_token ipc4_sched_tokens[] = {
27 	{SOF_TKN_SCHED_LP_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
28 		offsetof(struct sof_ipc4_pipeline, lp_mode)},
29 	{SOF_TKN_SCHED_CORE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
30 		offsetof(struct sof_ipc4_pipeline, core_id)},
31 };
32 
33 static const struct sof_topology_token pipeline_tokens[] = {
34 	{SOF_TKN_SCHED_DYNAMIC_PIPELINE, SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16,
35 		offsetof(struct snd_sof_widget, dynamic_pipeline_widget)},
36 };
37 
38 static const struct sof_topology_token ipc4_comp_tokens[] = {
39 	{SOF_TKN_COMP_CPC, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
40 		offsetof(struct sof_ipc4_base_module_cfg, cpc)},
41 	{SOF_TKN_COMP_IS_PAGES, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
42 		offsetof(struct sof_ipc4_base_module_cfg, is_pages)},
43 };
44 
45 static const struct sof_topology_token ipc4_in_audio_format_tokens[] = {
46 	{SOF_TKN_CAVS_AUDIO_FORMAT_IN_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
47 		offsetof(struct sof_ipc4_pin_format, audio_fmt.sampling_frequency)},
48 	{SOF_TKN_CAVS_AUDIO_FORMAT_IN_BIT_DEPTH, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
49 		offsetof(struct sof_ipc4_pin_format, audio_fmt.bit_depth)},
50 	{SOF_TKN_CAVS_AUDIO_FORMAT_IN_CH_MAP, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
51 		offsetof(struct sof_ipc4_pin_format, audio_fmt.ch_map)},
52 	{SOF_TKN_CAVS_AUDIO_FORMAT_IN_CH_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
53 		offsetof(struct sof_ipc4_pin_format, audio_fmt.ch_cfg)},
54 	{SOF_TKN_CAVS_AUDIO_FORMAT_IN_INTERLEAVING_STYLE, SND_SOC_TPLG_TUPLE_TYPE_WORD,
55 		get_token_u32, offsetof(struct sof_ipc4_pin_format,
56 		audio_fmt.interleaving_style)},
57 	{SOF_TKN_CAVS_AUDIO_FORMAT_IN_FMT_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
58 		offsetof(struct sof_ipc4_pin_format, audio_fmt.fmt_cfg)},
59 	{SOF_TKN_CAVS_AUDIO_FORMAT_PIN_INDEX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
60 		offsetof(struct sof_ipc4_pin_format, pin_index)},
61 	{SOF_TKN_CAVS_AUDIO_FORMAT_IBS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
62 		offsetof(struct sof_ipc4_pin_format, buffer_size)},
63 };
64 
65 static const struct sof_topology_token ipc4_out_audio_format_tokens[] = {
66 	{SOF_TKN_CAVS_AUDIO_FORMAT_OUT_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
67 		offsetof(struct sof_ipc4_pin_format, audio_fmt.sampling_frequency)},
68 	{SOF_TKN_CAVS_AUDIO_FORMAT_OUT_BIT_DEPTH, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
69 		offsetof(struct sof_ipc4_pin_format, audio_fmt.bit_depth)},
70 	{SOF_TKN_CAVS_AUDIO_FORMAT_OUT_CH_MAP, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
71 		offsetof(struct sof_ipc4_pin_format, audio_fmt.ch_map)},
72 	{SOF_TKN_CAVS_AUDIO_FORMAT_OUT_CH_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
73 		offsetof(struct sof_ipc4_pin_format, audio_fmt.ch_cfg)},
74 	{SOF_TKN_CAVS_AUDIO_FORMAT_OUT_INTERLEAVING_STYLE, SND_SOC_TPLG_TUPLE_TYPE_WORD,
75 		get_token_u32, offsetof(struct sof_ipc4_pin_format,
76 		audio_fmt.interleaving_style)},
77 	{SOF_TKN_CAVS_AUDIO_FORMAT_OUT_FMT_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
78 		offsetof(struct sof_ipc4_pin_format, audio_fmt.fmt_cfg)},
79 	{SOF_TKN_CAVS_AUDIO_FORMAT_PIN_INDEX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
80 		offsetof(struct sof_ipc4_pin_format, pin_index)},
81 	{SOF_TKN_CAVS_AUDIO_FORMAT_OBS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
82 		offsetof(struct sof_ipc4_pin_format, buffer_size)},
83 };
84 
85 static const struct sof_topology_token ipc4_copier_deep_buffer_tokens[] = {
86 	{SOF_TKN_INTEL_COPIER_DEEP_BUFFER_DMA_MS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 0},
87 };
88 
89 static const struct sof_topology_token ipc4_copier_tokens[] = {
90 	{SOF_TKN_INTEL_COPIER_NODE_TYPE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 0},
91 };
92 
93 static const struct sof_topology_token ipc4_audio_fmt_num_tokens[] = {
94 	{SOF_TKN_COMP_NUM_INPUT_AUDIO_FORMATS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
95 		offsetof(struct sof_ipc4_available_audio_format, num_input_formats)},
96 	{SOF_TKN_COMP_NUM_OUTPUT_AUDIO_FORMATS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
97 		offsetof(struct sof_ipc4_available_audio_format, num_output_formats)},
98 };
99 
100 static const struct sof_topology_token dai_tokens[] = {
101 	{SOF_TKN_DAI_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_dai_type,
102 		offsetof(struct sof_ipc4_copier, dai_type)},
103 	{SOF_TKN_DAI_INDEX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
104 		offsetof(struct sof_ipc4_copier, dai_index)},
105 };
106 
107 /* Component extended tokens */
108 static const struct sof_topology_token comp_ext_tokens[] = {
109 	{SOF_TKN_COMP_UUID, SND_SOC_TPLG_TUPLE_TYPE_UUID, get_token_uuid,
110 		offsetof(struct snd_sof_widget, uuid)},
111 	{SOF_TKN_COMP_CORE_ID, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
112 		offsetof(struct snd_sof_widget, core)},
113 };
114 
115 static const struct sof_topology_token gain_tokens[] = {
116 	{SOF_TKN_GAIN_RAMP_TYPE, SND_SOC_TPLG_TUPLE_TYPE_WORD,
117 		get_token_u32, offsetof(struct sof_ipc4_gain_data, curve_type)},
118 	{SOF_TKN_GAIN_RAMP_DURATION,
119 		SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
120 		offsetof(struct sof_ipc4_gain_data, curve_duration_l)},
121 	{SOF_TKN_GAIN_VAL, SND_SOC_TPLG_TUPLE_TYPE_WORD,
122 		get_token_u32, offsetof(struct sof_ipc4_gain_data, init_val)},
123 };
124 
125 /* SRC */
126 static const struct sof_topology_token src_tokens[] = {
127 	{SOF_TKN_SRC_RATE_OUT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
128 		offsetof(struct sof_ipc4_src, sink_rate)},
129 };
130 
131 static const struct sof_token_info ipc4_token_list[SOF_TOKEN_COUNT] = {
132 	[SOF_DAI_TOKENS] = {"DAI tokens", dai_tokens, ARRAY_SIZE(dai_tokens)},
133 	[SOF_PIPELINE_TOKENS] = {"Pipeline tokens", pipeline_tokens, ARRAY_SIZE(pipeline_tokens)},
134 	[SOF_SCHED_TOKENS] = {"Scheduler tokens", ipc4_sched_tokens,
135 		ARRAY_SIZE(ipc4_sched_tokens)},
136 	[SOF_COMP_EXT_TOKENS] = {"Comp extended tokens", comp_ext_tokens,
137 		ARRAY_SIZE(comp_ext_tokens)},
138 	[SOF_COMP_TOKENS] = {"IPC4 Component tokens",
139 		ipc4_comp_tokens, ARRAY_SIZE(ipc4_comp_tokens)},
140 	[SOF_IN_AUDIO_FORMAT_TOKENS] = {"IPC4 Input Audio format tokens",
141 		ipc4_in_audio_format_tokens, ARRAY_SIZE(ipc4_in_audio_format_tokens)},
142 	[SOF_OUT_AUDIO_FORMAT_TOKENS] = {"IPC4 Output Audio format tokens",
143 		ipc4_out_audio_format_tokens, ARRAY_SIZE(ipc4_out_audio_format_tokens)},
144 	[SOF_COPIER_DEEP_BUFFER_TOKENS] = {"IPC4 Copier deep buffer tokens",
145 		ipc4_copier_deep_buffer_tokens, ARRAY_SIZE(ipc4_copier_deep_buffer_tokens)},
146 	[SOF_COPIER_TOKENS] = {"IPC4 Copier tokens", ipc4_copier_tokens,
147 		ARRAY_SIZE(ipc4_copier_tokens)},
148 	[SOF_AUDIO_FMT_NUM_TOKENS] = {"IPC4 Audio format number tokens",
149 		ipc4_audio_fmt_num_tokens, ARRAY_SIZE(ipc4_audio_fmt_num_tokens)},
150 	[SOF_GAIN_TOKENS] = {"Gain tokens", gain_tokens, ARRAY_SIZE(gain_tokens)},
151 	[SOF_SRC_TOKENS] = {"SRC tokens", src_tokens, ARRAY_SIZE(src_tokens)},
152 };
153 
154 static void sof_ipc4_dbg_audio_format(struct device *dev, struct sof_ipc4_pin_format *pin_fmt,
155 				      int num_formats)
156 {
157 	int i;
158 
159 	for (i = 0; i < num_formats; i++) {
160 		struct sof_ipc4_audio_format *fmt = &pin_fmt[i].audio_fmt;
161 		dev_dbg(dev,
162 			"Pin index #%d: %uHz, %ubit (ch_map %#x ch_cfg %u interleaving_style %u fmt_cfg %#x) buffer size %d\n",
163 			pin_fmt[i].pin_index, fmt->sampling_frequency, fmt->bit_depth, fmt->ch_map,
164 			fmt->ch_cfg, fmt->interleaving_style, fmt->fmt_cfg,
165 			pin_fmt[i].buffer_size);
166 	}
167 }
168 
169 static const struct sof_ipc4_audio_format *
170 sof_ipc4_get_input_pin_audio_fmt(struct snd_sof_widget *swidget, int pin_index)
171 {
172 	struct sof_ipc4_base_module_cfg_ext *base_cfg_ext;
173 	struct sof_ipc4_process *process;
174 	int i;
175 
176 	if (swidget->id != snd_soc_dapm_effect) {
177 		struct sof_ipc4_base_module_cfg *base = swidget->private;
178 
179 		/* For non-process modules, base module config format is used for all input pins */
180 		return &base->audio_fmt;
181 	}
182 
183 	process = swidget->private;
184 	base_cfg_ext = process->base_config_ext;
185 
186 	/*
187 	 * If there are multiple input formats available for a pin, the first available format
188 	 * is chosen.
189 	 */
190 	for (i = 0; i < base_cfg_ext->num_input_pin_fmts; i++) {
191 		struct sof_ipc4_pin_format *pin_format = &base_cfg_ext->pin_formats[i];
192 
193 		if (pin_format->pin_index == pin_index)
194 			return &pin_format->audio_fmt;
195 	}
196 
197 	return NULL;
198 }
199 
200 /**
201  * sof_ipc4_get_audio_fmt - get available audio formats from swidget->tuples
202  * @scomp: pointer to pointer to SOC component
203  * @swidget: pointer to struct snd_sof_widget containing tuples
204  * @available_fmt: pointer to struct sof_ipc4_available_audio_format being filling in
205  * @module_base_cfg: Pointer to the base_config in the module init IPC payload
206  *
207  * Return: 0 if successful
208  */
209 static int sof_ipc4_get_audio_fmt(struct snd_soc_component *scomp,
210 				  struct snd_sof_widget *swidget,
211 				  struct sof_ipc4_available_audio_format *available_fmt,
212 				  struct sof_ipc4_base_module_cfg *module_base_cfg)
213 {
214 	struct sof_ipc4_pin_format *in_format = NULL;
215 	struct sof_ipc4_pin_format *out_format;
216 	int ret;
217 
218 	ret = sof_update_ipc_object(scomp, available_fmt,
219 				    SOF_AUDIO_FMT_NUM_TOKENS, swidget->tuples,
220 				    swidget->num_tuples, sizeof(available_fmt), 1);
221 	if (ret) {
222 		dev_err(scomp->dev, "Failed to parse audio format token count\n");
223 		return ret;
224 	}
225 
226 	if (!available_fmt->num_input_formats && !available_fmt->num_output_formats) {
227 		dev_err(scomp->dev, "No input/output pin formats set in topology\n");
228 		return -EINVAL;
229 	}
230 
231 	dev_dbg(scomp->dev,
232 		"Number of input audio formats: %d. Number of output audio formats: %d\n",
233 		available_fmt->num_input_formats, available_fmt->num_output_formats);
234 
235 	/* set cpc and is_pages in the module's base_config */
236 	ret = sof_update_ipc_object(scomp, module_base_cfg, SOF_COMP_TOKENS, swidget->tuples,
237 				    swidget->num_tuples, sizeof(*module_base_cfg), 1);
238 	if (ret) {
239 		dev_err(scomp->dev, "parse comp tokens for %s failed, error: %d\n",
240 			swidget->widget->name, ret);
241 		return ret;
242 	}
243 
244 	dev_dbg(scomp->dev, "widget %s cpc: %d is_pages: %d\n",
245 		swidget->widget->name, module_base_cfg->cpc, module_base_cfg->is_pages);
246 
247 	if (available_fmt->num_input_formats) {
248 		in_format = kcalloc(available_fmt->num_input_formats,
249 				    sizeof(*in_format), GFP_KERNEL);
250 		if (!in_format)
251 			return -ENOMEM;
252 		available_fmt->input_pin_fmts = in_format;
253 
254 		ret = sof_update_ipc_object(scomp, in_format,
255 					    SOF_IN_AUDIO_FORMAT_TOKENS, swidget->tuples,
256 					    swidget->num_tuples, sizeof(*in_format),
257 					    available_fmt->num_input_formats);
258 		if (ret) {
259 			dev_err(scomp->dev, "parse input audio fmt tokens failed %d\n", ret);
260 			goto err_in;
261 		}
262 
263 		dev_dbg(scomp->dev, "Input audio formats for %s\n", swidget->widget->name);
264 		sof_ipc4_dbg_audio_format(scomp->dev, in_format,
265 					  available_fmt->num_input_formats);
266 	}
267 
268 	if (available_fmt->num_output_formats) {
269 		out_format = kcalloc(available_fmt->num_output_formats, sizeof(*out_format),
270 				     GFP_KERNEL);
271 		if (!out_format) {
272 			ret = -ENOMEM;
273 			goto err_in;
274 		}
275 
276 		ret = sof_update_ipc_object(scomp, out_format,
277 					    SOF_OUT_AUDIO_FORMAT_TOKENS, swidget->tuples,
278 					    swidget->num_tuples, sizeof(*out_format),
279 					    available_fmt->num_output_formats);
280 		if (ret) {
281 			dev_err(scomp->dev, "parse output audio fmt tokens failed\n");
282 			goto err_out;
283 		}
284 
285 		available_fmt->output_pin_fmts = out_format;
286 		dev_dbg(scomp->dev, "Output audio formats for %s\n", swidget->widget->name);
287 		sof_ipc4_dbg_audio_format(scomp->dev, out_format,
288 					  available_fmt->num_output_formats);
289 	}
290 
291 	return 0;
292 
293 err_out:
294 	kfree(out_format);
295 err_in:
296 	kfree(in_format);
297 	available_fmt->input_pin_fmts = NULL;
298 	return ret;
299 }
300 
301 /* release the memory allocated in sof_ipc4_get_audio_fmt */
302 static void sof_ipc4_free_audio_fmt(struct sof_ipc4_available_audio_format *available_fmt)
303 
304 {
305 	kfree(available_fmt->output_pin_fmts);
306 	available_fmt->output_pin_fmts = NULL;
307 	kfree(available_fmt->input_pin_fmts);
308 	available_fmt->input_pin_fmts = NULL;
309 }
310 
311 static void sof_ipc4_widget_free_comp_pipeline(struct snd_sof_widget *swidget)
312 {
313 	kfree(swidget->private);
314 }
315 
316 static int sof_ipc4_widget_set_module_info(struct snd_sof_widget *swidget)
317 {
318 	struct snd_soc_component *scomp = swidget->scomp;
319 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
320 
321 	swidget->module_info = sof_ipc4_find_module_by_uuid(sdev, &swidget->uuid);
322 
323 	if (swidget->module_info)
324 		return 0;
325 
326 	dev_err(sdev->dev, "failed to find module info for widget %s with UUID %pUL\n",
327 		swidget->widget->name, &swidget->uuid);
328 	return -EINVAL;
329 }
330 
331 static int sof_ipc4_widget_setup_msg(struct snd_sof_widget *swidget, struct sof_ipc4_msg *msg)
332 {
333 	struct sof_ipc4_fw_module *fw_module;
334 	uint32_t type;
335 	int ret;
336 
337 	ret = sof_ipc4_widget_set_module_info(swidget);
338 	if (ret)
339 		return ret;
340 
341 	fw_module = swidget->module_info;
342 
343 	msg->primary = fw_module->man4_module_entry.id;
344 	msg->primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_INIT_INSTANCE);
345 	msg->primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
346 	msg->primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
347 
348 	msg->extension = SOF_IPC4_MOD_EXT_CORE_ID(swidget->core);
349 
350 	type = (fw_module->man4_module_entry.type & SOF_IPC4_MODULE_DP) ? 1 : 0;
351 	msg->extension |= SOF_IPC4_MOD_EXT_DOMAIN(type);
352 
353 	return 0;
354 }
355 
356 static void sof_ipc4_widget_update_kcontrol_module_id(struct snd_sof_widget *swidget)
357 {
358 	struct snd_soc_component *scomp = swidget->scomp;
359 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
360 	struct sof_ipc4_fw_module *fw_module = swidget->module_info;
361 	struct snd_sof_control *scontrol;
362 
363 	/* update module ID for all kcontrols for this widget */
364 	list_for_each_entry(scontrol, &sdev->kcontrol_list, list) {
365 		if (scontrol->comp_id == swidget->comp_id) {
366 			struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
367 			struct sof_ipc4_msg *msg = &cdata->msg;
368 
369 			msg->primary |= fw_module->man4_module_entry.id;
370 		}
371 	}
372 }
373 
374 static int sof_ipc4_widget_setup_pcm(struct snd_sof_widget *swidget)
375 {
376 	struct sof_ipc4_available_audio_format *available_fmt;
377 	struct snd_soc_component *scomp = swidget->scomp;
378 	struct sof_ipc4_copier *ipc4_copier;
379 	int node_type = 0;
380 	int ret;
381 
382 	ipc4_copier = kzalloc(sizeof(*ipc4_copier), GFP_KERNEL);
383 	if (!ipc4_copier)
384 		return -ENOMEM;
385 
386 	swidget->private = ipc4_copier;
387 	available_fmt = &ipc4_copier->available_fmt;
388 
389 	dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name);
390 
391 	ret = sof_ipc4_get_audio_fmt(scomp, swidget, available_fmt,
392 				     &ipc4_copier->data.base_config);
393 	if (ret)
394 		goto free_copier;
395 
396 	/*
397 	 * This callback is used by host copier and module-to-module copier,
398 	 * and only host copier needs to set gtw_cfg.
399 	 */
400 	if (!WIDGET_IS_AIF(swidget->id))
401 		goto skip_gtw_cfg;
402 
403 	ret = sof_update_ipc_object(scomp, &node_type,
404 				    SOF_COPIER_TOKENS, swidget->tuples,
405 				    swidget->num_tuples, sizeof(node_type), 1);
406 
407 	if (ret) {
408 		dev_err(scomp->dev, "parse host copier node type token failed %d\n",
409 			ret);
410 		goto free_available_fmt;
411 	}
412 	dev_dbg(scomp->dev, "host copier '%s' node_type %u\n", swidget->widget->name, node_type);
413 
414 skip_gtw_cfg:
415 	ipc4_copier->gtw_attr = kzalloc(sizeof(*ipc4_copier->gtw_attr), GFP_KERNEL);
416 	if (!ipc4_copier->gtw_attr) {
417 		ret = -ENOMEM;
418 		goto free_available_fmt;
419 	}
420 
421 	ipc4_copier->copier_config = (uint32_t *)ipc4_copier->gtw_attr;
422 	ipc4_copier->data.gtw_cfg.config_length =
423 		sizeof(struct sof_ipc4_gtw_attributes) >> 2;
424 
425 	switch (swidget->id) {
426 	case snd_soc_dapm_aif_in:
427 	case snd_soc_dapm_aif_out:
428 		ipc4_copier->data.gtw_cfg.node_id = SOF_IPC4_NODE_TYPE(node_type);
429 		break;
430 	case snd_soc_dapm_buffer:
431 		ipc4_copier->data.gtw_cfg.node_id = SOF_IPC4_INVALID_NODE_ID;
432 		ipc4_copier->ipc_config_size = 0;
433 		break;
434 	default:
435 		dev_err(scomp->dev, "invalid widget type %d\n", swidget->id);
436 		ret = -EINVAL;
437 		goto free_gtw_attr;
438 	}
439 
440 	/* set up module info and message header */
441 	ret = sof_ipc4_widget_setup_msg(swidget, &ipc4_copier->msg);
442 	if (ret)
443 		goto free_gtw_attr;
444 
445 	return 0;
446 
447 free_gtw_attr:
448 	kfree(ipc4_copier->gtw_attr);
449 free_available_fmt:
450 	sof_ipc4_free_audio_fmt(available_fmt);
451 free_copier:
452 	kfree(ipc4_copier);
453 	swidget->private = NULL;
454 	return ret;
455 }
456 
457 static void sof_ipc4_widget_free_comp_pcm(struct snd_sof_widget *swidget)
458 {
459 	struct sof_ipc4_copier *ipc4_copier = swidget->private;
460 	struct sof_ipc4_available_audio_format *available_fmt;
461 
462 	if (!ipc4_copier)
463 		return;
464 
465 	available_fmt = &ipc4_copier->available_fmt;
466 	kfree(available_fmt->output_pin_fmts);
467 	kfree(ipc4_copier->gtw_attr);
468 	kfree(ipc4_copier);
469 	swidget->private = NULL;
470 }
471 
472 static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget)
473 {
474 	struct sof_ipc4_available_audio_format *available_fmt;
475 	struct snd_soc_component *scomp = swidget->scomp;
476 	struct snd_sof_dai *dai = swidget->private;
477 	struct sof_ipc4_copier *ipc4_copier;
478 	int node_type = 0;
479 	int ret;
480 
481 	ipc4_copier = kzalloc(sizeof(*ipc4_copier), GFP_KERNEL);
482 	if (!ipc4_copier)
483 		return -ENOMEM;
484 
485 	available_fmt = &ipc4_copier->available_fmt;
486 
487 	dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name);
488 
489 	ret = sof_ipc4_get_audio_fmt(scomp, swidget, available_fmt,
490 				     &ipc4_copier->data.base_config);
491 	if (ret)
492 		goto free_copier;
493 
494 	ret = sof_update_ipc_object(scomp, &node_type,
495 				    SOF_COPIER_TOKENS, swidget->tuples,
496 				    swidget->num_tuples, sizeof(node_type), 1);
497 	if (ret) {
498 		dev_err(scomp->dev, "parse dai node type failed %d\n", ret);
499 		goto free_available_fmt;
500 	}
501 
502 	ret = sof_update_ipc_object(scomp, ipc4_copier,
503 				    SOF_DAI_TOKENS, swidget->tuples,
504 				    swidget->num_tuples, sizeof(u32), 1);
505 	if (ret) {
506 		dev_err(scomp->dev, "parse dai copier node token failed %d\n", ret);
507 		goto free_available_fmt;
508 	}
509 
510 	dev_dbg(scomp->dev, "dai %s node_type %u dai_type %u dai_index %d\n", swidget->widget->name,
511 		node_type, ipc4_copier->dai_type, ipc4_copier->dai_index);
512 
513 	ipc4_copier->data.gtw_cfg.node_id = SOF_IPC4_NODE_TYPE(node_type);
514 
515 	switch (ipc4_copier->dai_type) {
516 	case SOF_DAI_INTEL_ALH:
517 	{
518 		struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
519 		struct sof_ipc4_alh_configuration_blob *blob;
520 		struct snd_soc_dapm_path *p;
521 		struct snd_sof_widget *w;
522 		int src_num = 0;
523 
524 		snd_soc_dapm_widget_for_each_source_path(swidget->widget, p)
525 			src_num++;
526 
527 		if (swidget->id == snd_soc_dapm_dai_in && src_num == 0) {
528 			/*
529 			 * The blob will not be used if the ALH copier is playback direction
530 			 * and doesn't connect to any source.
531 			 * It is fine to call kfree(ipc4_copier->copier_config) since
532 			 * ipc4_copier->copier_config is null.
533 			 */
534 			ret = 0;
535 			break;
536 		}
537 
538 		blob = kzalloc(sizeof(*blob), GFP_KERNEL);
539 		if (!blob) {
540 			ret = -ENOMEM;
541 			goto free_available_fmt;
542 		}
543 
544 		list_for_each_entry(w, &sdev->widget_list, list) {
545 			if (w->widget->sname &&
546 			    strcmp(w->widget->sname, swidget->widget->sname))
547 				continue;
548 
549 			blob->alh_cfg.count++;
550 		}
551 
552 		ipc4_copier->copier_config = (uint32_t *)blob;
553 		ipc4_copier->data.gtw_cfg.config_length = sizeof(*blob) >> 2;
554 		break;
555 	}
556 	case SOF_DAI_INTEL_SSP:
557 		/* set SSP DAI index as the node_id */
558 		ipc4_copier->data.gtw_cfg.node_id |=
559 			SOF_IPC4_NODE_INDEX_INTEL_SSP(ipc4_copier->dai_index);
560 		break;
561 	case SOF_DAI_INTEL_DMIC:
562 		/* set DMIC DAI index as the node_id */
563 		ipc4_copier->data.gtw_cfg.node_id |=
564 			SOF_IPC4_NODE_INDEX_INTEL_DMIC(ipc4_copier->dai_index);
565 		break;
566 	default:
567 		ipc4_copier->gtw_attr = kzalloc(sizeof(*ipc4_copier->gtw_attr), GFP_KERNEL);
568 		if (!ipc4_copier->gtw_attr) {
569 			ret = -ENOMEM;
570 			goto free_available_fmt;
571 		}
572 
573 		ipc4_copier->copier_config = (uint32_t *)ipc4_copier->gtw_attr;
574 		ipc4_copier->data.gtw_cfg.config_length =
575 			sizeof(struct sof_ipc4_gtw_attributes) >> 2;
576 		break;
577 	}
578 
579 	dai->scomp = scomp;
580 	dai->private = ipc4_copier;
581 
582 	/* set up module info and message header */
583 	ret = sof_ipc4_widget_setup_msg(swidget, &ipc4_copier->msg);
584 	if (ret)
585 		goto free_copier_config;
586 
587 	return 0;
588 
589 free_copier_config:
590 	kfree(ipc4_copier->copier_config);
591 free_available_fmt:
592 	sof_ipc4_free_audio_fmt(available_fmt);
593 free_copier:
594 	kfree(ipc4_copier);
595 	dai->private = NULL;
596 	dai->scomp = NULL;
597 	return ret;
598 }
599 
600 static void sof_ipc4_widget_free_comp_dai(struct snd_sof_widget *swidget)
601 {
602 	struct sof_ipc4_available_audio_format *available_fmt;
603 	struct snd_sof_dai *dai = swidget->private;
604 	struct sof_ipc4_copier *ipc4_copier;
605 
606 	if (!dai)
607 		return;
608 
609 	if (!dai->private) {
610 		kfree(dai);
611 		swidget->private = NULL;
612 		return;
613 	}
614 
615 	ipc4_copier = dai->private;
616 	available_fmt = &ipc4_copier->available_fmt;
617 
618 	kfree(available_fmt->output_pin_fmts);
619 	if (ipc4_copier->dai_type != SOF_DAI_INTEL_SSP &&
620 	    ipc4_copier->dai_type != SOF_DAI_INTEL_DMIC)
621 		kfree(ipc4_copier->copier_config);
622 	kfree(dai->private);
623 	kfree(dai);
624 	swidget->private = NULL;
625 }
626 
627 static int sof_ipc4_widget_setup_comp_pipeline(struct snd_sof_widget *swidget)
628 {
629 	struct snd_soc_component *scomp = swidget->scomp;
630 	struct sof_ipc4_pipeline *pipeline;
631 	int ret;
632 
633 	pipeline = kzalloc(sizeof(*pipeline), GFP_KERNEL);
634 	if (!pipeline)
635 		return -ENOMEM;
636 
637 	ret = sof_update_ipc_object(scomp, pipeline, SOF_SCHED_TOKENS, swidget->tuples,
638 				    swidget->num_tuples, sizeof(*pipeline), 1);
639 	if (ret) {
640 		dev_err(scomp->dev, "parsing scheduler tokens failed\n");
641 		goto err;
642 	}
643 
644 	swidget->core = pipeline->core_id;
645 
646 	/* parse one set of pipeline tokens */
647 	ret = sof_update_ipc_object(scomp, swidget, SOF_PIPELINE_TOKENS, swidget->tuples,
648 				    swidget->num_tuples, sizeof(*swidget), 1);
649 	if (ret) {
650 		dev_err(scomp->dev, "parsing pipeline tokens failed\n");
651 		goto err;
652 	}
653 
654 	/* TODO: Get priority from topology */
655 	pipeline->priority = 0;
656 
657 	dev_dbg(scomp->dev, "pipeline '%s': id %d, pri %d, core_id %u, lp mode %d\n",
658 		swidget->widget->name, swidget->pipeline_id,
659 		pipeline->priority, pipeline->core_id, pipeline->lp_mode);
660 
661 	swidget->private = pipeline;
662 
663 	pipeline->msg.primary = SOF_IPC4_GLB_PIPE_PRIORITY(pipeline->priority);
664 	pipeline->msg.primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_CREATE_PIPELINE);
665 	pipeline->msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
666 	pipeline->msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG);
667 
668 	pipeline->msg.extension = pipeline->lp_mode;
669 	pipeline->msg.extension |= SOF_IPC4_GLB_PIPE_EXT_CORE_ID(pipeline->core_id);
670 	pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED;
671 
672 	return 0;
673 err:
674 	kfree(pipeline);
675 	return ret;
676 }
677 
678 static int sof_ipc4_widget_setup_comp_pga(struct snd_sof_widget *swidget)
679 {
680 	struct snd_soc_component *scomp = swidget->scomp;
681 	struct sof_ipc4_gain *gain;
682 	int ret;
683 
684 	gain = kzalloc(sizeof(*gain), GFP_KERNEL);
685 	if (!gain)
686 		return -ENOMEM;
687 
688 	swidget->private = gain;
689 
690 	gain->data.channels = SOF_IPC4_GAIN_ALL_CHANNELS_MASK;
691 	gain->data.init_val = SOF_IPC4_VOL_ZERO_DB;
692 
693 	ret = sof_ipc4_get_audio_fmt(scomp, swidget, &gain->available_fmt, &gain->base_config);
694 	if (ret)
695 		goto err;
696 
697 	ret = sof_update_ipc_object(scomp, &gain->data, SOF_GAIN_TOKENS, swidget->tuples,
698 				    swidget->num_tuples, sizeof(gain->data), 1);
699 	if (ret) {
700 		dev_err(scomp->dev, "Parsing gain tokens failed\n");
701 		goto err;
702 	}
703 
704 	dev_dbg(scomp->dev,
705 		"pga widget %s: ramp type: %d, ramp duration %d, initial gain value: %#x, cpc %d\n",
706 		swidget->widget->name, gain->data.curve_type, gain->data.curve_duration_l,
707 		gain->data.init_val, gain->base_config.cpc);
708 
709 	ret = sof_ipc4_widget_setup_msg(swidget, &gain->msg);
710 	if (ret)
711 		goto err;
712 
713 	sof_ipc4_widget_update_kcontrol_module_id(swidget);
714 
715 	return 0;
716 err:
717 	sof_ipc4_free_audio_fmt(&gain->available_fmt);
718 	kfree(gain);
719 	swidget->private = NULL;
720 	return ret;
721 }
722 
723 static void sof_ipc4_widget_free_comp_pga(struct snd_sof_widget *swidget)
724 {
725 	struct sof_ipc4_gain *gain = swidget->private;
726 
727 	if (!gain)
728 		return;
729 
730 	sof_ipc4_free_audio_fmt(&gain->available_fmt);
731 	kfree(swidget->private);
732 	swidget->private = NULL;
733 }
734 
735 static int sof_ipc4_widget_setup_comp_mixer(struct snd_sof_widget *swidget)
736 {
737 	struct snd_soc_component *scomp = swidget->scomp;
738 	struct sof_ipc4_mixer *mixer;
739 	int ret;
740 
741 	dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name);
742 
743 	mixer = kzalloc(sizeof(*mixer), GFP_KERNEL);
744 	if (!mixer)
745 		return -ENOMEM;
746 
747 	swidget->private = mixer;
748 
749 	ret = sof_ipc4_get_audio_fmt(scomp, swidget, &mixer->available_fmt,
750 				     &mixer->base_config);
751 	if (ret)
752 		goto err;
753 
754 	ret = sof_ipc4_widget_setup_msg(swidget, &mixer->msg);
755 	if (ret)
756 		goto err;
757 
758 	return 0;
759 err:
760 	sof_ipc4_free_audio_fmt(&mixer->available_fmt);
761 	kfree(mixer);
762 	swidget->private = NULL;
763 	return ret;
764 }
765 
766 static int sof_ipc4_widget_setup_comp_src(struct snd_sof_widget *swidget)
767 {
768 	struct snd_soc_component *scomp = swidget->scomp;
769 	struct sof_ipc4_src *src;
770 	int ret;
771 
772 	dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name);
773 
774 	src = kzalloc(sizeof(*src), GFP_KERNEL);
775 	if (!src)
776 		return -ENOMEM;
777 
778 	swidget->private = src;
779 
780 	ret = sof_ipc4_get_audio_fmt(scomp, swidget, &src->available_fmt, &src->base_config);
781 	if (ret)
782 		goto err;
783 
784 	ret = sof_update_ipc_object(scomp, src, SOF_SRC_TOKENS, swidget->tuples,
785 				    swidget->num_tuples, sizeof(*src), 1);
786 	if (ret) {
787 		dev_err(scomp->dev, "Parsing SRC tokens failed\n");
788 		goto err;
789 	}
790 
791 	dev_dbg(scomp->dev, "SRC sink rate %d\n", src->sink_rate);
792 
793 	ret = sof_ipc4_widget_setup_msg(swidget, &src->msg);
794 	if (ret)
795 		goto err;
796 
797 	return 0;
798 err:
799 	sof_ipc4_free_audio_fmt(&src->available_fmt);
800 	kfree(src);
801 	swidget->private = NULL;
802 	return ret;
803 }
804 
805 static void sof_ipc4_widget_free_comp_src(struct snd_sof_widget *swidget)
806 {
807 	struct sof_ipc4_src *src = swidget->private;
808 
809 	if (!src)
810 		return;
811 
812 	sof_ipc4_free_audio_fmt(&src->available_fmt);
813 	kfree(swidget->private);
814 	swidget->private = NULL;
815 }
816 
817 static void sof_ipc4_widget_free_comp_mixer(struct snd_sof_widget *swidget)
818 {
819 	struct sof_ipc4_mixer *mixer = swidget->private;
820 
821 	if (!mixer)
822 		return;
823 
824 	sof_ipc4_free_audio_fmt(&mixer->available_fmt);
825 	kfree(swidget->private);
826 	swidget->private = NULL;
827 }
828 
829 /*
830  * Add the process modules support. The process modules are defined as snd_soc_dapm_effect modules.
831  */
832 static int sof_ipc4_widget_setup_comp_process(struct snd_sof_widget *swidget)
833 {
834 	struct snd_soc_component *scomp = swidget->scomp;
835 	struct sof_ipc4_fw_module *fw_module;
836 	struct sof_ipc4_process *process;
837 	void *cfg;
838 	int ret;
839 
840 	process = kzalloc(sizeof(*process), GFP_KERNEL);
841 	if (!process)
842 		return -ENOMEM;
843 
844 	swidget->private = process;
845 
846 	ret = sof_ipc4_get_audio_fmt(scomp, swidget, &process->available_fmt,
847 				     &process->base_config);
848 	if (ret)
849 		goto err;
850 
851 	ret = sof_ipc4_widget_setup_msg(swidget, &process->msg);
852 	if (ret)
853 		goto err;
854 
855 	/* parse process init module payload config type from module info */
856 	fw_module = swidget->module_info;
857 	process->init_config = FIELD_GET(SOF_IPC4_MODULE_INIT_CONFIG_MASK,
858 					 fw_module->man4_module_entry.type);
859 
860 	process->ipc_config_size = sizeof(struct sof_ipc4_base_module_cfg);
861 
862 	/* allocate memory for base config extension if needed */
863 	if (process->init_config == SOF_IPC4_MODULE_INIT_CONFIG_TYPE_BASE_CFG_WITH_EXT) {
864 		struct sof_ipc4_base_module_cfg_ext *base_cfg_ext;
865 		u32 ext_size = struct_size(base_cfg_ext, pin_formats,
866 						swidget->num_input_pins + swidget->num_output_pins);
867 
868 		base_cfg_ext = kzalloc(ext_size, GFP_KERNEL);
869 		if (!base_cfg_ext) {
870 			ret = -ENOMEM;
871 			goto free_available_fmt;
872 		}
873 
874 		base_cfg_ext->num_input_pin_fmts = swidget->num_input_pins;
875 		base_cfg_ext->num_output_pin_fmts = swidget->num_output_pins;
876 		process->base_config_ext = base_cfg_ext;
877 		process->base_config_ext_size = ext_size;
878 		process->ipc_config_size += ext_size;
879 	}
880 
881 	cfg = kzalloc(process->ipc_config_size, GFP_KERNEL);
882 	if (!cfg) {
883 		ret = -ENOMEM;
884 		goto free_base_cfg_ext;
885 	}
886 
887 	process->ipc_config_data = cfg;
888 
889 	sof_ipc4_widget_update_kcontrol_module_id(swidget);
890 
891 	return 0;
892 free_base_cfg_ext:
893 	kfree(process->base_config_ext);
894 	process->base_config_ext = NULL;
895 free_available_fmt:
896 	sof_ipc4_free_audio_fmt(&process->available_fmt);
897 err:
898 	kfree(process);
899 	swidget->private = NULL;
900 	return ret;
901 }
902 
903 static void sof_ipc4_widget_free_comp_process(struct snd_sof_widget *swidget)
904 {
905 	struct sof_ipc4_process *process = swidget->private;
906 
907 	if (!process)
908 		return;
909 
910 	kfree(process->ipc_config_data);
911 	kfree(process->base_config_ext);
912 	sof_ipc4_free_audio_fmt(&process->available_fmt);
913 	kfree(swidget->private);
914 	swidget->private = NULL;
915 }
916 
917 static void
918 sof_ipc4_update_pipeline_mem_usage(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
919 				   struct sof_ipc4_base_module_cfg *base_config)
920 {
921 	struct sof_ipc4_fw_module *fw_module = swidget->module_info;
922 	struct snd_sof_widget *pipe_widget;
923 	struct sof_ipc4_pipeline *pipeline;
924 	int task_mem, queue_mem;
925 	int ibs, bss, total;
926 
927 	ibs = base_config->ibs;
928 	bss = base_config->is_pages;
929 
930 	task_mem = SOF_IPC4_PIPELINE_OBJECT_SIZE;
931 	task_mem += SOF_IPC4_MODULE_INSTANCE_LIST_ITEM_SIZE + bss;
932 
933 	if (fw_module->man4_module_entry.type & SOF_IPC4_MODULE_LL) {
934 		task_mem += SOF_IPC4_FW_ROUNDUP(SOF_IPC4_LL_TASK_OBJECT_SIZE);
935 		task_mem += SOF_IPC4_FW_MAX_QUEUE_COUNT * SOF_IPC4_MODULE_INSTANCE_LIST_ITEM_SIZE;
936 		task_mem += SOF_IPC4_LL_TASK_LIST_ITEM_SIZE;
937 	} else {
938 		task_mem += SOF_IPC4_FW_ROUNDUP(SOF_IPC4_DP_TASK_OBJECT_SIZE);
939 		task_mem += SOF_IPC4_DP_TASK_LIST_SIZE;
940 	}
941 
942 	ibs = SOF_IPC4_FW_ROUNDUP(ibs);
943 	queue_mem = SOF_IPC4_FW_MAX_QUEUE_COUNT * (SOF_IPC4_DATA_QUEUE_OBJECT_SIZE +  ibs);
944 
945 	total = SOF_IPC4_FW_PAGE(task_mem + queue_mem);
946 
947 	pipe_widget = swidget->spipe->pipe_widget;
948 	pipeline = pipe_widget->private;
949 	pipeline->mem_usage += total;
950 }
951 
952 static int sof_ipc4_widget_assign_instance_id(struct snd_sof_dev *sdev,
953 					      struct snd_sof_widget *swidget)
954 {
955 	struct sof_ipc4_fw_module *fw_module = swidget->module_info;
956 	int max_instances = fw_module->man4_module_entry.instance_max_count;
957 
958 	swidget->instance_id = ida_alloc_max(&fw_module->m_ida, max_instances, GFP_KERNEL);
959 	if (swidget->instance_id < 0) {
960 		dev_err(sdev->dev, "failed to assign instance id for widget %s",
961 			swidget->widget->name);
962 		return swidget->instance_id;
963 	}
964 
965 	return 0;
966 }
967 
968 /* update hw_params based on the audio stream format */
969 static int sof_ipc4_update_hw_params(struct snd_sof_dev *sdev, struct snd_pcm_hw_params *params,
970 				     struct sof_ipc4_audio_format *fmt)
971 {
972 	snd_pcm_format_t snd_fmt;
973 	struct snd_interval *i;
974 	struct snd_mask *m;
975 	int valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
976 	unsigned int channels, rate;
977 
978 	switch (valid_bits) {
979 	case 16:
980 		snd_fmt = SNDRV_PCM_FORMAT_S16_LE;
981 		break;
982 	case 24:
983 		snd_fmt = SNDRV_PCM_FORMAT_S24_LE;
984 		break;
985 	case 32:
986 		snd_fmt = SNDRV_PCM_FORMAT_S32_LE;
987 		break;
988 	default:
989 		dev_err(sdev->dev, "invalid PCM valid_bits %d\n", valid_bits);
990 		return -EINVAL;
991 	}
992 
993 	m = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
994 	snd_mask_none(m);
995 	snd_mask_set_format(m, snd_fmt);
996 
997 	rate = fmt->sampling_frequency;
998 	i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
999 	i->min = rate;
1000 	i->max = rate;
1001 
1002 	channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg);
1003 	i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
1004 	i->min = channels;
1005 	i->max = channels;
1006 
1007 	return 0;
1008 }
1009 
1010 static int sof_ipc4_init_audio_fmt(struct snd_sof_dev *sdev,
1011 				   struct snd_sof_widget *swidget,
1012 				   struct sof_ipc4_base_module_cfg *base_config,
1013 				   struct snd_pcm_hw_params *params,
1014 				   struct sof_ipc4_available_audio_format *available_fmt,
1015 				   struct sof_ipc4_pin_format *pin_fmts, u32 pin_fmts_size)
1016 {
1017 	u32 valid_bits;
1018 	u32 channels;
1019 	u32 rate;
1020 	int sample_valid_bits;
1021 	int i;
1022 
1023 	if (!pin_fmts) {
1024 		dev_err(sdev->dev, "no reference formats for %s\n", swidget->widget->name);
1025 		return -EINVAL;
1026 	}
1027 
1028 	switch (params_format(params)) {
1029 	case SNDRV_PCM_FORMAT_S16_LE:
1030 		sample_valid_bits = 16;
1031 		break;
1032 	case SNDRV_PCM_FORMAT_S24_LE:
1033 		sample_valid_bits = 24;
1034 		break;
1035 	case SNDRV_PCM_FORMAT_S32_LE:
1036 		sample_valid_bits = 32;
1037 		break;
1038 	default:
1039 		dev_err(sdev->dev, "invalid pcm frame format %d\n", params_format(params));
1040 		return -EINVAL;
1041 	}
1042 
1043 	if (!pin_fmts_size) {
1044 		dev_err(sdev->dev, "no formats available for %s\n", swidget->widget->name);
1045 		return -EINVAL;
1046 	}
1047 
1048 	/*
1049 	 * Search supported audio formats with pin index 0 to match rate, channels ,and
1050 	 * sample_valid_bytes from runtime params
1051 	 */
1052 	for (i = 0; i < pin_fmts_size; i++) {
1053 		struct sof_ipc4_audio_format *fmt = &pin_fmts[i].audio_fmt;
1054 
1055 		if (pin_fmts[i].pin_index)
1056 			continue;
1057 
1058 		rate = fmt->sampling_frequency;
1059 		channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg);
1060 		valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
1061 		if (params_rate(params) == rate && params_channels(params) == channels &&
1062 		    sample_valid_bits == valid_bits) {
1063 			dev_dbg(sdev->dev, "matched audio format index for %uHz, %ubit, %u channels: %d\n",
1064 				rate, valid_bits, channels, i);
1065 			break;
1066 		}
1067 	}
1068 
1069 	if (i == pin_fmts_size) {
1070 		dev_err(sdev->dev, "%s: Unsupported audio format: %uHz, %ubit, %u channels\n",
1071 			__func__, params_rate(params), sample_valid_bits, params_channels(params));
1072 		return -EINVAL;
1073 	}
1074 
1075 	/* copy input format */
1076 	if (available_fmt->num_input_formats && i < available_fmt->num_input_formats) {
1077 		memcpy(&base_config->audio_fmt, &available_fmt->input_pin_fmts[i].audio_fmt,
1078 		       sizeof(struct sof_ipc4_audio_format));
1079 
1080 		/* set base_cfg ibs/obs */
1081 		base_config->ibs = available_fmt->input_pin_fmts[i].buffer_size;
1082 
1083 		dev_dbg(sdev->dev, "Init input audio formats for %s\n", swidget->widget->name);
1084 		sof_ipc4_dbg_audio_format(sdev->dev, &available_fmt->input_pin_fmts[i], 1);
1085 	}
1086 
1087 	if (available_fmt->num_output_formats && i < available_fmt->num_output_formats)
1088 		base_config->obs = available_fmt->output_pin_fmts[i].buffer_size;
1089 
1090 	/* Return the index of the matched format */
1091 	return i;
1092 }
1093 
1094 static void sof_ipc4_unprepare_copier_module(struct snd_sof_widget *swidget)
1095 {
1096 	struct sof_ipc4_copier *ipc4_copier = NULL;
1097 	struct snd_sof_widget *pipe_widget;
1098 	struct sof_ipc4_pipeline *pipeline;
1099 
1100 	/* reset pipeline memory usage */
1101 	pipe_widget = swidget->spipe->pipe_widget;
1102 	pipeline = pipe_widget->private;
1103 	pipeline->mem_usage = 0;
1104 
1105 	if (WIDGET_IS_AIF(swidget->id) || swidget->id == snd_soc_dapm_buffer) {
1106 		ipc4_copier = swidget->private;
1107 	} else if (WIDGET_IS_DAI(swidget->id)) {
1108 		struct snd_sof_dai *dai = swidget->private;
1109 
1110 		ipc4_copier = dai->private;
1111 		if (ipc4_copier->dai_type == SOF_DAI_INTEL_ALH) {
1112 			struct sof_ipc4_copier_data *copier_data = &ipc4_copier->data;
1113 			struct sof_ipc4_alh_configuration_blob *blob;
1114 			unsigned int group_id;
1115 
1116 			blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config;
1117 			if (blob->alh_cfg.count > 1) {
1118 				group_id = SOF_IPC4_NODE_INDEX(ipc4_copier->data.gtw_cfg.node_id) -
1119 					   ALH_MULTI_GTW_BASE;
1120 				ida_free(&alh_group_ida, group_id);
1121 			}
1122 
1123 			/* clear the node ID */
1124 			copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
1125 		}
1126 	}
1127 
1128 	if (ipc4_copier) {
1129 		kfree(ipc4_copier->ipc_config_data);
1130 		ipc4_copier->ipc_config_data = NULL;
1131 		ipc4_copier->ipc_config_size = 0;
1132 	}
1133 }
1134 
1135 #if IS_ENABLED(CONFIG_ACPI) && IS_ENABLED(CONFIG_SND_INTEL_NHLT)
1136 static int snd_sof_get_hw_config_params(struct snd_sof_dev *sdev, struct snd_sof_dai *dai,
1137 					int *sample_rate, int *channel_count, int *bit_depth)
1138 {
1139 	struct snd_soc_tplg_hw_config *hw_config;
1140 	struct snd_sof_dai_link *slink;
1141 	bool dai_link_found = false;
1142 	bool hw_cfg_found = false;
1143 	int i;
1144 
1145 	/* get current hw_config from link */
1146 	list_for_each_entry(slink, &sdev->dai_link_list, list) {
1147 		if (!strcmp(slink->link->name, dai->name)) {
1148 			dai_link_found = true;
1149 			break;
1150 		}
1151 	}
1152 
1153 	if (!dai_link_found) {
1154 		dev_err(sdev->dev, "%s: no DAI link found for DAI %s\n", __func__, dai->name);
1155 		return -EINVAL;
1156 	}
1157 
1158 	for (i = 0; i < slink->num_hw_configs; i++) {
1159 		hw_config = &slink->hw_configs[i];
1160 		if (dai->current_config == le32_to_cpu(hw_config->id)) {
1161 			hw_cfg_found = true;
1162 			break;
1163 		}
1164 	}
1165 
1166 	if (!hw_cfg_found) {
1167 		dev_err(sdev->dev, "%s: no matching hw_config found for DAI %s\n", __func__,
1168 			dai->name);
1169 		return -EINVAL;
1170 	}
1171 
1172 	*bit_depth = le32_to_cpu(hw_config->tdm_slot_width);
1173 	*channel_count = le32_to_cpu(hw_config->tdm_slots);
1174 	*sample_rate = le32_to_cpu(hw_config->fsync_rate);
1175 
1176 	dev_dbg(sdev->dev, "sample rate: %d sample width: %d channels: %d\n",
1177 		*sample_rate, *bit_depth, *channel_count);
1178 
1179 	return 0;
1180 }
1181 
1182 static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai,
1183 					  struct snd_pcm_hw_params *params, u32 dai_index,
1184 					  u32 linktype, u8 dir, u32 **dst, u32 *len)
1185 {
1186 	struct sof_ipc4_fw_data *ipc4_data = sdev->private;
1187 	struct nhlt_specific_cfg *cfg;
1188 	int sample_rate, channel_count;
1189 	int bit_depth, ret;
1190 	u32 nhlt_type;
1191 
1192 	/* convert to NHLT type */
1193 	switch (linktype) {
1194 	case SOF_DAI_INTEL_DMIC:
1195 		nhlt_type = NHLT_LINK_DMIC;
1196 		bit_depth = params_width(params);
1197 		channel_count = params_channels(params);
1198 		sample_rate = params_rate(params);
1199 		break;
1200 	case SOF_DAI_INTEL_SSP:
1201 		nhlt_type = NHLT_LINK_SSP;
1202 		ret = snd_sof_get_hw_config_params(sdev, dai, &sample_rate, &channel_count,
1203 						   &bit_depth);
1204 		if (ret < 0)
1205 			return ret;
1206 		break;
1207 	default:
1208 		return 0;
1209 	}
1210 
1211 	dev_dbg(sdev->dev, "dai index %d nhlt type %d direction %d\n",
1212 		dai_index, nhlt_type, dir);
1213 
1214 	/* find NHLT blob with matching params */
1215 	cfg = intel_nhlt_get_endpoint_blob(sdev->dev, ipc4_data->nhlt, dai_index, nhlt_type,
1216 					   bit_depth, bit_depth, channel_count, sample_rate,
1217 					   dir, 0);
1218 
1219 	if (!cfg) {
1220 		dev_err(sdev->dev,
1221 			"no matching blob for sample rate: %d sample width: %d channels: %d\n",
1222 			sample_rate, bit_depth, channel_count);
1223 		return -EINVAL;
1224 	}
1225 
1226 	/* config length should be in dwords */
1227 	*len = cfg->size >> 2;
1228 	*dst = (u32 *)cfg->caps;
1229 
1230 	return 0;
1231 }
1232 #else
1233 static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai,
1234 					  struct snd_pcm_hw_params *params, u32 dai_index,
1235 					  u32 linktype, u8 dir, u32 **dst, u32 *len)
1236 {
1237 	return 0;
1238 }
1239 #endif
1240 
1241 static int ipc4_set_fmt_mask(struct snd_mask *fmt, unsigned int bit_depth)
1242 {
1243 	switch (bit_depth) {
1244 	case 16:
1245 		snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
1246 		break;
1247 	case 24:
1248 		snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
1249 		break;
1250 	case 32:
1251 		snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE);
1252 		break;
1253 	default:
1254 		return -EINVAL;
1255 	}
1256 
1257 	return 0;
1258 }
1259 
1260 static int ipc4_copier_set_capture_fmt(struct snd_sof_dev *sdev,
1261 				       struct snd_pcm_hw_params *pipeline_params,
1262 				       struct snd_pcm_hw_params *fe_params,
1263 				       struct sof_ipc4_available_audio_format *available_fmt)
1264 {
1265 	struct sof_ipc4_audio_format *audio_fmt;
1266 	unsigned int sample_valid_bits;
1267 	bool multiple_formats = false;
1268 	bool fe_format_match = false;
1269 	struct snd_mask *fmt;
1270 	int i;
1271 
1272 	for (i = 0; i < available_fmt->num_output_formats; i++) {
1273 		unsigned int val;
1274 
1275 		audio_fmt = &available_fmt->output_pin_fmts[i].audio_fmt;
1276 		val = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(audio_fmt->fmt_cfg);
1277 
1278 		if (i == 0)
1279 			sample_valid_bits = val;
1280 		else if (sample_valid_bits != val)
1281 			multiple_formats = true;
1282 
1283 		if (snd_pcm_format_width(params_format(fe_params)) == val)
1284 			fe_format_match = true;
1285 	}
1286 
1287 	fmt = hw_param_mask(pipeline_params, SNDRV_PCM_HW_PARAM_FORMAT);
1288 	snd_mask_none(fmt);
1289 
1290 	if (multiple_formats) {
1291 		if (fe_format_match) {
1292 			/* multiple formats defined and one matches FE */
1293 			snd_mask_set_format(fmt, params_format(fe_params));
1294 			return 0;
1295 		}
1296 
1297 		dev_err(sdev->dev, "Multiple audio formats for single dai_out not supported\n");
1298 		return -EINVAL;
1299 	}
1300 
1301 	return ipc4_set_fmt_mask(fmt, sample_valid_bits);
1302 }
1303 
1304 static int
1305 sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
1306 			       struct snd_pcm_hw_params *fe_params,
1307 			       struct snd_sof_platform_stream_params *platform_params,
1308 			       struct snd_pcm_hw_params *pipeline_params, int dir)
1309 {
1310 	struct sof_ipc4_available_audio_format *available_fmt;
1311 	struct snd_soc_component *scomp = swidget->scomp;
1312 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1313 	struct sof_ipc4_pin_format *format_list_to_search;
1314 	struct sof_ipc4_copier_data *copier_data;
1315 	struct snd_pcm_hw_params *ref_params;
1316 	struct sof_ipc4_copier *ipc4_copier;
1317 	struct snd_sof_dai *dai;
1318 	struct snd_mask *fmt;
1319 	int out_sample_valid_bits;
1320 	void **ipc_config_data;
1321 	int *ipc_config_size;
1322 	u32 **data;
1323 	int ipc_size, ret;
1324 	u32 deep_buffer_dma_ms = 0;
1325 	u32 format_list_count;
1326 
1327 	dev_dbg(sdev->dev, "copier %s, type %d", swidget->widget->name, swidget->id);
1328 
1329 	switch (swidget->id) {
1330 	case snd_soc_dapm_aif_in:
1331 	case snd_soc_dapm_aif_out:
1332 	{
1333 		struct sof_ipc4_gtw_attributes *gtw_attr;
1334 		struct snd_sof_widget *pipe_widget;
1335 		struct sof_ipc4_pipeline *pipeline;
1336 
1337 		/* parse the deep buffer dma size */
1338 		ret = sof_update_ipc_object(scomp, &deep_buffer_dma_ms,
1339 					    SOF_COPIER_DEEP_BUFFER_TOKENS, swidget->tuples,
1340 					    swidget->num_tuples, sizeof(u32), 1);
1341 		if (ret) {
1342 			dev_err(scomp->dev, "Failed to parse deep buffer dma size for %s\n",
1343 				swidget->widget->name);
1344 			return ret;
1345 		}
1346 
1347 		pipe_widget = swidget->spipe->pipe_widget;
1348 		pipeline = pipe_widget->private;
1349 		ipc4_copier = (struct sof_ipc4_copier *)swidget->private;
1350 		gtw_attr = ipc4_copier->gtw_attr;
1351 		copier_data = &ipc4_copier->data;
1352 		available_fmt = &ipc4_copier->available_fmt;
1353 
1354 		/*
1355 		 * Use the input_pin_fmts to match pcm params for playback and the output_pin_fmts
1356 		 * for capture.
1357 		 */
1358 		if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
1359 			format_list_to_search = available_fmt->input_pin_fmts;
1360 			format_list_count = available_fmt->num_input_formats;
1361 		} else {
1362 			format_list_to_search = available_fmt->output_pin_fmts;
1363 			format_list_count = available_fmt->num_output_formats;
1364 		}
1365 
1366 		copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
1367 		copier_data->gtw_cfg.node_id |=
1368 			SOF_IPC4_NODE_INDEX(platform_params->stream_tag - 1);
1369 
1370 		/* set gateway attributes */
1371 		gtw_attr->lp_buffer_alloc = pipeline->lp_mode;
1372 		ref_params = fe_params;
1373 		break;
1374 	}
1375 	case snd_soc_dapm_dai_in:
1376 	case snd_soc_dapm_dai_out:
1377 	{
1378 		dai = swidget->private;
1379 
1380 		ipc4_copier = (struct sof_ipc4_copier *)dai->private;
1381 		copier_data = &ipc4_copier->data;
1382 		available_fmt = &ipc4_copier->available_fmt;
1383 		if (dir == SNDRV_PCM_STREAM_CAPTURE) {
1384 			format_list_to_search = available_fmt->output_pin_fmts;
1385 			format_list_count = available_fmt->num_output_formats;
1386 
1387 			ret = ipc4_copier_set_capture_fmt(sdev, pipeline_params, fe_params,
1388 							  available_fmt);
1389 			if (ret < 0)
1390 				return ret;
1391 		} else {
1392 			format_list_to_search = available_fmt->input_pin_fmts;
1393 			format_list_count = available_fmt->num_input_formats;
1394 		}
1395 
1396 		ref_params = pipeline_params;
1397 
1398 		ret = snd_sof_get_nhlt_endpoint_data(sdev, dai, fe_params, ipc4_copier->dai_index,
1399 						     ipc4_copier->dai_type, dir,
1400 						     &ipc4_copier->copier_config,
1401 						     &copier_data->gtw_cfg.config_length);
1402 		if (ret < 0)
1403 			return ret;
1404 
1405 		break;
1406 	}
1407 	case snd_soc_dapm_buffer:
1408 	{
1409 		ipc4_copier = (struct sof_ipc4_copier *)swidget->private;
1410 		copier_data = &ipc4_copier->data;
1411 		available_fmt = &ipc4_copier->available_fmt;
1412 
1413 		/* Use the input formats to match pcm params */
1414 		format_list_to_search = available_fmt->input_pin_fmts;
1415 		format_list_count = available_fmt->num_input_formats;
1416 		ref_params = pipeline_params;
1417 
1418 		break;
1419 	}
1420 	default:
1421 		dev_err(sdev->dev, "unsupported type %d for copier %s",
1422 			swidget->id, swidget->widget->name);
1423 		return -EINVAL;
1424 	}
1425 
1426 	/* set input and output audio formats */
1427 	ret = sof_ipc4_init_audio_fmt(sdev, swidget, &copier_data->base_config, ref_params,
1428 				      available_fmt, format_list_to_search, format_list_count);
1429 	if (ret < 0)
1430 		return ret;
1431 
1432 	/*
1433 	 * Set the output format. Current topology defines pin 0 input and output formats in pairs.
1434 	 * This assumes that the pin 0 formats are defined before all other pins.
1435 	 * So pick the output audio format with the same index as the chosen
1436 	 * input format. This logic will need to be updated when the format definitions
1437 	 * in topology change.
1438 	 */
1439 	memcpy(&copier_data->out_format, &available_fmt->output_pin_fmts[ret].audio_fmt,
1440 	       sizeof(struct sof_ipc4_audio_format));
1441 	dev_dbg(sdev->dev, "Output audio format for %s\n", swidget->widget->name);
1442 	sof_ipc4_dbg_audio_format(sdev->dev, &available_fmt->output_pin_fmts[ret], 1);
1443 
1444 	switch (swidget->id) {
1445 	case snd_soc_dapm_dai_in:
1446 	case snd_soc_dapm_dai_out:
1447 	{
1448 		/*
1449 		 * Only SOF_DAI_INTEL_ALH needs copier_data to set blob.
1450 		 * That's why only ALH dai's blob is set after sof_ipc4_init_audio_fmt
1451 		 */
1452 		if (ipc4_copier->dai_type == SOF_DAI_INTEL_ALH) {
1453 			struct sof_ipc4_alh_configuration_blob *blob;
1454 			struct sof_ipc4_copier_data *alh_data;
1455 			struct sof_ipc4_copier *alh_copier;
1456 			struct snd_sof_widget *w;
1457 			u32 ch_count = 0;
1458 			u32 ch_mask = 0;
1459 			u32 ch_map;
1460 			u32 step;
1461 			u32 mask;
1462 			int i;
1463 
1464 			blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config;
1465 
1466 			blob->gw_attr.lp_buffer_alloc = 0;
1467 
1468 			/* Get channel_mask from ch_map */
1469 			ch_map = copier_data->base_config.audio_fmt.ch_map;
1470 			for (i = 0; ch_map; i++) {
1471 				if ((ch_map & 0xf) != 0xf) {
1472 					ch_mask |= BIT(i);
1473 					ch_count++;
1474 				}
1475 				ch_map >>= 4;
1476 			}
1477 
1478 			step = ch_count / blob->alh_cfg.count;
1479 			mask =  GENMASK(step - 1, 0);
1480 			/*
1481 			 * Set each gtw_cfg.node_id to blob->alh_cfg.mapping[]
1482 			 * for all widgets with the same stream name
1483 			 */
1484 			i = 0;
1485 			list_for_each_entry(w, &sdev->widget_list, list) {
1486 				if (w->widget->sname &&
1487 				    strcmp(w->widget->sname, swidget->widget->sname))
1488 					continue;
1489 
1490 				dai = w->private;
1491 				alh_copier = (struct sof_ipc4_copier *)dai->private;
1492 				alh_data = &alh_copier->data;
1493 				blob->alh_cfg.mapping[i].alh_id = alh_data->gtw_cfg.node_id;
1494 				/*
1495 				 * Set the same channel mask for playback as the audio data is
1496 				 * duplicated for all speakers. For capture, split the channels
1497 				 * among the aggregated DAIs. For example, with 4 channels on 2
1498 				 * aggregated DAIs, the channel_mask should be 0x3 and 0xc for the
1499 				 * two DAI's.
1500 				 * The channel masks used depend on the cpu_dais used in the
1501 				 * dailink at the machine driver level, which actually comes from
1502 				 * the tables in soc_acpi files depending on the _ADR and devID
1503 				 * registers for each codec.
1504 				 */
1505 				if (w->id == snd_soc_dapm_dai_in)
1506 					blob->alh_cfg.mapping[i].channel_mask = ch_mask;
1507 				else
1508 					blob->alh_cfg.mapping[i].channel_mask = mask << (step * i);
1509 
1510 				i++;
1511 			}
1512 			if (blob->alh_cfg.count > 1) {
1513 				int group_id;
1514 
1515 				group_id = ida_alloc_max(&alh_group_ida, ALH_MULTI_GTW_COUNT - 1,
1516 							 GFP_KERNEL);
1517 
1518 				if (group_id < 0)
1519 					return group_id;
1520 
1521 				/* add multi-gateway base */
1522 				group_id += ALH_MULTI_GTW_BASE;
1523 				copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
1524 				copier_data->gtw_cfg.node_id |= SOF_IPC4_NODE_INDEX(group_id);
1525 			}
1526 		}
1527 	}
1528 	}
1529 
1530 	/* modify the input params for the next widget */
1531 	fmt = hw_param_mask(pipeline_params, SNDRV_PCM_HW_PARAM_FORMAT);
1532 	out_sample_valid_bits =
1533 		SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(copier_data->out_format.fmt_cfg);
1534 	snd_mask_none(fmt);
1535 	ret = ipc4_set_fmt_mask(fmt, out_sample_valid_bits);
1536 	if (ret)
1537 		return ret;
1538 
1539 	/*
1540 	 * Set the gateway dma_buffer_size to 2ms buffer size to meet the FW expectation. In the
1541 	 * deep buffer case, set the dma_buffer_size depending on the deep_buffer_dma_ms set
1542 	 * in topology.
1543 	 */
1544 	switch (swidget->id) {
1545 	case snd_soc_dapm_dai_in:
1546 		copier_data->gtw_cfg.dma_buffer_size =
1547 			SOF_IPC4_MIN_DMA_BUFFER_SIZE * copier_data->base_config.ibs;
1548 		break;
1549 	case snd_soc_dapm_aif_in:
1550 			copier_data->gtw_cfg.dma_buffer_size =
1551 				max((u32)SOF_IPC4_MIN_DMA_BUFFER_SIZE, deep_buffer_dma_ms) *
1552 					copier_data->base_config.ibs;
1553 		break;
1554 	case snd_soc_dapm_dai_out:
1555 	case snd_soc_dapm_aif_out:
1556 		copier_data->gtw_cfg.dma_buffer_size =
1557 			SOF_IPC4_MIN_DMA_BUFFER_SIZE * copier_data->base_config.obs;
1558 		break;
1559 	default:
1560 		break;
1561 	}
1562 
1563 	data = &ipc4_copier->copier_config;
1564 	ipc_config_size = &ipc4_copier->ipc_config_size;
1565 	ipc_config_data = &ipc4_copier->ipc_config_data;
1566 
1567 	/* config_length is DWORD based */
1568 	ipc_size = sizeof(*copier_data) + copier_data->gtw_cfg.config_length * 4;
1569 
1570 	dev_dbg(sdev->dev, "copier %s, IPC size is %d", swidget->widget->name, ipc_size);
1571 
1572 	*ipc_config_data = kzalloc(ipc_size, GFP_KERNEL);
1573 	if (!*ipc_config_data)
1574 		return -ENOMEM;
1575 
1576 	*ipc_config_size = ipc_size;
1577 
1578 	/* copy IPC data */
1579 	memcpy(*ipc_config_data, (void *)copier_data, sizeof(*copier_data));
1580 	if (copier_data->gtw_cfg.config_length)
1581 		memcpy(*ipc_config_data + sizeof(*copier_data),
1582 		       *data, copier_data->gtw_cfg.config_length * 4);
1583 
1584 	/* update pipeline memory usage */
1585 	sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &copier_data->base_config);
1586 
1587 	return 0;
1588 }
1589 
1590 static int sof_ipc4_prepare_gain_module(struct snd_sof_widget *swidget,
1591 					struct snd_pcm_hw_params *fe_params,
1592 					struct snd_sof_platform_stream_params *platform_params,
1593 					struct snd_pcm_hw_params *pipeline_params, int dir)
1594 {
1595 	struct snd_soc_component *scomp = swidget->scomp;
1596 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1597 	struct sof_ipc4_gain *gain = swidget->private;
1598 	struct sof_ipc4_available_audio_format *available_fmt = &gain->available_fmt;
1599 	int ret;
1600 
1601 	ret = sof_ipc4_init_audio_fmt(sdev, swidget, &gain->base_config,
1602 				      pipeline_params, available_fmt,
1603 				      available_fmt->input_pin_fmts,
1604 				      available_fmt->num_input_formats);
1605 	if (ret < 0)
1606 		return ret;
1607 
1608 	/* update pipeline memory usage */
1609 	sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &gain->base_config);
1610 
1611 	return 0;
1612 }
1613 
1614 static int sof_ipc4_prepare_mixer_module(struct snd_sof_widget *swidget,
1615 					 struct snd_pcm_hw_params *fe_params,
1616 					 struct snd_sof_platform_stream_params *platform_params,
1617 					 struct snd_pcm_hw_params *pipeline_params, int dir)
1618 {
1619 	struct snd_soc_component *scomp = swidget->scomp;
1620 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1621 	struct sof_ipc4_mixer *mixer = swidget->private;
1622 	struct sof_ipc4_available_audio_format *available_fmt = &mixer->available_fmt;
1623 	int ret;
1624 
1625 	ret = sof_ipc4_init_audio_fmt(sdev, swidget, &mixer->base_config,
1626 				      pipeline_params, available_fmt,
1627 				      available_fmt->input_pin_fmts,
1628 				      available_fmt->num_input_formats);
1629 	if (ret < 0)
1630 		return ret;
1631 
1632 	/* update pipeline memory usage */
1633 	sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &mixer->base_config);
1634 
1635 	return 0;
1636 }
1637 
1638 static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget,
1639 				       struct snd_pcm_hw_params *fe_params,
1640 				       struct snd_sof_platform_stream_params *platform_params,
1641 				       struct snd_pcm_hw_params *pipeline_params, int dir)
1642 {
1643 	struct snd_soc_component *scomp = swidget->scomp;
1644 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1645 	struct sof_ipc4_src *src = swidget->private;
1646 	struct sof_ipc4_available_audio_format *available_fmt = &src->available_fmt;
1647 	struct snd_interval *rate;
1648 	int ret;
1649 
1650 	ret = sof_ipc4_init_audio_fmt(sdev, swidget, &src->base_config,
1651 				      pipeline_params, available_fmt,
1652 				      available_fmt->input_pin_fmts,
1653 				      available_fmt->num_input_formats);
1654 	if (ret < 0)
1655 		return ret;
1656 
1657 	/* update pipeline memory usage */
1658 	sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &src->base_config);
1659 
1660 	/* update pipeline_params for sink widgets */
1661 	rate = hw_param_interval(pipeline_params, SNDRV_PCM_HW_PARAM_RATE);
1662 	rate->min = src->sink_rate;
1663 	rate->max = rate->min;
1664 
1665 	return 0;
1666 }
1667 
1668 static int
1669 sof_ipc4_process_set_pin_formats(struct snd_sof_widget *swidget, int pin_type)
1670 {
1671 	struct sof_ipc4_process *process = swidget->private;
1672 	struct sof_ipc4_base_module_cfg_ext *base_cfg_ext = process->base_config_ext;
1673 	struct sof_ipc4_available_audio_format *available_fmt = &process->available_fmt;
1674 	struct sof_ipc4_pin_format *pin_format, *format_list_to_search;
1675 	struct snd_soc_component *scomp = swidget->scomp;
1676 	int num_pins, format_list_count;
1677 	int pin_format_offset = 0;
1678 	int i, j;
1679 
1680 	/* set number of pins, offset of pin format and format list to search based on pin type */
1681 	if (pin_type == SOF_PIN_TYPE_INPUT) {
1682 		num_pins = swidget->num_input_pins;
1683 		format_list_to_search = available_fmt->input_pin_fmts;
1684 		format_list_count = available_fmt->num_input_formats;
1685 	} else {
1686 		num_pins = swidget->num_output_pins;
1687 		pin_format_offset = swidget->num_input_pins;
1688 		format_list_to_search = available_fmt->output_pin_fmts;
1689 		format_list_count = available_fmt->num_output_formats;
1690 	}
1691 
1692 	for (i = pin_format_offset; i < num_pins + pin_format_offset; i++) {
1693 		pin_format = &base_cfg_ext->pin_formats[i];
1694 
1695 		/* Pin 0 audio formats are derived from the base config input/output format */
1696 		if (i == pin_format_offset) {
1697 			if (pin_type == SOF_PIN_TYPE_INPUT) {
1698 				pin_format->buffer_size = process->base_config.ibs;
1699 				pin_format->audio_fmt = process->base_config.audio_fmt;
1700 			} else {
1701 				pin_format->buffer_size = process->base_config.obs;
1702 				pin_format->audio_fmt = process->output_format;
1703 			}
1704 			continue;
1705 		}
1706 
1707 		/*
1708 		 * For all other pins, find the pin formats from those set in topology. If there
1709 		 * is more than one format specified for a pin, this will pick the first available
1710 		 * one.
1711 		 */
1712 		for (j = 0; j < format_list_count; j++) {
1713 			struct sof_ipc4_pin_format *pin_format_item = &format_list_to_search[j];
1714 
1715 			if (pin_format_item->pin_index == i - pin_format_offset) {
1716 				*pin_format = *pin_format_item;
1717 				break;
1718 			}
1719 		}
1720 
1721 		if (j == format_list_count) {
1722 			dev_err(scomp->dev, "%s pin %d format not found for %s\n",
1723 				(pin_type == SOF_PIN_TYPE_INPUT) ? "input" : "output",
1724 				i - pin_format_offset, swidget->widget->name);
1725 			return -EINVAL;
1726 		}
1727 	}
1728 
1729 	return 0;
1730 }
1731 
1732 static int sof_ipc4_process_add_base_cfg_extn(struct snd_sof_widget *swidget)
1733 {
1734 	int ret, i;
1735 
1736 	/* copy input and output pin formats */
1737 	for (i = 0; i <= SOF_PIN_TYPE_OUTPUT; i++) {
1738 		ret = sof_ipc4_process_set_pin_formats(swidget, i);
1739 		if (ret < 0)
1740 			return ret;
1741 	}
1742 
1743 	return 0;
1744 }
1745 
1746 static int sof_ipc4_prepare_process_module(struct snd_sof_widget *swidget,
1747 					   struct snd_pcm_hw_params *fe_params,
1748 					   struct snd_sof_platform_stream_params *platform_params,
1749 					   struct snd_pcm_hw_params *pipeline_params, int dir)
1750 {
1751 	struct snd_soc_component *scomp = swidget->scomp;
1752 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1753 	struct sof_ipc4_process *process = swidget->private;
1754 	struct sof_ipc4_available_audio_format *available_fmt = &process->available_fmt;
1755 	void *cfg = process->ipc_config_data;
1756 	int ret;
1757 
1758 	ret = sof_ipc4_init_audio_fmt(sdev, swidget, &process->base_config,
1759 				      pipeline_params, available_fmt,
1760 				      available_fmt->input_pin_fmts,
1761 				      available_fmt->num_input_formats);
1762 	if (ret < 0)
1763 		return ret;
1764 
1765 	/* copy Pin 0 output format */
1766 	if (available_fmt->num_output_formats && ret < available_fmt->num_output_formats &&
1767 	    !available_fmt->output_pin_fmts[ret].pin_index) {
1768 		memcpy(&process->output_format, &available_fmt->output_pin_fmts[ret].audio_fmt,
1769 		       sizeof(struct sof_ipc4_audio_format));
1770 
1771 		/* modify the pipeline params with the pin 0 output format */
1772 		ret = sof_ipc4_update_hw_params(sdev, pipeline_params, &process->output_format);
1773 		if (ret)
1774 			return ret;
1775 	}
1776 
1777 	/* update pipeline memory usage */
1778 	sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &process->base_config);
1779 
1780 	/* ipc_config_data is composed of the base_config followed by an optional extension */
1781 	memcpy(cfg, &process->base_config, sizeof(struct sof_ipc4_base_module_cfg));
1782 	cfg += sizeof(struct sof_ipc4_base_module_cfg);
1783 
1784 	if (process->init_config == SOF_IPC4_MODULE_INIT_CONFIG_TYPE_BASE_CFG_WITH_EXT) {
1785 		struct sof_ipc4_base_module_cfg_ext *base_cfg_ext = process->base_config_ext;
1786 
1787 		ret = sof_ipc4_process_add_base_cfg_extn(swidget);
1788 		if (ret < 0)
1789 			return ret;
1790 
1791 		memcpy(cfg, base_cfg_ext, process->base_config_ext_size);
1792 	}
1793 
1794 	return 0;
1795 }
1796 
1797 static int sof_ipc4_control_load_volume(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
1798 {
1799 	struct sof_ipc4_control_data *control_data;
1800 	struct sof_ipc4_msg *msg;
1801 	int i;
1802 
1803 	scontrol->size = struct_size(control_data, chanv, scontrol->num_channels);
1804 
1805 	/* scontrol->ipc_control_data will be freed in sof_control_unload */
1806 	scontrol->ipc_control_data = kzalloc(scontrol->size, GFP_KERNEL);
1807 	if (!scontrol->ipc_control_data)
1808 		return -ENOMEM;
1809 
1810 	control_data = scontrol->ipc_control_data;
1811 	control_data->index = scontrol->index;
1812 
1813 	msg = &control_data->msg;
1814 	msg->primary = SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_LARGE_CONFIG_SET);
1815 	msg->primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
1816 	msg->primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
1817 
1818 	msg->extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_GAIN_PARAM_ID);
1819 
1820 	/* set default volume values to 0dB in control */
1821 	for (i = 0; i < scontrol->num_channels; i++) {
1822 		control_data->chanv[i].channel = i;
1823 		control_data->chanv[i].value = SOF_IPC4_VOL_ZERO_DB;
1824 	}
1825 
1826 	return 0;
1827 }
1828 
1829 static int sof_ipc4_control_load_bytes(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
1830 {
1831 	struct sof_ipc4_control_data *control_data;
1832 	struct sof_ipc4_msg *msg;
1833 	int ret;
1834 
1835 	if (scontrol->max_size < (sizeof(*control_data) + sizeof(struct sof_abi_hdr))) {
1836 		dev_err(sdev->dev, "insufficient size for a bytes control %s: %zu.\n",
1837 			scontrol->name, scontrol->max_size);
1838 		return -EINVAL;
1839 	}
1840 
1841 	if (scontrol->priv_size > scontrol->max_size - sizeof(*control_data)) {
1842 		dev_err(sdev->dev, "scontrol %s bytes data size %zu exceeds max %zu.\n",
1843 			scontrol->name, scontrol->priv_size,
1844 			scontrol->max_size - sizeof(*control_data));
1845 		return -EINVAL;
1846 	}
1847 
1848 	scontrol->size = sizeof(struct sof_ipc4_control_data) + scontrol->priv_size;
1849 
1850 	scontrol->ipc_control_data = kzalloc(scontrol->max_size, GFP_KERNEL);
1851 	if (!scontrol->ipc_control_data)
1852 		return -ENOMEM;
1853 
1854 	control_data = scontrol->ipc_control_data;
1855 	control_data->index = scontrol->index;
1856 	if (scontrol->priv_size > 0) {
1857 		memcpy(control_data->data, scontrol->priv, scontrol->priv_size);
1858 		kfree(scontrol->priv);
1859 		scontrol->priv = NULL;
1860 
1861 		if (control_data->data->magic != SOF_IPC4_ABI_MAGIC) {
1862 			dev_err(sdev->dev, "Wrong ABI magic (%#x) for control: %s\n",
1863 				control_data->data->magic, scontrol->name);
1864 			ret = -EINVAL;
1865 			goto err;
1866 		}
1867 
1868 		/* TODO: check the ABI version */
1869 
1870 		if (control_data->data->size + sizeof(struct sof_abi_hdr) !=
1871 		    scontrol->priv_size) {
1872 			dev_err(sdev->dev, "Control %s conflict in bytes %zu vs. priv size %zu.\n",
1873 				scontrol->name,
1874 				control_data->data->size + sizeof(struct sof_abi_hdr),
1875 				scontrol->priv_size);
1876 			ret = -EINVAL;
1877 			goto err;
1878 		}
1879 	}
1880 
1881 	msg = &control_data->msg;
1882 	msg->primary = SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_LARGE_CONFIG_SET);
1883 	msg->primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
1884 	msg->primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
1885 
1886 	return 0;
1887 
1888 err:
1889 	kfree(scontrol->ipc_control_data);
1890 	scontrol->ipc_control_data = NULL;
1891 	return ret;
1892 }
1893 
1894 static int sof_ipc4_control_setup(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
1895 {
1896 	switch (scontrol->info_type) {
1897 	case SND_SOC_TPLG_CTL_VOLSW:
1898 	case SND_SOC_TPLG_CTL_VOLSW_SX:
1899 	case SND_SOC_TPLG_CTL_VOLSW_XR_SX:
1900 		return sof_ipc4_control_load_volume(sdev, scontrol);
1901 	case SND_SOC_TPLG_CTL_BYTES:
1902 		return sof_ipc4_control_load_bytes(sdev, scontrol);
1903 	default:
1904 		break;
1905 	}
1906 
1907 	return 0;
1908 }
1909 
1910 static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
1911 {
1912 	struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
1913 	struct sof_ipc4_fw_data *ipc4_data = sdev->private;
1914 	struct sof_ipc4_pipeline *pipeline;
1915 	struct sof_ipc4_msg *msg;
1916 	void *ipc_data = NULL;
1917 	u32 ipc_size = 0;
1918 	int ret;
1919 
1920 	switch (swidget->id) {
1921 	case snd_soc_dapm_scheduler:
1922 		pipeline = swidget->private;
1923 
1924 		dev_dbg(sdev->dev, "pipeline: %d memory pages: %d\n", swidget->pipeline_id,
1925 			pipeline->mem_usage);
1926 
1927 		msg = &pipeline->msg;
1928 		msg->primary |= pipeline->mem_usage;
1929 
1930 		swidget->instance_id = ida_alloc_max(&pipeline_ida, ipc4_data->max_num_pipelines,
1931 						     GFP_KERNEL);
1932 		if (swidget->instance_id < 0) {
1933 			dev_err(sdev->dev, "failed to assign pipeline id for %s: %d\n",
1934 				swidget->widget->name, swidget->instance_id);
1935 			return swidget->instance_id;
1936 		}
1937 		msg->primary &= ~SOF_IPC4_GLB_PIPE_INSTANCE_MASK;
1938 		msg->primary |= SOF_IPC4_GLB_PIPE_INSTANCE_ID(swidget->instance_id);
1939 		break;
1940 	case snd_soc_dapm_aif_in:
1941 	case snd_soc_dapm_aif_out:
1942 	case snd_soc_dapm_buffer:
1943 	{
1944 		struct sof_ipc4_copier *ipc4_copier = swidget->private;
1945 
1946 		ipc_size = ipc4_copier->ipc_config_size;
1947 		ipc_data = ipc4_copier->ipc_config_data;
1948 
1949 		msg = &ipc4_copier->msg;
1950 		break;
1951 	}
1952 	case snd_soc_dapm_dai_in:
1953 	case snd_soc_dapm_dai_out:
1954 	{
1955 		struct snd_sof_dai *dai = swidget->private;
1956 		struct sof_ipc4_copier *ipc4_copier = dai->private;
1957 
1958 		ipc_size = ipc4_copier->ipc_config_size;
1959 		ipc_data = ipc4_copier->ipc_config_data;
1960 
1961 		msg = &ipc4_copier->msg;
1962 		break;
1963 	}
1964 	case snd_soc_dapm_pga:
1965 	{
1966 		struct sof_ipc4_gain *gain = swidget->private;
1967 
1968 		ipc_size = sizeof(struct sof_ipc4_base_module_cfg) +
1969 			   sizeof(struct sof_ipc4_gain_data);
1970 		ipc_data = gain;
1971 
1972 		msg = &gain->msg;
1973 		break;
1974 	}
1975 	case snd_soc_dapm_mixer:
1976 	{
1977 		struct sof_ipc4_mixer *mixer = swidget->private;
1978 
1979 		ipc_size = sizeof(mixer->base_config);
1980 		ipc_data = &mixer->base_config;
1981 
1982 		msg = &mixer->msg;
1983 		break;
1984 	}
1985 	case snd_soc_dapm_src:
1986 	{
1987 		struct sof_ipc4_src *src = swidget->private;
1988 
1989 		ipc_size = sizeof(struct sof_ipc4_base_module_cfg) + sizeof(src->sink_rate);
1990 		ipc_data = src;
1991 
1992 		msg = &src->msg;
1993 		break;
1994 	}
1995 	case snd_soc_dapm_effect:
1996 	{
1997 		struct sof_ipc4_process *process = swidget->private;
1998 
1999 		if (!process->ipc_config_size) {
2000 			dev_err(sdev->dev, "module %s has no config data!\n",
2001 				swidget->widget->name);
2002 			return -EINVAL;
2003 		}
2004 
2005 		ipc_size = process->ipc_config_size;
2006 		ipc_data = process->ipc_config_data;
2007 
2008 		msg = &process->msg;
2009 		break;
2010 	}
2011 	default:
2012 		dev_err(sdev->dev, "widget type %d not supported", swidget->id);
2013 		return -EINVAL;
2014 	}
2015 
2016 	if (swidget->id != snd_soc_dapm_scheduler) {
2017 		ret = sof_ipc4_widget_assign_instance_id(sdev, swidget);
2018 		if (ret < 0) {
2019 			dev_err(sdev->dev, "failed to assign instance id for %s\n",
2020 				swidget->widget->name);
2021 			return ret;
2022 		}
2023 
2024 		msg->primary &= ~SOF_IPC4_MOD_INSTANCE_MASK;
2025 		msg->primary |= SOF_IPC4_MOD_INSTANCE(swidget->instance_id);
2026 
2027 		msg->extension &= ~SOF_IPC4_MOD_EXT_PARAM_SIZE_MASK;
2028 		msg->extension |= ipc_size >> 2;
2029 
2030 		msg->extension &= ~SOF_IPC4_MOD_EXT_PPL_ID_MASK;
2031 		msg->extension |= SOF_IPC4_MOD_EXT_PPL_ID(pipe_widget->instance_id);
2032 	}
2033 	dev_dbg(sdev->dev, "Create widget %s instance %d - pipe %d - core %d\n",
2034 		swidget->widget->name, swidget->instance_id, swidget->pipeline_id, swidget->core);
2035 
2036 	msg->data_size = ipc_size;
2037 	msg->data_ptr = ipc_data;
2038 
2039 	ret = sof_ipc_tx_message(sdev->ipc, msg, ipc_size, NULL, 0);
2040 	if (ret < 0) {
2041 		dev_err(sdev->dev, "failed to create module %s\n", swidget->widget->name);
2042 
2043 		if (swidget->id != snd_soc_dapm_scheduler) {
2044 			struct sof_ipc4_fw_module *fw_module = swidget->module_info;
2045 
2046 			ida_free(&fw_module->m_ida, swidget->instance_id);
2047 		} else {
2048 			ida_free(&pipeline_ida, swidget->instance_id);
2049 		}
2050 	}
2051 
2052 	return ret;
2053 }
2054 
2055 static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
2056 {
2057 	struct sof_ipc4_fw_module *fw_module = swidget->module_info;
2058 	struct sof_ipc4_fw_data *ipc4_data = sdev->private;
2059 	int ret = 0;
2060 
2061 	mutex_lock(&ipc4_data->pipeline_state_mutex);
2062 
2063 	/* freeing a pipeline frees all the widgets associated with it */
2064 	if (swidget->id == snd_soc_dapm_scheduler) {
2065 		struct sof_ipc4_pipeline *pipeline = swidget->private;
2066 		struct sof_ipc4_msg msg = {{ 0 }};
2067 		u32 header;
2068 
2069 		header = SOF_IPC4_GLB_PIPE_INSTANCE_ID(swidget->instance_id);
2070 		header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_DELETE_PIPELINE);
2071 		header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
2072 		header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG);
2073 
2074 		msg.primary = header;
2075 
2076 		ret = sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0);
2077 		if (ret < 0)
2078 			dev_err(sdev->dev, "failed to free pipeline widget %s\n",
2079 				swidget->widget->name);
2080 
2081 		pipeline->mem_usage = 0;
2082 		pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED;
2083 		ida_free(&pipeline_ida, swidget->instance_id);
2084 	} else {
2085 		ida_free(&fw_module->m_ida, swidget->instance_id);
2086 	}
2087 
2088 	mutex_unlock(&ipc4_data->pipeline_state_mutex);
2089 
2090 	return ret;
2091 }
2092 
2093 static int sof_ipc4_get_queue_id(struct snd_sof_widget *src_widget,
2094 				 struct snd_sof_widget *sink_widget, bool pin_type)
2095 {
2096 	struct snd_sof_widget *current_swidget;
2097 	struct snd_soc_component *scomp;
2098 	struct ida *queue_ida;
2099 	const char *buddy_name;
2100 	char **pin_binding;
2101 	u32 num_pins;
2102 	int i;
2103 
2104 	if (pin_type == SOF_PIN_TYPE_OUTPUT) {
2105 		current_swidget = src_widget;
2106 		pin_binding = src_widget->output_pin_binding;
2107 		queue_ida = &src_widget->output_queue_ida;
2108 		num_pins = src_widget->num_output_pins;
2109 		buddy_name = sink_widget->widget->name;
2110 	} else {
2111 		current_swidget = sink_widget;
2112 		pin_binding = sink_widget->input_pin_binding;
2113 		queue_ida = &sink_widget->input_queue_ida;
2114 		num_pins = sink_widget->num_input_pins;
2115 		buddy_name = src_widget->widget->name;
2116 	}
2117 
2118 	scomp = current_swidget->scomp;
2119 
2120 	if (num_pins < 1) {
2121 		dev_err(scomp->dev, "invalid %s num_pins: %d for queue allocation for %s\n",
2122 			(pin_type == SOF_PIN_TYPE_OUTPUT ? "output" : "input"),
2123 			num_pins, current_swidget->widget->name);
2124 		return -EINVAL;
2125 	}
2126 
2127 	/* If there is only one input/output pin, queue id must be 0 */
2128 	if (num_pins == 1)
2129 		return 0;
2130 
2131 	/* Allocate queue ID from pin binding array if it is defined in topology. */
2132 	if (pin_binding) {
2133 		for (i = 0; i < num_pins; i++) {
2134 			if (!strcmp(pin_binding[i], buddy_name))
2135 				return i;
2136 		}
2137 		/*
2138 		 * Fail if no queue ID found from pin binding array, so that we don't
2139 		 * mixed use pin binding array and ida for queue ID allocation.
2140 		 */
2141 		dev_err(scomp->dev, "no %s queue id found from pin binding array for %s\n",
2142 			(pin_type == SOF_PIN_TYPE_OUTPUT ? "output" : "input"),
2143 			current_swidget->widget->name);
2144 		return -EINVAL;
2145 	}
2146 
2147 	/* If no pin binding array specified in topology, use ida to allocate one */
2148 	return ida_alloc_max(queue_ida, num_pins, GFP_KERNEL);
2149 }
2150 
2151 static void sof_ipc4_put_queue_id(struct snd_sof_widget *swidget, int queue_id,
2152 				  bool pin_type)
2153 {
2154 	struct ida *queue_ida;
2155 	char **pin_binding;
2156 	int num_pins;
2157 
2158 	if (pin_type == SOF_PIN_TYPE_OUTPUT) {
2159 		pin_binding = swidget->output_pin_binding;
2160 		queue_ida = &swidget->output_queue_ida;
2161 		num_pins = swidget->num_output_pins;
2162 	} else {
2163 		pin_binding = swidget->input_pin_binding;
2164 		queue_ida = &swidget->input_queue_ida;
2165 		num_pins = swidget->num_input_pins;
2166 	}
2167 
2168 	/* Nothing to free if queue ID is not allocated with ida. */
2169 	if (num_pins == 1 || pin_binding)
2170 		return;
2171 
2172 	ida_free(queue_ida, queue_id);
2173 }
2174 
2175 static int sof_ipc4_set_copier_sink_format(struct snd_sof_dev *sdev,
2176 					   struct snd_sof_widget *src_widget,
2177 					   struct snd_sof_widget *sink_widget,
2178 					   int sink_id)
2179 {
2180 	struct sof_ipc4_copier_config_set_sink_format format;
2181 	struct sof_ipc4_base_module_cfg *src_config;
2182 	const struct sof_ipc4_audio_format *pin_fmt;
2183 	struct sof_ipc4_fw_module *fw_module;
2184 	struct sof_ipc4_msg msg = {{ 0 }};
2185 	u32 header, extension;
2186 
2187 	dev_dbg(sdev->dev, "%s set copier sink %d format\n",
2188 		src_widget->widget->name, sink_id);
2189 
2190 	if (WIDGET_IS_DAI(src_widget->id)) {
2191 		struct snd_sof_dai *dai = src_widget->private;
2192 
2193 		src_config = dai->private;
2194 	} else {
2195 		src_config = src_widget->private;
2196 	}
2197 
2198 	fw_module = src_widget->module_info;
2199 
2200 	format.sink_id = sink_id;
2201 	memcpy(&format.source_fmt, &src_config->audio_fmt, sizeof(format.source_fmt));
2202 
2203 	pin_fmt = sof_ipc4_get_input_pin_audio_fmt(sink_widget, sink_id);
2204 	if (!pin_fmt) {
2205 		dev_err(sdev->dev, "Unable to get pin %d format for %s",
2206 			sink_id, sink_widget->widget->name);
2207 		return -EINVAL;
2208 	}
2209 
2210 	memcpy(&format.sink_fmt, pin_fmt, sizeof(format.sink_fmt));
2211 
2212 	msg.data_size = sizeof(format);
2213 	msg.data_ptr = &format;
2214 
2215 	header = fw_module->man4_module_entry.id;
2216 	header |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id);
2217 	header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_LARGE_CONFIG_SET);
2218 	header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
2219 	header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
2220 
2221 	extension = SOF_IPC4_MOD_EXT_MSG_SIZE(msg.data_size);
2222 	extension |=
2223 		SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_COPIER_MODULE_CFG_PARAM_SET_SINK_FORMAT);
2224 	extension |= SOF_IPC4_MOD_EXT_MSG_LAST_BLOCK(1);
2225 	extension |= SOF_IPC4_MOD_EXT_MSG_FIRST_BLOCK(1);
2226 
2227 	msg.primary = header;
2228 	msg.extension = extension;
2229 
2230 	return sof_ipc_tx_message(sdev->ipc, &msg, msg.data_size, NULL, 0);
2231 }
2232 
2233 static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route *sroute)
2234 {
2235 	struct snd_sof_widget *src_widget = sroute->src_widget;
2236 	struct snd_sof_widget *sink_widget = sroute->sink_widget;
2237 	struct sof_ipc4_fw_module *src_fw_module = src_widget->module_info;
2238 	struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info;
2239 	struct sof_ipc4_msg msg = {{ 0 }};
2240 	u32 header, extension;
2241 	int ret;
2242 
2243 	sroute->src_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget,
2244 						     SOF_PIN_TYPE_OUTPUT);
2245 	if (sroute->src_queue_id < 0) {
2246 		dev_err(sdev->dev, "failed to get queue ID for source widget: %s\n",
2247 			src_widget->widget->name);
2248 		return sroute->src_queue_id;
2249 	}
2250 
2251 	sroute->dst_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget,
2252 						     SOF_PIN_TYPE_INPUT);
2253 	if (sroute->dst_queue_id < 0) {
2254 		dev_err(sdev->dev, "failed to get queue ID for sink widget: %s\n",
2255 			sink_widget->widget->name);
2256 		sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id,
2257 				      SOF_PIN_TYPE_OUTPUT);
2258 		return sroute->dst_queue_id;
2259 	}
2260 
2261 	/* Pin 0 format is already set during copier module init */
2262 	if (sroute->src_queue_id > 0 && WIDGET_IS_COPIER(src_widget->id)) {
2263 		ret = sof_ipc4_set_copier_sink_format(sdev, src_widget, sink_widget,
2264 						      sroute->src_queue_id);
2265 		if (ret < 0) {
2266 			dev_err(sdev->dev, "failed to set sink format for %s source queue ID %d\n",
2267 				src_widget->widget->name, sroute->src_queue_id);
2268 			goto out;
2269 		}
2270 	}
2271 
2272 	dev_dbg(sdev->dev, "bind %s:%d -> %s:%d\n",
2273 		src_widget->widget->name, sroute->src_queue_id,
2274 		sink_widget->widget->name, sroute->dst_queue_id);
2275 
2276 	header = src_fw_module->man4_module_entry.id;
2277 	header |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id);
2278 	header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_BIND);
2279 	header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
2280 	header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
2281 
2282 	extension = sink_fw_module->man4_module_entry.id;
2283 	extension |= SOF_IPC4_MOD_EXT_DST_MOD_INSTANCE(sink_widget->instance_id);
2284 	extension |= SOF_IPC4_MOD_EXT_DST_MOD_QUEUE_ID(sroute->dst_queue_id);
2285 	extension |= SOF_IPC4_MOD_EXT_SRC_MOD_QUEUE_ID(sroute->src_queue_id);
2286 
2287 	msg.primary = header;
2288 	msg.extension = extension;
2289 
2290 	ret = sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0);
2291 	if (ret < 0) {
2292 		dev_err(sdev->dev, "failed to bind modules %s:%d -> %s:%d\n",
2293 			src_widget->widget->name, sroute->src_queue_id,
2294 			sink_widget->widget->name, sroute->dst_queue_id);
2295 		goto out;
2296 	}
2297 
2298 	return ret;
2299 
2300 out:
2301 	sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id, SOF_PIN_TYPE_OUTPUT);
2302 	sof_ipc4_put_queue_id(sink_widget, sroute->dst_queue_id, SOF_PIN_TYPE_INPUT);
2303 	return ret;
2304 }
2305 
2306 static int sof_ipc4_route_free(struct snd_sof_dev *sdev, struct snd_sof_route *sroute)
2307 {
2308 	struct snd_sof_widget *src_widget = sroute->src_widget;
2309 	struct snd_sof_widget *sink_widget = sroute->sink_widget;
2310 	struct sof_ipc4_fw_module *src_fw_module = src_widget->module_info;
2311 	struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info;
2312 	struct sof_ipc4_msg msg = {{ 0 }};
2313 	u32 header, extension;
2314 	int ret = 0;
2315 
2316 	dev_dbg(sdev->dev, "unbind modules %s:%d -> %s:%d\n",
2317 		src_widget->widget->name, sroute->src_queue_id,
2318 		sink_widget->widget->name, sroute->dst_queue_id);
2319 
2320 	/*
2321 	 * routes belonging to the same pipeline will be disconnected by the FW when the pipeline
2322 	 * is freed. So avoid sending this IPC which will be ignored by the FW anyway.
2323 	 */
2324 	if (src_widget->spipe->pipe_widget == sink_widget->spipe->pipe_widget)
2325 		goto out;
2326 
2327 	header = src_fw_module->man4_module_entry.id;
2328 	header |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id);
2329 	header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_UNBIND);
2330 	header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
2331 	header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
2332 
2333 	extension = sink_fw_module->man4_module_entry.id;
2334 	extension |= SOF_IPC4_MOD_EXT_DST_MOD_INSTANCE(sink_widget->instance_id);
2335 	extension |= SOF_IPC4_MOD_EXT_DST_MOD_QUEUE_ID(sroute->dst_queue_id);
2336 	extension |= SOF_IPC4_MOD_EXT_SRC_MOD_QUEUE_ID(sroute->src_queue_id);
2337 
2338 	msg.primary = header;
2339 	msg.extension = extension;
2340 
2341 	ret = sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0);
2342 	if (ret < 0)
2343 		dev_err(sdev->dev, "failed to unbind modules %s:%d -> %s:%d\n",
2344 			src_widget->widget->name, sroute->src_queue_id,
2345 			sink_widget->widget->name, sroute->dst_queue_id);
2346 out:
2347 	sof_ipc4_put_queue_id(sink_widget, sroute->dst_queue_id, SOF_PIN_TYPE_INPUT);
2348 	sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id, SOF_PIN_TYPE_OUTPUT);
2349 
2350 	return ret;
2351 }
2352 
2353 static int sof_ipc4_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
2354 			       unsigned int flags, struct snd_sof_dai_config_data *data)
2355 {
2356 	struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
2357 	struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
2358 	struct snd_sof_dai *dai = swidget->private;
2359 	struct sof_ipc4_gtw_attributes *gtw_attr;
2360 	struct sof_ipc4_copier_data *copier_data;
2361 	struct sof_ipc4_copier *ipc4_copier;
2362 
2363 	if (!dai || !dai->private) {
2364 		dev_err(sdev->dev, "Invalid DAI or DAI private data for %s\n",
2365 			swidget->widget->name);
2366 		return -EINVAL;
2367 	}
2368 
2369 	ipc4_copier = (struct sof_ipc4_copier *)dai->private;
2370 	copier_data = &ipc4_copier->data;
2371 
2372 	if (!data)
2373 		return 0;
2374 
2375 	switch (ipc4_copier->dai_type) {
2376 	case SOF_DAI_INTEL_HDA:
2377 		gtw_attr = ipc4_copier->gtw_attr;
2378 		gtw_attr->lp_buffer_alloc = pipeline->lp_mode;
2379 		pipeline->skip_during_fe_trigger = true;
2380 		fallthrough;
2381 	case SOF_DAI_INTEL_ALH:
2382 		/*
2383 		 * Do not clear the node ID when this op is invoked with
2384 		 * SOF_DAI_CONFIG_FLAGS_HW_FREE. It is needed to free the group_ida during
2385 		 * unprepare.
2386 		 */
2387 		if (flags & SOF_DAI_CONFIG_FLAGS_HW_PARAMS) {
2388 			copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
2389 			copier_data->gtw_cfg.node_id |= SOF_IPC4_NODE_INDEX(data->dai_data);
2390 		}
2391 		break;
2392 	case SOF_DAI_INTEL_DMIC:
2393 	case SOF_DAI_INTEL_SSP:
2394 		/* nothing to do for SSP/DMIC */
2395 		break;
2396 	default:
2397 		dev_err(sdev->dev, "%s: unsupported dai type %d\n", __func__,
2398 			ipc4_copier->dai_type);
2399 		return -EINVAL;
2400 	}
2401 
2402 	return 0;
2403 }
2404 
2405 static int sof_ipc4_parse_manifest(struct snd_soc_component *scomp, int index,
2406 				   struct snd_soc_tplg_manifest *man)
2407 {
2408 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
2409 	struct sof_ipc4_fw_data *ipc4_data = sdev->private;
2410 	struct sof_manifest_tlv *manifest_tlv;
2411 	struct sof_manifest *manifest;
2412 	u32 size = le32_to_cpu(man->priv.size);
2413 	u8 *man_ptr = man->priv.data;
2414 	u32 len_check;
2415 	int i;
2416 
2417 	if (!size || size < SOF_IPC4_TPLG_ABI_SIZE) {
2418 		dev_err(scomp->dev, "%s: Invalid topology ABI size: %u\n",
2419 			__func__, size);
2420 		return -EINVAL;
2421 	}
2422 
2423 	manifest = (struct sof_manifest *)man_ptr;
2424 
2425 	dev_info(scomp->dev,
2426 		 "Topology: ABI %d:%d:%d Kernel ABI %u:%u:%u\n",
2427 		  le16_to_cpu(manifest->abi_major), le16_to_cpu(manifest->abi_minor),
2428 		  le16_to_cpu(manifest->abi_patch),
2429 		  SOF_ABI_MAJOR, SOF_ABI_MINOR, SOF_ABI_PATCH);
2430 
2431 	/* TODO: Add ABI compatibility check */
2432 
2433 	/* no more data after the ABI version */
2434 	if (size <= SOF_IPC4_TPLG_ABI_SIZE)
2435 		return 0;
2436 
2437 	manifest_tlv = manifest->items;
2438 	len_check = sizeof(struct sof_manifest);
2439 	for (i = 0; i < le16_to_cpu(manifest->count); i++) {
2440 		len_check += sizeof(struct sof_manifest_tlv) + le32_to_cpu(manifest_tlv->size);
2441 		if (len_check > size)
2442 			return -EINVAL;
2443 
2444 		switch (le32_to_cpu(manifest_tlv->type)) {
2445 		case SOF_MANIFEST_DATA_TYPE_NHLT:
2446 			/* no NHLT in BIOS, so use the one from topology manifest */
2447 			if (ipc4_data->nhlt)
2448 				break;
2449 			ipc4_data->nhlt = devm_kmemdup(sdev->dev, manifest_tlv->data,
2450 						       le32_to_cpu(manifest_tlv->size), GFP_KERNEL);
2451 			if (!ipc4_data->nhlt)
2452 				return -ENOMEM;
2453 			break;
2454 		default:
2455 			dev_warn(scomp->dev, "Skipping unknown manifest data type %d\n",
2456 				 manifest_tlv->type);
2457 			break;
2458 		}
2459 		man_ptr += sizeof(struct sof_manifest_tlv) + le32_to_cpu(manifest_tlv->size);
2460 		manifest_tlv = (struct sof_manifest_tlv *)man_ptr;
2461 	}
2462 
2463 	return 0;
2464 }
2465 
2466 static int sof_ipc4_dai_get_clk(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, int clk_type)
2467 {
2468 	struct sof_ipc4_copier *ipc4_copier = dai->private;
2469 	struct snd_soc_tplg_hw_config *hw_config;
2470 	struct snd_sof_dai_link *slink;
2471 	bool dai_link_found = false;
2472 	bool hw_cfg_found = false;
2473 	int i;
2474 
2475 	if (!ipc4_copier)
2476 		return 0;
2477 
2478 	list_for_each_entry(slink, &sdev->dai_link_list, list) {
2479 		if (!strcmp(slink->link->name, dai->name)) {
2480 			dai_link_found = true;
2481 			break;
2482 		}
2483 	}
2484 
2485 	if (!dai_link_found) {
2486 		dev_err(sdev->dev, "no DAI link found for DAI %s\n", dai->name);
2487 		return -EINVAL;
2488 	}
2489 
2490 	for (i = 0; i < slink->num_hw_configs; i++) {
2491 		hw_config = &slink->hw_configs[i];
2492 		if (dai->current_config == le32_to_cpu(hw_config->id)) {
2493 			hw_cfg_found = true;
2494 			break;
2495 		}
2496 	}
2497 
2498 	if (!hw_cfg_found) {
2499 		dev_err(sdev->dev, "no matching hw_config found for DAI %s\n", dai->name);
2500 		return -EINVAL;
2501 	}
2502 
2503 	switch (ipc4_copier->dai_type) {
2504 	case SOF_DAI_INTEL_SSP:
2505 		switch (clk_type) {
2506 		case SOF_DAI_CLK_INTEL_SSP_MCLK:
2507 			return le32_to_cpu(hw_config->mclk_rate);
2508 		case SOF_DAI_CLK_INTEL_SSP_BCLK:
2509 			return le32_to_cpu(hw_config->bclk_rate);
2510 		default:
2511 			dev_err(sdev->dev, "Invalid clk type for SSP %d\n", clk_type);
2512 			break;
2513 		}
2514 		break;
2515 	default:
2516 		dev_err(sdev->dev, "DAI type %d not supported yet!\n", ipc4_copier->dai_type);
2517 		break;
2518 	}
2519 
2520 	return -EINVAL;
2521 }
2522 
2523 static int sof_ipc4_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verify)
2524 {
2525 	struct snd_sof_pcm *spcm;
2526 	int dir, ret;
2527 
2528 	/*
2529 	 * This function is called during system suspend, we need to make sure
2530 	 * that all streams have been freed up.
2531 	 * Freeing might have been skipped when xrun happened just at the start
2532 	 * of the suspend and it sent a SNDRV_PCM_TRIGGER_STOP to the active
2533 	 * stream. This will call sof_pcm_stream_free() with
2534 	 * free_widget_list = false which will leave the kernel and firmware out
2535 	 * of sync during suspend/resume.
2536 	 *
2537 	 * This will also make sure that paused streams handled correctly.
2538 	 */
2539 	list_for_each_entry(spcm, &sdev->pcm_list, list) {
2540 		for_each_pcm_streams(dir) {
2541 			struct snd_pcm_substream *substream = spcm->stream[dir].substream;
2542 
2543 			if (!substream || !substream->runtime || spcm->stream[dir].suspend_ignored)
2544 				continue;
2545 
2546 			if (spcm->stream[dir].list) {
2547 				ret = sof_pcm_stream_free(sdev, substream, spcm, dir, true);
2548 				if (ret < 0)
2549 					return ret;
2550 			}
2551 		}
2552 	}
2553 	return 0;
2554 }
2555 
2556 static int sof_ipc4_link_setup(struct snd_sof_dev *sdev, struct snd_soc_dai_link *link)
2557 {
2558 	if (link->no_pcm)
2559 		return 0;
2560 
2561 	/*
2562 	 * set default trigger order for all links. Exceptions to
2563 	 * the rule will be handled in sof_pcm_dai_link_fixup()
2564 	 * For playback, the sequence is the following: start BE,
2565 	 * start FE, stop FE, stop BE; for Capture the sequence is
2566 	 * inverted start FE, start BE, stop BE, stop FE
2567 	 */
2568 	link->trigger[SNDRV_PCM_STREAM_PLAYBACK] = SND_SOC_DPCM_TRIGGER_POST;
2569 	link->trigger[SNDRV_PCM_STREAM_CAPTURE] = SND_SOC_DPCM_TRIGGER_PRE;
2570 
2571 	return 0;
2572 }
2573 
2574 static enum sof_tokens common_copier_token_list[] = {
2575 	SOF_COMP_TOKENS,
2576 	SOF_AUDIO_FMT_NUM_TOKENS,
2577 	SOF_IN_AUDIO_FORMAT_TOKENS,
2578 	SOF_OUT_AUDIO_FORMAT_TOKENS,
2579 	SOF_COPIER_DEEP_BUFFER_TOKENS,
2580 	SOF_COPIER_TOKENS,
2581 	SOF_COMP_EXT_TOKENS,
2582 };
2583 
2584 static enum sof_tokens pipeline_token_list[] = {
2585 	SOF_SCHED_TOKENS,
2586 	SOF_PIPELINE_TOKENS,
2587 };
2588 
2589 static enum sof_tokens dai_token_list[] = {
2590 	SOF_COMP_TOKENS,
2591 	SOF_AUDIO_FMT_NUM_TOKENS,
2592 	SOF_IN_AUDIO_FORMAT_TOKENS,
2593 	SOF_OUT_AUDIO_FORMAT_TOKENS,
2594 	SOF_COPIER_TOKENS,
2595 	SOF_DAI_TOKENS,
2596 	SOF_COMP_EXT_TOKENS,
2597 };
2598 
2599 static enum sof_tokens pga_token_list[] = {
2600 	SOF_COMP_TOKENS,
2601 	SOF_GAIN_TOKENS,
2602 	SOF_AUDIO_FMT_NUM_TOKENS,
2603 	SOF_IN_AUDIO_FORMAT_TOKENS,
2604 	SOF_OUT_AUDIO_FORMAT_TOKENS,
2605 	SOF_COMP_EXT_TOKENS,
2606 };
2607 
2608 static enum sof_tokens mixer_token_list[] = {
2609 	SOF_COMP_TOKENS,
2610 	SOF_AUDIO_FMT_NUM_TOKENS,
2611 	SOF_IN_AUDIO_FORMAT_TOKENS,
2612 	SOF_OUT_AUDIO_FORMAT_TOKENS,
2613 	SOF_COMP_EXT_TOKENS,
2614 };
2615 
2616 static enum sof_tokens src_token_list[] = {
2617 	SOF_COMP_TOKENS,
2618 	SOF_SRC_TOKENS,
2619 	SOF_AUDIO_FMT_NUM_TOKENS,
2620 	SOF_IN_AUDIO_FORMAT_TOKENS,
2621 	SOF_OUT_AUDIO_FORMAT_TOKENS,
2622 	SOF_COMP_EXT_TOKENS,
2623 };
2624 
2625 static enum sof_tokens process_token_list[] = {
2626 	SOF_COMP_TOKENS,
2627 	SOF_AUDIO_FMT_NUM_TOKENS,
2628 	SOF_IN_AUDIO_FORMAT_TOKENS,
2629 	SOF_OUT_AUDIO_FORMAT_TOKENS,
2630 	SOF_COMP_EXT_TOKENS,
2631 };
2632 
2633 static const struct sof_ipc_tplg_widget_ops tplg_ipc4_widget_ops[SND_SOC_DAPM_TYPE_COUNT] = {
2634 	[snd_soc_dapm_aif_in] =  {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm,
2635 				  common_copier_token_list, ARRAY_SIZE(common_copier_token_list),
2636 				  NULL, sof_ipc4_prepare_copier_module,
2637 				  sof_ipc4_unprepare_copier_module},
2638 	[snd_soc_dapm_aif_out] = {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm,
2639 				  common_copier_token_list, ARRAY_SIZE(common_copier_token_list),
2640 				  NULL, sof_ipc4_prepare_copier_module,
2641 				  sof_ipc4_unprepare_copier_module},
2642 	[snd_soc_dapm_dai_in] = {sof_ipc4_widget_setup_comp_dai, sof_ipc4_widget_free_comp_dai,
2643 				 dai_token_list, ARRAY_SIZE(dai_token_list), NULL,
2644 				 sof_ipc4_prepare_copier_module,
2645 				 sof_ipc4_unprepare_copier_module},
2646 	[snd_soc_dapm_dai_out] = {sof_ipc4_widget_setup_comp_dai, sof_ipc4_widget_free_comp_dai,
2647 				  dai_token_list, ARRAY_SIZE(dai_token_list), NULL,
2648 				  sof_ipc4_prepare_copier_module,
2649 				  sof_ipc4_unprepare_copier_module},
2650 	[snd_soc_dapm_buffer] = {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm,
2651 				 common_copier_token_list, ARRAY_SIZE(common_copier_token_list),
2652 				 NULL, sof_ipc4_prepare_copier_module,
2653 				 sof_ipc4_unprepare_copier_module},
2654 	[snd_soc_dapm_scheduler] = {sof_ipc4_widget_setup_comp_pipeline,
2655 				    sof_ipc4_widget_free_comp_pipeline,
2656 				    pipeline_token_list, ARRAY_SIZE(pipeline_token_list), NULL,
2657 				    NULL, NULL},
2658 	[snd_soc_dapm_pga] = {sof_ipc4_widget_setup_comp_pga, sof_ipc4_widget_free_comp_pga,
2659 			      pga_token_list, ARRAY_SIZE(pga_token_list), NULL,
2660 			      sof_ipc4_prepare_gain_module,
2661 			      NULL},
2662 	[snd_soc_dapm_mixer] = {sof_ipc4_widget_setup_comp_mixer, sof_ipc4_widget_free_comp_mixer,
2663 				mixer_token_list, ARRAY_SIZE(mixer_token_list),
2664 				NULL, sof_ipc4_prepare_mixer_module,
2665 				NULL},
2666 	[snd_soc_dapm_src] = {sof_ipc4_widget_setup_comp_src, sof_ipc4_widget_free_comp_src,
2667 				src_token_list, ARRAY_SIZE(src_token_list),
2668 				NULL, sof_ipc4_prepare_src_module,
2669 				NULL},
2670 	[snd_soc_dapm_effect] = {sof_ipc4_widget_setup_comp_process,
2671 				sof_ipc4_widget_free_comp_process,
2672 				process_token_list, ARRAY_SIZE(process_token_list),
2673 				NULL, sof_ipc4_prepare_process_module,
2674 				NULL},
2675 };
2676 
2677 const struct sof_ipc_tplg_ops ipc4_tplg_ops = {
2678 	.widget = tplg_ipc4_widget_ops,
2679 	.token_list = ipc4_token_list,
2680 	.control_setup = sof_ipc4_control_setup,
2681 	.control = &tplg_ipc4_control_ops,
2682 	.widget_setup = sof_ipc4_widget_setup,
2683 	.widget_free = sof_ipc4_widget_free,
2684 	.route_setup = sof_ipc4_route_setup,
2685 	.route_free = sof_ipc4_route_free,
2686 	.dai_config = sof_ipc4_dai_config,
2687 	.parse_manifest = sof_ipc4_parse_manifest,
2688 	.dai_get_clk = sof_ipc4_dai_get_clk,
2689 	.tear_down_all_pipelines = sof_ipc4_tear_down_all_pipelines,
2690 	.link_setup = sof_ipc4_link_setup,
2691 };
2692