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