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