Merge tag 'flex-array-transformations-6.4-rc1' of git://git.kernel.org/pub/scm/linux...
[linux-block.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_l)},
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: %uHz, %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_l,
696                 gain->data.init_val, gain->base_config.cpc);
697
698         ret = sof_ipc4_widget_setup_msg(swidget, &gain->msg);
699         if (ret)
700                 goto err;
701
702         fw_module = swidget->module_info;
703
704         /* update module ID for all kcontrols for this widget */
705         list_for_each_entry(scontrol, &sdev->kcontrol_list, list)
706                 if (scontrol->comp_id == swidget->comp_id) {
707                         struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
708                         struct sof_ipc4_msg *msg = &cdata->msg;
709
710                         msg->primary |= fw_module->man4_module_entry.id;
711                 }
712
713         return 0;
714 err:
715         sof_ipc4_free_audio_fmt(&gain->available_fmt);
716         kfree(gain);
717         swidget->private = NULL;
718         return ret;
719 }
720
721 static void sof_ipc4_widget_free_comp_pga(struct snd_sof_widget *swidget)
722 {
723         struct sof_ipc4_gain *gain = swidget->private;
724
725         if (!gain)
726                 return;
727
728         sof_ipc4_free_audio_fmt(&gain->available_fmt);
729         kfree(swidget->private);
730         swidget->private = NULL;
731 }
732
733 static int sof_ipc4_widget_setup_comp_mixer(struct snd_sof_widget *swidget)
734 {
735         struct snd_soc_component *scomp = swidget->scomp;
736         struct sof_ipc4_mixer *mixer;
737         int ret;
738
739         dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name);
740
741         mixer = kzalloc(sizeof(*mixer), GFP_KERNEL);
742         if (!mixer)
743                 return -ENOMEM;
744
745         swidget->private = mixer;
746
747         /* The out_audio_fmt in topology is ignored as it is not required to be sent to the FW */
748         ret = sof_ipc4_get_audio_fmt(scomp, swidget, &mixer->available_fmt, false);
749         if (ret)
750                 goto err;
751
752         ret = sof_ipc4_widget_setup_msg(swidget, &mixer->msg);
753         if (ret)
754                 goto err;
755
756         return 0;
757 err:
758         sof_ipc4_free_audio_fmt(&mixer->available_fmt);
759         kfree(mixer);
760         swidget->private = NULL;
761         return ret;
762 }
763
764 static int sof_ipc4_widget_setup_comp_src(struct snd_sof_widget *swidget)
765 {
766         struct snd_soc_component *scomp = swidget->scomp;
767         struct sof_ipc4_src *src;
768         int ret;
769
770         dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name);
771
772         src = kzalloc(sizeof(*src), GFP_KERNEL);
773         if (!src)
774                 return -ENOMEM;
775
776         swidget->private = src;
777
778         /* The out_audio_fmt in topology is ignored as it is not required by SRC */
779         ret = sof_ipc4_get_audio_fmt(scomp, swidget, &src->available_fmt, false);
780         if (ret)
781                 goto err;
782
783         ret = sof_update_ipc_object(scomp, src, SOF_SRC_TOKENS, swidget->tuples,
784                                     swidget->num_tuples, sizeof(*src), 1);
785         if (ret) {
786                 dev_err(scomp->dev, "Parsing SRC tokens failed\n");
787                 goto err;
788         }
789
790         dev_dbg(scomp->dev, "SRC sink rate %d\n", src->sink_rate);
791
792         ret = sof_ipc4_widget_setup_msg(swidget, &src->msg);
793         if (ret)
794                 goto err;
795
796         return 0;
797 err:
798         sof_ipc4_free_audio_fmt(&src->available_fmt);
799         kfree(src);
800         swidget->private = NULL;
801         return ret;
802 }
803
804 static void sof_ipc4_widget_free_comp_src(struct snd_sof_widget *swidget)
805 {
806         struct sof_ipc4_src *src = swidget->private;
807
808         if (!src)
809                 return;
810
811         sof_ipc4_free_audio_fmt(&src->available_fmt);
812         kfree(swidget->private);
813         swidget->private = NULL;
814 }
815
816 static void sof_ipc4_widget_free_comp_mixer(struct snd_sof_widget *swidget)
817 {
818         struct sof_ipc4_mixer *mixer = swidget->private;
819
820         if (!mixer)
821                 return;
822
823         sof_ipc4_free_audio_fmt(&mixer->available_fmt);
824         kfree(swidget->private);
825         swidget->private = NULL;
826 }
827
828 static void
829 sof_ipc4_update_pipeline_mem_usage(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
830                                    struct sof_ipc4_base_module_cfg *base_config)
831 {
832         struct sof_ipc4_fw_module *fw_module = swidget->module_info;
833         struct snd_sof_widget *pipe_widget;
834         struct sof_ipc4_pipeline *pipeline;
835         int task_mem, queue_mem;
836         int ibs, bss, total;
837
838         ibs = base_config->ibs;
839         bss = base_config->is_pages;
840
841         task_mem = SOF_IPC4_PIPELINE_OBJECT_SIZE;
842         task_mem += SOF_IPC4_MODULE_INSTANCE_LIST_ITEM_SIZE + bss;
843
844         if (fw_module->man4_module_entry.type & SOF_IPC4_MODULE_LL) {
845                 task_mem += SOF_IPC4_FW_ROUNDUP(SOF_IPC4_LL_TASK_OBJECT_SIZE);
846                 task_mem += SOF_IPC4_FW_MAX_QUEUE_COUNT * SOF_IPC4_MODULE_INSTANCE_LIST_ITEM_SIZE;
847                 task_mem += SOF_IPC4_LL_TASK_LIST_ITEM_SIZE;
848         } else {
849                 task_mem += SOF_IPC4_FW_ROUNDUP(SOF_IPC4_DP_TASK_OBJECT_SIZE);
850                 task_mem += SOF_IPC4_DP_TASK_LIST_SIZE;
851         }
852
853         ibs = SOF_IPC4_FW_ROUNDUP(ibs);
854         queue_mem = SOF_IPC4_FW_MAX_QUEUE_COUNT * (SOF_IPC4_DATA_QUEUE_OBJECT_SIZE +  ibs);
855
856         total = SOF_IPC4_FW_PAGE(task_mem + queue_mem);
857
858         pipe_widget = swidget->spipe->pipe_widget;
859         pipeline = pipe_widget->private;
860         pipeline->mem_usage += total;
861 }
862
863 static int sof_ipc4_widget_assign_instance_id(struct snd_sof_dev *sdev,
864                                               struct snd_sof_widget *swidget)
865 {
866         struct sof_ipc4_fw_module *fw_module = swidget->module_info;
867         int max_instances = fw_module->man4_module_entry.instance_max_count;
868
869         swidget->instance_id = ida_alloc_max(&fw_module->m_ida, max_instances, GFP_KERNEL);
870         if (swidget->instance_id < 0) {
871                 dev_err(sdev->dev, "failed to assign instance id for widget %s",
872                         swidget->widget->name);
873                 return swidget->instance_id;
874         }
875
876         return 0;
877 }
878
879 static int sof_ipc4_init_audio_fmt(struct snd_sof_dev *sdev,
880                                    struct snd_sof_widget *swidget,
881                                    struct sof_ipc4_base_module_cfg *base_config,
882                                    struct sof_ipc4_audio_format *out_format,
883                                    struct snd_pcm_hw_params *params,
884                                    struct sof_ipc4_available_audio_format *available_fmt,
885                                    size_t object_offset)
886 {
887         void *ptr = available_fmt->ref_audio_fmt;
888         u32 valid_bits;
889         u32 channels;
890         u32 rate;
891         int sample_valid_bits;
892         int i;
893
894         if (!ptr) {
895                 dev_err(sdev->dev, "no reference formats for %s\n", swidget->widget->name);
896                 return -EINVAL;
897         }
898
899         switch (params_format(params)) {
900         case SNDRV_PCM_FORMAT_S16_LE:
901                 sample_valid_bits = 16;
902                 break;
903         case SNDRV_PCM_FORMAT_S24_LE:
904                 sample_valid_bits = 24;
905                 break;
906         case SNDRV_PCM_FORMAT_S32_LE:
907                 sample_valid_bits = 32;
908                 break;
909         default:
910                 dev_err(sdev->dev, "invalid pcm frame format %d\n", params_format(params));
911                 return -EINVAL;
912         }
913
914         if (!available_fmt->audio_fmt_num) {
915                 dev_err(sdev->dev, "no formats available for %s\n", swidget->widget->name);
916                 return -EINVAL;
917         }
918
919         /*
920          * Search supported audio formats to match rate, channels ,and
921          * sample_valid_bytes from runtime params
922          */
923         for (i = 0; i < available_fmt->audio_fmt_num; i++, ptr = (u8 *)ptr + object_offset) {
924                 struct sof_ipc4_audio_format *fmt = ptr;
925
926                 rate = fmt->sampling_frequency;
927                 channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg);
928                 valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
929                 if (params_rate(params) == rate && params_channels(params) == channels &&
930                     sample_valid_bits == valid_bits) {
931                         dev_dbg(sdev->dev, "matching audio format index for %uHz, %ubit, %u channels: %d\n",
932                                 rate, valid_bits, channels, i);
933
934                         /* copy ibs/obs and input format */
935                         memcpy(base_config, &available_fmt->base_config[i],
936                                sizeof(struct sof_ipc4_base_module_cfg));
937
938                         /* copy output format */
939                         if (out_format)
940                                 memcpy(out_format, &available_fmt->out_audio_fmt[i],
941                                        sizeof(struct sof_ipc4_audio_format));
942                         break;
943                 }
944         }
945
946         if (i == available_fmt->audio_fmt_num) {
947                 dev_err(sdev->dev, "%s: Unsupported audio format: %uHz, %ubit, %u channels\n",
948                         __func__, params_rate(params), sample_valid_bits, params_channels(params));
949                 return -EINVAL;
950         }
951
952         dev_dbg(sdev->dev, "Init input audio formats for %s\n", swidget->widget->name);
953         sof_ipc4_dbg_audio_format(sdev->dev, &base_config->audio_fmt,
954                                   sizeof(*base_config), 1);
955         if (out_format) {
956                 dev_dbg(sdev->dev, "Init output audio formats for %s\n", swidget->widget->name);
957                 sof_ipc4_dbg_audio_format(sdev->dev, out_format,
958                                           sizeof(*out_format), 1);
959         }
960
961         /* Return the index of the matched format */
962         return i;
963 }
964
965 static void sof_ipc4_unprepare_copier_module(struct snd_sof_widget *swidget)
966 {
967         struct sof_ipc4_copier *ipc4_copier = NULL;
968         struct snd_sof_widget *pipe_widget;
969         struct sof_ipc4_pipeline *pipeline;
970
971         /* reset pipeline memory usage */
972         pipe_widget = swidget->spipe->pipe_widget;
973         pipeline = pipe_widget->private;
974         pipeline->mem_usage = 0;
975
976         if (WIDGET_IS_AIF(swidget->id) || swidget->id == snd_soc_dapm_buffer) {
977                 ipc4_copier = swidget->private;
978         } else if (WIDGET_IS_DAI(swidget->id)) {
979                 struct snd_sof_dai *dai = swidget->private;
980
981                 ipc4_copier = dai->private;
982                 if (ipc4_copier->dai_type == SOF_DAI_INTEL_ALH) {
983                         struct sof_ipc4_copier_data *copier_data = &ipc4_copier->data;
984                         struct sof_ipc4_alh_configuration_blob *blob;
985                         unsigned int group_id;
986
987                         blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config;
988                         if (blob->alh_cfg.count > 1) {
989                                 group_id = SOF_IPC4_NODE_INDEX(ipc4_copier->data.gtw_cfg.node_id) -
990                                            ALH_MULTI_GTW_BASE;
991                                 ida_free(&alh_group_ida, group_id);
992                         }
993
994                         /* clear the node ID */
995                         copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
996                 }
997         }
998
999         if (ipc4_copier) {
1000                 kfree(ipc4_copier->ipc_config_data);
1001                 ipc4_copier->ipc_config_data = NULL;
1002                 ipc4_copier->ipc_config_size = 0;
1003         }
1004 }
1005
1006 #if IS_ENABLED(CONFIG_ACPI) && IS_ENABLED(CONFIG_SND_INTEL_NHLT)
1007 static int snd_sof_get_hw_config_params(struct snd_sof_dev *sdev, struct snd_sof_dai *dai,
1008                                         int *sample_rate, int *channel_count, int *bit_depth)
1009 {
1010         struct snd_soc_tplg_hw_config *hw_config;
1011         struct snd_sof_dai_link *slink;
1012         bool dai_link_found = false;
1013         bool hw_cfg_found = false;
1014         int i;
1015
1016         /* get current hw_config from link */
1017         list_for_each_entry(slink, &sdev->dai_link_list, list) {
1018                 if (!strcmp(slink->link->name, dai->name)) {
1019                         dai_link_found = true;
1020                         break;
1021                 }
1022         }
1023
1024         if (!dai_link_found) {
1025                 dev_err(sdev->dev, "%s: no DAI link found for DAI %s\n", __func__, dai->name);
1026                 return -EINVAL;
1027         }
1028
1029         for (i = 0; i < slink->num_hw_configs; i++) {
1030                 hw_config = &slink->hw_configs[i];
1031                 if (dai->current_config == le32_to_cpu(hw_config->id)) {
1032                         hw_cfg_found = true;
1033                         break;
1034                 }
1035         }
1036
1037         if (!hw_cfg_found) {
1038                 dev_err(sdev->dev, "%s: no matching hw_config found for DAI %s\n", __func__,
1039                         dai->name);
1040                 return -EINVAL;
1041         }
1042
1043         *bit_depth = le32_to_cpu(hw_config->tdm_slot_width);
1044         *channel_count = le32_to_cpu(hw_config->tdm_slots);
1045         *sample_rate = le32_to_cpu(hw_config->fsync_rate);
1046
1047         dev_dbg(sdev->dev, "sample rate: %d sample width: %d channels: %d\n",
1048                 *sample_rate, *bit_depth, *channel_count);
1049
1050         return 0;
1051 }
1052
1053 static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai,
1054                                           struct snd_pcm_hw_params *params, u32 dai_index,
1055                                           u32 linktype, u8 dir, u32 **dst, u32 *len)
1056 {
1057         struct sof_ipc4_fw_data *ipc4_data = sdev->private;
1058         struct nhlt_specific_cfg *cfg;
1059         int sample_rate, channel_count;
1060         int bit_depth, ret;
1061         u32 nhlt_type;
1062
1063         /* convert to NHLT type */
1064         switch (linktype) {
1065         case SOF_DAI_INTEL_DMIC:
1066                 nhlt_type = NHLT_LINK_DMIC;
1067                 bit_depth = params_width(params);
1068                 channel_count = params_channels(params);
1069                 sample_rate = params_rate(params);
1070                 break;
1071         case SOF_DAI_INTEL_SSP:
1072                 nhlt_type = NHLT_LINK_SSP;
1073                 ret = snd_sof_get_hw_config_params(sdev, dai, &sample_rate, &channel_count,
1074                                                    &bit_depth);
1075                 if (ret < 0)
1076                         return ret;
1077                 break;
1078         default:
1079                 return 0;
1080         }
1081
1082         dev_dbg(sdev->dev, "dai index %d nhlt type %d direction %d\n",
1083                 dai_index, nhlt_type, dir);
1084
1085         /* find NHLT blob with matching params */
1086         cfg = intel_nhlt_get_endpoint_blob(sdev->dev, ipc4_data->nhlt, dai_index, nhlt_type,
1087                                            bit_depth, bit_depth, channel_count, sample_rate,
1088                                            dir, 0);
1089
1090         if (!cfg) {
1091                 dev_err(sdev->dev,
1092                         "no matching blob for sample rate: %d sample width: %d channels: %d\n",
1093                         sample_rate, bit_depth, channel_count);
1094                 return -EINVAL;
1095         }
1096
1097         /* config length should be in dwords */
1098         *len = cfg->size >> 2;
1099         *dst = (u32 *)cfg->caps;
1100
1101         return 0;
1102 }
1103 #else
1104 static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai,
1105                                           struct snd_pcm_hw_params *params, u32 dai_index,
1106                                           u32 linktype, u8 dir, u32 **dst, u32 *len)
1107 {
1108         return 0;
1109 }
1110 #endif
1111
1112 static int
1113 sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
1114                                struct snd_pcm_hw_params *fe_params,
1115                                struct snd_sof_platform_stream_params *platform_params,
1116                                struct snd_pcm_hw_params *pipeline_params, int dir)
1117 {
1118         struct sof_ipc4_available_audio_format *available_fmt;
1119         struct snd_soc_component *scomp = swidget->scomp;
1120         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1121         struct sof_ipc4_copier_data *copier_data;
1122         struct snd_pcm_hw_params *ref_params;
1123         struct sof_ipc4_copier *ipc4_copier;
1124         struct snd_sof_dai *dai;
1125         struct snd_mask *fmt;
1126         int out_sample_valid_bits;
1127         size_t ref_audio_fmt_size;
1128         void **ipc_config_data;
1129         int *ipc_config_size;
1130         u32 **data;
1131         int ipc_size, ret;
1132
1133         dev_dbg(sdev->dev, "copier %s, type %d", swidget->widget->name, swidget->id);
1134
1135         switch (swidget->id) {
1136         case snd_soc_dapm_aif_in:
1137         case snd_soc_dapm_aif_out:
1138         {
1139                 struct sof_ipc4_gtw_attributes *gtw_attr;
1140                 struct snd_sof_widget *pipe_widget;
1141                 struct sof_ipc4_pipeline *pipeline;
1142
1143                 pipe_widget = swidget->spipe->pipe_widget;
1144                 pipeline = pipe_widget->private;
1145                 ipc4_copier = (struct sof_ipc4_copier *)swidget->private;
1146                 gtw_attr = ipc4_copier->gtw_attr;
1147                 copier_data = &ipc4_copier->data;
1148                 available_fmt = &ipc4_copier->available_fmt;
1149
1150                 /*
1151                  * base_config->audio_fmt and out_audio_fmt represent the input and output audio
1152                  * formats. Use the input format as the reference to match pcm params for playback
1153                  * and the output format as reference for capture.
1154                  */
1155                 if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
1156                         available_fmt->ref_audio_fmt = &available_fmt->base_config->audio_fmt;
1157                         ref_audio_fmt_size = sizeof(struct sof_ipc4_base_module_cfg);
1158                 } else {
1159                         available_fmt->ref_audio_fmt = available_fmt->out_audio_fmt;
1160                         ref_audio_fmt_size = sizeof(struct sof_ipc4_audio_format);
1161                 }
1162                 copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
1163                 copier_data->gtw_cfg.node_id |=
1164                         SOF_IPC4_NODE_INDEX(platform_params->stream_tag - 1);
1165
1166                 /* set gateway attributes */
1167                 gtw_attr->lp_buffer_alloc = pipeline->lp_mode;
1168                 ref_params = fe_params;
1169                 break;
1170         }
1171         case snd_soc_dapm_dai_in:
1172         case snd_soc_dapm_dai_out:
1173         {
1174                 dai = swidget->private;
1175
1176                 ipc4_copier = (struct sof_ipc4_copier *)dai->private;
1177                 copier_data = &ipc4_copier->data;
1178                 available_fmt = &ipc4_copier->available_fmt;
1179                 if (dir == SNDRV_PCM_STREAM_CAPTURE) {
1180                         available_fmt->ref_audio_fmt = available_fmt->out_audio_fmt;
1181                         ref_audio_fmt_size = sizeof(struct sof_ipc4_audio_format);
1182
1183                         /*
1184                          * modify the input params for the dai copier as it only supports
1185                          * 32-bit always
1186                          */
1187                         fmt = hw_param_mask(pipeline_params, SNDRV_PCM_HW_PARAM_FORMAT);
1188                         snd_mask_none(fmt);
1189                         snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE);
1190                 } else {
1191                         available_fmt->ref_audio_fmt = &available_fmt->base_config->audio_fmt;
1192                         ref_audio_fmt_size = sizeof(struct sof_ipc4_base_module_cfg);
1193                 }
1194
1195                 ref_params = pipeline_params;
1196
1197                 ret = snd_sof_get_nhlt_endpoint_data(sdev, dai, fe_params, ipc4_copier->dai_index,
1198                                                      ipc4_copier->dai_type, dir,
1199                                                      &ipc4_copier->copier_config,
1200                                                      &copier_data->gtw_cfg.config_length);
1201                 if (ret < 0)
1202                         return ret;
1203
1204                 break;
1205         }
1206         case snd_soc_dapm_buffer:
1207         {
1208                 ipc4_copier = (struct sof_ipc4_copier *)swidget->private;
1209                 copier_data = &ipc4_copier->data;
1210                 available_fmt = &ipc4_copier->available_fmt;
1211
1212                 /*
1213                  * base_config->audio_fmt represent the input audio formats. Use
1214                  * the input format as the reference to match pcm params
1215                  */
1216                 available_fmt->ref_audio_fmt = &available_fmt->base_config->audio_fmt;
1217                 ref_audio_fmt_size = sizeof(struct sof_ipc4_base_module_cfg);
1218                 ref_params = pipeline_params;
1219
1220                 break;
1221         }
1222         default:
1223                 dev_err(sdev->dev, "unsupported type %d for copier %s",
1224                         swidget->id, swidget->widget->name);
1225                 return -EINVAL;
1226         }
1227
1228         /* set input and output audio formats */
1229         ret = sof_ipc4_init_audio_fmt(sdev, swidget, &copier_data->base_config,
1230                                       &copier_data->out_format, ref_params,
1231                                       available_fmt, ref_audio_fmt_size);
1232         if (ret < 0)
1233                 return ret;
1234
1235         switch (swidget->id) {
1236         case snd_soc_dapm_dai_in:
1237         case snd_soc_dapm_dai_out:
1238         {
1239                 /*
1240                  * Only SOF_DAI_INTEL_ALH needs copier_data to set blob.
1241                  * That's why only ALH dai's blob is set after sof_ipc4_init_audio_fmt
1242                  */
1243                 if (ipc4_copier->dai_type == SOF_DAI_INTEL_ALH) {
1244                         struct sof_ipc4_alh_configuration_blob *blob;
1245                         struct sof_ipc4_copier_data *alh_data;
1246                         struct sof_ipc4_copier *alh_copier;
1247                         struct snd_sof_widget *w;
1248                         u32 ch_count = 0;
1249                         u32 ch_mask = 0;
1250                         u32 ch_map;
1251                         u32 step;
1252                         u32 mask;
1253                         int i;
1254
1255                         blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config;
1256
1257                         blob->gw_attr.lp_buffer_alloc = 0;
1258
1259                         /* Get channel_mask from ch_map */
1260                         ch_map = copier_data->base_config.audio_fmt.ch_map;
1261                         for (i = 0; ch_map; i++) {
1262                                 if ((ch_map & 0xf) != 0xf) {
1263                                         ch_mask |= BIT(i);
1264                                         ch_count++;
1265                                 }
1266                                 ch_map >>= 4;
1267                         }
1268
1269                         step = ch_count / blob->alh_cfg.count;
1270                         mask =  GENMASK(step - 1, 0);
1271                         /*
1272                          * Set each gtw_cfg.node_id to blob->alh_cfg.mapping[]
1273                          * for all widgets with the same stream name
1274                          */
1275                         i = 0;
1276                         list_for_each_entry(w, &sdev->widget_list, list) {
1277                                 if (w->widget->sname &&
1278                                     strcmp(w->widget->sname, swidget->widget->sname))
1279                                         continue;
1280
1281                                 dai = w->private;
1282                                 alh_copier = (struct sof_ipc4_copier *)dai->private;
1283                                 alh_data = &alh_copier->data;
1284                                 blob->alh_cfg.mapping[i].alh_id = alh_data->gtw_cfg.node_id;
1285                                 /*
1286                                  * Set the same channel mask for playback as the audio data is
1287                                  * duplicated for all speakers. For capture, split the channels
1288                                  * among the aggregated DAIs. For example, with 4 channels on 2
1289                                  * aggregated DAIs, the channel_mask should be 0x3 and 0xc for the
1290                                  * two DAI's.
1291                                  * The channel masks used depend on the cpu_dais used in the
1292                                  * dailink at the machine driver level, which actually comes from
1293                                  * the tables in soc_acpi files depending on the _ADR and devID
1294                                  * registers for each codec.
1295                                  */
1296                                 if (w->id == snd_soc_dapm_dai_in)
1297                                         blob->alh_cfg.mapping[i].channel_mask = ch_mask;
1298                                 else
1299                                         blob->alh_cfg.mapping[i].channel_mask = mask << (step * i);
1300
1301                                 i++;
1302                         }
1303                         if (blob->alh_cfg.count > 1) {
1304                                 int group_id;
1305
1306                                 group_id = ida_alloc_max(&alh_group_ida, ALH_MULTI_GTW_COUNT - 1,
1307                                                          GFP_KERNEL);
1308
1309                                 if (group_id < 0)
1310                                         return group_id;
1311
1312                                 /* add multi-gateway base */
1313                                 group_id += ALH_MULTI_GTW_BASE;
1314                                 copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
1315                                 copier_data->gtw_cfg.node_id |= SOF_IPC4_NODE_INDEX(group_id);
1316                         }
1317                 }
1318         }
1319         }
1320
1321         /* modify the input params for the next widget */
1322         fmt = hw_param_mask(pipeline_params, SNDRV_PCM_HW_PARAM_FORMAT);
1323         out_sample_valid_bits =
1324                 SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(copier_data->out_format.fmt_cfg);
1325         snd_mask_none(fmt);
1326         switch (out_sample_valid_bits) {
1327         case 16:
1328                 snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
1329                 break;
1330         case 24:
1331                 snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
1332                 break;
1333         case 32:
1334                 snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE);
1335                 break;
1336         default:
1337                 dev_err(sdev->dev, "invalid sample frame format %d\n",
1338                         params_format(pipeline_params));
1339                 return -EINVAL;
1340         }
1341
1342         /* set the gateway dma_buffer_size using the matched ID returned above */
1343         copier_data->gtw_cfg.dma_buffer_size = available_fmt->dma_buffer_size[ret];
1344
1345         data = &ipc4_copier->copier_config;
1346         ipc_config_size = &ipc4_copier->ipc_config_size;
1347         ipc_config_data = &ipc4_copier->ipc_config_data;
1348
1349         /* config_length is DWORD based */
1350         ipc_size = sizeof(*copier_data) + copier_data->gtw_cfg.config_length * 4;
1351
1352         dev_dbg(sdev->dev, "copier %s, IPC size is %d", swidget->widget->name, ipc_size);
1353
1354         *ipc_config_data = kzalloc(ipc_size, GFP_KERNEL);
1355         if (!*ipc_config_data)
1356                 return -ENOMEM;
1357
1358         *ipc_config_size = ipc_size;
1359
1360         /* copy IPC data */
1361         memcpy(*ipc_config_data, (void *)copier_data, sizeof(*copier_data));
1362         if (copier_data->gtw_cfg.config_length)
1363                 memcpy(*ipc_config_data + sizeof(*copier_data),
1364                        *data, copier_data->gtw_cfg.config_length * 4);
1365
1366         /* update pipeline memory usage */
1367         sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &copier_data->base_config);
1368
1369         return 0;
1370 }
1371
1372 static int sof_ipc4_prepare_gain_module(struct snd_sof_widget *swidget,
1373                                         struct snd_pcm_hw_params *fe_params,
1374                                         struct snd_sof_platform_stream_params *platform_params,
1375                                         struct snd_pcm_hw_params *pipeline_params, int dir)
1376 {
1377         struct snd_soc_component *scomp = swidget->scomp;
1378         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1379         struct sof_ipc4_gain *gain = swidget->private;
1380         int ret;
1381
1382         gain->available_fmt.ref_audio_fmt = &gain->available_fmt.base_config->audio_fmt;
1383
1384         /* output format is not required to be sent to the FW for gain */
1385         ret = sof_ipc4_init_audio_fmt(sdev, swidget, &gain->base_config,
1386                                       NULL, pipeline_params, &gain->available_fmt,
1387                                       sizeof(gain->base_config));
1388         if (ret < 0)
1389                 return ret;
1390
1391         /* update pipeline memory usage */
1392         sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &gain->base_config);
1393
1394         return 0;
1395 }
1396
1397 static int sof_ipc4_prepare_mixer_module(struct snd_sof_widget *swidget,
1398                                          struct snd_pcm_hw_params *fe_params,
1399                                          struct snd_sof_platform_stream_params *platform_params,
1400                                          struct snd_pcm_hw_params *pipeline_params, int dir)
1401 {
1402         struct snd_soc_component *scomp = swidget->scomp;
1403         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1404         struct sof_ipc4_mixer *mixer = swidget->private;
1405         int ret;
1406
1407         /* only 32bit is supported by mixer */
1408         mixer->available_fmt.ref_audio_fmt = &mixer->available_fmt.base_config->audio_fmt;
1409
1410         /* output format is not required to be sent to the FW for mixer */
1411         ret = sof_ipc4_init_audio_fmt(sdev, swidget, &mixer->base_config,
1412                                       NULL, pipeline_params, &mixer->available_fmt,
1413                                       sizeof(mixer->base_config));
1414         if (ret < 0)
1415                 return ret;
1416
1417         /* update pipeline memory usage */
1418         sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &mixer->base_config);
1419
1420         return 0;
1421 }
1422
1423 static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget,
1424                                        struct snd_pcm_hw_params *fe_params,
1425                                        struct snd_sof_platform_stream_params *platform_params,
1426                                        struct snd_pcm_hw_params *pipeline_params, int dir)
1427 {
1428         struct snd_soc_component *scomp = swidget->scomp;
1429         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1430         struct sof_ipc4_src *src = swidget->private;
1431         struct snd_interval *rate;
1432         int ret;
1433
1434         src->available_fmt.ref_audio_fmt = &src->available_fmt.base_config->audio_fmt;
1435
1436         /* output format is not required to be sent to the FW for SRC */
1437         ret = sof_ipc4_init_audio_fmt(sdev, swidget, &src->base_config,
1438                                       NULL, pipeline_params, &src->available_fmt,
1439                                       sizeof(src->base_config));
1440         if (ret < 0)
1441                 return ret;
1442
1443         /* update pipeline memory usage */
1444         sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &src->base_config);
1445
1446         /* update pipeline_params for sink widgets */
1447         rate = hw_param_interval(pipeline_params, SNDRV_PCM_HW_PARAM_RATE);
1448         rate->min = src->sink_rate;
1449         rate->max = rate->min;
1450
1451         return 0;
1452 }
1453
1454 static int sof_ipc4_control_load_volume(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
1455 {
1456         struct sof_ipc4_control_data *control_data;
1457         struct sof_ipc4_msg *msg;
1458         int i;
1459
1460         scontrol->size = struct_size(control_data, chanv, scontrol->num_channels);
1461
1462         /* scontrol->ipc_control_data will be freed in sof_control_unload */
1463         scontrol->ipc_control_data = kzalloc(scontrol->size, GFP_KERNEL);
1464         if (!scontrol->ipc_control_data)
1465                 return -ENOMEM;
1466
1467         control_data = scontrol->ipc_control_data;
1468         control_data->index = scontrol->index;
1469
1470         msg = &control_data->msg;
1471         msg->primary = SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_LARGE_CONFIG_SET);
1472         msg->primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
1473         msg->primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
1474
1475         msg->extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_GAIN_PARAM_ID);
1476
1477         /* set default volume values to 0dB in control */
1478         for (i = 0; i < scontrol->num_channels; i++) {
1479                 control_data->chanv[i].channel = i;
1480                 control_data->chanv[i].value = SOF_IPC4_VOL_ZERO_DB;
1481         }
1482
1483         return 0;
1484 }
1485
1486 static int sof_ipc4_control_setup(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
1487 {
1488         switch (scontrol->info_type) {
1489         case SND_SOC_TPLG_CTL_VOLSW:
1490         case SND_SOC_TPLG_CTL_VOLSW_SX:
1491         case SND_SOC_TPLG_CTL_VOLSW_XR_SX:
1492                 return sof_ipc4_control_load_volume(sdev, scontrol);
1493         default:
1494                 break;
1495         }
1496
1497         return 0;
1498 }
1499
1500 static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
1501 {
1502         struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
1503         struct sof_ipc4_fw_data *ipc4_data = sdev->private;
1504         struct sof_ipc4_pipeline *pipeline;
1505         struct sof_ipc4_msg *msg;
1506         void *ipc_data = NULL;
1507         u32 ipc_size = 0;
1508         int ret;
1509
1510         switch (swidget->id) {
1511         case snd_soc_dapm_scheduler:
1512                 pipeline = swidget->private;
1513
1514                 dev_dbg(sdev->dev, "pipeline: %d memory pages: %d\n", swidget->pipeline_id,
1515                         pipeline->mem_usage);
1516
1517                 msg = &pipeline->msg;
1518                 msg->primary |= pipeline->mem_usage;
1519
1520                 swidget->instance_id = ida_alloc_max(&pipeline_ida, ipc4_data->max_num_pipelines,
1521                                                      GFP_KERNEL);
1522                 if (swidget->instance_id < 0) {
1523                         dev_err(sdev->dev, "failed to assign pipeline id for %s: %d\n",
1524                                 swidget->widget->name, swidget->instance_id);
1525                         return swidget->instance_id;
1526                 }
1527                 msg->primary &= ~SOF_IPC4_GLB_PIPE_INSTANCE_MASK;
1528                 msg->primary |= SOF_IPC4_GLB_PIPE_INSTANCE_ID(swidget->instance_id);
1529                 break;
1530         case snd_soc_dapm_aif_in:
1531         case snd_soc_dapm_aif_out:
1532         case snd_soc_dapm_buffer:
1533         {
1534                 struct sof_ipc4_copier *ipc4_copier = swidget->private;
1535
1536                 ipc_size = ipc4_copier->ipc_config_size;
1537                 ipc_data = ipc4_copier->ipc_config_data;
1538
1539                 msg = &ipc4_copier->msg;
1540                 break;
1541         }
1542         case snd_soc_dapm_dai_in:
1543         case snd_soc_dapm_dai_out:
1544         {
1545                 struct snd_sof_dai *dai = swidget->private;
1546                 struct sof_ipc4_copier *ipc4_copier = dai->private;
1547
1548                 ipc_size = ipc4_copier->ipc_config_size;
1549                 ipc_data = ipc4_copier->ipc_config_data;
1550
1551                 msg = &ipc4_copier->msg;
1552                 break;
1553         }
1554         case snd_soc_dapm_pga:
1555         {
1556                 struct sof_ipc4_gain *gain = swidget->private;
1557
1558                 ipc_size = sizeof(struct sof_ipc4_base_module_cfg) +
1559                            sizeof(struct sof_ipc4_gain_data);
1560                 ipc_data = gain;
1561
1562                 msg = &gain->msg;
1563                 break;
1564         }
1565         case snd_soc_dapm_mixer:
1566         {
1567                 struct sof_ipc4_mixer *mixer = swidget->private;
1568
1569                 ipc_size = sizeof(mixer->base_config);
1570                 ipc_data = &mixer->base_config;
1571
1572                 msg = &mixer->msg;
1573                 break;
1574         }
1575         case snd_soc_dapm_src:
1576         {
1577                 struct sof_ipc4_src *src = swidget->private;
1578
1579                 ipc_size = sizeof(struct sof_ipc4_base_module_cfg) + sizeof(src->sink_rate);
1580                 ipc_data = src;
1581
1582                 msg = &src->msg;
1583                 break;
1584         }
1585         default:
1586                 dev_err(sdev->dev, "widget type %d not supported", swidget->id);
1587                 return -EINVAL;
1588         }
1589
1590         if (swidget->id != snd_soc_dapm_scheduler) {
1591                 ret = sof_ipc4_widget_assign_instance_id(sdev, swidget);
1592                 if (ret < 0) {
1593                         dev_err(sdev->dev, "failed to assign instance id for %s\n",
1594                                 swidget->widget->name);
1595                         return ret;
1596                 }
1597
1598                 msg->primary &= ~SOF_IPC4_MOD_INSTANCE_MASK;
1599                 msg->primary |= SOF_IPC4_MOD_INSTANCE(swidget->instance_id);
1600
1601                 msg->extension &= ~SOF_IPC4_MOD_EXT_PARAM_SIZE_MASK;
1602                 msg->extension |= ipc_size >> 2;
1603
1604                 msg->extension &= ~SOF_IPC4_MOD_EXT_PPL_ID_MASK;
1605                 msg->extension |= SOF_IPC4_MOD_EXT_PPL_ID(pipe_widget->instance_id);
1606         }
1607         dev_dbg(sdev->dev, "Create widget %s instance %d - pipe %d - core %d\n",
1608                 swidget->widget->name, swidget->instance_id, swidget->pipeline_id, swidget->core);
1609
1610         msg->data_size = ipc_size;
1611         msg->data_ptr = ipc_data;
1612
1613         ret = sof_ipc_tx_message(sdev->ipc, msg, ipc_size, NULL, 0);
1614         if (ret < 0) {
1615                 dev_err(sdev->dev, "failed to create module %s\n", swidget->widget->name);
1616
1617                 if (swidget->id != snd_soc_dapm_scheduler) {
1618                         struct sof_ipc4_fw_module *fw_module = swidget->module_info;
1619
1620                         ida_free(&fw_module->m_ida, swidget->instance_id);
1621                 } else {
1622                         ida_free(&pipeline_ida, swidget->instance_id);
1623                 }
1624         }
1625
1626         return ret;
1627 }
1628
1629 static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
1630 {
1631         struct sof_ipc4_fw_module *fw_module = swidget->module_info;
1632         struct sof_ipc4_fw_data *ipc4_data = sdev->private;
1633         int ret = 0;
1634
1635         mutex_lock(&ipc4_data->pipeline_state_mutex);
1636
1637         /* freeing a pipeline frees all the widgets associated with it */
1638         if (swidget->id == snd_soc_dapm_scheduler) {
1639                 struct sof_ipc4_pipeline *pipeline = swidget->private;
1640                 struct sof_ipc4_msg msg = {{ 0 }};
1641                 u32 header;
1642
1643                 header = SOF_IPC4_GLB_PIPE_INSTANCE_ID(swidget->instance_id);
1644                 header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_DELETE_PIPELINE);
1645                 header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
1646                 header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG);
1647
1648                 msg.primary = header;
1649
1650                 ret = sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0);
1651                 if (ret < 0)
1652                         dev_err(sdev->dev, "failed to free pipeline widget %s\n",
1653                                 swidget->widget->name);
1654
1655                 pipeline->mem_usage = 0;
1656                 pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED;
1657                 ida_free(&pipeline_ida, swidget->instance_id);
1658         } else {
1659                 ida_free(&fw_module->m_ida, swidget->instance_id);
1660         }
1661
1662         mutex_unlock(&ipc4_data->pipeline_state_mutex);
1663
1664         return ret;
1665 }
1666
1667 static int sof_ipc4_get_queue_id(struct snd_sof_widget *src_widget,
1668                                  struct snd_sof_widget *sink_widget, bool pin_type)
1669 {
1670         struct snd_sof_widget *current_swidget;
1671         struct snd_soc_component *scomp;
1672         struct ida *queue_ida;
1673         const char *buddy_name;
1674         char **pin_binding;
1675         u32 num_pins;
1676         int i;
1677
1678         if (pin_type == SOF_PIN_TYPE_SOURCE) {
1679                 current_swidget = src_widget;
1680                 pin_binding = src_widget->src_pin_binding;
1681                 queue_ida = &src_widget->src_queue_ida;
1682                 num_pins = src_widget->num_source_pins;
1683                 buddy_name = sink_widget->widget->name;
1684         } else {
1685                 current_swidget = sink_widget;
1686                 pin_binding = sink_widget->sink_pin_binding;
1687                 queue_ida = &sink_widget->sink_queue_ida;
1688                 num_pins = sink_widget->num_sink_pins;
1689                 buddy_name = src_widget->widget->name;
1690         }
1691
1692         scomp = current_swidget->scomp;
1693
1694         if (num_pins < 1) {
1695                 dev_err(scomp->dev, "invalid %s num_pins: %d for queue allocation for %s\n",
1696                         (pin_type == SOF_PIN_TYPE_SOURCE ? "source" : "sink"),
1697                         num_pins, current_swidget->widget->name);
1698                 return -EINVAL;
1699         }
1700
1701         /* If there is only one sink/source pin, queue id must be 0 */
1702         if (num_pins == 1)
1703                 return 0;
1704
1705         /* Allocate queue ID from pin binding array if it is defined in topology. */
1706         if (pin_binding) {
1707                 for (i = 0; i < num_pins; i++) {
1708                         if (!strcmp(pin_binding[i], buddy_name))
1709                                 return i;
1710                 }
1711                 /*
1712                  * Fail if no queue ID found from pin binding array, so that we don't
1713                  * mixed use pin binding array and ida for queue ID allocation.
1714                  */
1715                 dev_err(scomp->dev, "no %s queue id found from pin binding array for %s\n",
1716                         (pin_type == SOF_PIN_TYPE_SOURCE ? "source" : "sink"),
1717                         current_swidget->widget->name);
1718                 return -EINVAL;
1719         }
1720
1721         /* If no pin binding array specified in topology, use ida to allocate one */
1722         return ida_alloc_max(queue_ida, num_pins, GFP_KERNEL);
1723 }
1724
1725 static void sof_ipc4_put_queue_id(struct snd_sof_widget *swidget, int queue_id,
1726                                   bool pin_type)
1727 {
1728         struct ida *queue_ida;
1729         char **pin_binding;
1730         int num_pins;
1731
1732         if (pin_type == SOF_PIN_TYPE_SOURCE) {
1733                 pin_binding = swidget->src_pin_binding;
1734                 queue_ida = &swidget->src_queue_ida;
1735                 num_pins = swidget->num_source_pins;
1736         } else {
1737                 pin_binding = swidget->sink_pin_binding;
1738                 queue_ida = &swidget->sink_queue_ida;
1739                 num_pins = swidget->num_sink_pins;
1740         }
1741
1742         /* Nothing to free if queue ID is not allocated with ida. */
1743         if (num_pins == 1 || pin_binding)
1744                 return;
1745
1746         ida_free(queue_ida, queue_id);
1747 }
1748
1749 static int sof_ipc4_set_copier_sink_format(struct snd_sof_dev *sdev,
1750                                            struct snd_sof_widget *src_widget,
1751                                            struct snd_sof_widget *sink_widget,
1752                                            int sink_id)
1753 {
1754         struct sof_ipc4_base_module_cfg *sink_config = sink_widget->private;
1755         struct sof_ipc4_base_module_cfg *src_config;
1756         struct sof_ipc4_copier_config_set_sink_format format;
1757         struct sof_ipc4_fw_module *fw_module;
1758         struct sof_ipc4_msg msg = {{ 0 }};
1759         u32 header, extension;
1760
1761         dev_dbg(sdev->dev, "%s set copier sink %d format\n",
1762                 src_widget->widget->name, sink_id);
1763
1764         if (WIDGET_IS_DAI(src_widget->id)) {
1765                 struct snd_sof_dai *dai = src_widget->private;
1766
1767                 src_config = dai->private;
1768         } else {
1769                 src_config = src_widget->private;
1770         }
1771
1772         fw_module = src_widget->module_info;
1773
1774         format.sink_id = sink_id;
1775         memcpy(&format.source_fmt, &src_config->audio_fmt, sizeof(format.source_fmt));
1776         memcpy(&format.sink_fmt, &sink_config->audio_fmt, sizeof(format.sink_fmt));
1777         msg.data_size = sizeof(format);
1778         msg.data_ptr = &format;
1779
1780         header = fw_module->man4_module_entry.id;
1781         header |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id);
1782         header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_LARGE_CONFIG_SET);
1783         header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
1784         header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
1785
1786         extension = SOF_IPC4_MOD_EXT_MSG_SIZE(msg.data_size);
1787         extension |=
1788                 SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_COPIER_MODULE_CFG_PARAM_SET_SINK_FORMAT);
1789         extension |= SOF_IPC4_MOD_EXT_MSG_LAST_BLOCK(1);
1790         extension |= SOF_IPC4_MOD_EXT_MSG_FIRST_BLOCK(1);
1791
1792         msg.primary = header;
1793         msg.extension = extension;
1794
1795         return sof_ipc_tx_message(sdev->ipc, &msg, msg.data_size, NULL, 0);
1796 }
1797
1798 static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route *sroute)
1799 {
1800         struct snd_sof_widget *src_widget = sroute->src_widget;
1801         struct snd_sof_widget *sink_widget = sroute->sink_widget;
1802         struct sof_ipc4_fw_module *src_fw_module = src_widget->module_info;
1803         struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info;
1804         struct sof_ipc4_msg msg = {{ 0 }};
1805         u32 header, extension;
1806         int ret;
1807
1808         if (!src_fw_module || !sink_fw_module) {
1809                 dev_err(sdev->dev,
1810                         "cannot bind %s -> %s, no firmware module for: %s%s\n",
1811                         src_widget->widget->name, sink_widget->widget->name,
1812                         src_fw_module ? "" : " source",
1813                         sink_fw_module ? "" : " sink");
1814
1815                 return -ENODEV;
1816         }
1817
1818         sroute->src_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget,
1819                                                      SOF_PIN_TYPE_SOURCE);
1820         if (sroute->src_queue_id < 0) {
1821                 dev_err(sdev->dev, "failed to get queue ID for source widget: %s\n",
1822                         src_widget->widget->name);
1823                 return sroute->src_queue_id;
1824         }
1825
1826         sroute->dst_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget,
1827                                                      SOF_PIN_TYPE_SINK);
1828         if (sroute->dst_queue_id < 0) {
1829                 dev_err(sdev->dev, "failed to get queue ID for sink widget: %s\n",
1830                         sink_widget->widget->name);
1831                 sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id,
1832                                       SOF_PIN_TYPE_SOURCE);
1833                 return sroute->dst_queue_id;
1834         }
1835
1836         /* Pin 0 format is already set during copier module init */
1837         if (sroute->src_queue_id > 0 && WIDGET_IS_COPIER(src_widget->id)) {
1838                 ret = sof_ipc4_set_copier_sink_format(sdev, src_widget, sink_widget,
1839                                                       sroute->src_queue_id);
1840                 if (ret < 0) {
1841                         dev_err(sdev->dev, "failed to set sink format for %s source queue ID %d\n",
1842                                 src_widget->widget->name, sroute->src_queue_id);
1843                         goto out;
1844                 }
1845         }
1846
1847         dev_dbg(sdev->dev, "bind %s:%d -> %s:%d\n",
1848                 src_widget->widget->name, sroute->src_queue_id,
1849                 sink_widget->widget->name, sroute->dst_queue_id);
1850
1851         header = src_fw_module->man4_module_entry.id;
1852         header |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id);
1853         header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_BIND);
1854         header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
1855         header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
1856
1857         extension = sink_fw_module->man4_module_entry.id;
1858         extension |= SOF_IPC4_MOD_EXT_DST_MOD_INSTANCE(sink_widget->instance_id);
1859         extension |= SOF_IPC4_MOD_EXT_DST_MOD_QUEUE_ID(sroute->dst_queue_id);
1860         extension |= SOF_IPC4_MOD_EXT_SRC_MOD_QUEUE_ID(sroute->src_queue_id);
1861
1862         msg.primary = header;
1863         msg.extension = extension;
1864
1865         ret = sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0);
1866         if (ret < 0) {
1867                 dev_err(sdev->dev, "failed to bind modules %s:%d -> %s:%d\n",
1868                         src_widget->widget->name, sroute->src_queue_id,
1869                         sink_widget->widget->name, sroute->dst_queue_id);
1870                 goto out;
1871         }
1872
1873         return ret;
1874
1875 out:
1876         sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id, SOF_PIN_TYPE_SOURCE);
1877         sof_ipc4_put_queue_id(sink_widget, sroute->dst_queue_id, SOF_PIN_TYPE_SINK);
1878         return ret;
1879 }
1880
1881 static int sof_ipc4_route_free(struct snd_sof_dev *sdev, struct snd_sof_route *sroute)
1882 {
1883         struct snd_sof_widget *src_widget = sroute->src_widget;
1884         struct snd_sof_widget *sink_widget = sroute->sink_widget;
1885         struct sof_ipc4_fw_module *src_fw_module = src_widget->module_info;
1886         struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info;
1887         struct sof_ipc4_msg msg = {{ 0 }};
1888         u32 header, extension;
1889         int ret = 0;
1890
1891         dev_dbg(sdev->dev, "unbind modules %s:%d -> %s:%d\n",
1892                 src_widget->widget->name, sroute->src_queue_id,
1893                 sink_widget->widget->name, sroute->dst_queue_id);
1894
1895         /*
1896          * routes belonging to the same pipeline will be disconnected by the FW when the pipeline
1897          * is freed. So avoid sending this IPC which will be ignored by the FW anyway.
1898          */
1899         if (src_widget->spipe->pipe_widget == sink_widget->spipe->pipe_widget)
1900                 goto out;
1901
1902         header = src_fw_module->man4_module_entry.id;
1903         header |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id);
1904         header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_UNBIND);
1905         header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
1906         header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
1907
1908         extension = sink_fw_module->man4_module_entry.id;
1909         extension |= SOF_IPC4_MOD_EXT_DST_MOD_INSTANCE(sink_widget->instance_id);
1910         extension |= SOF_IPC4_MOD_EXT_DST_MOD_QUEUE_ID(sroute->dst_queue_id);
1911         extension |= SOF_IPC4_MOD_EXT_SRC_MOD_QUEUE_ID(sroute->src_queue_id);
1912
1913         msg.primary = header;
1914         msg.extension = extension;
1915
1916         ret = sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0);
1917         if (ret < 0)
1918                 dev_err(sdev->dev, "failed to unbind modules %s:%d -> %s:%d\n",
1919                         src_widget->widget->name, sroute->src_queue_id,
1920                         sink_widget->widget->name, sroute->dst_queue_id);
1921 out:
1922         sof_ipc4_put_queue_id(sink_widget, sroute->dst_queue_id, SOF_PIN_TYPE_SINK);
1923         sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id, SOF_PIN_TYPE_SOURCE);
1924
1925         return ret;
1926 }
1927
1928 static int sof_ipc4_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
1929                                unsigned int flags, struct snd_sof_dai_config_data *data)
1930 {
1931         struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
1932         struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
1933         struct snd_sof_dai *dai = swidget->private;
1934         struct sof_ipc4_gtw_attributes *gtw_attr;
1935         struct sof_ipc4_copier_data *copier_data;
1936         struct sof_ipc4_copier *ipc4_copier;
1937
1938         if (!dai || !dai->private) {
1939                 dev_err(sdev->dev, "Invalid DAI or DAI private data for %s\n",
1940                         swidget->widget->name);
1941                 return -EINVAL;
1942         }
1943
1944         ipc4_copier = (struct sof_ipc4_copier *)dai->private;
1945         copier_data = &ipc4_copier->data;
1946
1947         if (!data)
1948                 return 0;
1949
1950         switch (ipc4_copier->dai_type) {
1951         case SOF_DAI_INTEL_HDA:
1952                 gtw_attr = ipc4_copier->gtw_attr;
1953                 gtw_attr->lp_buffer_alloc = pipeline->lp_mode;
1954                 pipeline->skip_during_fe_trigger = true;
1955                 fallthrough;
1956         case SOF_DAI_INTEL_ALH:
1957                 /*
1958                  * Do not clear the node ID when this op is invoked with
1959                  * SOF_DAI_CONFIG_FLAGS_HW_FREE. It is needed to free the group_ida during
1960                  * unprepare.
1961                  */
1962                 if (flags & SOF_DAI_CONFIG_FLAGS_HW_PARAMS) {
1963                         copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
1964                         copier_data->gtw_cfg.node_id |= SOF_IPC4_NODE_INDEX(data->dai_data);
1965                 }
1966                 break;
1967         case SOF_DAI_INTEL_DMIC:
1968         case SOF_DAI_INTEL_SSP:
1969                 /* nothing to do for SSP/DMIC */
1970                 break;
1971         default:
1972                 dev_err(sdev->dev, "%s: unsupported dai type %d\n", __func__,
1973                         ipc4_copier->dai_type);
1974                 return -EINVAL;
1975         }
1976
1977         return 0;
1978 }
1979
1980 static int sof_ipc4_parse_manifest(struct snd_soc_component *scomp, int index,
1981                                    struct snd_soc_tplg_manifest *man)
1982 {
1983         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1984         struct sof_ipc4_fw_data *ipc4_data = sdev->private;
1985         struct sof_manifest_tlv *manifest_tlv;
1986         struct sof_manifest *manifest;
1987         u32 size = le32_to_cpu(man->priv.size);
1988         u8 *man_ptr = man->priv.data;
1989         u32 len_check;
1990         int i;
1991
1992         if (!size || size < SOF_IPC4_TPLG_ABI_SIZE) {
1993                 dev_err(scomp->dev, "%s: Invalid topology ABI size: %u\n",
1994                         __func__, size);
1995                 return -EINVAL;
1996         }
1997
1998         manifest = (struct sof_manifest *)man_ptr;
1999
2000         dev_info(scomp->dev,
2001                  "Topology: ABI %d:%d:%d Kernel ABI %u:%u:%u\n",
2002                   le16_to_cpu(manifest->abi_major), le16_to_cpu(manifest->abi_minor),
2003                   le16_to_cpu(manifest->abi_patch),
2004                   SOF_ABI_MAJOR, SOF_ABI_MINOR, SOF_ABI_PATCH);
2005
2006         /* TODO: Add ABI compatibility check */
2007
2008         /* no more data after the ABI version */
2009         if (size <= SOF_IPC4_TPLG_ABI_SIZE)
2010                 return 0;
2011
2012         manifest_tlv = manifest->items;
2013         len_check = sizeof(struct sof_manifest);
2014         for (i = 0; i < le16_to_cpu(manifest->count); i++) {
2015                 len_check += sizeof(struct sof_manifest_tlv) + le32_to_cpu(manifest_tlv->size);
2016                 if (len_check > size)
2017                         return -EINVAL;
2018
2019                 switch (le32_to_cpu(manifest_tlv->type)) {
2020                 case SOF_MANIFEST_DATA_TYPE_NHLT:
2021                         /* no NHLT in BIOS, so use the one from topology manifest */
2022                         if (ipc4_data->nhlt)
2023                                 break;
2024                         ipc4_data->nhlt = devm_kmemdup(sdev->dev, manifest_tlv->data,
2025                                                        le32_to_cpu(manifest_tlv->size), GFP_KERNEL);
2026                         if (!ipc4_data->nhlt)
2027                                 return -ENOMEM;
2028                         break;
2029                 default:
2030                         dev_warn(scomp->dev, "Skipping unknown manifest data type %d\n",
2031                                  manifest_tlv->type);
2032                         break;
2033                 }
2034                 man_ptr += sizeof(struct sof_manifest_tlv) + le32_to_cpu(manifest_tlv->size);
2035                 manifest_tlv = (struct sof_manifest_tlv *)man_ptr;
2036         }
2037
2038         return 0;
2039 }
2040
2041 static int sof_ipc4_dai_get_clk(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, int clk_type)
2042 {
2043         struct sof_ipc4_copier *ipc4_copier = dai->private;
2044         struct snd_soc_tplg_hw_config *hw_config;
2045         struct snd_sof_dai_link *slink;
2046         bool dai_link_found = false;
2047         bool hw_cfg_found = false;
2048         int i;
2049
2050         if (!ipc4_copier)
2051                 return 0;
2052
2053         list_for_each_entry(slink, &sdev->dai_link_list, list) {
2054                 if (!strcmp(slink->link->name, dai->name)) {
2055                         dai_link_found = true;
2056                         break;
2057                 }
2058         }
2059
2060         if (!dai_link_found) {
2061                 dev_err(sdev->dev, "no DAI link found for DAI %s\n", dai->name);
2062                 return -EINVAL;
2063         }
2064
2065         for (i = 0; i < slink->num_hw_configs; i++) {
2066                 hw_config = &slink->hw_configs[i];
2067                 if (dai->current_config == le32_to_cpu(hw_config->id)) {
2068                         hw_cfg_found = true;
2069                         break;
2070                 }
2071         }
2072
2073         if (!hw_cfg_found) {
2074                 dev_err(sdev->dev, "no matching hw_config found for DAI %s\n", dai->name);
2075                 return -EINVAL;
2076         }
2077
2078         switch (ipc4_copier->dai_type) {
2079         case SOF_DAI_INTEL_SSP:
2080                 switch (clk_type) {
2081                 case SOF_DAI_CLK_INTEL_SSP_MCLK:
2082                         return le32_to_cpu(hw_config->mclk_rate);
2083                 case SOF_DAI_CLK_INTEL_SSP_BCLK:
2084                         return le32_to_cpu(hw_config->bclk_rate);
2085                 default:
2086                         dev_err(sdev->dev, "Invalid clk type for SSP %d\n", clk_type);
2087                         break;
2088                 }
2089                 break;
2090         default:
2091                 dev_err(sdev->dev, "DAI type %d not supported yet!\n", ipc4_copier->dai_type);
2092                 break;
2093         }
2094
2095         return -EINVAL;
2096 }
2097
2098 static int sof_ipc4_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verify)
2099 {
2100         struct snd_sof_pcm *spcm;
2101         int dir, ret;
2102
2103         /*
2104          * This function is called during system suspend, we need to make sure
2105          * that all streams have been freed up.
2106          * Freeing might have been skipped when xrun happened just at the start
2107          * of the suspend and it sent a SNDRV_PCM_TRIGGER_STOP to the active
2108          * stream. This will call sof_pcm_stream_free() with
2109          * free_widget_list = false which will leave the kernel and firmware out
2110          * of sync during suspend/resume.
2111          *
2112          * This will also make sure that paused streams handled correctly.
2113          */
2114         list_for_each_entry(spcm, &sdev->pcm_list, list) {
2115                 for_each_pcm_streams(dir) {
2116                         struct snd_pcm_substream *substream = spcm->stream[dir].substream;
2117
2118                         if (!substream || !substream->runtime || spcm->stream[dir].suspend_ignored)
2119                                 continue;
2120
2121                         if (spcm->stream[dir].list) {
2122                                 ret = sof_pcm_stream_free(sdev, substream, spcm, dir, true);
2123                                 if (ret < 0)
2124                                         return ret;
2125                         }
2126                 }
2127         }
2128         return 0;
2129 }
2130
2131 static int sof_ipc4_link_setup(struct snd_sof_dev *sdev, struct snd_soc_dai_link *link)
2132 {
2133         if (link->no_pcm)
2134                 return 0;
2135
2136         /*
2137          * set default trigger order for all links. Exceptions to
2138          * the rule will be handled in sof_pcm_dai_link_fixup()
2139          * For playback, the sequence is the following: start BE,
2140          * start FE, stop FE, stop BE; for Capture the sequence is
2141          * inverted start FE, start BE, stop BE, stop FE
2142          */
2143         link->trigger[SNDRV_PCM_STREAM_PLAYBACK] = SND_SOC_DPCM_TRIGGER_POST;
2144         link->trigger[SNDRV_PCM_STREAM_CAPTURE] = SND_SOC_DPCM_TRIGGER_PRE;
2145
2146         return 0;
2147 }
2148
2149 static enum sof_tokens common_copier_token_list[] = {
2150         SOF_COMP_TOKENS,
2151         SOF_AUDIO_FMT_NUM_TOKENS,
2152         SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS,
2153         SOF_IN_AUDIO_FORMAT_TOKENS,
2154         SOF_OUT_AUDIO_FORMAT_TOKENS,
2155         SOF_COPIER_GATEWAY_CFG_TOKENS,
2156         SOF_COPIER_TOKENS,
2157         SOF_COMP_EXT_TOKENS,
2158 };
2159
2160 static enum sof_tokens pipeline_token_list[] = {
2161         SOF_SCHED_TOKENS,
2162         SOF_PIPELINE_TOKENS,
2163 };
2164
2165 static enum sof_tokens dai_token_list[] = {
2166         SOF_COMP_TOKENS,
2167         SOF_AUDIO_FMT_NUM_TOKENS,
2168         SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS,
2169         SOF_IN_AUDIO_FORMAT_TOKENS,
2170         SOF_OUT_AUDIO_FORMAT_TOKENS,
2171         SOF_COPIER_GATEWAY_CFG_TOKENS,
2172         SOF_COPIER_TOKENS,
2173         SOF_DAI_TOKENS,
2174         SOF_COMP_EXT_TOKENS,
2175 };
2176
2177 static enum sof_tokens pga_token_list[] = {
2178         SOF_COMP_TOKENS,
2179         SOF_GAIN_TOKENS,
2180         SOF_AUDIO_FMT_NUM_TOKENS,
2181         SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS,
2182         SOF_IN_AUDIO_FORMAT_TOKENS,
2183         SOF_COMP_EXT_TOKENS,
2184 };
2185
2186 static enum sof_tokens mixer_token_list[] = {
2187         SOF_COMP_TOKENS,
2188         SOF_AUDIO_FMT_NUM_TOKENS,
2189         SOF_IN_AUDIO_FORMAT_TOKENS,
2190         SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS,
2191         SOF_COMP_EXT_TOKENS,
2192 };
2193
2194 static enum sof_tokens src_token_list[] = {
2195         SOF_COMP_TOKENS,
2196         SOF_SRC_TOKENS,
2197         SOF_AUDIO_FMT_NUM_TOKENS,
2198         SOF_IN_AUDIO_FORMAT_TOKENS,
2199         SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS,
2200         SOF_COMP_EXT_TOKENS,
2201 };
2202
2203 static const struct sof_ipc_tplg_widget_ops tplg_ipc4_widget_ops[SND_SOC_DAPM_TYPE_COUNT] = {
2204         [snd_soc_dapm_aif_in] =  {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm,
2205                                   common_copier_token_list, ARRAY_SIZE(common_copier_token_list),
2206                                   NULL, sof_ipc4_prepare_copier_module,
2207                                   sof_ipc4_unprepare_copier_module},
2208         [snd_soc_dapm_aif_out] = {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm,
2209                                   common_copier_token_list, ARRAY_SIZE(common_copier_token_list),
2210                                   NULL, sof_ipc4_prepare_copier_module,
2211                                   sof_ipc4_unprepare_copier_module},
2212         [snd_soc_dapm_dai_in] = {sof_ipc4_widget_setup_comp_dai, sof_ipc4_widget_free_comp_dai,
2213                                  dai_token_list, ARRAY_SIZE(dai_token_list), NULL,
2214                                  sof_ipc4_prepare_copier_module,
2215                                  sof_ipc4_unprepare_copier_module},
2216         [snd_soc_dapm_dai_out] = {sof_ipc4_widget_setup_comp_dai, sof_ipc4_widget_free_comp_dai,
2217                                   dai_token_list, ARRAY_SIZE(dai_token_list), NULL,
2218                                   sof_ipc4_prepare_copier_module,
2219                                   sof_ipc4_unprepare_copier_module},
2220         [snd_soc_dapm_buffer] = {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm,
2221                                  common_copier_token_list, ARRAY_SIZE(common_copier_token_list),
2222                                  NULL, sof_ipc4_prepare_copier_module,
2223                                  sof_ipc4_unprepare_copier_module},
2224         [snd_soc_dapm_scheduler] = {sof_ipc4_widget_setup_comp_pipeline,
2225                                     sof_ipc4_widget_free_comp_pipeline,
2226                                     pipeline_token_list, ARRAY_SIZE(pipeline_token_list), NULL,
2227                                     NULL, NULL},
2228         [snd_soc_dapm_pga] = {sof_ipc4_widget_setup_comp_pga, sof_ipc4_widget_free_comp_pga,
2229                               pga_token_list, ARRAY_SIZE(pga_token_list), NULL,
2230                               sof_ipc4_prepare_gain_module,
2231                               NULL},
2232         [snd_soc_dapm_mixer] = {sof_ipc4_widget_setup_comp_mixer, sof_ipc4_widget_free_comp_mixer,
2233                                 mixer_token_list, ARRAY_SIZE(mixer_token_list),
2234                                 NULL, sof_ipc4_prepare_mixer_module,
2235                                 NULL},
2236         [snd_soc_dapm_src] = {sof_ipc4_widget_setup_comp_src, sof_ipc4_widget_free_comp_src,
2237                                 src_token_list, ARRAY_SIZE(src_token_list),
2238                                 NULL, sof_ipc4_prepare_src_module,
2239                                 NULL},
2240 };
2241
2242 const struct sof_ipc_tplg_ops ipc4_tplg_ops = {
2243         .widget = tplg_ipc4_widget_ops,
2244         .token_list = ipc4_token_list,
2245         .control_setup = sof_ipc4_control_setup,
2246         .control = &tplg_ipc4_control_ops,
2247         .widget_setup = sof_ipc4_widget_setup,
2248         .widget_free = sof_ipc4_widget_free,
2249         .route_setup = sof_ipc4_route_setup,
2250         .route_free = sof_ipc4_route_free,
2251         .dai_config = sof_ipc4_dai_config,
2252         .parse_manifest = sof_ipc4_parse_manifest,
2253         .dai_get_clk = sof_ipc4_dai_get_clk,
2254         .tear_down_all_pipelines = sof_ipc4_tear_down_all_pipelines,
2255         .link_setup = sof_ipc4_link_setup,
2256 };