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