190e89155SRanjani Sridharan // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) 290e89155SRanjani Sridharan // 390e89155SRanjani Sridharan // This file is provided under a dual BSD/GPLv2 license. When using or 490e89155SRanjani Sridharan // redistributing this file, you may do so under either license. 590e89155SRanjani Sridharan // 690e89155SRanjani Sridharan // Copyright(c) 2022 Intel Corporation. All rights reserved. 790e89155SRanjani Sridharan // 890e89155SRanjani Sridharan // 9f9efae95SRanjani Sridharan #include <linux/bitfield.h> 1090e89155SRanjani Sridharan #include <uapi/sound/sof/tokens.h> 1190e89155SRanjani Sridharan #include <sound/pcm_params.h> 1290e89155SRanjani Sridharan #include <sound/sof/ext_manifest4.h> 13aa84ffb7SRanjani Sridharan #include <sound/intel-nhlt.h> 1490e89155SRanjani Sridharan #include "sof-priv.h" 1590e89155SRanjani Sridharan #include "sof-audio.h" 1690e89155SRanjani Sridharan #include "ipc4-priv.h" 1790e89155SRanjani Sridharan #include "ipc4-topology.h" 1890e89155SRanjani Sridharan #include "ops.h" 1990e89155SRanjani Sridharan 20d97964f8SRanjani Sridharan #define SOF_IPC4_GAIN_PARAM_ID 0 21323aa1f0SRanjani Sridharan #define SOF_IPC4_TPLG_ABI_SIZE 6 22ca5ce0caSJyri Sarha #define SOF_IPC4_CHAIN_DMA_BUF_SIZE_MS 2 23d97964f8SRanjani Sridharan 24a150345aSBard Liao static DEFINE_IDA(alh_group_ida); 25a2ba1f70SBard Liao static DEFINE_IDA(pipeline_ida); 26a150345aSBard Liao 2790e89155SRanjani Sridharan static const struct sof_topology_token ipc4_sched_tokens[] = { 2890e89155SRanjani Sridharan {SOF_TKN_SCHED_LP_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 2905ade472SPeter Ujfalusi offsetof(struct sof_ipc4_pipeline, lp_mode)}, 30ca5ce0caSJyri Sarha {SOF_TKN_SCHED_USE_CHAIN_DMA, SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16, 31ca5ce0caSJyri Sarha offsetof(struct sof_ipc4_pipeline, use_chain_dma)}, 3205ade472SPeter Ujfalusi {SOF_TKN_SCHED_CORE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 3305ade472SPeter Ujfalusi offsetof(struct sof_ipc4_pipeline, core_id)}, 3490e89155SRanjani Sridharan }; 3590e89155SRanjani Sridharan 3690e89155SRanjani Sridharan static const struct sof_topology_token pipeline_tokens[] = { 3790e89155SRanjani Sridharan {SOF_TKN_SCHED_DYNAMIC_PIPELINE, SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16, 3890e89155SRanjani Sridharan offsetof(struct snd_sof_widget, dynamic_pipeline_widget)}, 3990e89155SRanjani Sridharan }; 4090e89155SRanjani Sridharan 412cabd02bSRanjani Sridharan static const struct sof_topology_token ipc4_comp_tokens[] = { 422cabd02bSRanjani Sridharan {SOF_TKN_COMP_IS_PAGES, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 432cabd02bSRanjani Sridharan offsetof(struct sof_ipc4_base_module_cfg, is_pages)}, 442cabd02bSRanjani Sridharan }; 452cabd02bSRanjani Sridharan 462cabd02bSRanjani Sridharan static const struct sof_topology_token ipc4_in_audio_format_tokens[] = { 472cabd02bSRanjani Sridharan {SOF_TKN_CAVS_AUDIO_FORMAT_IN_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 487ab6b1e8SRanjani Sridharan offsetof(struct sof_ipc4_pin_format, audio_fmt.sampling_frequency)}, 492cabd02bSRanjani Sridharan {SOF_TKN_CAVS_AUDIO_FORMAT_IN_BIT_DEPTH, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 507ab6b1e8SRanjani Sridharan offsetof(struct sof_ipc4_pin_format, audio_fmt.bit_depth)}, 512cabd02bSRanjani Sridharan {SOF_TKN_CAVS_AUDIO_FORMAT_IN_CH_MAP, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 527ab6b1e8SRanjani Sridharan offsetof(struct sof_ipc4_pin_format, audio_fmt.ch_map)}, 532cabd02bSRanjani Sridharan {SOF_TKN_CAVS_AUDIO_FORMAT_IN_CH_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 547ab6b1e8SRanjani Sridharan offsetof(struct sof_ipc4_pin_format, audio_fmt.ch_cfg)}, 552cabd02bSRanjani Sridharan {SOF_TKN_CAVS_AUDIO_FORMAT_IN_INTERLEAVING_STYLE, SND_SOC_TPLG_TUPLE_TYPE_WORD, 567ab6b1e8SRanjani Sridharan get_token_u32, offsetof(struct sof_ipc4_pin_format, 577ab6b1e8SRanjani Sridharan audio_fmt.interleaving_style)}, 582cabd02bSRanjani Sridharan {SOF_TKN_CAVS_AUDIO_FORMAT_IN_FMT_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 597ab6b1e8SRanjani Sridharan offsetof(struct sof_ipc4_pin_format, audio_fmt.fmt_cfg)}, 60be3c2153SRanjani Sridharan {SOF_TKN_CAVS_AUDIO_FORMAT_INPUT_PIN_INDEX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 617ab6b1e8SRanjani Sridharan offsetof(struct sof_ipc4_pin_format, pin_index)}, 627ab6b1e8SRanjani Sridharan {SOF_TKN_CAVS_AUDIO_FORMAT_IBS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 637ab6b1e8SRanjani Sridharan offsetof(struct sof_ipc4_pin_format, buffer_size)}, 642cabd02bSRanjani Sridharan }; 652cabd02bSRanjani Sridharan 662cabd02bSRanjani Sridharan static const struct sof_topology_token ipc4_out_audio_format_tokens[] = { 672cabd02bSRanjani Sridharan {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 687ab6b1e8SRanjani Sridharan offsetof(struct sof_ipc4_pin_format, audio_fmt.sampling_frequency)}, 692cabd02bSRanjani Sridharan {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_BIT_DEPTH, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 707ab6b1e8SRanjani Sridharan offsetof(struct sof_ipc4_pin_format, audio_fmt.bit_depth)}, 712cabd02bSRanjani Sridharan {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_CH_MAP, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 727ab6b1e8SRanjani Sridharan offsetof(struct sof_ipc4_pin_format, audio_fmt.ch_map)}, 732cabd02bSRanjani Sridharan {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_CH_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 747ab6b1e8SRanjani Sridharan offsetof(struct sof_ipc4_pin_format, audio_fmt.ch_cfg)}, 752cabd02bSRanjani Sridharan {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_INTERLEAVING_STYLE, SND_SOC_TPLG_TUPLE_TYPE_WORD, 767ab6b1e8SRanjani Sridharan get_token_u32, offsetof(struct sof_ipc4_pin_format, 777ab6b1e8SRanjani Sridharan audio_fmt.interleaving_style)}, 782cabd02bSRanjani Sridharan {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_FMT_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 797ab6b1e8SRanjani Sridharan offsetof(struct sof_ipc4_pin_format, audio_fmt.fmt_cfg)}, 80be3c2153SRanjani Sridharan {SOF_TKN_CAVS_AUDIO_FORMAT_OUTPUT_PIN_INDEX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 817ab6b1e8SRanjani Sridharan offsetof(struct sof_ipc4_pin_format, pin_index)}, 827ab6b1e8SRanjani Sridharan {SOF_TKN_CAVS_AUDIO_FORMAT_OBS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 837ab6b1e8SRanjani Sridharan offsetof(struct sof_ipc4_pin_format, buffer_size)}, 842cabd02bSRanjani Sridharan }; 852cabd02bSRanjani Sridharan 86594c1bb9SRanjani Sridharan static const struct sof_topology_token ipc4_copier_deep_buffer_tokens[] = { 87594c1bb9SRanjani Sridharan {SOF_TKN_INTEL_COPIER_DEEP_BUFFER_DMA_MS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 0}, 882cabd02bSRanjani Sridharan }; 892cabd02bSRanjani Sridharan 902cabd02bSRanjani Sridharan static const struct sof_topology_token ipc4_copier_tokens[] = { 912cabd02bSRanjani Sridharan {SOF_TKN_INTEL_COPIER_NODE_TYPE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 0}, 922cabd02bSRanjani Sridharan }; 932cabd02bSRanjani Sridharan 942cabd02bSRanjani Sridharan static const struct sof_topology_token ipc4_audio_fmt_num_tokens[] = { 954fdef47aSRanjani Sridharan {SOF_TKN_COMP_NUM_INPUT_AUDIO_FORMATS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 964fdef47aSRanjani Sridharan offsetof(struct sof_ipc4_available_audio_format, num_input_formats)}, 974fdef47aSRanjani Sridharan {SOF_TKN_COMP_NUM_OUTPUT_AUDIO_FORMATS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 984fdef47aSRanjani Sridharan offsetof(struct sof_ipc4_available_audio_format, num_output_formats)}, 992cabd02bSRanjani Sridharan }; 1002cabd02bSRanjani Sridharan 101abfb536bSRanjani Sridharan static const struct sof_topology_token dai_tokens[] = { 102abfb536bSRanjani Sridharan {SOF_TKN_DAI_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_dai_type, 103abfb536bSRanjani Sridharan offsetof(struct sof_ipc4_copier, dai_type)}, 104abfb536bSRanjani Sridharan {SOF_TKN_DAI_INDEX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 105abfb536bSRanjani Sridharan offsetof(struct sof_ipc4_copier, dai_index)}, 106abfb536bSRanjani Sridharan }; 107abfb536bSRanjani Sridharan 1082cabd02bSRanjani Sridharan /* Component extended tokens */ 1092cabd02bSRanjani Sridharan static const struct sof_topology_token comp_ext_tokens[] = { 1102cabd02bSRanjani Sridharan {SOF_TKN_COMP_UUID, SND_SOC_TPLG_TUPLE_TYPE_UUID, get_token_uuid, 1112cabd02bSRanjani Sridharan offsetof(struct snd_sof_widget, uuid)}, 112755ddc3aSRander Wang {SOF_TKN_COMP_CORE_ID, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 113755ddc3aSRander Wang offsetof(struct snd_sof_widget, core)}, 1142cabd02bSRanjani Sridharan }; 1152cabd02bSRanjani Sridharan 1164f838ab2SRanjani Sridharan static const struct sof_topology_token gain_tokens[] = { 1174f838ab2SRanjani Sridharan {SOF_TKN_GAIN_RAMP_TYPE, SND_SOC_TPLG_TUPLE_TYPE_WORD, 1184f838ab2SRanjani Sridharan get_token_u32, offsetof(struct sof_ipc4_gain_data, curve_type)}, 1194f838ab2SRanjani Sridharan {SOF_TKN_GAIN_RAMP_DURATION, 1204f838ab2SRanjani Sridharan SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 121e45cd86cSRander Wang offsetof(struct sof_ipc4_gain_data, curve_duration_l)}, 1224f838ab2SRanjani Sridharan {SOF_TKN_GAIN_VAL, SND_SOC_TPLG_TUPLE_TYPE_WORD, 1234f838ab2SRanjani Sridharan get_token_u32, offsetof(struct sof_ipc4_gain_data, init_val)}, 1244f838ab2SRanjani Sridharan }; 1254f838ab2SRanjani Sridharan 126b85f4fc4SRander Wang /* SRC */ 127b85f4fc4SRander Wang static const struct sof_topology_token src_tokens[] = { 128b85f4fc4SRander Wang {SOF_TKN_SRC_RATE_OUT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 129b85f4fc4SRander Wang offsetof(struct sof_ipc4_src, sink_rate)}, 130b85f4fc4SRander Wang }; 131b85f4fc4SRander Wang 13290e89155SRanjani Sridharan static const struct sof_token_info ipc4_token_list[SOF_TOKEN_COUNT] = { 133abfb536bSRanjani Sridharan [SOF_DAI_TOKENS] = {"DAI tokens", dai_tokens, ARRAY_SIZE(dai_tokens)}, 13490e89155SRanjani Sridharan [SOF_PIPELINE_TOKENS] = {"Pipeline tokens", pipeline_tokens, ARRAY_SIZE(pipeline_tokens)}, 13590e89155SRanjani Sridharan [SOF_SCHED_TOKENS] = {"Scheduler tokens", ipc4_sched_tokens, 13690e89155SRanjani Sridharan ARRAY_SIZE(ipc4_sched_tokens)}, 1372cabd02bSRanjani Sridharan [SOF_COMP_EXT_TOKENS] = {"Comp extended tokens", comp_ext_tokens, 1382cabd02bSRanjani Sridharan ARRAY_SIZE(comp_ext_tokens)}, 1392cabd02bSRanjani Sridharan [SOF_COMP_TOKENS] = {"IPC4 Component tokens", 1402cabd02bSRanjani Sridharan ipc4_comp_tokens, ARRAY_SIZE(ipc4_comp_tokens)}, 1412cabd02bSRanjani Sridharan [SOF_IN_AUDIO_FORMAT_TOKENS] = {"IPC4 Input Audio format tokens", 1422cabd02bSRanjani Sridharan ipc4_in_audio_format_tokens, ARRAY_SIZE(ipc4_in_audio_format_tokens)}, 1432cabd02bSRanjani Sridharan [SOF_OUT_AUDIO_FORMAT_TOKENS] = {"IPC4 Output Audio format tokens", 1442cabd02bSRanjani Sridharan ipc4_out_audio_format_tokens, ARRAY_SIZE(ipc4_out_audio_format_tokens)}, 145594c1bb9SRanjani Sridharan [SOF_COPIER_DEEP_BUFFER_TOKENS] = {"IPC4 Copier deep buffer tokens", 146594c1bb9SRanjani Sridharan ipc4_copier_deep_buffer_tokens, ARRAY_SIZE(ipc4_copier_deep_buffer_tokens)}, 1472cabd02bSRanjani Sridharan [SOF_COPIER_TOKENS] = {"IPC4 Copier tokens", ipc4_copier_tokens, 1482cabd02bSRanjani Sridharan ARRAY_SIZE(ipc4_copier_tokens)}, 1492cabd02bSRanjani Sridharan [SOF_AUDIO_FMT_NUM_TOKENS] = {"IPC4 Audio format number tokens", 1502cabd02bSRanjani Sridharan ipc4_audio_fmt_num_tokens, ARRAY_SIZE(ipc4_audio_fmt_num_tokens)}, 1514f838ab2SRanjani Sridharan [SOF_GAIN_TOKENS] = {"Gain tokens", gain_tokens, ARRAY_SIZE(gain_tokens)}, 152b85f4fc4SRander Wang [SOF_SRC_TOKENS] = {"SRC tokens", src_tokens, ARRAY_SIZE(src_tokens)}, 15390e89155SRanjani Sridharan }; 15490e89155SRanjani Sridharan 1557ab6b1e8SRanjani Sridharan static void sof_ipc4_dbg_audio_format(struct device *dev, struct sof_ipc4_pin_format *pin_fmt, 1567ab6b1e8SRanjani Sridharan int num_formats) 1572cabd02bSRanjani Sridharan { 1582cabd02bSRanjani Sridharan int i; 1592cabd02bSRanjani Sridharan 1607ab6b1e8SRanjani Sridharan for (i = 0; i < num_formats; i++) { 1617ab6b1e8SRanjani Sridharan struct sof_ipc4_audio_format *fmt = &pin_fmt[i].audio_fmt; 1622cabd02bSRanjani Sridharan dev_dbg(dev, 1637ab6b1e8SRanjani Sridharan "Pin index #%d: %uHz, %ubit (ch_map %#x ch_cfg %u interleaving_style %u fmt_cfg %#x) buffer size %d\n", 1647ab6b1e8SRanjani Sridharan pin_fmt[i].pin_index, fmt->sampling_frequency, fmt->bit_depth, fmt->ch_map, 1657ab6b1e8SRanjani Sridharan fmt->ch_cfg, fmt->interleaving_style, fmt->fmt_cfg, 1667ab6b1e8SRanjani Sridharan pin_fmt[i].buffer_size); 1672cabd02bSRanjani Sridharan } 1682cabd02bSRanjani Sridharan } 1692cabd02bSRanjani Sridharan 170648fea12SChao Song static const struct sof_ipc4_audio_format * 171648fea12SChao Song sof_ipc4_get_input_pin_audio_fmt(struct snd_sof_widget *swidget, int pin_index) 172648fea12SChao Song { 173648fea12SChao Song struct sof_ipc4_base_module_cfg_ext *base_cfg_ext; 174648fea12SChao Song struct sof_ipc4_process *process; 175648fea12SChao Song int i; 176648fea12SChao Song 177648fea12SChao Song if (swidget->id != snd_soc_dapm_effect) { 178648fea12SChao Song struct sof_ipc4_base_module_cfg *base = swidget->private; 179648fea12SChao Song 180648fea12SChao Song /* For non-process modules, base module config format is used for all input pins */ 181648fea12SChao Song return &base->audio_fmt; 182648fea12SChao Song } 183648fea12SChao Song 184648fea12SChao Song process = swidget->private; 185648fea12SChao Song base_cfg_ext = process->base_config_ext; 186648fea12SChao Song 187648fea12SChao Song /* 188648fea12SChao Song * If there are multiple input formats available for a pin, the first available format 189648fea12SChao Song * is chosen. 190648fea12SChao Song */ 191648fea12SChao Song for (i = 0; i < base_cfg_ext->num_input_pin_fmts; i++) { 192648fea12SChao Song struct sof_ipc4_pin_format *pin_format = &base_cfg_ext->pin_formats[i]; 193648fea12SChao Song 194648fea12SChao Song if (pin_format->pin_index == pin_index) 195648fea12SChao Song return &pin_format->audio_fmt; 196648fea12SChao Song } 197648fea12SChao Song 198648fea12SChao Song return NULL; 199648fea12SChao Song } 200648fea12SChao Song 2012cabd02bSRanjani Sridharan /** 2022cabd02bSRanjani Sridharan * sof_ipc4_get_audio_fmt - get available audio formats from swidget->tuples 2032cabd02bSRanjani Sridharan * @scomp: pointer to pointer to SOC component 2042cabd02bSRanjani Sridharan * @swidget: pointer to struct snd_sof_widget containing tuples 2052cabd02bSRanjani Sridharan * @available_fmt: pointer to struct sof_ipc4_available_audio_format being filling in 206171d5cceSRanjani Sridharan * @module_base_cfg: Pointer to the base_config in the module init IPC payload 2072cabd02bSRanjani Sridharan * 2082cabd02bSRanjani Sridharan * Return: 0 if successful 2092cabd02bSRanjani Sridharan */ 2102cabd02bSRanjani Sridharan static int sof_ipc4_get_audio_fmt(struct snd_soc_component *scomp, 2112cabd02bSRanjani Sridharan struct snd_sof_widget *swidget, 2122cabd02bSRanjani Sridharan struct sof_ipc4_available_audio_format *available_fmt, 2138abc9ab9SRanjani Sridharan struct sof_ipc4_base_module_cfg *module_base_cfg) 2142cabd02bSRanjani Sridharan { 215ef51cd1eSPeter Ujfalusi struct sof_ipc4_pin_format *in_format = NULL; 216ef51cd1eSPeter Ujfalusi struct sof_ipc4_pin_format *out_format; 2177ab6b1e8SRanjani Sridharan int ret; 2182cabd02bSRanjani Sridharan 2194fdef47aSRanjani Sridharan ret = sof_update_ipc_object(scomp, available_fmt, 2202cabd02bSRanjani Sridharan SOF_AUDIO_FMT_NUM_TOKENS, swidget->tuples, 2214fdef47aSRanjani Sridharan swidget->num_tuples, sizeof(available_fmt), 1); 2224fdef47aSRanjani Sridharan if (ret) { 2234fdef47aSRanjani Sridharan dev_err(scomp->dev, "Failed to parse audio format token count\n"); 2244fdef47aSRanjani Sridharan return ret; 2254fdef47aSRanjani Sridharan } 2264fdef47aSRanjani Sridharan 2274fdef47aSRanjani Sridharan if (!available_fmt->num_input_formats && !available_fmt->num_output_formats) { 2284fdef47aSRanjani Sridharan dev_err(scomp->dev, "No input/output pin formats set in topology\n"); 2292cabd02bSRanjani Sridharan return -EINVAL; 2302cabd02bSRanjani Sridharan } 2312cabd02bSRanjani Sridharan 2324fdef47aSRanjani Sridharan dev_dbg(scomp->dev, 2334fdef47aSRanjani Sridharan "Number of input audio formats: %d. Number of output audio formats: %d\n", 2344fdef47aSRanjani Sridharan available_fmt->num_input_formats, available_fmt->num_output_formats); 2352cabd02bSRanjani Sridharan 2369caa9018SPeter Ujfalusi /* set is_pages in the module's base_config */ 237171d5cceSRanjani Sridharan ret = sof_update_ipc_object(scomp, module_base_cfg, SOF_COMP_TOKENS, swidget->tuples, 238171d5cceSRanjani Sridharan swidget->num_tuples, sizeof(*module_base_cfg), 1); 2392cabd02bSRanjani Sridharan if (ret) { 240171d5cceSRanjani Sridharan dev_err(scomp->dev, "parse comp tokens for %s failed, error: %d\n", 241171d5cceSRanjani Sridharan swidget->widget->name, ret); 2427ab6b1e8SRanjani Sridharan return ret; 2432cabd02bSRanjani Sridharan } 244171d5cceSRanjani Sridharan 2459caa9018SPeter Ujfalusi dev_dbg(scomp->dev, "widget %s: is_pages: %d\n", swidget->widget->name, 2469caa9018SPeter Ujfalusi module_base_cfg->is_pages); 2472cabd02bSRanjani Sridharan 2484fdef47aSRanjani Sridharan if (available_fmt->num_input_formats) { 2494fdef47aSRanjani Sridharan in_format = kcalloc(available_fmt->num_input_formats, 2504fdef47aSRanjani Sridharan sizeof(*in_format), GFP_KERNEL); 2517ab6b1e8SRanjani Sridharan if (!in_format) 2522cabd02bSRanjani Sridharan return -ENOMEM; 2534fdef47aSRanjani Sridharan available_fmt->input_pin_fmts = in_format; 2542cabd02bSRanjani Sridharan 2557ab6b1e8SRanjani Sridharan ret = sof_update_ipc_object(scomp, in_format, 2562cabd02bSRanjani Sridharan SOF_IN_AUDIO_FORMAT_TOKENS, swidget->tuples, 2577ab6b1e8SRanjani Sridharan swidget->num_tuples, sizeof(*in_format), 2584fdef47aSRanjani Sridharan available_fmt->num_input_formats); 2592cabd02bSRanjani Sridharan if (ret) { 2604fdef47aSRanjani Sridharan dev_err(scomp->dev, "parse input audio fmt tokens failed %d\n", ret); 2612cabd02bSRanjani Sridharan goto err_in; 2622cabd02bSRanjani Sridharan } 2632cabd02bSRanjani Sridharan 2644fdef47aSRanjani Sridharan dev_dbg(scomp->dev, "Input audio formats for %s\n", swidget->widget->name); 2654fdef47aSRanjani Sridharan sof_ipc4_dbg_audio_format(scomp->dev, in_format, 2664fdef47aSRanjani Sridharan available_fmt->num_input_formats); 2674fdef47aSRanjani Sridharan } 2682cabd02bSRanjani Sridharan 2694fdef47aSRanjani Sridharan if (available_fmt->num_output_formats) { 2704fdef47aSRanjani Sridharan out_format = kcalloc(available_fmt->num_output_formats, sizeof(*out_format), 2714fdef47aSRanjani Sridharan GFP_KERNEL); 2722cabd02bSRanjani Sridharan if (!out_format) { 2732cabd02bSRanjani Sridharan ret = -ENOMEM; 2742cabd02bSRanjani Sridharan goto err_in; 2752cabd02bSRanjani Sridharan } 2762cabd02bSRanjani Sridharan 2772cabd02bSRanjani Sridharan ret = sof_update_ipc_object(scomp, out_format, 2782cabd02bSRanjani Sridharan SOF_OUT_AUDIO_FORMAT_TOKENS, swidget->tuples, 2792cabd02bSRanjani Sridharan swidget->num_tuples, sizeof(*out_format), 2804fdef47aSRanjani Sridharan available_fmt->num_output_formats); 2812cabd02bSRanjani Sridharan if (ret) { 2824fdef47aSRanjani Sridharan dev_err(scomp->dev, "parse output audio fmt tokens failed\n"); 2832cabd02bSRanjani Sridharan goto err_out; 2842cabd02bSRanjani Sridharan } 2852cabd02bSRanjani Sridharan 2867ab6b1e8SRanjani Sridharan available_fmt->output_pin_fmts = out_format; 2874fdef47aSRanjani Sridharan dev_dbg(scomp->dev, "Output audio formats for %s\n", swidget->widget->name); 2884fdef47aSRanjani Sridharan sof_ipc4_dbg_audio_format(scomp->dev, out_format, 2894fdef47aSRanjani Sridharan available_fmt->num_output_formats); 2904fdef47aSRanjani Sridharan } 2912cabd02bSRanjani Sridharan 2922cabd02bSRanjani Sridharan return 0; 2932cabd02bSRanjani Sridharan 2942cabd02bSRanjani Sridharan err_out: 2952cabd02bSRanjani Sridharan kfree(out_format); 2962cabd02bSRanjani Sridharan err_in: 297e63a73f9SRanjani Sridharan kfree(in_format); 2984fdef47aSRanjani Sridharan available_fmt->input_pin_fmts = NULL; 2992cabd02bSRanjani Sridharan return ret; 3002cabd02bSRanjani Sridharan } 3012cabd02bSRanjani Sridharan 302dc4fc0aeSLibin Yang /* release the memory allocated in sof_ipc4_get_audio_fmt */ 303dc4fc0aeSLibin Yang static void sof_ipc4_free_audio_fmt(struct sof_ipc4_available_audio_format *available_fmt) 304dc4fc0aeSLibin Yang 305dc4fc0aeSLibin Yang { 3067ab6b1e8SRanjani Sridharan kfree(available_fmt->output_pin_fmts); 3077ab6b1e8SRanjani Sridharan available_fmt->output_pin_fmts = NULL; 3087ab6b1e8SRanjani Sridharan kfree(available_fmt->input_pin_fmts); 3097ab6b1e8SRanjani Sridharan available_fmt->input_pin_fmts = NULL; 310dc4fc0aeSLibin Yang } 311dc4fc0aeSLibin Yang 312a29b2d02SBard Liao static void sof_ipc4_widget_free_comp_pipeline(struct snd_sof_widget *swidget) 31390e89155SRanjani Sridharan { 31490e89155SRanjani Sridharan kfree(swidget->private); 31590e89155SRanjani Sridharan } 31690e89155SRanjani Sridharan 3172cabd02bSRanjani Sridharan static int sof_ipc4_widget_set_module_info(struct snd_sof_widget *swidget) 3182cabd02bSRanjani Sridharan { 3192cabd02bSRanjani Sridharan struct snd_soc_component *scomp = swidget->scomp; 3202cabd02bSRanjani Sridharan struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 3212cabd02bSRanjani Sridharan 322c73f8b47SPeter Ujfalusi swidget->module_info = sof_ipc4_find_module_by_uuid(sdev, &swidget->uuid); 3235a932cfcSPeter Ujfalusi 324c73f8b47SPeter Ujfalusi if (swidget->module_info) 3252cabd02bSRanjani Sridharan return 0; 3262cabd02bSRanjani Sridharan 3272cabd02bSRanjani Sridharan dev_err(sdev->dev, "failed to find module info for widget %s with UUID %pUL\n", 3282cabd02bSRanjani Sridharan swidget->widget->name, &swidget->uuid); 3292cabd02bSRanjani Sridharan return -EINVAL; 3302cabd02bSRanjani Sridharan } 3312cabd02bSRanjani Sridharan 3322cabd02bSRanjani Sridharan static int sof_ipc4_widget_setup_msg(struct snd_sof_widget *swidget, struct sof_ipc4_msg *msg) 3332cabd02bSRanjani Sridharan { 3342cabd02bSRanjani Sridharan struct sof_ipc4_fw_module *fw_module; 335dc6137a5SRander Wang uint32_t type; 3362cabd02bSRanjani Sridharan int ret; 3372cabd02bSRanjani Sridharan 3382cabd02bSRanjani Sridharan ret = sof_ipc4_widget_set_module_info(swidget); 3392cabd02bSRanjani Sridharan if (ret) 3402cabd02bSRanjani Sridharan return ret; 3412cabd02bSRanjani Sridharan 3422cabd02bSRanjani Sridharan fw_module = swidget->module_info; 3432cabd02bSRanjani Sridharan 3442cabd02bSRanjani Sridharan msg->primary = fw_module->man4_module_entry.id; 3452cabd02bSRanjani Sridharan msg->primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_INIT_INSTANCE); 3462cabd02bSRanjani Sridharan msg->primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); 3472cabd02bSRanjani Sridharan msg->primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG); 3482cabd02bSRanjani Sridharan 349a2ba1f70SBard Liao msg->extension = SOF_IPC4_MOD_EXT_CORE_ID(swidget->core); 3502cabd02bSRanjani Sridharan 35180d53171SPierre-Louis Bossart type = (fw_module->man4_module_entry.type & SOF_IPC4_MODULE_DP) ? 1 : 0; 352dc6137a5SRander Wang msg->extension |= SOF_IPC4_MOD_EXT_DOMAIN(type); 353dc6137a5SRander Wang 3542cabd02bSRanjani Sridharan return 0; 3552cabd02bSRanjani Sridharan } 3562cabd02bSRanjani Sridharan 35704b522a4SPeter Ujfalusi static void sof_ipc4_widget_update_kcontrol_module_id(struct snd_sof_widget *swidget) 35804b522a4SPeter Ujfalusi { 35904b522a4SPeter Ujfalusi struct snd_soc_component *scomp = swidget->scomp; 36004b522a4SPeter Ujfalusi struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 36104b522a4SPeter Ujfalusi struct sof_ipc4_fw_module *fw_module = swidget->module_info; 36204b522a4SPeter Ujfalusi struct snd_sof_control *scontrol; 36304b522a4SPeter Ujfalusi 36404b522a4SPeter Ujfalusi /* update module ID for all kcontrols for this widget */ 36504b522a4SPeter Ujfalusi list_for_each_entry(scontrol, &sdev->kcontrol_list, list) { 36604b522a4SPeter Ujfalusi if (scontrol->comp_id == swidget->comp_id) { 36704b522a4SPeter Ujfalusi struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data; 36804b522a4SPeter Ujfalusi struct sof_ipc4_msg *msg = &cdata->msg; 36904b522a4SPeter Ujfalusi 37004b522a4SPeter Ujfalusi msg->primary |= fw_module->man4_module_entry.id; 37104b522a4SPeter Ujfalusi } 37204b522a4SPeter Ujfalusi } 37304b522a4SPeter Ujfalusi } 37404b522a4SPeter Ujfalusi 3752cabd02bSRanjani Sridharan static int sof_ipc4_widget_setup_pcm(struct snd_sof_widget *swidget) 3762cabd02bSRanjani Sridharan { 3772cabd02bSRanjani Sridharan struct sof_ipc4_available_audio_format *available_fmt; 3782cabd02bSRanjani Sridharan struct snd_soc_component *scomp = swidget->scomp; 3792cabd02bSRanjani Sridharan struct sof_ipc4_copier *ipc4_copier; 3802cabd02bSRanjani Sridharan int node_type = 0; 381594c1bb9SRanjani Sridharan int ret; 3822cabd02bSRanjani Sridharan 3832cabd02bSRanjani Sridharan ipc4_copier = kzalloc(sizeof(*ipc4_copier), GFP_KERNEL); 3842cabd02bSRanjani Sridharan if (!ipc4_copier) 3852cabd02bSRanjani Sridharan return -ENOMEM; 3862cabd02bSRanjani Sridharan 3872cabd02bSRanjani Sridharan swidget->private = ipc4_copier; 3882cabd02bSRanjani Sridharan available_fmt = &ipc4_copier->available_fmt; 3892cabd02bSRanjani Sridharan 3902cabd02bSRanjani Sridharan dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name); 3912cabd02bSRanjani Sridharan 392171d5cceSRanjani Sridharan ret = sof_ipc4_get_audio_fmt(scomp, swidget, available_fmt, 3938abc9ab9SRanjani Sridharan &ipc4_copier->data.base_config); 3942cabd02bSRanjani Sridharan if (ret) 3952cabd02bSRanjani Sridharan goto free_copier; 3962cabd02bSRanjani Sridharan 3977d573425SBard Liao /* 3987d573425SBard Liao * This callback is used by host copier and module-to-module copier, 3997d573425SBard Liao * and only host copier needs to set gtw_cfg. 4007d573425SBard Liao */ 4017d573425SBard Liao if (!WIDGET_IS_AIF(swidget->id)) 4027d573425SBard Liao goto skip_gtw_cfg; 4037d573425SBard Liao 4042cabd02bSRanjani Sridharan ret = sof_update_ipc_object(scomp, &node_type, 4052cabd02bSRanjani Sridharan SOF_COPIER_TOKENS, swidget->tuples, 4062cabd02bSRanjani Sridharan swidget->num_tuples, sizeof(node_type), 1); 4072cabd02bSRanjani Sridharan 4082cabd02bSRanjani Sridharan if (ret) { 4092cabd02bSRanjani Sridharan dev_err(scomp->dev, "parse host copier node type token failed %d\n", 4102cabd02bSRanjani Sridharan ret); 411594c1bb9SRanjani Sridharan goto free_available_fmt; 4122cabd02bSRanjani Sridharan } 4132cabd02bSRanjani Sridharan dev_dbg(scomp->dev, "host copier '%s' node_type %u\n", swidget->widget->name, node_type); 4142cabd02bSRanjani Sridharan 4157d573425SBard Liao skip_gtw_cfg: 4162cabd02bSRanjani Sridharan ipc4_copier->gtw_attr = kzalloc(sizeof(*ipc4_copier->gtw_attr), GFP_KERNEL); 4172cabd02bSRanjani Sridharan if (!ipc4_copier->gtw_attr) { 4182cabd02bSRanjani Sridharan ret = -ENOMEM; 419594c1bb9SRanjani Sridharan goto free_available_fmt; 4202cabd02bSRanjani Sridharan } 4212cabd02bSRanjani Sridharan 4222cabd02bSRanjani Sridharan ipc4_copier->copier_config = (uint32_t *)ipc4_copier->gtw_attr; 4232cabd02bSRanjani Sridharan ipc4_copier->data.gtw_cfg.config_length = 4242cabd02bSRanjani Sridharan sizeof(struct sof_ipc4_gtw_attributes) >> 2; 4252cabd02bSRanjani Sridharan 4267d573425SBard Liao switch (swidget->id) { 4277d573425SBard Liao case snd_soc_dapm_aif_in: 4287d573425SBard Liao case snd_soc_dapm_aif_out: 4297d573425SBard Liao ipc4_copier->data.gtw_cfg.node_id = SOF_IPC4_NODE_TYPE(node_type); 4307d573425SBard Liao break; 4317d573425SBard Liao case snd_soc_dapm_buffer: 4327d573425SBard Liao ipc4_copier->data.gtw_cfg.node_id = SOF_IPC4_INVALID_NODE_ID; 4337d573425SBard Liao ipc4_copier->ipc_config_size = 0; 4347d573425SBard Liao break; 4357d573425SBard Liao default: 4367d573425SBard Liao dev_err(scomp->dev, "invalid widget type %d\n", swidget->id); 4377d573425SBard Liao ret = -EINVAL; 4387d573425SBard Liao goto free_gtw_attr; 4397d573425SBard Liao } 4407d573425SBard Liao 4412cabd02bSRanjani Sridharan /* set up module info and message header */ 4422cabd02bSRanjani Sridharan ret = sof_ipc4_widget_setup_msg(swidget, &ipc4_copier->msg); 4432cabd02bSRanjani Sridharan if (ret) 4442cabd02bSRanjani Sridharan goto free_gtw_attr; 4452cabd02bSRanjani Sridharan 4462cabd02bSRanjani Sridharan return 0; 4472cabd02bSRanjani Sridharan 4482cabd02bSRanjani Sridharan free_gtw_attr: 4492cabd02bSRanjani Sridharan kfree(ipc4_copier->gtw_attr); 450dc4fc0aeSLibin Yang free_available_fmt: 451dc4fc0aeSLibin Yang sof_ipc4_free_audio_fmt(available_fmt); 4522cabd02bSRanjani Sridharan free_copier: 4532cabd02bSRanjani Sridharan kfree(ipc4_copier); 454b737fd8cSLibin Yang swidget->private = NULL; 4552cabd02bSRanjani Sridharan return ret; 4562cabd02bSRanjani Sridharan } 4572cabd02bSRanjani Sridharan 4582cabd02bSRanjani Sridharan static void sof_ipc4_widget_free_comp_pcm(struct snd_sof_widget *swidget) 4592cabd02bSRanjani Sridharan { 4602cabd02bSRanjani Sridharan struct sof_ipc4_copier *ipc4_copier = swidget->private; 4612cabd02bSRanjani Sridharan struct sof_ipc4_available_audio_format *available_fmt; 4622cabd02bSRanjani Sridharan 4632cabd02bSRanjani Sridharan if (!ipc4_copier) 4642cabd02bSRanjani Sridharan return; 4652cabd02bSRanjani Sridharan 4662cabd02bSRanjani Sridharan available_fmt = &ipc4_copier->available_fmt; 4677ab6b1e8SRanjani Sridharan kfree(available_fmt->output_pin_fmts); 4682cabd02bSRanjani Sridharan kfree(ipc4_copier->gtw_attr); 4692cabd02bSRanjani Sridharan kfree(ipc4_copier); 4702cabd02bSRanjani Sridharan swidget->private = NULL; 4712cabd02bSRanjani Sridharan } 4722cabd02bSRanjani Sridharan 473abfb536bSRanjani Sridharan static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget) 474abfb536bSRanjani Sridharan { 475abfb536bSRanjani Sridharan struct sof_ipc4_available_audio_format *available_fmt; 476abfb536bSRanjani Sridharan struct snd_soc_component *scomp = swidget->scomp; 477abfb536bSRanjani Sridharan struct snd_sof_dai *dai = swidget->private; 478abfb536bSRanjani Sridharan struct sof_ipc4_copier *ipc4_copier; 479ca5ce0caSJyri Sarha struct snd_sof_widget *pipe_widget; 480ca5ce0caSJyri Sarha struct sof_ipc4_pipeline *pipeline; 481abfb536bSRanjani Sridharan int node_type = 0; 482594c1bb9SRanjani Sridharan int ret; 483abfb536bSRanjani Sridharan 484abfb536bSRanjani Sridharan ipc4_copier = kzalloc(sizeof(*ipc4_copier), GFP_KERNEL); 485abfb536bSRanjani Sridharan if (!ipc4_copier) 486abfb536bSRanjani Sridharan return -ENOMEM; 487abfb536bSRanjani Sridharan 488abfb536bSRanjani Sridharan available_fmt = &ipc4_copier->available_fmt; 489abfb536bSRanjani Sridharan 490abfb536bSRanjani Sridharan dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name); 491abfb536bSRanjani Sridharan 492171d5cceSRanjani Sridharan ret = sof_ipc4_get_audio_fmt(scomp, swidget, available_fmt, 4938abc9ab9SRanjani Sridharan &ipc4_copier->data.base_config); 494abfb536bSRanjani Sridharan if (ret) 495abfb536bSRanjani Sridharan goto free_copier; 496abfb536bSRanjani Sridharan 497abfb536bSRanjani Sridharan ret = sof_update_ipc_object(scomp, &node_type, 498abfb536bSRanjani Sridharan SOF_COPIER_TOKENS, swidget->tuples, 499abfb536bSRanjani Sridharan swidget->num_tuples, sizeof(node_type), 1); 500abfb536bSRanjani Sridharan if (ret) { 501abfb536bSRanjani Sridharan dev_err(scomp->dev, "parse dai node type failed %d\n", ret); 502594c1bb9SRanjani Sridharan goto free_available_fmt; 503abfb536bSRanjani Sridharan } 504abfb536bSRanjani Sridharan 505abfb536bSRanjani Sridharan ret = sof_update_ipc_object(scomp, ipc4_copier, 506abfb536bSRanjani Sridharan SOF_DAI_TOKENS, swidget->tuples, 507abfb536bSRanjani Sridharan swidget->num_tuples, sizeof(u32), 1); 508abfb536bSRanjani Sridharan if (ret) { 509abfb536bSRanjani Sridharan dev_err(scomp->dev, "parse dai copier node token failed %d\n", ret); 510594c1bb9SRanjani Sridharan goto free_available_fmt; 511abfb536bSRanjani Sridharan } 512abfb536bSRanjani Sridharan 513abfb536bSRanjani Sridharan dev_dbg(scomp->dev, "dai %s node_type %u dai_type %u dai_index %d\n", swidget->widget->name, 514abfb536bSRanjani Sridharan node_type, ipc4_copier->dai_type, ipc4_copier->dai_index); 515abfb536bSRanjani Sridharan 516abfb536bSRanjani Sridharan ipc4_copier->data.gtw_cfg.node_id = SOF_IPC4_NODE_TYPE(node_type); 517aa84ffb7SRanjani Sridharan 518ca5ce0caSJyri Sarha pipe_widget = swidget->spipe->pipe_widget; 519ca5ce0caSJyri Sarha pipeline = pipe_widget->private; 520ca5ce0caSJyri Sarha if (pipeline->use_chain_dma && ipc4_copier->dai_type != SOF_DAI_INTEL_HDA) { 521ca5ce0caSJyri Sarha dev_err(scomp->dev, 522ca5ce0caSJyri Sarha "Bad DAI type '%d', Chained DMA is only supported by HDA DAIs (%d).\n", 523ca5ce0caSJyri Sarha ipc4_copier->dai_type, SOF_DAI_INTEL_HDA); 524ca5ce0caSJyri Sarha ret = -ENODEV; 525ca5ce0caSJyri Sarha goto free_available_fmt; 526ca5ce0caSJyri Sarha } 527ca5ce0caSJyri Sarha 528aa84ffb7SRanjani Sridharan switch (ipc4_copier->dai_type) { 529a45a4d43SBard Liao case SOF_DAI_INTEL_ALH: 530a45a4d43SBard Liao { 531a150345aSBard Liao struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 532a45a4d43SBard Liao struct sof_ipc4_alh_configuration_blob *blob; 5333c50211fSBard Liao struct snd_soc_dapm_path *p; 534a150345aSBard Liao struct snd_sof_widget *w; 5353c50211fSBard Liao int src_num = 0; 5363c50211fSBard Liao 5373c50211fSBard Liao snd_soc_dapm_widget_for_each_source_path(swidget->widget, p) 5383c50211fSBard Liao src_num++; 5393c50211fSBard Liao 5403c50211fSBard Liao if (swidget->id == snd_soc_dapm_dai_in && src_num == 0) { 5413c50211fSBard Liao /* 5423c50211fSBard Liao * The blob will not be used if the ALH copier is playback direction 5433c50211fSBard Liao * and doesn't connect to any source. 5443c50211fSBard Liao * It is fine to call kfree(ipc4_copier->copier_config) since 5453c50211fSBard Liao * ipc4_copier->copier_config is null. 5463c50211fSBard Liao */ 5473c50211fSBard Liao ret = 0; 5483c50211fSBard Liao break; 5493c50211fSBard Liao } 550a45a4d43SBard Liao 551a45a4d43SBard Liao blob = kzalloc(sizeof(*blob), GFP_KERNEL); 552a45a4d43SBard Liao if (!blob) { 553a45a4d43SBard Liao ret = -ENOMEM; 554594c1bb9SRanjani Sridharan goto free_available_fmt; 555a45a4d43SBard Liao } 556a45a4d43SBard Liao 557a150345aSBard Liao list_for_each_entry(w, &sdev->widget_list, list) { 558a150345aSBard Liao if (w->widget->sname && 559a150345aSBard Liao strcmp(w->widget->sname, swidget->widget->sname)) 560a150345aSBard Liao continue; 561a150345aSBard Liao 562e186e1f2SPierre-Louis Bossart blob->alh_cfg.device_count++; 563a150345aSBard Liao } 564a150345aSBard Liao 565a45a4d43SBard Liao ipc4_copier->copier_config = (uint32_t *)blob; 566a45a4d43SBard Liao ipc4_copier->data.gtw_cfg.config_length = sizeof(*blob) >> 2; 567a45a4d43SBard Liao break; 568a45a4d43SBard Liao } 569aa84ffb7SRanjani Sridharan case SOF_DAI_INTEL_SSP: 570aa84ffb7SRanjani Sridharan /* set SSP DAI index as the node_id */ 571aa84ffb7SRanjani Sridharan ipc4_copier->data.gtw_cfg.node_id |= 572aa84ffb7SRanjani Sridharan SOF_IPC4_NODE_INDEX_INTEL_SSP(ipc4_copier->dai_index); 573aa84ffb7SRanjani Sridharan break; 574aa84ffb7SRanjani Sridharan case SOF_DAI_INTEL_DMIC: 575aa84ffb7SRanjani Sridharan /* set DMIC DAI index as the node_id */ 576aa84ffb7SRanjani Sridharan ipc4_copier->data.gtw_cfg.node_id |= 577aa84ffb7SRanjani Sridharan SOF_IPC4_NODE_INDEX_INTEL_DMIC(ipc4_copier->dai_index); 578aa84ffb7SRanjani Sridharan break; 579aa84ffb7SRanjani Sridharan default: 580abfb536bSRanjani Sridharan ipc4_copier->gtw_attr = kzalloc(sizeof(*ipc4_copier->gtw_attr), GFP_KERNEL); 581abfb536bSRanjani Sridharan if (!ipc4_copier->gtw_attr) { 582abfb536bSRanjani Sridharan ret = -ENOMEM; 583594c1bb9SRanjani Sridharan goto free_available_fmt; 584abfb536bSRanjani Sridharan } 585abfb536bSRanjani Sridharan 586abfb536bSRanjani Sridharan ipc4_copier->copier_config = (uint32_t *)ipc4_copier->gtw_attr; 587aa84ffb7SRanjani Sridharan ipc4_copier->data.gtw_cfg.config_length = 588aa84ffb7SRanjani Sridharan sizeof(struct sof_ipc4_gtw_attributes) >> 2; 589aa84ffb7SRanjani Sridharan break; 590aa84ffb7SRanjani Sridharan } 591abfb536bSRanjani Sridharan 592abfb536bSRanjani Sridharan dai->scomp = scomp; 593abfb536bSRanjani Sridharan dai->private = ipc4_copier; 594abfb536bSRanjani Sridharan 595abfb536bSRanjani Sridharan /* set up module info and message header */ 596abfb536bSRanjani Sridharan ret = sof_ipc4_widget_setup_msg(swidget, &ipc4_copier->msg); 597abfb536bSRanjani Sridharan if (ret) 598abfb536bSRanjani Sridharan goto free_copier_config; 599abfb536bSRanjani Sridharan 600abfb536bSRanjani Sridharan return 0; 601abfb536bSRanjani Sridharan 602abfb536bSRanjani Sridharan free_copier_config: 603abfb536bSRanjani Sridharan kfree(ipc4_copier->copier_config); 604dc4fc0aeSLibin Yang free_available_fmt: 605dc4fc0aeSLibin Yang sof_ipc4_free_audio_fmt(available_fmt); 606abfb536bSRanjani Sridharan free_copier: 607abfb536bSRanjani Sridharan kfree(ipc4_copier); 608b737fd8cSLibin Yang dai->private = NULL; 609b737fd8cSLibin Yang dai->scomp = NULL; 610abfb536bSRanjani Sridharan return ret; 611abfb536bSRanjani Sridharan } 612abfb536bSRanjani Sridharan 613abfb536bSRanjani Sridharan static void sof_ipc4_widget_free_comp_dai(struct snd_sof_widget *swidget) 614abfb536bSRanjani Sridharan { 615abfb536bSRanjani Sridharan struct sof_ipc4_available_audio_format *available_fmt; 616abfb536bSRanjani Sridharan struct snd_sof_dai *dai = swidget->private; 617abfb536bSRanjani Sridharan struct sof_ipc4_copier *ipc4_copier; 618abfb536bSRanjani Sridharan 619abfb536bSRanjani Sridharan if (!dai) 620abfb536bSRanjani Sridharan return; 621abfb536bSRanjani Sridharan 622b737fd8cSLibin Yang if (!dai->private) { 623b737fd8cSLibin Yang kfree(dai); 624b737fd8cSLibin Yang swidget->private = NULL; 625b737fd8cSLibin Yang return; 626b737fd8cSLibin Yang } 627b737fd8cSLibin Yang 628abfb536bSRanjani Sridharan ipc4_copier = dai->private; 629abfb536bSRanjani Sridharan available_fmt = &ipc4_copier->available_fmt; 630abfb536bSRanjani Sridharan 6317ab6b1e8SRanjani Sridharan kfree(available_fmt->output_pin_fmts); 632aa84ffb7SRanjani Sridharan if (ipc4_copier->dai_type != SOF_DAI_INTEL_SSP && 633aa84ffb7SRanjani Sridharan ipc4_copier->dai_type != SOF_DAI_INTEL_DMIC) 634abfb536bSRanjani Sridharan kfree(ipc4_copier->copier_config); 635abfb536bSRanjani Sridharan kfree(dai->private); 636abfb536bSRanjani Sridharan kfree(dai); 637abfb536bSRanjani Sridharan swidget->private = NULL; 638abfb536bSRanjani Sridharan } 639abfb536bSRanjani Sridharan 64090e89155SRanjani Sridharan static int sof_ipc4_widget_setup_comp_pipeline(struct snd_sof_widget *swidget) 64190e89155SRanjani Sridharan { 64290e89155SRanjani Sridharan struct snd_soc_component *scomp = swidget->scomp; 64390e89155SRanjani Sridharan struct sof_ipc4_pipeline *pipeline; 64490e89155SRanjani Sridharan int ret; 64590e89155SRanjani Sridharan 64690e89155SRanjani Sridharan pipeline = kzalloc(sizeof(*pipeline), GFP_KERNEL); 64790e89155SRanjani Sridharan if (!pipeline) 64890e89155SRanjani Sridharan return -ENOMEM; 64990e89155SRanjani Sridharan 65090e89155SRanjani Sridharan ret = sof_update_ipc_object(scomp, pipeline, SOF_SCHED_TOKENS, swidget->tuples, 65190e89155SRanjani Sridharan swidget->num_tuples, sizeof(*pipeline), 1); 65290e89155SRanjani Sridharan if (ret) { 65390e89155SRanjani Sridharan dev_err(scomp->dev, "parsing scheduler tokens failed\n"); 65490e89155SRanjani Sridharan goto err; 65590e89155SRanjani Sridharan } 65690e89155SRanjani Sridharan 65705ade472SPeter Ujfalusi swidget->core = pipeline->core_id; 65805ade472SPeter Ujfalusi 659ca5ce0caSJyri Sarha if (pipeline->use_chain_dma) { 660ca5ce0caSJyri Sarha dev_dbg(scomp->dev, "Set up chain DMA for %s\n", swidget->widget->name); 661ca5ce0caSJyri Sarha swidget->private = pipeline; 662ca5ce0caSJyri Sarha return 0; 663ca5ce0caSJyri Sarha } 664ca5ce0caSJyri Sarha 66590e89155SRanjani Sridharan /* parse one set of pipeline tokens */ 66690e89155SRanjani Sridharan ret = sof_update_ipc_object(scomp, swidget, SOF_PIPELINE_TOKENS, swidget->tuples, 66790e89155SRanjani Sridharan swidget->num_tuples, sizeof(*swidget), 1); 66890e89155SRanjani Sridharan if (ret) { 66990e89155SRanjani Sridharan dev_err(scomp->dev, "parsing pipeline tokens failed\n"); 67090e89155SRanjani Sridharan goto err; 67190e89155SRanjani Sridharan } 67290e89155SRanjani Sridharan 67390e89155SRanjani Sridharan /* TODO: Get priority from topology */ 67490e89155SRanjani Sridharan pipeline->priority = 0; 67590e89155SRanjani Sridharan 67605ade472SPeter Ujfalusi dev_dbg(scomp->dev, "pipeline '%s': id %d, pri %d, core_id %u, lp mode %d\n", 67790e89155SRanjani Sridharan swidget->widget->name, swidget->pipeline_id, 67805ade472SPeter Ujfalusi pipeline->priority, pipeline->core_id, pipeline->lp_mode); 67990e89155SRanjani Sridharan 68090e89155SRanjani Sridharan swidget->private = pipeline; 68190e89155SRanjani Sridharan 68290e89155SRanjani Sridharan pipeline->msg.primary = SOF_IPC4_GLB_PIPE_PRIORITY(pipeline->priority); 68390e89155SRanjani Sridharan pipeline->msg.primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_CREATE_PIPELINE); 68490e89155SRanjani Sridharan pipeline->msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); 68590e89155SRanjani Sridharan pipeline->msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG); 68690e89155SRanjani Sridharan 68790e89155SRanjani Sridharan pipeline->msg.extension = pipeline->lp_mode; 68805ade472SPeter Ujfalusi pipeline->msg.extension |= SOF_IPC4_GLB_PIPE_EXT_CORE_ID(pipeline->core_id); 68990e89155SRanjani Sridharan pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED; 69090e89155SRanjani Sridharan 69190e89155SRanjani Sridharan return 0; 69290e89155SRanjani Sridharan err: 69390e89155SRanjani Sridharan kfree(pipeline); 69490e89155SRanjani Sridharan return ret; 69590e89155SRanjani Sridharan } 69690e89155SRanjani Sridharan 6974f838ab2SRanjani Sridharan static int sof_ipc4_widget_setup_comp_pga(struct snd_sof_widget *swidget) 6984f838ab2SRanjani Sridharan { 6994f838ab2SRanjani Sridharan struct snd_soc_component *scomp = swidget->scomp; 7004f838ab2SRanjani Sridharan struct sof_ipc4_gain *gain; 7014f838ab2SRanjani Sridharan int ret; 7024f838ab2SRanjani Sridharan 7034f838ab2SRanjani Sridharan gain = kzalloc(sizeof(*gain), GFP_KERNEL); 7044f838ab2SRanjani Sridharan if (!gain) 7054f838ab2SRanjani Sridharan return -ENOMEM; 7064f838ab2SRanjani Sridharan 7074f838ab2SRanjani Sridharan swidget->private = gain; 7084f838ab2SRanjani Sridharan 7094f838ab2SRanjani Sridharan gain->data.channels = SOF_IPC4_GAIN_ALL_CHANNELS_MASK; 7104f838ab2SRanjani Sridharan gain->data.init_val = SOF_IPC4_VOL_ZERO_DB; 7114f838ab2SRanjani Sridharan 7128abc9ab9SRanjani Sridharan ret = sof_ipc4_get_audio_fmt(scomp, swidget, &gain->available_fmt, &gain->base_config); 7134f838ab2SRanjani Sridharan if (ret) 7144f838ab2SRanjani Sridharan goto err; 7154f838ab2SRanjani Sridharan 7164f838ab2SRanjani Sridharan ret = sof_update_ipc_object(scomp, &gain->data, SOF_GAIN_TOKENS, swidget->tuples, 7174f838ab2SRanjani Sridharan swidget->num_tuples, sizeof(gain->data), 1); 7184f838ab2SRanjani Sridharan if (ret) { 7194f838ab2SRanjani Sridharan dev_err(scomp->dev, "Parsing gain tokens failed\n"); 7204f838ab2SRanjani Sridharan goto err; 7214f838ab2SRanjani Sridharan } 7224f838ab2SRanjani Sridharan 7234f838ab2SRanjani Sridharan dev_dbg(scomp->dev, 7249caa9018SPeter Ujfalusi "pga widget %s: ramp type: %d, ramp duration %d, initial gain value: %#x\n", 725e45cd86cSRander Wang swidget->widget->name, gain->data.curve_type, gain->data.curve_duration_l, 7269caa9018SPeter Ujfalusi gain->data.init_val); 7274f838ab2SRanjani Sridharan 7284f838ab2SRanjani Sridharan ret = sof_ipc4_widget_setup_msg(swidget, &gain->msg); 7294f838ab2SRanjani Sridharan if (ret) 7304f838ab2SRanjani Sridharan goto err; 7314f838ab2SRanjani Sridharan 73204b522a4SPeter Ujfalusi sof_ipc4_widget_update_kcontrol_module_id(swidget); 7334f838ab2SRanjani Sridharan 7344f838ab2SRanjani Sridharan return 0; 7354f838ab2SRanjani Sridharan err: 736dc4fc0aeSLibin Yang sof_ipc4_free_audio_fmt(&gain->available_fmt); 7374f838ab2SRanjani Sridharan kfree(gain); 738b737fd8cSLibin Yang swidget->private = NULL; 7394f838ab2SRanjani Sridharan return ret; 7404f838ab2SRanjani Sridharan } 7414f838ab2SRanjani Sridharan 742dc4fc0aeSLibin Yang static void sof_ipc4_widget_free_comp_pga(struct snd_sof_widget *swidget) 743dc4fc0aeSLibin Yang { 744dc4fc0aeSLibin Yang struct sof_ipc4_gain *gain = swidget->private; 745dc4fc0aeSLibin Yang 746dc4fc0aeSLibin Yang if (!gain) 747dc4fc0aeSLibin Yang return; 748dc4fc0aeSLibin Yang 749dc4fc0aeSLibin Yang sof_ipc4_free_audio_fmt(&gain->available_fmt); 750dc4fc0aeSLibin Yang kfree(swidget->private); 751dc4fc0aeSLibin Yang swidget->private = NULL; 752dc4fc0aeSLibin Yang } 753dc4fc0aeSLibin Yang 7544d4ba014SRanjani Sridharan static int sof_ipc4_widget_setup_comp_mixer(struct snd_sof_widget *swidget) 7554d4ba014SRanjani Sridharan { 7564d4ba014SRanjani Sridharan struct snd_soc_component *scomp = swidget->scomp; 7574d4ba014SRanjani Sridharan struct sof_ipc4_mixer *mixer; 7584d4ba014SRanjani Sridharan int ret; 7594d4ba014SRanjani Sridharan 7604d4ba014SRanjani Sridharan dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name); 7614d4ba014SRanjani Sridharan 7624d4ba014SRanjani Sridharan mixer = kzalloc(sizeof(*mixer), GFP_KERNEL); 7634d4ba014SRanjani Sridharan if (!mixer) 7644d4ba014SRanjani Sridharan return -ENOMEM; 7654d4ba014SRanjani Sridharan 7664d4ba014SRanjani Sridharan swidget->private = mixer; 7674d4ba014SRanjani Sridharan 768171d5cceSRanjani Sridharan ret = sof_ipc4_get_audio_fmt(scomp, swidget, &mixer->available_fmt, 7698abc9ab9SRanjani Sridharan &mixer->base_config); 7704d4ba014SRanjani Sridharan if (ret) 7714d4ba014SRanjani Sridharan goto err; 7724d4ba014SRanjani Sridharan 7734d4ba014SRanjani Sridharan ret = sof_ipc4_widget_setup_msg(swidget, &mixer->msg); 7744d4ba014SRanjani Sridharan if (ret) 7754d4ba014SRanjani Sridharan goto err; 7764d4ba014SRanjani Sridharan 7774d4ba014SRanjani Sridharan return 0; 7784d4ba014SRanjani Sridharan err: 779dc4fc0aeSLibin Yang sof_ipc4_free_audio_fmt(&mixer->available_fmt); 7804d4ba014SRanjani Sridharan kfree(mixer); 781b737fd8cSLibin Yang swidget->private = NULL; 7824d4ba014SRanjani Sridharan return ret; 7834d4ba014SRanjani Sridharan } 7844d4ba014SRanjani Sridharan 785b85f4fc4SRander Wang static int sof_ipc4_widget_setup_comp_src(struct snd_sof_widget *swidget) 786b85f4fc4SRander Wang { 787b85f4fc4SRander Wang struct snd_soc_component *scomp = swidget->scomp; 788b85f4fc4SRander Wang struct sof_ipc4_src *src; 789b85f4fc4SRander Wang int ret; 790b85f4fc4SRander Wang 791b85f4fc4SRander Wang dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name); 792b85f4fc4SRander Wang 793b85f4fc4SRander Wang src = kzalloc(sizeof(*src), GFP_KERNEL); 794b85f4fc4SRander Wang if (!src) 795b85f4fc4SRander Wang return -ENOMEM; 796b85f4fc4SRander Wang 797b85f4fc4SRander Wang swidget->private = src; 798b85f4fc4SRander Wang 7998abc9ab9SRanjani Sridharan ret = sof_ipc4_get_audio_fmt(scomp, swidget, &src->available_fmt, &src->base_config); 800b85f4fc4SRander Wang if (ret) 801b85f4fc4SRander Wang goto err; 802b85f4fc4SRander Wang 803b85f4fc4SRander Wang ret = sof_update_ipc_object(scomp, src, SOF_SRC_TOKENS, swidget->tuples, 804ecdb10dfSYang Yingliang swidget->num_tuples, sizeof(*src), 1); 805b85f4fc4SRander Wang if (ret) { 806b85f4fc4SRander Wang dev_err(scomp->dev, "Parsing SRC tokens failed\n"); 807b85f4fc4SRander Wang goto err; 808b85f4fc4SRander Wang } 809b85f4fc4SRander Wang 810b85f4fc4SRander Wang dev_dbg(scomp->dev, "SRC sink rate %d\n", src->sink_rate); 811b85f4fc4SRander Wang 812b85f4fc4SRander Wang ret = sof_ipc4_widget_setup_msg(swidget, &src->msg); 813b85f4fc4SRander Wang if (ret) 814b85f4fc4SRander Wang goto err; 815b85f4fc4SRander Wang 816b85f4fc4SRander Wang return 0; 817b85f4fc4SRander Wang err: 818b85f4fc4SRander Wang sof_ipc4_free_audio_fmt(&src->available_fmt); 819b85f4fc4SRander Wang kfree(src); 820b85f4fc4SRander Wang swidget->private = NULL; 821b85f4fc4SRander Wang return ret; 822b85f4fc4SRander Wang } 823b85f4fc4SRander Wang 824b85f4fc4SRander Wang static void sof_ipc4_widget_free_comp_src(struct snd_sof_widget *swidget) 825b85f4fc4SRander Wang { 826b85f4fc4SRander Wang struct sof_ipc4_src *src = swidget->private; 827b85f4fc4SRander Wang 828b85f4fc4SRander Wang if (!src) 829b85f4fc4SRander Wang return; 830b85f4fc4SRander Wang 831b85f4fc4SRander Wang sof_ipc4_free_audio_fmt(&src->available_fmt); 832b85f4fc4SRander Wang kfree(swidget->private); 833b85f4fc4SRander Wang swidget->private = NULL; 834b85f4fc4SRander Wang } 835b85f4fc4SRander Wang 836dc4fc0aeSLibin Yang static void sof_ipc4_widget_free_comp_mixer(struct snd_sof_widget *swidget) 837dc4fc0aeSLibin Yang { 838dc4fc0aeSLibin Yang struct sof_ipc4_mixer *mixer = swidget->private; 839dc4fc0aeSLibin Yang 840dc4fc0aeSLibin Yang if (!mixer) 841dc4fc0aeSLibin Yang return; 842dc4fc0aeSLibin Yang 843dc4fc0aeSLibin Yang sof_ipc4_free_audio_fmt(&mixer->available_fmt); 844dc4fc0aeSLibin Yang kfree(swidget->private); 845dc4fc0aeSLibin Yang swidget->private = NULL; 846dc4fc0aeSLibin Yang } 847dc4fc0aeSLibin Yang 8487711a2bbSLibin Yang /* 8497711a2bbSLibin Yang * Add the process modules support. The process modules are defined as snd_soc_dapm_effect modules. 8507711a2bbSLibin Yang */ 8517711a2bbSLibin Yang static int sof_ipc4_widget_setup_comp_process(struct snd_sof_widget *swidget) 8527711a2bbSLibin Yang { 8537711a2bbSLibin Yang struct snd_soc_component *scomp = swidget->scomp; 854f9efae95SRanjani Sridharan struct sof_ipc4_fw_module *fw_module; 8557711a2bbSLibin Yang struct sof_ipc4_process *process; 8567711a2bbSLibin Yang void *cfg; 8577711a2bbSLibin Yang int ret; 8587711a2bbSLibin Yang 8597711a2bbSLibin Yang process = kzalloc(sizeof(*process), GFP_KERNEL); 8607711a2bbSLibin Yang if (!process) 8617711a2bbSLibin Yang return -ENOMEM; 8627711a2bbSLibin Yang 8637711a2bbSLibin Yang swidget->private = process; 8647711a2bbSLibin Yang 8657711a2bbSLibin Yang ret = sof_ipc4_get_audio_fmt(scomp, swidget, &process->available_fmt, 8667711a2bbSLibin Yang &process->base_config); 8677711a2bbSLibin Yang if (ret) 8687711a2bbSLibin Yang goto err; 8697711a2bbSLibin Yang 870f9efae95SRanjani Sridharan ret = sof_ipc4_widget_setup_msg(swidget, &process->msg); 871f9efae95SRanjani Sridharan if (ret) 872f9efae95SRanjani Sridharan goto err; 8737711a2bbSLibin Yang 874f9efae95SRanjani Sridharan /* parse process init module payload config type from module info */ 875f9efae95SRanjani Sridharan fw_module = swidget->module_info; 876f9efae95SRanjani Sridharan process->init_config = FIELD_GET(SOF_IPC4_MODULE_INIT_CONFIG_MASK, 877f9efae95SRanjani Sridharan fw_module->man4_module_entry.type); 878f9efae95SRanjani Sridharan 879f9efae95SRanjani Sridharan process->ipc_config_size = sizeof(struct sof_ipc4_base_module_cfg); 880f9efae95SRanjani Sridharan 881f9efae95SRanjani Sridharan /* allocate memory for base config extension if needed */ 882f9efae95SRanjani Sridharan if (process->init_config == SOF_IPC4_MODULE_INIT_CONFIG_TYPE_BASE_CFG_WITH_EXT) { 883f9efae95SRanjani Sridharan struct sof_ipc4_base_module_cfg_ext *base_cfg_ext; 884f9efae95SRanjani Sridharan u32 ext_size = struct_size(base_cfg_ext, pin_formats, 885f9efae95SRanjani Sridharan swidget->num_input_pins + swidget->num_output_pins); 886f9efae95SRanjani Sridharan 887f9efae95SRanjani Sridharan base_cfg_ext = kzalloc(ext_size, GFP_KERNEL); 888f9efae95SRanjani Sridharan if (!base_cfg_ext) { 8897711a2bbSLibin Yang ret = -ENOMEM; 8907711a2bbSLibin Yang goto free_available_fmt; 8917711a2bbSLibin Yang } 8927711a2bbSLibin Yang 893f9efae95SRanjani Sridharan base_cfg_ext->num_input_pin_fmts = swidget->num_input_pins; 894f9efae95SRanjani Sridharan base_cfg_ext->num_output_pin_fmts = swidget->num_output_pins; 895f9efae95SRanjani Sridharan process->base_config_ext = base_cfg_ext; 896f9efae95SRanjani Sridharan process->base_config_ext_size = ext_size; 897f9efae95SRanjani Sridharan process->ipc_config_size += ext_size; 898f9efae95SRanjani Sridharan } 899f9efae95SRanjani Sridharan 900f9efae95SRanjani Sridharan cfg = kzalloc(process->ipc_config_size, GFP_KERNEL); 901f9efae95SRanjani Sridharan if (!cfg) { 902f9efae95SRanjani Sridharan ret = -ENOMEM; 903f9efae95SRanjani Sridharan goto free_base_cfg_ext; 904f9efae95SRanjani Sridharan } 905f9efae95SRanjani Sridharan 9067711a2bbSLibin Yang process->ipc_config_data = cfg; 9077711a2bbSLibin Yang 9087711a2bbSLibin Yang sof_ipc4_widget_update_kcontrol_module_id(swidget); 9097711a2bbSLibin Yang 9107711a2bbSLibin Yang return 0; 911f9efae95SRanjani Sridharan free_base_cfg_ext: 912f9efae95SRanjani Sridharan kfree(process->base_config_ext); 913f9efae95SRanjani Sridharan process->base_config_ext = NULL; 9147711a2bbSLibin Yang free_available_fmt: 9157711a2bbSLibin Yang sof_ipc4_free_audio_fmt(&process->available_fmt); 9167711a2bbSLibin Yang err: 9177711a2bbSLibin Yang kfree(process); 9187711a2bbSLibin Yang swidget->private = NULL; 9197711a2bbSLibin Yang return ret; 9207711a2bbSLibin Yang } 9217711a2bbSLibin Yang 9227711a2bbSLibin Yang static void sof_ipc4_widget_free_comp_process(struct snd_sof_widget *swidget) 9237711a2bbSLibin Yang { 9247711a2bbSLibin Yang struct sof_ipc4_process *process = swidget->private; 9257711a2bbSLibin Yang 9267711a2bbSLibin Yang if (!process) 9277711a2bbSLibin Yang return; 9287711a2bbSLibin Yang 9297711a2bbSLibin Yang kfree(process->ipc_config_data); 930f9efae95SRanjani Sridharan kfree(process->base_config_ext); 9317711a2bbSLibin Yang sof_ipc4_free_audio_fmt(&process->available_fmt); 9327711a2bbSLibin Yang kfree(swidget->private); 9337711a2bbSLibin Yang swidget->private = NULL; 9347711a2bbSLibin Yang } 9357711a2bbSLibin Yang 936904c48c4SRanjani Sridharan static void 93719c745d1SPeter Ujfalusi sof_ipc4_update_resource_usage(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget, 938904c48c4SRanjani Sridharan struct sof_ipc4_base_module_cfg *base_config) 939904c48c4SRanjani Sridharan { 940904c48c4SRanjani Sridharan struct sof_ipc4_fw_module *fw_module = swidget->module_info; 941904c48c4SRanjani Sridharan struct snd_sof_widget *pipe_widget; 942904c48c4SRanjani Sridharan struct sof_ipc4_pipeline *pipeline; 943904c48c4SRanjani Sridharan int task_mem, queue_mem; 944904c48c4SRanjani Sridharan int ibs, bss, total; 945904c48c4SRanjani Sridharan 946904c48c4SRanjani Sridharan ibs = base_config->ibs; 947904c48c4SRanjani Sridharan bss = base_config->is_pages; 948904c48c4SRanjani Sridharan 949904c48c4SRanjani Sridharan task_mem = SOF_IPC4_PIPELINE_OBJECT_SIZE; 950904c48c4SRanjani Sridharan task_mem += SOF_IPC4_MODULE_INSTANCE_LIST_ITEM_SIZE + bss; 951904c48c4SRanjani Sridharan 952904c48c4SRanjani Sridharan if (fw_module->man4_module_entry.type & SOF_IPC4_MODULE_LL) { 953904c48c4SRanjani Sridharan task_mem += SOF_IPC4_FW_ROUNDUP(SOF_IPC4_LL_TASK_OBJECT_SIZE); 954904c48c4SRanjani Sridharan task_mem += SOF_IPC4_FW_MAX_QUEUE_COUNT * SOF_IPC4_MODULE_INSTANCE_LIST_ITEM_SIZE; 955904c48c4SRanjani Sridharan task_mem += SOF_IPC4_LL_TASK_LIST_ITEM_SIZE; 956904c48c4SRanjani Sridharan } else { 957904c48c4SRanjani Sridharan task_mem += SOF_IPC4_FW_ROUNDUP(SOF_IPC4_DP_TASK_OBJECT_SIZE); 958904c48c4SRanjani Sridharan task_mem += SOF_IPC4_DP_TASK_LIST_SIZE; 959904c48c4SRanjani Sridharan } 960904c48c4SRanjani Sridharan 961904c48c4SRanjani Sridharan ibs = SOF_IPC4_FW_ROUNDUP(ibs); 962904c48c4SRanjani Sridharan queue_mem = SOF_IPC4_FW_MAX_QUEUE_COUNT * (SOF_IPC4_DATA_QUEUE_OBJECT_SIZE + ibs); 963904c48c4SRanjani Sridharan 964904c48c4SRanjani Sridharan total = SOF_IPC4_FW_PAGE(task_mem + queue_mem); 965904c48c4SRanjani Sridharan 9669c04363dSRanjani Sridharan pipe_widget = swidget->spipe->pipe_widget; 967904c48c4SRanjani Sridharan pipeline = pipe_widget->private; 968904c48c4SRanjani Sridharan pipeline->mem_usage += total; 969d8a2c987SPeter Ujfalusi 970d8a2c987SPeter Ujfalusi /* Update base_config->cpc from the module manifest */ 971d8a2c987SPeter Ujfalusi sof_ipc4_update_cpc_from_manifest(sdev, fw_module, base_config); 972d8a2c987SPeter Ujfalusi 973d8a2c987SPeter Ujfalusi dev_dbg(sdev->dev, "%s: ibs / obs / cpc: %u / %u / %u\n", 974d8a2c987SPeter Ujfalusi swidget->widget->name, base_config->ibs, base_config->obs, 975d8a2c987SPeter Ujfalusi base_config->cpc); 976904c48c4SRanjani Sridharan } 977904c48c4SRanjani Sridharan 978904c48c4SRanjani Sridharan static int sof_ipc4_widget_assign_instance_id(struct snd_sof_dev *sdev, 979904c48c4SRanjani Sridharan struct snd_sof_widget *swidget) 980904c48c4SRanjani Sridharan { 981904c48c4SRanjani Sridharan struct sof_ipc4_fw_module *fw_module = swidget->module_info; 982904c48c4SRanjani Sridharan int max_instances = fw_module->man4_module_entry.instance_max_count; 983904c48c4SRanjani Sridharan 984904c48c4SRanjani Sridharan swidget->instance_id = ida_alloc_max(&fw_module->m_ida, max_instances, GFP_KERNEL); 985904c48c4SRanjani Sridharan if (swidget->instance_id < 0) { 986904c48c4SRanjani Sridharan dev_err(sdev->dev, "failed to assign instance id for widget %s", 987904c48c4SRanjani Sridharan swidget->widget->name); 988904c48c4SRanjani Sridharan return swidget->instance_id; 989904c48c4SRanjani Sridharan } 990904c48c4SRanjani Sridharan 991904c48c4SRanjani Sridharan return 0; 992904c48c4SRanjani Sridharan } 993904c48c4SRanjani Sridharan 994811a742fSLibin Yang /* update hw_params based on the audio stream format */ 995811a742fSLibin Yang static int sof_ipc4_update_hw_params(struct snd_sof_dev *sdev, struct snd_pcm_hw_params *params, 996811a742fSLibin Yang struct sof_ipc4_audio_format *fmt) 997811a742fSLibin Yang { 998811a742fSLibin Yang snd_pcm_format_t snd_fmt; 999811a742fSLibin Yang struct snd_interval *i; 1000811a742fSLibin Yang struct snd_mask *m; 1001811a742fSLibin Yang int valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg); 1002811a742fSLibin Yang unsigned int channels, rate; 1003811a742fSLibin Yang 1004811a742fSLibin Yang switch (valid_bits) { 1005811a742fSLibin Yang case 16: 1006811a742fSLibin Yang snd_fmt = SNDRV_PCM_FORMAT_S16_LE; 1007811a742fSLibin Yang break; 1008811a742fSLibin Yang case 24: 1009811a742fSLibin Yang snd_fmt = SNDRV_PCM_FORMAT_S24_LE; 1010811a742fSLibin Yang break; 1011811a742fSLibin Yang case 32: 1012811a742fSLibin Yang snd_fmt = SNDRV_PCM_FORMAT_S32_LE; 1013811a742fSLibin Yang break; 1014811a742fSLibin Yang default: 1015811a742fSLibin Yang dev_err(sdev->dev, "invalid PCM valid_bits %d\n", valid_bits); 1016811a742fSLibin Yang return -EINVAL; 1017811a742fSLibin Yang } 1018811a742fSLibin Yang 1019811a742fSLibin Yang m = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); 1020811a742fSLibin Yang snd_mask_none(m); 1021811a742fSLibin Yang snd_mask_set_format(m, snd_fmt); 1022811a742fSLibin Yang 1023811a742fSLibin Yang rate = fmt->sampling_frequency; 1024811a742fSLibin Yang i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); 1025811a742fSLibin Yang i->min = rate; 1026811a742fSLibin Yang i->max = rate; 1027811a742fSLibin Yang 1028811a742fSLibin Yang channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg); 1029811a742fSLibin Yang i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); 1030811a742fSLibin Yang i->min = channels; 1031811a742fSLibin Yang i->max = channels; 1032811a742fSLibin Yang 1033811a742fSLibin Yang return 0; 1034811a742fSLibin Yang } 1035811a742fSLibin Yang 1036f37b702cSRanjani Sridharan static bool sof_ipc4_is_single_format(struct snd_sof_dev *sdev, 10374fdef47aSRanjani Sridharan struct sof_ipc4_pin_format *pin_fmts, u32 pin_fmts_size) 1038904c48c4SRanjani Sridharan { 1039f37b702cSRanjani Sridharan struct sof_ipc4_audio_format *fmt; 1040f37b702cSRanjani Sridharan u32 rate, channels, valid_bits; 1041904c48c4SRanjani Sridharan int i; 1042904c48c4SRanjani Sridharan 1043f37b702cSRanjani Sridharan fmt = &pin_fmts[0].audio_fmt; 1044f37b702cSRanjani Sridharan rate = fmt->sampling_frequency; 1045f37b702cSRanjani Sridharan channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg); 1046f37b702cSRanjani Sridharan valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg); 1047f37b702cSRanjani Sridharan 1048f37b702cSRanjani Sridharan /* check if all output formats in topology are the same */ 1049f37b702cSRanjani Sridharan for (i = 1; i < pin_fmts_size; i++) { 1050f37b702cSRanjani Sridharan u32 _rate, _channels, _valid_bits; 1051f37b702cSRanjani Sridharan 1052f37b702cSRanjani Sridharan fmt = &pin_fmts[i].audio_fmt; 1053f37b702cSRanjani Sridharan _rate = fmt->sampling_frequency; 1054f37b702cSRanjani Sridharan _channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg); 1055f37b702cSRanjani Sridharan _valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg); 1056f37b702cSRanjani Sridharan 1057f37b702cSRanjani Sridharan if (_rate != rate || _channels != channels || _valid_bits != valid_bits) 1058f37b702cSRanjani Sridharan return false; 1059f37b702cSRanjani Sridharan } 1060f37b702cSRanjani Sridharan 1061f37b702cSRanjani Sridharan return true; 1062f37b702cSRanjani Sridharan } 1063f37b702cSRanjani Sridharan 1064523042f6SRanjani Sridharan static int sof_ipc4_init_output_audio_fmt(struct snd_sof_dev *sdev, 1065523042f6SRanjani Sridharan struct sof_ipc4_base_module_cfg *base_config, 1066523042f6SRanjani Sridharan struct sof_ipc4_available_audio_format *available_fmt, 10671af13f22SRanjani Sridharan u32 out_ref_rate, u32 out_ref_channels, 10681af13f22SRanjani Sridharan u32 out_ref_valid_bits) 1069523042f6SRanjani Sridharan { 1070f1ceebdbSRanjani Sridharan struct sof_ipc4_audio_format *out_fmt; 1071f37b702cSRanjani Sridharan bool single_format; 1072523042f6SRanjani Sridharan int i; 1073523042f6SRanjani Sridharan 1074f1ceebdbSRanjani Sridharan if (!available_fmt->num_output_formats) 1075f1ceebdbSRanjani Sridharan return -EINVAL; 1076f1ceebdbSRanjani Sridharan 1077f37b702cSRanjani Sridharan single_format = sof_ipc4_is_single_format(sdev, available_fmt->output_pin_fmts, 1078f37b702cSRanjani Sridharan available_fmt->num_output_formats); 1079f1ceebdbSRanjani Sridharan 1080f1ceebdbSRanjani Sridharan /* pick the first format if there's only one available or if all formats are the same */ 10811af13f22SRanjani Sridharan if (single_format) { 10821af13f22SRanjani Sridharan base_config->obs = available_fmt->output_pin_fmts[0].buffer_size; 10831af13f22SRanjani Sridharan return 0; 10841af13f22SRanjani Sridharan } 1085523042f6SRanjani Sridharan 10861af13f22SRanjani Sridharan /* 10871af13f22SRanjani Sridharan * if there are multiple output formats, then choose the output format that matches 10881af13f22SRanjani Sridharan * the reference params 10891af13f22SRanjani Sridharan */ 10901af13f22SRanjani Sridharan for (i = 0; i < available_fmt->num_output_formats; i++) { 10911af13f22SRanjani Sridharan u32 _out_rate, _out_channels, _out_valid_bits; 10921af13f22SRanjani Sridharan 10931af13f22SRanjani Sridharan out_fmt = &available_fmt->output_pin_fmts[i].audio_fmt; 10941af13f22SRanjani Sridharan _out_rate = out_fmt->sampling_frequency; 10951af13f22SRanjani Sridharan _out_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(out_fmt->fmt_cfg); 10961af13f22SRanjani Sridharan _out_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(out_fmt->fmt_cfg); 10971af13f22SRanjani Sridharan 10981af13f22SRanjani Sridharan if (_out_rate == out_ref_rate && _out_channels == out_ref_channels && 10991af13f22SRanjani Sridharan _out_valid_bits == out_ref_valid_bits) { 1100523042f6SRanjani Sridharan base_config->obs = available_fmt->output_pin_fmts[i].buffer_size; 1101523042f6SRanjani Sridharan return i; 1102523042f6SRanjani Sridharan } 11031af13f22SRanjani Sridharan } 11041af13f22SRanjani Sridharan 1105904c48c4SRanjani Sridharan return -EINVAL; 1106904c48c4SRanjani Sridharan } 1107904c48c4SRanjani Sridharan 110835171c1aSRanjani Sridharan static int sof_ipc4_get_valid_bits(struct snd_sof_dev *sdev, struct snd_pcm_hw_params *params) 110935171c1aSRanjani Sridharan { 1110904c48c4SRanjani Sridharan switch (params_format(params)) { 1111904c48c4SRanjani Sridharan case SNDRV_PCM_FORMAT_S16_LE: 111235171c1aSRanjani Sridharan return 16; 1113904c48c4SRanjani Sridharan case SNDRV_PCM_FORMAT_S24_LE: 111435171c1aSRanjani Sridharan return 24; 1115904c48c4SRanjani Sridharan case SNDRV_PCM_FORMAT_S32_LE: 111635171c1aSRanjani Sridharan return 32; 1117904c48c4SRanjani Sridharan default: 1118904c48c4SRanjani Sridharan dev_err(sdev->dev, "invalid pcm frame format %d\n", params_format(params)); 1119904c48c4SRanjani Sridharan return -EINVAL; 1120904c48c4SRanjani Sridharan } 112135171c1aSRanjani Sridharan } 1122904c48c4SRanjani Sridharan 1123ae45aebeSRanjani Sridharan static int sof_ipc4_init_input_audio_fmt(struct snd_sof_dev *sdev, 1124904c48c4SRanjani Sridharan struct snd_sof_widget *swidget, 1125904c48c4SRanjani Sridharan struct sof_ipc4_base_module_cfg *base_config, 1126904c48c4SRanjani Sridharan struct snd_pcm_hw_params *params, 11275a56c533SRanjani Sridharan struct sof_ipc4_available_audio_format *available_fmt) 1128904c48c4SRanjani Sridharan { 11295a56c533SRanjani Sridharan struct sof_ipc4_pin_format *pin_fmts = available_fmt->input_pin_fmts; 11305a56c533SRanjani Sridharan u32 pin_fmts_size = available_fmt->num_input_formats; 1131904c48c4SRanjani Sridharan u32 valid_bits; 1132904c48c4SRanjani Sridharan u32 channels; 1133904c48c4SRanjani Sridharan u32 rate; 11345a56c533SRanjani Sridharan bool single_format; 1135904c48c4SRanjani Sridharan int sample_valid_bits; 11364c7873d6SRanjani Sridharan int i = 0; 1137904c48c4SRanjani Sridharan 11385a56c533SRanjani Sridharan if (!available_fmt->num_input_formats) { 11395a56c533SRanjani Sridharan dev_err(sdev->dev, "no input formats for %s\n", swidget->widget->name); 1140904c48c4SRanjani Sridharan return -EINVAL; 1141904c48c4SRanjani Sridharan } 1142904c48c4SRanjani Sridharan 11435a56c533SRanjani Sridharan single_format = sof_ipc4_is_single_format(sdev, available_fmt->input_pin_fmts, 11445a56c533SRanjani Sridharan available_fmt->num_input_formats); 11455a56c533SRanjani Sridharan if (single_format) 11465a56c533SRanjani Sridharan goto in_fmt; 11475a56c533SRanjani Sridharan 114835171c1aSRanjani Sridharan sample_valid_bits = sof_ipc4_get_valid_bits(sdev, params); 114935171c1aSRanjani Sridharan if (sample_valid_bits < 0) 115035171c1aSRanjani Sridharan return sample_valid_bits; 1151904c48c4SRanjani Sridharan 1152904c48c4SRanjani Sridharan /* 11535a56c533SRanjani Sridharan * Search supported input audio formats with pin index 0 to match rate, channels and 11545a56c533SRanjani Sridharan * sample_valid_bits from reference params 1155904c48c4SRanjani Sridharan */ 11564fdef47aSRanjani Sridharan for (i = 0; i < pin_fmts_size; i++) { 1157f534a94cSRanjani Sridharan struct sof_ipc4_audio_format *fmt = &pin_fmts[i].audio_fmt; 11587ab6b1e8SRanjani Sridharan 1159ad70f2f0SRanjani Sridharan if (pin_fmts[i].pin_index) 1160ad70f2f0SRanjani Sridharan continue; 1161904c48c4SRanjani Sridharan 1162904c48c4SRanjani Sridharan rate = fmt->sampling_frequency; 1163904c48c4SRanjani Sridharan channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg); 1164904c48c4SRanjani Sridharan valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg); 1165904c48c4SRanjani Sridharan if (params_rate(params) == rate && params_channels(params) == channels && 1166904c48c4SRanjani Sridharan sample_valid_bits == valid_bits) { 1167e63a73f9SRanjani Sridharan dev_dbg(sdev->dev, "matched audio format index for %uHz, %ubit, %u channels: %d\n", 11683809264bSPierre-Louis Bossart rate, valid_bits, channels, i); 1169904c48c4SRanjani Sridharan break; 1170904c48c4SRanjani Sridharan } 1171904c48c4SRanjani Sridharan } 1172904c48c4SRanjani Sridharan 11734fdef47aSRanjani Sridharan if (i == pin_fmts_size) { 1174904c48c4SRanjani Sridharan dev_err(sdev->dev, "%s: Unsupported audio format: %uHz, %ubit, %u channels\n", 1175904c48c4SRanjani Sridharan __func__, params_rate(params), sample_valid_bits, params_channels(params)); 1176904c48c4SRanjani Sridharan return -EINVAL; 1177904c48c4SRanjani Sridharan } 1178904c48c4SRanjani Sridharan 11794c7873d6SRanjani Sridharan in_fmt: 1180e63a73f9SRanjani Sridharan /* copy input format */ 11814fdef47aSRanjani Sridharan if (available_fmt->num_input_formats && i < available_fmt->num_input_formats) { 11827ab6b1e8SRanjani Sridharan memcpy(&base_config->audio_fmt, &available_fmt->input_pin_fmts[i].audio_fmt, 11839c560549SRanjani Sridharan sizeof(struct sof_ipc4_audio_format)); 1184e63a73f9SRanjani Sridharan 1185e63a73f9SRanjani Sridharan /* set base_cfg ibs/obs */ 11867ab6b1e8SRanjani Sridharan base_config->ibs = available_fmt->input_pin_fmts[i].buffer_size; 1187e63a73f9SRanjani Sridharan 1188904c48c4SRanjani Sridharan dev_dbg(sdev->dev, "Init input audio formats for %s\n", swidget->widget->name); 11897ab6b1e8SRanjani Sridharan sof_ipc4_dbg_audio_format(sdev->dev, &available_fmt->input_pin_fmts[i], 1); 1190904c48c4SRanjani Sridharan } 1191904c48c4SRanjani Sridharan 1192904c48c4SRanjani Sridharan return i; 1193904c48c4SRanjani Sridharan } 1194904c48c4SRanjani Sridharan 1195904c48c4SRanjani Sridharan static void sof_ipc4_unprepare_copier_module(struct snd_sof_widget *swidget) 1196904c48c4SRanjani Sridharan { 1197904c48c4SRanjani Sridharan struct sof_ipc4_copier *ipc4_copier = NULL; 1198904c48c4SRanjani Sridharan struct snd_sof_widget *pipe_widget; 1199904c48c4SRanjani Sridharan struct sof_ipc4_pipeline *pipeline; 1200904c48c4SRanjani Sridharan 1201904c48c4SRanjani Sridharan /* reset pipeline memory usage */ 12029c04363dSRanjani Sridharan pipe_widget = swidget->spipe->pipe_widget; 1203904c48c4SRanjani Sridharan pipeline = pipe_widget->private; 1204904c48c4SRanjani Sridharan pipeline->mem_usage = 0; 1205904c48c4SRanjani Sridharan 12067d573425SBard Liao if (WIDGET_IS_AIF(swidget->id) || swidget->id == snd_soc_dapm_buffer) { 1207ca5ce0caSJyri Sarha if (pipeline->use_chain_dma) { 1208ca5ce0caSJyri Sarha pipeline->msg.primary = 0; 1209ca5ce0caSJyri Sarha pipeline->msg.extension = 0; 1210ca5ce0caSJyri Sarha } 1211904c48c4SRanjani Sridharan ipc4_copier = swidget->private; 1212acf52594SRanjani Sridharan } else if (WIDGET_IS_DAI(swidget->id)) { 1213acf52594SRanjani Sridharan struct snd_sof_dai *dai = swidget->private; 1214acf52594SRanjani Sridharan 1215acf52594SRanjani Sridharan ipc4_copier = dai->private; 1216ca5ce0caSJyri Sarha 1217ca5ce0caSJyri Sarha if (pipeline->use_chain_dma) { 1218ca5ce0caSJyri Sarha pipeline->msg.primary = 0; 1219ca5ce0caSJyri Sarha pipeline->msg.extension = 0; 1220ca5ce0caSJyri Sarha } 1221ca5ce0caSJyri Sarha 1222a150345aSBard Liao if (ipc4_copier->dai_type == SOF_DAI_INTEL_ALH) { 1223b66bfc3aSRanjani Sridharan struct sof_ipc4_copier_data *copier_data = &ipc4_copier->data; 1224a150345aSBard Liao struct sof_ipc4_alh_configuration_blob *blob; 1225a150345aSBard Liao unsigned int group_id; 1226a150345aSBard Liao 1227a150345aSBard Liao blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config; 1228e186e1f2SPierre-Louis Bossart if (blob->alh_cfg.device_count > 1) { 1229a150345aSBard Liao group_id = SOF_IPC4_NODE_INDEX(ipc4_copier->data.gtw_cfg.node_id) - 1230a150345aSBard Liao ALH_MULTI_GTW_BASE; 1231a150345aSBard Liao ida_free(&alh_group_ida, group_id); 1232a150345aSBard Liao } 1233b66bfc3aSRanjani Sridharan 1234b66bfc3aSRanjani Sridharan /* clear the node ID */ 1235b66bfc3aSRanjani Sridharan copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK; 1236a150345aSBard Liao } 1237acf52594SRanjani Sridharan } 1238904c48c4SRanjani Sridharan 1239904c48c4SRanjani Sridharan if (ipc4_copier) { 1240904c48c4SRanjani Sridharan kfree(ipc4_copier->ipc_config_data); 1241904c48c4SRanjani Sridharan ipc4_copier->ipc_config_data = NULL; 1242904c48c4SRanjani Sridharan ipc4_copier->ipc_config_size = 0; 1243904c48c4SRanjani Sridharan } 1244904c48c4SRanjani Sridharan } 1245904c48c4SRanjani Sridharan 1246aa84ffb7SRanjani Sridharan #if IS_ENABLED(CONFIG_ACPI) && IS_ENABLED(CONFIG_SND_INTEL_NHLT) 1247aa84ffb7SRanjani Sridharan static int snd_sof_get_hw_config_params(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, 1248aa84ffb7SRanjani Sridharan int *sample_rate, int *channel_count, int *bit_depth) 1249aa84ffb7SRanjani Sridharan { 1250aa84ffb7SRanjani Sridharan struct snd_soc_tplg_hw_config *hw_config; 1251aa84ffb7SRanjani Sridharan struct snd_sof_dai_link *slink; 1252aa84ffb7SRanjani Sridharan bool dai_link_found = false; 1253aa84ffb7SRanjani Sridharan bool hw_cfg_found = false; 1254aa84ffb7SRanjani Sridharan int i; 1255aa84ffb7SRanjani Sridharan 1256aa84ffb7SRanjani Sridharan /* get current hw_config from link */ 1257aa84ffb7SRanjani Sridharan list_for_each_entry(slink, &sdev->dai_link_list, list) { 1258aa84ffb7SRanjani Sridharan if (!strcmp(slink->link->name, dai->name)) { 1259aa84ffb7SRanjani Sridharan dai_link_found = true; 1260aa84ffb7SRanjani Sridharan break; 1261aa84ffb7SRanjani Sridharan } 1262aa84ffb7SRanjani Sridharan } 1263aa84ffb7SRanjani Sridharan 1264aa84ffb7SRanjani Sridharan if (!dai_link_found) { 1265aa84ffb7SRanjani Sridharan dev_err(sdev->dev, "%s: no DAI link found for DAI %s\n", __func__, dai->name); 1266aa84ffb7SRanjani Sridharan return -EINVAL; 1267aa84ffb7SRanjani Sridharan } 1268aa84ffb7SRanjani Sridharan 1269aa84ffb7SRanjani Sridharan for (i = 0; i < slink->num_hw_configs; i++) { 1270aa84ffb7SRanjani Sridharan hw_config = &slink->hw_configs[i]; 1271aa84ffb7SRanjani Sridharan if (dai->current_config == le32_to_cpu(hw_config->id)) { 1272aa84ffb7SRanjani Sridharan hw_cfg_found = true; 1273aa84ffb7SRanjani Sridharan break; 1274aa84ffb7SRanjani Sridharan } 1275aa84ffb7SRanjani Sridharan } 1276aa84ffb7SRanjani Sridharan 1277aa84ffb7SRanjani Sridharan if (!hw_cfg_found) { 1278aa84ffb7SRanjani Sridharan dev_err(sdev->dev, "%s: no matching hw_config found for DAI %s\n", __func__, 1279aa84ffb7SRanjani Sridharan dai->name); 1280aa84ffb7SRanjani Sridharan return -EINVAL; 1281aa84ffb7SRanjani Sridharan } 1282aa84ffb7SRanjani Sridharan 1283aa84ffb7SRanjani Sridharan *bit_depth = le32_to_cpu(hw_config->tdm_slot_width); 1284aa84ffb7SRanjani Sridharan *channel_count = le32_to_cpu(hw_config->tdm_slots); 1285aa84ffb7SRanjani Sridharan *sample_rate = le32_to_cpu(hw_config->fsync_rate); 1286aa84ffb7SRanjani Sridharan 12873809264bSPierre-Louis Bossart dev_dbg(sdev->dev, "sample rate: %d sample width: %d channels: %d\n", 12883809264bSPierre-Louis Bossart *sample_rate, *bit_depth, *channel_count); 1289aa84ffb7SRanjani Sridharan 1290aa84ffb7SRanjani Sridharan return 0; 1291aa84ffb7SRanjani Sridharan } 1292aa84ffb7SRanjani Sridharan 1293aa84ffb7SRanjani Sridharan static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, 1294aa84ffb7SRanjani Sridharan struct snd_pcm_hw_params *params, u32 dai_index, 1295aa84ffb7SRanjani Sridharan u32 linktype, u8 dir, u32 **dst, u32 *len) 1296aa84ffb7SRanjani Sridharan { 1297aa84ffb7SRanjani Sridharan struct sof_ipc4_fw_data *ipc4_data = sdev->private; 1298aa84ffb7SRanjani Sridharan struct nhlt_specific_cfg *cfg; 1299aa84ffb7SRanjani Sridharan int sample_rate, channel_count; 1300aa84ffb7SRanjani Sridharan int bit_depth, ret; 1301aa84ffb7SRanjani Sridharan u32 nhlt_type; 1302aa84ffb7SRanjani Sridharan 1303aa84ffb7SRanjani Sridharan /* convert to NHLT type */ 1304aa84ffb7SRanjani Sridharan switch (linktype) { 1305aa84ffb7SRanjani Sridharan case SOF_DAI_INTEL_DMIC: 1306aa84ffb7SRanjani Sridharan nhlt_type = NHLT_LINK_DMIC; 1307aa84ffb7SRanjani Sridharan bit_depth = params_width(params); 1308aa84ffb7SRanjani Sridharan channel_count = params_channels(params); 1309aa84ffb7SRanjani Sridharan sample_rate = params_rate(params); 1310aa84ffb7SRanjani Sridharan break; 1311aa84ffb7SRanjani Sridharan case SOF_DAI_INTEL_SSP: 1312aa84ffb7SRanjani Sridharan nhlt_type = NHLT_LINK_SSP; 1313aa84ffb7SRanjani Sridharan ret = snd_sof_get_hw_config_params(sdev, dai, &sample_rate, &channel_count, 1314aa84ffb7SRanjani Sridharan &bit_depth); 1315aa84ffb7SRanjani Sridharan if (ret < 0) 1316aa84ffb7SRanjani Sridharan return ret; 1317aa84ffb7SRanjani Sridharan break; 1318aa84ffb7SRanjani Sridharan default: 1319aa84ffb7SRanjani Sridharan return 0; 1320aa84ffb7SRanjani Sridharan } 1321aa84ffb7SRanjani Sridharan 13223809264bSPierre-Louis Bossart dev_dbg(sdev->dev, "dai index %d nhlt type %d direction %d\n", 13233809264bSPierre-Louis Bossart dai_index, nhlt_type, dir); 1324aa84ffb7SRanjani Sridharan 1325aa84ffb7SRanjani Sridharan /* find NHLT blob with matching params */ 1326aa84ffb7SRanjani Sridharan cfg = intel_nhlt_get_endpoint_blob(sdev->dev, ipc4_data->nhlt, dai_index, nhlt_type, 1327aa84ffb7SRanjani Sridharan bit_depth, bit_depth, channel_count, sample_rate, 1328aa84ffb7SRanjani Sridharan dir, 0); 1329aa84ffb7SRanjani Sridharan 1330aa84ffb7SRanjani Sridharan if (!cfg) { 1331aa84ffb7SRanjani Sridharan dev_err(sdev->dev, 1332aa84ffb7SRanjani Sridharan "no matching blob for sample rate: %d sample width: %d channels: %d\n", 1333aa84ffb7SRanjani Sridharan sample_rate, bit_depth, channel_count); 1334aa84ffb7SRanjani Sridharan return -EINVAL; 1335aa84ffb7SRanjani Sridharan } 1336aa84ffb7SRanjani Sridharan 1337aa84ffb7SRanjani Sridharan /* config length should be in dwords */ 1338aa84ffb7SRanjani Sridharan *len = cfg->size >> 2; 1339aa84ffb7SRanjani Sridharan *dst = (u32 *)cfg->caps; 1340aa84ffb7SRanjani Sridharan 1341aa84ffb7SRanjani Sridharan return 0; 1342aa84ffb7SRanjani Sridharan } 1343aa84ffb7SRanjani Sridharan #else 1344aa84ffb7SRanjani Sridharan static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, 1345aa84ffb7SRanjani Sridharan struct snd_pcm_hw_params *params, u32 dai_index, 1346aa84ffb7SRanjani Sridharan u32 linktype, u8 dir, u32 **dst, u32 *len) 1347aa84ffb7SRanjani Sridharan { 1348aa84ffb7SRanjani Sridharan return 0; 1349aa84ffb7SRanjani Sridharan } 1350aa84ffb7SRanjani Sridharan #endif 1351aa84ffb7SRanjani Sridharan 1352279e52d6SKai Vehmanen static int ipc4_set_fmt_mask(struct snd_mask *fmt, unsigned int bit_depth) 1353279e52d6SKai Vehmanen { 1354279e52d6SKai Vehmanen switch (bit_depth) { 1355279e52d6SKai Vehmanen case 16: 1356279e52d6SKai Vehmanen snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE); 1357279e52d6SKai Vehmanen break; 1358279e52d6SKai Vehmanen case 24: 1359279e52d6SKai Vehmanen snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); 1360279e52d6SKai Vehmanen break; 1361279e52d6SKai Vehmanen case 32: 1362279e52d6SKai Vehmanen snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE); 1363279e52d6SKai Vehmanen break; 1364279e52d6SKai Vehmanen default: 1365279e52d6SKai Vehmanen return -EINVAL; 1366279e52d6SKai Vehmanen } 1367279e52d6SKai Vehmanen 1368279e52d6SKai Vehmanen return 0; 1369279e52d6SKai Vehmanen } 1370279e52d6SKai Vehmanen 1371904c48c4SRanjani Sridharan static int 1372904c48c4SRanjani Sridharan sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, 1373904c48c4SRanjani Sridharan struct snd_pcm_hw_params *fe_params, 1374904c48c4SRanjani Sridharan struct snd_sof_platform_stream_params *platform_params, 1375904c48c4SRanjani Sridharan struct snd_pcm_hw_params *pipeline_params, int dir) 1376904c48c4SRanjani Sridharan { 1377904c48c4SRanjani Sridharan struct sof_ipc4_available_audio_format *available_fmt; 1378904c48c4SRanjani Sridharan struct snd_soc_component *scomp = swidget->scomp; 1379904c48c4SRanjani Sridharan struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 1380904c48c4SRanjani Sridharan struct sof_ipc4_copier_data *copier_data; 1381904c48c4SRanjani Sridharan struct snd_pcm_hw_params *ref_params; 1382904c48c4SRanjani Sridharan struct sof_ipc4_copier *ipc4_copier; 1383a150345aSBard Liao struct snd_sof_dai *dai; 1384904c48c4SRanjani Sridharan struct snd_mask *fmt; 1385904c48c4SRanjani Sridharan int out_sample_valid_bits; 1386a0659f81SPierre-Louis Bossart u32 gtw_cfg_config_length; 1387a0659f81SPierre-Louis Bossart u32 dma_config_tlv_size = 0; 1388904c48c4SRanjani Sridharan void **ipc_config_data; 1389904c48c4SRanjani Sridharan int *ipc_config_size; 1390904c48c4SRanjani Sridharan u32 **data; 1391fcbc3aacSYang Li int ipc_size, ret, out_ref_valid_bits; 1392fcbc3aacSYang Li u32 out_ref_rate, out_ref_channels; 1393594c1bb9SRanjani Sridharan u32 deep_buffer_dma_ms = 0; 1394a2e07c33SRanjani Sridharan int output_fmt_index; 1395904c48c4SRanjani Sridharan 13963809264bSPierre-Louis Bossart dev_dbg(sdev->dev, "copier %s, type %d", swidget->widget->name, swidget->id); 1397904c48c4SRanjani Sridharan 1398904c48c4SRanjani Sridharan switch (swidget->id) { 1399904c48c4SRanjani Sridharan case snd_soc_dapm_aif_in: 1400904c48c4SRanjani Sridharan case snd_soc_dapm_aif_out: 1401904c48c4SRanjani Sridharan { 1402904c48c4SRanjani Sridharan struct sof_ipc4_gtw_attributes *gtw_attr; 1403904c48c4SRanjani Sridharan struct snd_sof_widget *pipe_widget; 1404904c48c4SRanjani Sridharan struct sof_ipc4_pipeline *pipeline; 1405904c48c4SRanjani Sridharan 1406594c1bb9SRanjani Sridharan /* parse the deep buffer dma size */ 1407594c1bb9SRanjani Sridharan ret = sof_update_ipc_object(scomp, &deep_buffer_dma_ms, 1408594c1bb9SRanjani Sridharan SOF_COPIER_DEEP_BUFFER_TOKENS, swidget->tuples, 1409594c1bb9SRanjani Sridharan swidget->num_tuples, sizeof(u32), 1); 1410594c1bb9SRanjani Sridharan if (ret) { 1411594c1bb9SRanjani Sridharan dev_err(scomp->dev, "Failed to parse deep buffer dma size for %s\n", 1412594c1bb9SRanjani Sridharan swidget->widget->name); 1413594c1bb9SRanjani Sridharan return ret; 1414594c1bb9SRanjani Sridharan } 1415594c1bb9SRanjani Sridharan 1416904c48c4SRanjani Sridharan ipc4_copier = (struct sof_ipc4_copier *)swidget->private; 1417904c48c4SRanjani Sridharan gtw_attr = ipc4_copier->gtw_attr; 1418904c48c4SRanjani Sridharan copier_data = &ipc4_copier->data; 1419904c48c4SRanjani Sridharan available_fmt = &ipc4_copier->available_fmt; 1420904c48c4SRanjani Sridharan 1421ca5ce0caSJyri Sarha pipe_widget = swidget->spipe->pipe_widget; 1422ca5ce0caSJyri Sarha pipeline = pipe_widget->private; 1423ca5ce0caSJyri Sarha 1424ca5ce0caSJyri Sarha if (pipeline->use_chain_dma) { 1425ca5ce0caSJyri Sarha u32 host_dma_id; 1426ca5ce0caSJyri Sarha u32 fifo_size; 1427ca5ce0caSJyri Sarha 1428ca5ce0caSJyri Sarha host_dma_id = platform_params->stream_tag - 1; 1429ca5ce0caSJyri Sarha pipeline->msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_HOST_ID(host_dma_id); 1430ca5ce0caSJyri Sarha 1431ca5ce0caSJyri Sarha /* Set SCS bit for S16_LE format only */ 1432ca5ce0caSJyri Sarha if (params_format(fe_params) == SNDRV_PCM_FORMAT_S16_LE) 1433ca5ce0caSJyri Sarha pipeline->msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_SCS_MASK; 1434ca5ce0caSJyri Sarha 1435904c48c4SRanjani Sridharan /* 1436ca5ce0caSJyri Sarha * Despite its name the bitfield 'fifo_size' is used to define DMA buffer 1437ca5ce0caSJyri Sarha * size. The expression calculates 2ms buffer size. 1438ca5ce0caSJyri Sarha */ 1439ca5ce0caSJyri Sarha fifo_size = DIV_ROUND_UP((SOF_IPC4_CHAIN_DMA_BUF_SIZE_MS * 1440ca5ce0caSJyri Sarha params_rate(fe_params) * 1441ca5ce0caSJyri Sarha params_channels(fe_params) * 1442ca5ce0caSJyri Sarha params_physical_width(fe_params)), 8000); 1443ca5ce0caSJyri Sarha pipeline->msg.extension |= SOF_IPC4_GLB_EXT_CHAIN_DMA_FIFO_SIZE(fifo_size); 1444ca5ce0caSJyri Sarha 1445ca5ce0caSJyri Sarha /* 1446ca5ce0caSJyri Sarha * Chain DMA does not support stream timestamping, set node_id to invalid 1447ca5ce0caSJyri Sarha * to skip the code in sof_ipc4_get_stream_start_offset(). 1448ca5ce0caSJyri Sarha */ 1449ca5ce0caSJyri Sarha copier_data->gtw_cfg.node_id = SOF_IPC4_INVALID_NODE_ID; 1450ca5ce0caSJyri Sarha 1451ca5ce0caSJyri Sarha return 0; 1452ca5ce0caSJyri Sarha } 1453ca5ce0caSJyri Sarha 1454904c48c4SRanjani Sridharan /* 14557ab6b1e8SRanjani Sridharan * Use the input_pin_fmts to match pcm params for playback and the output_pin_fmts 1456e63a73f9SRanjani Sridharan * for capture. 1457904c48c4SRanjani Sridharan */ 14585a56c533SRanjani Sridharan if (dir == SNDRV_PCM_STREAM_PLAYBACK) 14595a56c533SRanjani Sridharan ref_params = fe_params; 14605a56c533SRanjani Sridharan else 14615a56c533SRanjani Sridharan ref_params = pipeline_params; 1462e63a73f9SRanjani Sridharan 1463904c48c4SRanjani Sridharan copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK; 1464904c48c4SRanjani Sridharan copier_data->gtw_cfg.node_id |= 1465904c48c4SRanjani Sridharan SOF_IPC4_NODE_INDEX(platform_params->stream_tag - 1); 1466904c48c4SRanjani Sridharan 1467904c48c4SRanjani Sridharan /* set gateway attributes */ 1468904c48c4SRanjani Sridharan gtw_attr->lp_buffer_alloc = pipeline->lp_mode; 1469904c48c4SRanjani Sridharan break; 1470904c48c4SRanjani Sridharan } 1471acf52594SRanjani Sridharan case snd_soc_dapm_dai_in: 1472acf52594SRanjani Sridharan case snd_soc_dapm_dai_out: 1473acf52594SRanjani Sridharan { 1474ca5ce0caSJyri Sarha struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget; 1475ca5ce0caSJyri Sarha struct sof_ipc4_pipeline *pipeline = pipe_widget->private; 1476ca5ce0caSJyri Sarha 1477ca5ce0caSJyri Sarha if (pipeline->use_chain_dma) 1478ca5ce0caSJyri Sarha return 0; 1479ca5ce0caSJyri Sarha 1480a150345aSBard Liao dai = swidget->private; 1481acf52594SRanjani Sridharan 1482acf52594SRanjani Sridharan ipc4_copier = (struct sof_ipc4_copier *)dai->private; 1483acf52594SRanjani Sridharan copier_data = &ipc4_copier->data; 1484acf52594SRanjani Sridharan available_fmt = &ipc4_copier->available_fmt; 1485acf52594SRanjani Sridharan 14865a56c533SRanjani Sridharan /* 14875a56c533SRanjani Sridharan * When there is format conversion within a pipeline, the number of supported 14885a56c533SRanjani Sridharan * output formats is typically limited to just 1 for the DAI copiers. But when there 14895a56c533SRanjani Sridharan * is no format conversion, the DAI copiers input format must match that of the 14905a56c533SRanjani Sridharan * FE hw_params for capture and the pipeline params for playback. 14915a56c533SRanjani Sridharan */ 14925a56c533SRanjani Sridharan if (dir == SNDRV_PCM_STREAM_PLAYBACK) 1493acf52594SRanjani Sridharan ref_params = pipeline_params; 14945a56c533SRanjani Sridharan else 14955a56c533SRanjani Sridharan ref_params = fe_params; 1496acf52594SRanjani Sridharan 1497aa84ffb7SRanjani Sridharan ret = snd_sof_get_nhlt_endpoint_data(sdev, dai, fe_params, ipc4_copier->dai_index, 1498aa84ffb7SRanjani Sridharan ipc4_copier->dai_type, dir, 1499aa84ffb7SRanjani Sridharan &ipc4_copier->copier_config, 1500aa84ffb7SRanjani Sridharan &copier_data->gtw_cfg.config_length); 1501aa84ffb7SRanjani Sridharan if (ret < 0) 1502aa84ffb7SRanjani Sridharan return ret; 1503aa84ffb7SRanjani Sridharan 1504acf52594SRanjani Sridharan break; 1505acf52594SRanjani Sridharan } 15067d573425SBard Liao case snd_soc_dapm_buffer: 15077d573425SBard Liao { 15087d573425SBard Liao ipc4_copier = (struct sof_ipc4_copier *)swidget->private; 15097d573425SBard Liao copier_data = &ipc4_copier->data; 15107d573425SBard Liao available_fmt = &ipc4_copier->available_fmt; 15117d573425SBard Liao ref_params = pipeline_params; 15127d573425SBard Liao 15137d573425SBard Liao break; 15147d573425SBard Liao } 1515904c48c4SRanjani Sridharan default: 1516904c48c4SRanjani Sridharan dev_err(sdev->dev, "unsupported type %d for copier %s", 1517904c48c4SRanjani Sridharan swidget->id, swidget->widget->name); 1518904c48c4SRanjani Sridharan return -EINVAL; 1519904c48c4SRanjani Sridharan } 1520904c48c4SRanjani Sridharan 1521904c48c4SRanjani Sridharan /* set input and output audio formats */ 1522ae45aebeSRanjani Sridharan ret = sof_ipc4_init_input_audio_fmt(sdev, swidget, &copier_data->base_config, ref_params, 15235a56c533SRanjani Sridharan available_fmt); 1524904c48c4SRanjani Sridharan if (ret < 0) 1525904c48c4SRanjani Sridharan return ret; 1526904c48c4SRanjani Sridharan 15271af13f22SRanjani Sridharan /* set the reference params for output format selection */ 15281af13f22SRanjani Sridharan switch (swidget->id) { 15291af13f22SRanjani Sridharan case snd_soc_dapm_aif_in: 15301af13f22SRanjani Sridharan case snd_soc_dapm_dai_out: 15311af13f22SRanjani Sridharan case snd_soc_dapm_buffer: 15321af13f22SRanjani Sridharan { 15331af13f22SRanjani Sridharan struct sof_ipc4_audio_format *in_fmt; 15341af13f22SRanjani Sridharan 15351af13f22SRanjani Sridharan in_fmt = &available_fmt->input_pin_fmts[ret].audio_fmt; 15361af13f22SRanjani Sridharan out_ref_rate = in_fmt->sampling_frequency; 15371af13f22SRanjani Sridharan out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg); 15381af13f22SRanjani Sridharan out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg); 15391af13f22SRanjani Sridharan break; 15401af13f22SRanjani Sridharan } 15411af13f22SRanjani Sridharan case snd_soc_dapm_aif_out: 15421af13f22SRanjani Sridharan case snd_soc_dapm_dai_in: 15431af13f22SRanjani Sridharan out_ref_valid_bits = sof_ipc4_get_valid_bits(sdev, fe_params); 15441af13f22SRanjani Sridharan if (out_ref_valid_bits < 0) 15451af13f22SRanjani Sridharan return out_ref_valid_bits; 15461af13f22SRanjani Sridharan 15471af13f22SRanjani Sridharan out_ref_rate = params_rate(fe_params); 15481af13f22SRanjani Sridharan out_ref_channels = params_channels(fe_params); 15491af13f22SRanjani Sridharan break; 15501af13f22SRanjani Sridharan default: 15511af13f22SRanjani Sridharan /* 15521af13f22SRanjani Sridharan * Unsupported type should be caught by the former switch default 15531af13f22SRanjani Sridharan * case, this should never happen in reality. 15541af13f22SRanjani Sridharan */ 15551af13f22SRanjani Sridharan return -EINVAL; 15561af13f22SRanjani Sridharan } 15571af13f22SRanjani Sridharan 1558a2e07c33SRanjani Sridharan output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, &copier_data->base_config, 15591af13f22SRanjani Sridharan available_fmt, out_ref_rate, 15601af13f22SRanjani Sridharan out_ref_channels, out_ref_valid_bits); 1561f1ceebdbSRanjani Sridharan if (output_fmt_index < 0) { 15621af13f22SRanjani Sridharan dev_err(sdev->dev, "Failed to initialize output format for %s", 1563f1ceebdbSRanjani Sridharan swidget->widget->name); 1564f1ceebdbSRanjani Sridharan return output_fmt_index; 1565f1ceebdbSRanjani Sridharan } 1566a2e07c33SRanjani Sridharan 15679c560549SRanjani Sridharan /* 15689c560549SRanjani Sridharan * Set the output format. Current topology defines pin 0 input and output formats in pairs. 15699c560549SRanjani Sridharan * This assumes that the pin 0 formats are defined before all other pins. 15709c560549SRanjani Sridharan * So pick the output audio format with the same index as the chosen 15719c560549SRanjani Sridharan * input format. This logic will need to be updated when the format definitions 15729c560549SRanjani Sridharan * in topology change. 15739c560549SRanjani Sridharan */ 1574a2e07c33SRanjani Sridharan memcpy(&copier_data->out_format, 1575a2e07c33SRanjani Sridharan &available_fmt->output_pin_fmts[output_fmt_index].audio_fmt, 15769c560549SRanjani Sridharan sizeof(struct sof_ipc4_audio_format)); 15779c560549SRanjani Sridharan dev_dbg(sdev->dev, "Output audio format for %s\n", swidget->widget->name); 1578a2e07c33SRanjani Sridharan sof_ipc4_dbg_audio_format(sdev->dev, &available_fmt->output_pin_fmts[output_fmt_index], 1); 15799c560549SRanjani Sridharan 1580a45a4d43SBard Liao switch (swidget->id) { 1581a45a4d43SBard Liao case snd_soc_dapm_dai_in: 1582a45a4d43SBard Liao case snd_soc_dapm_dai_out: 1583a45a4d43SBard Liao { 1584a45a4d43SBard Liao /* 1585a45a4d43SBard Liao * Only SOF_DAI_INTEL_ALH needs copier_data to set blob. 1586ae45aebeSRanjani Sridharan * That's why only ALH dai's blob is set after sof_ipc4_init_input_audio_fmt 1587a45a4d43SBard Liao */ 1588a45a4d43SBard Liao if (ipc4_copier->dai_type == SOF_DAI_INTEL_ALH) { 1589a45a4d43SBard Liao struct sof_ipc4_alh_configuration_blob *blob; 1590a150345aSBard Liao struct sof_ipc4_copier_data *alh_data; 1591a150345aSBard Liao struct sof_ipc4_copier *alh_copier; 1592a150345aSBard Liao struct snd_sof_widget *w; 15930390a102SBard Liao u32 ch_count = 0; 1594a150345aSBard Liao u32 ch_mask = 0; 1595a45a4d43SBard Liao u32 ch_map; 15960390a102SBard Liao u32 step; 15970390a102SBard Liao u32 mask; 1598a45a4d43SBard Liao int i; 1599a45a4d43SBard Liao 1600a45a4d43SBard Liao blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config; 1601a150345aSBard Liao 1602a45a4d43SBard Liao blob->gw_attr.lp_buffer_alloc = 0; 1603a45a4d43SBard Liao 1604a45a4d43SBard Liao /* Get channel_mask from ch_map */ 1605a45a4d43SBard Liao ch_map = copier_data->base_config.audio_fmt.ch_map; 1606a45a4d43SBard Liao for (i = 0; ch_map; i++) { 16070390a102SBard Liao if ((ch_map & 0xf) != 0xf) { 1608a150345aSBard Liao ch_mask |= BIT(i); 16090390a102SBard Liao ch_count++; 16100390a102SBard Liao } 1611a45a4d43SBard Liao ch_map >>= 4; 1612a45a4d43SBard Liao } 1613a150345aSBard Liao 1614e186e1f2SPierre-Louis Bossart step = ch_count / blob->alh_cfg.device_count; 16150390a102SBard Liao mask = GENMASK(step - 1, 0); 1616a150345aSBard Liao /* 1617a150345aSBard Liao * Set each gtw_cfg.node_id to blob->alh_cfg.mapping[] 1618a150345aSBard Liao * for all widgets with the same stream name 1619a150345aSBard Liao */ 1620a150345aSBard Liao i = 0; 1621a150345aSBard Liao list_for_each_entry(w, &sdev->widget_list, list) { 1622a150345aSBard Liao if (w->widget->sname && 1623a150345aSBard Liao strcmp(w->widget->sname, swidget->widget->sname)) 1624a150345aSBard Liao continue; 1625a150345aSBard Liao 1626a150345aSBard Liao dai = w->private; 1627a150345aSBard Liao alh_copier = (struct sof_ipc4_copier *)dai->private; 1628a150345aSBard Liao alh_data = &alh_copier->data; 1629e186e1f2SPierre-Louis Bossart blob->alh_cfg.mapping[i].device = alh_data->gtw_cfg.node_id; 16300390a102SBard Liao /* 16310390a102SBard Liao * Set the same channel mask for playback as the audio data is 16320390a102SBard Liao * duplicated for all speakers. For capture, split the channels 16330390a102SBard Liao * among the aggregated DAIs. For example, with 4 channels on 2 16340390a102SBard Liao * aggregated DAIs, the channel_mask should be 0x3 and 0xc for the 16350390a102SBard Liao * two DAI's. 16360390a102SBard Liao * The channel masks used depend on the cpu_dais used in the 16370390a102SBard Liao * dailink at the machine driver level, which actually comes from 16380390a102SBard Liao * the tables in soc_acpi files depending on the _ADR and devID 16390390a102SBard Liao * registers for each codec. 16400390a102SBard Liao */ 16410390a102SBard Liao if (w->id == snd_soc_dapm_dai_in) 1642a150345aSBard Liao blob->alh_cfg.mapping[i].channel_mask = ch_mask; 16430390a102SBard Liao else 16440390a102SBard Liao blob->alh_cfg.mapping[i].channel_mask = mask << (step * i); 16450390a102SBard Liao 1646a150345aSBard Liao i++; 1647a150345aSBard Liao } 1648e186e1f2SPierre-Louis Bossart if (blob->alh_cfg.device_count > 1) { 1649a150345aSBard Liao int group_id; 1650a150345aSBard Liao 16514ee6fc27SBard Liao group_id = ida_alloc_max(&alh_group_ida, ALH_MULTI_GTW_COUNT - 1, 1652a150345aSBard Liao GFP_KERNEL); 1653a150345aSBard Liao 1654a150345aSBard Liao if (group_id < 0) 1655a150345aSBard Liao return group_id; 1656a150345aSBard Liao 1657a150345aSBard Liao /* add multi-gateway base */ 1658a150345aSBard Liao group_id += ALH_MULTI_GTW_BASE; 1659a150345aSBard Liao copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK; 1660a150345aSBard Liao copier_data->gtw_cfg.node_id |= SOF_IPC4_NODE_INDEX(group_id); 1661a150345aSBard Liao } 1662a45a4d43SBard Liao } 1663a45a4d43SBard Liao } 1664a45a4d43SBard Liao } 1665a45a4d43SBard Liao 1666904c48c4SRanjani Sridharan /* modify the input params for the next widget */ 1667904c48c4SRanjani Sridharan fmt = hw_param_mask(pipeline_params, SNDRV_PCM_HW_PARAM_FORMAT); 1668904c48c4SRanjani Sridharan out_sample_valid_bits = 1669904c48c4SRanjani Sridharan SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(copier_data->out_format.fmt_cfg); 1670904c48c4SRanjani Sridharan snd_mask_none(fmt); 167137ec7ab4SKai Vehmanen ret = ipc4_set_fmt_mask(fmt, out_sample_valid_bits); 167237ec7ab4SKai Vehmanen if (ret) 167337ec7ab4SKai Vehmanen return ret; 1674904c48c4SRanjani Sridharan 1675594c1bb9SRanjani Sridharan /* 1676594c1bb9SRanjani Sridharan * Set the gateway dma_buffer_size to 2ms buffer size to meet the FW expectation. In the 1677594c1bb9SRanjani Sridharan * deep buffer case, set the dma_buffer_size depending on the deep_buffer_dma_ms set 1678594c1bb9SRanjani Sridharan * in topology. 1679594c1bb9SRanjani Sridharan */ 1680594c1bb9SRanjani Sridharan switch (swidget->id) { 1681594c1bb9SRanjani Sridharan case snd_soc_dapm_dai_in: 1682594c1bb9SRanjani Sridharan copier_data->gtw_cfg.dma_buffer_size = 1683594c1bb9SRanjani Sridharan SOF_IPC4_MIN_DMA_BUFFER_SIZE * copier_data->base_config.ibs; 1684904c48c4SRanjani Sridharan break; 1685594c1bb9SRanjani Sridharan case snd_soc_dapm_aif_in: 1686594c1bb9SRanjani Sridharan copier_data->gtw_cfg.dma_buffer_size = 1687594c1bb9SRanjani Sridharan max((u32)SOF_IPC4_MIN_DMA_BUFFER_SIZE, deep_buffer_dma_ms) * 1688594c1bb9SRanjani Sridharan copier_data->base_config.ibs; 1689904c48c4SRanjani Sridharan break; 1690594c1bb9SRanjani Sridharan case snd_soc_dapm_dai_out: 1691594c1bb9SRanjani Sridharan case snd_soc_dapm_aif_out: 1692594c1bb9SRanjani Sridharan copier_data->gtw_cfg.dma_buffer_size = 1693594c1bb9SRanjani Sridharan SOF_IPC4_MIN_DMA_BUFFER_SIZE * copier_data->base_config.obs; 1694904c48c4SRanjani Sridharan break; 1695904c48c4SRanjani Sridharan default: 1696594c1bb9SRanjani Sridharan break; 1697904c48c4SRanjani Sridharan } 1698904c48c4SRanjani Sridharan 1699904c48c4SRanjani Sridharan data = &ipc4_copier->copier_config; 1700904c48c4SRanjani Sridharan ipc_config_size = &ipc4_copier->ipc_config_size; 1701904c48c4SRanjani Sridharan ipc_config_data = &ipc4_copier->ipc_config_data; 1702904c48c4SRanjani Sridharan 1703904c48c4SRanjani Sridharan /* config_length is DWORD based */ 1704a0659f81SPierre-Louis Bossart gtw_cfg_config_length = copier_data->gtw_cfg.config_length * 4; 1705a0659f81SPierre-Louis Bossart ipc_size = sizeof(*copier_data) + gtw_cfg_config_length; 1706a0659f81SPierre-Louis Bossart 1707a0659f81SPierre-Louis Bossart if (ipc4_copier->dma_config_tlv.type == SOF_IPC4_GTW_DMA_CONFIG_ID && 1708a0659f81SPierre-Louis Bossart ipc4_copier->dma_config_tlv.length) { 1709a0659f81SPierre-Louis Bossart dma_config_tlv_size = sizeof(ipc4_copier->dma_config_tlv) + 1710a0659f81SPierre-Louis Bossart ipc4_copier->dma_config_tlv.dma_config.dma_priv_config_size; 1711a0659f81SPierre-Louis Bossart 1712a0659f81SPierre-Louis Bossart /* paranoia check on TLV size/length */ 1713a0659f81SPierre-Louis Bossart if (dma_config_tlv_size != ipc4_copier->dma_config_tlv.length + 1714a0659f81SPierre-Louis Bossart sizeof(uint32_t) * 2) { 1715a0659f81SPierre-Louis Bossart dev_err(sdev->dev, "Invalid configuration, TLV size %d length %d\n", 1716a0659f81SPierre-Louis Bossart dma_config_tlv_size, ipc4_copier->dma_config_tlv.length); 1717a0659f81SPierre-Louis Bossart return -EINVAL; 1718a0659f81SPierre-Louis Bossart } 1719a0659f81SPierre-Louis Bossart 1720a0659f81SPierre-Louis Bossart ipc_size += dma_config_tlv_size; 1721a0659f81SPierre-Louis Bossart 1722a0659f81SPierre-Louis Bossart /* we also need to increase the size at the gtw level */ 1723a0659f81SPierre-Louis Bossart copier_data->gtw_cfg.config_length += dma_config_tlv_size / 4; 1724a0659f81SPierre-Louis Bossart } 1725904c48c4SRanjani Sridharan 1726904c48c4SRanjani Sridharan dev_dbg(sdev->dev, "copier %s, IPC size is %d", swidget->widget->name, ipc_size); 1727904c48c4SRanjani Sridharan 1728904c48c4SRanjani Sridharan *ipc_config_data = kzalloc(ipc_size, GFP_KERNEL); 1729904c48c4SRanjani Sridharan if (!*ipc_config_data) 1730904c48c4SRanjani Sridharan return -ENOMEM; 1731904c48c4SRanjani Sridharan 1732904c48c4SRanjani Sridharan *ipc_config_size = ipc_size; 1733904c48c4SRanjani Sridharan 1734e6475ce2SPeter Ujfalusi /* update pipeline memory usage */ 1735e6475ce2SPeter Ujfalusi sof_ipc4_update_resource_usage(sdev, swidget, &copier_data->base_config); 1736e6475ce2SPeter Ujfalusi 1737904c48c4SRanjani Sridharan /* copy IPC data */ 1738904c48c4SRanjani Sridharan memcpy(*ipc_config_data, (void *)copier_data, sizeof(*copier_data)); 1739a0659f81SPierre-Louis Bossart if (gtw_cfg_config_length) 1740904c48c4SRanjani Sridharan memcpy(*ipc_config_data + sizeof(*copier_data), 1741a0659f81SPierre-Louis Bossart *data, gtw_cfg_config_length); 1742a0659f81SPierre-Louis Bossart 1743a0659f81SPierre-Louis Bossart /* add DMA Config TLV, if configured */ 1744a0659f81SPierre-Louis Bossart if (dma_config_tlv_size) 1745a0659f81SPierre-Louis Bossart memcpy(*ipc_config_data + sizeof(*copier_data) + 1746a0659f81SPierre-Louis Bossart gtw_cfg_config_length, 1747a0659f81SPierre-Louis Bossart &ipc4_copier->dma_config_tlv, dma_config_tlv_size); 1748904c48c4SRanjani Sridharan 1749ef8a29baSPierre-Louis Bossart /* 1750ef8a29baSPierre-Louis Bossart * Restore gateway config length now that IPC payload is prepared. This avoids 1751ef8a29baSPierre-Louis Bossart * counting the DMA CONFIG TLV multiple times 1752ef8a29baSPierre-Louis Bossart */ 1753ef8a29baSPierre-Louis Bossart copier_data->gtw_cfg.config_length = gtw_cfg_config_length / 4; 1754ef8a29baSPierre-Louis Bossart 1755711d0427SBard Liao return 0; 17564f838ab2SRanjani Sridharan } 17574f838ab2SRanjani Sridharan 17584f838ab2SRanjani Sridharan static int sof_ipc4_prepare_gain_module(struct snd_sof_widget *swidget, 17594f838ab2SRanjani Sridharan struct snd_pcm_hw_params *fe_params, 17604f838ab2SRanjani Sridharan struct snd_sof_platform_stream_params *platform_params, 17614f838ab2SRanjani Sridharan struct snd_pcm_hw_params *pipeline_params, int dir) 17624f838ab2SRanjani Sridharan { 17634f838ab2SRanjani Sridharan struct snd_soc_component *scomp = swidget->scomp; 17644f838ab2SRanjani Sridharan struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 17654f838ab2SRanjani Sridharan struct sof_ipc4_gain *gain = swidget->private; 1766e63a73f9SRanjani Sridharan struct sof_ipc4_available_audio_format *available_fmt = &gain->available_fmt; 17671af13f22SRanjani Sridharan struct sof_ipc4_audio_format *in_fmt; 17681af13f22SRanjani Sridharan u32 out_ref_rate, out_ref_channels, out_ref_valid_bits; 17694f838ab2SRanjani Sridharan int ret; 17704f838ab2SRanjani Sridharan 1771ae45aebeSRanjani Sridharan ret = sof_ipc4_init_input_audio_fmt(sdev, swidget, &gain->base_config, 17725a56c533SRanjani Sridharan pipeline_params, available_fmt); 17734f838ab2SRanjani Sridharan if (ret < 0) 17744f838ab2SRanjani Sridharan return ret; 17754f838ab2SRanjani Sridharan 17761af13f22SRanjani Sridharan in_fmt = &available_fmt->input_pin_fmts[ret].audio_fmt; 17771af13f22SRanjani Sridharan out_ref_rate = in_fmt->sampling_frequency; 17781af13f22SRanjani Sridharan out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg); 17791af13f22SRanjani Sridharan out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg); 17801af13f22SRanjani Sridharan 17811af13f22SRanjani Sridharan ret = sof_ipc4_init_output_audio_fmt(sdev, &gain->base_config, available_fmt, 17821af13f22SRanjani Sridharan out_ref_rate, out_ref_channels, out_ref_valid_bits); 1783f1ceebdbSRanjani Sridharan if (ret < 0) { 17841af13f22SRanjani Sridharan dev_err(sdev->dev, "Failed to initialize output format for %s", 17851af13f22SRanjani Sridharan swidget->widget->name); 1786f1ceebdbSRanjani Sridharan return ret; 1787f1ceebdbSRanjani Sridharan } 1788a2e07c33SRanjani Sridharan 17894f838ab2SRanjani Sridharan /* update pipeline memory usage */ 179019c745d1SPeter Ujfalusi sof_ipc4_update_resource_usage(sdev, swidget, &gain->base_config); 17914f838ab2SRanjani Sridharan 1792711d0427SBard Liao return 0; 17934f838ab2SRanjani Sridharan } 17944f838ab2SRanjani Sridharan 17954d4ba014SRanjani Sridharan static int sof_ipc4_prepare_mixer_module(struct snd_sof_widget *swidget, 17964d4ba014SRanjani Sridharan struct snd_pcm_hw_params *fe_params, 17974d4ba014SRanjani Sridharan struct snd_sof_platform_stream_params *platform_params, 17984d4ba014SRanjani Sridharan struct snd_pcm_hw_params *pipeline_params, int dir) 17994d4ba014SRanjani Sridharan { 18004d4ba014SRanjani Sridharan struct snd_soc_component *scomp = swidget->scomp; 18014d4ba014SRanjani Sridharan struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 18024d4ba014SRanjani Sridharan struct sof_ipc4_mixer *mixer = swidget->private; 1803e63a73f9SRanjani Sridharan struct sof_ipc4_available_audio_format *available_fmt = &mixer->available_fmt; 18041af13f22SRanjani Sridharan struct sof_ipc4_audio_format *in_fmt; 18051af13f22SRanjani Sridharan u32 out_ref_rate, out_ref_channels, out_ref_valid_bits; 18064d4ba014SRanjani Sridharan int ret; 18074d4ba014SRanjani Sridharan 1808ae45aebeSRanjani Sridharan ret = sof_ipc4_init_input_audio_fmt(sdev, swidget, &mixer->base_config, 18095a56c533SRanjani Sridharan pipeline_params, available_fmt); 18104d4ba014SRanjani Sridharan if (ret < 0) 18114d4ba014SRanjani Sridharan return ret; 18124d4ba014SRanjani Sridharan 18131af13f22SRanjani Sridharan in_fmt = &available_fmt->input_pin_fmts[ret].audio_fmt; 18141af13f22SRanjani Sridharan out_ref_rate = in_fmt->sampling_frequency; 18151af13f22SRanjani Sridharan out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg); 18161af13f22SRanjani Sridharan out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg); 18171af13f22SRanjani Sridharan 18181af13f22SRanjani Sridharan ret = sof_ipc4_init_output_audio_fmt(sdev, &mixer->base_config, available_fmt, 18191af13f22SRanjani Sridharan out_ref_rate, out_ref_channels, out_ref_valid_bits); 1820f1ceebdbSRanjani Sridharan if (ret < 0) { 18211af13f22SRanjani Sridharan dev_err(sdev->dev, "Failed to initialize output format for %s", 18221af13f22SRanjani Sridharan swidget->widget->name); 1823f1ceebdbSRanjani Sridharan return ret; 1824f1ceebdbSRanjani Sridharan } 1825a2e07c33SRanjani Sridharan 18264d4ba014SRanjani Sridharan /* update pipeline memory usage */ 182719c745d1SPeter Ujfalusi sof_ipc4_update_resource_usage(sdev, swidget, &mixer->base_config); 18284d4ba014SRanjani Sridharan 1829711d0427SBard Liao return 0; 18304d4ba014SRanjani Sridharan } 18314d4ba014SRanjani Sridharan 1832b85f4fc4SRander Wang static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget, 1833b85f4fc4SRander Wang struct snd_pcm_hw_params *fe_params, 1834b85f4fc4SRander Wang struct snd_sof_platform_stream_params *platform_params, 1835b85f4fc4SRander Wang struct snd_pcm_hw_params *pipeline_params, int dir) 1836b85f4fc4SRander Wang { 1837b85f4fc4SRander Wang struct snd_soc_component *scomp = swidget->scomp; 1838b85f4fc4SRander Wang struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 1839b85f4fc4SRander Wang struct sof_ipc4_src *src = swidget->private; 1840e63a73f9SRanjani Sridharan struct sof_ipc4_available_audio_format *available_fmt = &src->available_fmt; 1841*ef243882SRanjani Sridharan struct sof_ipc4_audio_format *out_audio_fmt; 18421af13f22SRanjani Sridharan struct sof_ipc4_audio_format *in_fmt; 18431af13f22SRanjani Sridharan u32 out_ref_rate, out_ref_channels, out_ref_valid_bits; 1844*ef243882SRanjani Sridharan int ret, output_format_index; 1845b85f4fc4SRander Wang 1846ae45aebeSRanjani Sridharan ret = sof_ipc4_init_input_audio_fmt(sdev, swidget, &src->base_config, 18475a56c533SRanjani Sridharan pipeline_params, available_fmt); 1848b85f4fc4SRander Wang if (ret < 0) 1849b85f4fc4SRander Wang return ret; 1850b85f4fc4SRander Wang 18511af13f22SRanjani Sridharan in_fmt = &available_fmt->input_pin_fmts[ret].audio_fmt; 18521af13f22SRanjani Sridharan out_ref_rate = in_fmt->sampling_frequency; 18531af13f22SRanjani Sridharan out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg); 18541af13f22SRanjani Sridharan out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg); 18551af13f22SRanjani Sridharan 1856*ef243882SRanjani Sridharan output_format_index = sof_ipc4_init_output_audio_fmt(sdev, &src->base_config, 1857*ef243882SRanjani Sridharan available_fmt, out_ref_rate, 1858*ef243882SRanjani Sridharan out_ref_channels, out_ref_valid_bits); 1859*ef243882SRanjani Sridharan if (output_format_index < 0) { 18601af13f22SRanjani Sridharan dev_err(sdev->dev, "Failed to initialize output format for %s", 18611af13f22SRanjani Sridharan swidget->widget->name); 1862*ef243882SRanjani Sridharan return output_format_index; 1863f1ceebdbSRanjani Sridharan } 1864a2e07c33SRanjani Sridharan 1865b85f4fc4SRander Wang /* update pipeline memory usage */ 186619c745d1SPeter Ujfalusi sof_ipc4_update_resource_usage(sdev, swidget, &src->base_config); 1867b85f4fc4SRander Wang 1868*ef243882SRanjani Sridharan out_audio_fmt = &available_fmt->output_pin_fmts[output_format_index].audio_fmt; 1869*ef243882SRanjani Sridharan src->sink_rate = out_audio_fmt->sampling_frequency; 1870b85f4fc4SRander Wang 1871*ef243882SRanjani Sridharan /* update pipeline_params for sink widgets */ 1872*ef243882SRanjani Sridharan return sof_ipc4_update_hw_params(sdev, pipeline_params, out_audio_fmt); 1873b85f4fc4SRander Wang } 1874b85f4fc4SRander Wang 1875f9efae95SRanjani Sridharan static int 1876f9efae95SRanjani Sridharan sof_ipc4_process_set_pin_formats(struct snd_sof_widget *swidget, int pin_type) 1877f9efae95SRanjani Sridharan { 1878f9efae95SRanjani Sridharan struct sof_ipc4_process *process = swidget->private; 1879f9efae95SRanjani Sridharan struct sof_ipc4_base_module_cfg_ext *base_cfg_ext = process->base_config_ext; 1880f9efae95SRanjani Sridharan struct sof_ipc4_available_audio_format *available_fmt = &process->available_fmt; 1881f9efae95SRanjani Sridharan struct sof_ipc4_pin_format *pin_format, *format_list_to_search; 1882f9efae95SRanjani Sridharan struct snd_soc_component *scomp = swidget->scomp; 1883f9efae95SRanjani Sridharan int num_pins, format_list_count; 1884f9efae95SRanjani Sridharan int pin_format_offset = 0; 1885f9efae95SRanjani Sridharan int i, j; 1886f9efae95SRanjani Sridharan 1887f9efae95SRanjani Sridharan /* set number of pins, offset of pin format and format list to search based on pin type */ 1888f9efae95SRanjani Sridharan if (pin_type == SOF_PIN_TYPE_INPUT) { 1889f9efae95SRanjani Sridharan num_pins = swidget->num_input_pins; 1890f9efae95SRanjani Sridharan format_list_to_search = available_fmt->input_pin_fmts; 1891f9efae95SRanjani Sridharan format_list_count = available_fmt->num_input_formats; 1892f9efae95SRanjani Sridharan } else { 1893f9efae95SRanjani Sridharan num_pins = swidget->num_output_pins; 1894f9efae95SRanjani Sridharan pin_format_offset = swidget->num_input_pins; 1895f9efae95SRanjani Sridharan format_list_to_search = available_fmt->output_pin_fmts; 1896f9efae95SRanjani Sridharan format_list_count = available_fmt->num_output_formats; 1897f9efae95SRanjani Sridharan } 1898f9efae95SRanjani Sridharan 1899f9efae95SRanjani Sridharan for (i = pin_format_offset; i < num_pins + pin_format_offset; i++) { 1900f9efae95SRanjani Sridharan pin_format = &base_cfg_ext->pin_formats[i]; 1901f9efae95SRanjani Sridharan 1902f9efae95SRanjani Sridharan /* Pin 0 audio formats are derived from the base config input/output format */ 1903f9efae95SRanjani Sridharan if (i == pin_format_offset) { 1904f9efae95SRanjani Sridharan if (pin_type == SOF_PIN_TYPE_INPUT) { 1905f9efae95SRanjani Sridharan pin_format->buffer_size = process->base_config.ibs; 1906f9efae95SRanjani Sridharan pin_format->audio_fmt = process->base_config.audio_fmt; 1907f9efae95SRanjani Sridharan } else { 1908f9efae95SRanjani Sridharan pin_format->buffer_size = process->base_config.obs; 1909f9efae95SRanjani Sridharan pin_format->audio_fmt = process->output_format; 1910f9efae95SRanjani Sridharan } 1911f9efae95SRanjani Sridharan continue; 1912f9efae95SRanjani Sridharan } 1913f9efae95SRanjani Sridharan 1914f9efae95SRanjani Sridharan /* 1915f9efae95SRanjani Sridharan * For all other pins, find the pin formats from those set in topology. If there 1916f9efae95SRanjani Sridharan * is more than one format specified for a pin, this will pick the first available 1917f9efae95SRanjani Sridharan * one. 1918f9efae95SRanjani Sridharan */ 1919f9efae95SRanjani Sridharan for (j = 0; j < format_list_count; j++) { 1920f9efae95SRanjani Sridharan struct sof_ipc4_pin_format *pin_format_item = &format_list_to_search[j]; 1921f9efae95SRanjani Sridharan 1922f9efae95SRanjani Sridharan if (pin_format_item->pin_index == i - pin_format_offset) { 1923f9efae95SRanjani Sridharan *pin_format = *pin_format_item; 1924f9efae95SRanjani Sridharan break; 1925f9efae95SRanjani Sridharan } 1926f9efae95SRanjani Sridharan } 1927f9efae95SRanjani Sridharan 1928f9efae95SRanjani Sridharan if (j == format_list_count) { 1929f9efae95SRanjani Sridharan dev_err(scomp->dev, "%s pin %d format not found for %s\n", 1930f9efae95SRanjani Sridharan (pin_type == SOF_PIN_TYPE_INPUT) ? "input" : "output", 1931f9efae95SRanjani Sridharan i - pin_format_offset, swidget->widget->name); 1932f9efae95SRanjani Sridharan return -EINVAL; 1933f9efae95SRanjani Sridharan } 1934f9efae95SRanjani Sridharan } 1935f9efae95SRanjani Sridharan 1936f9efae95SRanjani Sridharan return 0; 1937f9efae95SRanjani Sridharan } 1938f9efae95SRanjani Sridharan 1939f9efae95SRanjani Sridharan static int sof_ipc4_process_add_base_cfg_extn(struct snd_sof_widget *swidget) 1940f9efae95SRanjani Sridharan { 1941f9efae95SRanjani Sridharan int ret, i; 1942f9efae95SRanjani Sridharan 1943f9efae95SRanjani Sridharan /* copy input and output pin formats */ 1944f9efae95SRanjani Sridharan for (i = 0; i <= SOF_PIN_TYPE_OUTPUT; i++) { 1945f9efae95SRanjani Sridharan ret = sof_ipc4_process_set_pin_formats(swidget, i); 1946f9efae95SRanjani Sridharan if (ret < 0) 1947f9efae95SRanjani Sridharan return ret; 1948f9efae95SRanjani Sridharan } 1949f9efae95SRanjani Sridharan 1950f9efae95SRanjani Sridharan return 0; 1951f9efae95SRanjani Sridharan } 1952f9efae95SRanjani Sridharan 19537711a2bbSLibin Yang static int sof_ipc4_prepare_process_module(struct snd_sof_widget *swidget, 19547711a2bbSLibin Yang struct snd_pcm_hw_params *fe_params, 19557711a2bbSLibin Yang struct snd_sof_platform_stream_params *platform_params, 19567711a2bbSLibin Yang struct snd_pcm_hw_params *pipeline_params, int dir) 19577711a2bbSLibin Yang { 19587711a2bbSLibin Yang struct snd_soc_component *scomp = swidget->scomp; 19597711a2bbSLibin Yang struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 19607711a2bbSLibin Yang struct sof_ipc4_process *process = swidget->private; 19617711a2bbSLibin Yang struct sof_ipc4_available_audio_format *available_fmt = &process->available_fmt; 19621af13f22SRanjani Sridharan struct sof_ipc4_audio_format *in_fmt; 19631af13f22SRanjani Sridharan u32 out_ref_rate, out_ref_channels, out_ref_valid_bits; 19647711a2bbSLibin Yang void *cfg = process->ipc_config_data; 1965a2e07c33SRanjani Sridharan int output_fmt_index; 19667711a2bbSLibin Yang int ret; 19677711a2bbSLibin Yang 1968ae45aebeSRanjani Sridharan ret = sof_ipc4_init_input_audio_fmt(sdev, swidget, &process->base_config, 19695a56c533SRanjani Sridharan pipeline_params, available_fmt); 19707711a2bbSLibin Yang if (ret < 0) 19717711a2bbSLibin Yang return ret; 19727711a2bbSLibin Yang 19731af13f22SRanjani Sridharan in_fmt = &available_fmt->input_pin_fmts[ret].audio_fmt; 19741af13f22SRanjani Sridharan out_ref_rate = in_fmt->sampling_frequency; 19751af13f22SRanjani Sridharan out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg); 19761af13f22SRanjani Sridharan out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg); 19771af13f22SRanjani Sridharan 1978a2e07c33SRanjani Sridharan output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, &process->base_config, 19791af13f22SRanjani Sridharan available_fmt, out_ref_rate, 19801af13f22SRanjani Sridharan out_ref_channels, out_ref_valid_bits); 19811af13f22SRanjani Sridharan if (output_fmt_index < 0 && available_fmt->num_output_formats) { 19821af13f22SRanjani Sridharan dev_err(sdev->dev, "Failed to initialize output format for %s", 19831af13f22SRanjani Sridharan swidget->widget->name); 19841af13f22SRanjani Sridharan return output_fmt_index; 19851af13f22SRanjani Sridharan } 1986a2e07c33SRanjani Sridharan 1987f9efae95SRanjani Sridharan /* copy Pin 0 output format */ 1988a2e07c33SRanjani Sridharan if (available_fmt->num_output_formats && 1989a2e07c33SRanjani Sridharan output_fmt_index < available_fmt->num_output_formats && 1990a2e07c33SRanjani Sridharan !available_fmt->output_pin_fmts[output_fmt_index].pin_index) { 1991a2e07c33SRanjani Sridharan memcpy(&process->output_format, 1992a2e07c33SRanjani Sridharan &available_fmt->output_pin_fmts[output_fmt_index].audio_fmt, 1993f9efae95SRanjani Sridharan sizeof(struct sof_ipc4_audio_format)); 1994f9efae95SRanjani Sridharan 1995811a742fSLibin Yang /* modify the pipeline params with the pin 0 output format */ 1996811a742fSLibin Yang ret = sof_ipc4_update_hw_params(sdev, pipeline_params, &process->output_format); 1997811a742fSLibin Yang if (ret) 1998811a742fSLibin Yang return ret; 1999811a742fSLibin Yang } 2000811a742fSLibin Yang 20017711a2bbSLibin Yang /* update pipeline memory usage */ 200219c745d1SPeter Ujfalusi sof_ipc4_update_resource_usage(sdev, swidget, &process->base_config); 20037711a2bbSLibin Yang 2004f9efae95SRanjani Sridharan /* ipc_config_data is composed of the base_config followed by an optional extension */ 20057711a2bbSLibin Yang memcpy(cfg, &process->base_config, sizeof(struct sof_ipc4_base_module_cfg)); 20067711a2bbSLibin Yang cfg += sizeof(struct sof_ipc4_base_module_cfg); 20077711a2bbSLibin Yang 2008f9efae95SRanjani Sridharan if (process->init_config == SOF_IPC4_MODULE_INIT_CONFIG_TYPE_BASE_CFG_WITH_EXT) { 2009f9efae95SRanjani Sridharan struct sof_ipc4_base_module_cfg_ext *base_cfg_ext = process->base_config_ext; 2010f9efae95SRanjani Sridharan 2011f9efae95SRanjani Sridharan ret = sof_ipc4_process_add_base_cfg_extn(swidget); 2012f9efae95SRanjani Sridharan if (ret < 0) 2013f9efae95SRanjani Sridharan return ret; 2014f9efae95SRanjani Sridharan 2015f9efae95SRanjani Sridharan memcpy(cfg, base_cfg_ext, process->base_config_ext_size); 2016f9efae95SRanjani Sridharan } 2017f9efae95SRanjani Sridharan 20187711a2bbSLibin Yang return 0; 20197711a2bbSLibin Yang } 20207711a2bbSLibin Yang 2021d97964f8SRanjani Sridharan static int sof_ipc4_control_load_volume(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol) 2022d97964f8SRanjani Sridharan { 2023d97964f8SRanjani Sridharan struct sof_ipc4_control_data *control_data; 2024d97964f8SRanjani Sridharan struct sof_ipc4_msg *msg; 2025d97964f8SRanjani Sridharan int i; 2026d97964f8SRanjani Sridharan 2027d97964f8SRanjani Sridharan scontrol->size = struct_size(control_data, chanv, scontrol->num_channels); 2028d97964f8SRanjani Sridharan 2029d97964f8SRanjani Sridharan /* scontrol->ipc_control_data will be freed in sof_control_unload */ 2030d97964f8SRanjani Sridharan scontrol->ipc_control_data = kzalloc(scontrol->size, GFP_KERNEL); 2031d97964f8SRanjani Sridharan if (!scontrol->ipc_control_data) 2032d97964f8SRanjani Sridharan return -ENOMEM; 2033d97964f8SRanjani Sridharan 2034d97964f8SRanjani Sridharan control_data = scontrol->ipc_control_data; 2035d97964f8SRanjani Sridharan control_data->index = scontrol->index; 2036d97964f8SRanjani Sridharan 2037d97964f8SRanjani Sridharan msg = &control_data->msg; 2038d97964f8SRanjani Sridharan msg->primary = SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_LARGE_CONFIG_SET); 2039d97964f8SRanjani Sridharan msg->primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); 2040d97964f8SRanjani Sridharan msg->primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG); 2041d97964f8SRanjani Sridharan 2042d97964f8SRanjani Sridharan msg->extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_GAIN_PARAM_ID); 2043d97964f8SRanjani Sridharan 2044d97964f8SRanjani Sridharan /* set default volume values to 0dB in control */ 2045d97964f8SRanjani Sridharan for (i = 0; i < scontrol->num_channels; i++) { 2046d97964f8SRanjani Sridharan control_data->chanv[i].channel = i; 2047d97964f8SRanjani Sridharan control_data->chanv[i].value = SOF_IPC4_VOL_ZERO_DB; 2048d97964f8SRanjani Sridharan } 2049d97964f8SRanjani Sridharan 2050d97964f8SRanjani Sridharan return 0; 2051d97964f8SRanjani Sridharan } 2052d97964f8SRanjani Sridharan 2053a382082fSLibin Yang static int sof_ipc4_control_load_bytes(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol) 2054a382082fSLibin Yang { 2055a382082fSLibin Yang struct sof_ipc4_control_data *control_data; 2056a382082fSLibin Yang struct sof_ipc4_msg *msg; 2057a382082fSLibin Yang int ret; 2058a382082fSLibin Yang 2059a382082fSLibin Yang if (scontrol->max_size < (sizeof(*control_data) + sizeof(struct sof_abi_hdr))) { 2060a382082fSLibin Yang dev_err(sdev->dev, "insufficient size for a bytes control %s: %zu.\n", 2061a382082fSLibin Yang scontrol->name, scontrol->max_size); 2062a382082fSLibin Yang return -EINVAL; 2063a382082fSLibin Yang } 2064a382082fSLibin Yang 2065a382082fSLibin Yang if (scontrol->priv_size > scontrol->max_size - sizeof(*control_data)) { 2066a382082fSLibin Yang dev_err(sdev->dev, "scontrol %s bytes data size %zu exceeds max %zu.\n", 2067a382082fSLibin Yang scontrol->name, scontrol->priv_size, 2068a382082fSLibin Yang scontrol->max_size - sizeof(*control_data)); 2069a382082fSLibin Yang return -EINVAL; 2070a382082fSLibin Yang } 2071a382082fSLibin Yang 2072a382082fSLibin Yang scontrol->size = sizeof(struct sof_ipc4_control_data) + scontrol->priv_size; 2073a382082fSLibin Yang 2074a382082fSLibin Yang scontrol->ipc_control_data = kzalloc(scontrol->max_size, GFP_KERNEL); 2075a382082fSLibin Yang if (!scontrol->ipc_control_data) 2076a382082fSLibin Yang return -ENOMEM; 2077a382082fSLibin Yang 2078a382082fSLibin Yang control_data = scontrol->ipc_control_data; 2079a382082fSLibin Yang control_data->index = scontrol->index; 2080a382082fSLibin Yang if (scontrol->priv_size > 0) { 2081a382082fSLibin Yang memcpy(control_data->data, scontrol->priv, scontrol->priv_size); 2082a382082fSLibin Yang kfree(scontrol->priv); 2083a382082fSLibin Yang scontrol->priv = NULL; 2084a382082fSLibin Yang 2085a382082fSLibin Yang if (control_data->data->magic != SOF_IPC4_ABI_MAGIC) { 2086a382082fSLibin Yang dev_err(sdev->dev, "Wrong ABI magic (%#x) for control: %s\n", 2087a382082fSLibin Yang control_data->data->magic, scontrol->name); 2088a382082fSLibin Yang ret = -EINVAL; 2089a382082fSLibin Yang goto err; 2090a382082fSLibin Yang } 2091a382082fSLibin Yang 2092a382082fSLibin Yang /* TODO: check the ABI version */ 2093a382082fSLibin Yang 2094a382082fSLibin Yang if (control_data->data->size + sizeof(struct sof_abi_hdr) != 2095a382082fSLibin Yang scontrol->priv_size) { 2096a382082fSLibin Yang dev_err(sdev->dev, "Control %s conflict in bytes %zu vs. priv size %zu.\n", 2097a382082fSLibin Yang scontrol->name, 2098a382082fSLibin Yang control_data->data->size + sizeof(struct sof_abi_hdr), 2099a382082fSLibin Yang scontrol->priv_size); 2100a382082fSLibin Yang ret = -EINVAL; 2101a382082fSLibin Yang goto err; 2102a382082fSLibin Yang } 2103a382082fSLibin Yang } 2104a382082fSLibin Yang 2105a382082fSLibin Yang msg = &control_data->msg; 2106a382082fSLibin Yang msg->primary = SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_LARGE_CONFIG_SET); 2107a382082fSLibin Yang msg->primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); 2108a382082fSLibin Yang msg->primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG); 2109a382082fSLibin Yang 2110a382082fSLibin Yang return 0; 2111a382082fSLibin Yang 2112a382082fSLibin Yang err: 2113a382082fSLibin Yang kfree(scontrol->ipc_control_data); 2114a382082fSLibin Yang scontrol->ipc_control_data = NULL; 2115a382082fSLibin Yang return ret; 2116a382082fSLibin Yang } 2117a382082fSLibin Yang 2118d97964f8SRanjani Sridharan static int sof_ipc4_control_setup(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol) 2119d97964f8SRanjani Sridharan { 2120d97964f8SRanjani Sridharan switch (scontrol->info_type) { 2121d97964f8SRanjani Sridharan case SND_SOC_TPLG_CTL_VOLSW: 2122d97964f8SRanjani Sridharan case SND_SOC_TPLG_CTL_VOLSW_SX: 2123d97964f8SRanjani Sridharan case SND_SOC_TPLG_CTL_VOLSW_XR_SX: 2124d97964f8SRanjani Sridharan return sof_ipc4_control_load_volume(sdev, scontrol); 2125a382082fSLibin Yang case SND_SOC_TPLG_CTL_BYTES: 2126a382082fSLibin Yang return sof_ipc4_control_load_bytes(sdev, scontrol); 2127d97964f8SRanjani Sridharan default: 2128d97964f8SRanjani Sridharan break; 2129d97964f8SRanjani Sridharan } 2130d97964f8SRanjani Sridharan 2131d97964f8SRanjani Sridharan return 0; 2132d97964f8SRanjani Sridharan } 2133d97964f8SRanjani Sridharan 21346e9257a1SRanjani Sridharan static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) 21356e9257a1SRanjani Sridharan { 21369c04363dSRanjani Sridharan struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget; 2137a2ba1f70SBard Liao struct sof_ipc4_fw_data *ipc4_data = sdev->private; 21386e9257a1SRanjani Sridharan struct sof_ipc4_pipeline *pipeline; 21396e9257a1SRanjani Sridharan struct sof_ipc4_msg *msg; 21406e9257a1SRanjani Sridharan void *ipc_data = NULL; 21416e9257a1SRanjani Sridharan u32 ipc_size = 0; 21426e9257a1SRanjani Sridharan int ret; 21436e9257a1SRanjani Sridharan 21446e9257a1SRanjani Sridharan switch (swidget->id) { 21456e9257a1SRanjani Sridharan case snd_soc_dapm_scheduler: 21466e9257a1SRanjani Sridharan pipeline = swidget->private; 21476e9257a1SRanjani Sridharan 2148935d31fdSJyri Sarha if (pipeline->use_chain_dma) { 2149056db840SColin Ian King dev_warn(sdev->dev, "use_chain_dma set for scheduler %s", 2150935d31fdSJyri Sarha swidget->widget->name); 2151ca5ce0caSJyri Sarha return 0; 2152935d31fdSJyri Sarha } 2153ca5ce0caSJyri Sarha 21546e9257a1SRanjani Sridharan dev_dbg(sdev->dev, "pipeline: %d memory pages: %d\n", swidget->pipeline_id, 21556e9257a1SRanjani Sridharan pipeline->mem_usage); 21566e9257a1SRanjani Sridharan 21576e9257a1SRanjani Sridharan msg = &pipeline->msg; 21586e9257a1SRanjani Sridharan msg->primary |= pipeline->mem_usage; 2159a2ba1f70SBard Liao 2160a2ba1f70SBard Liao swidget->instance_id = ida_alloc_max(&pipeline_ida, ipc4_data->max_num_pipelines, 2161a2ba1f70SBard Liao GFP_KERNEL); 2162a2ba1f70SBard Liao if (swidget->instance_id < 0) { 2163a2ba1f70SBard Liao dev_err(sdev->dev, "failed to assign pipeline id for %s: %d\n", 2164a2ba1f70SBard Liao swidget->widget->name, swidget->instance_id); 2165a2ba1f70SBard Liao return swidget->instance_id; 2166a2ba1f70SBard Liao } 2167a2ba1f70SBard Liao msg->primary &= ~SOF_IPC4_GLB_PIPE_INSTANCE_MASK; 2168a2ba1f70SBard Liao msg->primary |= SOF_IPC4_GLB_PIPE_INSTANCE_ID(swidget->instance_id); 21696e9257a1SRanjani Sridharan break; 21706e9257a1SRanjani Sridharan case snd_soc_dapm_aif_in: 21716e9257a1SRanjani Sridharan case snd_soc_dapm_aif_out: 21727d573425SBard Liao case snd_soc_dapm_buffer: 21736e9257a1SRanjani Sridharan { 21746e9257a1SRanjani Sridharan struct sof_ipc4_copier *ipc4_copier = swidget->private; 21756e9257a1SRanjani Sridharan 2176ca5ce0caSJyri Sarha pipeline = pipe_widget->private; 2177ca5ce0caSJyri Sarha if (pipeline->use_chain_dma) 2178ca5ce0caSJyri Sarha return 0; 2179ca5ce0caSJyri Sarha 21806e9257a1SRanjani Sridharan ipc_size = ipc4_copier->ipc_config_size; 21816e9257a1SRanjani Sridharan ipc_data = ipc4_copier->ipc_config_data; 21826e9257a1SRanjani Sridharan 21836e9257a1SRanjani Sridharan msg = &ipc4_copier->msg; 21846e9257a1SRanjani Sridharan break; 21856e9257a1SRanjani Sridharan } 21866e9257a1SRanjani Sridharan case snd_soc_dapm_dai_in: 21876e9257a1SRanjani Sridharan case snd_soc_dapm_dai_out: 21886e9257a1SRanjani Sridharan { 21896e9257a1SRanjani Sridharan struct snd_sof_dai *dai = swidget->private; 21906e9257a1SRanjani Sridharan struct sof_ipc4_copier *ipc4_copier = dai->private; 21916e9257a1SRanjani Sridharan 2192ca5ce0caSJyri Sarha pipeline = pipe_widget->private; 2193ca5ce0caSJyri Sarha if (pipeline->use_chain_dma) 2194ca5ce0caSJyri Sarha return 0; 2195ca5ce0caSJyri Sarha 21966e9257a1SRanjani Sridharan ipc_size = ipc4_copier->ipc_config_size; 21976e9257a1SRanjani Sridharan ipc_data = ipc4_copier->ipc_config_data; 21986e9257a1SRanjani Sridharan 21996e9257a1SRanjani Sridharan msg = &ipc4_copier->msg; 22006e9257a1SRanjani Sridharan break; 22016e9257a1SRanjani Sridharan } 22026e9257a1SRanjani Sridharan case snd_soc_dapm_pga: 22036e9257a1SRanjani Sridharan { 22046e9257a1SRanjani Sridharan struct sof_ipc4_gain *gain = swidget->private; 22056e9257a1SRanjani Sridharan 22066e9257a1SRanjani Sridharan ipc_size = sizeof(struct sof_ipc4_base_module_cfg) + 22076e9257a1SRanjani Sridharan sizeof(struct sof_ipc4_gain_data); 22086e9257a1SRanjani Sridharan ipc_data = gain; 22096e9257a1SRanjani Sridharan 22106e9257a1SRanjani Sridharan msg = &gain->msg; 22116e9257a1SRanjani Sridharan break; 22126e9257a1SRanjani Sridharan } 22136e9257a1SRanjani Sridharan case snd_soc_dapm_mixer: 22146e9257a1SRanjani Sridharan { 22156e9257a1SRanjani Sridharan struct sof_ipc4_mixer *mixer = swidget->private; 22166e9257a1SRanjani Sridharan 22176e9257a1SRanjani Sridharan ipc_size = sizeof(mixer->base_config); 22186e9257a1SRanjani Sridharan ipc_data = &mixer->base_config; 22196e9257a1SRanjani Sridharan 22206e9257a1SRanjani Sridharan msg = &mixer->msg; 22216e9257a1SRanjani Sridharan break; 22226e9257a1SRanjani Sridharan } 2223b85f4fc4SRander Wang case snd_soc_dapm_src: 2224b85f4fc4SRander Wang { 2225b85f4fc4SRander Wang struct sof_ipc4_src *src = swidget->private; 2226b85f4fc4SRander Wang 2227b85f4fc4SRander Wang ipc_size = sizeof(struct sof_ipc4_base_module_cfg) + sizeof(src->sink_rate); 2228b85f4fc4SRander Wang ipc_data = src; 2229b85f4fc4SRander Wang 2230b85f4fc4SRander Wang msg = &src->msg; 2231b85f4fc4SRander Wang break; 2232b85f4fc4SRander Wang } 22337711a2bbSLibin Yang case snd_soc_dapm_effect: 22347711a2bbSLibin Yang { 22357711a2bbSLibin Yang struct sof_ipc4_process *process = swidget->private; 22367711a2bbSLibin Yang 22377711a2bbSLibin Yang if (!process->ipc_config_size) { 22387711a2bbSLibin Yang dev_err(sdev->dev, "module %s has no config data!\n", 22397711a2bbSLibin Yang swidget->widget->name); 22407711a2bbSLibin Yang return -EINVAL; 22417711a2bbSLibin Yang } 22427711a2bbSLibin Yang 22437711a2bbSLibin Yang ipc_size = process->ipc_config_size; 22447711a2bbSLibin Yang ipc_data = process->ipc_config_data; 22457711a2bbSLibin Yang 22467711a2bbSLibin Yang msg = &process->msg; 22477711a2bbSLibin Yang break; 22487711a2bbSLibin Yang } 22496e9257a1SRanjani Sridharan default: 22506e9257a1SRanjani Sridharan dev_err(sdev->dev, "widget type %d not supported", swidget->id); 22516e9257a1SRanjani Sridharan return -EINVAL; 22526e9257a1SRanjani Sridharan } 22536e9257a1SRanjani Sridharan 22546e9257a1SRanjani Sridharan if (swidget->id != snd_soc_dapm_scheduler) { 2255711d0427SBard Liao ret = sof_ipc4_widget_assign_instance_id(sdev, swidget); 2256711d0427SBard Liao if (ret < 0) { 2257711d0427SBard Liao dev_err(sdev->dev, "failed to assign instance id for %s\n", 2258711d0427SBard Liao swidget->widget->name); 2259711d0427SBard Liao return ret; 2260711d0427SBard Liao } 22617738211bSPierre-Louis Bossart 22626e9257a1SRanjani Sridharan msg->primary &= ~SOF_IPC4_MOD_INSTANCE_MASK; 22636e9257a1SRanjani Sridharan msg->primary |= SOF_IPC4_MOD_INSTANCE(swidget->instance_id); 22646e9257a1SRanjani Sridharan 22656e9257a1SRanjani Sridharan msg->extension &= ~SOF_IPC4_MOD_EXT_PARAM_SIZE_MASK; 22666e9257a1SRanjani Sridharan msg->extension |= ipc_size >> 2; 2267a2ba1f70SBard Liao 2268a2ba1f70SBard Liao msg->extension &= ~SOF_IPC4_MOD_EXT_PPL_ID_MASK; 2269a2ba1f70SBard Liao msg->extension |= SOF_IPC4_MOD_EXT_PPL_ID(pipe_widget->instance_id); 22706e9257a1SRanjani Sridharan } 2271711d0427SBard Liao dev_dbg(sdev->dev, "Create widget %s instance %d - pipe %d - core %d\n", 2272711d0427SBard Liao swidget->widget->name, swidget->instance_id, swidget->pipeline_id, swidget->core); 22736e9257a1SRanjani Sridharan 22746e9257a1SRanjani Sridharan msg->data_size = ipc_size; 22756e9257a1SRanjani Sridharan msg->data_ptr = ipc_data; 22766e9257a1SRanjani Sridharan 2277367fd6ffSCurtis Malainey ret = sof_ipc_tx_message_no_reply(sdev->ipc, msg, ipc_size); 227861eb0addSPeter Ujfalusi if (ret < 0) { 22796e9257a1SRanjani Sridharan dev_err(sdev->dev, "failed to create module %s\n", swidget->widget->name); 22806e9257a1SRanjani Sridharan 228161eb0addSPeter Ujfalusi if (swidget->id != snd_soc_dapm_scheduler) { 228261eb0addSPeter Ujfalusi struct sof_ipc4_fw_module *fw_module = swidget->module_info; 228361eb0addSPeter Ujfalusi 228461eb0addSPeter Ujfalusi ida_free(&fw_module->m_ida, swidget->instance_id); 2285a2ba1f70SBard Liao } else { 2286a2ba1f70SBard Liao ida_free(&pipeline_ida, swidget->instance_id); 228761eb0addSPeter Ujfalusi } 228861eb0addSPeter Ujfalusi } 228961eb0addSPeter Ujfalusi 22906e9257a1SRanjani Sridharan return ret; 22916e9257a1SRanjani Sridharan } 22926e9257a1SRanjani Sridharan 22936e9257a1SRanjani Sridharan static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) 22946e9257a1SRanjani Sridharan { 2295711d0427SBard Liao struct sof_ipc4_fw_module *fw_module = swidget->module_info; 22966bc4d1b7SRanjani Sridharan struct sof_ipc4_fw_data *ipc4_data = sdev->private; 22976e9257a1SRanjani Sridharan int ret = 0; 22986e9257a1SRanjani Sridharan 22996bc4d1b7SRanjani Sridharan mutex_lock(&ipc4_data->pipeline_state_mutex); 23006bc4d1b7SRanjani Sridharan 23016e9257a1SRanjani Sridharan /* freeing a pipeline frees all the widgets associated with it */ 23026e9257a1SRanjani Sridharan if (swidget->id == snd_soc_dapm_scheduler) { 23036e9257a1SRanjani Sridharan struct sof_ipc4_pipeline *pipeline = swidget->private; 23046e9257a1SRanjani Sridharan struct sof_ipc4_msg msg = {{ 0 }}; 23056e9257a1SRanjani Sridharan u32 header; 23066e9257a1SRanjani Sridharan 2307935d31fdSJyri Sarha if (pipeline->use_chain_dma) { 2308056db840SColin Ian King dev_warn(sdev->dev, "use_chain_dma set for scheduler %s", 2309935d31fdSJyri Sarha swidget->widget->name); 2310935d31fdSJyri Sarha mutex_unlock(&ipc4_data->pipeline_state_mutex); 2311ca5ce0caSJyri Sarha return 0; 2312935d31fdSJyri Sarha } 2313ca5ce0caSJyri Sarha 2314a2ba1f70SBard Liao header = SOF_IPC4_GLB_PIPE_INSTANCE_ID(swidget->instance_id); 23156e9257a1SRanjani Sridharan header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_DELETE_PIPELINE); 23166e9257a1SRanjani Sridharan header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); 23176e9257a1SRanjani Sridharan header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG); 23186e9257a1SRanjani Sridharan 23196e9257a1SRanjani Sridharan msg.primary = header; 23206e9257a1SRanjani Sridharan 2321367fd6ffSCurtis Malainey ret = sof_ipc_tx_message_no_reply(sdev->ipc, &msg, 0); 23226e9257a1SRanjani Sridharan if (ret < 0) 23236e9257a1SRanjani Sridharan dev_err(sdev->dev, "failed to free pipeline widget %s\n", 23246e9257a1SRanjani Sridharan swidget->widget->name); 23256e9257a1SRanjani Sridharan 23266e9257a1SRanjani Sridharan pipeline->mem_usage = 0; 23276e9257a1SRanjani Sridharan pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED; 2328a2ba1f70SBard Liao ida_free(&pipeline_ida, swidget->instance_id); 2329defc0c63SRanjani Sridharan swidget->instance_id = -EINVAL; 2330711d0427SBard Liao } else { 2331ca5ce0caSJyri Sarha struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget; 2332ca5ce0caSJyri Sarha struct sof_ipc4_pipeline *pipeline = pipe_widget->private; 2333ca5ce0caSJyri Sarha 2334ca5ce0caSJyri Sarha if (!pipeline->use_chain_dma) 2335711d0427SBard Liao ida_free(&fw_module->m_ida, swidget->instance_id); 23366e9257a1SRanjani Sridharan } 23376e9257a1SRanjani Sridharan 23386bc4d1b7SRanjani Sridharan mutex_unlock(&ipc4_data->pipeline_state_mutex); 23396bc4d1b7SRanjani Sridharan 23406e9257a1SRanjani Sridharan return ret; 23416e9257a1SRanjani Sridharan } 23426e9257a1SRanjani Sridharan 2343c84443dbSChao Song static int sof_ipc4_get_queue_id(struct snd_sof_widget *src_widget, 2344c84443dbSChao Song struct snd_sof_widget *sink_widget, bool pin_type) 2345c84443dbSChao Song { 2346c84443dbSChao Song struct snd_sof_widget *current_swidget; 2347c84443dbSChao Song struct snd_soc_component *scomp; 2348c84443dbSChao Song struct ida *queue_ida; 2349c84443dbSChao Song const char *buddy_name; 2350c84443dbSChao Song char **pin_binding; 2351c84443dbSChao Song u32 num_pins; 2352c84443dbSChao Song int i; 2353c84443dbSChao Song 2354bb79f2a6SRanjani Sridharan if (pin_type == SOF_PIN_TYPE_OUTPUT) { 2355c84443dbSChao Song current_swidget = src_widget; 2356bb79f2a6SRanjani Sridharan pin_binding = src_widget->output_pin_binding; 2357bb79f2a6SRanjani Sridharan queue_ida = &src_widget->output_queue_ida; 2358bb79f2a6SRanjani Sridharan num_pins = src_widget->num_output_pins; 2359c84443dbSChao Song buddy_name = sink_widget->widget->name; 2360c84443dbSChao Song } else { 2361c84443dbSChao Song current_swidget = sink_widget; 2362bb79f2a6SRanjani Sridharan pin_binding = sink_widget->input_pin_binding; 2363bb79f2a6SRanjani Sridharan queue_ida = &sink_widget->input_queue_ida; 2364bb79f2a6SRanjani Sridharan num_pins = sink_widget->num_input_pins; 2365c84443dbSChao Song buddy_name = src_widget->widget->name; 2366c84443dbSChao Song } 2367c84443dbSChao Song 2368c84443dbSChao Song scomp = current_swidget->scomp; 2369c84443dbSChao Song 2370c84443dbSChao Song if (num_pins < 1) { 2371c84443dbSChao Song dev_err(scomp->dev, "invalid %s num_pins: %d for queue allocation for %s\n", 2372bb79f2a6SRanjani Sridharan (pin_type == SOF_PIN_TYPE_OUTPUT ? "output" : "input"), 2373c84443dbSChao Song num_pins, current_swidget->widget->name); 2374c84443dbSChao Song return -EINVAL; 2375c84443dbSChao Song } 2376c84443dbSChao Song 2377bb79f2a6SRanjani Sridharan /* If there is only one input/output pin, queue id must be 0 */ 2378c84443dbSChao Song if (num_pins == 1) 2379c84443dbSChao Song return 0; 2380c84443dbSChao Song 2381c84443dbSChao Song /* Allocate queue ID from pin binding array if it is defined in topology. */ 2382c84443dbSChao Song if (pin_binding) { 2383c84443dbSChao Song for (i = 0; i < num_pins; i++) { 2384c84443dbSChao Song if (!strcmp(pin_binding[i], buddy_name)) 2385c84443dbSChao Song return i; 2386c84443dbSChao Song } 2387c84443dbSChao Song /* 2388c84443dbSChao Song * Fail if no queue ID found from pin binding array, so that we don't 2389c84443dbSChao Song * mixed use pin binding array and ida for queue ID allocation. 2390c84443dbSChao Song */ 2391c84443dbSChao Song dev_err(scomp->dev, "no %s queue id found from pin binding array for %s\n", 2392bb79f2a6SRanjani Sridharan (pin_type == SOF_PIN_TYPE_OUTPUT ? "output" : "input"), 2393c84443dbSChao Song current_swidget->widget->name); 2394c84443dbSChao Song return -EINVAL; 2395c84443dbSChao Song } 2396c84443dbSChao Song 2397c84443dbSChao Song /* If no pin binding array specified in topology, use ida to allocate one */ 2398c84443dbSChao Song return ida_alloc_max(queue_ida, num_pins, GFP_KERNEL); 2399c84443dbSChao Song } 2400c84443dbSChao Song 2401c84443dbSChao Song static void sof_ipc4_put_queue_id(struct snd_sof_widget *swidget, int queue_id, 2402c84443dbSChao Song bool pin_type) 2403c84443dbSChao Song { 2404c84443dbSChao Song struct ida *queue_ida; 2405c84443dbSChao Song char **pin_binding; 2406c84443dbSChao Song int num_pins; 2407c84443dbSChao Song 2408bb79f2a6SRanjani Sridharan if (pin_type == SOF_PIN_TYPE_OUTPUT) { 2409bb79f2a6SRanjani Sridharan pin_binding = swidget->output_pin_binding; 2410bb79f2a6SRanjani Sridharan queue_ida = &swidget->output_queue_ida; 2411bb79f2a6SRanjani Sridharan num_pins = swidget->num_output_pins; 2412c84443dbSChao Song } else { 2413bb79f2a6SRanjani Sridharan pin_binding = swidget->input_pin_binding; 2414bb79f2a6SRanjani Sridharan queue_ida = &swidget->input_queue_ida; 2415bb79f2a6SRanjani Sridharan num_pins = swidget->num_input_pins; 2416c84443dbSChao Song } 2417c84443dbSChao Song 2418c84443dbSChao Song /* Nothing to free if queue ID is not allocated with ida. */ 2419c84443dbSChao Song if (num_pins == 1 || pin_binding) 2420c84443dbSChao Song return; 2421c84443dbSChao Song 2422c84443dbSChao Song ida_free(queue_ida, queue_id); 2423c84443dbSChao Song } 2424c84443dbSChao Song 242511f60563SBard Liao static int sof_ipc4_set_copier_sink_format(struct snd_sof_dev *sdev, 242611f60563SBard Liao struct snd_sof_widget *src_widget, 242711f60563SBard Liao struct snd_sof_widget *sink_widget, 242811f60563SBard Liao int sink_id) 242911f60563SBard Liao { 243011f60563SBard Liao struct sof_ipc4_copier_config_set_sink_format format; 24317a975e9bSPeter Ujfalusi const struct sof_ipc_ops *iops = sdev->ipc->ops; 2432648fea12SChao Song struct sof_ipc4_base_module_cfg *src_config; 2433648fea12SChao Song const struct sof_ipc4_audio_format *pin_fmt; 243411f60563SBard Liao struct sof_ipc4_fw_module *fw_module; 243511f60563SBard Liao struct sof_ipc4_msg msg = {{ 0 }}; 243611f60563SBard Liao 243711f60563SBard Liao dev_dbg(sdev->dev, "%s set copier sink %d format\n", 243811f60563SBard Liao src_widget->widget->name, sink_id); 243911f60563SBard Liao 244011f60563SBard Liao if (WIDGET_IS_DAI(src_widget->id)) { 244111f60563SBard Liao struct snd_sof_dai *dai = src_widget->private; 244211f60563SBard Liao 244311f60563SBard Liao src_config = dai->private; 244411f60563SBard Liao } else { 244511f60563SBard Liao src_config = src_widget->private; 244611f60563SBard Liao } 244711f60563SBard Liao 244811f60563SBard Liao fw_module = src_widget->module_info; 244911f60563SBard Liao 245011f60563SBard Liao format.sink_id = sink_id; 245111f60563SBard Liao memcpy(&format.source_fmt, &src_config->audio_fmt, sizeof(format.source_fmt)); 2452648fea12SChao Song 2453648fea12SChao Song pin_fmt = sof_ipc4_get_input_pin_audio_fmt(sink_widget, sink_id); 2454648fea12SChao Song if (!pin_fmt) { 2455648fea12SChao Song dev_err(sdev->dev, "Unable to get pin %d format for %s", 2456648fea12SChao Song sink_id, sink_widget->widget->name); 2457648fea12SChao Song return -EINVAL; 2458648fea12SChao Song } 2459648fea12SChao Song 2460648fea12SChao Song memcpy(&format.sink_fmt, pin_fmt, sizeof(format.sink_fmt)); 2461648fea12SChao Song 246211f60563SBard Liao msg.data_size = sizeof(format); 246311f60563SBard Liao msg.data_ptr = &format; 246411f60563SBard Liao 24657a975e9bSPeter Ujfalusi msg.primary = fw_module->man4_module_entry.id; 24667a975e9bSPeter Ujfalusi msg.primary |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id); 24677a975e9bSPeter Ujfalusi msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); 24687a975e9bSPeter Ujfalusi msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG); 246911f60563SBard Liao 24707a975e9bSPeter Ujfalusi msg.extension = 247111f60563SBard Liao SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_COPIER_MODULE_CFG_PARAM_SET_SINK_FORMAT); 247211f60563SBard Liao 24737a975e9bSPeter Ujfalusi return iops->set_get_data(sdev, &msg, msg.data_size, true); 247411f60563SBard Liao } 247511f60563SBard Liao 24763acd5270SRanjani Sridharan static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route *sroute) 24773acd5270SRanjani Sridharan { 24783acd5270SRanjani Sridharan struct snd_sof_widget *src_widget = sroute->src_widget; 24793acd5270SRanjani Sridharan struct snd_sof_widget *sink_widget = sroute->sink_widget; 2480ca5ce0caSJyri Sarha struct snd_sof_widget *src_pipe_widget = src_widget->spipe->pipe_widget; 2481ca5ce0caSJyri Sarha struct snd_sof_widget *sink_pipe_widget = sink_widget->spipe->pipe_widget; 24823acd5270SRanjani Sridharan struct sof_ipc4_fw_module *src_fw_module = src_widget->module_info; 24833acd5270SRanjani Sridharan struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info; 2484ca5ce0caSJyri Sarha struct sof_ipc4_pipeline *src_pipeline = src_pipe_widget->private; 2485ca5ce0caSJyri Sarha struct sof_ipc4_pipeline *sink_pipeline = sink_pipe_widget->private; 24863acd5270SRanjani Sridharan struct sof_ipc4_msg msg = {{ 0 }}; 24873acd5270SRanjani Sridharan u32 header, extension; 24883acd5270SRanjani Sridharan int ret; 24893acd5270SRanjani Sridharan 2490ca5ce0caSJyri Sarha /* no route set up if chain DMA is used */ 2491ca5ce0caSJyri Sarha if (src_pipeline->use_chain_dma || sink_pipeline->use_chain_dma) { 2492ca5ce0caSJyri Sarha if (!src_pipeline->use_chain_dma || !sink_pipeline->use_chain_dma) { 2493ca5ce0caSJyri Sarha dev_err(sdev->dev, 2494ca5ce0caSJyri Sarha "use_chain_dma must be set for both src %s and sink %s pipelines\n", 2495ca5ce0caSJyri Sarha src_widget->widget->name, sink_widget->widget->name); 2496ca5ce0caSJyri Sarha return -EINVAL; 2497ca5ce0caSJyri Sarha } 2498ca5ce0caSJyri Sarha return 0; 2499ca5ce0caSJyri Sarha } 2500ca5ce0caSJyri Sarha 2501e3720f92SGuennadi Liakhovetski if (!src_fw_module || !sink_fw_module) { 2502de6aa72bSPeter Ujfalusi dev_err(sdev->dev, 2503de6aa72bSPeter Ujfalusi "cannot bind %s -> %s, no firmware module for: %s%s\n", 2504de6aa72bSPeter Ujfalusi src_widget->widget->name, sink_widget->widget->name, 2505de6aa72bSPeter Ujfalusi src_fw_module ? "" : " source", 2506de6aa72bSPeter Ujfalusi sink_fw_module ? "" : " sink"); 2507de6aa72bSPeter Ujfalusi 2508e3720f92SGuennadi Liakhovetski return -ENODEV; 2509e3720f92SGuennadi Liakhovetski } 2510e3720f92SGuennadi Liakhovetski 2511c84443dbSChao Song sroute->src_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget, 2512bb79f2a6SRanjani Sridharan SOF_PIN_TYPE_OUTPUT); 2513c84443dbSChao Song if (sroute->src_queue_id < 0) { 2514c84443dbSChao Song dev_err(sdev->dev, "failed to get queue ID for source widget: %s\n", 2515c84443dbSChao Song src_widget->widget->name); 2516c84443dbSChao Song return sroute->src_queue_id; 2517c84443dbSChao Song } 2518c84443dbSChao Song 2519c84443dbSChao Song sroute->dst_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget, 2520bb79f2a6SRanjani Sridharan SOF_PIN_TYPE_INPUT); 2521c84443dbSChao Song if (sroute->dst_queue_id < 0) { 2522c84443dbSChao Song dev_err(sdev->dev, "failed to get queue ID for sink widget: %s\n", 2523c84443dbSChao Song sink_widget->widget->name); 2524c84443dbSChao Song sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id, 2525bb79f2a6SRanjani Sridharan SOF_PIN_TYPE_OUTPUT); 2526c84443dbSChao Song return sroute->dst_queue_id; 2527c84443dbSChao Song } 2528c84443dbSChao Song 252911f60563SBard Liao /* Pin 0 format is already set during copier module init */ 253011f60563SBard Liao if (sroute->src_queue_id > 0 && WIDGET_IS_COPIER(src_widget->id)) { 253111f60563SBard Liao ret = sof_ipc4_set_copier_sink_format(sdev, src_widget, sink_widget, 253211f60563SBard Liao sroute->src_queue_id); 253311f60563SBard Liao if (ret < 0) { 253411f60563SBard Liao dev_err(sdev->dev, "failed to set sink format for %s source queue ID %d\n", 253511f60563SBard Liao src_widget->widget->name, sroute->src_queue_id); 253611f60563SBard Liao goto out; 253711f60563SBard Liao } 253811f60563SBard Liao } 253911f60563SBard Liao 2540c84443dbSChao Song dev_dbg(sdev->dev, "bind %s:%d -> %s:%d\n", 2541c84443dbSChao Song src_widget->widget->name, sroute->src_queue_id, 2542c84443dbSChao Song sink_widget->widget->name, sroute->dst_queue_id); 25433acd5270SRanjani Sridharan 25443acd5270SRanjani Sridharan header = src_fw_module->man4_module_entry.id; 25453acd5270SRanjani Sridharan header |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id); 25463acd5270SRanjani Sridharan header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_BIND); 25473acd5270SRanjani Sridharan header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); 25483acd5270SRanjani Sridharan header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG); 25493acd5270SRanjani Sridharan 25503acd5270SRanjani Sridharan extension = sink_fw_module->man4_module_entry.id; 25513acd5270SRanjani Sridharan extension |= SOF_IPC4_MOD_EXT_DST_MOD_INSTANCE(sink_widget->instance_id); 2552c84443dbSChao Song extension |= SOF_IPC4_MOD_EXT_DST_MOD_QUEUE_ID(sroute->dst_queue_id); 2553c84443dbSChao Song extension |= SOF_IPC4_MOD_EXT_SRC_MOD_QUEUE_ID(sroute->src_queue_id); 25543acd5270SRanjani Sridharan 25553acd5270SRanjani Sridharan msg.primary = header; 25563acd5270SRanjani Sridharan msg.extension = extension; 25573acd5270SRanjani Sridharan 2558367fd6ffSCurtis Malainey ret = sof_ipc_tx_message_no_reply(sdev->ipc, &msg, 0); 2559c84443dbSChao Song if (ret < 0) { 2560b796ff3bSRanjani Sridharan dev_err(sdev->dev, "failed to bind modules %s:%d -> %s:%d\n", 2561b796ff3bSRanjani Sridharan src_widget->widget->name, sroute->src_queue_id, 2562b796ff3bSRanjani Sridharan sink_widget->widget->name, sroute->dst_queue_id); 256311f60563SBard Liao goto out; 2564c84443dbSChao Song } 2565c84443dbSChao Song 25663acd5270SRanjani Sridharan return ret; 256711f60563SBard Liao 256811f60563SBard Liao out: 2569bb79f2a6SRanjani Sridharan sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id, SOF_PIN_TYPE_OUTPUT); 2570bb79f2a6SRanjani Sridharan sof_ipc4_put_queue_id(sink_widget, sroute->dst_queue_id, SOF_PIN_TYPE_INPUT); 257111f60563SBard Liao return ret; 25723acd5270SRanjani Sridharan } 25733acd5270SRanjani Sridharan 25743acd5270SRanjani Sridharan static int sof_ipc4_route_free(struct snd_sof_dev *sdev, struct snd_sof_route *sroute) 25753acd5270SRanjani Sridharan { 25763acd5270SRanjani Sridharan struct snd_sof_widget *src_widget = sroute->src_widget; 25773acd5270SRanjani Sridharan struct snd_sof_widget *sink_widget = sroute->sink_widget; 25783acd5270SRanjani Sridharan struct sof_ipc4_fw_module *src_fw_module = src_widget->module_info; 25793acd5270SRanjani Sridharan struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info; 25803acd5270SRanjani Sridharan struct sof_ipc4_msg msg = {{ 0 }}; 2581ca5ce0caSJyri Sarha struct snd_sof_widget *src_pipe_widget = src_widget->spipe->pipe_widget; 2582ca5ce0caSJyri Sarha struct snd_sof_widget *sink_pipe_widget = sink_widget->spipe->pipe_widget; 2583ca5ce0caSJyri Sarha struct sof_ipc4_pipeline *src_pipeline = src_pipe_widget->private; 2584ca5ce0caSJyri Sarha struct sof_ipc4_pipeline *sink_pipeline = sink_pipe_widget->private; 25853acd5270SRanjani Sridharan u32 header, extension; 25869a62d87aSRanjani Sridharan int ret = 0; 25873acd5270SRanjani Sridharan 2588ca5ce0caSJyri Sarha /* no route is set up if chain DMA is used */ 2589ca5ce0caSJyri Sarha if (src_pipeline->use_chain_dma || sink_pipeline->use_chain_dma) 2590ca5ce0caSJyri Sarha return 0; 2591ca5ce0caSJyri Sarha 2592c84443dbSChao Song dev_dbg(sdev->dev, "unbind modules %s:%d -> %s:%d\n", 2593c84443dbSChao Song src_widget->widget->name, sroute->src_queue_id, 2594c84443dbSChao Song sink_widget->widget->name, sroute->dst_queue_id); 25953acd5270SRanjani Sridharan 25969a62d87aSRanjani Sridharan /* 25979a62d87aSRanjani Sridharan * routes belonging to the same pipeline will be disconnected by the FW when the pipeline 25989a62d87aSRanjani Sridharan * is freed. So avoid sending this IPC which will be ignored by the FW anyway. 25999a62d87aSRanjani Sridharan */ 26009c04363dSRanjani Sridharan if (src_widget->spipe->pipe_widget == sink_widget->spipe->pipe_widget) 26019a62d87aSRanjani Sridharan goto out; 26029a62d87aSRanjani Sridharan 26033acd5270SRanjani Sridharan header = src_fw_module->man4_module_entry.id; 26043acd5270SRanjani Sridharan header |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id); 26053acd5270SRanjani Sridharan header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_UNBIND); 26063acd5270SRanjani Sridharan header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); 26073acd5270SRanjani Sridharan header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG); 26083acd5270SRanjani Sridharan 26093acd5270SRanjani Sridharan extension = sink_fw_module->man4_module_entry.id; 26103acd5270SRanjani Sridharan extension |= SOF_IPC4_MOD_EXT_DST_MOD_INSTANCE(sink_widget->instance_id); 2611c84443dbSChao Song extension |= SOF_IPC4_MOD_EXT_DST_MOD_QUEUE_ID(sroute->dst_queue_id); 2612c84443dbSChao Song extension |= SOF_IPC4_MOD_EXT_SRC_MOD_QUEUE_ID(sroute->src_queue_id); 26133acd5270SRanjani Sridharan 26143acd5270SRanjani Sridharan msg.primary = header; 26153acd5270SRanjani Sridharan msg.extension = extension; 26163acd5270SRanjani Sridharan 2617367fd6ffSCurtis Malainey ret = sof_ipc_tx_message_no_reply(sdev->ipc, &msg, 0); 26183acd5270SRanjani Sridharan if (ret < 0) 2619b796ff3bSRanjani Sridharan dev_err(sdev->dev, "failed to unbind modules %s:%d -> %s:%d\n", 2620b796ff3bSRanjani Sridharan src_widget->widget->name, sroute->src_queue_id, 2621b796ff3bSRanjani Sridharan sink_widget->widget->name, sroute->dst_queue_id); 26229a62d87aSRanjani Sridharan out: 2623bb79f2a6SRanjani Sridharan sof_ipc4_put_queue_id(sink_widget, sroute->dst_queue_id, SOF_PIN_TYPE_INPUT); 2624bb79f2a6SRanjani Sridharan sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id, SOF_PIN_TYPE_OUTPUT); 2625c84443dbSChao Song 26263acd5270SRanjani Sridharan return ret; 26273acd5270SRanjani Sridharan } 26283acd5270SRanjani Sridharan 2629acf48a1fSRanjani Sridharan static int sof_ipc4_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget, 2630acf48a1fSRanjani Sridharan unsigned int flags, struct snd_sof_dai_config_data *data) 2631acf48a1fSRanjani Sridharan { 26329c04363dSRanjani Sridharan struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget; 2633acf48a1fSRanjani Sridharan struct sof_ipc4_pipeline *pipeline = pipe_widget->private; 2634acf48a1fSRanjani Sridharan struct snd_sof_dai *dai = swidget->private; 2635acf48a1fSRanjani Sridharan struct sof_ipc4_gtw_attributes *gtw_attr; 2636acf48a1fSRanjani Sridharan struct sof_ipc4_copier_data *copier_data; 2637acf48a1fSRanjani Sridharan struct sof_ipc4_copier *ipc4_copier; 2638acf48a1fSRanjani Sridharan 2639acf48a1fSRanjani Sridharan if (!dai || !dai->private) { 2640acf48a1fSRanjani Sridharan dev_err(sdev->dev, "Invalid DAI or DAI private data for %s\n", 2641acf48a1fSRanjani Sridharan swidget->widget->name); 2642acf48a1fSRanjani Sridharan return -EINVAL; 2643acf48a1fSRanjani Sridharan } 2644acf48a1fSRanjani Sridharan 2645acf48a1fSRanjani Sridharan ipc4_copier = (struct sof_ipc4_copier *)dai->private; 2646acf48a1fSRanjani Sridharan copier_data = &ipc4_copier->data; 2647acf48a1fSRanjani Sridharan 2648acf48a1fSRanjani Sridharan if (!data) 2649acf48a1fSRanjani Sridharan return 0; 2650acf48a1fSRanjani Sridharan 2651acf48a1fSRanjani Sridharan switch (ipc4_copier->dai_type) { 2652acf48a1fSRanjani Sridharan case SOF_DAI_INTEL_HDA: 2653ca5ce0caSJyri Sarha if (pipeline->use_chain_dma) { 2654ca5ce0caSJyri Sarha pipeline->msg.primary &= ~SOF_IPC4_GLB_CHAIN_DMA_LINK_ID_MASK; 2655ca5ce0caSJyri Sarha pipeline->msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_LINK_ID(data->dai_data); 2656ca5ce0caSJyri Sarha break; 2657ca5ce0caSJyri Sarha } 2658acf48a1fSRanjani Sridharan gtw_attr = ipc4_copier->gtw_attr; 2659acf48a1fSRanjani Sridharan gtw_attr->lp_buffer_alloc = pipeline->lp_mode; 2660acf48a1fSRanjani Sridharan fallthrough; 2661acf48a1fSRanjani Sridharan case SOF_DAI_INTEL_ALH: 2662b66bfc3aSRanjani Sridharan /* 2663b66bfc3aSRanjani Sridharan * Do not clear the node ID when this op is invoked with 2664b66bfc3aSRanjani Sridharan * SOF_DAI_CONFIG_FLAGS_HW_FREE. It is needed to free the group_ida during 2665b66bfc3aSRanjani Sridharan * unprepare. 2666b66bfc3aSRanjani Sridharan */ 2667b66bfc3aSRanjani Sridharan if (flags & SOF_DAI_CONFIG_FLAGS_HW_PARAMS) { 2668acf48a1fSRanjani Sridharan copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK; 2669acf48a1fSRanjani Sridharan copier_data->gtw_cfg.node_id |= SOF_IPC4_NODE_INDEX(data->dai_data); 2670b66bfc3aSRanjani Sridharan } 2671acf48a1fSRanjani Sridharan break; 2672acf48a1fSRanjani Sridharan case SOF_DAI_INTEL_DMIC: 2673acf48a1fSRanjani Sridharan case SOF_DAI_INTEL_SSP: 2674acf48a1fSRanjani Sridharan /* nothing to do for SSP/DMIC */ 2675acf48a1fSRanjani Sridharan break; 2676acf48a1fSRanjani Sridharan default: 2677acf48a1fSRanjani Sridharan dev_err(sdev->dev, "%s: unsupported dai type %d\n", __func__, 2678acf48a1fSRanjani Sridharan ipc4_copier->dai_type); 2679acf48a1fSRanjani Sridharan return -EINVAL; 2680acf48a1fSRanjani Sridharan } 2681acf48a1fSRanjani Sridharan 2682acf48a1fSRanjani Sridharan return 0; 2683acf48a1fSRanjani Sridharan } 2684acf48a1fSRanjani Sridharan 2685323aa1f0SRanjani Sridharan static int sof_ipc4_parse_manifest(struct snd_soc_component *scomp, int index, 2686323aa1f0SRanjani Sridharan struct snd_soc_tplg_manifest *man) 2687323aa1f0SRanjani Sridharan { 2688323aa1f0SRanjani Sridharan struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 2689323aa1f0SRanjani Sridharan struct sof_ipc4_fw_data *ipc4_data = sdev->private; 2690323aa1f0SRanjani Sridharan struct sof_manifest_tlv *manifest_tlv; 2691323aa1f0SRanjani Sridharan struct sof_manifest *manifest; 2692323aa1f0SRanjani Sridharan u32 size = le32_to_cpu(man->priv.size); 2693323aa1f0SRanjani Sridharan u8 *man_ptr = man->priv.data; 2694323aa1f0SRanjani Sridharan u32 len_check; 2695323aa1f0SRanjani Sridharan int i; 2696323aa1f0SRanjani Sridharan 2697323aa1f0SRanjani Sridharan if (!size || size < SOF_IPC4_TPLG_ABI_SIZE) { 2698323aa1f0SRanjani Sridharan dev_err(scomp->dev, "%s: Invalid topology ABI size: %u\n", 2699323aa1f0SRanjani Sridharan __func__, size); 2700323aa1f0SRanjani Sridharan return -EINVAL; 2701323aa1f0SRanjani Sridharan } 2702323aa1f0SRanjani Sridharan 2703323aa1f0SRanjani Sridharan manifest = (struct sof_manifest *)man_ptr; 2704323aa1f0SRanjani Sridharan 2705323aa1f0SRanjani Sridharan dev_info(scomp->dev, 2706323aa1f0SRanjani Sridharan "Topology: ABI %d:%d:%d Kernel ABI %u:%u:%u\n", 2707323aa1f0SRanjani Sridharan le16_to_cpu(manifest->abi_major), le16_to_cpu(manifest->abi_minor), 2708323aa1f0SRanjani Sridharan le16_to_cpu(manifest->abi_patch), 2709323aa1f0SRanjani Sridharan SOF_ABI_MAJOR, SOF_ABI_MINOR, SOF_ABI_PATCH); 2710323aa1f0SRanjani Sridharan 2711323aa1f0SRanjani Sridharan /* TODO: Add ABI compatibility check */ 2712323aa1f0SRanjani Sridharan 2713323aa1f0SRanjani Sridharan /* no more data after the ABI version */ 2714323aa1f0SRanjani Sridharan if (size <= SOF_IPC4_TPLG_ABI_SIZE) 2715323aa1f0SRanjani Sridharan return 0; 2716323aa1f0SRanjani Sridharan 2717323aa1f0SRanjani Sridharan manifest_tlv = manifest->items; 2718323aa1f0SRanjani Sridharan len_check = sizeof(struct sof_manifest); 2719323aa1f0SRanjani Sridharan for (i = 0; i < le16_to_cpu(manifest->count); i++) { 2720323aa1f0SRanjani Sridharan len_check += sizeof(struct sof_manifest_tlv) + le32_to_cpu(manifest_tlv->size); 2721323aa1f0SRanjani Sridharan if (len_check > size) 2722323aa1f0SRanjani Sridharan return -EINVAL; 2723323aa1f0SRanjani Sridharan 2724323aa1f0SRanjani Sridharan switch (le32_to_cpu(manifest_tlv->type)) { 2725323aa1f0SRanjani Sridharan case SOF_MANIFEST_DATA_TYPE_NHLT: 2726323aa1f0SRanjani Sridharan /* no NHLT in BIOS, so use the one from topology manifest */ 2727323aa1f0SRanjani Sridharan if (ipc4_data->nhlt) 2728323aa1f0SRanjani Sridharan break; 2729323aa1f0SRanjani Sridharan ipc4_data->nhlt = devm_kmemdup(sdev->dev, manifest_tlv->data, 2730323aa1f0SRanjani Sridharan le32_to_cpu(manifest_tlv->size), GFP_KERNEL); 2731323aa1f0SRanjani Sridharan if (!ipc4_data->nhlt) 2732323aa1f0SRanjani Sridharan return -ENOMEM; 2733323aa1f0SRanjani Sridharan break; 2734323aa1f0SRanjani Sridharan default: 2735323aa1f0SRanjani Sridharan dev_warn(scomp->dev, "Skipping unknown manifest data type %d\n", 2736323aa1f0SRanjani Sridharan manifest_tlv->type); 2737323aa1f0SRanjani Sridharan break; 2738323aa1f0SRanjani Sridharan } 2739323aa1f0SRanjani Sridharan man_ptr += sizeof(struct sof_manifest_tlv) + le32_to_cpu(manifest_tlv->size); 2740323aa1f0SRanjani Sridharan manifest_tlv = (struct sof_manifest_tlv *)man_ptr; 2741323aa1f0SRanjani Sridharan } 2742323aa1f0SRanjani Sridharan 2743323aa1f0SRanjani Sridharan return 0; 2744323aa1f0SRanjani Sridharan } 2745323aa1f0SRanjani Sridharan 27469e2b5d33SRanjani Sridharan static int sof_ipc4_dai_get_clk(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, int clk_type) 27479e2b5d33SRanjani Sridharan { 27489e2b5d33SRanjani Sridharan struct sof_ipc4_copier *ipc4_copier = dai->private; 27499e2b5d33SRanjani Sridharan struct snd_soc_tplg_hw_config *hw_config; 27509e2b5d33SRanjani Sridharan struct snd_sof_dai_link *slink; 27519e2b5d33SRanjani Sridharan bool dai_link_found = false; 27529e2b5d33SRanjani Sridharan bool hw_cfg_found = false; 27539e2b5d33SRanjani Sridharan int i; 27549e2b5d33SRanjani Sridharan 27559e2b5d33SRanjani Sridharan if (!ipc4_copier) 27569e2b5d33SRanjani Sridharan return 0; 27579e2b5d33SRanjani Sridharan 27589e2b5d33SRanjani Sridharan list_for_each_entry(slink, &sdev->dai_link_list, list) { 27599e2b5d33SRanjani Sridharan if (!strcmp(slink->link->name, dai->name)) { 27609e2b5d33SRanjani Sridharan dai_link_found = true; 27619e2b5d33SRanjani Sridharan break; 27629e2b5d33SRanjani Sridharan } 27639e2b5d33SRanjani Sridharan } 27649e2b5d33SRanjani Sridharan 27659e2b5d33SRanjani Sridharan if (!dai_link_found) { 27669e2b5d33SRanjani Sridharan dev_err(sdev->dev, "no DAI link found for DAI %s\n", dai->name); 27679e2b5d33SRanjani Sridharan return -EINVAL; 27689e2b5d33SRanjani Sridharan } 27699e2b5d33SRanjani Sridharan 27709e2b5d33SRanjani Sridharan for (i = 0; i < slink->num_hw_configs; i++) { 27719e2b5d33SRanjani Sridharan hw_config = &slink->hw_configs[i]; 27729e2b5d33SRanjani Sridharan if (dai->current_config == le32_to_cpu(hw_config->id)) { 27739e2b5d33SRanjani Sridharan hw_cfg_found = true; 27749e2b5d33SRanjani Sridharan break; 27759e2b5d33SRanjani Sridharan } 27769e2b5d33SRanjani Sridharan } 27779e2b5d33SRanjani Sridharan 27789e2b5d33SRanjani Sridharan if (!hw_cfg_found) { 27799e2b5d33SRanjani Sridharan dev_err(sdev->dev, "no matching hw_config found for DAI %s\n", dai->name); 27809e2b5d33SRanjani Sridharan return -EINVAL; 27819e2b5d33SRanjani Sridharan } 27829e2b5d33SRanjani Sridharan 27839e2b5d33SRanjani Sridharan switch (ipc4_copier->dai_type) { 27849e2b5d33SRanjani Sridharan case SOF_DAI_INTEL_SSP: 27859e2b5d33SRanjani Sridharan switch (clk_type) { 27869e2b5d33SRanjani Sridharan case SOF_DAI_CLK_INTEL_SSP_MCLK: 27879e2b5d33SRanjani Sridharan return le32_to_cpu(hw_config->mclk_rate); 27889e2b5d33SRanjani Sridharan case SOF_DAI_CLK_INTEL_SSP_BCLK: 27899e2b5d33SRanjani Sridharan return le32_to_cpu(hw_config->bclk_rate); 27909e2b5d33SRanjani Sridharan default: 27919e2b5d33SRanjani Sridharan dev_err(sdev->dev, "Invalid clk type for SSP %d\n", clk_type); 27929e2b5d33SRanjani Sridharan break; 27939e2b5d33SRanjani Sridharan } 27949e2b5d33SRanjani Sridharan break; 27959e2b5d33SRanjani Sridharan default: 27969e2b5d33SRanjani Sridharan dev_err(sdev->dev, "DAI type %d not supported yet!\n", ipc4_copier->dai_type); 27979e2b5d33SRanjani Sridharan break; 27989e2b5d33SRanjani Sridharan } 27999e2b5d33SRanjani Sridharan 28009e2b5d33SRanjani Sridharan return -EINVAL; 28019e2b5d33SRanjani Sridharan } 28029e2b5d33SRanjani Sridharan 280318cd1f32SPeter Ujfalusi static int sof_ipc4_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verify) 280418cd1f32SPeter Ujfalusi { 280518cd1f32SPeter Ujfalusi struct snd_sof_pcm *spcm; 280618cd1f32SPeter Ujfalusi int dir, ret; 280718cd1f32SPeter Ujfalusi 280818cd1f32SPeter Ujfalusi /* 280918cd1f32SPeter Ujfalusi * This function is called during system suspend, we need to make sure 281018cd1f32SPeter Ujfalusi * that all streams have been freed up. 281118cd1f32SPeter Ujfalusi * Freeing might have been skipped when xrun happened just at the start 281218cd1f32SPeter Ujfalusi * of the suspend and it sent a SNDRV_PCM_TRIGGER_STOP to the active 281318cd1f32SPeter Ujfalusi * stream. This will call sof_pcm_stream_free() with 281418cd1f32SPeter Ujfalusi * free_widget_list = false which will leave the kernel and firmware out 281518cd1f32SPeter Ujfalusi * of sync during suspend/resume. 281618cd1f32SPeter Ujfalusi * 281718cd1f32SPeter Ujfalusi * This will also make sure that paused streams handled correctly. 281818cd1f32SPeter Ujfalusi */ 281918cd1f32SPeter Ujfalusi list_for_each_entry(spcm, &sdev->pcm_list, list) { 282018cd1f32SPeter Ujfalusi for_each_pcm_streams(dir) { 282118cd1f32SPeter Ujfalusi struct snd_pcm_substream *substream = spcm->stream[dir].substream; 282218cd1f32SPeter Ujfalusi 282382b18242SRanjani Sridharan if (!substream || !substream->runtime || spcm->stream[dir].suspend_ignored) 282418cd1f32SPeter Ujfalusi continue; 282518cd1f32SPeter Ujfalusi 282618cd1f32SPeter Ujfalusi if (spcm->stream[dir].list) { 282718cd1f32SPeter Ujfalusi ret = sof_pcm_stream_free(sdev, substream, spcm, dir, true); 282818cd1f32SPeter Ujfalusi if (ret < 0) 282918cd1f32SPeter Ujfalusi return ret; 283018cd1f32SPeter Ujfalusi } 283118cd1f32SPeter Ujfalusi } 283218cd1f32SPeter Ujfalusi } 283318cd1f32SPeter Ujfalusi return 0; 283418cd1f32SPeter Ujfalusi } 283518cd1f32SPeter Ujfalusi 2836e380c907SRanjani Sridharan static int sof_ipc4_link_setup(struct snd_sof_dev *sdev, struct snd_soc_dai_link *link) 2837e380c907SRanjani Sridharan { 2838e380c907SRanjani Sridharan if (link->no_pcm) 2839e380c907SRanjani Sridharan return 0; 2840e380c907SRanjani Sridharan 2841e380c907SRanjani Sridharan /* 2842e380c907SRanjani Sridharan * set default trigger order for all links. Exceptions to 2843e380c907SRanjani Sridharan * the rule will be handled in sof_pcm_dai_link_fixup() 2844e380c907SRanjani Sridharan * For playback, the sequence is the following: start BE, 2845e380c907SRanjani Sridharan * start FE, stop FE, stop BE; for Capture the sequence is 2846e380c907SRanjani Sridharan * inverted start FE, start BE, stop BE, stop FE 2847e380c907SRanjani Sridharan */ 2848e380c907SRanjani Sridharan link->trigger[SNDRV_PCM_STREAM_PLAYBACK] = SND_SOC_DPCM_TRIGGER_POST; 2849e380c907SRanjani Sridharan link->trigger[SNDRV_PCM_STREAM_CAPTURE] = SND_SOC_DPCM_TRIGGER_PRE; 2850e380c907SRanjani Sridharan 2851e380c907SRanjani Sridharan return 0; 2852e380c907SRanjani Sridharan } 2853e380c907SRanjani Sridharan 28547d573425SBard Liao static enum sof_tokens common_copier_token_list[] = { 28552cabd02bSRanjani Sridharan SOF_COMP_TOKENS, 28562cabd02bSRanjani Sridharan SOF_AUDIO_FMT_NUM_TOKENS, 28572cabd02bSRanjani Sridharan SOF_IN_AUDIO_FORMAT_TOKENS, 28582cabd02bSRanjani Sridharan SOF_OUT_AUDIO_FORMAT_TOKENS, 2859594c1bb9SRanjani Sridharan SOF_COPIER_DEEP_BUFFER_TOKENS, 28602cabd02bSRanjani Sridharan SOF_COPIER_TOKENS, 28612cabd02bSRanjani Sridharan SOF_COMP_EXT_TOKENS, 28622cabd02bSRanjani Sridharan }; 28632cabd02bSRanjani Sridharan 286490e89155SRanjani Sridharan static enum sof_tokens pipeline_token_list[] = { 286590e89155SRanjani Sridharan SOF_SCHED_TOKENS, 286690e89155SRanjani Sridharan SOF_PIPELINE_TOKENS, 286790e89155SRanjani Sridharan }; 286890e89155SRanjani Sridharan 2869abfb536bSRanjani Sridharan static enum sof_tokens dai_token_list[] = { 2870abfb536bSRanjani Sridharan SOF_COMP_TOKENS, 2871abfb536bSRanjani Sridharan SOF_AUDIO_FMT_NUM_TOKENS, 2872abfb536bSRanjani Sridharan SOF_IN_AUDIO_FORMAT_TOKENS, 2873abfb536bSRanjani Sridharan SOF_OUT_AUDIO_FORMAT_TOKENS, 2874abfb536bSRanjani Sridharan SOF_COPIER_TOKENS, 2875abfb536bSRanjani Sridharan SOF_DAI_TOKENS, 2876abfb536bSRanjani Sridharan SOF_COMP_EXT_TOKENS, 2877abfb536bSRanjani Sridharan }; 2878abfb536bSRanjani Sridharan 28794f838ab2SRanjani Sridharan static enum sof_tokens pga_token_list[] = { 28804f838ab2SRanjani Sridharan SOF_COMP_TOKENS, 28814f838ab2SRanjani Sridharan SOF_GAIN_TOKENS, 28824f838ab2SRanjani Sridharan SOF_AUDIO_FMT_NUM_TOKENS, 28834f838ab2SRanjani Sridharan SOF_IN_AUDIO_FORMAT_TOKENS, 28847ab6b1e8SRanjani Sridharan SOF_OUT_AUDIO_FORMAT_TOKENS, 28854f838ab2SRanjani Sridharan SOF_COMP_EXT_TOKENS, 28864f838ab2SRanjani Sridharan }; 28874f838ab2SRanjani Sridharan 28884d4ba014SRanjani Sridharan static enum sof_tokens mixer_token_list[] = { 28894d4ba014SRanjani Sridharan SOF_COMP_TOKENS, 28904d4ba014SRanjani Sridharan SOF_AUDIO_FMT_NUM_TOKENS, 28914d4ba014SRanjani Sridharan SOF_IN_AUDIO_FORMAT_TOKENS, 28927ab6b1e8SRanjani Sridharan SOF_OUT_AUDIO_FORMAT_TOKENS, 28934d4ba014SRanjani Sridharan SOF_COMP_EXT_TOKENS, 28944d4ba014SRanjani Sridharan }; 28954d4ba014SRanjani Sridharan 2896b85f4fc4SRander Wang static enum sof_tokens src_token_list[] = { 2897b85f4fc4SRander Wang SOF_COMP_TOKENS, 2898b85f4fc4SRander Wang SOF_SRC_TOKENS, 2899b85f4fc4SRander Wang SOF_AUDIO_FMT_NUM_TOKENS, 2900b85f4fc4SRander Wang SOF_IN_AUDIO_FORMAT_TOKENS, 29017ab6b1e8SRanjani Sridharan SOF_OUT_AUDIO_FORMAT_TOKENS, 2902b85f4fc4SRander Wang SOF_COMP_EXT_TOKENS, 2903b85f4fc4SRander Wang }; 2904b85f4fc4SRander Wang 29057711a2bbSLibin Yang static enum sof_tokens process_token_list[] = { 29067711a2bbSLibin Yang SOF_COMP_TOKENS, 29077711a2bbSLibin Yang SOF_AUDIO_FMT_NUM_TOKENS, 29087711a2bbSLibin Yang SOF_IN_AUDIO_FORMAT_TOKENS, 29097711a2bbSLibin Yang SOF_OUT_AUDIO_FORMAT_TOKENS, 291090e89155SRanjani Sridharan SOF_COMP_EXT_TOKENS, 291190e89155SRanjani Sridharan }; 291290e89155SRanjani Sridharan 291390e89155SRanjani Sridharan static const struct sof_ipc_tplg_widget_ops tplg_ipc4_widget_ops[SND_SOC_DAPM_TYPE_COUNT] = { 29142cabd02bSRanjani Sridharan [snd_soc_dapm_aif_in] = {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm, 29157d573425SBard Liao common_copier_token_list, ARRAY_SIZE(common_copier_token_list), 29167d573425SBard Liao NULL, sof_ipc4_prepare_copier_module, 2917904c48c4SRanjani Sridharan sof_ipc4_unprepare_copier_module}, 29182cabd02bSRanjani Sridharan [snd_soc_dapm_aif_out] = {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm, 29197d573425SBard Liao common_copier_token_list, ARRAY_SIZE(common_copier_token_list), 29207d573425SBard Liao NULL, sof_ipc4_prepare_copier_module, 2921904c48c4SRanjani Sridharan sof_ipc4_unprepare_copier_module}, 2922abfb536bSRanjani Sridharan [snd_soc_dapm_dai_in] = {sof_ipc4_widget_setup_comp_dai, sof_ipc4_widget_free_comp_dai, 2923acf52594SRanjani Sridharan dai_token_list, ARRAY_SIZE(dai_token_list), NULL, 2924acf52594SRanjani Sridharan sof_ipc4_prepare_copier_module, 2925acf52594SRanjani Sridharan sof_ipc4_unprepare_copier_module}, 2926abfb536bSRanjani Sridharan [snd_soc_dapm_dai_out] = {sof_ipc4_widget_setup_comp_dai, sof_ipc4_widget_free_comp_dai, 2927acf52594SRanjani Sridharan dai_token_list, ARRAY_SIZE(dai_token_list), NULL, 2928acf52594SRanjani Sridharan sof_ipc4_prepare_copier_module, 2929acf52594SRanjani Sridharan sof_ipc4_unprepare_copier_module}, 29307d573425SBard Liao [snd_soc_dapm_buffer] = {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm, 29317d573425SBard Liao common_copier_token_list, ARRAY_SIZE(common_copier_token_list), 29327d573425SBard Liao NULL, sof_ipc4_prepare_copier_module, 29337d573425SBard Liao sof_ipc4_unprepare_copier_module}, 2934a29b2d02SBard Liao [snd_soc_dapm_scheduler] = {sof_ipc4_widget_setup_comp_pipeline, 2935a29b2d02SBard Liao sof_ipc4_widget_free_comp_pipeline, 293690e89155SRanjani Sridharan pipeline_token_list, ARRAY_SIZE(pipeline_token_list), NULL, 293790e89155SRanjani Sridharan NULL, NULL}, 2938dc4fc0aeSLibin Yang [snd_soc_dapm_pga] = {sof_ipc4_widget_setup_comp_pga, sof_ipc4_widget_free_comp_pga, 29394f838ab2SRanjani Sridharan pga_token_list, ARRAY_SIZE(pga_token_list), NULL, 29404f838ab2SRanjani Sridharan sof_ipc4_prepare_gain_module, 2941711d0427SBard Liao NULL}, 2942dc4fc0aeSLibin Yang [snd_soc_dapm_mixer] = {sof_ipc4_widget_setup_comp_mixer, sof_ipc4_widget_free_comp_mixer, 29434d4ba014SRanjani Sridharan mixer_token_list, ARRAY_SIZE(mixer_token_list), 29444d4ba014SRanjani Sridharan NULL, sof_ipc4_prepare_mixer_module, 2945711d0427SBard Liao NULL}, 2946b85f4fc4SRander Wang [snd_soc_dapm_src] = {sof_ipc4_widget_setup_comp_src, sof_ipc4_widget_free_comp_src, 2947b85f4fc4SRander Wang src_token_list, ARRAY_SIZE(src_token_list), 2948b85f4fc4SRander Wang NULL, sof_ipc4_prepare_src_module, 2949b85f4fc4SRander Wang NULL}, 29507711a2bbSLibin Yang [snd_soc_dapm_effect] = {sof_ipc4_widget_setup_comp_process, 29517711a2bbSLibin Yang sof_ipc4_widget_free_comp_process, 29527711a2bbSLibin Yang process_token_list, ARRAY_SIZE(process_token_list), 29537711a2bbSLibin Yang NULL, sof_ipc4_prepare_process_module, 29547711a2bbSLibin Yang NULL}, 295590e89155SRanjani Sridharan }; 295690e89155SRanjani Sridharan 295790e89155SRanjani Sridharan const struct sof_ipc_tplg_ops ipc4_tplg_ops = { 295890e89155SRanjani Sridharan .widget = tplg_ipc4_widget_ops, 295990e89155SRanjani Sridharan .token_list = ipc4_token_list, 2960d97964f8SRanjani Sridharan .control_setup = sof_ipc4_control_setup, 2961955e84fcSRanjani Sridharan .control = &tplg_ipc4_control_ops, 29626e9257a1SRanjani Sridharan .widget_setup = sof_ipc4_widget_setup, 29636e9257a1SRanjani Sridharan .widget_free = sof_ipc4_widget_free, 29643acd5270SRanjani Sridharan .route_setup = sof_ipc4_route_setup, 29653acd5270SRanjani Sridharan .route_free = sof_ipc4_route_free, 2966acf48a1fSRanjani Sridharan .dai_config = sof_ipc4_dai_config, 2967323aa1f0SRanjani Sridharan .parse_manifest = sof_ipc4_parse_manifest, 29689e2b5d33SRanjani Sridharan .dai_get_clk = sof_ipc4_dai_get_clk, 296918cd1f32SPeter Ujfalusi .tear_down_all_pipelines = sof_ipc4_tear_down_all_pipelines, 2970e380c907SRanjani Sridharan .link_setup = sof_ipc4_link_setup, 297190e89155SRanjani Sridharan }; 2972