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