xref: /openbmc/linux/sound/soc/sof/ipc4-topology.c (revision 66dabbb6)
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_l)},
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: %uHz, %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 	/*
358 	 * This callback is used by host copier and module-to-module copier,
359 	 * and only host copier needs to set gtw_cfg.
360 	 */
361 	if (!WIDGET_IS_AIF(swidget->id))
362 		goto skip_gtw_cfg;
363 
364 	ret = sof_update_ipc_object(scomp, available_fmt->dma_buffer_size,
365 				    SOF_COPIER_GATEWAY_CFG_TOKENS, swidget->tuples,
366 				    swidget->num_tuples, sizeof(u32),
367 				    available_fmt->audio_fmt_num);
368 	if (ret) {
369 		dev_err(scomp->dev, "Failed to parse dma buffer size in audio format for %s\n",
370 			swidget->widget->name);
371 		goto err;
372 	}
373 
374 	dev_dbg(scomp->dev, "dma buffer size:\n");
375 	for (i = 0; i < available_fmt->audio_fmt_num; i++)
376 		dev_dbg(scomp->dev, "%d: %u\n", i,
377 			available_fmt->dma_buffer_size[i]);
378 
379 	ret = sof_update_ipc_object(scomp, &node_type,
380 				    SOF_COPIER_TOKENS, swidget->tuples,
381 				    swidget->num_tuples, sizeof(node_type), 1);
382 
383 	if (ret) {
384 		dev_err(scomp->dev, "parse host copier node type token failed %d\n",
385 			ret);
386 		goto err;
387 	}
388 	dev_dbg(scomp->dev, "host copier '%s' node_type %u\n", swidget->widget->name, node_type);
389 
390 skip_gtw_cfg:
391 	ipc4_copier->gtw_attr = kzalloc(sizeof(*ipc4_copier->gtw_attr), GFP_KERNEL);
392 	if (!ipc4_copier->gtw_attr) {
393 		ret = -ENOMEM;
394 		goto err;
395 	}
396 
397 	ipc4_copier->copier_config = (uint32_t *)ipc4_copier->gtw_attr;
398 	ipc4_copier->data.gtw_cfg.config_length =
399 		sizeof(struct sof_ipc4_gtw_attributes) >> 2;
400 
401 	switch (swidget->id) {
402 	case snd_soc_dapm_aif_in:
403 	case snd_soc_dapm_aif_out:
404 		ipc4_copier->data.gtw_cfg.node_id = SOF_IPC4_NODE_TYPE(node_type);
405 		break;
406 	case snd_soc_dapm_buffer:
407 		ipc4_copier->data.gtw_cfg.node_id = SOF_IPC4_INVALID_NODE_ID;
408 		ipc4_copier->ipc_config_size = 0;
409 		break;
410 	default:
411 		dev_err(scomp->dev, "invalid widget type %d\n", swidget->id);
412 		ret = -EINVAL;
413 		goto free_gtw_attr;
414 	}
415 
416 	/* set up module info and message header */
417 	ret = sof_ipc4_widget_setup_msg(swidget, &ipc4_copier->msg);
418 	if (ret)
419 		goto free_gtw_attr;
420 
421 	return 0;
422 
423 free_gtw_attr:
424 	kfree(ipc4_copier->gtw_attr);
425 err:
426 	kfree(available_fmt->dma_buffer_size);
427 free_available_fmt:
428 	sof_ipc4_free_audio_fmt(available_fmt);
429 free_copier:
430 	kfree(ipc4_copier);
431 	swidget->private = NULL;
432 	return ret;
433 }
434 
435 static void sof_ipc4_widget_free_comp_pcm(struct snd_sof_widget *swidget)
436 {
437 	struct sof_ipc4_copier *ipc4_copier = swidget->private;
438 	struct sof_ipc4_available_audio_format *available_fmt;
439 
440 	if (!ipc4_copier)
441 		return;
442 
443 	available_fmt = &ipc4_copier->available_fmt;
444 	kfree(available_fmt->dma_buffer_size);
445 	kfree(available_fmt->base_config);
446 	kfree(available_fmt->out_audio_fmt);
447 	kfree(ipc4_copier->gtw_attr);
448 	kfree(ipc4_copier);
449 	swidget->private = NULL;
450 }
451 
452 static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget)
453 {
454 	struct sof_ipc4_available_audio_format *available_fmt;
455 	struct snd_soc_component *scomp = swidget->scomp;
456 	struct snd_sof_dai *dai = swidget->private;
457 	struct sof_ipc4_copier *ipc4_copier;
458 	int node_type = 0;
459 	int ret, i;
460 
461 	ipc4_copier = kzalloc(sizeof(*ipc4_copier), GFP_KERNEL);
462 	if (!ipc4_copier)
463 		return -ENOMEM;
464 
465 	available_fmt = &ipc4_copier->available_fmt;
466 
467 	dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name);
468 
469 	ret = sof_ipc4_get_audio_fmt(scomp, swidget, available_fmt, true);
470 	if (ret)
471 		goto free_copier;
472 
473 	available_fmt->dma_buffer_size = kcalloc(available_fmt->audio_fmt_num, sizeof(u32),
474 						 GFP_KERNEL);
475 	if (!available_fmt->dma_buffer_size) {
476 		ret = -ENOMEM;
477 		goto free_available_fmt;
478 	}
479 
480 	ret = sof_update_ipc_object(scomp, available_fmt->dma_buffer_size,
481 				    SOF_COPIER_GATEWAY_CFG_TOKENS, swidget->tuples,
482 				    swidget->num_tuples, sizeof(u32),
483 				    available_fmt->audio_fmt_num);
484 	if (ret) {
485 		dev_err(scomp->dev, "Failed to parse dma buffer size in audio format for %s\n",
486 			swidget->widget->name);
487 		goto err;
488 	}
489 
490 	for (i = 0; i < available_fmt->audio_fmt_num; i++)
491 		dev_dbg(scomp->dev, "%d: dma buffer size: %u\n", i,
492 			available_fmt->dma_buffer_size[i]);
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 err;
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 err;
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_sof_widget *w;
521 
522 		blob = kzalloc(sizeof(*blob), GFP_KERNEL);
523 		if (!blob) {
524 			ret = -ENOMEM;
525 			goto err;
526 		}
527 
528 		list_for_each_entry(w, &sdev->widget_list, list) {
529 			if (w->widget->sname &&
530 			    strcmp(w->widget->sname, swidget->widget->sname))
531 				continue;
532 
533 			blob->alh_cfg.count++;
534 		}
535 
536 		ipc4_copier->copier_config = (uint32_t *)blob;
537 		ipc4_copier->data.gtw_cfg.config_length = sizeof(*blob) >> 2;
538 		break;
539 	}
540 	case SOF_DAI_INTEL_SSP:
541 		/* set SSP DAI index as the node_id */
542 		ipc4_copier->data.gtw_cfg.node_id |=
543 			SOF_IPC4_NODE_INDEX_INTEL_SSP(ipc4_copier->dai_index);
544 		break;
545 	case SOF_DAI_INTEL_DMIC:
546 		/* set DMIC DAI index as the node_id */
547 		ipc4_copier->data.gtw_cfg.node_id |=
548 			SOF_IPC4_NODE_INDEX_INTEL_DMIC(ipc4_copier->dai_index);
549 		break;
550 	default:
551 		ipc4_copier->gtw_attr = kzalloc(sizeof(*ipc4_copier->gtw_attr), GFP_KERNEL);
552 		if (!ipc4_copier->gtw_attr) {
553 			ret = -ENOMEM;
554 			goto err;
555 		}
556 
557 		ipc4_copier->copier_config = (uint32_t *)ipc4_copier->gtw_attr;
558 		ipc4_copier->data.gtw_cfg.config_length =
559 			sizeof(struct sof_ipc4_gtw_attributes) >> 2;
560 		break;
561 	}
562 
563 	dai->scomp = scomp;
564 	dai->private = ipc4_copier;
565 
566 	/* set up module info and message header */
567 	ret = sof_ipc4_widget_setup_msg(swidget, &ipc4_copier->msg);
568 	if (ret)
569 		goto free_copier_config;
570 
571 	return 0;
572 
573 free_copier_config:
574 	kfree(ipc4_copier->copier_config);
575 err:
576 	kfree(available_fmt->dma_buffer_size);
577 free_available_fmt:
578 	sof_ipc4_free_audio_fmt(available_fmt);
579 free_copier:
580 	kfree(ipc4_copier);
581 	dai->private = NULL;
582 	dai->scomp = NULL;
583 	return ret;
584 }
585 
586 static void sof_ipc4_widget_free_comp_dai(struct snd_sof_widget *swidget)
587 {
588 	struct sof_ipc4_available_audio_format *available_fmt;
589 	struct snd_sof_dai *dai = swidget->private;
590 	struct sof_ipc4_copier *ipc4_copier;
591 
592 	if (!dai)
593 		return;
594 
595 	if (!dai->private) {
596 		kfree(dai);
597 		swidget->private = NULL;
598 		return;
599 	}
600 
601 	ipc4_copier = dai->private;
602 	available_fmt = &ipc4_copier->available_fmt;
603 
604 	kfree(available_fmt->dma_buffer_size);
605 	kfree(available_fmt->base_config);
606 	kfree(available_fmt->out_audio_fmt);
607 	if (ipc4_copier->dai_type != SOF_DAI_INTEL_SSP &&
608 	    ipc4_copier->dai_type != SOF_DAI_INTEL_DMIC)
609 		kfree(ipc4_copier->copier_config);
610 	kfree(dai->private);
611 	kfree(dai);
612 	swidget->private = NULL;
613 }
614 
615 static int sof_ipc4_widget_setup_comp_pipeline(struct snd_sof_widget *swidget)
616 {
617 	struct snd_soc_component *scomp = swidget->scomp;
618 	struct sof_ipc4_pipeline *pipeline;
619 	int ret;
620 
621 	pipeline = kzalloc(sizeof(*pipeline), GFP_KERNEL);
622 	if (!pipeline)
623 		return -ENOMEM;
624 
625 	ret = sof_update_ipc_object(scomp, pipeline, SOF_SCHED_TOKENS, swidget->tuples,
626 				    swidget->num_tuples, sizeof(*pipeline), 1);
627 	if (ret) {
628 		dev_err(scomp->dev, "parsing scheduler tokens failed\n");
629 		goto err;
630 	}
631 
632 	/* parse one set of pipeline tokens */
633 	ret = sof_update_ipc_object(scomp, swidget, SOF_PIPELINE_TOKENS, swidget->tuples,
634 				    swidget->num_tuples, sizeof(*swidget), 1);
635 	if (ret) {
636 		dev_err(scomp->dev, "parsing pipeline tokens failed\n");
637 		goto err;
638 	}
639 
640 	/* TODO: Get priority from topology */
641 	pipeline->priority = 0;
642 
643 	dev_dbg(scomp->dev, "pipeline '%s': id %d pri %d lp mode %d\n",
644 		swidget->widget->name, swidget->pipeline_id,
645 		pipeline->priority, pipeline->lp_mode);
646 
647 	swidget->private = pipeline;
648 
649 	pipeline->msg.primary = SOF_IPC4_GLB_PIPE_PRIORITY(pipeline->priority);
650 	pipeline->msg.primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_CREATE_PIPELINE);
651 	pipeline->msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
652 	pipeline->msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG);
653 
654 	pipeline->msg.extension = pipeline->lp_mode;
655 	pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED;
656 
657 	return 0;
658 err:
659 	kfree(pipeline);
660 	return ret;
661 }
662 
663 static int sof_ipc4_widget_setup_comp_pga(struct snd_sof_widget *swidget)
664 {
665 	struct snd_soc_component *scomp = swidget->scomp;
666 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
667 	struct sof_ipc4_fw_module *fw_module;
668 	struct snd_sof_control *scontrol;
669 	struct sof_ipc4_gain *gain;
670 	int ret;
671 
672 	gain = kzalloc(sizeof(*gain), GFP_KERNEL);
673 	if (!gain)
674 		return -ENOMEM;
675 
676 	swidget->private = gain;
677 
678 	gain->data.channels = SOF_IPC4_GAIN_ALL_CHANNELS_MASK;
679 	gain->data.init_val = SOF_IPC4_VOL_ZERO_DB;
680 
681 	/* The out_audio_fmt in topology is ignored as it is not required to be sent to the FW */
682 	ret = sof_ipc4_get_audio_fmt(scomp, swidget, &gain->available_fmt, false);
683 	if (ret)
684 		goto err;
685 
686 	ret = sof_update_ipc_object(scomp, &gain->data, SOF_GAIN_TOKENS, swidget->tuples,
687 				    swidget->num_tuples, sizeof(gain->data), 1);
688 	if (ret) {
689 		dev_err(scomp->dev, "Parsing gain tokens failed\n");
690 		goto err;
691 	}
692 
693 	dev_dbg(scomp->dev,
694 		"pga widget %s: ramp type: %d, ramp duration %d, initial gain value: %#x, cpc %d\n",
695 		swidget->widget->name, gain->data.curve_type, gain->data.curve_duration_l,
696 		gain->data.init_val, gain->base_config.cpc);
697 
698 	ret = sof_ipc4_widget_setup_msg(swidget, &gain->msg);
699 	if (ret)
700 		goto err;
701 
702 	fw_module = swidget->module_info;
703 
704 	/* update module ID for all kcontrols for this widget */
705 	list_for_each_entry(scontrol, &sdev->kcontrol_list, list)
706 		if (scontrol->comp_id == swidget->comp_id) {
707 			struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
708 			struct sof_ipc4_msg *msg = &cdata->msg;
709 
710 			msg->primary |= fw_module->man4_module_entry.id;
711 		}
712 
713 	return 0;
714 err:
715 	sof_ipc4_free_audio_fmt(&gain->available_fmt);
716 	kfree(gain);
717 	swidget->private = NULL;
718 	return ret;
719 }
720 
721 static void sof_ipc4_widget_free_comp_pga(struct snd_sof_widget *swidget)
722 {
723 	struct sof_ipc4_gain *gain = swidget->private;
724 
725 	if (!gain)
726 		return;
727 
728 	sof_ipc4_free_audio_fmt(&gain->available_fmt);
729 	kfree(swidget->private);
730 	swidget->private = NULL;
731 }
732 
733 static int sof_ipc4_widget_setup_comp_mixer(struct snd_sof_widget *swidget)
734 {
735 	struct snd_soc_component *scomp = swidget->scomp;
736 	struct sof_ipc4_mixer *mixer;
737 	int ret;
738 
739 	dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name);
740 
741 	mixer = kzalloc(sizeof(*mixer), GFP_KERNEL);
742 	if (!mixer)
743 		return -ENOMEM;
744 
745 	swidget->private = mixer;
746 
747 	/* The out_audio_fmt in topology is ignored as it is not required to be sent to the FW */
748 	ret = sof_ipc4_get_audio_fmt(scomp, swidget, &mixer->available_fmt, false);
749 	if (ret)
750 		goto err;
751 
752 	ret = sof_ipc4_widget_setup_msg(swidget, &mixer->msg);
753 	if (ret)
754 		goto err;
755 
756 	return 0;
757 err:
758 	sof_ipc4_free_audio_fmt(&mixer->available_fmt);
759 	kfree(mixer);
760 	swidget->private = NULL;
761 	return ret;
762 }
763 
764 static int sof_ipc4_widget_setup_comp_src(struct snd_sof_widget *swidget)
765 {
766 	struct snd_soc_component *scomp = swidget->scomp;
767 	struct sof_ipc4_src *src;
768 	int ret;
769 
770 	dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name);
771 
772 	src = kzalloc(sizeof(*src), GFP_KERNEL);
773 	if (!src)
774 		return -ENOMEM;
775 
776 	swidget->private = src;
777 
778 	/* The out_audio_fmt in topology is ignored as it is not required by SRC */
779 	ret = sof_ipc4_get_audio_fmt(scomp, swidget, &src->available_fmt, false);
780 	if (ret)
781 		goto err;
782 
783 	ret = sof_update_ipc_object(scomp, src, SOF_SRC_TOKENS, swidget->tuples,
784 				    swidget->num_tuples, sizeof(*src), 1);
785 	if (ret) {
786 		dev_err(scomp->dev, "Parsing SRC tokens failed\n");
787 		goto err;
788 	}
789 
790 	dev_dbg(scomp->dev, "SRC sink rate %d\n", src->sink_rate);
791 
792 	ret = sof_ipc4_widget_setup_msg(swidget, &src->msg);
793 	if (ret)
794 		goto err;
795 
796 	return 0;
797 err:
798 	sof_ipc4_free_audio_fmt(&src->available_fmt);
799 	kfree(src);
800 	swidget->private = NULL;
801 	return ret;
802 }
803 
804 static void sof_ipc4_widget_free_comp_src(struct snd_sof_widget *swidget)
805 {
806 	struct sof_ipc4_src *src = swidget->private;
807 
808 	if (!src)
809 		return;
810 
811 	sof_ipc4_free_audio_fmt(&src->available_fmt);
812 	kfree(swidget->private);
813 	swidget->private = NULL;
814 }
815 
816 static void sof_ipc4_widget_free_comp_mixer(struct snd_sof_widget *swidget)
817 {
818 	struct sof_ipc4_mixer *mixer = swidget->private;
819 
820 	if (!mixer)
821 		return;
822 
823 	sof_ipc4_free_audio_fmt(&mixer->available_fmt);
824 	kfree(swidget->private);
825 	swidget->private = NULL;
826 }
827 
828 static void
829 sof_ipc4_update_pipeline_mem_usage(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
830 				   struct sof_ipc4_base_module_cfg *base_config)
831 {
832 	struct sof_ipc4_fw_module *fw_module = swidget->module_info;
833 	struct snd_sof_widget *pipe_widget;
834 	struct sof_ipc4_pipeline *pipeline;
835 	int task_mem, queue_mem;
836 	int ibs, bss, total;
837 
838 	ibs = base_config->ibs;
839 	bss = base_config->is_pages;
840 
841 	task_mem = SOF_IPC4_PIPELINE_OBJECT_SIZE;
842 	task_mem += SOF_IPC4_MODULE_INSTANCE_LIST_ITEM_SIZE + bss;
843 
844 	if (fw_module->man4_module_entry.type & SOF_IPC4_MODULE_LL) {
845 		task_mem += SOF_IPC4_FW_ROUNDUP(SOF_IPC4_LL_TASK_OBJECT_SIZE);
846 		task_mem += SOF_IPC4_FW_MAX_QUEUE_COUNT * SOF_IPC4_MODULE_INSTANCE_LIST_ITEM_SIZE;
847 		task_mem += SOF_IPC4_LL_TASK_LIST_ITEM_SIZE;
848 	} else {
849 		task_mem += SOF_IPC4_FW_ROUNDUP(SOF_IPC4_DP_TASK_OBJECT_SIZE);
850 		task_mem += SOF_IPC4_DP_TASK_LIST_SIZE;
851 	}
852 
853 	ibs = SOF_IPC4_FW_ROUNDUP(ibs);
854 	queue_mem = SOF_IPC4_FW_MAX_QUEUE_COUNT * (SOF_IPC4_DATA_QUEUE_OBJECT_SIZE +  ibs);
855 
856 	total = SOF_IPC4_FW_PAGE(task_mem + queue_mem);
857 
858 	pipe_widget = swidget->spipe->pipe_widget;
859 	pipeline = pipe_widget->private;
860 	pipeline->mem_usage += total;
861 }
862 
863 static int sof_ipc4_widget_assign_instance_id(struct snd_sof_dev *sdev,
864 					      struct snd_sof_widget *swidget)
865 {
866 	struct sof_ipc4_fw_module *fw_module = swidget->module_info;
867 	int max_instances = fw_module->man4_module_entry.instance_max_count;
868 
869 	swidget->instance_id = ida_alloc_max(&fw_module->m_ida, max_instances, GFP_KERNEL);
870 	if (swidget->instance_id < 0) {
871 		dev_err(sdev->dev, "failed to assign instance id for widget %s",
872 			swidget->widget->name);
873 		return swidget->instance_id;
874 	}
875 
876 	return 0;
877 }
878 
879 static int sof_ipc4_init_audio_fmt(struct snd_sof_dev *sdev,
880 				   struct snd_sof_widget *swidget,
881 				   struct sof_ipc4_base_module_cfg *base_config,
882 				   struct sof_ipc4_audio_format *out_format,
883 				   struct snd_pcm_hw_params *params,
884 				   struct sof_ipc4_available_audio_format *available_fmt,
885 				   size_t object_offset)
886 {
887 	void *ptr = available_fmt->ref_audio_fmt;
888 	u32 valid_bits;
889 	u32 channels;
890 	u32 rate;
891 	int sample_valid_bits;
892 	int i;
893 
894 	if (!ptr) {
895 		dev_err(sdev->dev, "no reference formats for %s\n", swidget->widget->name);
896 		return -EINVAL;
897 	}
898 
899 	switch (params_format(params)) {
900 	case SNDRV_PCM_FORMAT_S16_LE:
901 		sample_valid_bits = 16;
902 		break;
903 	case SNDRV_PCM_FORMAT_S24_LE:
904 		sample_valid_bits = 24;
905 		break;
906 	case SNDRV_PCM_FORMAT_S32_LE:
907 		sample_valid_bits = 32;
908 		break;
909 	default:
910 		dev_err(sdev->dev, "invalid pcm frame format %d\n", params_format(params));
911 		return -EINVAL;
912 	}
913 
914 	if (!available_fmt->audio_fmt_num) {
915 		dev_err(sdev->dev, "no formats available for %s\n", swidget->widget->name);
916 		return -EINVAL;
917 	}
918 
919 	/*
920 	 * Search supported audio formats to match rate, channels ,and
921 	 * sample_valid_bytes from runtime params
922 	 */
923 	for (i = 0; i < available_fmt->audio_fmt_num; i++, ptr = (u8 *)ptr + object_offset) {
924 		struct sof_ipc4_audio_format *fmt = ptr;
925 
926 		rate = fmt->sampling_frequency;
927 		channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg);
928 		valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
929 		if (params_rate(params) == rate && params_channels(params) == channels &&
930 		    sample_valid_bits == valid_bits) {
931 			dev_dbg(sdev->dev, "matching audio format index for %uHz, %ubit, %u channels: %d\n",
932 				rate, valid_bits, channels, i);
933 
934 			/* copy ibs/obs and input format */
935 			memcpy(base_config, &available_fmt->base_config[i],
936 			       sizeof(struct sof_ipc4_base_module_cfg));
937 
938 			/* copy output format */
939 			if (out_format)
940 				memcpy(out_format, &available_fmt->out_audio_fmt[i],
941 				       sizeof(struct sof_ipc4_audio_format));
942 			break;
943 		}
944 	}
945 
946 	if (i == available_fmt->audio_fmt_num) {
947 		dev_err(sdev->dev, "%s: Unsupported audio format: %uHz, %ubit, %u channels\n",
948 			__func__, params_rate(params), sample_valid_bits, params_channels(params));
949 		return -EINVAL;
950 	}
951 
952 	dev_dbg(sdev->dev, "Init input audio formats for %s\n", swidget->widget->name);
953 	sof_ipc4_dbg_audio_format(sdev->dev, &base_config->audio_fmt,
954 				  sizeof(*base_config), 1);
955 	if (out_format) {
956 		dev_dbg(sdev->dev, "Init output audio formats for %s\n", swidget->widget->name);
957 		sof_ipc4_dbg_audio_format(sdev->dev, out_format,
958 					  sizeof(*out_format), 1);
959 	}
960 
961 	/* Return the index of the matched format */
962 	return i;
963 }
964 
965 static void sof_ipc4_unprepare_copier_module(struct snd_sof_widget *swidget)
966 {
967 	struct sof_ipc4_copier *ipc4_copier = NULL;
968 	struct snd_sof_widget *pipe_widget;
969 	struct sof_ipc4_pipeline *pipeline;
970 
971 	/* reset pipeline memory usage */
972 	pipe_widget = swidget->spipe->pipe_widget;
973 	pipeline = pipe_widget->private;
974 	pipeline->mem_usage = 0;
975 
976 	if (WIDGET_IS_AIF(swidget->id) || swidget->id == snd_soc_dapm_buffer) {
977 		ipc4_copier = swidget->private;
978 	} else if (WIDGET_IS_DAI(swidget->id)) {
979 		struct snd_sof_dai *dai = swidget->private;
980 
981 		ipc4_copier = dai->private;
982 		if (ipc4_copier->dai_type == SOF_DAI_INTEL_ALH) {
983 			struct sof_ipc4_copier_data *copier_data = &ipc4_copier->data;
984 			struct sof_ipc4_alh_configuration_blob *blob;
985 			unsigned int group_id;
986 
987 			blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config;
988 			if (blob->alh_cfg.count > 1) {
989 				group_id = SOF_IPC4_NODE_INDEX(ipc4_copier->data.gtw_cfg.node_id) -
990 					   ALH_MULTI_GTW_BASE;
991 				ida_free(&alh_group_ida, group_id);
992 			}
993 
994 			/* clear the node ID */
995 			copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
996 		}
997 	}
998 
999 	if (ipc4_copier) {
1000 		kfree(ipc4_copier->ipc_config_data);
1001 		ipc4_copier->ipc_config_data = NULL;
1002 		ipc4_copier->ipc_config_size = 0;
1003 	}
1004 }
1005 
1006 #if IS_ENABLED(CONFIG_ACPI) && IS_ENABLED(CONFIG_SND_INTEL_NHLT)
1007 static int snd_sof_get_hw_config_params(struct snd_sof_dev *sdev, struct snd_sof_dai *dai,
1008 					int *sample_rate, int *channel_count, int *bit_depth)
1009 {
1010 	struct snd_soc_tplg_hw_config *hw_config;
1011 	struct snd_sof_dai_link *slink;
1012 	bool dai_link_found = false;
1013 	bool hw_cfg_found = false;
1014 	int i;
1015 
1016 	/* get current hw_config from link */
1017 	list_for_each_entry(slink, &sdev->dai_link_list, list) {
1018 		if (!strcmp(slink->link->name, dai->name)) {
1019 			dai_link_found = true;
1020 			break;
1021 		}
1022 	}
1023 
1024 	if (!dai_link_found) {
1025 		dev_err(sdev->dev, "%s: no DAI link found for DAI %s\n", __func__, dai->name);
1026 		return -EINVAL;
1027 	}
1028 
1029 	for (i = 0; i < slink->num_hw_configs; i++) {
1030 		hw_config = &slink->hw_configs[i];
1031 		if (dai->current_config == le32_to_cpu(hw_config->id)) {
1032 			hw_cfg_found = true;
1033 			break;
1034 		}
1035 	}
1036 
1037 	if (!hw_cfg_found) {
1038 		dev_err(sdev->dev, "%s: no matching hw_config found for DAI %s\n", __func__,
1039 			dai->name);
1040 		return -EINVAL;
1041 	}
1042 
1043 	*bit_depth = le32_to_cpu(hw_config->tdm_slot_width);
1044 	*channel_count = le32_to_cpu(hw_config->tdm_slots);
1045 	*sample_rate = le32_to_cpu(hw_config->fsync_rate);
1046 
1047 	dev_dbg(sdev->dev, "sample rate: %d sample width: %d channels: %d\n",
1048 		*sample_rate, *bit_depth, *channel_count);
1049 
1050 	return 0;
1051 }
1052 
1053 static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai,
1054 					  struct snd_pcm_hw_params *params, u32 dai_index,
1055 					  u32 linktype, u8 dir, u32 **dst, u32 *len)
1056 {
1057 	struct sof_ipc4_fw_data *ipc4_data = sdev->private;
1058 	struct nhlt_specific_cfg *cfg;
1059 	int sample_rate, channel_count;
1060 	int bit_depth, ret;
1061 	u32 nhlt_type;
1062 
1063 	/* convert to NHLT type */
1064 	switch (linktype) {
1065 	case SOF_DAI_INTEL_DMIC:
1066 		nhlt_type = NHLT_LINK_DMIC;
1067 		bit_depth = params_width(params);
1068 		channel_count = params_channels(params);
1069 		sample_rate = params_rate(params);
1070 		break;
1071 	case SOF_DAI_INTEL_SSP:
1072 		nhlt_type = NHLT_LINK_SSP;
1073 		ret = snd_sof_get_hw_config_params(sdev, dai, &sample_rate, &channel_count,
1074 						   &bit_depth);
1075 		if (ret < 0)
1076 			return ret;
1077 		break;
1078 	default:
1079 		return 0;
1080 	}
1081 
1082 	dev_dbg(sdev->dev, "dai index %d nhlt type %d direction %d\n",
1083 		dai_index, nhlt_type, dir);
1084 
1085 	/* find NHLT blob with matching params */
1086 	cfg = intel_nhlt_get_endpoint_blob(sdev->dev, ipc4_data->nhlt, dai_index, nhlt_type,
1087 					   bit_depth, bit_depth, channel_count, sample_rate,
1088 					   dir, 0);
1089 
1090 	if (!cfg) {
1091 		dev_err(sdev->dev,
1092 			"no matching blob for sample rate: %d sample width: %d channels: %d\n",
1093 			sample_rate, bit_depth, channel_count);
1094 		return -EINVAL;
1095 	}
1096 
1097 	/* config length should be in dwords */
1098 	*len = cfg->size >> 2;
1099 	*dst = (u32 *)cfg->caps;
1100 
1101 	return 0;
1102 }
1103 #else
1104 static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai,
1105 					  struct snd_pcm_hw_params *params, u32 dai_index,
1106 					  u32 linktype, u8 dir, u32 **dst, u32 *len)
1107 {
1108 	return 0;
1109 }
1110 #endif
1111 
1112 static int
1113 sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
1114 			       struct snd_pcm_hw_params *fe_params,
1115 			       struct snd_sof_platform_stream_params *platform_params,
1116 			       struct snd_pcm_hw_params *pipeline_params, int dir)
1117 {
1118 	struct sof_ipc4_available_audio_format *available_fmt;
1119 	struct snd_soc_component *scomp = swidget->scomp;
1120 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1121 	struct sof_ipc4_copier_data *copier_data;
1122 	struct snd_pcm_hw_params *ref_params;
1123 	struct sof_ipc4_copier *ipc4_copier;
1124 	struct snd_sof_dai *dai;
1125 	struct snd_mask *fmt;
1126 	int out_sample_valid_bits;
1127 	size_t ref_audio_fmt_size;
1128 	void **ipc_config_data;
1129 	int *ipc_config_size;
1130 	u32 **data;
1131 	int ipc_size, ret;
1132 
1133 	dev_dbg(sdev->dev, "copier %s, type %d", swidget->widget->name, swidget->id);
1134 
1135 	switch (swidget->id) {
1136 	case snd_soc_dapm_aif_in:
1137 	case snd_soc_dapm_aif_out:
1138 	{
1139 		struct sof_ipc4_gtw_attributes *gtw_attr;
1140 		struct snd_sof_widget *pipe_widget;
1141 		struct sof_ipc4_pipeline *pipeline;
1142 
1143 		pipe_widget = swidget->spipe->pipe_widget;
1144 		pipeline = pipe_widget->private;
1145 		ipc4_copier = (struct sof_ipc4_copier *)swidget->private;
1146 		gtw_attr = ipc4_copier->gtw_attr;
1147 		copier_data = &ipc4_copier->data;
1148 		available_fmt = &ipc4_copier->available_fmt;
1149 
1150 		/*
1151 		 * base_config->audio_fmt and out_audio_fmt represent the input and output audio
1152 		 * formats. Use the input format as the reference to match pcm params for playback
1153 		 * and the output format as reference for capture.
1154 		 */
1155 		if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
1156 			available_fmt->ref_audio_fmt = &available_fmt->base_config->audio_fmt;
1157 			ref_audio_fmt_size = sizeof(struct sof_ipc4_base_module_cfg);
1158 		} else {
1159 			available_fmt->ref_audio_fmt = available_fmt->out_audio_fmt;
1160 			ref_audio_fmt_size = sizeof(struct sof_ipc4_audio_format);
1161 		}
1162 		copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
1163 		copier_data->gtw_cfg.node_id |=
1164 			SOF_IPC4_NODE_INDEX(platform_params->stream_tag - 1);
1165 
1166 		/* set gateway attributes */
1167 		gtw_attr->lp_buffer_alloc = pipeline->lp_mode;
1168 		ref_params = fe_params;
1169 		break;
1170 	}
1171 	case snd_soc_dapm_dai_in:
1172 	case snd_soc_dapm_dai_out:
1173 	{
1174 		dai = swidget->private;
1175 
1176 		ipc4_copier = (struct sof_ipc4_copier *)dai->private;
1177 		copier_data = &ipc4_copier->data;
1178 		available_fmt = &ipc4_copier->available_fmt;
1179 		if (dir == SNDRV_PCM_STREAM_CAPTURE) {
1180 			available_fmt->ref_audio_fmt = available_fmt->out_audio_fmt;
1181 			ref_audio_fmt_size = sizeof(struct sof_ipc4_audio_format);
1182 
1183 			/*
1184 			 * modify the input params for the dai copier as it only supports
1185 			 * 32-bit always
1186 			 */
1187 			fmt = hw_param_mask(pipeline_params, SNDRV_PCM_HW_PARAM_FORMAT);
1188 			snd_mask_none(fmt);
1189 			snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE);
1190 		} else {
1191 			available_fmt->ref_audio_fmt = &available_fmt->base_config->audio_fmt;
1192 			ref_audio_fmt_size = sizeof(struct sof_ipc4_base_module_cfg);
1193 		}
1194 
1195 		ref_params = pipeline_params;
1196 
1197 		ret = snd_sof_get_nhlt_endpoint_data(sdev, dai, fe_params, ipc4_copier->dai_index,
1198 						     ipc4_copier->dai_type, dir,
1199 						     &ipc4_copier->copier_config,
1200 						     &copier_data->gtw_cfg.config_length);
1201 		if (ret < 0)
1202 			return ret;
1203 
1204 		break;
1205 	}
1206 	case snd_soc_dapm_buffer:
1207 	{
1208 		ipc4_copier = (struct sof_ipc4_copier *)swidget->private;
1209 		copier_data = &ipc4_copier->data;
1210 		available_fmt = &ipc4_copier->available_fmt;
1211 
1212 		/*
1213 		 * base_config->audio_fmt represent the input audio formats. Use
1214 		 * the input format as the reference to match pcm params
1215 		 */
1216 		available_fmt->ref_audio_fmt = &available_fmt->base_config->audio_fmt;
1217 		ref_audio_fmt_size = sizeof(struct sof_ipc4_base_module_cfg);
1218 		ref_params = pipeline_params;
1219 
1220 		break;
1221 	}
1222 	default:
1223 		dev_err(sdev->dev, "unsupported type %d for copier %s",
1224 			swidget->id, swidget->widget->name);
1225 		return -EINVAL;
1226 	}
1227 
1228 	/* set input and output audio formats */
1229 	ret = sof_ipc4_init_audio_fmt(sdev, swidget, &copier_data->base_config,
1230 				      &copier_data->out_format, ref_params,
1231 				      available_fmt, ref_audio_fmt_size);
1232 	if (ret < 0)
1233 		return ret;
1234 
1235 	switch (swidget->id) {
1236 	case snd_soc_dapm_dai_in:
1237 	case snd_soc_dapm_dai_out:
1238 	{
1239 		/*
1240 		 * Only SOF_DAI_INTEL_ALH needs copier_data to set blob.
1241 		 * That's why only ALH dai's blob is set after sof_ipc4_init_audio_fmt
1242 		 */
1243 		if (ipc4_copier->dai_type == SOF_DAI_INTEL_ALH) {
1244 			struct sof_ipc4_alh_configuration_blob *blob;
1245 			struct sof_ipc4_copier_data *alh_data;
1246 			struct sof_ipc4_copier *alh_copier;
1247 			struct snd_sof_widget *w;
1248 			u32 ch_count = 0;
1249 			u32 ch_mask = 0;
1250 			u32 ch_map;
1251 			u32 step;
1252 			u32 mask;
1253 			int i;
1254 
1255 			blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config;
1256 
1257 			blob->gw_attr.lp_buffer_alloc = 0;
1258 
1259 			/* Get channel_mask from ch_map */
1260 			ch_map = copier_data->base_config.audio_fmt.ch_map;
1261 			for (i = 0; ch_map; i++) {
1262 				if ((ch_map & 0xf) != 0xf) {
1263 					ch_mask |= BIT(i);
1264 					ch_count++;
1265 				}
1266 				ch_map >>= 4;
1267 			}
1268 
1269 			step = ch_count / blob->alh_cfg.count;
1270 			mask =  GENMASK(step - 1, 0);
1271 			/*
1272 			 * Set each gtw_cfg.node_id to blob->alh_cfg.mapping[]
1273 			 * for all widgets with the same stream name
1274 			 */
1275 			i = 0;
1276 			list_for_each_entry(w, &sdev->widget_list, list) {
1277 				if (w->widget->sname &&
1278 				    strcmp(w->widget->sname, swidget->widget->sname))
1279 					continue;
1280 
1281 				dai = w->private;
1282 				alh_copier = (struct sof_ipc4_copier *)dai->private;
1283 				alh_data = &alh_copier->data;
1284 				blob->alh_cfg.mapping[i].alh_id = alh_data->gtw_cfg.node_id;
1285 				/*
1286 				 * Set the same channel mask for playback as the audio data is
1287 				 * duplicated for all speakers. For capture, split the channels
1288 				 * among the aggregated DAIs. For example, with 4 channels on 2
1289 				 * aggregated DAIs, the channel_mask should be 0x3 and 0xc for the
1290 				 * two DAI's.
1291 				 * The channel masks used depend on the cpu_dais used in the
1292 				 * dailink at the machine driver level, which actually comes from
1293 				 * the tables in soc_acpi files depending on the _ADR and devID
1294 				 * registers for each codec.
1295 				 */
1296 				if (w->id == snd_soc_dapm_dai_in)
1297 					blob->alh_cfg.mapping[i].channel_mask = ch_mask;
1298 				else
1299 					blob->alh_cfg.mapping[i].channel_mask = mask << (step * i);
1300 
1301 				i++;
1302 			}
1303 			if (blob->alh_cfg.count > 1) {
1304 				int group_id;
1305 
1306 				group_id = ida_alloc_max(&alh_group_ida, ALH_MULTI_GTW_COUNT - 1,
1307 							 GFP_KERNEL);
1308 
1309 				if (group_id < 0)
1310 					return group_id;
1311 
1312 				/* add multi-gateway base */
1313 				group_id += ALH_MULTI_GTW_BASE;
1314 				copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
1315 				copier_data->gtw_cfg.node_id |= SOF_IPC4_NODE_INDEX(group_id);
1316 			}
1317 		}
1318 	}
1319 	}
1320 
1321 	/* modify the input params for the next widget */
1322 	fmt = hw_param_mask(pipeline_params, SNDRV_PCM_HW_PARAM_FORMAT);
1323 	out_sample_valid_bits =
1324 		SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(copier_data->out_format.fmt_cfg);
1325 	snd_mask_none(fmt);
1326 	switch (out_sample_valid_bits) {
1327 	case 16:
1328 		snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
1329 		break;
1330 	case 24:
1331 		snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
1332 		break;
1333 	case 32:
1334 		snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE);
1335 		break;
1336 	default:
1337 		dev_err(sdev->dev, "invalid sample frame format %d\n",
1338 			params_format(pipeline_params));
1339 		return -EINVAL;
1340 	}
1341 
1342 	/* set the gateway dma_buffer_size using the matched ID returned above */
1343 	copier_data->gtw_cfg.dma_buffer_size = available_fmt->dma_buffer_size[ret];
1344 
1345 	data = &ipc4_copier->copier_config;
1346 	ipc_config_size = &ipc4_copier->ipc_config_size;
1347 	ipc_config_data = &ipc4_copier->ipc_config_data;
1348 
1349 	/* config_length is DWORD based */
1350 	ipc_size = sizeof(*copier_data) + copier_data->gtw_cfg.config_length * 4;
1351 
1352 	dev_dbg(sdev->dev, "copier %s, IPC size is %d", swidget->widget->name, ipc_size);
1353 
1354 	*ipc_config_data = kzalloc(ipc_size, GFP_KERNEL);
1355 	if (!*ipc_config_data)
1356 		return -ENOMEM;
1357 
1358 	*ipc_config_size = ipc_size;
1359 
1360 	/* copy IPC data */
1361 	memcpy(*ipc_config_data, (void *)copier_data, sizeof(*copier_data));
1362 	if (copier_data->gtw_cfg.config_length)
1363 		memcpy(*ipc_config_data + sizeof(*copier_data),
1364 		       *data, copier_data->gtw_cfg.config_length * 4);
1365 
1366 	/* update pipeline memory usage */
1367 	sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &copier_data->base_config);
1368 
1369 	return 0;
1370 }
1371 
1372 static int sof_ipc4_prepare_gain_module(struct snd_sof_widget *swidget,
1373 					struct snd_pcm_hw_params *fe_params,
1374 					struct snd_sof_platform_stream_params *platform_params,
1375 					struct snd_pcm_hw_params *pipeline_params, int dir)
1376 {
1377 	struct snd_soc_component *scomp = swidget->scomp;
1378 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1379 	struct sof_ipc4_gain *gain = swidget->private;
1380 	int ret;
1381 
1382 	gain->available_fmt.ref_audio_fmt = &gain->available_fmt.base_config->audio_fmt;
1383 
1384 	/* output format is not required to be sent to the FW for gain */
1385 	ret = sof_ipc4_init_audio_fmt(sdev, swidget, &gain->base_config,
1386 				      NULL, pipeline_params, &gain->available_fmt,
1387 				      sizeof(gain->base_config));
1388 	if (ret < 0)
1389 		return ret;
1390 
1391 	/* update pipeline memory usage */
1392 	sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &gain->base_config);
1393 
1394 	return 0;
1395 }
1396 
1397 static int sof_ipc4_prepare_mixer_module(struct snd_sof_widget *swidget,
1398 					 struct snd_pcm_hw_params *fe_params,
1399 					 struct snd_sof_platform_stream_params *platform_params,
1400 					 struct snd_pcm_hw_params *pipeline_params, int dir)
1401 {
1402 	struct snd_soc_component *scomp = swidget->scomp;
1403 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1404 	struct sof_ipc4_mixer *mixer = swidget->private;
1405 	int ret;
1406 
1407 	/* only 32bit is supported by mixer */
1408 	mixer->available_fmt.ref_audio_fmt = &mixer->available_fmt.base_config->audio_fmt;
1409 
1410 	/* output format is not required to be sent to the FW for mixer */
1411 	ret = sof_ipc4_init_audio_fmt(sdev, swidget, &mixer->base_config,
1412 				      NULL, pipeline_params, &mixer->available_fmt,
1413 				      sizeof(mixer->base_config));
1414 	if (ret < 0)
1415 		return ret;
1416 
1417 	/* update pipeline memory usage */
1418 	sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &mixer->base_config);
1419 
1420 	return 0;
1421 }
1422 
1423 static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget,
1424 				       struct snd_pcm_hw_params *fe_params,
1425 				       struct snd_sof_platform_stream_params *platform_params,
1426 				       struct snd_pcm_hw_params *pipeline_params, int dir)
1427 {
1428 	struct snd_soc_component *scomp = swidget->scomp;
1429 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1430 	struct sof_ipc4_src *src = swidget->private;
1431 	struct snd_interval *rate;
1432 	int ret;
1433 
1434 	src->available_fmt.ref_audio_fmt = &src->available_fmt.base_config->audio_fmt;
1435 
1436 	/* output format is not required to be sent to the FW for SRC */
1437 	ret = sof_ipc4_init_audio_fmt(sdev, swidget, &src->base_config,
1438 				      NULL, pipeline_params, &src->available_fmt,
1439 				      sizeof(src->base_config));
1440 	if (ret < 0)
1441 		return ret;
1442 
1443 	/* update pipeline memory usage */
1444 	sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &src->base_config);
1445 
1446 	/* update pipeline_params for sink widgets */
1447 	rate = hw_param_interval(pipeline_params, SNDRV_PCM_HW_PARAM_RATE);
1448 	rate->min = src->sink_rate;
1449 	rate->max = rate->min;
1450 
1451 	return 0;
1452 }
1453 
1454 static int sof_ipc4_control_load_volume(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
1455 {
1456 	struct sof_ipc4_control_data *control_data;
1457 	struct sof_ipc4_msg *msg;
1458 	int i;
1459 
1460 	scontrol->size = struct_size(control_data, chanv, scontrol->num_channels);
1461 
1462 	/* scontrol->ipc_control_data will be freed in sof_control_unload */
1463 	scontrol->ipc_control_data = kzalloc(scontrol->size, GFP_KERNEL);
1464 	if (!scontrol->ipc_control_data)
1465 		return -ENOMEM;
1466 
1467 	control_data = scontrol->ipc_control_data;
1468 	control_data->index = scontrol->index;
1469 
1470 	msg = &control_data->msg;
1471 	msg->primary = SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_LARGE_CONFIG_SET);
1472 	msg->primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
1473 	msg->primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
1474 
1475 	msg->extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_GAIN_PARAM_ID);
1476 
1477 	/* set default volume values to 0dB in control */
1478 	for (i = 0; i < scontrol->num_channels; i++) {
1479 		control_data->chanv[i].channel = i;
1480 		control_data->chanv[i].value = SOF_IPC4_VOL_ZERO_DB;
1481 	}
1482 
1483 	return 0;
1484 }
1485 
1486 static int sof_ipc4_control_setup(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
1487 {
1488 	switch (scontrol->info_type) {
1489 	case SND_SOC_TPLG_CTL_VOLSW:
1490 	case SND_SOC_TPLG_CTL_VOLSW_SX:
1491 	case SND_SOC_TPLG_CTL_VOLSW_XR_SX:
1492 		return sof_ipc4_control_load_volume(sdev, scontrol);
1493 	default:
1494 		break;
1495 	}
1496 
1497 	return 0;
1498 }
1499 
1500 static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
1501 {
1502 	struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
1503 	struct sof_ipc4_fw_data *ipc4_data = sdev->private;
1504 	struct sof_ipc4_pipeline *pipeline;
1505 	struct sof_ipc4_msg *msg;
1506 	void *ipc_data = NULL;
1507 	u32 ipc_size = 0;
1508 	int ret;
1509 
1510 	switch (swidget->id) {
1511 	case snd_soc_dapm_scheduler:
1512 		pipeline = swidget->private;
1513 
1514 		dev_dbg(sdev->dev, "pipeline: %d memory pages: %d\n", swidget->pipeline_id,
1515 			pipeline->mem_usage);
1516 
1517 		msg = &pipeline->msg;
1518 		msg->primary |= pipeline->mem_usage;
1519 
1520 		swidget->instance_id = ida_alloc_max(&pipeline_ida, ipc4_data->max_num_pipelines,
1521 						     GFP_KERNEL);
1522 		if (swidget->instance_id < 0) {
1523 			dev_err(sdev->dev, "failed to assign pipeline id for %s: %d\n",
1524 				swidget->widget->name, swidget->instance_id);
1525 			return swidget->instance_id;
1526 		}
1527 		msg->primary &= ~SOF_IPC4_GLB_PIPE_INSTANCE_MASK;
1528 		msg->primary |= SOF_IPC4_GLB_PIPE_INSTANCE_ID(swidget->instance_id);
1529 		break;
1530 	case snd_soc_dapm_aif_in:
1531 	case snd_soc_dapm_aif_out:
1532 	case snd_soc_dapm_buffer:
1533 	{
1534 		struct sof_ipc4_copier *ipc4_copier = swidget->private;
1535 
1536 		ipc_size = ipc4_copier->ipc_config_size;
1537 		ipc_data = ipc4_copier->ipc_config_data;
1538 
1539 		msg = &ipc4_copier->msg;
1540 		break;
1541 	}
1542 	case snd_soc_dapm_dai_in:
1543 	case snd_soc_dapm_dai_out:
1544 	{
1545 		struct snd_sof_dai *dai = swidget->private;
1546 		struct sof_ipc4_copier *ipc4_copier = dai->private;
1547 
1548 		ipc_size = ipc4_copier->ipc_config_size;
1549 		ipc_data = ipc4_copier->ipc_config_data;
1550 
1551 		msg = &ipc4_copier->msg;
1552 		break;
1553 	}
1554 	case snd_soc_dapm_pga:
1555 	{
1556 		struct sof_ipc4_gain *gain = swidget->private;
1557 
1558 		ipc_size = sizeof(struct sof_ipc4_base_module_cfg) +
1559 			   sizeof(struct sof_ipc4_gain_data);
1560 		ipc_data = gain;
1561 
1562 		msg = &gain->msg;
1563 		break;
1564 	}
1565 	case snd_soc_dapm_mixer:
1566 	{
1567 		struct sof_ipc4_mixer *mixer = swidget->private;
1568 
1569 		ipc_size = sizeof(mixer->base_config);
1570 		ipc_data = &mixer->base_config;
1571 
1572 		msg = &mixer->msg;
1573 		break;
1574 	}
1575 	case snd_soc_dapm_src:
1576 	{
1577 		struct sof_ipc4_src *src = swidget->private;
1578 
1579 		ipc_size = sizeof(struct sof_ipc4_base_module_cfg) + sizeof(src->sink_rate);
1580 		ipc_data = src;
1581 
1582 		msg = &src->msg;
1583 		break;
1584 	}
1585 	default:
1586 		dev_err(sdev->dev, "widget type %d not supported", swidget->id);
1587 		return -EINVAL;
1588 	}
1589 
1590 	if (swidget->id != snd_soc_dapm_scheduler) {
1591 		ret = sof_ipc4_widget_assign_instance_id(sdev, swidget);
1592 		if (ret < 0) {
1593 			dev_err(sdev->dev, "failed to assign instance id for %s\n",
1594 				swidget->widget->name);
1595 			return ret;
1596 		}
1597 
1598 		msg->primary &= ~SOF_IPC4_MOD_INSTANCE_MASK;
1599 		msg->primary |= SOF_IPC4_MOD_INSTANCE(swidget->instance_id);
1600 
1601 		msg->extension &= ~SOF_IPC4_MOD_EXT_PARAM_SIZE_MASK;
1602 		msg->extension |= ipc_size >> 2;
1603 
1604 		msg->extension &= ~SOF_IPC4_MOD_EXT_PPL_ID_MASK;
1605 		msg->extension |= SOF_IPC4_MOD_EXT_PPL_ID(pipe_widget->instance_id);
1606 	}
1607 	dev_dbg(sdev->dev, "Create widget %s instance %d - pipe %d - core %d\n",
1608 		swidget->widget->name, swidget->instance_id, swidget->pipeline_id, swidget->core);
1609 
1610 	msg->data_size = ipc_size;
1611 	msg->data_ptr = ipc_data;
1612 
1613 	ret = sof_ipc_tx_message(sdev->ipc, msg, ipc_size, NULL, 0);
1614 	if (ret < 0) {
1615 		dev_err(sdev->dev, "failed to create module %s\n", swidget->widget->name);
1616 
1617 		if (swidget->id != snd_soc_dapm_scheduler) {
1618 			struct sof_ipc4_fw_module *fw_module = swidget->module_info;
1619 
1620 			ida_free(&fw_module->m_ida, swidget->instance_id);
1621 		} else {
1622 			ida_free(&pipeline_ida, swidget->instance_id);
1623 		}
1624 	}
1625 
1626 	return ret;
1627 }
1628 
1629 static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
1630 {
1631 	struct sof_ipc4_fw_module *fw_module = swidget->module_info;
1632 	struct sof_ipc4_fw_data *ipc4_data = sdev->private;
1633 	int ret = 0;
1634 
1635 	mutex_lock(&ipc4_data->pipeline_state_mutex);
1636 
1637 	/* freeing a pipeline frees all the widgets associated with it */
1638 	if (swidget->id == snd_soc_dapm_scheduler) {
1639 		struct sof_ipc4_pipeline *pipeline = swidget->private;
1640 		struct sof_ipc4_msg msg = {{ 0 }};
1641 		u32 header;
1642 
1643 		header = SOF_IPC4_GLB_PIPE_INSTANCE_ID(swidget->instance_id);
1644 		header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_DELETE_PIPELINE);
1645 		header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
1646 		header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG);
1647 
1648 		msg.primary = header;
1649 
1650 		ret = sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0);
1651 		if (ret < 0)
1652 			dev_err(sdev->dev, "failed to free pipeline widget %s\n",
1653 				swidget->widget->name);
1654 
1655 		pipeline->mem_usage = 0;
1656 		pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED;
1657 		ida_free(&pipeline_ida, swidget->instance_id);
1658 	} else {
1659 		ida_free(&fw_module->m_ida, swidget->instance_id);
1660 	}
1661 
1662 	mutex_unlock(&ipc4_data->pipeline_state_mutex);
1663 
1664 	return ret;
1665 }
1666 
1667 static int sof_ipc4_get_queue_id(struct snd_sof_widget *src_widget,
1668 				 struct snd_sof_widget *sink_widget, bool pin_type)
1669 {
1670 	struct snd_sof_widget *current_swidget;
1671 	struct snd_soc_component *scomp;
1672 	struct ida *queue_ida;
1673 	const char *buddy_name;
1674 	char **pin_binding;
1675 	u32 num_pins;
1676 	int i;
1677 
1678 	if (pin_type == SOF_PIN_TYPE_SOURCE) {
1679 		current_swidget = src_widget;
1680 		pin_binding = src_widget->src_pin_binding;
1681 		queue_ida = &src_widget->src_queue_ida;
1682 		num_pins = src_widget->num_source_pins;
1683 		buddy_name = sink_widget->widget->name;
1684 	} else {
1685 		current_swidget = sink_widget;
1686 		pin_binding = sink_widget->sink_pin_binding;
1687 		queue_ida = &sink_widget->sink_queue_ida;
1688 		num_pins = sink_widget->num_sink_pins;
1689 		buddy_name = src_widget->widget->name;
1690 	}
1691 
1692 	scomp = current_swidget->scomp;
1693 
1694 	if (num_pins < 1) {
1695 		dev_err(scomp->dev, "invalid %s num_pins: %d for queue allocation for %s\n",
1696 			(pin_type == SOF_PIN_TYPE_SOURCE ? "source" : "sink"),
1697 			num_pins, current_swidget->widget->name);
1698 		return -EINVAL;
1699 	}
1700 
1701 	/* If there is only one sink/source pin, queue id must be 0 */
1702 	if (num_pins == 1)
1703 		return 0;
1704 
1705 	/* Allocate queue ID from pin binding array if it is defined in topology. */
1706 	if (pin_binding) {
1707 		for (i = 0; i < num_pins; i++) {
1708 			if (!strcmp(pin_binding[i], buddy_name))
1709 				return i;
1710 		}
1711 		/*
1712 		 * Fail if no queue ID found from pin binding array, so that we don't
1713 		 * mixed use pin binding array and ida for queue ID allocation.
1714 		 */
1715 		dev_err(scomp->dev, "no %s queue id found from pin binding array for %s\n",
1716 			(pin_type == SOF_PIN_TYPE_SOURCE ? "source" : "sink"),
1717 			current_swidget->widget->name);
1718 		return -EINVAL;
1719 	}
1720 
1721 	/* If no pin binding array specified in topology, use ida to allocate one */
1722 	return ida_alloc_max(queue_ida, num_pins, GFP_KERNEL);
1723 }
1724 
1725 static void sof_ipc4_put_queue_id(struct snd_sof_widget *swidget, int queue_id,
1726 				  bool pin_type)
1727 {
1728 	struct ida *queue_ida;
1729 	char **pin_binding;
1730 	int num_pins;
1731 
1732 	if (pin_type == SOF_PIN_TYPE_SOURCE) {
1733 		pin_binding = swidget->src_pin_binding;
1734 		queue_ida = &swidget->src_queue_ida;
1735 		num_pins = swidget->num_source_pins;
1736 	} else {
1737 		pin_binding = swidget->sink_pin_binding;
1738 		queue_ida = &swidget->sink_queue_ida;
1739 		num_pins = swidget->num_sink_pins;
1740 	}
1741 
1742 	/* Nothing to free if queue ID is not allocated with ida. */
1743 	if (num_pins == 1 || pin_binding)
1744 		return;
1745 
1746 	ida_free(queue_ida, queue_id);
1747 }
1748 
1749 static int sof_ipc4_set_copier_sink_format(struct snd_sof_dev *sdev,
1750 					   struct snd_sof_widget *src_widget,
1751 					   struct snd_sof_widget *sink_widget,
1752 					   int sink_id)
1753 {
1754 	struct sof_ipc4_base_module_cfg *sink_config = sink_widget->private;
1755 	struct sof_ipc4_base_module_cfg *src_config;
1756 	struct sof_ipc4_copier_config_set_sink_format format;
1757 	struct sof_ipc4_fw_module *fw_module;
1758 	struct sof_ipc4_msg msg = {{ 0 }};
1759 	u32 header, extension;
1760 
1761 	dev_dbg(sdev->dev, "%s set copier sink %d format\n",
1762 		src_widget->widget->name, sink_id);
1763 
1764 	if (WIDGET_IS_DAI(src_widget->id)) {
1765 		struct snd_sof_dai *dai = src_widget->private;
1766 
1767 		src_config = dai->private;
1768 	} else {
1769 		src_config = src_widget->private;
1770 	}
1771 
1772 	fw_module = src_widget->module_info;
1773 
1774 	format.sink_id = sink_id;
1775 	memcpy(&format.source_fmt, &src_config->audio_fmt, sizeof(format.source_fmt));
1776 	memcpy(&format.sink_fmt, &sink_config->audio_fmt, sizeof(format.sink_fmt));
1777 	msg.data_size = sizeof(format);
1778 	msg.data_ptr = &format;
1779 
1780 	header = fw_module->man4_module_entry.id;
1781 	header |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id);
1782 	header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_LARGE_CONFIG_SET);
1783 	header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
1784 	header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
1785 
1786 	extension = SOF_IPC4_MOD_EXT_MSG_SIZE(msg.data_size);
1787 	extension |=
1788 		SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_COPIER_MODULE_CFG_PARAM_SET_SINK_FORMAT);
1789 	extension |= SOF_IPC4_MOD_EXT_MSG_LAST_BLOCK(1);
1790 	extension |= SOF_IPC4_MOD_EXT_MSG_FIRST_BLOCK(1);
1791 
1792 	msg.primary = header;
1793 	msg.extension = extension;
1794 
1795 	return sof_ipc_tx_message(sdev->ipc, &msg, msg.data_size, NULL, 0);
1796 }
1797 
1798 static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route *sroute)
1799 {
1800 	struct snd_sof_widget *src_widget = sroute->src_widget;
1801 	struct snd_sof_widget *sink_widget = sroute->sink_widget;
1802 	struct sof_ipc4_fw_module *src_fw_module = src_widget->module_info;
1803 	struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info;
1804 	struct sof_ipc4_msg msg = {{ 0 }};
1805 	u32 header, extension;
1806 	int ret;
1807 
1808 	sroute->src_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget,
1809 						     SOF_PIN_TYPE_SOURCE);
1810 	if (sroute->src_queue_id < 0) {
1811 		dev_err(sdev->dev, "failed to get queue ID for source widget: %s\n",
1812 			src_widget->widget->name);
1813 		return sroute->src_queue_id;
1814 	}
1815 
1816 	sroute->dst_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget,
1817 						     SOF_PIN_TYPE_SINK);
1818 	if (sroute->dst_queue_id < 0) {
1819 		dev_err(sdev->dev, "failed to get queue ID for sink widget: %s\n",
1820 			sink_widget->widget->name);
1821 		sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id,
1822 				      SOF_PIN_TYPE_SOURCE);
1823 		return sroute->dst_queue_id;
1824 	}
1825 
1826 	/* Pin 0 format is already set during copier module init */
1827 	if (sroute->src_queue_id > 0 && WIDGET_IS_COPIER(src_widget->id)) {
1828 		ret = sof_ipc4_set_copier_sink_format(sdev, src_widget, sink_widget,
1829 						      sroute->src_queue_id);
1830 		if (ret < 0) {
1831 			dev_err(sdev->dev, "failed to set sink format for %s source queue ID %d\n",
1832 				src_widget->widget->name, sroute->src_queue_id);
1833 			goto out;
1834 		}
1835 	}
1836 
1837 	dev_dbg(sdev->dev, "bind %s:%d -> %s:%d\n",
1838 		src_widget->widget->name, sroute->src_queue_id,
1839 		sink_widget->widget->name, sroute->dst_queue_id);
1840 
1841 	header = src_fw_module->man4_module_entry.id;
1842 	header |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id);
1843 	header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_BIND);
1844 	header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
1845 	header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
1846 
1847 	extension = sink_fw_module->man4_module_entry.id;
1848 	extension |= SOF_IPC4_MOD_EXT_DST_MOD_INSTANCE(sink_widget->instance_id);
1849 	extension |= SOF_IPC4_MOD_EXT_DST_MOD_QUEUE_ID(sroute->dst_queue_id);
1850 	extension |= SOF_IPC4_MOD_EXT_SRC_MOD_QUEUE_ID(sroute->src_queue_id);
1851 
1852 	msg.primary = header;
1853 	msg.extension = extension;
1854 
1855 	ret = sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0);
1856 	if (ret < 0) {
1857 		dev_err(sdev->dev, "failed to bind modules %s:%d -> %s:%d\n",
1858 			src_widget->widget->name, sroute->src_queue_id,
1859 			sink_widget->widget->name, sroute->dst_queue_id);
1860 		goto out;
1861 	}
1862 
1863 	return ret;
1864 
1865 out:
1866 	sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id, SOF_PIN_TYPE_SOURCE);
1867 	sof_ipc4_put_queue_id(sink_widget, sroute->dst_queue_id, SOF_PIN_TYPE_SINK);
1868 	return ret;
1869 }
1870 
1871 static int sof_ipc4_route_free(struct snd_sof_dev *sdev, struct snd_sof_route *sroute)
1872 {
1873 	struct snd_sof_widget *src_widget = sroute->src_widget;
1874 	struct snd_sof_widget *sink_widget = sroute->sink_widget;
1875 	struct sof_ipc4_fw_module *src_fw_module = src_widget->module_info;
1876 	struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info;
1877 	struct sof_ipc4_msg msg = {{ 0 }};
1878 	u32 header, extension;
1879 	int ret = 0;
1880 
1881 	dev_dbg(sdev->dev, "unbind modules %s:%d -> %s:%d\n",
1882 		src_widget->widget->name, sroute->src_queue_id,
1883 		sink_widget->widget->name, sroute->dst_queue_id);
1884 
1885 	/*
1886 	 * routes belonging to the same pipeline will be disconnected by the FW when the pipeline
1887 	 * is freed. So avoid sending this IPC which will be ignored by the FW anyway.
1888 	 */
1889 	if (src_widget->spipe->pipe_widget == sink_widget->spipe->pipe_widget)
1890 		goto out;
1891 
1892 	header = src_fw_module->man4_module_entry.id;
1893 	header |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id);
1894 	header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_UNBIND);
1895 	header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
1896 	header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
1897 
1898 	extension = sink_fw_module->man4_module_entry.id;
1899 	extension |= SOF_IPC4_MOD_EXT_DST_MOD_INSTANCE(sink_widget->instance_id);
1900 	extension |= SOF_IPC4_MOD_EXT_DST_MOD_QUEUE_ID(sroute->dst_queue_id);
1901 	extension |= SOF_IPC4_MOD_EXT_SRC_MOD_QUEUE_ID(sroute->src_queue_id);
1902 
1903 	msg.primary = header;
1904 	msg.extension = extension;
1905 
1906 	ret = sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0);
1907 	if (ret < 0)
1908 		dev_err(sdev->dev, "failed to unbind modules %s:%d -> %s:%d\n",
1909 			src_widget->widget->name, sroute->src_queue_id,
1910 			sink_widget->widget->name, sroute->dst_queue_id);
1911 out:
1912 	sof_ipc4_put_queue_id(sink_widget, sroute->dst_queue_id, SOF_PIN_TYPE_SINK);
1913 	sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id, SOF_PIN_TYPE_SOURCE);
1914 
1915 	return ret;
1916 }
1917 
1918 static int sof_ipc4_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
1919 			       unsigned int flags, struct snd_sof_dai_config_data *data)
1920 {
1921 	struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
1922 	struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
1923 	struct snd_sof_dai *dai = swidget->private;
1924 	struct sof_ipc4_gtw_attributes *gtw_attr;
1925 	struct sof_ipc4_copier_data *copier_data;
1926 	struct sof_ipc4_copier *ipc4_copier;
1927 
1928 	if (!dai || !dai->private) {
1929 		dev_err(sdev->dev, "Invalid DAI or DAI private data for %s\n",
1930 			swidget->widget->name);
1931 		return -EINVAL;
1932 	}
1933 
1934 	ipc4_copier = (struct sof_ipc4_copier *)dai->private;
1935 	copier_data = &ipc4_copier->data;
1936 
1937 	if (!data)
1938 		return 0;
1939 
1940 	switch (ipc4_copier->dai_type) {
1941 	case SOF_DAI_INTEL_HDA:
1942 		gtw_attr = ipc4_copier->gtw_attr;
1943 		gtw_attr->lp_buffer_alloc = pipeline->lp_mode;
1944 		pipeline->skip_during_fe_trigger = true;
1945 		fallthrough;
1946 	case SOF_DAI_INTEL_ALH:
1947 		/*
1948 		 * Do not clear the node ID when this op is invoked with
1949 		 * SOF_DAI_CONFIG_FLAGS_HW_FREE. It is needed to free the group_ida during
1950 		 * unprepare.
1951 		 */
1952 		if (flags & SOF_DAI_CONFIG_FLAGS_HW_PARAMS) {
1953 			copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
1954 			copier_data->gtw_cfg.node_id |= SOF_IPC4_NODE_INDEX(data->dai_data);
1955 		}
1956 		break;
1957 	case SOF_DAI_INTEL_DMIC:
1958 	case SOF_DAI_INTEL_SSP:
1959 		/* nothing to do for SSP/DMIC */
1960 		break;
1961 	default:
1962 		dev_err(sdev->dev, "%s: unsupported dai type %d\n", __func__,
1963 			ipc4_copier->dai_type);
1964 		return -EINVAL;
1965 	}
1966 
1967 	return 0;
1968 }
1969 
1970 static int sof_ipc4_parse_manifest(struct snd_soc_component *scomp, int index,
1971 				   struct snd_soc_tplg_manifest *man)
1972 {
1973 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1974 	struct sof_ipc4_fw_data *ipc4_data = sdev->private;
1975 	struct sof_manifest_tlv *manifest_tlv;
1976 	struct sof_manifest *manifest;
1977 	u32 size = le32_to_cpu(man->priv.size);
1978 	u8 *man_ptr = man->priv.data;
1979 	u32 len_check;
1980 	int i;
1981 
1982 	if (!size || size < SOF_IPC4_TPLG_ABI_SIZE) {
1983 		dev_err(scomp->dev, "%s: Invalid topology ABI size: %u\n",
1984 			__func__, size);
1985 		return -EINVAL;
1986 	}
1987 
1988 	manifest = (struct sof_manifest *)man_ptr;
1989 
1990 	dev_info(scomp->dev,
1991 		 "Topology: ABI %d:%d:%d Kernel ABI %u:%u:%u\n",
1992 		  le16_to_cpu(manifest->abi_major), le16_to_cpu(manifest->abi_minor),
1993 		  le16_to_cpu(manifest->abi_patch),
1994 		  SOF_ABI_MAJOR, SOF_ABI_MINOR, SOF_ABI_PATCH);
1995 
1996 	/* TODO: Add ABI compatibility check */
1997 
1998 	/* no more data after the ABI version */
1999 	if (size <= SOF_IPC4_TPLG_ABI_SIZE)
2000 		return 0;
2001 
2002 	manifest_tlv = manifest->items;
2003 	len_check = sizeof(struct sof_manifest);
2004 	for (i = 0; i < le16_to_cpu(manifest->count); i++) {
2005 		len_check += sizeof(struct sof_manifest_tlv) + le32_to_cpu(manifest_tlv->size);
2006 		if (len_check > size)
2007 			return -EINVAL;
2008 
2009 		switch (le32_to_cpu(manifest_tlv->type)) {
2010 		case SOF_MANIFEST_DATA_TYPE_NHLT:
2011 			/* no NHLT in BIOS, so use the one from topology manifest */
2012 			if (ipc4_data->nhlt)
2013 				break;
2014 			ipc4_data->nhlt = devm_kmemdup(sdev->dev, manifest_tlv->data,
2015 						       le32_to_cpu(manifest_tlv->size), GFP_KERNEL);
2016 			if (!ipc4_data->nhlt)
2017 				return -ENOMEM;
2018 			break;
2019 		default:
2020 			dev_warn(scomp->dev, "Skipping unknown manifest data type %d\n",
2021 				 manifest_tlv->type);
2022 			break;
2023 		}
2024 		man_ptr += sizeof(struct sof_manifest_tlv) + le32_to_cpu(manifest_tlv->size);
2025 		manifest_tlv = (struct sof_manifest_tlv *)man_ptr;
2026 	}
2027 
2028 	return 0;
2029 }
2030 
2031 static int sof_ipc4_dai_get_clk(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, int clk_type)
2032 {
2033 	struct sof_ipc4_copier *ipc4_copier = dai->private;
2034 	struct snd_soc_tplg_hw_config *hw_config;
2035 	struct snd_sof_dai_link *slink;
2036 	bool dai_link_found = false;
2037 	bool hw_cfg_found = false;
2038 	int i;
2039 
2040 	if (!ipc4_copier)
2041 		return 0;
2042 
2043 	list_for_each_entry(slink, &sdev->dai_link_list, list) {
2044 		if (!strcmp(slink->link->name, dai->name)) {
2045 			dai_link_found = true;
2046 			break;
2047 		}
2048 	}
2049 
2050 	if (!dai_link_found) {
2051 		dev_err(sdev->dev, "no DAI link found for DAI %s\n", dai->name);
2052 		return -EINVAL;
2053 	}
2054 
2055 	for (i = 0; i < slink->num_hw_configs; i++) {
2056 		hw_config = &slink->hw_configs[i];
2057 		if (dai->current_config == le32_to_cpu(hw_config->id)) {
2058 			hw_cfg_found = true;
2059 			break;
2060 		}
2061 	}
2062 
2063 	if (!hw_cfg_found) {
2064 		dev_err(sdev->dev, "no matching hw_config found for DAI %s\n", dai->name);
2065 		return -EINVAL;
2066 	}
2067 
2068 	switch (ipc4_copier->dai_type) {
2069 	case SOF_DAI_INTEL_SSP:
2070 		switch (clk_type) {
2071 		case SOF_DAI_CLK_INTEL_SSP_MCLK:
2072 			return le32_to_cpu(hw_config->mclk_rate);
2073 		case SOF_DAI_CLK_INTEL_SSP_BCLK:
2074 			return le32_to_cpu(hw_config->bclk_rate);
2075 		default:
2076 			dev_err(sdev->dev, "Invalid clk type for SSP %d\n", clk_type);
2077 			break;
2078 		}
2079 		break;
2080 	default:
2081 		dev_err(sdev->dev, "DAI type %d not supported yet!\n", ipc4_copier->dai_type);
2082 		break;
2083 	}
2084 
2085 	return -EINVAL;
2086 }
2087 
2088 static int sof_ipc4_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verify)
2089 {
2090 	struct snd_sof_pcm *spcm;
2091 	int dir, ret;
2092 
2093 	/*
2094 	 * This function is called during system suspend, we need to make sure
2095 	 * that all streams have been freed up.
2096 	 * Freeing might have been skipped when xrun happened just at the start
2097 	 * of the suspend and it sent a SNDRV_PCM_TRIGGER_STOP to the active
2098 	 * stream. This will call sof_pcm_stream_free() with
2099 	 * free_widget_list = false which will leave the kernel and firmware out
2100 	 * of sync during suspend/resume.
2101 	 *
2102 	 * This will also make sure that paused streams handled correctly.
2103 	 */
2104 	list_for_each_entry(spcm, &sdev->pcm_list, list) {
2105 		for_each_pcm_streams(dir) {
2106 			struct snd_pcm_substream *substream = spcm->stream[dir].substream;
2107 
2108 			if (!substream || !substream->runtime || spcm->stream[dir].suspend_ignored)
2109 				continue;
2110 
2111 			if (spcm->stream[dir].list) {
2112 				ret = sof_pcm_stream_free(sdev, substream, spcm, dir, true);
2113 				if (ret < 0)
2114 					return ret;
2115 			}
2116 		}
2117 	}
2118 	return 0;
2119 }
2120 
2121 static int sof_ipc4_link_setup(struct snd_sof_dev *sdev, struct snd_soc_dai_link *link)
2122 {
2123 	if (link->no_pcm)
2124 		return 0;
2125 
2126 	/*
2127 	 * set default trigger order for all links. Exceptions to
2128 	 * the rule will be handled in sof_pcm_dai_link_fixup()
2129 	 * For playback, the sequence is the following: start BE,
2130 	 * start FE, stop FE, stop BE; for Capture the sequence is
2131 	 * inverted start FE, start BE, stop BE, stop FE
2132 	 */
2133 	link->trigger[SNDRV_PCM_STREAM_PLAYBACK] = SND_SOC_DPCM_TRIGGER_POST;
2134 	link->trigger[SNDRV_PCM_STREAM_CAPTURE] = SND_SOC_DPCM_TRIGGER_PRE;
2135 
2136 	return 0;
2137 }
2138 
2139 static enum sof_tokens common_copier_token_list[] = {
2140 	SOF_COMP_TOKENS,
2141 	SOF_AUDIO_FMT_NUM_TOKENS,
2142 	SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS,
2143 	SOF_IN_AUDIO_FORMAT_TOKENS,
2144 	SOF_OUT_AUDIO_FORMAT_TOKENS,
2145 	SOF_COPIER_GATEWAY_CFG_TOKENS,
2146 	SOF_COPIER_TOKENS,
2147 	SOF_COMP_EXT_TOKENS,
2148 };
2149 
2150 static enum sof_tokens pipeline_token_list[] = {
2151 	SOF_SCHED_TOKENS,
2152 	SOF_PIPELINE_TOKENS,
2153 };
2154 
2155 static enum sof_tokens dai_token_list[] = {
2156 	SOF_COMP_TOKENS,
2157 	SOF_AUDIO_FMT_NUM_TOKENS,
2158 	SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS,
2159 	SOF_IN_AUDIO_FORMAT_TOKENS,
2160 	SOF_OUT_AUDIO_FORMAT_TOKENS,
2161 	SOF_COPIER_GATEWAY_CFG_TOKENS,
2162 	SOF_COPIER_TOKENS,
2163 	SOF_DAI_TOKENS,
2164 	SOF_COMP_EXT_TOKENS,
2165 };
2166 
2167 static enum sof_tokens pga_token_list[] = {
2168 	SOF_COMP_TOKENS,
2169 	SOF_GAIN_TOKENS,
2170 	SOF_AUDIO_FMT_NUM_TOKENS,
2171 	SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS,
2172 	SOF_IN_AUDIO_FORMAT_TOKENS,
2173 	SOF_COMP_EXT_TOKENS,
2174 };
2175 
2176 static enum sof_tokens mixer_token_list[] = {
2177 	SOF_COMP_TOKENS,
2178 	SOF_AUDIO_FMT_NUM_TOKENS,
2179 	SOF_IN_AUDIO_FORMAT_TOKENS,
2180 	SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS,
2181 	SOF_COMP_EXT_TOKENS,
2182 };
2183 
2184 static enum sof_tokens src_token_list[] = {
2185 	SOF_COMP_TOKENS,
2186 	SOF_SRC_TOKENS,
2187 	SOF_AUDIO_FMT_NUM_TOKENS,
2188 	SOF_IN_AUDIO_FORMAT_TOKENS,
2189 	SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS,
2190 	SOF_COMP_EXT_TOKENS,
2191 };
2192 
2193 static const struct sof_ipc_tplg_widget_ops tplg_ipc4_widget_ops[SND_SOC_DAPM_TYPE_COUNT] = {
2194 	[snd_soc_dapm_aif_in] =  {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm,
2195 				  common_copier_token_list, ARRAY_SIZE(common_copier_token_list),
2196 				  NULL, sof_ipc4_prepare_copier_module,
2197 				  sof_ipc4_unprepare_copier_module},
2198 	[snd_soc_dapm_aif_out] = {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm,
2199 				  common_copier_token_list, ARRAY_SIZE(common_copier_token_list),
2200 				  NULL, sof_ipc4_prepare_copier_module,
2201 				  sof_ipc4_unprepare_copier_module},
2202 	[snd_soc_dapm_dai_in] = {sof_ipc4_widget_setup_comp_dai, sof_ipc4_widget_free_comp_dai,
2203 				 dai_token_list, ARRAY_SIZE(dai_token_list), NULL,
2204 				 sof_ipc4_prepare_copier_module,
2205 				 sof_ipc4_unprepare_copier_module},
2206 	[snd_soc_dapm_dai_out] = {sof_ipc4_widget_setup_comp_dai, sof_ipc4_widget_free_comp_dai,
2207 				  dai_token_list, ARRAY_SIZE(dai_token_list), NULL,
2208 				  sof_ipc4_prepare_copier_module,
2209 				  sof_ipc4_unprepare_copier_module},
2210 	[snd_soc_dapm_buffer] = {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm,
2211 				 common_copier_token_list, ARRAY_SIZE(common_copier_token_list),
2212 				 NULL, sof_ipc4_prepare_copier_module,
2213 				 sof_ipc4_unprepare_copier_module},
2214 	[snd_soc_dapm_scheduler] = {sof_ipc4_widget_setup_comp_pipeline,
2215 				    sof_ipc4_widget_free_comp_pipeline,
2216 				    pipeline_token_list, ARRAY_SIZE(pipeline_token_list), NULL,
2217 				    NULL, NULL},
2218 	[snd_soc_dapm_pga] = {sof_ipc4_widget_setup_comp_pga, sof_ipc4_widget_free_comp_pga,
2219 			      pga_token_list, ARRAY_SIZE(pga_token_list), NULL,
2220 			      sof_ipc4_prepare_gain_module,
2221 			      NULL},
2222 	[snd_soc_dapm_mixer] = {sof_ipc4_widget_setup_comp_mixer, sof_ipc4_widget_free_comp_mixer,
2223 				mixer_token_list, ARRAY_SIZE(mixer_token_list),
2224 				NULL, sof_ipc4_prepare_mixer_module,
2225 				NULL},
2226 	[snd_soc_dapm_src] = {sof_ipc4_widget_setup_comp_src, sof_ipc4_widget_free_comp_src,
2227 				src_token_list, ARRAY_SIZE(src_token_list),
2228 				NULL, sof_ipc4_prepare_src_module,
2229 				NULL},
2230 };
2231 
2232 const struct sof_ipc_tplg_ops ipc4_tplg_ops = {
2233 	.widget = tplg_ipc4_widget_ops,
2234 	.token_list = ipc4_token_list,
2235 	.control_setup = sof_ipc4_control_setup,
2236 	.control = &tplg_ipc4_control_ops,
2237 	.widget_setup = sof_ipc4_widget_setup,
2238 	.widget_free = sof_ipc4_widget_free,
2239 	.route_setup = sof_ipc4_route_setup,
2240 	.route_free = sof_ipc4_route_free,
2241 	.dai_config = sof_ipc4_dai_config,
2242 	.parse_manifest = sof_ipc4_parse_manifest,
2243 	.dai_get_clk = sof_ipc4_dai_get_clk,
2244 	.tear_down_all_pipelines = sof_ipc4_tear_down_all_pipelines,
2245 	.link_setup = sof_ipc4_link_setup,
2246 };
2247