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 // 990e89155SRanjani Sridharan #include <uapi/sound/sof/tokens.h> 1090e89155SRanjani Sridharan #include <sound/pcm_params.h> 1190e89155SRanjani Sridharan #include <sound/sof/ext_manifest4.h> 12aa84ffb7SRanjani Sridharan #include <sound/intel-nhlt.h> 1390e89155SRanjani Sridharan #include "sof-priv.h" 1490e89155SRanjani Sridharan #include "sof-audio.h" 1590e89155SRanjani Sridharan #include "ipc4-priv.h" 1690e89155SRanjani Sridharan #include "ipc4-topology.h" 1790e89155SRanjani Sridharan #include "ops.h" 1890e89155SRanjani Sridharan 19d97964f8SRanjani Sridharan #define SOF_IPC4_GAIN_PARAM_ID 0 20323aa1f0SRanjani Sridharan #define SOF_IPC4_TPLG_ABI_SIZE 6 21d97964f8SRanjani Sridharan 22a150345aSBard Liao static DEFINE_IDA(alh_group_ida); 23a2ba1f70SBard Liao static DEFINE_IDA(pipeline_ida); 24a150345aSBard Liao 2590e89155SRanjani Sridharan static const struct sof_topology_token ipc4_sched_tokens[] = { 2690e89155SRanjani Sridharan {SOF_TKN_SCHED_LP_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 2790e89155SRanjani Sridharan offsetof(struct sof_ipc4_pipeline, lp_mode)} 2890e89155SRanjani Sridharan }; 2990e89155SRanjani Sridharan 3090e89155SRanjani Sridharan static const struct sof_topology_token pipeline_tokens[] = { 3190e89155SRanjani Sridharan {SOF_TKN_SCHED_DYNAMIC_PIPELINE, SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16, 3290e89155SRanjani Sridharan offsetof(struct snd_sof_widget, dynamic_pipeline_widget)}, 3390e89155SRanjani Sridharan }; 3490e89155SRanjani Sridharan 352cabd02bSRanjani Sridharan static const struct sof_topology_token ipc4_comp_tokens[] = { 362cabd02bSRanjani Sridharan {SOF_TKN_COMP_CPC, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 372cabd02bSRanjani Sridharan offsetof(struct sof_ipc4_base_module_cfg, cpc)}, 382cabd02bSRanjani Sridharan {SOF_TKN_COMP_IS_PAGES, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 392cabd02bSRanjani Sridharan offsetof(struct sof_ipc4_base_module_cfg, is_pages)}, 402cabd02bSRanjani Sridharan }; 412cabd02bSRanjani Sridharan 422cabd02bSRanjani Sridharan static const struct sof_topology_token ipc4_audio_format_buffer_size_tokens[] = { 432cabd02bSRanjani Sridharan {SOF_TKN_CAVS_AUDIO_FORMAT_IBS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 442cabd02bSRanjani Sridharan offsetof(struct sof_ipc4_base_module_cfg, ibs)}, 452cabd02bSRanjani Sridharan {SOF_TKN_CAVS_AUDIO_FORMAT_OBS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 462cabd02bSRanjani Sridharan offsetof(struct sof_ipc4_base_module_cfg, obs)}, 472cabd02bSRanjani Sridharan }; 482cabd02bSRanjani Sridharan 492cabd02bSRanjani Sridharan static const struct sof_topology_token ipc4_in_audio_format_tokens[] = { 502cabd02bSRanjani Sridharan {SOF_TKN_CAVS_AUDIO_FORMAT_IN_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 512cabd02bSRanjani Sridharan offsetof(struct sof_ipc4_audio_format, sampling_frequency)}, 522cabd02bSRanjani Sridharan {SOF_TKN_CAVS_AUDIO_FORMAT_IN_BIT_DEPTH, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 532cabd02bSRanjani Sridharan offsetof(struct sof_ipc4_audio_format, bit_depth)}, 542cabd02bSRanjani Sridharan {SOF_TKN_CAVS_AUDIO_FORMAT_IN_CH_MAP, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 552cabd02bSRanjani Sridharan offsetof(struct sof_ipc4_audio_format, ch_map)}, 562cabd02bSRanjani Sridharan {SOF_TKN_CAVS_AUDIO_FORMAT_IN_CH_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 572cabd02bSRanjani Sridharan offsetof(struct sof_ipc4_audio_format, ch_cfg)}, 582cabd02bSRanjani Sridharan {SOF_TKN_CAVS_AUDIO_FORMAT_IN_INTERLEAVING_STYLE, SND_SOC_TPLG_TUPLE_TYPE_WORD, 592cabd02bSRanjani Sridharan get_token_u32, offsetof(struct sof_ipc4_audio_format, interleaving_style)}, 602cabd02bSRanjani Sridharan {SOF_TKN_CAVS_AUDIO_FORMAT_IN_FMT_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 612cabd02bSRanjani Sridharan offsetof(struct sof_ipc4_audio_format, fmt_cfg)}, 622cabd02bSRanjani Sridharan }; 632cabd02bSRanjani Sridharan 642cabd02bSRanjani Sridharan static const struct sof_topology_token ipc4_out_audio_format_tokens[] = { 652cabd02bSRanjani Sridharan {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 662cabd02bSRanjani Sridharan offsetof(struct sof_ipc4_audio_format, sampling_frequency)}, 672cabd02bSRanjani Sridharan {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_BIT_DEPTH, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 682cabd02bSRanjani Sridharan offsetof(struct sof_ipc4_audio_format, bit_depth)}, 692cabd02bSRanjani Sridharan {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_CH_MAP, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 702cabd02bSRanjani Sridharan offsetof(struct sof_ipc4_audio_format, ch_map)}, 712cabd02bSRanjani Sridharan {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_CH_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 722cabd02bSRanjani Sridharan offsetof(struct sof_ipc4_audio_format, ch_cfg)}, 732cabd02bSRanjani Sridharan {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_INTERLEAVING_STYLE, SND_SOC_TPLG_TUPLE_TYPE_WORD, 742cabd02bSRanjani Sridharan get_token_u32, offsetof(struct sof_ipc4_audio_format, interleaving_style)}, 752cabd02bSRanjani Sridharan {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_FMT_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 762cabd02bSRanjani Sridharan offsetof(struct sof_ipc4_audio_format, fmt_cfg)}, 772cabd02bSRanjani Sridharan }; 782cabd02bSRanjani Sridharan 792cabd02bSRanjani Sridharan static const struct sof_topology_token ipc4_copier_gateway_cfg_tokens[] = { 802cabd02bSRanjani Sridharan {SOF_TKN_CAVS_AUDIO_FORMAT_DMA_BUFFER_SIZE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 0}, 812cabd02bSRanjani Sridharan }; 822cabd02bSRanjani Sridharan 832cabd02bSRanjani Sridharan static const struct sof_topology_token ipc4_copier_tokens[] = { 842cabd02bSRanjani Sridharan {SOF_TKN_INTEL_COPIER_NODE_TYPE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 0}, 852cabd02bSRanjani Sridharan }; 862cabd02bSRanjani Sridharan 872cabd02bSRanjani Sridharan static const struct sof_topology_token ipc4_audio_fmt_num_tokens[] = { 882cabd02bSRanjani Sridharan {SOF_TKN_COMP_NUM_AUDIO_FORMATS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 892cabd02bSRanjani Sridharan 0}, 902cabd02bSRanjani Sridharan }; 912cabd02bSRanjani Sridharan 92abfb536bSRanjani Sridharan static const struct sof_topology_token dai_tokens[] = { 93abfb536bSRanjani Sridharan {SOF_TKN_DAI_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_dai_type, 94abfb536bSRanjani Sridharan offsetof(struct sof_ipc4_copier, dai_type)}, 95abfb536bSRanjani Sridharan {SOF_TKN_DAI_INDEX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 96abfb536bSRanjani Sridharan offsetof(struct sof_ipc4_copier, dai_index)}, 97abfb536bSRanjani Sridharan }; 98abfb536bSRanjani Sridharan 992cabd02bSRanjani Sridharan /* Component extended tokens */ 1002cabd02bSRanjani Sridharan static const struct sof_topology_token comp_ext_tokens[] = { 1012cabd02bSRanjani Sridharan {SOF_TKN_COMP_UUID, SND_SOC_TPLG_TUPLE_TYPE_UUID, get_token_uuid, 1022cabd02bSRanjani Sridharan offsetof(struct snd_sof_widget, uuid)}, 1032cabd02bSRanjani Sridharan }; 1042cabd02bSRanjani Sridharan 1054f838ab2SRanjani Sridharan static const struct sof_topology_token gain_tokens[] = { 1064f838ab2SRanjani Sridharan {SOF_TKN_GAIN_RAMP_TYPE, SND_SOC_TPLG_TUPLE_TYPE_WORD, 1074f838ab2SRanjani Sridharan get_token_u32, offsetof(struct sof_ipc4_gain_data, curve_type)}, 1084f838ab2SRanjani Sridharan {SOF_TKN_GAIN_RAMP_DURATION, 1094f838ab2SRanjani Sridharan SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 110e45cd86cSRander Wang offsetof(struct sof_ipc4_gain_data, curve_duration_l)}, 1114f838ab2SRanjani Sridharan {SOF_TKN_GAIN_VAL, SND_SOC_TPLG_TUPLE_TYPE_WORD, 1124f838ab2SRanjani Sridharan get_token_u32, offsetof(struct sof_ipc4_gain_data, init_val)}, 1134f838ab2SRanjani Sridharan }; 1144f838ab2SRanjani Sridharan 115b85f4fc4SRander Wang /* SRC */ 116b85f4fc4SRander Wang static const struct sof_topology_token src_tokens[] = { 117b85f4fc4SRander Wang {SOF_TKN_SRC_RATE_OUT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 118b85f4fc4SRander Wang offsetof(struct sof_ipc4_src, sink_rate)}, 119b85f4fc4SRander Wang }; 120b85f4fc4SRander Wang 12190e89155SRanjani Sridharan static const struct sof_token_info ipc4_token_list[SOF_TOKEN_COUNT] = { 122abfb536bSRanjani Sridharan [SOF_DAI_TOKENS] = {"DAI tokens", dai_tokens, ARRAY_SIZE(dai_tokens)}, 12390e89155SRanjani Sridharan [SOF_PIPELINE_TOKENS] = {"Pipeline tokens", pipeline_tokens, ARRAY_SIZE(pipeline_tokens)}, 12490e89155SRanjani Sridharan [SOF_SCHED_TOKENS] = {"Scheduler tokens", ipc4_sched_tokens, 12590e89155SRanjani Sridharan ARRAY_SIZE(ipc4_sched_tokens)}, 1262cabd02bSRanjani Sridharan [SOF_COMP_EXT_TOKENS] = {"Comp extended tokens", comp_ext_tokens, 1272cabd02bSRanjani Sridharan ARRAY_SIZE(comp_ext_tokens)}, 1282cabd02bSRanjani Sridharan [SOF_COMP_TOKENS] = {"IPC4 Component tokens", 1292cabd02bSRanjani Sridharan ipc4_comp_tokens, ARRAY_SIZE(ipc4_comp_tokens)}, 1302cabd02bSRanjani Sridharan [SOF_IN_AUDIO_FORMAT_TOKENS] = {"IPC4 Input Audio format tokens", 1312cabd02bSRanjani Sridharan ipc4_in_audio_format_tokens, ARRAY_SIZE(ipc4_in_audio_format_tokens)}, 1322cabd02bSRanjani Sridharan [SOF_OUT_AUDIO_FORMAT_TOKENS] = {"IPC4 Output Audio format tokens", 1332cabd02bSRanjani Sridharan ipc4_out_audio_format_tokens, ARRAY_SIZE(ipc4_out_audio_format_tokens)}, 1342cabd02bSRanjani Sridharan [SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS] = {"IPC4 Audio format buffer size tokens", 1352cabd02bSRanjani Sridharan ipc4_audio_format_buffer_size_tokens, 1362cabd02bSRanjani Sridharan ARRAY_SIZE(ipc4_audio_format_buffer_size_tokens)}, 1372cabd02bSRanjani Sridharan [SOF_COPIER_GATEWAY_CFG_TOKENS] = {"IPC4 Copier gateway config tokens", 1382cabd02bSRanjani Sridharan ipc4_copier_gateway_cfg_tokens, ARRAY_SIZE(ipc4_copier_gateway_cfg_tokens)}, 1392cabd02bSRanjani Sridharan [SOF_COPIER_TOKENS] = {"IPC4 Copier tokens", ipc4_copier_tokens, 1402cabd02bSRanjani Sridharan ARRAY_SIZE(ipc4_copier_tokens)}, 1412cabd02bSRanjani Sridharan [SOF_AUDIO_FMT_NUM_TOKENS] = {"IPC4 Audio format number tokens", 1422cabd02bSRanjani Sridharan ipc4_audio_fmt_num_tokens, ARRAY_SIZE(ipc4_audio_fmt_num_tokens)}, 1434f838ab2SRanjani Sridharan [SOF_GAIN_TOKENS] = {"Gain tokens", gain_tokens, ARRAY_SIZE(gain_tokens)}, 144b85f4fc4SRander Wang [SOF_SRC_TOKENS] = {"SRC tokens", src_tokens, ARRAY_SIZE(src_tokens)}, 14590e89155SRanjani Sridharan }; 14690e89155SRanjani Sridharan 1472cabd02bSRanjani Sridharan static void sof_ipc4_dbg_audio_format(struct device *dev, 1482cabd02bSRanjani Sridharan struct sof_ipc4_audio_format *format, 1492cabd02bSRanjani Sridharan size_t object_size, int num_format) 1502cabd02bSRanjani Sridharan { 1512cabd02bSRanjani Sridharan struct sof_ipc4_audio_format *fmt; 1522cabd02bSRanjani Sridharan void *ptr = format; 1532cabd02bSRanjani Sridharan int i; 1542cabd02bSRanjani Sridharan 1552cabd02bSRanjani Sridharan for (i = 0; i < num_format; i++, ptr = (u8 *)ptr + object_size) { 1562cabd02bSRanjani Sridharan fmt = ptr; 1572cabd02bSRanjani Sridharan dev_dbg(dev, 1589e269e3aSSeppo Ingalsuo " #%d: %uHz, %ubit (ch_map %#x ch_cfg %u interleaving_style %u fmt_cfg %#x)\n", 1592cabd02bSRanjani Sridharan i, fmt->sampling_frequency, fmt->bit_depth, fmt->ch_map, 1602cabd02bSRanjani Sridharan fmt->ch_cfg, fmt->interleaving_style, fmt->fmt_cfg); 1612cabd02bSRanjani Sridharan } 1622cabd02bSRanjani Sridharan } 1632cabd02bSRanjani Sridharan 1642cabd02bSRanjani Sridharan /** 1652cabd02bSRanjani Sridharan * sof_ipc4_get_audio_fmt - get available audio formats from swidget->tuples 1662cabd02bSRanjani Sridharan * @scomp: pointer to pointer to SOC component 1672cabd02bSRanjani Sridharan * @swidget: pointer to struct snd_sof_widget containing tuples 1682cabd02bSRanjani Sridharan * @available_fmt: pointer to struct sof_ipc4_available_audio_format being filling in 1692cabd02bSRanjani Sridharan * @has_out_format: true if available_fmt contains output format 1702cabd02bSRanjani Sridharan * 1712cabd02bSRanjani Sridharan * Return: 0 if successful 1722cabd02bSRanjani Sridharan */ 1732cabd02bSRanjani Sridharan static int sof_ipc4_get_audio_fmt(struct snd_soc_component *scomp, 1742cabd02bSRanjani Sridharan struct snd_sof_widget *swidget, 1752cabd02bSRanjani Sridharan struct sof_ipc4_available_audio_format *available_fmt, 1762cabd02bSRanjani Sridharan bool has_out_format) 1772cabd02bSRanjani Sridharan { 1782cabd02bSRanjani Sridharan struct sof_ipc4_base_module_cfg *base_config; 1792cabd02bSRanjani Sridharan struct sof_ipc4_audio_format *out_format; 1802cabd02bSRanjani Sridharan int audio_fmt_num = 0; 1812cabd02bSRanjani Sridharan int ret, i; 1822cabd02bSRanjani Sridharan 1832cabd02bSRanjani Sridharan ret = sof_update_ipc_object(scomp, &audio_fmt_num, 1842cabd02bSRanjani Sridharan SOF_AUDIO_FMT_NUM_TOKENS, swidget->tuples, 1852cabd02bSRanjani Sridharan swidget->num_tuples, sizeof(audio_fmt_num), 1); 1862cabd02bSRanjani Sridharan if (ret || audio_fmt_num <= 0) { 1872cabd02bSRanjani Sridharan dev_err(scomp->dev, "Invalid number of audio formats: %d\n", audio_fmt_num); 1882cabd02bSRanjani Sridharan return -EINVAL; 1892cabd02bSRanjani Sridharan } 1902cabd02bSRanjani Sridharan available_fmt->audio_fmt_num = audio_fmt_num; 1912cabd02bSRanjani Sridharan 1922cabd02bSRanjani Sridharan dev_dbg(scomp->dev, "Number of audio formats: %d\n", available_fmt->audio_fmt_num); 1932cabd02bSRanjani Sridharan 1942cabd02bSRanjani Sridharan base_config = kcalloc(available_fmt->audio_fmt_num, sizeof(*base_config), GFP_KERNEL); 1952cabd02bSRanjani Sridharan if (!base_config) 1962cabd02bSRanjani Sridharan return -ENOMEM; 1972cabd02bSRanjani Sridharan 1982cabd02bSRanjani Sridharan /* set cpc and is_pages for all base_cfg */ 1992cabd02bSRanjani Sridharan for (i = 0; i < available_fmt->audio_fmt_num; i++) { 2002cabd02bSRanjani Sridharan ret = sof_update_ipc_object(scomp, &base_config[i], 2012cabd02bSRanjani Sridharan SOF_COMP_TOKENS, swidget->tuples, 2022cabd02bSRanjani Sridharan swidget->num_tuples, sizeof(*base_config), 1); 2032cabd02bSRanjani Sridharan if (ret) { 2042cabd02bSRanjani Sridharan dev_err(scomp->dev, "parse comp tokens failed %d\n", ret); 2052cabd02bSRanjani Sridharan goto err_in; 2062cabd02bSRanjani Sridharan } 2072cabd02bSRanjani Sridharan } 2082cabd02bSRanjani Sridharan 2092cabd02bSRanjani Sridharan /* copy the ibs/obs for each base_cfg */ 2102cabd02bSRanjani Sridharan ret = sof_update_ipc_object(scomp, base_config, 2112cabd02bSRanjani Sridharan SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS, swidget->tuples, 2122cabd02bSRanjani Sridharan swidget->num_tuples, sizeof(*base_config), 2132cabd02bSRanjani Sridharan available_fmt->audio_fmt_num); 2142cabd02bSRanjani Sridharan if (ret) { 2152cabd02bSRanjani Sridharan dev_err(scomp->dev, "parse buffer size tokens failed %d\n", ret); 2162cabd02bSRanjani Sridharan goto err_in; 2172cabd02bSRanjani Sridharan } 2182cabd02bSRanjani Sridharan 2192cabd02bSRanjani Sridharan for (i = 0; i < available_fmt->audio_fmt_num; i++) 2202cabd02bSRanjani Sridharan dev_dbg(scomp->dev, "%d: ibs: %d obs: %d cpc: %d is_pages: %d\n", i, 2212cabd02bSRanjani Sridharan base_config[i].ibs, base_config[i].obs, 2222cabd02bSRanjani Sridharan base_config[i].cpc, base_config[i].is_pages); 2232cabd02bSRanjani Sridharan 2242cabd02bSRanjani Sridharan ret = sof_update_ipc_object(scomp, &base_config->audio_fmt, 2252cabd02bSRanjani Sridharan SOF_IN_AUDIO_FORMAT_TOKENS, swidget->tuples, 2262cabd02bSRanjani Sridharan swidget->num_tuples, sizeof(*base_config), 2272cabd02bSRanjani Sridharan available_fmt->audio_fmt_num); 2282cabd02bSRanjani Sridharan if (ret) { 2292cabd02bSRanjani Sridharan dev_err(scomp->dev, "parse base_config audio_fmt tokens failed %d\n", ret); 2302cabd02bSRanjani Sridharan goto err_in; 2312cabd02bSRanjani Sridharan } 2322cabd02bSRanjani Sridharan 2332cabd02bSRanjani Sridharan dev_dbg(scomp->dev, "Get input audio formats for %s\n", swidget->widget->name); 2342cabd02bSRanjani Sridharan sof_ipc4_dbg_audio_format(scomp->dev, &base_config->audio_fmt, 2352cabd02bSRanjani Sridharan sizeof(*base_config), 2362cabd02bSRanjani Sridharan available_fmt->audio_fmt_num); 2372cabd02bSRanjani Sridharan 2382cabd02bSRanjani Sridharan available_fmt->base_config = base_config; 2392cabd02bSRanjani Sridharan 2402cabd02bSRanjani Sridharan if (!has_out_format) 2412cabd02bSRanjani Sridharan return 0; 2422cabd02bSRanjani Sridharan 2432cabd02bSRanjani Sridharan out_format = kcalloc(available_fmt->audio_fmt_num, sizeof(*out_format), GFP_KERNEL); 2442cabd02bSRanjani Sridharan if (!out_format) { 2452cabd02bSRanjani Sridharan ret = -ENOMEM; 2462cabd02bSRanjani Sridharan goto err_in; 2472cabd02bSRanjani Sridharan } 2482cabd02bSRanjani Sridharan 2492cabd02bSRanjani Sridharan ret = sof_update_ipc_object(scomp, out_format, 2502cabd02bSRanjani Sridharan SOF_OUT_AUDIO_FORMAT_TOKENS, swidget->tuples, 2512cabd02bSRanjani Sridharan swidget->num_tuples, sizeof(*out_format), 2522cabd02bSRanjani Sridharan available_fmt->audio_fmt_num); 2532cabd02bSRanjani Sridharan 2542cabd02bSRanjani Sridharan if (ret) { 2552cabd02bSRanjani Sridharan dev_err(scomp->dev, "parse output audio_fmt tokens failed\n"); 2562cabd02bSRanjani Sridharan goto err_out; 2572cabd02bSRanjani Sridharan } 2582cabd02bSRanjani Sridharan 2592cabd02bSRanjani Sridharan available_fmt->out_audio_fmt = out_format; 2602cabd02bSRanjani Sridharan dev_dbg(scomp->dev, "Get output audio formats for %s\n", swidget->widget->name); 2612cabd02bSRanjani Sridharan sof_ipc4_dbg_audio_format(scomp->dev, out_format, sizeof(*out_format), 2622cabd02bSRanjani Sridharan available_fmt->audio_fmt_num); 2632cabd02bSRanjani Sridharan 2642cabd02bSRanjani Sridharan return 0; 2652cabd02bSRanjani Sridharan 2662cabd02bSRanjani Sridharan err_out: 2672cabd02bSRanjani Sridharan kfree(out_format); 2682cabd02bSRanjani Sridharan err_in: 2692cabd02bSRanjani Sridharan kfree(base_config); 2702cabd02bSRanjani Sridharan 2712cabd02bSRanjani Sridharan return ret; 2722cabd02bSRanjani Sridharan } 2732cabd02bSRanjani Sridharan 274dc4fc0aeSLibin Yang /* release the memory allocated in sof_ipc4_get_audio_fmt */ 275dc4fc0aeSLibin Yang static void sof_ipc4_free_audio_fmt(struct sof_ipc4_available_audio_format *available_fmt) 276dc4fc0aeSLibin Yang 277dc4fc0aeSLibin Yang { 278dc4fc0aeSLibin Yang kfree(available_fmt->base_config); 279dc4fc0aeSLibin Yang available_fmt->base_config = NULL; 280dc4fc0aeSLibin Yang kfree(available_fmt->out_audio_fmt); 281dc4fc0aeSLibin Yang available_fmt->out_audio_fmt = NULL; 282dc4fc0aeSLibin Yang } 283dc4fc0aeSLibin Yang 284a29b2d02SBard Liao static void sof_ipc4_widget_free_comp_pipeline(struct snd_sof_widget *swidget) 28590e89155SRanjani Sridharan { 28690e89155SRanjani Sridharan kfree(swidget->private); 28790e89155SRanjani Sridharan } 28890e89155SRanjani Sridharan 2892cabd02bSRanjani Sridharan static int sof_ipc4_widget_set_module_info(struct snd_sof_widget *swidget) 2902cabd02bSRanjani Sridharan { 2912cabd02bSRanjani Sridharan struct snd_soc_component *scomp = swidget->scomp; 2922cabd02bSRanjani Sridharan struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 2932cabd02bSRanjani Sridharan 294c73f8b47SPeter Ujfalusi swidget->module_info = sof_ipc4_find_module_by_uuid(sdev, &swidget->uuid); 2955a932cfcSPeter Ujfalusi 296c73f8b47SPeter Ujfalusi if (swidget->module_info) 2972cabd02bSRanjani Sridharan return 0; 2982cabd02bSRanjani Sridharan 2992cabd02bSRanjani Sridharan dev_err(sdev->dev, "failed to find module info for widget %s with UUID %pUL\n", 3002cabd02bSRanjani Sridharan swidget->widget->name, &swidget->uuid); 3012cabd02bSRanjani Sridharan return -EINVAL; 3022cabd02bSRanjani Sridharan } 3032cabd02bSRanjani Sridharan 3042cabd02bSRanjani Sridharan static int sof_ipc4_widget_setup_msg(struct snd_sof_widget *swidget, struct sof_ipc4_msg *msg) 3052cabd02bSRanjani Sridharan { 3062cabd02bSRanjani Sridharan struct sof_ipc4_fw_module *fw_module; 307dc6137a5SRander Wang uint32_t type; 3082cabd02bSRanjani Sridharan int ret; 3092cabd02bSRanjani Sridharan 3102cabd02bSRanjani Sridharan ret = sof_ipc4_widget_set_module_info(swidget); 3112cabd02bSRanjani Sridharan if (ret) 3122cabd02bSRanjani Sridharan return ret; 3132cabd02bSRanjani Sridharan 3142cabd02bSRanjani Sridharan fw_module = swidget->module_info; 3152cabd02bSRanjani Sridharan 3162cabd02bSRanjani Sridharan msg->primary = fw_module->man4_module_entry.id; 3172cabd02bSRanjani Sridharan msg->primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_INIT_INSTANCE); 3182cabd02bSRanjani Sridharan msg->primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); 3192cabd02bSRanjani Sridharan msg->primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG); 3202cabd02bSRanjani Sridharan 321a2ba1f70SBard Liao msg->extension = SOF_IPC4_MOD_EXT_CORE_ID(swidget->core); 3222cabd02bSRanjani Sridharan 32380d53171SPierre-Louis Bossart type = (fw_module->man4_module_entry.type & SOF_IPC4_MODULE_DP) ? 1 : 0; 324dc6137a5SRander Wang msg->extension |= SOF_IPC4_MOD_EXT_DOMAIN(type); 325dc6137a5SRander Wang 3262cabd02bSRanjani Sridharan return 0; 3272cabd02bSRanjani Sridharan } 3282cabd02bSRanjani Sridharan 3292cabd02bSRanjani Sridharan static int sof_ipc4_widget_setup_pcm(struct snd_sof_widget *swidget) 3302cabd02bSRanjani Sridharan { 3312cabd02bSRanjani Sridharan struct sof_ipc4_available_audio_format *available_fmt; 3322cabd02bSRanjani Sridharan struct snd_soc_component *scomp = swidget->scomp; 3332cabd02bSRanjani Sridharan struct sof_ipc4_copier *ipc4_copier; 3342cabd02bSRanjani Sridharan int node_type = 0; 3352cabd02bSRanjani Sridharan int ret, i; 3362cabd02bSRanjani Sridharan 3372cabd02bSRanjani Sridharan ipc4_copier = kzalloc(sizeof(*ipc4_copier), GFP_KERNEL); 3382cabd02bSRanjani Sridharan if (!ipc4_copier) 3392cabd02bSRanjani Sridharan return -ENOMEM; 3402cabd02bSRanjani Sridharan 3412cabd02bSRanjani Sridharan swidget->private = ipc4_copier; 3422cabd02bSRanjani Sridharan available_fmt = &ipc4_copier->available_fmt; 3432cabd02bSRanjani Sridharan 3442cabd02bSRanjani Sridharan dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name); 3452cabd02bSRanjani Sridharan 3462cabd02bSRanjani Sridharan ret = sof_ipc4_get_audio_fmt(scomp, swidget, available_fmt, true); 3472cabd02bSRanjani Sridharan if (ret) 3482cabd02bSRanjani Sridharan goto free_copier; 3492cabd02bSRanjani Sridharan 3502cabd02bSRanjani Sridharan available_fmt->dma_buffer_size = kcalloc(available_fmt->audio_fmt_num, sizeof(u32), 3512cabd02bSRanjani Sridharan GFP_KERNEL); 3522cabd02bSRanjani Sridharan if (!available_fmt->dma_buffer_size) { 3532cabd02bSRanjani Sridharan ret = -ENOMEM; 354dc4fc0aeSLibin Yang goto free_available_fmt; 3552cabd02bSRanjani Sridharan } 3562cabd02bSRanjani Sridharan 3577d573425SBard Liao /* 3587d573425SBard Liao * This callback is used by host copier and module-to-module copier, 3597d573425SBard Liao * and only host copier needs to set gtw_cfg. 3607d573425SBard Liao */ 3617d573425SBard Liao if (!WIDGET_IS_AIF(swidget->id)) 3627d573425SBard Liao goto skip_gtw_cfg; 3637d573425SBard Liao 3642cabd02bSRanjani Sridharan ret = sof_update_ipc_object(scomp, available_fmt->dma_buffer_size, 3652cabd02bSRanjani Sridharan SOF_COPIER_GATEWAY_CFG_TOKENS, swidget->tuples, 3662cabd02bSRanjani Sridharan swidget->num_tuples, sizeof(u32), 3672cabd02bSRanjani Sridharan available_fmt->audio_fmt_num); 3682cabd02bSRanjani Sridharan if (ret) { 3692cabd02bSRanjani Sridharan dev_err(scomp->dev, "Failed to parse dma buffer size in audio format for %s\n", 3702cabd02bSRanjani Sridharan swidget->widget->name); 3712cabd02bSRanjani Sridharan goto err; 3722cabd02bSRanjani Sridharan } 3732cabd02bSRanjani Sridharan 3742cabd02bSRanjani Sridharan dev_dbg(scomp->dev, "dma buffer size:\n"); 3752cabd02bSRanjani Sridharan for (i = 0; i < available_fmt->audio_fmt_num; i++) 3762cabd02bSRanjani Sridharan dev_dbg(scomp->dev, "%d: %u\n", i, 3772cabd02bSRanjani Sridharan available_fmt->dma_buffer_size[i]); 3782cabd02bSRanjani Sridharan 3792cabd02bSRanjani Sridharan ret = sof_update_ipc_object(scomp, &node_type, 3802cabd02bSRanjani Sridharan SOF_COPIER_TOKENS, swidget->tuples, 3812cabd02bSRanjani Sridharan swidget->num_tuples, sizeof(node_type), 1); 3822cabd02bSRanjani Sridharan 3832cabd02bSRanjani Sridharan if (ret) { 3842cabd02bSRanjani Sridharan dev_err(scomp->dev, "parse host copier node type token failed %d\n", 3852cabd02bSRanjani Sridharan ret); 3862cabd02bSRanjani Sridharan goto err; 3872cabd02bSRanjani Sridharan } 3882cabd02bSRanjani Sridharan dev_dbg(scomp->dev, "host copier '%s' node_type %u\n", swidget->widget->name, node_type); 3892cabd02bSRanjani Sridharan 3907d573425SBard Liao skip_gtw_cfg: 3912cabd02bSRanjani Sridharan ipc4_copier->gtw_attr = kzalloc(sizeof(*ipc4_copier->gtw_attr), GFP_KERNEL); 3922cabd02bSRanjani Sridharan if (!ipc4_copier->gtw_attr) { 3932cabd02bSRanjani Sridharan ret = -ENOMEM; 3942cabd02bSRanjani Sridharan goto err; 3952cabd02bSRanjani Sridharan } 3962cabd02bSRanjani Sridharan 3972cabd02bSRanjani Sridharan ipc4_copier->copier_config = (uint32_t *)ipc4_copier->gtw_attr; 3982cabd02bSRanjani Sridharan ipc4_copier->data.gtw_cfg.config_length = 3992cabd02bSRanjani Sridharan sizeof(struct sof_ipc4_gtw_attributes) >> 2; 4002cabd02bSRanjani Sridharan 4017d573425SBard Liao switch (swidget->id) { 4027d573425SBard Liao case snd_soc_dapm_aif_in: 4037d573425SBard Liao case snd_soc_dapm_aif_out: 4047d573425SBard Liao ipc4_copier->data.gtw_cfg.node_id = SOF_IPC4_NODE_TYPE(node_type); 4057d573425SBard Liao break; 4067d573425SBard Liao case snd_soc_dapm_buffer: 4077d573425SBard Liao ipc4_copier->data.gtw_cfg.node_id = SOF_IPC4_INVALID_NODE_ID; 4087d573425SBard Liao ipc4_copier->ipc_config_size = 0; 4097d573425SBard Liao break; 4107d573425SBard Liao default: 4117d573425SBard Liao dev_err(scomp->dev, "invalid widget type %d\n", swidget->id); 4127d573425SBard Liao ret = -EINVAL; 4137d573425SBard Liao goto free_gtw_attr; 4147d573425SBard Liao } 4157d573425SBard Liao 4162cabd02bSRanjani Sridharan /* set up module info and message header */ 4172cabd02bSRanjani Sridharan ret = sof_ipc4_widget_setup_msg(swidget, &ipc4_copier->msg); 4182cabd02bSRanjani Sridharan if (ret) 4192cabd02bSRanjani Sridharan goto free_gtw_attr; 4202cabd02bSRanjani Sridharan 4212cabd02bSRanjani Sridharan return 0; 4222cabd02bSRanjani Sridharan 4232cabd02bSRanjani Sridharan free_gtw_attr: 4242cabd02bSRanjani Sridharan kfree(ipc4_copier->gtw_attr); 4252cabd02bSRanjani Sridharan err: 4262cabd02bSRanjani Sridharan kfree(available_fmt->dma_buffer_size); 427dc4fc0aeSLibin Yang free_available_fmt: 428dc4fc0aeSLibin Yang sof_ipc4_free_audio_fmt(available_fmt); 4292cabd02bSRanjani Sridharan free_copier: 4302cabd02bSRanjani Sridharan kfree(ipc4_copier); 431b737fd8cSLibin Yang swidget->private = NULL; 4322cabd02bSRanjani Sridharan return ret; 4332cabd02bSRanjani Sridharan } 4342cabd02bSRanjani Sridharan 4352cabd02bSRanjani Sridharan static void sof_ipc4_widget_free_comp_pcm(struct snd_sof_widget *swidget) 4362cabd02bSRanjani Sridharan { 4372cabd02bSRanjani Sridharan struct sof_ipc4_copier *ipc4_copier = swidget->private; 4382cabd02bSRanjani Sridharan struct sof_ipc4_available_audio_format *available_fmt; 4392cabd02bSRanjani Sridharan 4402cabd02bSRanjani Sridharan if (!ipc4_copier) 4412cabd02bSRanjani Sridharan return; 4422cabd02bSRanjani Sridharan 4432cabd02bSRanjani Sridharan available_fmt = &ipc4_copier->available_fmt; 4442cabd02bSRanjani Sridharan kfree(available_fmt->dma_buffer_size); 4452cabd02bSRanjani Sridharan kfree(available_fmt->base_config); 4462cabd02bSRanjani Sridharan kfree(available_fmt->out_audio_fmt); 4472cabd02bSRanjani Sridharan kfree(ipc4_copier->gtw_attr); 4482cabd02bSRanjani Sridharan kfree(ipc4_copier); 4492cabd02bSRanjani Sridharan swidget->private = NULL; 4502cabd02bSRanjani Sridharan } 4512cabd02bSRanjani Sridharan 452abfb536bSRanjani Sridharan static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget) 453abfb536bSRanjani Sridharan { 454abfb536bSRanjani Sridharan struct sof_ipc4_available_audio_format *available_fmt; 455abfb536bSRanjani Sridharan struct snd_soc_component *scomp = swidget->scomp; 456abfb536bSRanjani Sridharan struct snd_sof_dai *dai = swidget->private; 457abfb536bSRanjani Sridharan struct sof_ipc4_copier *ipc4_copier; 458abfb536bSRanjani Sridharan int node_type = 0; 459abfb536bSRanjani Sridharan int ret, i; 460abfb536bSRanjani Sridharan 461abfb536bSRanjani Sridharan ipc4_copier = kzalloc(sizeof(*ipc4_copier), GFP_KERNEL); 462abfb536bSRanjani Sridharan if (!ipc4_copier) 463abfb536bSRanjani Sridharan return -ENOMEM; 464abfb536bSRanjani Sridharan 465abfb536bSRanjani Sridharan available_fmt = &ipc4_copier->available_fmt; 466abfb536bSRanjani Sridharan 467abfb536bSRanjani Sridharan dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name); 468abfb536bSRanjani Sridharan 469abfb536bSRanjani Sridharan ret = sof_ipc4_get_audio_fmt(scomp, swidget, available_fmt, true); 470abfb536bSRanjani Sridharan if (ret) 471abfb536bSRanjani Sridharan goto free_copier; 472abfb536bSRanjani Sridharan 473abfb536bSRanjani Sridharan available_fmt->dma_buffer_size = kcalloc(available_fmt->audio_fmt_num, sizeof(u32), 474abfb536bSRanjani Sridharan GFP_KERNEL); 475abfb536bSRanjani Sridharan if (!available_fmt->dma_buffer_size) { 476abfb536bSRanjani Sridharan ret = -ENOMEM; 477dc4fc0aeSLibin Yang goto free_available_fmt; 478abfb536bSRanjani Sridharan } 479abfb536bSRanjani Sridharan 480abfb536bSRanjani Sridharan ret = sof_update_ipc_object(scomp, available_fmt->dma_buffer_size, 481abfb536bSRanjani Sridharan SOF_COPIER_GATEWAY_CFG_TOKENS, swidget->tuples, 482abfb536bSRanjani Sridharan swidget->num_tuples, sizeof(u32), 483abfb536bSRanjani Sridharan available_fmt->audio_fmt_num); 484abfb536bSRanjani Sridharan if (ret) { 485abfb536bSRanjani Sridharan dev_err(scomp->dev, "Failed to parse dma buffer size in audio format for %s\n", 486abfb536bSRanjani Sridharan swidget->widget->name); 487abfb536bSRanjani Sridharan goto err; 488abfb536bSRanjani Sridharan } 489abfb536bSRanjani Sridharan 490abfb536bSRanjani Sridharan for (i = 0; i < available_fmt->audio_fmt_num; i++) 491abfb536bSRanjani Sridharan dev_dbg(scomp->dev, "%d: dma buffer size: %u\n", i, 492abfb536bSRanjani Sridharan available_fmt->dma_buffer_size[i]); 493abfb536bSRanjani Sridharan 494abfb536bSRanjani Sridharan ret = sof_update_ipc_object(scomp, &node_type, 495abfb536bSRanjani Sridharan SOF_COPIER_TOKENS, swidget->tuples, 496abfb536bSRanjani Sridharan swidget->num_tuples, sizeof(node_type), 1); 497abfb536bSRanjani Sridharan if (ret) { 498abfb536bSRanjani Sridharan dev_err(scomp->dev, "parse dai node type failed %d\n", ret); 499abfb536bSRanjani Sridharan goto err; 500abfb536bSRanjani Sridharan } 501abfb536bSRanjani Sridharan 502abfb536bSRanjani Sridharan ret = sof_update_ipc_object(scomp, ipc4_copier, 503abfb536bSRanjani Sridharan SOF_DAI_TOKENS, swidget->tuples, 504abfb536bSRanjani Sridharan swidget->num_tuples, sizeof(u32), 1); 505abfb536bSRanjani Sridharan if (ret) { 506abfb536bSRanjani Sridharan dev_err(scomp->dev, "parse dai copier node token failed %d\n", ret); 507abfb536bSRanjani Sridharan goto err; 508abfb536bSRanjani Sridharan } 509abfb536bSRanjani Sridharan 510abfb536bSRanjani Sridharan dev_dbg(scomp->dev, "dai %s node_type %u dai_type %u dai_index %d\n", swidget->widget->name, 511abfb536bSRanjani Sridharan node_type, ipc4_copier->dai_type, ipc4_copier->dai_index); 512abfb536bSRanjani Sridharan 513abfb536bSRanjani Sridharan ipc4_copier->data.gtw_cfg.node_id = SOF_IPC4_NODE_TYPE(node_type); 514aa84ffb7SRanjani Sridharan 515aa84ffb7SRanjani Sridharan switch (ipc4_copier->dai_type) { 516a45a4d43SBard Liao case SOF_DAI_INTEL_ALH: 517a45a4d43SBard Liao { 518a150345aSBard Liao struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 519a45a4d43SBard Liao struct sof_ipc4_alh_configuration_blob *blob; 520a150345aSBard Liao struct snd_sof_widget *w; 521a45a4d43SBard Liao 522a45a4d43SBard Liao blob = kzalloc(sizeof(*blob), GFP_KERNEL); 523a45a4d43SBard Liao if (!blob) { 524a45a4d43SBard Liao ret = -ENOMEM; 525a45a4d43SBard Liao goto err; 526a45a4d43SBard Liao } 527a45a4d43SBard Liao 528a150345aSBard Liao list_for_each_entry(w, &sdev->widget_list, list) { 529a150345aSBard Liao if (w->widget->sname && 530a150345aSBard Liao strcmp(w->widget->sname, swidget->widget->sname)) 531a150345aSBard Liao continue; 532a150345aSBard Liao 533a150345aSBard Liao blob->alh_cfg.count++; 534a150345aSBard Liao } 535a150345aSBard Liao 536a45a4d43SBard Liao ipc4_copier->copier_config = (uint32_t *)blob; 537a45a4d43SBard Liao ipc4_copier->data.gtw_cfg.config_length = sizeof(*blob) >> 2; 538a45a4d43SBard Liao break; 539a45a4d43SBard Liao } 540aa84ffb7SRanjani Sridharan case SOF_DAI_INTEL_SSP: 541aa84ffb7SRanjani Sridharan /* set SSP DAI index as the node_id */ 542aa84ffb7SRanjani Sridharan ipc4_copier->data.gtw_cfg.node_id |= 543aa84ffb7SRanjani Sridharan SOF_IPC4_NODE_INDEX_INTEL_SSP(ipc4_copier->dai_index); 544aa84ffb7SRanjani Sridharan break; 545aa84ffb7SRanjani Sridharan case SOF_DAI_INTEL_DMIC: 546aa84ffb7SRanjani Sridharan /* set DMIC DAI index as the node_id */ 547aa84ffb7SRanjani Sridharan ipc4_copier->data.gtw_cfg.node_id |= 548aa84ffb7SRanjani Sridharan SOF_IPC4_NODE_INDEX_INTEL_DMIC(ipc4_copier->dai_index); 549aa84ffb7SRanjani Sridharan break; 550aa84ffb7SRanjani Sridharan default: 551abfb536bSRanjani Sridharan ipc4_copier->gtw_attr = kzalloc(sizeof(*ipc4_copier->gtw_attr), GFP_KERNEL); 552abfb536bSRanjani Sridharan if (!ipc4_copier->gtw_attr) { 553abfb536bSRanjani Sridharan ret = -ENOMEM; 554abfb536bSRanjani Sridharan goto err; 555abfb536bSRanjani Sridharan } 556abfb536bSRanjani Sridharan 557abfb536bSRanjani Sridharan ipc4_copier->copier_config = (uint32_t *)ipc4_copier->gtw_attr; 558aa84ffb7SRanjani Sridharan ipc4_copier->data.gtw_cfg.config_length = 559aa84ffb7SRanjani Sridharan sizeof(struct sof_ipc4_gtw_attributes) >> 2; 560aa84ffb7SRanjani Sridharan break; 561aa84ffb7SRanjani Sridharan } 562abfb536bSRanjani Sridharan 563abfb536bSRanjani Sridharan dai->scomp = scomp; 564abfb536bSRanjani Sridharan dai->private = ipc4_copier; 565abfb536bSRanjani Sridharan 566abfb536bSRanjani Sridharan /* set up module info and message header */ 567abfb536bSRanjani Sridharan ret = sof_ipc4_widget_setup_msg(swidget, &ipc4_copier->msg); 568abfb536bSRanjani Sridharan if (ret) 569abfb536bSRanjani Sridharan goto free_copier_config; 570abfb536bSRanjani Sridharan 571abfb536bSRanjani Sridharan return 0; 572abfb536bSRanjani Sridharan 573abfb536bSRanjani Sridharan free_copier_config: 574abfb536bSRanjani Sridharan kfree(ipc4_copier->copier_config); 575abfb536bSRanjani Sridharan err: 576abfb536bSRanjani Sridharan kfree(available_fmt->dma_buffer_size); 577dc4fc0aeSLibin Yang free_available_fmt: 578dc4fc0aeSLibin Yang sof_ipc4_free_audio_fmt(available_fmt); 579abfb536bSRanjani Sridharan free_copier: 580abfb536bSRanjani Sridharan kfree(ipc4_copier); 581b737fd8cSLibin Yang dai->private = NULL; 582b737fd8cSLibin Yang dai->scomp = NULL; 583abfb536bSRanjani Sridharan return ret; 584abfb536bSRanjani Sridharan } 585abfb536bSRanjani Sridharan 586abfb536bSRanjani Sridharan static void sof_ipc4_widget_free_comp_dai(struct snd_sof_widget *swidget) 587abfb536bSRanjani Sridharan { 588abfb536bSRanjani Sridharan struct sof_ipc4_available_audio_format *available_fmt; 589abfb536bSRanjani Sridharan struct snd_sof_dai *dai = swidget->private; 590abfb536bSRanjani Sridharan struct sof_ipc4_copier *ipc4_copier; 591abfb536bSRanjani Sridharan 592abfb536bSRanjani Sridharan if (!dai) 593abfb536bSRanjani Sridharan return; 594abfb536bSRanjani Sridharan 595b737fd8cSLibin Yang if (!dai->private) { 596b737fd8cSLibin Yang kfree(dai); 597b737fd8cSLibin Yang swidget->private = NULL; 598b737fd8cSLibin Yang return; 599b737fd8cSLibin Yang } 600b737fd8cSLibin Yang 601abfb536bSRanjani Sridharan ipc4_copier = dai->private; 602abfb536bSRanjani Sridharan available_fmt = &ipc4_copier->available_fmt; 603abfb536bSRanjani Sridharan 604abfb536bSRanjani Sridharan kfree(available_fmt->dma_buffer_size); 605abfb536bSRanjani Sridharan kfree(available_fmt->base_config); 606abfb536bSRanjani Sridharan kfree(available_fmt->out_audio_fmt); 607aa84ffb7SRanjani Sridharan if (ipc4_copier->dai_type != SOF_DAI_INTEL_SSP && 608aa84ffb7SRanjani Sridharan ipc4_copier->dai_type != SOF_DAI_INTEL_DMIC) 609abfb536bSRanjani Sridharan kfree(ipc4_copier->copier_config); 610abfb536bSRanjani Sridharan kfree(dai->private); 611abfb536bSRanjani Sridharan kfree(dai); 612abfb536bSRanjani Sridharan swidget->private = NULL; 613abfb536bSRanjani Sridharan } 614abfb536bSRanjani Sridharan 61590e89155SRanjani Sridharan static int sof_ipc4_widget_setup_comp_pipeline(struct snd_sof_widget *swidget) 61690e89155SRanjani Sridharan { 61790e89155SRanjani Sridharan struct snd_soc_component *scomp = swidget->scomp; 61890e89155SRanjani Sridharan struct sof_ipc4_pipeline *pipeline; 61990e89155SRanjani Sridharan int ret; 62090e89155SRanjani Sridharan 62190e89155SRanjani Sridharan pipeline = kzalloc(sizeof(*pipeline), GFP_KERNEL); 62290e89155SRanjani Sridharan if (!pipeline) 62390e89155SRanjani Sridharan return -ENOMEM; 62490e89155SRanjani Sridharan 62590e89155SRanjani Sridharan ret = sof_update_ipc_object(scomp, pipeline, SOF_SCHED_TOKENS, swidget->tuples, 62690e89155SRanjani Sridharan swidget->num_tuples, sizeof(*pipeline), 1); 62790e89155SRanjani Sridharan if (ret) { 62890e89155SRanjani Sridharan dev_err(scomp->dev, "parsing scheduler tokens failed\n"); 62990e89155SRanjani Sridharan goto err; 63090e89155SRanjani Sridharan } 63190e89155SRanjani Sridharan 63290e89155SRanjani Sridharan /* parse one set of pipeline tokens */ 63390e89155SRanjani Sridharan ret = sof_update_ipc_object(scomp, swidget, SOF_PIPELINE_TOKENS, swidget->tuples, 63490e89155SRanjani Sridharan swidget->num_tuples, sizeof(*swidget), 1); 63590e89155SRanjani Sridharan if (ret) { 63690e89155SRanjani Sridharan dev_err(scomp->dev, "parsing pipeline tokens failed\n"); 63790e89155SRanjani Sridharan goto err; 63890e89155SRanjani Sridharan } 63990e89155SRanjani Sridharan 64090e89155SRanjani Sridharan /* TODO: Get priority from topology */ 64190e89155SRanjani Sridharan pipeline->priority = 0; 64290e89155SRanjani Sridharan 64390e89155SRanjani Sridharan dev_dbg(scomp->dev, "pipeline '%s': id %d pri %d lp mode %d\n", 64490e89155SRanjani Sridharan swidget->widget->name, swidget->pipeline_id, 64590e89155SRanjani Sridharan pipeline->priority, pipeline->lp_mode); 64690e89155SRanjani Sridharan 64790e89155SRanjani Sridharan swidget->private = pipeline; 64890e89155SRanjani Sridharan 64990e89155SRanjani Sridharan pipeline->msg.primary = SOF_IPC4_GLB_PIPE_PRIORITY(pipeline->priority); 65090e89155SRanjani Sridharan pipeline->msg.primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_CREATE_PIPELINE); 65190e89155SRanjani Sridharan pipeline->msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); 65290e89155SRanjani Sridharan pipeline->msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG); 65390e89155SRanjani Sridharan 65490e89155SRanjani Sridharan pipeline->msg.extension = pipeline->lp_mode; 65590e89155SRanjani Sridharan pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED; 65690e89155SRanjani Sridharan 65790e89155SRanjani Sridharan return 0; 65890e89155SRanjani Sridharan err: 65990e89155SRanjani Sridharan kfree(pipeline); 66090e89155SRanjani Sridharan return ret; 66190e89155SRanjani Sridharan } 66290e89155SRanjani Sridharan 6634f838ab2SRanjani Sridharan static int sof_ipc4_widget_setup_comp_pga(struct snd_sof_widget *swidget) 6644f838ab2SRanjani Sridharan { 6654f838ab2SRanjani Sridharan struct snd_soc_component *scomp = swidget->scomp; 6664f838ab2SRanjani Sridharan struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 6674f838ab2SRanjani Sridharan struct sof_ipc4_fw_module *fw_module; 6684f838ab2SRanjani Sridharan struct snd_sof_control *scontrol; 6694f838ab2SRanjani Sridharan struct sof_ipc4_gain *gain; 6704f838ab2SRanjani Sridharan int ret; 6714f838ab2SRanjani Sridharan 6724f838ab2SRanjani Sridharan gain = kzalloc(sizeof(*gain), GFP_KERNEL); 6734f838ab2SRanjani Sridharan if (!gain) 6744f838ab2SRanjani Sridharan return -ENOMEM; 6754f838ab2SRanjani Sridharan 6764f838ab2SRanjani Sridharan swidget->private = gain; 6774f838ab2SRanjani Sridharan 6784f838ab2SRanjani Sridharan gain->data.channels = SOF_IPC4_GAIN_ALL_CHANNELS_MASK; 6794f838ab2SRanjani Sridharan gain->data.init_val = SOF_IPC4_VOL_ZERO_DB; 6804f838ab2SRanjani Sridharan 6814f838ab2SRanjani Sridharan /* The out_audio_fmt in topology is ignored as it is not required to be sent to the FW */ 6824f838ab2SRanjani Sridharan ret = sof_ipc4_get_audio_fmt(scomp, swidget, &gain->available_fmt, false); 6834f838ab2SRanjani Sridharan if (ret) 6844f838ab2SRanjani Sridharan goto err; 6854f838ab2SRanjani Sridharan 6864f838ab2SRanjani Sridharan ret = sof_update_ipc_object(scomp, &gain->data, SOF_GAIN_TOKENS, swidget->tuples, 6874f838ab2SRanjani Sridharan swidget->num_tuples, sizeof(gain->data), 1); 6884f838ab2SRanjani Sridharan if (ret) { 6894f838ab2SRanjani Sridharan dev_err(scomp->dev, "Parsing gain tokens failed\n"); 6904f838ab2SRanjani Sridharan goto err; 6914f838ab2SRanjani Sridharan } 6924f838ab2SRanjani Sridharan 6934f838ab2SRanjani Sridharan dev_dbg(scomp->dev, 6944f838ab2SRanjani Sridharan "pga widget %s: ramp type: %d, ramp duration %d, initial gain value: %#x, cpc %d\n", 695e45cd86cSRander Wang swidget->widget->name, gain->data.curve_type, gain->data.curve_duration_l, 6964f838ab2SRanjani Sridharan gain->data.init_val, gain->base_config.cpc); 6974f838ab2SRanjani Sridharan 6984f838ab2SRanjani Sridharan ret = sof_ipc4_widget_setup_msg(swidget, &gain->msg); 6994f838ab2SRanjani Sridharan if (ret) 7004f838ab2SRanjani Sridharan goto err; 7014f838ab2SRanjani Sridharan 7024f838ab2SRanjani Sridharan fw_module = swidget->module_info; 7034f838ab2SRanjani Sridharan 7044f838ab2SRanjani Sridharan /* update module ID for all kcontrols for this widget */ 7054f838ab2SRanjani Sridharan list_for_each_entry(scontrol, &sdev->kcontrol_list, list) 7064f838ab2SRanjani Sridharan if (scontrol->comp_id == swidget->comp_id) { 7074f838ab2SRanjani Sridharan struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data; 7084f838ab2SRanjani Sridharan struct sof_ipc4_msg *msg = &cdata->msg; 7094f838ab2SRanjani Sridharan 7104f838ab2SRanjani Sridharan msg->primary |= fw_module->man4_module_entry.id; 7114f838ab2SRanjani Sridharan } 7124f838ab2SRanjani Sridharan 7134f838ab2SRanjani Sridharan return 0; 7144f838ab2SRanjani Sridharan err: 715dc4fc0aeSLibin Yang sof_ipc4_free_audio_fmt(&gain->available_fmt); 7164f838ab2SRanjani Sridharan kfree(gain); 717b737fd8cSLibin Yang swidget->private = NULL; 7184f838ab2SRanjani Sridharan return ret; 7194f838ab2SRanjani Sridharan } 7204f838ab2SRanjani Sridharan 721dc4fc0aeSLibin Yang static void sof_ipc4_widget_free_comp_pga(struct snd_sof_widget *swidget) 722dc4fc0aeSLibin Yang { 723dc4fc0aeSLibin Yang struct sof_ipc4_gain *gain = swidget->private; 724dc4fc0aeSLibin Yang 725dc4fc0aeSLibin Yang if (!gain) 726dc4fc0aeSLibin Yang return; 727dc4fc0aeSLibin Yang 728dc4fc0aeSLibin Yang sof_ipc4_free_audio_fmt(&gain->available_fmt); 729dc4fc0aeSLibin Yang kfree(swidget->private); 730dc4fc0aeSLibin Yang swidget->private = NULL; 731dc4fc0aeSLibin Yang } 732dc4fc0aeSLibin Yang 7334d4ba014SRanjani Sridharan static int sof_ipc4_widget_setup_comp_mixer(struct snd_sof_widget *swidget) 7344d4ba014SRanjani Sridharan { 7354d4ba014SRanjani Sridharan struct snd_soc_component *scomp = swidget->scomp; 7364d4ba014SRanjani Sridharan struct sof_ipc4_mixer *mixer; 7374d4ba014SRanjani Sridharan int ret; 7384d4ba014SRanjani Sridharan 7394d4ba014SRanjani Sridharan dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name); 7404d4ba014SRanjani Sridharan 7414d4ba014SRanjani Sridharan mixer = kzalloc(sizeof(*mixer), GFP_KERNEL); 7424d4ba014SRanjani Sridharan if (!mixer) 7434d4ba014SRanjani Sridharan return -ENOMEM; 7444d4ba014SRanjani Sridharan 7454d4ba014SRanjani Sridharan swidget->private = mixer; 7464d4ba014SRanjani Sridharan 7474d4ba014SRanjani Sridharan /* The out_audio_fmt in topology is ignored as it is not required to be sent to the FW */ 7484d4ba014SRanjani Sridharan ret = sof_ipc4_get_audio_fmt(scomp, swidget, &mixer->available_fmt, false); 7494d4ba014SRanjani Sridharan if (ret) 7504d4ba014SRanjani Sridharan goto err; 7514d4ba014SRanjani Sridharan 7524d4ba014SRanjani Sridharan ret = sof_ipc4_widget_setup_msg(swidget, &mixer->msg); 7534d4ba014SRanjani Sridharan if (ret) 7544d4ba014SRanjani Sridharan goto err; 7554d4ba014SRanjani Sridharan 7564d4ba014SRanjani Sridharan return 0; 7574d4ba014SRanjani Sridharan err: 758dc4fc0aeSLibin Yang sof_ipc4_free_audio_fmt(&mixer->available_fmt); 7594d4ba014SRanjani Sridharan kfree(mixer); 760b737fd8cSLibin Yang swidget->private = NULL; 7614d4ba014SRanjani Sridharan return ret; 7624d4ba014SRanjani Sridharan } 7634d4ba014SRanjani Sridharan 764b85f4fc4SRander Wang static int sof_ipc4_widget_setup_comp_src(struct snd_sof_widget *swidget) 765b85f4fc4SRander Wang { 766b85f4fc4SRander Wang struct snd_soc_component *scomp = swidget->scomp; 767b85f4fc4SRander Wang struct sof_ipc4_src *src; 768b85f4fc4SRander Wang int ret; 769b85f4fc4SRander Wang 770b85f4fc4SRander Wang dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name); 771b85f4fc4SRander Wang 772b85f4fc4SRander Wang src = kzalloc(sizeof(*src), GFP_KERNEL); 773b85f4fc4SRander Wang if (!src) 774b85f4fc4SRander Wang return -ENOMEM; 775b85f4fc4SRander Wang 776b85f4fc4SRander Wang swidget->private = src; 777b85f4fc4SRander Wang 778b85f4fc4SRander Wang /* The out_audio_fmt in topology is ignored as it is not required by SRC */ 779b85f4fc4SRander Wang ret = sof_ipc4_get_audio_fmt(scomp, swidget, &src->available_fmt, false); 780b85f4fc4SRander Wang if (ret) 781b85f4fc4SRander Wang goto err; 782b85f4fc4SRander Wang 783b85f4fc4SRander Wang ret = sof_update_ipc_object(scomp, src, SOF_SRC_TOKENS, swidget->tuples, 784ecdb10dfSYang Yingliang swidget->num_tuples, sizeof(*src), 1); 785b85f4fc4SRander Wang if (ret) { 786b85f4fc4SRander Wang dev_err(scomp->dev, "Parsing SRC tokens failed\n"); 787b85f4fc4SRander Wang goto err; 788b85f4fc4SRander Wang } 789b85f4fc4SRander Wang 790b85f4fc4SRander Wang dev_dbg(scomp->dev, "SRC sink rate %d\n", src->sink_rate); 791b85f4fc4SRander Wang 792b85f4fc4SRander Wang ret = sof_ipc4_widget_setup_msg(swidget, &src->msg); 793b85f4fc4SRander Wang if (ret) 794b85f4fc4SRander Wang goto err; 795b85f4fc4SRander Wang 796b85f4fc4SRander Wang return 0; 797b85f4fc4SRander Wang err: 798b85f4fc4SRander Wang sof_ipc4_free_audio_fmt(&src->available_fmt); 799b85f4fc4SRander Wang kfree(src); 800b85f4fc4SRander Wang swidget->private = NULL; 801b85f4fc4SRander Wang return ret; 802b85f4fc4SRander Wang } 803b85f4fc4SRander Wang 804b85f4fc4SRander Wang static void sof_ipc4_widget_free_comp_src(struct snd_sof_widget *swidget) 805b85f4fc4SRander Wang { 806b85f4fc4SRander Wang struct sof_ipc4_src *src = swidget->private; 807b85f4fc4SRander Wang 808b85f4fc4SRander Wang if (!src) 809b85f4fc4SRander Wang return; 810b85f4fc4SRander Wang 811b85f4fc4SRander Wang sof_ipc4_free_audio_fmt(&src->available_fmt); 812b85f4fc4SRander Wang kfree(swidget->private); 813b85f4fc4SRander Wang swidget->private = NULL; 814b85f4fc4SRander Wang } 815b85f4fc4SRander Wang 816dc4fc0aeSLibin Yang static void sof_ipc4_widget_free_comp_mixer(struct snd_sof_widget *swidget) 817dc4fc0aeSLibin Yang { 818dc4fc0aeSLibin Yang struct sof_ipc4_mixer *mixer = swidget->private; 819dc4fc0aeSLibin Yang 820dc4fc0aeSLibin Yang if (!mixer) 821dc4fc0aeSLibin Yang return; 822dc4fc0aeSLibin Yang 823dc4fc0aeSLibin Yang sof_ipc4_free_audio_fmt(&mixer->available_fmt); 824dc4fc0aeSLibin Yang kfree(swidget->private); 825dc4fc0aeSLibin Yang swidget->private = NULL; 826dc4fc0aeSLibin Yang } 827dc4fc0aeSLibin Yang 828904c48c4SRanjani Sridharan static void 829904c48c4SRanjani Sridharan sof_ipc4_update_pipeline_mem_usage(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget, 830904c48c4SRanjani Sridharan struct sof_ipc4_base_module_cfg *base_config) 831904c48c4SRanjani Sridharan { 832904c48c4SRanjani Sridharan struct sof_ipc4_fw_module *fw_module = swidget->module_info; 833904c48c4SRanjani Sridharan struct snd_sof_widget *pipe_widget; 834904c48c4SRanjani Sridharan struct sof_ipc4_pipeline *pipeline; 835904c48c4SRanjani Sridharan int task_mem, queue_mem; 836904c48c4SRanjani Sridharan int ibs, bss, total; 837904c48c4SRanjani Sridharan 838904c48c4SRanjani Sridharan ibs = base_config->ibs; 839904c48c4SRanjani Sridharan bss = base_config->is_pages; 840904c48c4SRanjani Sridharan 841904c48c4SRanjani Sridharan task_mem = SOF_IPC4_PIPELINE_OBJECT_SIZE; 842904c48c4SRanjani Sridharan task_mem += SOF_IPC4_MODULE_INSTANCE_LIST_ITEM_SIZE + bss; 843904c48c4SRanjani Sridharan 844904c48c4SRanjani Sridharan if (fw_module->man4_module_entry.type & SOF_IPC4_MODULE_LL) { 845904c48c4SRanjani Sridharan task_mem += SOF_IPC4_FW_ROUNDUP(SOF_IPC4_LL_TASK_OBJECT_SIZE); 846904c48c4SRanjani Sridharan task_mem += SOF_IPC4_FW_MAX_QUEUE_COUNT * SOF_IPC4_MODULE_INSTANCE_LIST_ITEM_SIZE; 847904c48c4SRanjani Sridharan task_mem += SOF_IPC4_LL_TASK_LIST_ITEM_SIZE; 848904c48c4SRanjani Sridharan } else { 849904c48c4SRanjani Sridharan task_mem += SOF_IPC4_FW_ROUNDUP(SOF_IPC4_DP_TASK_OBJECT_SIZE); 850904c48c4SRanjani Sridharan task_mem += SOF_IPC4_DP_TASK_LIST_SIZE; 851904c48c4SRanjani Sridharan } 852904c48c4SRanjani Sridharan 853904c48c4SRanjani Sridharan ibs = SOF_IPC4_FW_ROUNDUP(ibs); 854904c48c4SRanjani Sridharan queue_mem = SOF_IPC4_FW_MAX_QUEUE_COUNT * (SOF_IPC4_DATA_QUEUE_OBJECT_SIZE + ibs); 855904c48c4SRanjani Sridharan 856904c48c4SRanjani Sridharan total = SOF_IPC4_FW_PAGE(task_mem + queue_mem); 857904c48c4SRanjani Sridharan 8589c04363dSRanjani Sridharan pipe_widget = swidget->spipe->pipe_widget; 859904c48c4SRanjani Sridharan pipeline = pipe_widget->private; 860904c48c4SRanjani Sridharan pipeline->mem_usage += total; 861904c48c4SRanjani Sridharan } 862904c48c4SRanjani Sridharan 863904c48c4SRanjani Sridharan static int sof_ipc4_widget_assign_instance_id(struct snd_sof_dev *sdev, 864904c48c4SRanjani Sridharan struct snd_sof_widget *swidget) 865904c48c4SRanjani Sridharan { 866904c48c4SRanjani Sridharan struct sof_ipc4_fw_module *fw_module = swidget->module_info; 867904c48c4SRanjani Sridharan int max_instances = fw_module->man4_module_entry.instance_max_count; 868904c48c4SRanjani Sridharan 869904c48c4SRanjani Sridharan swidget->instance_id = ida_alloc_max(&fw_module->m_ida, max_instances, GFP_KERNEL); 870904c48c4SRanjani Sridharan if (swidget->instance_id < 0) { 871904c48c4SRanjani Sridharan dev_err(sdev->dev, "failed to assign instance id for widget %s", 872904c48c4SRanjani Sridharan swidget->widget->name); 873904c48c4SRanjani Sridharan return swidget->instance_id; 874904c48c4SRanjani Sridharan } 875904c48c4SRanjani Sridharan 876904c48c4SRanjani Sridharan return 0; 877904c48c4SRanjani Sridharan } 878904c48c4SRanjani Sridharan 879904c48c4SRanjani Sridharan static int sof_ipc4_init_audio_fmt(struct snd_sof_dev *sdev, 880904c48c4SRanjani Sridharan struct snd_sof_widget *swidget, 881904c48c4SRanjani Sridharan struct sof_ipc4_base_module_cfg *base_config, 882904c48c4SRanjani Sridharan struct sof_ipc4_audio_format *out_format, 883904c48c4SRanjani Sridharan struct snd_pcm_hw_params *params, 884904c48c4SRanjani Sridharan struct sof_ipc4_available_audio_format *available_fmt, 885904c48c4SRanjani Sridharan size_t object_offset) 886904c48c4SRanjani Sridharan { 887904c48c4SRanjani Sridharan void *ptr = available_fmt->ref_audio_fmt; 888904c48c4SRanjani Sridharan u32 valid_bits; 889904c48c4SRanjani Sridharan u32 channels; 890904c48c4SRanjani Sridharan u32 rate; 891904c48c4SRanjani Sridharan int sample_valid_bits; 892904c48c4SRanjani Sridharan int i; 893904c48c4SRanjani Sridharan 894904c48c4SRanjani Sridharan if (!ptr) { 895904c48c4SRanjani Sridharan dev_err(sdev->dev, "no reference formats for %s\n", swidget->widget->name); 896904c48c4SRanjani Sridharan return -EINVAL; 897904c48c4SRanjani Sridharan } 898904c48c4SRanjani Sridharan 899904c48c4SRanjani Sridharan switch (params_format(params)) { 900904c48c4SRanjani Sridharan case SNDRV_PCM_FORMAT_S16_LE: 901904c48c4SRanjani Sridharan sample_valid_bits = 16; 902904c48c4SRanjani Sridharan break; 903904c48c4SRanjani Sridharan case SNDRV_PCM_FORMAT_S24_LE: 904904c48c4SRanjani Sridharan sample_valid_bits = 24; 905904c48c4SRanjani Sridharan break; 906904c48c4SRanjani Sridharan case SNDRV_PCM_FORMAT_S32_LE: 907904c48c4SRanjani Sridharan sample_valid_bits = 32; 908904c48c4SRanjani Sridharan break; 909904c48c4SRanjani Sridharan default: 910904c48c4SRanjani Sridharan dev_err(sdev->dev, "invalid pcm frame format %d\n", params_format(params)); 911904c48c4SRanjani Sridharan return -EINVAL; 912904c48c4SRanjani Sridharan } 913904c48c4SRanjani Sridharan 914904c48c4SRanjani Sridharan if (!available_fmt->audio_fmt_num) { 915904c48c4SRanjani Sridharan dev_err(sdev->dev, "no formats available for %s\n", swidget->widget->name); 916904c48c4SRanjani Sridharan return -EINVAL; 917904c48c4SRanjani Sridharan } 918904c48c4SRanjani Sridharan 919904c48c4SRanjani Sridharan /* 920904c48c4SRanjani Sridharan * Search supported audio formats to match rate, channels ,and 921904c48c4SRanjani Sridharan * sample_valid_bytes from runtime params 922904c48c4SRanjani Sridharan */ 923904c48c4SRanjani Sridharan for (i = 0; i < available_fmt->audio_fmt_num; i++, ptr = (u8 *)ptr + object_offset) { 924904c48c4SRanjani Sridharan struct sof_ipc4_audio_format *fmt = ptr; 925904c48c4SRanjani Sridharan 926904c48c4SRanjani Sridharan rate = fmt->sampling_frequency; 927904c48c4SRanjani Sridharan channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg); 928904c48c4SRanjani Sridharan valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg); 929904c48c4SRanjani Sridharan if (params_rate(params) == rate && params_channels(params) == channels && 930904c48c4SRanjani Sridharan sample_valid_bits == valid_bits) { 9313809264bSPierre-Louis Bossart dev_dbg(sdev->dev, "matching audio format index for %uHz, %ubit, %u channels: %d\n", 9323809264bSPierre-Louis Bossart rate, valid_bits, channels, i); 933904c48c4SRanjani Sridharan 934904c48c4SRanjani Sridharan /* copy ibs/obs and input format */ 935904c48c4SRanjani Sridharan memcpy(base_config, &available_fmt->base_config[i], 936904c48c4SRanjani Sridharan sizeof(struct sof_ipc4_base_module_cfg)); 937904c48c4SRanjani Sridharan 938904c48c4SRanjani Sridharan /* copy output format */ 939904c48c4SRanjani Sridharan if (out_format) 940904c48c4SRanjani Sridharan memcpy(out_format, &available_fmt->out_audio_fmt[i], 941904c48c4SRanjani Sridharan sizeof(struct sof_ipc4_audio_format)); 942904c48c4SRanjani Sridharan break; 943904c48c4SRanjani Sridharan } 944904c48c4SRanjani Sridharan } 945904c48c4SRanjani Sridharan 946904c48c4SRanjani Sridharan if (i == available_fmt->audio_fmt_num) { 947904c48c4SRanjani Sridharan dev_err(sdev->dev, "%s: Unsupported audio format: %uHz, %ubit, %u channels\n", 948904c48c4SRanjani Sridharan __func__, params_rate(params), sample_valid_bits, params_channels(params)); 949904c48c4SRanjani Sridharan return -EINVAL; 950904c48c4SRanjani Sridharan } 951904c48c4SRanjani Sridharan 952904c48c4SRanjani Sridharan dev_dbg(sdev->dev, "Init input audio formats for %s\n", swidget->widget->name); 953904c48c4SRanjani Sridharan sof_ipc4_dbg_audio_format(sdev->dev, &base_config->audio_fmt, 954904c48c4SRanjani Sridharan sizeof(*base_config), 1); 955904c48c4SRanjani Sridharan if (out_format) { 956904c48c4SRanjani Sridharan dev_dbg(sdev->dev, "Init output audio formats for %s\n", swidget->widget->name); 957904c48c4SRanjani Sridharan sof_ipc4_dbg_audio_format(sdev->dev, out_format, 958904c48c4SRanjani Sridharan sizeof(*out_format), 1); 959904c48c4SRanjani Sridharan } 960904c48c4SRanjani Sridharan 961904c48c4SRanjani Sridharan /* Return the index of the matched format */ 962904c48c4SRanjani Sridharan return i; 963904c48c4SRanjani Sridharan } 964904c48c4SRanjani Sridharan 965904c48c4SRanjani Sridharan static void sof_ipc4_unprepare_copier_module(struct snd_sof_widget *swidget) 966904c48c4SRanjani Sridharan { 967904c48c4SRanjani Sridharan struct sof_ipc4_copier *ipc4_copier = NULL; 968904c48c4SRanjani Sridharan struct snd_sof_widget *pipe_widget; 969904c48c4SRanjani Sridharan struct sof_ipc4_pipeline *pipeline; 970904c48c4SRanjani Sridharan 971904c48c4SRanjani Sridharan /* reset pipeline memory usage */ 9729c04363dSRanjani Sridharan pipe_widget = swidget->spipe->pipe_widget; 973904c48c4SRanjani Sridharan pipeline = pipe_widget->private; 974904c48c4SRanjani Sridharan pipeline->mem_usage = 0; 975904c48c4SRanjani Sridharan 9767d573425SBard Liao if (WIDGET_IS_AIF(swidget->id) || swidget->id == snd_soc_dapm_buffer) { 977904c48c4SRanjani Sridharan ipc4_copier = swidget->private; 978acf52594SRanjani Sridharan } else if (WIDGET_IS_DAI(swidget->id)) { 979acf52594SRanjani Sridharan struct snd_sof_dai *dai = swidget->private; 980acf52594SRanjani Sridharan 981acf52594SRanjani Sridharan ipc4_copier = dai->private; 982a150345aSBard Liao if (ipc4_copier->dai_type == SOF_DAI_INTEL_ALH) { 983b66bfc3aSRanjani Sridharan struct sof_ipc4_copier_data *copier_data = &ipc4_copier->data; 984a150345aSBard Liao struct sof_ipc4_alh_configuration_blob *blob; 985a150345aSBard Liao unsigned int group_id; 986a150345aSBard Liao 987a150345aSBard Liao blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config; 988a150345aSBard Liao if (blob->alh_cfg.count > 1) { 989a150345aSBard Liao group_id = SOF_IPC4_NODE_INDEX(ipc4_copier->data.gtw_cfg.node_id) - 990a150345aSBard Liao ALH_MULTI_GTW_BASE; 991a150345aSBard Liao ida_free(&alh_group_ida, group_id); 992a150345aSBard Liao } 993b66bfc3aSRanjani Sridharan 994b66bfc3aSRanjani Sridharan /* clear the node ID */ 995b66bfc3aSRanjani Sridharan copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK; 996a150345aSBard Liao } 997acf52594SRanjani Sridharan } 998904c48c4SRanjani Sridharan 999904c48c4SRanjani Sridharan if (ipc4_copier) { 1000904c48c4SRanjani Sridharan kfree(ipc4_copier->ipc_config_data); 1001904c48c4SRanjani Sridharan ipc4_copier->ipc_config_data = NULL; 1002904c48c4SRanjani Sridharan ipc4_copier->ipc_config_size = 0; 1003904c48c4SRanjani Sridharan } 1004904c48c4SRanjani Sridharan } 1005904c48c4SRanjani Sridharan 1006aa84ffb7SRanjani Sridharan #if IS_ENABLED(CONFIG_ACPI) && IS_ENABLED(CONFIG_SND_INTEL_NHLT) 1007aa84ffb7SRanjani Sridharan static int snd_sof_get_hw_config_params(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, 1008aa84ffb7SRanjani Sridharan int *sample_rate, int *channel_count, int *bit_depth) 1009aa84ffb7SRanjani Sridharan { 1010aa84ffb7SRanjani Sridharan struct snd_soc_tplg_hw_config *hw_config; 1011aa84ffb7SRanjani Sridharan struct snd_sof_dai_link *slink; 1012aa84ffb7SRanjani Sridharan bool dai_link_found = false; 1013aa84ffb7SRanjani Sridharan bool hw_cfg_found = false; 1014aa84ffb7SRanjani Sridharan int i; 1015aa84ffb7SRanjani Sridharan 1016aa84ffb7SRanjani Sridharan /* get current hw_config from link */ 1017aa84ffb7SRanjani Sridharan list_for_each_entry(slink, &sdev->dai_link_list, list) { 1018aa84ffb7SRanjani Sridharan if (!strcmp(slink->link->name, dai->name)) { 1019aa84ffb7SRanjani Sridharan dai_link_found = true; 1020aa84ffb7SRanjani Sridharan break; 1021aa84ffb7SRanjani Sridharan } 1022aa84ffb7SRanjani Sridharan } 1023aa84ffb7SRanjani Sridharan 1024aa84ffb7SRanjani Sridharan if (!dai_link_found) { 1025aa84ffb7SRanjani Sridharan dev_err(sdev->dev, "%s: no DAI link found for DAI %s\n", __func__, dai->name); 1026aa84ffb7SRanjani Sridharan return -EINVAL; 1027aa84ffb7SRanjani Sridharan } 1028aa84ffb7SRanjani Sridharan 1029aa84ffb7SRanjani Sridharan for (i = 0; i < slink->num_hw_configs; i++) { 1030aa84ffb7SRanjani Sridharan hw_config = &slink->hw_configs[i]; 1031aa84ffb7SRanjani Sridharan if (dai->current_config == le32_to_cpu(hw_config->id)) { 1032aa84ffb7SRanjani Sridharan hw_cfg_found = true; 1033aa84ffb7SRanjani Sridharan break; 1034aa84ffb7SRanjani Sridharan } 1035aa84ffb7SRanjani Sridharan } 1036aa84ffb7SRanjani Sridharan 1037aa84ffb7SRanjani Sridharan if (!hw_cfg_found) { 1038aa84ffb7SRanjani Sridharan dev_err(sdev->dev, "%s: no matching hw_config found for DAI %s\n", __func__, 1039aa84ffb7SRanjani Sridharan dai->name); 1040aa84ffb7SRanjani Sridharan return -EINVAL; 1041aa84ffb7SRanjani Sridharan } 1042aa84ffb7SRanjani Sridharan 1043aa84ffb7SRanjani Sridharan *bit_depth = le32_to_cpu(hw_config->tdm_slot_width); 1044aa84ffb7SRanjani Sridharan *channel_count = le32_to_cpu(hw_config->tdm_slots); 1045aa84ffb7SRanjani Sridharan *sample_rate = le32_to_cpu(hw_config->fsync_rate); 1046aa84ffb7SRanjani Sridharan 10473809264bSPierre-Louis Bossart dev_dbg(sdev->dev, "sample rate: %d sample width: %d channels: %d\n", 10483809264bSPierre-Louis Bossart *sample_rate, *bit_depth, *channel_count); 1049aa84ffb7SRanjani Sridharan 1050aa84ffb7SRanjani Sridharan return 0; 1051aa84ffb7SRanjani Sridharan } 1052aa84ffb7SRanjani Sridharan 1053aa84ffb7SRanjani Sridharan static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, 1054aa84ffb7SRanjani Sridharan struct snd_pcm_hw_params *params, u32 dai_index, 1055aa84ffb7SRanjani Sridharan u32 linktype, u8 dir, u32 **dst, u32 *len) 1056aa84ffb7SRanjani Sridharan { 1057aa84ffb7SRanjani Sridharan struct sof_ipc4_fw_data *ipc4_data = sdev->private; 1058aa84ffb7SRanjani Sridharan struct nhlt_specific_cfg *cfg; 1059aa84ffb7SRanjani Sridharan int sample_rate, channel_count; 1060aa84ffb7SRanjani Sridharan int bit_depth, ret; 1061aa84ffb7SRanjani Sridharan u32 nhlt_type; 1062aa84ffb7SRanjani Sridharan 1063aa84ffb7SRanjani Sridharan /* convert to NHLT type */ 1064aa84ffb7SRanjani Sridharan switch (linktype) { 1065aa84ffb7SRanjani Sridharan case SOF_DAI_INTEL_DMIC: 1066aa84ffb7SRanjani Sridharan nhlt_type = NHLT_LINK_DMIC; 1067aa84ffb7SRanjani Sridharan bit_depth = params_width(params); 1068aa84ffb7SRanjani Sridharan channel_count = params_channels(params); 1069aa84ffb7SRanjani Sridharan sample_rate = params_rate(params); 1070aa84ffb7SRanjani Sridharan break; 1071aa84ffb7SRanjani Sridharan case SOF_DAI_INTEL_SSP: 1072aa84ffb7SRanjani Sridharan nhlt_type = NHLT_LINK_SSP; 1073aa84ffb7SRanjani Sridharan ret = snd_sof_get_hw_config_params(sdev, dai, &sample_rate, &channel_count, 1074aa84ffb7SRanjani Sridharan &bit_depth); 1075aa84ffb7SRanjani Sridharan if (ret < 0) 1076aa84ffb7SRanjani Sridharan return ret; 1077aa84ffb7SRanjani Sridharan break; 1078aa84ffb7SRanjani Sridharan default: 1079aa84ffb7SRanjani Sridharan return 0; 1080aa84ffb7SRanjani Sridharan } 1081aa84ffb7SRanjani Sridharan 10823809264bSPierre-Louis Bossart dev_dbg(sdev->dev, "dai index %d nhlt type %d direction %d\n", 10833809264bSPierre-Louis Bossart dai_index, nhlt_type, dir); 1084aa84ffb7SRanjani Sridharan 1085aa84ffb7SRanjani Sridharan /* find NHLT blob with matching params */ 1086aa84ffb7SRanjani Sridharan cfg = intel_nhlt_get_endpoint_blob(sdev->dev, ipc4_data->nhlt, dai_index, nhlt_type, 1087aa84ffb7SRanjani Sridharan bit_depth, bit_depth, channel_count, sample_rate, 1088aa84ffb7SRanjani Sridharan dir, 0); 1089aa84ffb7SRanjani Sridharan 1090aa84ffb7SRanjani Sridharan if (!cfg) { 1091aa84ffb7SRanjani Sridharan dev_err(sdev->dev, 1092aa84ffb7SRanjani Sridharan "no matching blob for sample rate: %d sample width: %d channels: %d\n", 1093aa84ffb7SRanjani Sridharan sample_rate, bit_depth, channel_count); 1094aa84ffb7SRanjani Sridharan return -EINVAL; 1095aa84ffb7SRanjani Sridharan } 1096aa84ffb7SRanjani Sridharan 1097aa84ffb7SRanjani Sridharan /* config length should be in dwords */ 1098aa84ffb7SRanjani Sridharan *len = cfg->size >> 2; 1099aa84ffb7SRanjani Sridharan *dst = (u32 *)cfg->caps; 1100aa84ffb7SRanjani Sridharan 1101aa84ffb7SRanjani Sridharan return 0; 1102aa84ffb7SRanjani Sridharan } 1103aa84ffb7SRanjani Sridharan #else 1104aa84ffb7SRanjani Sridharan static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, 1105aa84ffb7SRanjani Sridharan struct snd_pcm_hw_params *params, u32 dai_index, 1106aa84ffb7SRanjani Sridharan u32 linktype, u8 dir, u32 **dst, u32 *len) 1107aa84ffb7SRanjani Sridharan { 1108aa84ffb7SRanjani Sridharan return 0; 1109aa84ffb7SRanjani Sridharan } 1110aa84ffb7SRanjani Sridharan #endif 1111aa84ffb7SRanjani Sridharan 1112904c48c4SRanjani Sridharan static int 1113904c48c4SRanjani Sridharan sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, 1114904c48c4SRanjani Sridharan struct snd_pcm_hw_params *fe_params, 1115904c48c4SRanjani Sridharan struct snd_sof_platform_stream_params *platform_params, 1116904c48c4SRanjani Sridharan struct snd_pcm_hw_params *pipeline_params, int dir) 1117904c48c4SRanjani Sridharan { 1118904c48c4SRanjani Sridharan struct sof_ipc4_available_audio_format *available_fmt; 1119904c48c4SRanjani Sridharan struct snd_soc_component *scomp = swidget->scomp; 1120904c48c4SRanjani Sridharan struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 1121904c48c4SRanjani Sridharan struct sof_ipc4_copier_data *copier_data; 1122904c48c4SRanjani Sridharan struct snd_pcm_hw_params *ref_params; 1123904c48c4SRanjani Sridharan struct sof_ipc4_copier *ipc4_copier; 1124a150345aSBard Liao struct snd_sof_dai *dai; 1125904c48c4SRanjani Sridharan struct snd_mask *fmt; 1126904c48c4SRanjani Sridharan int out_sample_valid_bits; 1127904c48c4SRanjani Sridharan size_t ref_audio_fmt_size; 1128904c48c4SRanjani Sridharan void **ipc_config_data; 1129904c48c4SRanjani Sridharan int *ipc_config_size; 1130904c48c4SRanjani Sridharan u32 **data; 1131904c48c4SRanjani Sridharan int ipc_size, ret; 1132904c48c4SRanjani Sridharan 11333809264bSPierre-Louis Bossart dev_dbg(sdev->dev, "copier %s, type %d", swidget->widget->name, swidget->id); 1134904c48c4SRanjani Sridharan 1135904c48c4SRanjani Sridharan switch (swidget->id) { 1136904c48c4SRanjani Sridharan case snd_soc_dapm_aif_in: 1137904c48c4SRanjani Sridharan case snd_soc_dapm_aif_out: 1138904c48c4SRanjani Sridharan { 1139904c48c4SRanjani Sridharan struct sof_ipc4_gtw_attributes *gtw_attr; 1140904c48c4SRanjani Sridharan struct snd_sof_widget *pipe_widget; 1141904c48c4SRanjani Sridharan struct sof_ipc4_pipeline *pipeline; 1142904c48c4SRanjani Sridharan 11439c04363dSRanjani Sridharan pipe_widget = swidget->spipe->pipe_widget; 1144904c48c4SRanjani Sridharan pipeline = pipe_widget->private; 1145904c48c4SRanjani Sridharan ipc4_copier = (struct sof_ipc4_copier *)swidget->private; 1146904c48c4SRanjani Sridharan gtw_attr = ipc4_copier->gtw_attr; 1147904c48c4SRanjani Sridharan copier_data = &ipc4_copier->data; 1148904c48c4SRanjani Sridharan available_fmt = &ipc4_copier->available_fmt; 1149904c48c4SRanjani Sridharan 1150904c48c4SRanjani Sridharan /* 1151904c48c4SRanjani Sridharan * base_config->audio_fmt and out_audio_fmt represent the input and output audio 1152904c48c4SRanjani Sridharan * formats. Use the input format as the reference to match pcm params for playback 1153904c48c4SRanjani Sridharan * and the output format as reference for capture. 1154904c48c4SRanjani Sridharan */ 1155904c48c4SRanjani Sridharan if (dir == SNDRV_PCM_STREAM_PLAYBACK) { 1156904c48c4SRanjani Sridharan available_fmt->ref_audio_fmt = &available_fmt->base_config->audio_fmt; 1157904c48c4SRanjani Sridharan ref_audio_fmt_size = sizeof(struct sof_ipc4_base_module_cfg); 1158904c48c4SRanjani Sridharan } else { 1159904c48c4SRanjani Sridharan available_fmt->ref_audio_fmt = available_fmt->out_audio_fmt; 1160904c48c4SRanjani Sridharan ref_audio_fmt_size = sizeof(struct sof_ipc4_audio_format); 1161904c48c4SRanjani Sridharan } 1162904c48c4SRanjani Sridharan copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK; 1163904c48c4SRanjani Sridharan copier_data->gtw_cfg.node_id |= 1164904c48c4SRanjani Sridharan SOF_IPC4_NODE_INDEX(platform_params->stream_tag - 1); 1165904c48c4SRanjani Sridharan 1166904c48c4SRanjani Sridharan /* set gateway attributes */ 1167904c48c4SRanjani Sridharan gtw_attr->lp_buffer_alloc = pipeline->lp_mode; 1168904c48c4SRanjani Sridharan ref_params = fe_params; 1169904c48c4SRanjani Sridharan break; 1170904c48c4SRanjani Sridharan } 1171acf52594SRanjani Sridharan case snd_soc_dapm_dai_in: 1172acf52594SRanjani Sridharan case snd_soc_dapm_dai_out: 1173acf52594SRanjani Sridharan { 1174a150345aSBard Liao dai = swidget->private; 1175acf52594SRanjani Sridharan 1176acf52594SRanjani Sridharan ipc4_copier = (struct sof_ipc4_copier *)dai->private; 1177acf52594SRanjani Sridharan copier_data = &ipc4_copier->data; 1178acf52594SRanjani Sridharan available_fmt = &ipc4_copier->available_fmt; 1179acf52594SRanjani Sridharan if (dir == SNDRV_PCM_STREAM_CAPTURE) { 1180acf52594SRanjani Sridharan available_fmt->ref_audio_fmt = available_fmt->out_audio_fmt; 1181acf52594SRanjani Sridharan ref_audio_fmt_size = sizeof(struct sof_ipc4_audio_format); 1182acf52594SRanjani Sridharan 1183acf52594SRanjani Sridharan /* 1184acf52594SRanjani Sridharan * modify the input params for the dai copier as it only supports 1185acf52594SRanjani Sridharan * 32-bit always 1186acf52594SRanjani Sridharan */ 1187acf52594SRanjani Sridharan fmt = hw_param_mask(pipeline_params, SNDRV_PCM_HW_PARAM_FORMAT); 1188acf52594SRanjani Sridharan snd_mask_none(fmt); 1189acf52594SRanjani Sridharan snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE); 1190acf52594SRanjani Sridharan } else { 1191acf52594SRanjani Sridharan available_fmt->ref_audio_fmt = &available_fmt->base_config->audio_fmt; 1192acf52594SRanjani Sridharan ref_audio_fmt_size = sizeof(struct sof_ipc4_base_module_cfg); 1193acf52594SRanjani Sridharan } 1194acf52594SRanjani Sridharan 1195acf52594SRanjani Sridharan ref_params = pipeline_params; 1196acf52594SRanjani Sridharan 1197aa84ffb7SRanjani Sridharan ret = snd_sof_get_nhlt_endpoint_data(sdev, dai, fe_params, ipc4_copier->dai_index, 1198aa84ffb7SRanjani Sridharan ipc4_copier->dai_type, dir, 1199aa84ffb7SRanjani Sridharan &ipc4_copier->copier_config, 1200aa84ffb7SRanjani Sridharan &copier_data->gtw_cfg.config_length); 1201aa84ffb7SRanjani Sridharan if (ret < 0) 1202aa84ffb7SRanjani Sridharan return ret; 1203aa84ffb7SRanjani Sridharan 1204acf52594SRanjani Sridharan break; 1205acf52594SRanjani Sridharan } 12067d573425SBard Liao case snd_soc_dapm_buffer: 12077d573425SBard Liao { 12087d573425SBard Liao ipc4_copier = (struct sof_ipc4_copier *)swidget->private; 12097d573425SBard Liao copier_data = &ipc4_copier->data; 12107d573425SBard Liao available_fmt = &ipc4_copier->available_fmt; 12117d573425SBard Liao 12127d573425SBard Liao /* 12137d573425SBard Liao * base_config->audio_fmt represent the input audio formats. Use 12147d573425SBard Liao * the input format as the reference to match pcm params 12157d573425SBard Liao */ 12167d573425SBard Liao available_fmt->ref_audio_fmt = &available_fmt->base_config->audio_fmt; 12177d573425SBard Liao ref_audio_fmt_size = sizeof(struct sof_ipc4_base_module_cfg); 12187d573425SBard Liao ref_params = pipeline_params; 12197d573425SBard Liao 12207d573425SBard Liao break; 12217d573425SBard Liao } 1222904c48c4SRanjani Sridharan default: 1223904c48c4SRanjani Sridharan dev_err(sdev->dev, "unsupported type %d for copier %s", 1224904c48c4SRanjani Sridharan swidget->id, swidget->widget->name); 1225904c48c4SRanjani Sridharan return -EINVAL; 1226904c48c4SRanjani Sridharan } 1227904c48c4SRanjani Sridharan 1228904c48c4SRanjani Sridharan /* set input and output audio formats */ 1229904c48c4SRanjani Sridharan ret = sof_ipc4_init_audio_fmt(sdev, swidget, &copier_data->base_config, 1230904c48c4SRanjani Sridharan &copier_data->out_format, ref_params, 1231904c48c4SRanjani Sridharan available_fmt, ref_audio_fmt_size); 1232904c48c4SRanjani Sridharan if (ret < 0) 1233904c48c4SRanjani Sridharan return ret; 1234904c48c4SRanjani Sridharan 1235a45a4d43SBard Liao switch (swidget->id) { 1236a45a4d43SBard Liao case snd_soc_dapm_dai_in: 1237a45a4d43SBard Liao case snd_soc_dapm_dai_out: 1238a45a4d43SBard Liao { 1239a45a4d43SBard Liao /* 1240a45a4d43SBard Liao * Only SOF_DAI_INTEL_ALH needs copier_data to set blob. 1241a45a4d43SBard Liao * That's why only ALH dai's blob is set after sof_ipc4_init_audio_fmt 1242a45a4d43SBard Liao */ 1243a45a4d43SBard Liao if (ipc4_copier->dai_type == SOF_DAI_INTEL_ALH) { 1244a45a4d43SBard Liao struct sof_ipc4_alh_configuration_blob *blob; 1245a150345aSBard Liao struct sof_ipc4_copier_data *alh_data; 1246a150345aSBard Liao struct sof_ipc4_copier *alh_copier; 1247a150345aSBard Liao struct snd_sof_widget *w; 12480390a102SBard Liao u32 ch_count = 0; 1249a150345aSBard Liao u32 ch_mask = 0; 1250a45a4d43SBard Liao u32 ch_map; 12510390a102SBard Liao u32 step; 12520390a102SBard Liao u32 mask; 1253a45a4d43SBard Liao int i; 1254a45a4d43SBard Liao 1255a45a4d43SBard Liao blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config; 1256a150345aSBard Liao 1257a45a4d43SBard Liao blob->gw_attr.lp_buffer_alloc = 0; 1258a45a4d43SBard Liao 1259a45a4d43SBard Liao /* Get channel_mask from ch_map */ 1260a45a4d43SBard Liao ch_map = copier_data->base_config.audio_fmt.ch_map; 1261a45a4d43SBard Liao for (i = 0; ch_map; i++) { 12620390a102SBard Liao if ((ch_map & 0xf) != 0xf) { 1263a150345aSBard Liao ch_mask |= BIT(i); 12640390a102SBard Liao ch_count++; 12650390a102SBard Liao } 1266a45a4d43SBard Liao ch_map >>= 4; 1267a45a4d43SBard Liao } 1268a150345aSBard Liao 12690390a102SBard Liao step = ch_count / blob->alh_cfg.count; 12700390a102SBard Liao mask = GENMASK(step - 1, 0); 1271a150345aSBard Liao /* 1272a150345aSBard Liao * Set each gtw_cfg.node_id to blob->alh_cfg.mapping[] 1273a150345aSBard Liao * for all widgets with the same stream name 1274a150345aSBard Liao */ 1275a150345aSBard Liao i = 0; 1276a150345aSBard Liao list_for_each_entry(w, &sdev->widget_list, list) { 1277a150345aSBard Liao if (w->widget->sname && 1278a150345aSBard Liao strcmp(w->widget->sname, swidget->widget->sname)) 1279a150345aSBard Liao continue; 1280a150345aSBard Liao 1281a150345aSBard Liao dai = w->private; 1282a150345aSBard Liao alh_copier = (struct sof_ipc4_copier *)dai->private; 1283a150345aSBard Liao alh_data = &alh_copier->data; 1284a150345aSBard Liao blob->alh_cfg.mapping[i].alh_id = alh_data->gtw_cfg.node_id; 12850390a102SBard Liao /* 12860390a102SBard Liao * Set the same channel mask for playback as the audio data is 12870390a102SBard Liao * duplicated for all speakers. For capture, split the channels 12880390a102SBard Liao * among the aggregated DAIs. For example, with 4 channels on 2 12890390a102SBard Liao * aggregated DAIs, the channel_mask should be 0x3 and 0xc for the 12900390a102SBard Liao * two DAI's. 12910390a102SBard Liao * The channel masks used depend on the cpu_dais used in the 12920390a102SBard Liao * dailink at the machine driver level, which actually comes from 12930390a102SBard Liao * the tables in soc_acpi files depending on the _ADR and devID 12940390a102SBard Liao * registers for each codec. 12950390a102SBard Liao */ 12960390a102SBard Liao if (w->id == snd_soc_dapm_dai_in) 1297a150345aSBard Liao blob->alh_cfg.mapping[i].channel_mask = ch_mask; 12980390a102SBard Liao else 12990390a102SBard Liao blob->alh_cfg.mapping[i].channel_mask = mask << (step * i); 13000390a102SBard Liao 1301a150345aSBard Liao i++; 1302a150345aSBard Liao } 1303a150345aSBard Liao if (blob->alh_cfg.count > 1) { 1304a150345aSBard Liao int group_id; 1305a150345aSBard Liao 13064ee6fc27SBard Liao group_id = ida_alloc_max(&alh_group_ida, ALH_MULTI_GTW_COUNT - 1, 1307a150345aSBard Liao GFP_KERNEL); 1308a150345aSBard Liao 1309a150345aSBard Liao if (group_id < 0) 1310a150345aSBard Liao return group_id; 1311a150345aSBard Liao 1312a150345aSBard Liao /* add multi-gateway base */ 1313a150345aSBard Liao group_id += ALH_MULTI_GTW_BASE; 1314a150345aSBard Liao copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK; 1315a150345aSBard Liao copier_data->gtw_cfg.node_id |= SOF_IPC4_NODE_INDEX(group_id); 1316a150345aSBard Liao } 1317a45a4d43SBard Liao } 1318a45a4d43SBard Liao } 1319a45a4d43SBard Liao } 1320a45a4d43SBard Liao 1321904c48c4SRanjani Sridharan /* modify the input params for the next widget */ 1322904c48c4SRanjani Sridharan fmt = hw_param_mask(pipeline_params, SNDRV_PCM_HW_PARAM_FORMAT); 1323904c48c4SRanjani Sridharan out_sample_valid_bits = 1324904c48c4SRanjani Sridharan SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(copier_data->out_format.fmt_cfg); 1325904c48c4SRanjani Sridharan snd_mask_none(fmt); 1326904c48c4SRanjani Sridharan switch (out_sample_valid_bits) { 1327904c48c4SRanjani Sridharan case 16: 1328904c48c4SRanjani Sridharan snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE); 1329904c48c4SRanjani Sridharan break; 1330904c48c4SRanjani Sridharan case 24: 1331904c48c4SRanjani Sridharan snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); 1332904c48c4SRanjani Sridharan break; 1333904c48c4SRanjani Sridharan case 32: 1334904c48c4SRanjani Sridharan snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE); 1335904c48c4SRanjani Sridharan break; 1336904c48c4SRanjani Sridharan default: 1337904c48c4SRanjani Sridharan dev_err(sdev->dev, "invalid sample frame format %d\n", 1338904c48c4SRanjani Sridharan params_format(pipeline_params)); 1339904c48c4SRanjani Sridharan return -EINVAL; 1340904c48c4SRanjani Sridharan } 1341904c48c4SRanjani Sridharan 1342904c48c4SRanjani Sridharan /* set the gateway dma_buffer_size using the matched ID returned above */ 1343904c48c4SRanjani Sridharan copier_data->gtw_cfg.dma_buffer_size = available_fmt->dma_buffer_size[ret]; 1344904c48c4SRanjani Sridharan 1345904c48c4SRanjani Sridharan data = &ipc4_copier->copier_config; 1346904c48c4SRanjani Sridharan ipc_config_size = &ipc4_copier->ipc_config_size; 1347904c48c4SRanjani Sridharan ipc_config_data = &ipc4_copier->ipc_config_data; 1348904c48c4SRanjani Sridharan 1349904c48c4SRanjani Sridharan /* config_length is DWORD based */ 1350904c48c4SRanjani Sridharan ipc_size = sizeof(*copier_data) + copier_data->gtw_cfg.config_length * 4; 1351904c48c4SRanjani Sridharan 1352904c48c4SRanjani Sridharan dev_dbg(sdev->dev, "copier %s, IPC size is %d", swidget->widget->name, ipc_size); 1353904c48c4SRanjani Sridharan 1354904c48c4SRanjani Sridharan *ipc_config_data = kzalloc(ipc_size, GFP_KERNEL); 1355904c48c4SRanjani Sridharan if (!*ipc_config_data) 1356904c48c4SRanjani Sridharan return -ENOMEM; 1357904c48c4SRanjani Sridharan 1358904c48c4SRanjani Sridharan *ipc_config_size = ipc_size; 1359904c48c4SRanjani Sridharan 1360904c48c4SRanjani Sridharan /* copy IPC data */ 1361904c48c4SRanjani Sridharan memcpy(*ipc_config_data, (void *)copier_data, sizeof(*copier_data)); 1362904c48c4SRanjani Sridharan if (copier_data->gtw_cfg.config_length) 1363904c48c4SRanjani Sridharan memcpy(*ipc_config_data + sizeof(*copier_data), 1364904c48c4SRanjani Sridharan *data, copier_data->gtw_cfg.config_length * 4); 1365904c48c4SRanjani Sridharan 1366904c48c4SRanjani Sridharan /* update pipeline memory usage */ 1367904c48c4SRanjani Sridharan sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &copier_data->base_config); 1368904c48c4SRanjani Sridharan 1369711d0427SBard Liao return 0; 13704f838ab2SRanjani Sridharan } 13714f838ab2SRanjani Sridharan 13724f838ab2SRanjani Sridharan static int sof_ipc4_prepare_gain_module(struct snd_sof_widget *swidget, 13734f838ab2SRanjani Sridharan struct snd_pcm_hw_params *fe_params, 13744f838ab2SRanjani Sridharan struct snd_sof_platform_stream_params *platform_params, 13754f838ab2SRanjani Sridharan struct snd_pcm_hw_params *pipeline_params, int dir) 13764f838ab2SRanjani Sridharan { 13774f838ab2SRanjani Sridharan struct snd_soc_component *scomp = swidget->scomp; 13784f838ab2SRanjani Sridharan struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 13794f838ab2SRanjani Sridharan struct sof_ipc4_gain *gain = swidget->private; 13804f838ab2SRanjani Sridharan int ret; 13814f838ab2SRanjani Sridharan 13824f838ab2SRanjani Sridharan gain->available_fmt.ref_audio_fmt = &gain->available_fmt.base_config->audio_fmt; 13834f838ab2SRanjani Sridharan 13844f838ab2SRanjani Sridharan /* output format is not required to be sent to the FW for gain */ 13854f838ab2SRanjani Sridharan ret = sof_ipc4_init_audio_fmt(sdev, swidget, &gain->base_config, 13864f838ab2SRanjani Sridharan NULL, pipeline_params, &gain->available_fmt, 13874f838ab2SRanjani Sridharan sizeof(gain->base_config)); 13884f838ab2SRanjani Sridharan if (ret < 0) 13894f838ab2SRanjani Sridharan return ret; 13904f838ab2SRanjani Sridharan 13914f838ab2SRanjani Sridharan /* update pipeline memory usage */ 13924f838ab2SRanjani Sridharan sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &gain->base_config); 13934f838ab2SRanjani Sridharan 1394711d0427SBard Liao return 0; 13954f838ab2SRanjani Sridharan } 13964f838ab2SRanjani Sridharan 13974d4ba014SRanjani Sridharan static int sof_ipc4_prepare_mixer_module(struct snd_sof_widget *swidget, 13984d4ba014SRanjani Sridharan struct snd_pcm_hw_params *fe_params, 13994d4ba014SRanjani Sridharan struct snd_sof_platform_stream_params *platform_params, 14004d4ba014SRanjani Sridharan struct snd_pcm_hw_params *pipeline_params, int dir) 14014d4ba014SRanjani Sridharan { 14024d4ba014SRanjani Sridharan struct snd_soc_component *scomp = swidget->scomp; 14034d4ba014SRanjani Sridharan struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 14044d4ba014SRanjani Sridharan struct sof_ipc4_mixer *mixer = swidget->private; 14054d4ba014SRanjani Sridharan int ret; 14064d4ba014SRanjani Sridharan 14074d4ba014SRanjani Sridharan /* only 32bit is supported by mixer */ 14084d4ba014SRanjani Sridharan mixer->available_fmt.ref_audio_fmt = &mixer->available_fmt.base_config->audio_fmt; 14094d4ba014SRanjani Sridharan 14104d4ba014SRanjani Sridharan /* output format is not required to be sent to the FW for mixer */ 14114d4ba014SRanjani Sridharan ret = sof_ipc4_init_audio_fmt(sdev, swidget, &mixer->base_config, 14124d4ba014SRanjani Sridharan NULL, pipeline_params, &mixer->available_fmt, 14134d4ba014SRanjani Sridharan sizeof(mixer->base_config)); 14144d4ba014SRanjani Sridharan if (ret < 0) 14154d4ba014SRanjani Sridharan return ret; 14164d4ba014SRanjani Sridharan 14174d4ba014SRanjani Sridharan /* update pipeline memory usage */ 14184d4ba014SRanjani Sridharan sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &mixer->base_config); 14194d4ba014SRanjani Sridharan 1420711d0427SBard Liao return 0; 14214d4ba014SRanjani Sridharan } 14224d4ba014SRanjani Sridharan 1423b85f4fc4SRander Wang static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget, 1424b85f4fc4SRander Wang struct snd_pcm_hw_params *fe_params, 1425b85f4fc4SRander Wang struct snd_sof_platform_stream_params *platform_params, 1426b85f4fc4SRander Wang struct snd_pcm_hw_params *pipeline_params, int dir) 1427b85f4fc4SRander Wang { 1428b85f4fc4SRander Wang struct snd_soc_component *scomp = swidget->scomp; 1429b85f4fc4SRander Wang struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 1430b85f4fc4SRander Wang struct sof_ipc4_src *src = swidget->private; 1431b85f4fc4SRander Wang struct snd_interval *rate; 1432b85f4fc4SRander Wang int ret; 1433b85f4fc4SRander Wang 1434b85f4fc4SRander Wang src->available_fmt.ref_audio_fmt = &src->available_fmt.base_config->audio_fmt; 1435b85f4fc4SRander Wang 1436b85f4fc4SRander Wang /* output format is not required to be sent to the FW for SRC */ 1437b85f4fc4SRander Wang ret = sof_ipc4_init_audio_fmt(sdev, swidget, &src->base_config, 1438b85f4fc4SRander Wang NULL, pipeline_params, &src->available_fmt, 1439b85f4fc4SRander Wang sizeof(src->base_config)); 1440b85f4fc4SRander Wang if (ret < 0) 1441b85f4fc4SRander Wang return ret; 1442b85f4fc4SRander Wang 1443b85f4fc4SRander Wang /* update pipeline memory usage */ 1444b85f4fc4SRander Wang sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &src->base_config); 1445b85f4fc4SRander Wang 1446b85f4fc4SRander Wang /* update pipeline_params for sink widgets */ 1447b85f4fc4SRander Wang rate = hw_param_interval(pipeline_params, SNDRV_PCM_HW_PARAM_RATE); 1448b85f4fc4SRander Wang rate->min = src->sink_rate; 1449b85f4fc4SRander Wang rate->max = rate->min; 1450b85f4fc4SRander Wang 1451b85f4fc4SRander Wang return 0; 1452b85f4fc4SRander Wang } 1453b85f4fc4SRander Wang 1454d97964f8SRanjani Sridharan static int sof_ipc4_control_load_volume(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol) 1455d97964f8SRanjani Sridharan { 1456d97964f8SRanjani Sridharan struct sof_ipc4_control_data *control_data; 1457d97964f8SRanjani Sridharan struct sof_ipc4_msg *msg; 1458d97964f8SRanjani Sridharan int i; 1459d97964f8SRanjani Sridharan 1460d97964f8SRanjani Sridharan scontrol->size = struct_size(control_data, chanv, scontrol->num_channels); 1461d97964f8SRanjani Sridharan 1462d97964f8SRanjani Sridharan /* scontrol->ipc_control_data will be freed in sof_control_unload */ 1463d97964f8SRanjani Sridharan scontrol->ipc_control_data = kzalloc(scontrol->size, GFP_KERNEL); 1464d97964f8SRanjani Sridharan if (!scontrol->ipc_control_data) 1465d97964f8SRanjani Sridharan return -ENOMEM; 1466d97964f8SRanjani Sridharan 1467d97964f8SRanjani Sridharan control_data = scontrol->ipc_control_data; 1468d97964f8SRanjani Sridharan control_data->index = scontrol->index; 1469d97964f8SRanjani Sridharan 1470d97964f8SRanjani Sridharan msg = &control_data->msg; 1471d97964f8SRanjani Sridharan msg->primary = SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_LARGE_CONFIG_SET); 1472d97964f8SRanjani Sridharan msg->primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); 1473d97964f8SRanjani Sridharan msg->primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG); 1474d97964f8SRanjani Sridharan 1475d97964f8SRanjani Sridharan msg->extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_GAIN_PARAM_ID); 1476d97964f8SRanjani Sridharan 1477d97964f8SRanjani Sridharan /* set default volume values to 0dB in control */ 1478d97964f8SRanjani Sridharan for (i = 0; i < scontrol->num_channels; i++) { 1479d97964f8SRanjani Sridharan control_data->chanv[i].channel = i; 1480d97964f8SRanjani Sridharan control_data->chanv[i].value = SOF_IPC4_VOL_ZERO_DB; 1481d97964f8SRanjani Sridharan } 1482d97964f8SRanjani Sridharan 1483d97964f8SRanjani Sridharan return 0; 1484d97964f8SRanjani Sridharan } 1485d97964f8SRanjani Sridharan 1486d97964f8SRanjani Sridharan static int sof_ipc4_control_setup(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol) 1487d97964f8SRanjani Sridharan { 1488d97964f8SRanjani Sridharan switch (scontrol->info_type) { 1489d97964f8SRanjani Sridharan case SND_SOC_TPLG_CTL_VOLSW: 1490d97964f8SRanjani Sridharan case SND_SOC_TPLG_CTL_VOLSW_SX: 1491d97964f8SRanjani Sridharan case SND_SOC_TPLG_CTL_VOLSW_XR_SX: 1492d97964f8SRanjani Sridharan return sof_ipc4_control_load_volume(sdev, scontrol); 1493d97964f8SRanjani Sridharan default: 1494d97964f8SRanjani Sridharan break; 1495d97964f8SRanjani Sridharan } 1496d97964f8SRanjani Sridharan 1497d97964f8SRanjani Sridharan return 0; 1498d97964f8SRanjani Sridharan } 1499d97964f8SRanjani Sridharan 15006e9257a1SRanjani Sridharan static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) 15016e9257a1SRanjani Sridharan { 15029c04363dSRanjani Sridharan struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget; 1503a2ba1f70SBard Liao struct sof_ipc4_fw_data *ipc4_data = sdev->private; 15046e9257a1SRanjani Sridharan struct sof_ipc4_pipeline *pipeline; 15056e9257a1SRanjani Sridharan struct sof_ipc4_msg *msg; 15066e9257a1SRanjani Sridharan void *ipc_data = NULL; 15076e9257a1SRanjani Sridharan u32 ipc_size = 0; 15086e9257a1SRanjani Sridharan int ret; 15096e9257a1SRanjani Sridharan 15106e9257a1SRanjani Sridharan switch (swidget->id) { 15116e9257a1SRanjani Sridharan case snd_soc_dapm_scheduler: 15126e9257a1SRanjani Sridharan pipeline = swidget->private; 15136e9257a1SRanjani Sridharan 15146e9257a1SRanjani Sridharan dev_dbg(sdev->dev, "pipeline: %d memory pages: %d\n", swidget->pipeline_id, 15156e9257a1SRanjani Sridharan pipeline->mem_usage); 15166e9257a1SRanjani Sridharan 15176e9257a1SRanjani Sridharan msg = &pipeline->msg; 15186e9257a1SRanjani Sridharan msg->primary |= pipeline->mem_usage; 1519a2ba1f70SBard Liao 1520a2ba1f70SBard Liao swidget->instance_id = ida_alloc_max(&pipeline_ida, ipc4_data->max_num_pipelines, 1521a2ba1f70SBard Liao GFP_KERNEL); 1522a2ba1f70SBard Liao if (swidget->instance_id < 0) { 1523a2ba1f70SBard Liao dev_err(sdev->dev, "failed to assign pipeline id for %s: %d\n", 1524a2ba1f70SBard Liao swidget->widget->name, swidget->instance_id); 1525a2ba1f70SBard Liao return swidget->instance_id; 1526a2ba1f70SBard Liao } 1527a2ba1f70SBard Liao msg->primary &= ~SOF_IPC4_GLB_PIPE_INSTANCE_MASK; 1528a2ba1f70SBard Liao msg->primary |= SOF_IPC4_GLB_PIPE_INSTANCE_ID(swidget->instance_id); 15296e9257a1SRanjani Sridharan break; 15306e9257a1SRanjani Sridharan case snd_soc_dapm_aif_in: 15316e9257a1SRanjani Sridharan case snd_soc_dapm_aif_out: 15327d573425SBard Liao case snd_soc_dapm_buffer: 15336e9257a1SRanjani Sridharan { 15346e9257a1SRanjani Sridharan struct sof_ipc4_copier *ipc4_copier = swidget->private; 15356e9257a1SRanjani Sridharan 15366e9257a1SRanjani Sridharan ipc_size = ipc4_copier->ipc_config_size; 15376e9257a1SRanjani Sridharan ipc_data = ipc4_copier->ipc_config_data; 15386e9257a1SRanjani Sridharan 15396e9257a1SRanjani Sridharan msg = &ipc4_copier->msg; 15406e9257a1SRanjani Sridharan break; 15416e9257a1SRanjani Sridharan } 15426e9257a1SRanjani Sridharan case snd_soc_dapm_dai_in: 15436e9257a1SRanjani Sridharan case snd_soc_dapm_dai_out: 15446e9257a1SRanjani Sridharan { 15456e9257a1SRanjani Sridharan struct snd_sof_dai *dai = swidget->private; 15466e9257a1SRanjani Sridharan struct sof_ipc4_copier *ipc4_copier = dai->private; 15476e9257a1SRanjani Sridharan 15486e9257a1SRanjani Sridharan ipc_size = ipc4_copier->ipc_config_size; 15496e9257a1SRanjani Sridharan ipc_data = ipc4_copier->ipc_config_data; 15506e9257a1SRanjani Sridharan 15516e9257a1SRanjani Sridharan msg = &ipc4_copier->msg; 15526e9257a1SRanjani Sridharan break; 15536e9257a1SRanjani Sridharan } 15546e9257a1SRanjani Sridharan case snd_soc_dapm_pga: 15556e9257a1SRanjani Sridharan { 15566e9257a1SRanjani Sridharan struct sof_ipc4_gain *gain = swidget->private; 15576e9257a1SRanjani Sridharan 15586e9257a1SRanjani Sridharan ipc_size = sizeof(struct sof_ipc4_base_module_cfg) + 15596e9257a1SRanjani Sridharan sizeof(struct sof_ipc4_gain_data); 15606e9257a1SRanjani Sridharan ipc_data = gain; 15616e9257a1SRanjani Sridharan 15626e9257a1SRanjani Sridharan msg = &gain->msg; 15636e9257a1SRanjani Sridharan break; 15646e9257a1SRanjani Sridharan } 15656e9257a1SRanjani Sridharan case snd_soc_dapm_mixer: 15666e9257a1SRanjani Sridharan { 15676e9257a1SRanjani Sridharan struct sof_ipc4_mixer *mixer = swidget->private; 15686e9257a1SRanjani Sridharan 15696e9257a1SRanjani Sridharan ipc_size = sizeof(mixer->base_config); 15706e9257a1SRanjani Sridharan ipc_data = &mixer->base_config; 15716e9257a1SRanjani Sridharan 15726e9257a1SRanjani Sridharan msg = &mixer->msg; 15736e9257a1SRanjani Sridharan break; 15746e9257a1SRanjani Sridharan } 1575b85f4fc4SRander Wang case snd_soc_dapm_src: 1576b85f4fc4SRander Wang { 1577b85f4fc4SRander Wang struct sof_ipc4_src *src = swidget->private; 1578b85f4fc4SRander Wang 1579b85f4fc4SRander Wang ipc_size = sizeof(struct sof_ipc4_base_module_cfg) + sizeof(src->sink_rate); 1580b85f4fc4SRander Wang ipc_data = src; 1581b85f4fc4SRander Wang 1582b85f4fc4SRander Wang msg = &src->msg; 1583b85f4fc4SRander Wang break; 1584b85f4fc4SRander Wang } 15856e9257a1SRanjani Sridharan default: 15866e9257a1SRanjani Sridharan dev_err(sdev->dev, "widget type %d not supported", swidget->id); 15876e9257a1SRanjani Sridharan return -EINVAL; 15886e9257a1SRanjani Sridharan } 15896e9257a1SRanjani Sridharan 15906e9257a1SRanjani Sridharan if (swidget->id != snd_soc_dapm_scheduler) { 1591711d0427SBard Liao ret = sof_ipc4_widget_assign_instance_id(sdev, swidget); 1592711d0427SBard Liao if (ret < 0) { 1593711d0427SBard Liao dev_err(sdev->dev, "failed to assign instance id for %s\n", 1594711d0427SBard Liao swidget->widget->name); 1595711d0427SBard Liao return ret; 1596711d0427SBard Liao } 15977738211bSPierre-Louis Bossart 15986e9257a1SRanjani Sridharan msg->primary &= ~SOF_IPC4_MOD_INSTANCE_MASK; 15996e9257a1SRanjani Sridharan msg->primary |= SOF_IPC4_MOD_INSTANCE(swidget->instance_id); 16006e9257a1SRanjani Sridharan 16016e9257a1SRanjani Sridharan msg->extension &= ~SOF_IPC4_MOD_EXT_PARAM_SIZE_MASK; 16026e9257a1SRanjani Sridharan msg->extension |= ipc_size >> 2; 1603a2ba1f70SBard Liao 1604a2ba1f70SBard Liao msg->extension &= ~SOF_IPC4_MOD_EXT_PPL_ID_MASK; 1605a2ba1f70SBard Liao msg->extension |= SOF_IPC4_MOD_EXT_PPL_ID(pipe_widget->instance_id); 16066e9257a1SRanjani Sridharan } 1607711d0427SBard Liao dev_dbg(sdev->dev, "Create widget %s instance %d - pipe %d - core %d\n", 1608711d0427SBard Liao swidget->widget->name, swidget->instance_id, swidget->pipeline_id, swidget->core); 16096e9257a1SRanjani Sridharan 16106e9257a1SRanjani Sridharan msg->data_size = ipc_size; 16116e9257a1SRanjani Sridharan msg->data_ptr = ipc_data; 16126e9257a1SRanjani Sridharan 16136e9257a1SRanjani Sridharan ret = sof_ipc_tx_message(sdev->ipc, msg, ipc_size, NULL, 0); 161461eb0addSPeter Ujfalusi if (ret < 0) { 16156e9257a1SRanjani Sridharan dev_err(sdev->dev, "failed to create module %s\n", swidget->widget->name); 16166e9257a1SRanjani Sridharan 161761eb0addSPeter Ujfalusi if (swidget->id != snd_soc_dapm_scheduler) { 161861eb0addSPeter Ujfalusi struct sof_ipc4_fw_module *fw_module = swidget->module_info; 161961eb0addSPeter Ujfalusi 162061eb0addSPeter Ujfalusi ida_free(&fw_module->m_ida, swidget->instance_id); 1621a2ba1f70SBard Liao } else { 1622a2ba1f70SBard Liao ida_free(&pipeline_ida, swidget->instance_id); 162361eb0addSPeter Ujfalusi } 162461eb0addSPeter Ujfalusi } 162561eb0addSPeter Ujfalusi 16266e9257a1SRanjani Sridharan return ret; 16276e9257a1SRanjani Sridharan } 16286e9257a1SRanjani Sridharan 16296e9257a1SRanjani Sridharan static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) 16306e9257a1SRanjani Sridharan { 1631711d0427SBard Liao struct sof_ipc4_fw_module *fw_module = swidget->module_info; 16326bc4d1b7SRanjani Sridharan struct sof_ipc4_fw_data *ipc4_data = sdev->private; 16336e9257a1SRanjani Sridharan int ret = 0; 16346e9257a1SRanjani Sridharan 16356bc4d1b7SRanjani Sridharan mutex_lock(&ipc4_data->pipeline_state_mutex); 16366bc4d1b7SRanjani Sridharan 16376e9257a1SRanjani Sridharan /* freeing a pipeline frees all the widgets associated with it */ 16386e9257a1SRanjani Sridharan if (swidget->id == snd_soc_dapm_scheduler) { 16396e9257a1SRanjani Sridharan struct sof_ipc4_pipeline *pipeline = swidget->private; 16406e9257a1SRanjani Sridharan struct sof_ipc4_msg msg = {{ 0 }}; 16416e9257a1SRanjani Sridharan u32 header; 16426e9257a1SRanjani Sridharan 1643a2ba1f70SBard Liao header = SOF_IPC4_GLB_PIPE_INSTANCE_ID(swidget->instance_id); 16446e9257a1SRanjani Sridharan header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_DELETE_PIPELINE); 16456e9257a1SRanjani Sridharan header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); 16466e9257a1SRanjani Sridharan header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG); 16476e9257a1SRanjani Sridharan 16486e9257a1SRanjani Sridharan msg.primary = header; 16496e9257a1SRanjani Sridharan 16506e9257a1SRanjani Sridharan ret = sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0); 16516e9257a1SRanjani Sridharan if (ret < 0) 16526e9257a1SRanjani Sridharan dev_err(sdev->dev, "failed to free pipeline widget %s\n", 16536e9257a1SRanjani Sridharan swidget->widget->name); 16546e9257a1SRanjani Sridharan 16556e9257a1SRanjani Sridharan pipeline->mem_usage = 0; 16566e9257a1SRanjani Sridharan pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED; 1657a2ba1f70SBard Liao ida_free(&pipeline_ida, swidget->instance_id); 1658711d0427SBard Liao } else { 1659711d0427SBard Liao ida_free(&fw_module->m_ida, swidget->instance_id); 16606e9257a1SRanjani Sridharan } 16616e9257a1SRanjani Sridharan 16626bc4d1b7SRanjani Sridharan mutex_unlock(&ipc4_data->pipeline_state_mutex); 16636bc4d1b7SRanjani Sridharan 16646e9257a1SRanjani Sridharan return ret; 16656e9257a1SRanjani Sridharan } 16666e9257a1SRanjani Sridharan 1667c84443dbSChao Song static int sof_ipc4_get_queue_id(struct snd_sof_widget *src_widget, 1668c84443dbSChao Song struct snd_sof_widget *sink_widget, bool pin_type) 1669c84443dbSChao Song { 1670c84443dbSChao Song struct snd_sof_widget *current_swidget; 1671c84443dbSChao Song struct snd_soc_component *scomp; 1672c84443dbSChao Song struct ida *queue_ida; 1673c84443dbSChao Song const char *buddy_name; 1674c84443dbSChao Song char **pin_binding; 1675c84443dbSChao Song u32 num_pins; 1676c84443dbSChao Song int i; 1677c84443dbSChao Song 1678c84443dbSChao Song if (pin_type == SOF_PIN_TYPE_SOURCE) { 1679c84443dbSChao Song current_swidget = src_widget; 1680c84443dbSChao Song pin_binding = src_widget->src_pin_binding; 1681c84443dbSChao Song queue_ida = &src_widget->src_queue_ida; 1682c84443dbSChao Song num_pins = src_widget->num_source_pins; 1683c84443dbSChao Song buddy_name = sink_widget->widget->name; 1684c84443dbSChao Song } else { 1685c84443dbSChao Song current_swidget = sink_widget; 1686c84443dbSChao Song pin_binding = sink_widget->sink_pin_binding; 1687c84443dbSChao Song queue_ida = &sink_widget->sink_queue_ida; 1688c84443dbSChao Song num_pins = sink_widget->num_sink_pins; 1689c84443dbSChao Song buddy_name = src_widget->widget->name; 1690c84443dbSChao Song } 1691c84443dbSChao Song 1692c84443dbSChao Song scomp = current_swidget->scomp; 1693c84443dbSChao Song 1694c84443dbSChao Song if (num_pins < 1) { 1695c84443dbSChao Song dev_err(scomp->dev, "invalid %s num_pins: %d for queue allocation for %s\n", 1696c84443dbSChao Song (pin_type == SOF_PIN_TYPE_SOURCE ? "source" : "sink"), 1697c84443dbSChao Song num_pins, current_swidget->widget->name); 1698c84443dbSChao Song return -EINVAL; 1699c84443dbSChao Song } 1700c84443dbSChao Song 1701c84443dbSChao Song /* If there is only one sink/source pin, queue id must be 0 */ 1702c84443dbSChao Song if (num_pins == 1) 1703c84443dbSChao Song return 0; 1704c84443dbSChao Song 1705c84443dbSChao Song /* Allocate queue ID from pin binding array if it is defined in topology. */ 1706c84443dbSChao Song if (pin_binding) { 1707c84443dbSChao Song for (i = 0; i < num_pins; i++) { 1708c84443dbSChao Song if (!strcmp(pin_binding[i], buddy_name)) 1709c84443dbSChao Song return i; 1710c84443dbSChao Song } 1711c84443dbSChao Song /* 1712c84443dbSChao Song * Fail if no queue ID found from pin binding array, so that we don't 1713c84443dbSChao Song * mixed use pin binding array and ida for queue ID allocation. 1714c84443dbSChao Song */ 1715c84443dbSChao Song dev_err(scomp->dev, "no %s queue id found from pin binding array for %s\n", 1716c84443dbSChao Song (pin_type == SOF_PIN_TYPE_SOURCE ? "source" : "sink"), 1717c84443dbSChao Song current_swidget->widget->name); 1718c84443dbSChao Song return -EINVAL; 1719c84443dbSChao Song } 1720c84443dbSChao Song 1721c84443dbSChao Song /* If no pin binding array specified in topology, use ida to allocate one */ 1722c84443dbSChao Song return ida_alloc_max(queue_ida, num_pins, GFP_KERNEL); 1723c84443dbSChao Song } 1724c84443dbSChao Song 1725c84443dbSChao Song static void sof_ipc4_put_queue_id(struct snd_sof_widget *swidget, int queue_id, 1726c84443dbSChao Song bool pin_type) 1727c84443dbSChao Song { 1728c84443dbSChao Song struct ida *queue_ida; 1729c84443dbSChao Song char **pin_binding; 1730c84443dbSChao Song int num_pins; 1731c84443dbSChao Song 1732c84443dbSChao Song if (pin_type == SOF_PIN_TYPE_SOURCE) { 1733c84443dbSChao Song pin_binding = swidget->src_pin_binding; 1734c84443dbSChao Song queue_ida = &swidget->src_queue_ida; 1735c84443dbSChao Song num_pins = swidget->num_source_pins; 1736c84443dbSChao Song } else { 1737c84443dbSChao Song pin_binding = swidget->sink_pin_binding; 1738c84443dbSChao Song queue_ida = &swidget->sink_queue_ida; 1739c84443dbSChao Song num_pins = swidget->num_sink_pins; 1740c84443dbSChao Song } 1741c84443dbSChao Song 1742c84443dbSChao Song /* Nothing to free if queue ID is not allocated with ida. */ 1743c84443dbSChao Song if (num_pins == 1 || pin_binding) 1744c84443dbSChao Song return; 1745c84443dbSChao Song 1746c84443dbSChao Song ida_free(queue_ida, queue_id); 1747c84443dbSChao Song } 1748c84443dbSChao Song 174911f60563SBard Liao static int sof_ipc4_set_copier_sink_format(struct snd_sof_dev *sdev, 175011f60563SBard Liao struct snd_sof_widget *src_widget, 175111f60563SBard Liao struct snd_sof_widget *sink_widget, 175211f60563SBard Liao int sink_id) 175311f60563SBard Liao { 175411f60563SBard Liao struct sof_ipc4_base_module_cfg *sink_config = sink_widget->private; 175511f60563SBard Liao struct sof_ipc4_base_module_cfg *src_config; 175611f60563SBard Liao struct sof_ipc4_copier_config_set_sink_format format; 175711f60563SBard Liao struct sof_ipc4_fw_module *fw_module; 175811f60563SBard Liao struct sof_ipc4_msg msg = {{ 0 }}; 175911f60563SBard Liao u32 header, extension; 176011f60563SBard Liao 176111f60563SBard Liao dev_dbg(sdev->dev, "%s set copier sink %d format\n", 176211f60563SBard Liao src_widget->widget->name, sink_id); 176311f60563SBard Liao 176411f60563SBard Liao if (WIDGET_IS_DAI(src_widget->id)) { 176511f60563SBard Liao struct snd_sof_dai *dai = src_widget->private; 176611f60563SBard Liao 176711f60563SBard Liao src_config = dai->private; 176811f60563SBard Liao } else { 176911f60563SBard Liao src_config = src_widget->private; 177011f60563SBard Liao } 177111f60563SBard Liao 177211f60563SBard Liao fw_module = src_widget->module_info; 177311f60563SBard Liao 177411f60563SBard Liao format.sink_id = sink_id; 177511f60563SBard Liao memcpy(&format.source_fmt, &src_config->audio_fmt, sizeof(format.source_fmt)); 177611f60563SBard Liao memcpy(&format.sink_fmt, &sink_config->audio_fmt, sizeof(format.sink_fmt)); 177711f60563SBard Liao msg.data_size = sizeof(format); 177811f60563SBard Liao msg.data_ptr = &format; 177911f60563SBard Liao 178011f60563SBard Liao header = fw_module->man4_module_entry.id; 178111f60563SBard Liao header |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id); 178211f60563SBard Liao header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_LARGE_CONFIG_SET); 178311f60563SBard Liao header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); 178411f60563SBard Liao header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG); 178511f60563SBard Liao 178611f60563SBard Liao extension = SOF_IPC4_MOD_EXT_MSG_SIZE(msg.data_size); 178711f60563SBard Liao extension |= 178811f60563SBard Liao SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_COPIER_MODULE_CFG_PARAM_SET_SINK_FORMAT); 178911f60563SBard Liao extension |= SOF_IPC4_MOD_EXT_MSG_LAST_BLOCK(1); 179011f60563SBard Liao extension |= SOF_IPC4_MOD_EXT_MSG_FIRST_BLOCK(1); 179111f60563SBard Liao 179211f60563SBard Liao msg.primary = header; 179311f60563SBard Liao msg.extension = extension; 179411f60563SBard Liao 179511f60563SBard Liao return sof_ipc_tx_message(sdev->ipc, &msg, msg.data_size, NULL, 0); 179611f60563SBard Liao } 179711f60563SBard Liao 17983acd5270SRanjani Sridharan static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route *sroute) 17993acd5270SRanjani Sridharan { 18003acd5270SRanjani Sridharan struct snd_sof_widget *src_widget = sroute->src_widget; 18013acd5270SRanjani Sridharan struct snd_sof_widget *sink_widget = sroute->sink_widget; 18023acd5270SRanjani Sridharan struct sof_ipc4_fw_module *src_fw_module = src_widget->module_info; 18033acd5270SRanjani Sridharan struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info; 18043acd5270SRanjani Sridharan struct sof_ipc4_msg msg = {{ 0 }}; 18053acd5270SRanjani Sridharan u32 header, extension; 18063acd5270SRanjani Sridharan int ret; 18073acd5270SRanjani Sridharan 1808e3720f92SGuennadi Liakhovetski if (!src_fw_module || !sink_fw_module) { 1809*de6aa72bSPeter Ujfalusi dev_err(sdev->dev, 1810*de6aa72bSPeter Ujfalusi "cannot bind %s -> %s, no firmware module for: %s%s\n", 1811*de6aa72bSPeter Ujfalusi src_widget->widget->name, sink_widget->widget->name, 1812*de6aa72bSPeter Ujfalusi src_fw_module ? "" : " source", 1813*de6aa72bSPeter Ujfalusi sink_fw_module ? "" : " sink"); 1814*de6aa72bSPeter Ujfalusi 1815e3720f92SGuennadi Liakhovetski return -ENODEV; 1816e3720f92SGuennadi Liakhovetski } 1817e3720f92SGuennadi Liakhovetski 1818c84443dbSChao Song sroute->src_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget, 1819c84443dbSChao Song SOF_PIN_TYPE_SOURCE); 1820c84443dbSChao Song if (sroute->src_queue_id < 0) { 1821c84443dbSChao Song dev_err(sdev->dev, "failed to get queue ID for source widget: %s\n", 1822c84443dbSChao Song src_widget->widget->name); 1823c84443dbSChao Song return sroute->src_queue_id; 1824c84443dbSChao Song } 1825c84443dbSChao Song 1826c84443dbSChao Song sroute->dst_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget, 1827c84443dbSChao Song SOF_PIN_TYPE_SINK); 1828c84443dbSChao Song if (sroute->dst_queue_id < 0) { 1829c84443dbSChao Song dev_err(sdev->dev, "failed to get queue ID for sink widget: %s\n", 1830c84443dbSChao Song sink_widget->widget->name); 1831c84443dbSChao Song sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id, 1832c84443dbSChao Song SOF_PIN_TYPE_SOURCE); 1833c84443dbSChao Song return sroute->dst_queue_id; 1834c84443dbSChao Song } 1835c84443dbSChao Song 183611f60563SBard Liao /* Pin 0 format is already set during copier module init */ 183711f60563SBard Liao if (sroute->src_queue_id > 0 && WIDGET_IS_COPIER(src_widget->id)) { 183811f60563SBard Liao ret = sof_ipc4_set_copier_sink_format(sdev, src_widget, sink_widget, 183911f60563SBard Liao sroute->src_queue_id); 184011f60563SBard Liao if (ret < 0) { 184111f60563SBard Liao dev_err(sdev->dev, "failed to set sink format for %s source queue ID %d\n", 184211f60563SBard Liao src_widget->widget->name, sroute->src_queue_id); 184311f60563SBard Liao goto out; 184411f60563SBard Liao } 184511f60563SBard Liao } 184611f60563SBard Liao 1847c84443dbSChao Song dev_dbg(sdev->dev, "bind %s:%d -> %s:%d\n", 1848c84443dbSChao Song src_widget->widget->name, sroute->src_queue_id, 1849c84443dbSChao Song sink_widget->widget->name, sroute->dst_queue_id); 18503acd5270SRanjani Sridharan 18513acd5270SRanjani Sridharan header = src_fw_module->man4_module_entry.id; 18523acd5270SRanjani Sridharan header |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id); 18533acd5270SRanjani Sridharan header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_BIND); 18543acd5270SRanjani Sridharan header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); 18553acd5270SRanjani Sridharan header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG); 18563acd5270SRanjani Sridharan 18573acd5270SRanjani Sridharan extension = sink_fw_module->man4_module_entry.id; 18583acd5270SRanjani Sridharan extension |= SOF_IPC4_MOD_EXT_DST_MOD_INSTANCE(sink_widget->instance_id); 1859c84443dbSChao Song extension |= SOF_IPC4_MOD_EXT_DST_MOD_QUEUE_ID(sroute->dst_queue_id); 1860c84443dbSChao Song extension |= SOF_IPC4_MOD_EXT_SRC_MOD_QUEUE_ID(sroute->src_queue_id); 18613acd5270SRanjani Sridharan 18623acd5270SRanjani Sridharan msg.primary = header; 18633acd5270SRanjani Sridharan msg.extension = extension; 18643acd5270SRanjani Sridharan 18653acd5270SRanjani Sridharan ret = sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0); 1866c84443dbSChao Song if (ret < 0) { 1867b796ff3bSRanjani Sridharan dev_err(sdev->dev, "failed to bind modules %s:%d -> %s:%d\n", 1868b796ff3bSRanjani Sridharan src_widget->widget->name, sroute->src_queue_id, 1869b796ff3bSRanjani Sridharan sink_widget->widget->name, sroute->dst_queue_id); 187011f60563SBard Liao goto out; 1871c84443dbSChao Song } 1872c84443dbSChao Song 18733acd5270SRanjani Sridharan return ret; 187411f60563SBard Liao 187511f60563SBard Liao out: 187611f60563SBard Liao sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id, SOF_PIN_TYPE_SOURCE); 187711f60563SBard Liao sof_ipc4_put_queue_id(sink_widget, sroute->dst_queue_id, SOF_PIN_TYPE_SINK); 187811f60563SBard Liao return ret; 18793acd5270SRanjani Sridharan } 18803acd5270SRanjani Sridharan 18813acd5270SRanjani Sridharan static int sof_ipc4_route_free(struct snd_sof_dev *sdev, struct snd_sof_route *sroute) 18823acd5270SRanjani Sridharan { 18833acd5270SRanjani Sridharan struct snd_sof_widget *src_widget = sroute->src_widget; 18843acd5270SRanjani Sridharan struct snd_sof_widget *sink_widget = sroute->sink_widget; 18853acd5270SRanjani Sridharan struct sof_ipc4_fw_module *src_fw_module = src_widget->module_info; 18863acd5270SRanjani Sridharan struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info; 18873acd5270SRanjani Sridharan struct sof_ipc4_msg msg = {{ 0 }}; 18883acd5270SRanjani Sridharan u32 header, extension; 18899a62d87aSRanjani Sridharan int ret = 0; 18903acd5270SRanjani Sridharan 1891c84443dbSChao Song dev_dbg(sdev->dev, "unbind modules %s:%d -> %s:%d\n", 1892c84443dbSChao Song src_widget->widget->name, sroute->src_queue_id, 1893c84443dbSChao Song sink_widget->widget->name, sroute->dst_queue_id); 18943acd5270SRanjani Sridharan 18959a62d87aSRanjani Sridharan /* 18969a62d87aSRanjani Sridharan * routes belonging to the same pipeline will be disconnected by the FW when the pipeline 18979a62d87aSRanjani Sridharan * is freed. So avoid sending this IPC which will be ignored by the FW anyway. 18989a62d87aSRanjani Sridharan */ 18999c04363dSRanjani Sridharan if (src_widget->spipe->pipe_widget == sink_widget->spipe->pipe_widget) 19009a62d87aSRanjani Sridharan goto out; 19019a62d87aSRanjani Sridharan 19023acd5270SRanjani Sridharan header = src_fw_module->man4_module_entry.id; 19033acd5270SRanjani Sridharan header |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id); 19043acd5270SRanjani Sridharan header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_UNBIND); 19053acd5270SRanjani Sridharan header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); 19063acd5270SRanjani Sridharan header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG); 19073acd5270SRanjani Sridharan 19083acd5270SRanjani Sridharan extension = sink_fw_module->man4_module_entry.id; 19093acd5270SRanjani Sridharan extension |= SOF_IPC4_MOD_EXT_DST_MOD_INSTANCE(sink_widget->instance_id); 1910c84443dbSChao Song extension |= SOF_IPC4_MOD_EXT_DST_MOD_QUEUE_ID(sroute->dst_queue_id); 1911c84443dbSChao Song extension |= SOF_IPC4_MOD_EXT_SRC_MOD_QUEUE_ID(sroute->src_queue_id); 19123acd5270SRanjani Sridharan 19133acd5270SRanjani Sridharan msg.primary = header; 19143acd5270SRanjani Sridharan msg.extension = extension; 19153acd5270SRanjani Sridharan 19163acd5270SRanjani Sridharan ret = sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0); 19173acd5270SRanjani Sridharan if (ret < 0) 1918b796ff3bSRanjani Sridharan dev_err(sdev->dev, "failed to unbind modules %s:%d -> %s:%d\n", 1919b796ff3bSRanjani Sridharan src_widget->widget->name, sroute->src_queue_id, 1920b796ff3bSRanjani Sridharan sink_widget->widget->name, sroute->dst_queue_id); 19219a62d87aSRanjani Sridharan out: 1922c84443dbSChao Song sof_ipc4_put_queue_id(sink_widget, sroute->dst_queue_id, SOF_PIN_TYPE_SINK); 1923c84443dbSChao Song sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id, SOF_PIN_TYPE_SOURCE); 1924c84443dbSChao Song 19253acd5270SRanjani Sridharan return ret; 19263acd5270SRanjani Sridharan } 19273acd5270SRanjani Sridharan 1928acf48a1fSRanjani Sridharan static int sof_ipc4_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget, 1929acf48a1fSRanjani Sridharan unsigned int flags, struct snd_sof_dai_config_data *data) 1930acf48a1fSRanjani Sridharan { 19319c04363dSRanjani Sridharan struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget; 1932acf48a1fSRanjani Sridharan struct sof_ipc4_pipeline *pipeline = pipe_widget->private; 1933acf48a1fSRanjani Sridharan struct snd_sof_dai *dai = swidget->private; 1934acf48a1fSRanjani Sridharan struct sof_ipc4_gtw_attributes *gtw_attr; 1935acf48a1fSRanjani Sridharan struct sof_ipc4_copier_data *copier_data; 1936acf48a1fSRanjani Sridharan struct sof_ipc4_copier *ipc4_copier; 1937acf48a1fSRanjani Sridharan 1938acf48a1fSRanjani Sridharan if (!dai || !dai->private) { 1939acf48a1fSRanjani Sridharan dev_err(sdev->dev, "Invalid DAI or DAI private data for %s\n", 1940acf48a1fSRanjani Sridharan swidget->widget->name); 1941acf48a1fSRanjani Sridharan return -EINVAL; 1942acf48a1fSRanjani Sridharan } 1943acf48a1fSRanjani Sridharan 1944acf48a1fSRanjani Sridharan ipc4_copier = (struct sof_ipc4_copier *)dai->private; 1945acf48a1fSRanjani Sridharan copier_data = &ipc4_copier->data; 1946acf48a1fSRanjani Sridharan 1947acf48a1fSRanjani Sridharan if (!data) 1948acf48a1fSRanjani Sridharan return 0; 1949acf48a1fSRanjani Sridharan 1950acf48a1fSRanjani Sridharan switch (ipc4_copier->dai_type) { 1951acf48a1fSRanjani Sridharan case SOF_DAI_INTEL_HDA: 1952acf48a1fSRanjani Sridharan gtw_attr = ipc4_copier->gtw_attr; 1953acf48a1fSRanjani Sridharan gtw_attr->lp_buffer_alloc = pipeline->lp_mode; 195437a26eecSRanjani Sridharan pipeline->skip_during_fe_trigger = true; 1955acf48a1fSRanjani Sridharan fallthrough; 1956acf48a1fSRanjani Sridharan case SOF_DAI_INTEL_ALH: 1957b66bfc3aSRanjani Sridharan /* 1958b66bfc3aSRanjani Sridharan * Do not clear the node ID when this op is invoked with 1959b66bfc3aSRanjani Sridharan * SOF_DAI_CONFIG_FLAGS_HW_FREE. It is needed to free the group_ida during 1960b66bfc3aSRanjani Sridharan * unprepare. 1961b66bfc3aSRanjani Sridharan */ 1962b66bfc3aSRanjani Sridharan if (flags & SOF_DAI_CONFIG_FLAGS_HW_PARAMS) { 1963acf48a1fSRanjani Sridharan copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK; 1964acf48a1fSRanjani Sridharan copier_data->gtw_cfg.node_id |= SOF_IPC4_NODE_INDEX(data->dai_data); 1965b66bfc3aSRanjani Sridharan } 1966acf48a1fSRanjani Sridharan break; 1967acf48a1fSRanjani Sridharan case SOF_DAI_INTEL_DMIC: 1968acf48a1fSRanjani Sridharan case SOF_DAI_INTEL_SSP: 1969acf48a1fSRanjani Sridharan /* nothing to do for SSP/DMIC */ 1970acf48a1fSRanjani Sridharan break; 1971acf48a1fSRanjani Sridharan default: 1972acf48a1fSRanjani Sridharan dev_err(sdev->dev, "%s: unsupported dai type %d\n", __func__, 1973acf48a1fSRanjani Sridharan ipc4_copier->dai_type); 1974acf48a1fSRanjani Sridharan return -EINVAL; 1975acf48a1fSRanjani Sridharan } 1976acf48a1fSRanjani Sridharan 1977acf48a1fSRanjani Sridharan return 0; 1978acf48a1fSRanjani Sridharan } 1979acf48a1fSRanjani Sridharan 1980323aa1f0SRanjani Sridharan static int sof_ipc4_parse_manifest(struct snd_soc_component *scomp, int index, 1981323aa1f0SRanjani Sridharan struct snd_soc_tplg_manifest *man) 1982323aa1f0SRanjani Sridharan { 1983323aa1f0SRanjani Sridharan struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 1984323aa1f0SRanjani Sridharan struct sof_ipc4_fw_data *ipc4_data = sdev->private; 1985323aa1f0SRanjani Sridharan struct sof_manifest_tlv *manifest_tlv; 1986323aa1f0SRanjani Sridharan struct sof_manifest *manifest; 1987323aa1f0SRanjani Sridharan u32 size = le32_to_cpu(man->priv.size); 1988323aa1f0SRanjani Sridharan u8 *man_ptr = man->priv.data; 1989323aa1f0SRanjani Sridharan u32 len_check; 1990323aa1f0SRanjani Sridharan int i; 1991323aa1f0SRanjani Sridharan 1992323aa1f0SRanjani Sridharan if (!size || size < SOF_IPC4_TPLG_ABI_SIZE) { 1993323aa1f0SRanjani Sridharan dev_err(scomp->dev, "%s: Invalid topology ABI size: %u\n", 1994323aa1f0SRanjani Sridharan __func__, size); 1995323aa1f0SRanjani Sridharan return -EINVAL; 1996323aa1f0SRanjani Sridharan } 1997323aa1f0SRanjani Sridharan 1998323aa1f0SRanjani Sridharan manifest = (struct sof_manifest *)man_ptr; 1999323aa1f0SRanjani Sridharan 2000323aa1f0SRanjani Sridharan dev_info(scomp->dev, 2001323aa1f0SRanjani Sridharan "Topology: ABI %d:%d:%d Kernel ABI %u:%u:%u\n", 2002323aa1f0SRanjani Sridharan le16_to_cpu(manifest->abi_major), le16_to_cpu(manifest->abi_minor), 2003323aa1f0SRanjani Sridharan le16_to_cpu(manifest->abi_patch), 2004323aa1f0SRanjani Sridharan SOF_ABI_MAJOR, SOF_ABI_MINOR, SOF_ABI_PATCH); 2005323aa1f0SRanjani Sridharan 2006323aa1f0SRanjani Sridharan /* TODO: Add ABI compatibility check */ 2007323aa1f0SRanjani Sridharan 2008323aa1f0SRanjani Sridharan /* no more data after the ABI version */ 2009323aa1f0SRanjani Sridharan if (size <= SOF_IPC4_TPLG_ABI_SIZE) 2010323aa1f0SRanjani Sridharan return 0; 2011323aa1f0SRanjani Sridharan 2012323aa1f0SRanjani Sridharan manifest_tlv = manifest->items; 2013323aa1f0SRanjani Sridharan len_check = sizeof(struct sof_manifest); 2014323aa1f0SRanjani Sridharan for (i = 0; i < le16_to_cpu(manifest->count); i++) { 2015323aa1f0SRanjani Sridharan len_check += sizeof(struct sof_manifest_tlv) + le32_to_cpu(manifest_tlv->size); 2016323aa1f0SRanjani Sridharan if (len_check > size) 2017323aa1f0SRanjani Sridharan return -EINVAL; 2018323aa1f0SRanjani Sridharan 2019323aa1f0SRanjani Sridharan switch (le32_to_cpu(manifest_tlv->type)) { 2020323aa1f0SRanjani Sridharan case SOF_MANIFEST_DATA_TYPE_NHLT: 2021323aa1f0SRanjani Sridharan /* no NHLT in BIOS, so use the one from topology manifest */ 2022323aa1f0SRanjani Sridharan if (ipc4_data->nhlt) 2023323aa1f0SRanjani Sridharan break; 2024323aa1f0SRanjani Sridharan ipc4_data->nhlt = devm_kmemdup(sdev->dev, manifest_tlv->data, 2025323aa1f0SRanjani Sridharan le32_to_cpu(manifest_tlv->size), GFP_KERNEL); 2026323aa1f0SRanjani Sridharan if (!ipc4_data->nhlt) 2027323aa1f0SRanjani Sridharan return -ENOMEM; 2028323aa1f0SRanjani Sridharan break; 2029323aa1f0SRanjani Sridharan default: 2030323aa1f0SRanjani Sridharan dev_warn(scomp->dev, "Skipping unknown manifest data type %d\n", 2031323aa1f0SRanjani Sridharan manifest_tlv->type); 2032323aa1f0SRanjani Sridharan break; 2033323aa1f0SRanjani Sridharan } 2034323aa1f0SRanjani Sridharan man_ptr += sizeof(struct sof_manifest_tlv) + le32_to_cpu(manifest_tlv->size); 2035323aa1f0SRanjani Sridharan manifest_tlv = (struct sof_manifest_tlv *)man_ptr; 2036323aa1f0SRanjani Sridharan } 2037323aa1f0SRanjani Sridharan 2038323aa1f0SRanjani Sridharan return 0; 2039323aa1f0SRanjani Sridharan } 2040323aa1f0SRanjani Sridharan 20419e2b5d33SRanjani Sridharan static int sof_ipc4_dai_get_clk(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, int clk_type) 20429e2b5d33SRanjani Sridharan { 20439e2b5d33SRanjani Sridharan struct sof_ipc4_copier *ipc4_copier = dai->private; 20449e2b5d33SRanjani Sridharan struct snd_soc_tplg_hw_config *hw_config; 20459e2b5d33SRanjani Sridharan struct snd_sof_dai_link *slink; 20469e2b5d33SRanjani Sridharan bool dai_link_found = false; 20479e2b5d33SRanjani Sridharan bool hw_cfg_found = false; 20489e2b5d33SRanjani Sridharan int i; 20499e2b5d33SRanjani Sridharan 20509e2b5d33SRanjani Sridharan if (!ipc4_copier) 20519e2b5d33SRanjani Sridharan return 0; 20529e2b5d33SRanjani Sridharan 20539e2b5d33SRanjani Sridharan list_for_each_entry(slink, &sdev->dai_link_list, list) { 20549e2b5d33SRanjani Sridharan if (!strcmp(slink->link->name, dai->name)) { 20559e2b5d33SRanjani Sridharan dai_link_found = true; 20569e2b5d33SRanjani Sridharan break; 20579e2b5d33SRanjani Sridharan } 20589e2b5d33SRanjani Sridharan } 20599e2b5d33SRanjani Sridharan 20609e2b5d33SRanjani Sridharan if (!dai_link_found) { 20619e2b5d33SRanjani Sridharan dev_err(sdev->dev, "no DAI link found for DAI %s\n", dai->name); 20629e2b5d33SRanjani Sridharan return -EINVAL; 20639e2b5d33SRanjani Sridharan } 20649e2b5d33SRanjani Sridharan 20659e2b5d33SRanjani Sridharan for (i = 0; i < slink->num_hw_configs; i++) { 20669e2b5d33SRanjani Sridharan hw_config = &slink->hw_configs[i]; 20679e2b5d33SRanjani Sridharan if (dai->current_config == le32_to_cpu(hw_config->id)) { 20689e2b5d33SRanjani Sridharan hw_cfg_found = true; 20699e2b5d33SRanjani Sridharan break; 20709e2b5d33SRanjani Sridharan } 20719e2b5d33SRanjani Sridharan } 20729e2b5d33SRanjani Sridharan 20739e2b5d33SRanjani Sridharan if (!hw_cfg_found) { 20749e2b5d33SRanjani Sridharan dev_err(sdev->dev, "no matching hw_config found for DAI %s\n", dai->name); 20759e2b5d33SRanjani Sridharan return -EINVAL; 20769e2b5d33SRanjani Sridharan } 20779e2b5d33SRanjani Sridharan 20789e2b5d33SRanjani Sridharan switch (ipc4_copier->dai_type) { 20799e2b5d33SRanjani Sridharan case SOF_DAI_INTEL_SSP: 20809e2b5d33SRanjani Sridharan switch (clk_type) { 20819e2b5d33SRanjani Sridharan case SOF_DAI_CLK_INTEL_SSP_MCLK: 20829e2b5d33SRanjani Sridharan return le32_to_cpu(hw_config->mclk_rate); 20839e2b5d33SRanjani Sridharan case SOF_DAI_CLK_INTEL_SSP_BCLK: 20849e2b5d33SRanjani Sridharan return le32_to_cpu(hw_config->bclk_rate); 20859e2b5d33SRanjani Sridharan default: 20869e2b5d33SRanjani Sridharan dev_err(sdev->dev, "Invalid clk type for SSP %d\n", clk_type); 20879e2b5d33SRanjani Sridharan break; 20889e2b5d33SRanjani Sridharan } 20899e2b5d33SRanjani Sridharan break; 20909e2b5d33SRanjani Sridharan default: 20919e2b5d33SRanjani Sridharan dev_err(sdev->dev, "DAI type %d not supported yet!\n", ipc4_copier->dai_type); 20929e2b5d33SRanjani Sridharan break; 20939e2b5d33SRanjani Sridharan } 20949e2b5d33SRanjani Sridharan 20959e2b5d33SRanjani Sridharan return -EINVAL; 20969e2b5d33SRanjani Sridharan } 20979e2b5d33SRanjani Sridharan 209818cd1f32SPeter Ujfalusi static int sof_ipc4_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verify) 209918cd1f32SPeter Ujfalusi { 210018cd1f32SPeter Ujfalusi struct snd_sof_pcm *spcm; 210118cd1f32SPeter Ujfalusi int dir, ret; 210218cd1f32SPeter Ujfalusi 210318cd1f32SPeter Ujfalusi /* 210418cd1f32SPeter Ujfalusi * This function is called during system suspend, we need to make sure 210518cd1f32SPeter Ujfalusi * that all streams have been freed up. 210618cd1f32SPeter Ujfalusi * Freeing might have been skipped when xrun happened just at the start 210718cd1f32SPeter Ujfalusi * of the suspend and it sent a SNDRV_PCM_TRIGGER_STOP to the active 210818cd1f32SPeter Ujfalusi * stream. This will call sof_pcm_stream_free() with 210918cd1f32SPeter Ujfalusi * free_widget_list = false which will leave the kernel and firmware out 211018cd1f32SPeter Ujfalusi * of sync during suspend/resume. 211118cd1f32SPeter Ujfalusi * 211218cd1f32SPeter Ujfalusi * This will also make sure that paused streams handled correctly. 211318cd1f32SPeter Ujfalusi */ 211418cd1f32SPeter Ujfalusi list_for_each_entry(spcm, &sdev->pcm_list, list) { 211518cd1f32SPeter Ujfalusi for_each_pcm_streams(dir) { 211618cd1f32SPeter Ujfalusi struct snd_pcm_substream *substream = spcm->stream[dir].substream; 211718cd1f32SPeter Ujfalusi 211882b18242SRanjani Sridharan if (!substream || !substream->runtime || spcm->stream[dir].suspend_ignored) 211918cd1f32SPeter Ujfalusi continue; 212018cd1f32SPeter Ujfalusi 212118cd1f32SPeter Ujfalusi if (spcm->stream[dir].list) { 212218cd1f32SPeter Ujfalusi ret = sof_pcm_stream_free(sdev, substream, spcm, dir, true); 212318cd1f32SPeter Ujfalusi if (ret < 0) 212418cd1f32SPeter Ujfalusi return ret; 212518cd1f32SPeter Ujfalusi } 212618cd1f32SPeter Ujfalusi } 212718cd1f32SPeter Ujfalusi } 212818cd1f32SPeter Ujfalusi return 0; 212918cd1f32SPeter Ujfalusi } 213018cd1f32SPeter Ujfalusi 2131e380c907SRanjani Sridharan static int sof_ipc4_link_setup(struct snd_sof_dev *sdev, struct snd_soc_dai_link *link) 2132e380c907SRanjani Sridharan { 2133e380c907SRanjani Sridharan if (link->no_pcm) 2134e380c907SRanjani Sridharan return 0; 2135e380c907SRanjani Sridharan 2136e380c907SRanjani Sridharan /* 2137e380c907SRanjani Sridharan * set default trigger order for all links. Exceptions to 2138e380c907SRanjani Sridharan * the rule will be handled in sof_pcm_dai_link_fixup() 2139e380c907SRanjani Sridharan * For playback, the sequence is the following: start BE, 2140e380c907SRanjani Sridharan * start FE, stop FE, stop BE; for Capture the sequence is 2141e380c907SRanjani Sridharan * inverted start FE, start BE, stop BE, stop FE 2142e380c907SRanjani Sridharan */ 2143e380c907SRanjani Sridharan link->trigger[SNDRV_PCM_STREAM_PLAYBACK] = SND_SOC_DPCM_TRIGGER_POST; 2144e380c907SRanjani Sridharan link->trigger[SNDRV_PCM_STREAM_CAPTURE] = SND_SOC_DPCM_TRIGGER_PRE; 2145e380c907SRanjani Sridharan 2146e380c907SRanjani Sridharan return 0; 2147e380c907SRanjani Sridharan } 2148e380c907SRanjani Sridharan 21497d573425SBard Liao static enum sof_tokens common_copier_token_list[] = { 21502cabd02bSRanjani Sridharan SOF_COMP_TOKENS, 21512cabd02bSRanjani Sridharan SOF_AUDIO_FMT_NUM_TOKENS, 21522cabd02bSRanjani Sridharan SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS, 21532cabd02bSRanjani Sridharan SOF_IN_AUDIO_FORMAT_TOKENS, 21542cabd02bSRanjani Sridharan SOF_OUT_AUDIO_FORMAT_TOKENS, 21552cabd02bSRanjani Sridharan SOF_COPIER_GATEWAY_CFG_TOKENS, 21562cabd02bSRanjani Sridharan SOF_COPIER_TOKENS, 21572cabd02bSRanjani Sridharan SOF_COMP_EXT_TOKENS, 21582cabd02bSRanjani Sridharan }; 21592cabd02bSRanjani Sridharan 216090e89155SRanjani Sridharan static enum sof_tokens pipeline_token_list[] = { 216190e89155SRanjani Sridharan SOF_SCHED_TOKENS, 216290e89155SRanjani Sridharan SOF_PIPELINE_TOKENS, 216390e89155SRanjani Sridharan }; 216490e89155SRanjani Sridharan 2165abfb536bSRanjani Sridharan static enum sof_tokens dai_token_list[] = { 2166abfb536bSRanjani Sridharan SOF_COMP_TOKENS, 2167abfb536bSRanjani Sridharan SOF_AUDIO_FMT_NUM_TOKENS, 2168abfb536bSRanjani Sridharan SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS, 2169abfb536bSRanjani Sridharan SOF_IN_AUDIO_FORMAT_TOKENS, 2170abfb536bSRanjani Sridharan SOF_OUT_AUDIO_FORMAT_TOKENS, 2171abfb536bSRanjani Sridharan SOF_COPIER_GATEWAY_CFG_TOKENS, 2172abfb536bSRanjani Sridharan SOF_COPIER_TOKENS, 2173abfb536bSRanjani Sridharan SOF_DAI_TOKENS, 2174abfb536bSRanjani Sridharan SOF_COMP_EXT_TOKENS, 2175abfb536bSRanjani Sridharan }; 2176abfb536bSRanjani Sridharan 21774f838ab2SRanjani Sridharan static enum sof_tokens pga_token_list[] = { 21784f838ab2SRanjani Sridharan SOF_COMP_TOKENS, 21794f838ab2SRanjani Sridharan SOF_GAIN_TOKENS, 21804f838ab2SRanjani Sridharan SOF_AUDIO_FMT_NUM_TOKENS, 21814f838ab2SRanjani Sridharan SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS, 21824f838ab2SRanjani Sridharan SOF_IN_AUDIO_FORMAT_TOKENS, 21834f838ab2SRanjani Sridharan SOF_COMP_EXT_TOKENS, 21844f838ab2SRanjani Sridharan }; 21854f838ab2SRanjani Sridharan 21864d4ba014SRanjani Sridharan static enum sof_tokens mixer_token_list[] = { 21874d4ba014SRanjani Sridharan SOF_COMP_TOKENS, 21884d4ba014SRanjani Sridharan SOF_AUDIO_FMT_NUM_TOKENS, 21894d4ba014SRanjani Sridharan SOF_IN_AUDIO_FORMAT_TOKENS, 21904d4ba014SRanjani Sridharan SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS, 21914d4ba014SRanjani Sridharan SOF_COMP_EXT_TOKENS, 21924d4ba014SRanjani Sridharan }; 21934d4ba014SRanjani Sridharan 2194b85f4fc4SRander Wang static enum sof_tokens src_token_list[] = { 2195b85f4fc4SRander Wang SOF_COMP_TOKENS, 2196b85f4fc4SRander Wang SOF_SRC_TOKENS, 2197b85f4fc4SRander Wang SOF_AUDIO_FMT_NUM_TOKENS, 2198b85f4fc4SRander Wang SOF_IN_AUDIO_FORMAT_TOKENS, 2199b85f4fc4SRander Wang SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS, 2200b85f4fc4SRander Wang SOF_COMP_EXT_TOKENS, 2201b85f4fc4SRander Wang }; 2202b85f4fc4SRander Wang 220390e89155SRanjani Sridharan static const struct sof_ipc_tplg_widget_ops tplg_ipc4_widget_ops[SND_SOC_DAPM_TYPE_COUNT] = { 22042cabd02bSRanjani Sridharan [snd_soc_dapm_aif_in] = {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm, 22057d573425SBard Liao common_copier_token_list, ARRAY_SIZE(common_copier_token_list), 22067d573425SBard Liao NULL, sof_ipc4_prepare_copier_module, 2207904c48c4SRanjani Sridharan sof_ipc4_unprepare_copier_module}, 22082cabd02bSRanjani Sridharan [snd_soc_dapm_aif_out] = {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm, 22097d573425SBard Liao common_copier_token_list, ARRAY_SIZE(common_copier_token_list), 22107d573425SBard Liao NULL, sof_ipc4_prepare_copier_module, 2211904c48c4SRanjani Sridharan sof_ipc4_unprepare_copier_module}, 2212abfb536bSRanjani Sridharan [snd_soc_dapm_dai_in] = {sof_ipc4_widget_setup_comp_dai, sof_ipc4_widget_free_comp_dai, 2213acf52594SRanjani Sridharan dai_token_list, ARRAY_SIZE(dai_token_list), NULL, 2214acf52594SRanjani Sridharan sof_ipc4_prepare_copier_module, 2215acf52594SRanjani Sridharan sof_ipc4_unprepare_copier_module}, 2216abfb536bSRanjani Sridharan [snd_soc_dapm_dai_out] = {sof_ipc4_widget_setup_comp_dai, sof_ipc4_widget_free_comp_dai, 2217acf52594SRanjani Sridharan dai_token_list, ARRAY_SIZE(dai_token_list), NULL, 2218acf52594SRanjani Sridharan sof_ipc4_prepare_copier_module, 2219acf52594SRanjani Sridharan sof_ipc4_unprepare_copier_module}, 22207d573425SBard Liao [snd_soc_dapm_buffer] = {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm, 22217d573425SBard Liao common_copier_token_list, ARRAY_SIZE(common_copier_token_list), 22227d573425SBard Liao NULL, sof_ipc4_prepare_copier_module, 22237d573425SBard Liao sof_ipc4_unprepare_copier_module}, 2224a29b2d02SBard Liao [snd_soc_dapm_scheduler] = {sof_ipc4_widget_setup_comp_pipeline, 2225a29b2d02SBard Liao sof_ipc4_widget_free_comp_pipeline, 222690e89155SRanjani Sridharan pipeline_token_list, ARRAY_SIZE(pipeline_token_list), NULL, 222790e89155SRanjani Sridharan NULL, NULL}, 2228dc4fc0aeSLibin Yang [snd_soc_dapm_pga] = {sof_ipc4_widget_setup_comp_pga, sof_ipc4_widget_free_comp_pga, 22294f838ab2SRanjani Sridharan pga_token_list, ARRAY_SIZE(pga_token_list), NULL, 22304f838ab2SRanjani Sridharan sof_ipc4_prepare_gain_module, 2231711d0427SBard Liao NULL}, 2232dc4fc0aeSLibin Yang [snd_soc_dapm_mixer] = {sof_ipc4_widget_setup_comp_mixer, sof_ipc4_widget_free_comp_mixer, 22334d4ba014SRanjani Sridharan mixer_token_list, ARRAY_SIZE(mixer_token_list), 22344d4ba014SRanjani Sridharan NULL, sof_ipc4_prepare_mixer_module, 2235711d0427SBard Liao NULL}, 2236b85f4fc4SRander Wang [snd_soc_dapm_src] = {sof_ipc4_widget_setup_comp_src, sof_ipc4_widget_free_comp_src, 2237b85f4fc4SRander Wang src_token_list, ARRAY_SIZE(src_token_list), 2238b85f4fc4SRander Wang NULL, sof_ipc4_prepare_src_module, 2239b85f4fc4SRander Wang NULL}, 224090e89155SRanjani Sridharan }; 224190e89155SRanjani Sridharan 224290e89155SRanjani Sridharan const struct sof_ipc_tplg_ops ipc4_tplg_ops = { 224390e89155SRanjani Sridharan .widget = tplg_ipc4_widget_ops, 224490e89155SRanjani Sridharan .token_list = ipc4_token_list, 2245d97964f8SRanjani Sridharan .control_setup = sof_ipc4_control_setup, 2246955e84fcSRanjani Sridharan .control = &tplg_ipc4_control_ops, 22476e9257a1SRanjani Sridharan .widget_setup = sof_ipc4_widget_setup, 22486e9257a1SRanjani Sridharan .widget_free = sof_ipc4_widget_free, 22493acd5270SRanjani Sridharan .route_setup = sof_ipc4_route_setup, 22503acd5270SRanjani Sridharan .route_free = sof_ipc4_route_free, 2251acf48a1fSRanjani Sridharan .dai_config = sof_ipc4_dai_config, 2252323aa1f0SRanjani Sridharan .parse_manifest = sof_ipc4_parse_manifest, 22539e2b5d33SRanjani Sridharan .dai_get_clk = sof_ipc4_dai_get_clk, 225418cd1f32SPeter Ujfalusi .tear_down_all_pipelines = sof_ipc4_tear_down_all_pipelines, 2255e380c907SRanjani Sridharan .link_setup = sof_ipc4_link_setup, 225690e89155SRanjani Sridharan }; 2257