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