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