xref: /openbmc/linux/sound/soc/sof/ipc4-topology.c (revision 5626af8f)
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 <uapi/sound/sof/tokens.h>
10 #include <sound/pcm_params.h>
11 #include <sound/sof/ext_manifest4.h>
12 #include <sound/intel-nhlt.h>
13 #include "sof-priv.h"
14 #include "sof-audio.h"
15 #include "ipc4-priv.h"
16 #include "ipc4-topology.h"
17 #include "ops.h"
18 
19 #define SOF_IPC4_GAIN_PARAM_ID  0
20 #define SOF_IPC4_TPLG_ABI_SIZE 6
21 
22 static DEFINE_IDA(alh_group_ida);
23 static DEFINE_IDA(pipeline_ida);
24 
25 static const struct sof_topology_token ipc4_sched_tokens[] = {
26 	{SOF_TKN_SCHED_LP_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
27 		offsetof(struct sof_ipc4_pipeline, lp_mode)}
28 };
29 
30 static const struct sof_topology_token pipeline_tokens[] = {
31 	{SOF_TKN_SCHED_DYNAMIC_PIPELINE, SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16,
32 		offsetof(struct snd_sof_widget, dynamic_pipeline_widget)},
33 };
34 
35 static const struct sof_topology_token ipc4_comp_tokens[] = {
36 	{SOF_TKN_COMP_CPC, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
37 		offsetof(struct sof_ipc4_base_module_cfg, cpc)},
38 	{SOF_TKN_COMP_IS_PAGES, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
39 		offsetof(struct sof_ipc4_base_module_cfg, is_pages)},
40 };
41 
42 static const struct sof_topology_token ipc4_audio_format_buffer_size_tokens[] = {
43 	{SOF_TKN_CAVS_AUDIO_FORMAT_IBS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
44 		offsetof(struct sof_ipc4_base_module_cfg, ibs)},
45 	{SOF_TKN_CAVS_AUDIO_FORMAT_OBS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
46 		offsetof(struct sof_ipc4_base_module_cfg, obs)},
47 };
48 
49 static const struct sof_topology_token ipc4_in_audio_format_tokens[] = {
50 	{SOF_TKN_CAVS_AUDIO_FORMAT_IN_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
51 		offsetof(struct sof_ipc4_audio_format, sampling_frequency)},
52 	{SOF_TKN_CAVS_AUDIO_FORMAT_IN_BIT_DEPTH, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
53 		offsetof(struct sof_ipc4_audio_format, bit_depth)},
54 	{SOF_TKN_CAVS_AUDIO_FORMAT_IN_CH_MAP, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
55 		offsetof(struct sof_ipc4_audio_format, ch_map)},
56 	{SOF_TKN_CAVS_AUDIO_FORMAT_IN_CH_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
57 		offsetof(struct sof_ipc4_audio_format, ch_cfg)},
58 	{SOF_TKN_CAVS_AUDIO_FORMAT_IN_INTERLEAVING_STYLE, SND_SOC_TPLG_TUPLE_TYPE_WORD,
59 		get_token_u32, offsetof(struct sof_ipc4_audio_format, interleaving_style)},
60 	{SOF_TKN_CAVS_AUDIO_FORMAT_IN_FMT_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
61 		offsetof(struct sof_ipc4_audio_format, fmt_cfg)},
62 };
63 
64 static const struct sof_topology_token ipc4_out_audio_format_tokens[] = {
65 	{SOF_TKN_CAVS_AUDIO_FORMAT_OUT_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
66 		offsetof(struct sof_ipc4_audio_format, sampling_frequency)},
67 	{SOF_TKN_CAVS_AUDIO_FORMAT_OUT_BIT_DEPTH, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
68 		offsetof(struct sof_ipc4_audio_format, bit_depth)},
69 	{SOF_TKN_CAVS_AUDIO_FORMAT_OUT_CH_MAP, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
70 		offsetof(struct sof_ipc4_audio_format, ch_map)},
71 	{SOF_TKN_CAVS_AUDIO_FORMAT_OUT_CH_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
72 		offsetof(struct sof_ipc4_audio_format, ch_cfg)},
73 	{SOF_TKN_CAVS_AUDIO_FORMAT_OUT_INTERLEAVING_STYLE, SND_SOC_TPLG_TUPLE_TYPE_WORD,
74 		get_token_u32, offsetof(struct sof_ipc4_audio_format, interleaving_style)},
75 	{SOF_TKN_CAVS_AUDIO_FORMAT_OUT_FMT_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
76 		offsetof(struct sof_ipc4_audio_format, fmt_cfg)},
77 };
78 
79 static const struct sof_topology_token ipc4_copier_gateway_cfg_tokens[] = {
80 	{SOF_TKN_CAVS_AUDIO_FORMAT_DMA_BUFFER_SIZE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 0},
81 };
82 
83 static const struct sof_topology_token ipc4_copier_tokens[] = {
84 	{SOF_TKN_INTEL_COPIER_NODE_TYPE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 0},
85 };
86 
87 static const struct sof_topology_token ipc4_audio_fmt_num_tokens[] = {
88 	{SOF_TKN_COMP_NUM_AUDIO_FORMATS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
89 		0},
90 };
91 
92 static const struct sof_topology_token dai_tokens[] = {
93 	{SOF_TKN_DAI_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_dai_type,
94 		offsetof(struct sof_ipc4_copier, dai_type)},
95 	{SOF_TKN_DAI_INDEX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
96 		offsetof(struct sof_ipc4_copier, dai_index)},
97 };
98 
99 /* Component extended tokens */
100 static const struct sof_topology_token comp_ext_tokens[] = {
101 	{SOF_TKN_COMP_UUID, SND_SOC_TPLG_TUPLE_TYPE_UUID, get_token_uuid,
102 		offsetof(struct snd_sof_widget, uuid)},
103 };
104 
105 static const struct sof_topology_token gain_tokens[] = {
106 	{SOF_TKN_GAIN_RAMP_TYPE, SND_SOC_TPLG_TUPLE_TYPE_WORD,
107 		get_token_u32, offsetof(struct sof_ipc4_gain_data, curve_type)},
108 	{SOF_TKN_GAIN_RAMP_DURATION,
109 		SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
110 		offsetof(struct sof_ipc4_gain_data, curve_duration)},
111 	{SOF_TKN_GAIN_VAL, SND_SOC_TPLG_TUPLE_TYPE_WORD,
112 		get_token_u32, offsetof(struct sof_ipc4_gain_data, init_val)},
113 };
114 
115 /* SRC */
116 static const struct sof_topology_token src_tokens[] = {
117 	{SOF_TKN_SRC_RATE_OUT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
118 		offsetof(struct sof_ipc4_src, sink_rate)},
119 };
120 
121 static const struct sof_token_info ipc4_token_list[SOF_TOKEN_COUNT] = {
122 	[SOF_DAI_TOKENS] = {"DAI tokens", dai_tokens, ARRAY_SIZE(dai_tokens)},
123 	[SOF_PIPELINE_TOKENS] = {"Pipeline tokens", pipeline_tokens, ARRAY_SIZE(pipeline_tokens)},
124 	[SOF_SCHED_TOKENS] = {"Scheduler tokens", ipc4_sched_tokens,
125 		ARRAY_SIZE(ipc4_sched_tokens)},
126 	[SOF_COMP_EXT_TOKENS] = {"Comp extended tokens", comp_ext_tokens,
127 		ARRAY_SIZE(comp_ext_tokens)},
128 	[SOF_COMP_TOKENS] = {"IPC4 Component tokens",
129 		ipc4_comp_tokens, ARRAY_SIZE(ipc4_comp_tokens)},
130 	[SOF_IN_AUDIO_FORMAT_TOKENS] = {"IPC4 Input Audio format tokens",
131 		ipc4_in_audio_format_tokens, ARRAY_SIZE(ipc4_in_audio_format_tokens)},
132 	[SOF_OUT_AUDIO_FORMAT_TOKENS] = {"IPC4 Output Audio format tokens",
133 		ipc4_out_audio_format_tokens, ARRAY_SIZE(ipc4_out_audio_format_tokens)},
134 	[SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS] = {"IPC4 Audio format buffer size tokens",
135 		ipc4_audio_format_buffer_size_tokens,
136 		ARRAY_SIZE(ipc4_audio_format_buffer_size_tokens)},
137 	[SOF_COPIER_GATEWAY_CFG_TOKENS] = {"IPC4 Copier gateway config tokens",
138 		ipc4_copier_gateway_cfg_tokens, ARRAY_SIZE(ipc4_copier_gateway_cfg_tokens)},
139 	[SOF_COPIER_TOKENS] = {"IPC4 Copier tokens", ipc4_copier_tokens,
140 		ARRAY_SIZE(ipc4_copier_tokens)},
141 	[SOF_AUDIO_FMT_NUM_TOKENS] = {"IPC4 Audio format number tokens",
142 		ipc4_audio_fmt_num_tokens, ARRAY_SIZE(ipc4_audio_fmt_num_tokens)},
143 	[SOF_GAIN_TOKENS] = {"Gain tokens", gain_tokens, ARRAY_SIZE(gain_tokens)},
144 	[SOF_SRC_TOKENS] = {"SRC tokens", src_tokens, ARRAY_SIZE(src_tokens)},
145 };
146 
147 static void sof_ipc4_dbg_audio_format(struct device *dev,
148 				      struct sof_ipc4_audio_format *format,
149 				      size_t object_size, int num_format)
150 {
151 	struct sof_ipc4_audio_format *fmt;
152 	void *ptr = format;
153 	int i;
154 
155 	for (i = 0; i < num_format; i++, ptr = (u8 *)ptr + object_size) {
156 		fmt = ptr;
157 		dev_dbg(dev,
158 			" #%d: %uKHz, %ubit (ch_map %#x ch_cfg %u interleaving_style %u fmt_cfg %#x)\n",
159 			i, fmt->sampling_frequency, fmt->bit_depth, fmt->ch_map,
160 			fmt->ch_cfg, fmt->interleaving_style, fmt->fmt_cfg);
161 	}
162 }
163 
164 /**
165  * sof_ipc4_get_audio_fmt - get available audio formats from swidget->tuples
166  * @scomp: pointer to pointer to SOC component
167  * @swidget: pointer to struct snd_sof_widget containing tuples
168  * @available_fmt: pointer to struct sof_ipc4_available_audio_format being filling in
169  * @has_out_format: true if available_fmt contains output format
170  *
171  * Return: 0 if successful
172  */
173 static int sof_ipc4_get_audio_fmt(struct snd_soc_component *scomp,
174 				  struct snd_sof_widget *swidget,
175 				  struct sof_ipc4_available_audio_format *available_fmt,
176 				  bool has_out_format)
177 {
178 	struct sof_ipc4_base_module_cfg *base_config;
179 	struct sof_ipc4_audio_format *out_format;
180 	int audio_fmt_num = 0;
181 	int ret, i;
182 
183 	ret = sof_update_ipc_object(scomp, &audio_fmt_num,
184 				    SOF_AUDIO_FMT_NUM_TOKENS, swidget->tuples,
185 				    swidget->num_tuples, sizeof(audio_fmt_num), 1);
186 	if (ret || audio_fmt_num <= 0) {
187 		dev_err(scomp->dev, "Invalid number of audio formats: %d\n", audio_fmt_num);
188 		return -EINVAL;
189 	}
190 	available_fmt->audio_fmt_num = audio_fmt_num;
191 
192 	dev_dbg(scomp->dev, "Number of audio formats: %d\n", available_fmt->audio_fmt_num);
193 
194 	base_config = kcalloc(available_fmt->audio_fmt_num, sizeof(*base_config), GFP_KERNEL);
195 	if (!base_config)
196 		return -ENOMEM;
197 
198 	/* set cpc and is_pages for all base_cfg */
199 	for (i = 0; i < available_fmt->audio_fmt_num; i++) {
200 		ret = sof_update_ipc_object(scomp, &base_config[i],
201 					    SOF_COMP_TOKENS, swidget->tuples,
202 					    swidget->num_tuples, sizeof(*base_config), 1);
203 		if (ret) {
204 			dev_err(scomp->dev, "parse comp tokens failed %d\n", ret);
205 			goto err_in;
206 		}
207 	}
208 
209 	/* copy the ibs/obs for each base_cfg */
210 	ret = sof_update_ipc_object(scomp, base_config,
211 				    SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS, swidget->tuples,
212 				    swidget->num_tuples, sizeof(*base_config),
213 				    available_fmt->audio_fmt_num);
214 	if (ret) {
215 		dev_err(scomp->dev, "parse buffer size tokens failed %d\n", ret);
216 		goto err_in;
217 	}
218 
219 	for (i = 0; i < available_fmt->audio_fmt_num; i++)
220 		dev_dbg(scomp->dev, "%d: ibs: %d obs: %d cpc: %d is_pages: %d\n", i,
221 			base_config[i].ibs, base_config[i].obs,
222 			base_config[i].cpc, base_config[i].is_pages);
223 
224 	ret = sof_update_ipc_object(scomp, &base_config->audio_fmt,
225 				    SOF_IN_AUDIO_FORMAT_TOKENS, swidget->tuples,
226 				    swidget->num_tuples, sizeof(*base_config),
227 				    available_fmt->audio_fmt_num);
228 	if (ret) {
229 		dev_err(scomp->dev, "parse base_config audio_fmt tokens failed %d\n", ret);
230 		goto err_in;
231 	}
232 
233 	dev_dbg(scomp->dev, "Get input audio formats for %s\n", swidget->widget->name);
234 	sof_ipc4_dbg_audio_format(scomp->dev, &base_config->audio_fmt,
235 				  sizeof(*base_config),
236 				  available_fmt->audio_fmt_num);
237 
238 	available_fmt->base_config = base_config;
239 
240 	if (!has_out_format)
241 		return 0;
242 
243 	out_format = kcalloc(available_fmt->audio_fmt_num, sizeof(*out_format), GFP_KERNEL);
244 	if (!out_format) {
245 		ret = -ENOMEM;
246 		goto err_in;
247 	}
248 
249 	ret = sof_update_ipc_object(scomp, out_format,
250 				    SOF_OUT_AUDIO_FORMAT_TOKENS, swidget->tuples,
251 				    swidget->num_tuples, sizeof(*out_format),
252 				    available_fmt->audio_fmt_num);
253 
254 	if (ret) {
255 		dev_err(scomp->dev, "parse output audio_fmt tokens failed\n");
256 		goto err_out;
257 	}
258 
259 	available_fmt->out_audio_fmt = out_format;
260 	dev_dbg(scomp->dev, "Get output audio formats for %s\n", swidget->widget->name);
261 	sof_ipc4_dbg_audio_format(scomp->dev, out_format, sizeof(*out_format),
262 				  available_fmt->audio_fmt_num);
263 
264 	return 0;
265 
266 err_out:
267 	kfree(out_format);
268 err_in:
269 	kfree(base_config);
270 
271 	return ret;
272 }
273 
274 /* release the memory allocated in sof_ipc4_get_audio_fmt */
275 static void sof_ipc4_free_audio_fmt(struct sof_ipc4_available_audio_format *available_fmt)
276 
277 {
278 	kfree(available_fmt->base_config);
279 	available_fmt->base_config = NULL;
280 	kfree(available_fmt->out_audio_fmt);
281 	available_fmt->out_audio_fmt = NULL;
282 }
283 
284 static void sof_ipc4_widget_free_comp_pipeline(struct snd_sof_widget *swidget)
285 {
286 	kfree(swidget->private);
287 }
288 
289 static int sof_ipc4_widget_set_module_info(struct snd_sof_widget *swidget)
290 {
291 	struct snd_soc_component *scomp = swidget->scomp;
292 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
293 
294 	swidget->module_info = sof_ipc4_find_module_by_uuid(sdev, &swidget->uuid);
295 
296 	if (swidget->module_info)
297 		return 0;
298 
299 	dev_err(sdev->dev, "failed to find module info for widget %s with UUID %pUL\n",
300 		swidget->widget->name, &swidget->uuid);
301 	return -EINVAL;
302 }
303 
304 static int sof_ipc4_widget_setup_msg(struct snd_sof_widget *swidget, struct sof_ipc4_msg *msg)
305 {
306 	struct sof_ipc4_fw_module *fw_module;
307 	uint32_t type;
308 	int ret;
309 
310 	ret = sof_ipc4_widget_set_module_info(swidget);
311 	if (ret)
312 		return ret;
313 
314 	fw_module = swidget->module_info;
315 
316 	msg->primary = fw_module->man4_module_entry.id;
317 	msg->primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_INIT_INSTANCE);
318 	msg->primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
319 	msg->primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
320 
321 	msg->extension = SOF_IPC4_MOD_EXT_CORE_ID(swidget->core);
322 
323 	type = (fw_module->man4_module_entry.type & SOF_IPC4_MODULE_DP) ? 1 : 0;
324 	msg->extension |= SOF_IPC4_MOD_EXT_DOMAIN(type);
325 
326 	return 0;
327 }
328 
329 static int sof_ipc4_widget_setup_pcm(struct snd_sof_widget *swidget)
330 {
331 	struct sof_ipc4_available_audio_format *available_fmt;
332 	struct snd_soc_component *scomp = swidget->scomp;
333 	struct sof_ipc4_copier *ipc4_copier;
334 	int node_type = 0;
335 	int ret, i;
336 
337 	ipc4_copier = kzalloc(sizeof(*ipc4_copier), GFP_KERNEL);
338 	if (!ipc4_copier)
339 		return -ENOMEM;
340 
341 	swidget->private = ipc4_copier;
342 	available_fmt = &ipc4_copier->available_fmt;
343 
344 	dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name);
345 
346 	ret = sof_ipc4_get_audio_fmt(scomp, swidget, available_fmt, true);
347 	if (ret)
348 		goto free_copier;
349 
350 	available_fmt->dma_buffer_size = kcalloc(available_fmt->audio_fmt_num, sizeof(u32),
351 						 GFP_KERNEL);
352 	if (!available_fmt->dma_buffer_size) {
353 		ret = -ENOMEM;
354 		goto free_available_fmt;
355 	}
356 
357 	ret = sof_update_ipc_object(scomp, available_fmt->dma_buffer_size,
358 				    SOF_COPIER_GATEWAY_CFG_TOKENS, swidget->tuples,
359 				    swidget->num_tuples, sizeof(u32),
360 				    available_fmt->audio_fmt_num);
361 	if (ret) {
362 		dev_err(scomp->dev, "Failed to parse dma buffer size in audio format for %s\n",
363 			swidget->widget->name);
364 		goto err;
365 	}
366 
367 	dev_dbg(scomp->dev, "dma buffer size:\n");
368 	for (i = 0; i < available_fmt->audio_fmt_num; i++)
369 		dev_dbg(scomp->dev, "%d: %u\n", i,
370 			available_fmt->dma_buffer_size[i]);
371 
372 	ret = sof_update_ipc_object(scomp, &node_type,
373 				    SOF_COPIER_TOKENS, swidget->tuples,
374 				    swidget->num_tuples, sizeof(node_type), 1);
375 
376 	if (ret) {
377 		dev_err(scomp->dev, "parse host copier node type token failed %d\n",
378 			ret);
379 		goto err;
380 	}
381 	dev_dbg(scomp->dev, "host copier '%s' node_type %u\n", swidget->widget->name, node_type);
382 
383 	ipc4_copier->data.gtw_cfg.node_id = SOF_IPC4_NODE_TYPE(node_type);
384 	ipc4_copier->gtw_attr = kzalloc(sizeof(*ipc4_copier->gtw_attr), GFP_KERNEL);
385 	if (!ipc4_copier->gtw_attr) {
386 		ret = -ENOMEM;
387 		goto err;
388 	}
389 
390 	ipc4_copier->copier_config = (uint32_t *)ipc4_copier->gtw_attr;
391 	ipc4_copier->data.gtw_cfg.config_length =
392 		sizeof(struct sof_ipc4_gtw_attributes) >> 2;
393 
394 	/* set up module info and message header */
395 	ret = sof_ipc4_widget_setup_msg(swidget, &ipc4_copier->msg);
396 	if (ret)
397 		goto free_gtw_attr;
398 
399 	return 0;
400 
401 free_gtw_attr:
402 	kfree(ipc4_copier->gtw_attr);
403 err:
404 	kfree(available_fmt->dma_buffer_size);
405 free_available_fmt:
406 	sof_ipc4_free_audio_fmt(available_fmt);
407 free_copier:
408 	kfree(ipc4_copier);
409 	swidget->private = NULL;
410 	return ret;
411 }
412 
413 static void sof_ipc4_widget_free_comp_pcm(struct snd_sof_widget *swidget)
414 {
415 	struct sof_ipc4_copier *ipc4_copier = swidget->private;
416 	struct sof_ipc4_available_audio_format *available_fmt;
417 
418 	if (!ipc4_copier)
419 		return;
420 
421 	available_fmt = &ipc4_copier->available_fmt;
422 	kfree(available_fmt->dma_buffer_size);
423 	kfree(available_fmt->base_config);
424 	kfree(available_fmt->out_audio_fmt);
425 	kfree(ipc4_copier->gtw_attr);
426 	kfree(ipc4_copier);
427 	swidget->private = NULL;
428 }
429 
430 static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget)
431 {
432 	struct sof_ipc4_available_audio_format *available_fmt;
433 	struct snd_soc_component *scomp = swidget->scomp;
434 	struct snd_sof_dai *dai = swidget->private;
435 	struct sof_ipc4_copier *ipc4_copier;
436 	int node_type = 0;
437 	int ret, i;
438 
439 	ipc4_copier = kzalloc(sizeof(*ipc4_copier), GFP_KERNEL);
440 	if (!ipc4_copier)
441 		return -ENOMEM;
442 
443 	available_fmt = &ipc4_copier->available_fmt;
444 
445 	dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name);
446 
447 	ret = sof_ipc4_get_audio_fmt(scomp, swidget, available_fmt, true);
448 	if (ret)
449 		goto free_copier;
450 
451 	available_fmt->dma_buffer_size = kcalloc(available_fmt->audio_fmt_num, sizeof(u32),
452 						 GFP_KERNEL);
453 	if (!available_fmt->dma_buffer_size) {
454 		ret = -ENOMEM;
455 		goto free_available_fmt;
456 	}
457 
458 	ret = sof_update_ipc_object(scomp, available_fmt->dma_buffer_size,
459 				    SOF_COPIER_GATEWAY_CFG_TOKENS, swidget->tuples,
460 				    swidget->num_tuples, sizeof(u32),
461 				    available_fmt->audio_fmt_num);
462 	if (ret) {
463 		dev_err(scomp->dev, "Failed to parse dma buffer size in audio format for %s\n",
464 			swidget->widget->name);
465 		goto err;
466 	}
467 
468 	for (i = 0; i < available_fmt->audio_fmt_num; i++)
469 		dev_dbg(scomp->dev, "%d: dma buffer size: %u\n", i,
470 			available_fmt->dma_buffer_size[i]);
471 
472 	ret = sof_update_ipc_object(scomp, &node_type,
473 				    SOF_COPIER_TOKENS, swidget->tuples,
474 				    swidget->num_tuples, sizeof(node_type), 1);
475 	if (ret) {
476 		dev_err(scomp->dev, "parse dai node type failed %d\n", ret);
477 		goto err;
478 	}
479 
480 	ret = sof_update_ipc_object(scomp, ipc4_copier,
481 				    SOF_DAI_TOKENS, swidget->tuples,
482 				    swidget->num_tuples, sizeof(u32), 1);
483 	if (ret) {
484 		dev_err(scomp->dev, "parse dai copier node token failed %d\n", ret);
485 		goto err;
486 	}
487 
488 	dev_dbg(scomp->dev, "dai %s node_type %u dai_type %u dai_index %d\n", swidget->widget->name,
489 		node_type, ipc4_copier->dai_type, ipc4_copier->dai_index);
490 
491 	ipc4_copier->data.gtw_cfg.node_id = SOF_IPC4_NODE_TYPE(node_type);
492 
493 	switch (ipc4_copier->dai_type) {
494 	case SOF_DAI_INTEL_ALH:
495 	{
496 		struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
497 		struct sof_ipc4_alh_configuration_blob *blob;
498 		struct snd_sof_widget *w;
499 
500 		blob = kzalloc(sizeof(*blob), GFP_KERNEL);
501 		if (!blob) {
502 			ret = -ENOMEM;
503 			goto err;
504 		}
505 
506 		list_for_each_entry(w, &sdev->widget_list, list) {
507 			if (w->widget->sname &&
508 			    strcmp(w->widget->sname, swidget->widget->sname))
509 				continue;
510 
511 			blob->alh_cfg.count++;
512 		}
513 
514 		ipc4_copier->copier_config = (uint32_t *)blob;
515 		ipc4_copier->data.gtw_cfg.config_length = sizeof(*blob) >> 2;
516 		break;
517 	}
518 	case SOF_DAI_INTEL_SSP:
519 		/* set SSP DAI index as the node_id */
520 		ipc4_copier->data.gtw_cfg.node_id |=
521 			SOF_IPC4_NODE_INDEX_INTEL_SSP(ipc4_copier->dai_index);
522 		break;
523 	case SOF_DAI_INTEL_DMIC:
524 		/* set DMIC DAI index as the node_id */
525 		ipc4_copier->data.gtw_cfg.node_id |=
526 			SOF_IPC4_NODE_INDEX_INTEL_DMIC(ipc4_copier->dai_index);
527 		break;
528 	default:
529 		ipc4_copier->gtw_attr = kzalloc(sizeof(*ipc4_copier->gtw_attr), GFP_KERNEL);
530 		if (!ipc4_copier->gtw_attr) {
531 			ret = -ENOMEM;
532 			goto err;
533 		}
534 
535 		ipc4_copier->copier_config = (uint32_t *)ipc4_copier->gtw_attr;
536 		ipc4_copier->data.gtw_cfg.config_length =
537 			sizeof(struct sof_ipc4_gtw_attributes) >> 2;
538 		break;
539 	}
540 
541 	dai->scomp = scomp;
542 	dai->private = ipc4_copier;
543 
544 	/* set up module info and message header */
545 	ret = sof_ipc4_widget_setup_msg(swidget, &ipc4_copier->msg);
546 	if (ret)
547 		goto free_copier_config;
548 
549 	return 0;
550 
551 free_copier_config:
552 	kfree(ipc4_copier->copier_config);
553 err:
554 	kfree(available_fmt->dma_buffer_size);
555 free_available_fmt:
556 	sof_ipc4_free_audio_fmt(available_fmt);
557 free_copier:
558 	kfree(ipc4_copier);
559 	dai->private = NULL;
560 	dai->scomp = NULL;
561 	return ret;
562 }
563 
564 static void sof_ipc4_widget_free_comp_dai(struct snd_sof_widget *swidget)
565 {
566 	struct sof_ipc4_available_audio_format *available_fmt;
567 	struct snd_sof_dai *dai = swidget->private;
568 	struct sof_ipc4_copier *ipc4_copier;
569 
570 	if (!dai)
571 		return;
572 
573 	if (!dai->private) {
574 		kfree(dai);
575 		swidget->private = NULL;
576 		return;
577 	}
578 
579 	ipc4_copier = dai->private;
580 	available_fmt = &ipc4_copier->available_fmt;
581 
582 	kfree(available_fmt->dma_buffer_size);
583 	kfree(available_fmt->base_config);
584 	kfree(available_fmt->out_audio_fmt);
585 	if (ipc4_copier->dai_type != SOF_DAI_INTEL_SSP &&
586 	    ipc4_copier->dai_type != SOF_DAI_INTEL_DMIC)
587 		kfree(ipc4_copier->copier_config);
588 	kfree(dai->private);
589 	kfree(dai);
590 	swidget->private = NULL;
591 }
592 
593 static int sof_ipc4_widget_setup_comp_pipeline(struct snd_sof_widget *swidget)
594 {
595 	struct snd_soc_component *scomp = swidget->scomp;
596 	struct sof_ipc4_pipeline *pipeline;
597 	int ret;
598 
599 	pipeline = kzalloc(sizeof(*pipeline), GFP_KERNEL);
600 	if (!pipeline)
601 		return -ENOMEM;
602 
603 	ret = sof_update_ipc_object(scomp, pipeline, SOF_SCHED_TOKENS, swidget->tuples,
604 				    swidget->num_tuples, sizeof(*pipeline), 1);
605 	if (ret) {
606 		dev_err(scomp->dev, "parsing scheduler tokens failed\n");
607 		goto err;
608 	}
609 
610 	/* parse one set of pipeline tokens */
611 	ret = sof_update_ipc_object(scomp, swidget, SOF_PIPELINE_TOKENS, swidget->tuples,
612 				    swidget->num_tuples, sizeof(*swidget), 1);
613 	if (ret) {
614 		dev_err(scomp->dev, "parsing pipeline tokens failed\n");
615 		goto err;
616 	}
617 
618 	/* TODO: Get priority from topology */
619 	pipeline->priority = 0;
620 
621 	dev_dbg(scomp->dev, "pipeline '%s': id %d pri %d lp mode %d\n",
622 		swidget->widget->name, swidget->pipeline_id,
623 		pipeline->priority, pipeline->lp_mode);
624 
625 	swidget->private = pipeline;
626 
627 	pipeline->msg.primary = SOF_IPC4_GLB_PIPE_PRIORITY(pipeline->priority);
628 	pipeline->msg.primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_CREATE_PIPELINE);
629 	pipeline->msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
630 	pipeline->msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG);
631 
632 	pipeline->msg.extension = pipeline->lp_mode;
633 	pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED;
634 
635 	return 0;
636 err:
637 	kfree(pipeline);
638 	return ret;
639 }
640 
641 static int sof_ipc4_widget_setup_comp_pga(struct snd_sof_widget *swidget)
642 {
643 	struct snd_soc_component *scomp = swidget->scomp;
644 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
645 	struct sof_ipc4_fw_module *fw_module;
646 	struct snd_sof_control *scontrol;
647 	struct sof_ipc4_gain *gain;
648 	int ret;
649 
650 	gain = kzalloc(sizeof(*gain), GFP_KERNEL);
651 	if (!gain)
652 		return -ENOMEM;
653 
654 	swidget->private = gain;
655 
656 	gain->data.channels = SOF_IPC4_GAIN_ALL_CHANNELS_MASK;
657 	gain->data.init_val = SOF_IPC4_VOL_ZERO_DB;
658 
659 	/* The out_audio_fmt in topology is ignored as it is not required to be sent to the FW */
660 	ret = sof_ipc4_get_audio_fmt(scomp, swidget, &gain->available_fmt, false);
661 	if (ret)
662 		goto err;
663 
664 	ret = sof_update_ipc_object(scomp, &gain->data, SOF_GAIN_TOKENS, swidget->tuples,
665 				    swidget->num_tuples, sizeof(gain->data), 1);
666 	if (ret) {
667 		dev_err(scomp->dev, "Parsing gain tokens failed\n");
668 		goto err;
669 	}
670 
671 	dev_dbg(scomp->dev,
672 		"pga widget %s: ramp type: %d, ramp duration %d, initial gain value: %#x, cpc %d\n",
673 		swidget->widget->name, gain->data.curve_type, gain->data.curve_duration,
674 		gain->data.init_val, gain->base_config.cpc);
675 
676 	ret = sof_ipc4_widget_setup_msg(swidget, &gain->msg);
677 	if (ret)
678 		goto err;
679 
680 	fw_module = swidget->module_info;
681 
682 	/* update module ID for all kcontrols for this widget */
683 	list_for_each_entry(scontrol, &sdev->kcontrol_list, list)
684 		if (scontrol->comp_id == swidget->comp_id) {
685 			struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
686 			struct sof_ipc4_msg *msg = &cdata->msg;
687 
688 			msg->primary |= fw_module->man4_module_entry.id;
689 		}
690 
691 	return 0;
692 err:
693 	sof_ipc4_free_audio_fmt(&gain->available_fmt);
694 	kfree(gain);
695 	swidget->private = NULL;
696 	return ret;
697 }
698 
699 static void sof_ipc4_widget_free_comp_pga(struct snd_sof_widget *swidget)
700 {
701 	struct sof_ipc4_gain *gain = swidget->private;
702 
703 	if (!gain)
704 		return;
705 
706 	sof_ipc4_free_audio_fmt(&gain->available_fmt);
707 	kfree(swidget->private);
708 	swidget->private = NULL;
709 }
710 
711 static int sof_ipc4_widget_setup_comp_mixer(struct snd_sof_widget *swidget)
712 {
713 	struct snd_soc_component *scomp = swidget->scomp;
714 	struct sof_ipc4_mixer *mixer;
715 	int ret;
716 
717 	dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name);
718 
719 	mixer = kzalloc(sizeof(*mixer), GFP_KERNEL);
720 	if (!mixer)
721 		return -ENOMEM;
722 
723 	swidget->private = mixer;
724 
725 	/* The out_audio_fmt in topology is ignored as it is not required to be sent to the FW */
726 	ret = sof_ipc4_get_audio_fmt(scomp, swidget, &mixer->available_fmt, false);
727 	if (ret)
728 		goto err;
729 
730 	ret = sof_ipc4_widget_setup_msg(swidget, &mixer->msg);
731 	if (ret)
732 		goto err;
733 
734 	return 0;
735 err:
736 	sof_ipc4_free_audio_fmt(&mixer->available_fmt);
737 	kfree(mixer);
738 	swidget->private = NULL;
739 	return ret;
740 }
741 
742 static int sof_ipc4_widget_setup_comp_src(struct snd_sof_widget *swidget)
743 {
744 	struct snd_soc_component *scomp = swidget->scomp;
745 	struct sof_ipc4_src *src;
746 	int ret;
747 
748 	dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name);
749 
750 	src = kzalloc(sizeof(*src), GFP_KERNEL);
751 	if (!src)
752 		return -ENOMEM;
753 
754 	swidget->private = src;
755 
756 	/* The out_audio_fmt in topology is ignored as it is not required by SRC */
757 	ret = sof_ipc4_get_audio_fmt(scomp, swidget, &src->available_fmt, false);
758 	if (ret)
759 		goto err;
760 
761 	ret = sof_update_ipc_object(scomp, src, SOF_SRC_TOKENS, swidget->tuples,
762 				    swidget->num_tuples, sizeof(*src), 1);
763 	if (ret) {
764 		dev_err(scomp->dev, "Parsing SRC tokens failed\n");
765 		goto err;
766 	}
767 
768 	dev_dbg(scomp->dev, "SRC sink rate %d\n", src->sink_rate);
769 
770 	ret = sof_ipc4_widget_setup_msg(swidget, &src->msg);
771 	if (ret)
772 		goto err;
773 
774 	return 0;
775 err:
776 	sof_ipc4_free_audio_fmt(&src->available_fmt);
777 	kfree(src);
778 	swidget->private = NULL;
779 	return ret;
780 }
781 
782 static void sof_ipc4_widget_free_comp_src(struct snd_sof_widget *swidget)
783 {
784 	struct sof_ipc4_src *src = swidget->private;
785 
786 	if (!src)
787 		return;
788 
789 	sof_ipc4_free_audio_fmt(&src->available_fmt);
790 	kfree(swidget->private);
791 	swidget->private = NULL;
792 }
793 
794 static void sof_ipc4_widget_free_comp_mixer(struct snd_sof_widget *swidget)
795 {
796 	struct sof_ipc4_mixer *mixer = swidget->private;
797 
798 	if (!mixer)
799 		return;
800 
801 	sof_ipc4_free_audio_fmt(&mixer->available_fmt);
802 	kfree(swidget->private);
803 	swidget->private = NULL;
804 }
805 
806 static void
807 sof_ipc4_update_pipeline_mem_usage(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
808 				   struct sof_ipc4_base_module_cfg *base_config)
809 {
810 	struct sof_ipc4_fw_module *fw_module = swidget->module_info;
811 	struct snd_sof_widget *pipe_widget;
812 	struct sof_ipc4_pipeline *pipeline;
813 	int task_mem, queue_mem;
814 	int ibs, bss, total;
815 
816 	ibs = base_config->ibs;
817 	bss = base_config->is_pages;
818 
819 	task_mem = SOF_IPC4_PIPELINE_OBJECT_SIZE;
820 	task_mem += SOF_IPC4_MODULE_INSTANCE_LIST_ITEM_SIZE + bss;
821 
822 	if (fw_module->man4_module_entry.type & SOF_IPC4_MODULE_LL) {
823 		task_mem += SOF_IPC4_FW_ROUNDUP(SOF_IPC4_LL_TASK_OBJECT_SIZE);
824 		task_mem += SOF_IPC4_FW_MAX_QUEUE_COUNT * SOF_IPC4_MODULE_INSTANCE_LIST_ITEM_SIZE;
825 		task_mem += SOF_IPC4_LL_TASK_LIST_ITEM_SIZE;
826 	} else {
827 		task_mem += SOF_IPC4_FW_ROUNDUP(SOF_IPC4_DP_TASK_OBJECT_SIZE);
828 		task_mem += SOF_IPC4_DP_TASK_LIST_SIZE;
829 	}
830 
831 	ibs = SOF_IPC4_FW_ROUNDUP(ibs);
832 	queue_mem = SOF_IPC4_FW_MAX_QUEUE_COUNT * (SOF_IPC4_DATA_QUEUE_OBJECT_SIZE +  ibs);
833 
834 	total = SOF_IPC4_FW_PAGE(task_mem + queue_mem);
835 
836 	pipe_widget = swidget->pipe_widget;
837 	pipeline = pipe_widget->private;
838 	pipeline->mem_usage += total;
839 }
840 
841 static int sof_ipc4_widget_assign_instance_id(struct snd_sof_dev *sdev,
842 					      struct snd_sof_widget *swidget)
843 {
844 	struct sof_ipc4_fw_module *fw_module = swidget->module_info;
845 	int max_instances = fw_module->man4_module_entry.instance_max_count;
846 
847 	swidget->instance_id = ida_alloc_max(&fw_module->m_ida, max_instances, GFP_KERNEL);
848 	if (swidget->instance_id < 0) {
849 		dev_err(sdev->dev, "failed to assign instance id for widget %s",
850 			swidget->widget->name);
851 		return swidget->instance_id;
852 	}
853 
854 	return 0;
855 }
856 
857 static int sof_ipc4_init_audio_fmt(struct snd_sof_dev *sdev,
858 				   struct snd_sof_widget *swidget,
859 				   struct sof_ipc4_base_module_cfg *base_config,
860 				   struct sof_ipc4_audio_format *out_format,
861 				   struct snd_pcm_hw_params *params,
862 				   struct sof_ipc4_available_audio_format *available_fmt,
863 				   size_t object_offset)
864 {
865 	void *ptr = available_fmt->ref_audio_fmt;
866 	u32 valid_bits;
867 	u32 channels;
868 	u32 rate;
869 	int sample_valid_bits;
870 	int i;
871 
872 	if (!ptr) {
873 		dev_err(sdev->dev, "no reference formats for %s\n", swidget->widget->name);
874 		return -EINVAL;
875 	}
876 
877 	switch (params_format(params)) {
878 	case SNDRV_PCM_FORMAT_S16_LE:
879 		sample_valid_bits = 16;
880 		break;
881 	case SNDRV_PCM_FORMAT_S24_LE:
882 		sample_valid_bits = 24;
883 		break;
884 	case SNDRV_PCM_FORMAT_S32_LE:
885 		sample_valid_bits = 32;
886 		break;
887 	default:
888 		dev_err(sdev->dev, "invalid pcm frame format %d\n", params_format(params));
889 		return -EINVAL;
890 	}
891 
892 	if (!available_fmt->audio_fmt_num) {
893 		dev_err(sdev->dev, "no formats available for %s\n", swidget->widget->name);
894 		return -EINVAL;
895 	}
896 
897 	/*
898 	 * Search supported audio formats to match rate, channels ,and
899 	 * sample_valid_bytes from runtime params
900 	 */
901 	for (i = 0; i < available_fmt->audio_fmt_num; i++, ptr = (u8 *)ptr + object_offset) {
902 		struct sof_ipc4_audio_format *fmt = ptr;
903 
904 		rate = fmt->sampling_frequency;
905 		channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg);
906 		valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
907 		if (params_rate(params) == rate && params_channels(params) == channels &&
908 		    sample_valid_bits == valid_bits) {
909 			dev_dbg(sdev->dev, "matching audio format index for %uHz, %ubit, %u channels: %d\n",
910 				rate, valid_bits, channels, i);
911 
912 			/* copy ibs/obs and input format */
913 			memcpy(base_config, &available_fmt->base_config[i],
914 			       sizeof(struct sof_ipc4_base_module_cfg));
915 
916 			/* copy output format */
917 			if (out_format)
918 				memcpy(out_format, &available_fmt->out_audio_fmt[i],
919 				       sizeof(struct sof_ipc4_audio_format));
920 			break;
921 		}
922 	}
923 
924 	if (i == available_fmt->audio_fmt_num) {
925 		dev_err(sdev->dev, "%s: Unsupported audio format: %uHz, %ubit, %u channels\n",
926 			__func__, params_rate(params), sample_valid_bits, params_channels(params));
927 		return -EINVAL;
928 	}
929 
930 	dev_dbg(sdev->dev, "Init input audio formats for %s\n", swidget->widget->name);
931 	sof_ipc4_dbg_audio_format(sdev->dev, &base_config->audio_fmt,
932 				  sizeof(*base_config), 1);
933 	if (out_format) {
934 		dev_dbg(sdev->dev, "Init output audio formats for %s\n", swidget->widget->name);
935 		sof_ipc4_dbg_audio_format(sdev->dev, out_format,
936 					  sizeof(*out_format), 1);
937 	}
938 
939 	/* Return the index of the matched format */
940 	return i;
941 }
942 
943 static void sof_ipc4_unprepare_copier_module(struct snd_sof_widget *swidget)
944 {
945 	struct sof_ipc4_copier *ipc4_copier = NULL;
946 	struct snd_sof_widget *pipe_widget;
947 	struct sof_ipc4_pipeline *pipeline;
948 
949 	/* reset pipeline memory usage */
950 	pipe_widget = swidget->pipe_widget;
951 	pipeline = pipe_widget->private;
952 	pipeline->mem_usage = 0;
953 
954 	if (WIDGET_IS_AIF(swidget->id)) {
955 		ipc4_copier = swidget->private;
956 	} else if (WIDGET_IS_DAI(swidget->id)) {
957 		struct snd_sof_dai *dai = swidget->private;
958 
959 		ipc4_copier = dai->private;
960 		if (ipc4_copier->dai_type == SOF_DAI_INTEL_ALH) {
961 			struct sof_ipc4_alh_configuration_blob *blob;
962 			unsigned int group_id;
963 
964 			blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config;
965 			if (blob->alh_cfg.count > 1) {
966 				group_id = SOF_IPC4_NODE_INDEX(ipc4_copier->data.gtw_cfg.node_id) -
967 					   ALH_MULTI_GTW_BASE;
968 				ida_free(&alh_group_ida, group_id);
969 			}
970 		}
971 	}
972 
973 	if (ipc4_copier) {
974 		kfree(ipc4_copier->ipc_config_data);
975 		ipc4_copier->ipc_config_data = NULL;
976 		ipc4_copier->ipc_config_size = 0;
977 	}
978 }
979 
980 #if IS_ENABLED(CONFIG_ACPI) && IS_ENABLED(CONFIG_SND_INTEL_NHLT)
981 static int snd_sof_get_hw_config_params(struct snd_sof_dev *sdev, struct snd_sof_dai *dai,
982 					int *sample_rate, int *channel_count, int *bit_depth)
983 {
984 	struct snd_soc_tplg_hw_config *hw_config;
985 	struct snd_sof_dai_link *slink;
986 	bool dai_link_found = false;
987 	bool hw_cfg_found = false;
988 	int i;
989 
990 	/* get current hw_config from link */
991 	list_for_each_entry(slink, &sdev->dai_link_list, list) {
992 		if (!strcmp(slink->link->name, dai->name)) {
993 			dai_link_found = true;
994 			break;
995 		}
996 	}
997 
998 	if (!dai_link_found) {
999 		dev_err(sdev->dev, "%s: no DAI link found for DAI %s\n", __func__, dai->name);
1000 		return -EINVAL;
1001 	}
1002 
1003 	for (i = 0; i < slink->num_hw_configs; i++) {
1004 		hw_config = &slink->hw_configs[i];
1005 		if (dai->current_config == le32_to_cpu(hw_config->id)) {
1006 			hw_cfg_found = true;
1007 			break;
1008 		}
1009 	}
1010 
1011 	if (!hw_cfg_found) {
1012 		dev_err(sdev->dev, "%s: no matching hw_config found for DAI %s\n", __func__,
1013 			dai->name);
1014 		return -EINVAL;
1015 	}
1016 
1017 	*bit_depth = le32_to_cpu(hw_config->tdm_slot_width);
1018 	*channel_count = le32_to_cpu(hw_config->tdm_slots);
1019 	*sample_rate = le32_to_cpu(hw_config->fsync_rate);
1020 
1021 	dev_dbg(sdev->dev, "sample rate: %d sample width: %d channels: %d\n",
1022 		*sample_rate, *bit_depth, *channel_count);
1023 
1024 	return 0;
1025 }
1026 
1027 static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai,
1028 					  struct snd_pcm_hw_params *params, u32 dai_index,
1029 					  u32 linktype, u8 dir, u32 **dst, u32 *len)
1030 {
1031 	struct sof_ipc4_fw_data *ipc4_data = sdev->private;
1032 	struct nhlt_specific_cfg *cfg;
1033 	int sample_rate, channel_count;
1034 	int bit_depth, ret;
1035 	u32 nhlt_type;
1036 
1037 	/* convert to NHLT type */
1038 	switch (linktype) {
1039 	case SOF_DAI_INTEL_DMIC:
1040 		nhlt_type = NHLT_LINK_DMIC;
1041 		bit_depth = params_width(params);
1042 		channel_count = params_channels(params);
1043 		sample_rate = params_rate(params);
1044 		break;
1045 	case SOF_DAI_INTEL_SSP:
1046 		nhlt_type = NHLT_LINK_SSP;
1047 		ret = snd_sof_get_hw_config_params(sdev, dai, &sample_rate, &channel_count,
1048 						   &bit_depth);
1049 		if (ret < 0)
1050 			return ret;
1051 		break;
1052 	default:
1053 		return 0;
1054 	}
1055 
1056 	dev_dbg(sdev->dev, "dai index %d nhlt type %d direction %d\n",
1057 		dai_index, nhlt_type, dir);
1058 
1059 	/* find NHLT blob with matching params */
1060 	cfg = intel_nhlt_get_endpoint_blob(sdev->dev, ipc4_data->nhlt, dai_index, nhlt_type,
1061 					   bit_depth, bit_depth, channel_count, sample_rate,
1062 					   dir, 0);
1063 
1064 	if (!cfg) {
1065 		dev_err(sdev->dev,
1066 			"no matching blob for sample rate: %d sample width: %d channels: %d\n",
1067 			sample_rate, bit_depth, channel_count);
1068 		return -EINVAL;
1069 	}
1070 
1071 	/* config length should be in dwords */
1072 	*len = cfg->size >> 2;
1073 	*dst = (u32 *)cfg->caps;
1074 
1075 	return 0;
1076 }
1077 #else
1078 static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai,
1079 					  struct snd_pcm_hw_params *params, u32 dai_index,
1080 					  u32 linktype, u8 dir, u32 **dst, u32 *len)
1081 {
1082 	return 0;
1083 }
1084 #endif
1085 
1086 static int
1087 sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
1088 			       struct snd_pcm_hw_params *fe_params,
1089 			       struct snd_sof_platform_stream_params *platform_params,
1090 			       struct snd_pcm_hw_params *pipeline_params, int dir)
1091 {
1092 	struct sof_ipc4_available_audio_format *available_fmt;
1093 	struct snd_soc_component *scomp = swidget->scomp;
1094 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1095 	struct sof_ipc4_copier_data *copier_data;
1096 	struct snd_pcm_hw_params *ref_params;
1097 	struct sof_ipc4_copier *ipc4_copier;
1098 	struct snd_sof_dai *dai;
1099 	struct snd_mask *fmt;
1100 	int out_sample_valid_bits;
1101 	size_t ref_audio_fmt_size;
1102 	void **ipc_config_data;
1103 	int *ipc_config_size;
1104 	u32 **data;
1105 	int ipc_size, ret;
1106 
1107 	dev_dbg(sdev->dev, "copier %s, type %d", swidget->widget->name, swidget->id);
1108 
1109 	switch (swidget->id) {
1110 	case snd_soc_dapm_aif_in:
1111 	case snd_soc_dapm_aif_out:
1112 	{
1113 		struct sof_ipc4_gtw_attributes *gtw_attr;
1114 		struct snd_sof_widget *pipe_widget;
1115 		struct sof_ipc4_pipeline *pipeline;
1116 
1117 		pipe_widget = swidget->pipe_widget;
1118 		pipeline = pipe_widget->private;
1119 		ipc4_copier = (struct sof_ipc4_copier *)swidget->private;
1120 		gtw_attr = ipc4_copier->gtw_attr;
1121 		copier_data = &ipc4_copier->data;
1122 		available_fmt = &ipc4_copier->available_fmt;
1123 
1124 		/*
1125 		 * base_config->audio_fmt and out_audio_fmt represent the input and output audio
1126 		 * formats. Use the input format as the reference to match pcm params for playback
1127 		 * and the output format as reference for capture.
1128 		 */
1129 		if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
1130 			available_fmt->ref_audio_fmt = &available_fmt->base_config->audio_fmt;
1131 			ref_audio_fmt_size = sizeof(struct sof_ipc4_base_module_cfg);
1132 		} else {
1133 			available_fmt->ref_audio_fmt = available_fmt->out_audio_fmt;
1134 			ref_audio_fmt_size = sizeof(struct sof_ipc4_audio_format);
1135 		}
1136 		copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
1137 		copier_data->gtw_cfg.node_id |=
1138 			SOF_IPC4_NODE_INDEX(platform_params->stream_tag - 1);
1139 
1140 		/* set gateway attributes */
1141 		gtw_attr->lp_buffer_alloc = pipeline->lp_mode;
1142 		ref_params = fe_params;
1143 		break;
1144 	}
1145 	case snd_soc_dapm_dai_in:
1146 	case snd_soc_dapm_dai_out:
1147 	{
1148 		dai = swidget->private;
1149 
1150 		ipc4_copier = (struct sof_ipc4_copier *)dai->private;
1151 		copier_data = &ipc4_copier->data;
1152 		available_fmt = &ipc4_copier->available_fmt;
1153 		if (dir == SNDRV_PCM_STREAM_CAPTURE) {
1154 			available_fmt->ref_audio_fmt = available_fmt->out_audio_fmt;
1155 			ref_audio_fmt_size = sizeof(struct sof_ipc4_audio_format);
1156 
1157 			/*
1158 			 * modify the input params for the dai copier as it only supports
1159 			 * 32-bit always
1160 			 */
1161 			fmt = hw_param_mask(pipeline_params, SNDRV_PCM_HW_PARAM_FORMAT);
1162 			snd_mask_none(fmt);
1163 			snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE);
1164 		} else {
1165 			available_fmt->ref_audio_fmt = &available_fmt->base_config->audio_fmt;
1166 			ref_audio_fmt_size = sizeof(struct sof_ipc4_base_module_cfg);
1167 		}
1168 
1169 		ref_params = pipeline_params;
1170 
1171 		ret = snd_sof_get_nhlt_endpoint_data(sdev, dai, fe_params, ipc4_copier->dai_index,
1172 						     ipc4_copier->dai_type, dir,
1173 						     &ipc4_copier->copier_config,
1174 						     &copier_data->gtw_cfg.config_length);
1175 		if (ret < 0)
1176 			return ret;
1177 
1178 		break;
1179 	}
1180 	default:
1181 		dev_err(sdev->dev, "unsupported type %d for copier %s",
1182 			swidget->id, swidget->widget->name);
1183 		return -EINVAL;
1184 	}
1185 
1186 	/* set input and output audio formats */
1187 	ret = sof_ipc4_init_audio_fmt(sdev, swidget, &copier_data->base_config,
1188 				      &copier_data->out_format, ref_params,
1189 				      available_fmt, ref_audio_fmt_size);
1190 	if (ret < 0)
1191 		return ret;
1192 
1193 	switch (swidget->id) {
1194 	case snd_soc_dapm_dai_in:
1195 	case snd_soc_dapm_dai_out:
1196 	{
1197 		/*
1198 		 * Only SOF_DAI_INTEL_ALH needs copier_data to set blob.
1199 		 * That's why only ALH dai's blob is set after sof_ipc4_init_audio_fmt
1200 		 */
1201 		if (ipc4_copier->dai_type == SOF_DAI_INTEL_ALH) {
1202 			struct sof_ipc4_alh_configuration_blob *blob;
1203 			struct sof_ipc4_copier_data *alh_data;
1204 			struct sof_ipc4_copier *alh_copier;
1205 			struct snd_sof_widget *w;
1206 			u32 ch_mask = 0;
1207 			u32 ch_map;
1208 			int i;
1209 
1210 			blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config;
1211 
1212 			blob->gw_attr.lp_buffer_alloc = 0;
1213 
1214 			/* Get channel_mask from ch_map */
1215 			ch_map = copier_data->base_config.audio_fmt.ch_map;
1216 			for (i = 0; ch_map; i++) {
1217 				if ((ch_map & 0xf) != 0xf)
1218 					ch_mask |= BIT(i);
1219 				ch_map >>= 4;
1220 			}
1221 
1222 			/*
1223 			 * Set each gtw_cfg.node_id to blob->alh_cfg.mapping[]
1224 			 * for all widgets with the same stream name
1225 			 */
1226 			i = 0;
1227 			list_for_each_entry(w, &sdev->widget_list, list) {
1228 				if (w->widget->sname &&
1229 				    strcmp(w->widget->sname, swidget->widget->sname))
1230 					continue;
1231 
1232 				dai = w->private;
1233 				alh_copier = (struct sof_ipc4_copier *)dai->private;
1234 				alh_data = &alh_copier->data;
1235 				blob->alh_cfg.mapping[i].alh_id = alh_data->gtw_cfg.node_id;
1236 				blob->alh_cfg.mapping[i].channel_mask = ch_mask;
1237 				i++;
1238 			}
1239 			if (blob->alh_cfg.count > 1) {
1240 				int group_id;
1241 
1242 				group_id = ida_alloc_max(&alh_group_ida, ALH_MULTI_GTW_COUNT - 1,
1243 							 GFP_KERNEL);
1244 
1245 				if (group_id < 0)
1246 					return group_id;
1247 
1248 				/* add multi-gateway base */
1249 				group_id += ALH_MULTI_GTW_BASE;
1250 				copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
1251 				copier_data->gtw_cfg.node_id |= SOF_IPC4_NODE_INDEX(group_id);
1252 			}
1253 		}
1254 	}
1255 	}
1256 
1257 	/* modify the input params for the next widget */
1258 	fmt = hw_param_mask(pipeline_params, SNDRV_PCM_HW_PARAM_FORMAT);
1259 	out_sample_valid_bits =
1260 		SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(copier_data->out_format.fmt_cfg);
1261 	snd_mask_none(fmt);
1262 	switch (out_sample_valid_bits) {
1263 	case 16:
1264 		snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
1265 		break;
1266 	case 24:
1267 		snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
1268 		break;
1269 	case 32:
1270 		snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE);
1271 		break;
1272 	default:
1273 		dev_err(sdev->dev, "invalid sample frame format %d\n",
1274 			params_format(pipeline_params));
1275 		return -EINVAL;
1276 	}
1277 
1278 	/* set the gateway dma_buffer_size using the matched ID returned above */
1279 	copier_data->gtw_cfg.dma_buffer_size = available_fmt->dma_buffer_size[ret];
1280 
1281 	data = &ipc4_copier->copier_config;
1282 	ipc_config_size = &ipc4_copier->ipc_config_size;
1283 	ipc_config_data = &ipc4_copier->ipc_config_data;
1284 
1285 	/* config_length is DWORD based */
1286 	ipc_size = sizeof(*copier_data) + copier_data->gtw_cfg.config_length * 4;
1287 
1288 	dev_dbg(sdev->dev, "copier %s, IPC size is %d", swidget->widget->name, ipc_size);
1289 
1290 	*ipc_config_data = kzalloc(ipc_size, GFP_KERNEL);
1291 	if (!*ipc_config_data)
1292 		return -ENOMEM;
1293 
1294 	*ipc_config_size = ipc_size;
1295 
1296 	/* copy IPC data */
1297 	memcpy(*ipc_config_data, (void *)copier_data, sizeof(*copier_data));
1298 	if (copier_data->gtw_cfg.config_length)
1299 		memcpy(*ipc_config_data + sizeof(*copier_data),
1300 		       *data, copier_data->gtw_cfg.config_length * 4);
1301 
1302 	/* update pipeline memory usage */
1303 	sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &copier_data->base_config);
1304 
1305 	return 0;
1306 }
1307 
1308 static int sof_ipc4_prepare_gain_module(struct snd_sof_widget *swidget,
1309 					struct snd_pcm_hw_params *fe_params,
1310 					struct snd_sof_platform_stream_params *platform_params,
1311 					struct snd_pcm_hw_params *pipeline_params, int dir)
1312 {
1313 	struct snd_soc_component *scomp = swidget->scomp;
1314 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1315 	struct sof_ipc4_gain *gain = swidget->private;
1316 	int ret;
1317 
1318 	gain->available_fmt.ref_audio_fmt = &gain->available_fmt.base_config->audio_fmt;
1319 
1320 	/* output format is not required to be sent to the FW for gain */
1321 	ret = sof_ipc4_init_audio_fmt(sdev, swidget, &gain->base_config,
1322 				      NULL, pipeline_params, &gain->available_fmt,
1323 				      sizeof(gain->base_config));
1324 	if (ret < 0)
1325 		return ret;
1326 
1327 	/* update pipeline memory usage */
1328 	sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &gain->base_config);
1329 
1330 	return 0;
1331 }
1332 
1333 static int sof_ipc4_prepare_mixer_module(struct snd_sof_widget *swidget,
1334 					 struct snd_pcm_hw_params *fe_params,
1335 					 struct snd_sof_platform_stream_params *platform_params,
1336 					 struct snd_pcm_hw_params *pipeline_params, int dir)
1337 {
1338 	struct snd_soc_component *scomp = swidget->scomp;
1339 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1340 	struct sof_ipc4_mixer *mixer = swidget->private;
1341 	int ret;
1342 
1343 	/* only 32bit is supported by mixer */
1344 	mixer->available_fmt.ref_audio_fmt = &mixer->available_fmt.base_config->audio_fmt;
1345 
1346 	/* output format is not required to be sent to the FW for mixer */
1347 	ret = sof_ipc4_init_audio_fmt(sdev, swidget, &mixer->base_config,
1348 				      NULL, pipeline_params, &mixer->available_fmt,
1349 				      sizeof(mixer->base_config));
1350 	if (ret < 0)
1351 		return ret;
1352 
1353 	/* update pipeline memory usage */
1354 	sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &mixer->base_config);
1355 
1356 	return 0;
1357 }
1358 
1359 static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget,
1360 				       struct snd_pcm_hw_params *fe_params,
1361 				       struct snd_sof_platform_stream_params *platform_params,
1362 				       struct snd_pcm_hw_params *pipeline_params, int dir)
1363 {
1364 	struct snd_soc_component *scomp = swidget->scomp;
1365 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1366 	struct sof_ipc4_src *src = swidget->private;
1367 	struct snd_interval *rate;
1368 	int ret;
1369 
1370 	src->available_fmt.ref_audio_fmt = &src->available_fmt.base_config->audio_fmt;
1371 
1372 	/* output format is not required to be sent to the FW for SRC */
1373 	ret = sof_ipc4_init_audio_fmt(sdev, swidget, &src->base_config,
1374 				      NULL, pipeline_params, &src->available_fmt,
1375 				      sizeof(src->base_config));
1376 	if (ret < 0)
1377 		return ret;
1378 
1379 	/* update pipeline memory usage */
1380 	sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &src->base_config);
1381 
1382 	/* update pipeline_params for sink widgets */
1383 	rate = hw_param_interval(pipeline_params, SNDRV_PCM_HW_PARAM_RATE);
1384 	rate->min = src->sink_rate;
1385 	rate->max = rate->min;
1386 
1387 	return 0;
1388 }
1389 
1390 static int sof_ipc4_control_load_volume(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
1391 {
1392 	struct sof_ipc4_control_data *control_data;
1393 	struct sof_ipc4_msg *msg;
1394 	int i;
1395 
1396 	scontrol->size = struct_size(control_data, chanv, scontrol->num_channels);
1397 
1398 	/* scontrol->ipc_control_data will be freed in sof_control_unload */
1399 	scontrol->ipc_control_data = kzalloc(scontrol->size, GFP_KERNEL);
1400 	if (!scontrol->ipc_control_data)
1401 		return -ENOMEM;
1402 
1403 	control_data = scontrol->ipc_control_data;
1404 	control_data->index = scontrol->index;
1405 
1406 	msg = &control_data->msg;
1407 	msg->primary = SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_LARGE_CONFIG_SET);
1408 	msg->primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
1409 	msg->primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
1410 
1411 	msg->extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_GAIN_PARAM_ID);
1412 
1413 	/* set default volume values to 0dB in control */
1414 	for (i = 0; i < scontrol->num_channels; i++) {
1415 		control_data->chanv[i].channel = i;
1416 		control_data->chanv[i].value = SOF_IPC4_VOL_ZERO_DB;
1417 	}
1418 
1419 	return 0;
1420 }
1421 
1422 static int sof_ipc4_control_setup(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
1423 {
1424 	switch (scontrol->info_type) {
1425 	case SND_SOC_TPLG_CTL_VOLSW:
1426 	case SND_SOC_TPLG_CTL_VOLSW_SX:
1427 	case SND_SOC_TPLG_CTL_VOLSW_XR_SX:
1428 		return sof_ipc4_control_load_volume(sdev, scontrol);
1429 	default:
1430 		break;
1431 	}
1432 
1433 	return 0;
1434 }
1435 
1436 static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
1437 {
1438 	struct snd_sof_widget *pipe_widget = swidget->pipe_widget;
1439 	struct sof_ipc4_fw_data *ipc4_data = sdev->private;
1440 	struct sof_ipc4_pipeline *pipeline;
1441 	struct sof_ipc4_msg *msg;
1442 	void *ipc_data = NULL;
1443 	u32 ipc_size = 0;
1444 	int ret;
1445 
1446 	switch (swidget->id) {
1447 	case snd_soc_dapm_scheduler:
1448 		pipeline = swidget->private;
1449 
1450 		dev_dbg(sdev->dev, "pipeline: %d memory pages: %d\n", swidget->pipeline_id,
1451 			pipeline->mem_usage);
1452 
1453 		msg = &pipeline->msg;
1454 		msg->primary |= pipeline->mem_usage;
1455 
1456 		swidget->instance_id = ida_alloc_max(&pipeline_ida, ipc4_data->max_num_pipelines,
1457 						     GFP_KERNEL);
1458 		if (swidget->instance_id < 0) {
1459 			dev_err(sdev->dev, "failed to assign pipeline id for %s: %d\n",
1460 				swidget->widget->name, swidget->instance_id);
1461 			return swidget->instance_id;
1462 		}
1463 		msg->primary &= ~SOF_IPC4_GLB_PIPE_INSTANCE_MASK;
1464 		msg->primary |= SOF_IPC4_GLB_PIPE_INSTANCE_ID(swidget->instance_id);
1465 		break;
1466 	case snd_soc_dapm_aif_in:
1467 	case snd_soc_dapm_aif_out:
1468 	{
1469 		struct sof_ipc4_copier *ipc4_copier = swidget->private;
1470 
1471 		ipc_size = ipc4_copier->ipc_config_size;
1472 		ipc_data = ipc4_copier->ipc_config_data;
1473 
1474 		msg = &ipc4_copier->msg;
1475 		break;
1476 	}
1477 	case snd_soc_dapm_dai_in:
1478 	case snd_soc_dapm_dai_out:
1479 	{
1480 		struct snd_sof_dai *dai = swidget->private;
1481 		struct sof_ipc4_copier *ipc4_copier = dai->private;
1482 
1483 		ipc_size = ipc4_copier->ipc_config_size;
1484 		ipc_data = ipc4_copier->ipc_config_data;
1485 
1486 		msg = &ipc4_copier->msg;
1487 		break;
1488 	}
1489 	case snd_soc_dapm_pga:
1490 	{
1491 		struct sof_ipc4_gain *gain = swidget->private;
1492 
1493 		ipc_size = sizeof(struct sof_ipc4_base_module_cfg) +
1494 			   sizeof(struct sof_ipc4_gain_data);
1495 		ipc_data = gain;
1496 
1497 		msg = &gain->msg;
1498 		break;
1499 	}
1500 	case snd_soc_dapm_mixer:
1501 	{
1502 		struct sof_ipc4_mixer *mixer = swidget->private;
1503 
1504 		ipc_size = sizeof(mixer->base_config);
1505 		ipc_data = &mixer->base_config;
1506 
1507 		msg = &mixer->msg;
1508 		break;
1509 	}
1510 	case snd_soc_dapm_src:
1511 	{
1512 		struct sof_ipc4_src *src = swidget->private;
1513 
1514 		ipc_size = sizeof(struct sof_ipc4_base_module_cfg) + sizeof(src->sink_rate);
1515 		ipc_data = src;
1516 
1517 		msg = &src->msg;
1518 		break;
1519 	}
1520 	default:
1521 		dev_err(sdev->dev, "widget type %d not supported", swidget->id);
1522 		return -EINVAL;
1523 	}
1524 
1525 	if (swidget->id != snd_soc_dapm_scheduler) {
1526 		ret = sof_ipc4_widget_assign_instance_id(sdev, swidget);
1527 		if (ret < 0) {
1528 			dev_err(sdev->dev, "failed to assign instance id for %s\n",
1529 				swidget->widget->name);
1530 			return ret;
1531 		}
1532 
1533 		msg->primary &= ~SOF_IPC4_MOD_INSTANCE_MASK;
1534 		msg->primary |= SOF_IPC4_MOD_INSTANCE(swidget->instance_id);
1535 
1536 		msg->extension &= ~SOF_IPC4_MOD_EXT_PARAM_SIZE_MASK;
1537 		msg->extension |= ipc_size >> 2;
1538 
1539 		msg->extension &= ~SOF_IPC4_MOD_EXT_PPL_ID_MASK;
1540 		msg->extension |= SOF_IPC4_MOD_EXT_PPL_ID(pipe_widget->instance_id);
1541 	}
1542 	dev_dbg(sdev->dev, "Create widget %s instance %d - pipe %d - core %d\n",
1543 		swidget->widget->name, swidget->instance_id, swidget->pipeline_id, swidget->core);
1544 
1545 	msg->data_size = ipc_size;
1546 	msg->data_ptr = ipc_data;
1547 
1548 	ret = sof_ipc_tx_message(sdev->ipc, msg, ipc_size, NULL, 0);
1549 	if (ret < 0) {
1550 		dev_err(sdev->dev, "failed to create module %s\n", swidget->widget->name);
1551 
1552 		if (swidget->id != snd_soc_dapm_scheduler) {
1553 			struct sof_ipc4_fw_module *fw_module = swidget->module_info;
1554 
1555 			ida_free(&fw_module->m_ida, swidget->instance_id);
1556 		} else {
1557 			ida_free(&pipeline_ida, swidget->instance_id);
1558 		}
1559 	}
1560 
1561 	return ret;
1562 }
1563 
1564 static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
1565 {
1566 	struct sof_ipc4_fw_module *fw_module = swidget->module_info;
1567 	int ret = 0;
1568 
1569 	/* freeing a pipeline frees all the widgets associated with it */
1570 	if (swidget->id == snd_soc_dapm_scheduler) {
1571 		struct sof_ipc4_pipeline *pipeline = swidget->private;
1572 		struct sof_ipc4_msg msg = {{ 0 }};
1573 		u32 header;
1574 
1575 		header = SOF_IPC4_GLB_PIPE_INSTANCE_ID(swidget->instance_id);
1576 		header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_DELETE_PIPELINE);
1577 		header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
1578 		header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG);
1579 
1580 		msg.primary = header;
1581 
1582 		ret = sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0);
1583 		if (ret < 0)
1584 			dev_err(sdev->dev, "failed to free pipeline widget %s\n",
1585 				swidget->widget->name);
1586 
1587 		pipeline->mem_usage = 0;
1588 		pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED;
1589 		ida_free(&pipeline_ida, swidget->instance_id);
1590 	} else {
1591 		ida_free(&fw_module->m_ida, swidget->instance_id);
1592 	}
1593 
1594 	return ret;
1595 }
1596 
1597 static int sof_ipc4_get_queue_id(struct snd_sof_widget *src_widget,
1598 				 struct snd_sof_widget *sink_widget, bool pin_type)
1599 {
1600 	struct snd_sof_widget *current_swidget;
1601 	struct snd_soc_component *scomp;
1602 	struct ida *queue_ida;
1603 	const char *buddy_name;
1604 	char **pin_binding;
1605 	u32 num_pins;
1606 	int i;
1607 
1608 	if (pin_type == SOF_PIN_TYPE_SOURCE) {
1609 		current_swidget = src_widget;
1610 		pin_binding = src_widget->src_pin_binding;
1611 		queue_ida = &src_widget->src_queue_ida;
1612 		num_pins = src_widget->num_source_pins;
1613 		buddy_name = sink_widget->widget->name;
1614 	} else {
1615 		current_swidget = sink_widget;
1616 		pin_binding = sink_widget->sink_pin_binding;
1617 		queue_ida = &sink_widget->sink_queue_ida;
1618 		num_pins = sink_widget->num_sink_pins;
1619 		buddy_name = src_widget->widget->name;
1620 	}
1621 
1622 	scomp = current_swidget->scomp;
1623 
1624 	if (num_pins < 1) {
1625 		dev_err(scomp->dev, "invalid %s num_pins: %d for queue allocation for %s\n",
1626 			(pin_type == SOF_PIN_TYPE_SOURCE ? "source" : "sink"),
1627 			num_pins, current_swidget->widget->name);
1628 		return -EINVAL;
1629 	}
1630 
1631 	/* If there is only one sink/source pin, queue id must be 0 */
1632 	if (num_pins == 1)
1633 		return 0;
1634 
1635 	/* Allocate queue ID from pin binding array if it is defined in topology. */
1636 	if (pin_binding) {
1637 		for (i = 0; i < num_pins; i++) {
1638 			if (!strcmp(pin_binding[i], buddy_name))
1639 				return i;
1640 		}
1641 		/*
1642 		 * Fail if no queue ID found from pin binding array, so that we don't
1643 		 * mixed use pin binding array and ida for queue ID allocation.
1644 		 */
1645 		dev_err(scomp->dev, "no %s queue id found from pin binding array for %s\n",
1646 			(pin_type == SOF_PIN_TYPE_SOURCE ? "source" : "sink"),
1647 			current_swidget->widget->name);
1648 		return -EINVAL;
1649 	}
1650 
1651 	/* If no pin binding array specified in topology, use ida to allocate one */
1652 	return ida_alloc_max(queue_ida, num_pins, GFP_KERNEL);
1653 }
1654 
1655 static void sof_ipc4_put_queue_id(struct snd_sof_widget *swidget, int queue_id,
1656 				  bool pin_type)
1657 {
1658 	struct ida *queue_ida;
1659 	char **pin_binding;
1660 	int num_pins;
1661 
1662 	if (pin_type == SOF_PIN_TYPE_SOURCE) {
1663 		pin_binding = swidget->src_pin_binding;
1664 		queue_ida = &swidget->src_queue_ida;
1665 		num_pins = swidget->num_source_pins;
1666 	} else {
1667 		pin_binding = swidget->sink_pin_binding;
1668 		queue_ida = &swidget->sink_queue_ida;
1669 		num_pins = swidget->num_sink_pins;
1670 	}
1671 
1672 	/* Nothing to free if queue ID is not allocated with ida. */
1673 	if (num_pins == 1 || pin_binding)
1674 		return;
1675 
1676 	ida_free(queue_ida, queue_id);
1677 }
1678 
1679 static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route *sroute)
1680 {
1681 	struct snd_sof_widget *src_widget = sroute->src_widget;
1682 	struct snd_sof_widget *sink_widget = sroute->sink_widget;
1683 	struct sof_ipc4_fw_module *src_fw_module = src_widget->module_info;
1684 	struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info;
1685 	struct sof_ipc4_msg msg = {{ 0 }};
1686 	u32 header, extension;
1687 	int ret;
1688 
1689 	sroute->src_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget,
1690 						     SOF_PIN_TYPE_SOURCE);
1691 	if (sroute->src_queue_id < 0) {
1692 		dev_err(sdev->dev, "failed to get queue ID for source widget: %s\n",
1693 			src_widget->widget->name);
1694 		return sroute->src_queue_id;
1695 	}
1696 
1697 	sroute->dst_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget,
1698 						     SOF_PIN_TYPE_SINK);
1699 	if (sroute->dst_queue_id < 0) {
1700 		dev_err(sdev->dev, "failed to get queue ID for sink widget: %s\n",
1701 			sink_widget->widget->name);
1702 		sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id,
1703 				      SOF_PIN_TYPE_SOURCE);
1704 		return sroute->dst_queue_id;
1705 	}
1706 
1707 	dev_dbg(sdev->dev, "bind %s:%d -> %s:%d\n",
1708 		src_widget->widget->name, sroute->src_queue_id,
1709 		sink_widget->widget->name, sroute->dst_queue_id);
1710 
1711 	header = src_fw_module->man4_module_entry.id;
1712 	header |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id);
1713 	header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_BIND);
1714 	header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
1715 	header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
1716 
1717 	extension = sink_fw_module->man4_module_entry.id;
1718 	extension |= SOF_IPC4_MOD_EXT_DST_MOD_INSTANCE(sink_widget->instance_id);
1719 	extension |= SOF_IPC4_MOD_EXT_DST_MOD_QUEUE_ID(sroute->dst_queue_id);
1720 	extension |= SOF_IPC4_MOD_EXT_SRC_MOD_QUEUE_ID(sroute->src_queue_id);
1721 
1722 	msg.primary = header;
1723 	msg.extension = extension;
1724 
1725 	ret = sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0);
1726 	if (ret < 0) {
1727 		dev_err(sdev->dev, "%s: failed to bind modules %s -> %s\n",
1728 			__func__, src_widget->widget->name, sink_widget->widget->name);
1729 
1730 		sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id,
1731 				      SOF_PIN_TYPE_SOURCE);
1732 		sof_ipc4_put_queue_id(sink_widget, sroute->dst_queue_id,
1733 				      SOF_PIN_TYPE_SINK);
1734 	}
1735 
1736 	return ret;
1737 }
1738 
1739 static int sof_ipc4_route_free(struct snd_sof_dev *sdev, struct snd_sof_route *sroute)
1740 {
1741 	struct snd_sof_widget *src_widget = sroute->src_widget;
1742 	struct snd_sof_widget *sink_widget = sroute->sink_widget;
1743 	struct sof_ipc4_fw_module *src_fw_module = src_widget->module_info;
1744 	struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info;
1745 	struct sof_ipc4_msg msg = {{ 0 }};
1746 	u32 header, extension;
1747 	int ret;
1748 
1749 	dev_dbg(sdev->dev, "unbind modules %s:%d -> %s:%d\n",
1750 		src_widget->widget->name, sroute->src_queue_id,
1751 		sink_widget->widget->name, sroute->dst_queue_id);
1752 
1753 	header = src_fw_module->man4_module_entry.id;
1754 	header |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id);
1755 	header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_UNBIND);
1756 	header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
1757 	header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
1758 
1759 	extension = sink_fw_module->man4_module_entry.id;
1760 	extension |= SOF_IPC4_MOD_EXT_DST_MOD_INSTANCE(sink_widget->instance_id);
1761 	extension |= SOF_IPC4_MOD_EXT_DST_MOD_QUEUE_ID(sroute->dst_queue_id);
1762 	extension |= SOF_IPC4_MOD_EXT_SRC_MOD_QUEUE_ID(sroute->src_queue_id);
1763 
1764 	msg.primary = header;
1765 	msg.extension = extension;
1766 
1767 	ret = sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0);
1768 	if (ret < 0)
1769 		dev_err(sdev->dev, "failed to unbind modules %s -> %s\n",
1770 			src_widget->widget->name, sink_widget->widget->name);
1771 
1772 	sof_ipc4_put_queue_id(sink_widget, sroute->dst_queue_id, SOF_PIN_TYPE_SINK);
1773 	sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id, SOF_PIN_TYPE_SOURCE);
1774 
1775 	return ret;
1776 }
1777 
1778 static int sof_ipc4_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
1779 			       unsigned int flags, struct snd_sof_dai_config_data *data)
1780 {
1781 	struct snd_sof_widget *pipe_widget = swidget->pipe_widget;
1782 	struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
1783 	struct snd_sof_dai *dai = swidget->private;
1784 	struct sof_ipc4_gtw_attributes *gtw_attr;
1785 	struct sof_ipc4_copier_data *copier_data;
1786 	struct sof_ipc4_copier *ipc4_copier;
1787 
1788 	if (!dai || !dai->private) {
1789 		dev_err(sdev->dev, "Invalid DAI or DAI private data for %s\n",
1790 			swidget->widget->name);
1791 		return -EINVAL;
1792 	}
1793 
1794 	ipc4_copier = (struct sof_ipc4_copier *)dai->private;
1795 	copier_data = &ipc4_copier->data;
1796 
1797 	if (!data)
1798 		return 0;
1799 
1800 	switch (ipc4_copier->dai_type) {
1801 	case SOF_DAI_INTEL_HDA:
1802 		gtw_attr = ipc4_copier->gtw_attr;
1803 		gtw_attr->lp_buffer_alloc = pipeline->lp_mode;
1804 		fallthrough;
1805 	case SOF_DAI_INTEL_ALH:
1806 		copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
1807 		copier_data->gtw_cfg.node_id |= SOF_IPC4_NODE_INDEX(data->dai_data);
1808 		break;
1809 	case SOF_DAI_INTEL_DMIC:
1810 	case SOF_DAI_INTEL_SSP:
1811 		/* nothing to do for SSP/DMIC */
1812 		break;
1813 	default:
1814 		dev_err(sdev->dev, "%s: unsupported dai type %d\n", __func__,
1815 			ipc4_copier->dai_type);
1816 		return -EINVAL;
1817 	}
1818 
1819 	return 0;
1820 }
1821 
1822 static int sof_ipc4_parse_manifest(struct snd_soc_component *scomp, int index,
1823 				   struct snd_soc_tplg_manifest *man)
1824 {
1825 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1826 	struct sof_ipc4_fw_data *ipc4_data = sdev->private;
1827 	struct sof_manifest_tlv *manifest_tlv;
1828 	struct sof_manifest *manifest;
1829 	u32 size = le32_to_cpu(man->priv.size);
1830 	u8 *man_ptr = man->priv.data;
1831 	u32 len_check;
1832 	int i;
1833 
1834 	if (!size || size < SOF_IPC4_TPLG_ABI_SIZE) {
1835 		dev_err(scomp->dev, "%s: Invalid topology ABI size: %u\n",
1836 			__func__, size);
1837 		return -EINVAL;
1838 	}
1839 
1840 	manifest = (struct sof_manifest *)man_ptr;
1841 
1842 	dev_info(scomp->dev,
1843 		 "Topology: ABI %d:%d:%d Kernel ABI %u:%u:%u\n",
1844 		  le16_to_cpu(manifest->abi_major), le16_to_cpu(manifest->abi_minor),
1845 		  le16_to_cpu(manifest->abi_patch),
1846 		  SOF_ABI_MAJOR, SOF_ABI_MINOR, SOF_ABI_PATCH);
1847 
1848 	/* TODO: Add ABI compatibility check */
1849 
1850 	/* no more data after the ABI version */
1851 	if (size <= SOF_IPC4_TPLG_ABI_SIZE)
1852 		return 0;
1853 
1854 	manifest_tlv = manifest->items;
1855 	len_check = sizeof(struct sof_manifest);
1856 	for (i = 0; i < le16_to_cpu(manifest->count); i++) {
1857 		len_check += sizeof(struct sof_manifest_tlv) + le32_to_cpu(manifest_tlv->size);
1858 		if (len_check > size)
1859 			return -EINVAL;
1860 
1861 		switch (le32_to_cpu(manifest_tlv->type)) {
1862 		case SOF_MANIFEST_DATA_TYPE_NHLT:
1863 			/* no NHLT in BIOS, so use the one from topology manifest */
1864 			if (ipc4_data->nhlt)
1865 				break;
1866 			ipc4_data->nhlt = devm_kmemdup(sdev->dev, manifest_tlv->data,
1867 						       le32_to_cpu(manifest_tlv->size), GFP_KERNEL);
1868 			if (!ipc4_data->nhlt)
1869 				return -ENOMEM;
1870 			break;
1871 		default:
1872 			dev_warn(scomp->dev, "Skipping unknown manifest data type %d\n",
1873 				 manifest_tlv->type);
1874 			break;
1875 		}
1876 		man_ptr += sizeof(struct sof_manifest_tlv) + le32_to_cpu(manifest_tlv->size);
1877 		manifest_tlv = (struct sof_manifest_tlv *)man_ptr;
1878 	}
1879 
1880 	return 0;
1881 }
1882 
1883 static int sof_ipc4_dai_get_clk(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, int clk_type)
1884 {
1885 	struct sof_ipc4_copier *ipc4_copier = dai->private;
1886 	struct snd_soc_tplg_hw_config *hw_config;
1887 	struct snd_sof_dai_link *slink;
1888 	bool dai_link_found = false;
1889 	bool hw_cfg_found = false;
1890 	int i;
1891 
1892 	if (!ipc4_copier)
1893 		return 0;
1894 
1895 	list_for_each_entry(slink, &sdev->dai_link_list, list) {
1896 		if (!strcmp(slink->link->name, dai->name)) {
1897 			dai_link_found = true;
1898 			break;
1899 		}
1900 	}
1901 
1902 	if (!dai_link_found) {
1903 		dev_err(sdev->dev, "no DAI link found for DAI %s\n", dai->name);
1904 		return -EINVAL;
1905 	}
1906 
1907 	for (i = 0; i < slink->num_hw_configs; i++) {
1908 		hw_config = &slink->hw_configs[i];
1909 		if (dai->current_config == le32_to_cpu(hw_config->id)) {
1910 			hw_cfg_found = true;
1911 			break;
1912 		}
1913 	}
1914 
1915 	if (!hw_cfg_found) {
1916 		dev_err(sdev->dev, "no matching hw_config found for DAI %s\n", dai->name);
1917 		return -EINVAL;
1918 	}
1919 
1920 	switch (ipc4_copier->dai_type) {
1921 	case SOF_DAI_INTEL_SSP:
1922 		switch (clk_type) {
1923 		case SOF_DAI_CLK_INTEL_SSP_MCLK:
1924 			return le32_to_cpu(hw_config->mclk_rate);
1925 		case SOF_DAI_CLK_INTEL_SSP_BCLK:
1926 			return le32_to_cpu(hw_config->bclk_rate);
1927 		default:
1928 			dev_err(sdev->dev, "Invalid clk type for SSP %d\n", clk_type);
1929 			break;
1930 		}
1931 		break;
1932 	default:
1933 		dev_err(sdev->dev, "DAI type %d not supported yet!\n", ipc4_copier->dai_type);
1934 		break;
1935 	}
1936 
1937 	return -EINVAL;
1938 }
1939 
1940 static int sof_ipc4_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verify)
1941 {
1942 	struct snd_sof_pcm *spcm;
1943 	int dir, ret;
1944 
1945 	/*
1946 	 * This function is called during system suspend, we need to make sure
1947 	 * that all streams have been freed up.
1948 	 * Freeing might have been skipped when xrun happened just at the start
1949 	 * of the suspend and it sent a SNDRV_PCM_TRIGGER_STOP to the active
1950 	 * stream. This will call sof_pcm_stream_free() with
1951 	 * free_widget_list = false which will leave the kernel and firmware out
1952 	 * of sync during suspend/resume.
1953 	 *
1954 	 * This will also make sure that paused streams handled correctly.
1955 	 */
1956 	list_for_each_entry(spcm, &sdev->pcm_list, list) {
1957 		for_each_pcm_streams(dir) {
1958 			struct snd_pcm_substream *substream = spcm->stream[dir].substream;
1959 
1960 			if (!substream || !substream->runtime)
1961 				continue;
1962 
1963 			if (spcm->stream[dir].list) {
1964 				ret = sof_pcm_stream_free(sdev, substream, spcm, dir, true);
1965 				if (ret < 0)
1966 					return ret;
1967 			}
1968 		}
1969 	}
1970 	return 0;
1971 }
1972 
1973 static enum sof_tokens host_token_list[] = {
1974 	SOF_COMP_TOKENS,
1975 	SOF_AUDIO_FMT_NUM_TOKENS,
1976 	SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS,
1977 	SOF_IN_AUDIO_FORMAT_TOKENS,
1978 	SOF_OUT_AUDIO_FORMAT_TOKENS,
1979 	SOF_COPIER_GATEWAY_CFG_TOKENS,
1980 	SOF_COPIER_TOKENS,
1981 	SOF_COMP_EXT_TOKENS,
1982 };
1983 
1984 static enum sof_tokens pipeline_token_list[] = {
1985 	SOF_SCHED_TOKENS,
1986 	SOF_PIPELINE_TOKENS,
1987 };
1988 
1989 static enum sof_tokens dai_token_list[] = {
1990 	SOF_COMP_TOKENS,
1991 	SOF_AUDIO_FMT_NUM_TOKENS,
1992 	SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS,
1993 	SOF_IN_AUDIO_FORMAT_TOKENS,
1994 	SOF_OUT_AUDIO_FORMAT_TOKENS,
1995 	SOF_COPIER_GATEWAY_CFG_TOKENS,
1996 	SOF_COPIER_TOKENS,
1997 	SOF_DAI_TOKENS,
1998 	SOF_COMP_EXT_TOKENS,
1999 };
2000 
2001 static enum sof_tokens pga_token_list[] = {
2002 	SOF_COMP_TOKENS,
2003 	SOF_GAIN_TOKENS,
2004 	SOF_AUDIO_FMT_NUM_TOKENS,
2005 	SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS,
2006 	SOF_IN_AUDIO_FORMAT_TOKENS,
2007 	SOF_COMP_EXT_TOKENS,
2008 };
2009 
2010 static enum sof_tokens mixer_token_list[] = {
2011 	SOF_COMP_TOKENS,
2012 	SOF_AUDIO_FMT_NUM_TOKENS,
2013 	SOF_IN_AUDIO_FORMAT_TOKENS,
2014 	SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS,
2015 	SOF_COMP_EXT_TOKENS,
2016 };
2017 
2018 static enum sof_tokens src_token_list[] = {
2019 	SOF_COMP_TOKENS,
2020 	SOF_SRC_TOKENS,
2021 	SOF_AUDIO_FMT_NUM_TOKENS,
2022 	SOF_IN_AUDIO_FORMAT_TOKENS,
2023 	SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS,
2024 	SOF_COMP_EXT_TOKENS,
2025 };
2026 
2027 static const struct sof_ipc_tplg_widget_ops tplg_ipc4_widget_ops[SND_SOC_DAPM_TYPE_COUNT] = {
2028 	[snd_soc_dapm_aif_in] =  {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm,
2029 				  host_token_list, ARRAY_SIZE(host_token_list), NULL,
2030 				  sof_ipc4_prepare_copier_module,
2031 				  sof_ipc4_unprepare_copier_module},
2032 	[snd_soc_dapm_aif_out] = {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm,
2033 				  host_token_list, ARRAY_SIZE(host_token_list), NULL,
2034 				  sof_ipc4_prepare_copier_module,
2035 				  sof_ipc4_unprepare_copier_module},
2036 	[snd_soc_dapm_dai_in] = {sof_ipc4_widget_setup_comp_dai, sof_ipc4_widget_free_comp_dai,
2037 				 dai_token_list, ARRAY_SIZE(dai_token_list), NULL,
2038 				 sof_ipc4_prepare_copier_module,
2039 				 sof_ipc4_unprepare_copier_module},
2040 	[snd_soc_dapm_dai_out] = {sof_ipc4_widget_setup_comp_dai, sof_ipc4_widget_free_comp_dai,
2041 				  dai_token_list, ARRAY_SIZE(dai_token_list), NULL,
2042 				  sof_ipc4_prepare_copier_module,
2043 				  sof_ipc4_unprepare_copier_module},
2044 	[snd_soc_dapm_scheduler] = {sof_ipc4_widget_setup_comp_pipeline,
2045 				    sof_ipc4_widget_free_comp_pipeline,
2046 				    pipeline_token_list, ARRAY_SIZE(pipeline_token_list), NULL,
2047 				    NULL, NULL},
2048 	[snd_soc_dapm_pga] = {sof_ipc4_widget_setup_comp_pga, sof_ipc4_widget_free_comp_pga,
2049 			      pga_token_list, ARRAY_SIZE(pga_token_list), NULL,
2050 			      sof_ipc4_prepare_gain_module,
2051 			      NULL},
2052 	[snd_soc_dapm_mixer] = {sof_ipc4_widget_setup_comp_mixer, sof_ipc4_widget_free_comp_mixer,
2053 				mixer_token_list, ARRAY_SIZE(mixer_token_list),
2054 				NULL, sof_ipc4_prepare_mixer_module,
2055 				NULL},
2056 	[snd_soc_dapm_src] = {sof_ipc4_widget_setup_comp_src, sof_ipc4_widget_free_comp_src,
2057 				src_token_list, ARRAY_SIZE(src_token_list),
2058 				NULL, sof_ipc4_prepare_src_module,
2059 				NULL},
2060 };
2061 
2062 const struct sof_ipc_tplg_ops ipc4_tplg_ops = {
2063 	.widget = tplg_ipc4_widget_ops,
2064 	.token_list = ipc4_token_list,
2065 	.control_setup = sof_ipc4_control_setup,
2066 	.control = &tplg_ipc4_control_ops,
2067 	.widget_setup = sof_ipc4_widget_setup,
2068 	.widget_free = sof_ipc4_widget_free,
2069 	.route_setup = sof_ipc4_route_setup,
2070 	.route_free = sof_ipc4_route_free,
2071 	.dai_config = sof_ipc4_dai_config,
2072 	.parse_manifest = sof_ipc4_parse_manifest,
2073 	.dai_get_clk = sof_ipc4_dai_get_clk,
2074 	.tear_down_all_pipelines = sof_ipc4_tear_down_all_pipelines,
2075 };
2076