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