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