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