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