From 1b2aba687453cedc8cfbd6d50425676abf842089 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Mon, 13 Jun 2022 16:45:38 +0800 Subject: [PATCH 1/3] ASoC: SOF: ipc4-pcm: set pcm rate to dai setting Dsp converts pcm rate to the one defined by dai. When SRC is used, the pcm runtime rate is different with dai rate and we need to fix it up for BE components. Signed-off-by: Rander Wang --- sound/soc/sof/ipc4-pcm.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c index 6a702f9dc065bd..732872395980ae 100644 --- a/sound/soc/sof/ipc4-pcm.c +++ b/sound/soc/sof/ipc4-pcm.c @@ -179,6 +179,7 @@ static int sof_ipc4_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, { struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME); struct snd_sof_dai *dai = snd_sof_find_dai(component, rtd->dai_link->name); + struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); struct sof_ipc4_copier *ipc4_copier; @@ -201,6 +202,9 @@ static int sof_ipc4_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, snd_mask_none(fmt); snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE); + rate->min = ipc4_copier->available_fmt.base_config->audio_fmt.sampling_frequency; + rate->max = rate->min; + /* * Set trigger order for capture to SND_SOC_DPCM_TRIGGER_PRE. This is required * to ensure that the BE DAI pipeline gets stopped/suspended before the FE DAI From 4e06df8e83bafb61a5821c9936d12ae7872c987c Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Mon, 13 Jun 2022 17:25:22 +0800 Subject: [PATCH 2/3] ASoC: SOF: add ipc4 SRC module support SRC module only needs two parameters : base module config and sink rate. This patch adds prepare and setup for SRC widgets. Signed-off-by: Rander Wang --- sound/soc/sof/ipc4-topology.c | 114 +++++++++++++++++++++++++++++++++- sound/soc/sof/ipc4-topology.h | 14 +++++ 2 files changed, 127 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index f7709191811806..47291fa3f166a7 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -111,6 +111,12 @@ static const struct sof_topology_token gain_tokens[] = { get_token_u32, offsetof(struct sof_ipc4_gain_data, init_val)}, }; +/* SRC */ +static const struct sof_topology_token src_tokens[] = { + {SOF_TKN_SRC_RATE_OUT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc4_src, sink_rate)}, +}; + static const struct sof_token_info ipc4_token_list[SOF_TOKEN_COUNT] = { [SOF_DAI_TOKENS] = {"DAI tokens", dai_tokens, ARRAY_SIZE(dai_tokens)}, [SOF_PIPELINE_TOKENS] = {"Pipeline tokens", pipeline_tokens, ARRAY_SIZE(pipeline_tokens)}, @@ -134,6 +140,7 @@ static const struct sof_token_info ipc4_token_list[SOF_TOKEN_COUNT] = { [SOF_AUDIO_FMT_NUM_TOKENS] = {"IPC4 Audio format number tokens", ipc4_audio_fmt_num_tokens, ARRAY_SIZE(ipc4_audio_fmt_num_tokens)}, [SOF_GAIN_TOKENS] = {"Gain tokens", gain_tokens, ARRAY_SIZE(gain_tokens)}, + [SOF_SRC_TOKENS] = {"SRC tokens", src_tokens, ARRAY_SIZE(src_tokens)}, }; static void sof_ipc4_dbg_audio_format(struct device *dev, @@ -740,6 +747,58 @@ static int sof_ipc4_widget_setup_comp_mixer(struct snd_sof_widget *swidget) return ret; } +static int sof_ipc4_widget_setup_comp_src(struct snd_sof_widget *swidget) +{ + struct snd_soc_component *scomp = swidget->scomp; + struct sof_ipc4_src *src; + int ret; + + dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name); + + src = kzalloc(sizeof(*src), GFP_KERNEL); + if (!src) + return -ENOMEM; + + swidget->private = src; + + /* The out_audio_fmt in topology is ignored as it is not required by SRC */ + ret = sof_ipc4_get_audio_fmt(scomp, swidget, &src->available_fmt, false); + if (ret) + goto err; + + ret = sof_update_ipc_object(scomp, src, SOF_SRC_TOKENS, swidget->tuples, + swidget->num_tuples, sizeof(src), 1); + if (ret) { + dev_err(scomp->dev, "Parsing SRC tokens failed\n"); + goto err; + } + + dev_dbg(scomp->dev, "SRC sink rate %d\n", src->sink_rate); + + ret = sof_ipc4_widget_setup_msg(swidget, &src->msg); + if (ret) + goto err; + + return 0; +err: + sof_ipc4_free_audio_fmt(&src->available_fmt); + kfree(src); + swidget->private = NULL; + return ret; +} + +static void sof_ipc4_widget_free_comp_src(struct snd_sof_widget *swidget) +{ + struct sof_ipc4_src *src = swidget->private; + + if (!src) + return; + + sof_ipc4_free_audio_fmt(&src->available_fmt); + kfree(swidget->private); + swidget->private = NULL; +} + static void sof_ipc4_widget_free_comp_mixer(struct snd_sof_widget *swidget) { struct sof_ipc4_mixer *mixer = swidget->private; @@ -1305,6 +1364,37 @@ static int sof_ipc4_prepare_mixer_module(struct snd_sof_widget *swidget, return 0; } +static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget, + struct snd_pcm_hw_params *fe_params, + struct snd_sof_platform_stream_params *platform_params, + struct snd_pcm_hw_params *pipeline_params, int dir) +{ + struct snd_soc_component *scomp = swidget->scomp; + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct sof_ipc4_src *src = swidget->private; + struct snd_interval *rate; + int ret; + + src->available_fmt.ref_audio_fmt = &src->available_fmt.base_config->audio_fmt; + + /* output format is not required to be sent to the FW for SRC */ + ret = sof_ipc4_init_audio_fmt(sdev, swidget, &src->base_config, + NULL, pipeline_params, &src->available_fmt, + sizeof(src->base_config)); + if (ret < 0) + return ret; + + /* update pipeline memory usage */ + sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &src->base_config); + + /* update pipeline_params for sink widgets */ + rate = hw_param_interval(pipeline_params, SNDRV_PCM_HW_PARAM_RATE); + rate->min = src->sink_rate; + rate->max = rate->min; + + return 0; +} + static int sof_ipc4_control_load_volume(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol) { struct sof_ipc4_control_data *control_data; @@ -1360,7 +1450,6 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget u32 ipc_size = 0; int ret; - switch (swidget->id) { case snd_soc_dapm_scheduler: pipeline = swidget->private; @@ -1415,6 +1504,16 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget msg = &mixer->msg; break; } + case snd_soc_dapm_src: + { + struct sof_ipc4_src *src = swidget->private; + + ipc_size = sizeof(struct sof_ipc4_base_module_cfg) + sizeof(src->sink_rate); + ipc_data = src; + + msg = &src->msg; + break; + } default: dev_err(sdev->dev, "widget type %d not supported", swidget->id); return -EINVAL; @@ -1762,6 +1861,15 @@ static enum sof_tokens mixer_token_list[] = { SOF_COMP_EXT_TOKENS, }; +static enum sof_tokens src_token_list[] = { + SOF_COMP_TOKENS, + SOF_SRC_TOKENS, + SOF_AUDIO_FMT_NUM_TOKENS, + SOF_IN_AUDIO_FORMAT_TOKENS, + SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS, + SOF_COMP_EXT_TOKENS, +}; + static const struct sof_ipc_tplg_widget_ops tplg_ipc4_widget_ops[SND_SOC_DAPM_TYPE_COUNT] = { [snd_soc_dapm_aif_in] = {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm, host_token_list, ARRAY_SIZE(host_token_list), NULL, @@ -1790,6 +1898,10 @@ static const struct sof_ipc_tplg_widget_ops tplg_ipc4_widget_ops[SND_SOC_DAPM_TY mixer_token_list, ARRAY_SIZE(mixer_token_list), NULL, sof_ipc4_prepare_mixer_module, NULL}, + [snd_soc_dapm_src] = {sof_ipc4_widget_setup_comp_src, sof_ipc4_widget_free_comp_src, + src_token_list, ARRAY_SIZE(src_token_list), + NULL, sof_ipc4_prepare_src_module, + NULL}, }; const struct sof_ipc_tplg_ops ipc4_tplg_ops = { diff --git a/sound/soc/sof/ipc4-topology.h b/sound/soc/sof/ipc4-topology.h index 3bc2fe38c7333a..56ab80e722ceec 100644 --- a/sound/soc/sof/ipc4-topology.h +++ b/sound/soc/sof/ipc4-topology.h @@ -242,4 +242,18 @@ struct sof_ipc4_mixer { struct sof_ipc4_msg msg; }; +/** + * struct sof_ipc4_src SRC config data + * @base_config: IPC base config data + * @sink_rate: Output rate for sink module + * @available_fmt: Available audio format + * @msg: IPC4 message struct containing header and data info + */ +struct sof_ipc4_src { + struct sof_ipc4_base_module_cfg base_config; + uint32_t sink_rate; + struct sof_ipc4_available_audio_format available_fmt; + struct sof_ipc4_msg msg; +}; + #endif From 586df0854aad43aae566e144586b86db6028186f Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Mon, 13 Jun 2022 17:47:33 +0800 Subject: [PATCH 3/3] ASoC: SOF: ipc4-topology: set domain bit based on dp domain type Currently the domain bit in ipc msg for module initialization is set to lp (low power) mode for pipeline. This is not correct since it is for module domain type: ll domain or dp domain which are for scheduler in fw. If the domain bit is set to 1 fw will process the module in dp domain or deal it with ll domain. So set domain bit based on dp domain setting. Signed-off-by: Rander Wang --- sound/soc/sof/ipc4-topology.c | 6 ++++-- sound/soc/sof/ipc4-topology.h | 13 ++++++++++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 47291fa3f166a7..af072b484a6072 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -314,6 +314,7 @@ static int sof_ipc4_widget_set_module_info(struct snd_sof_widget *swidget) static int sof_ipc4_widget_setup_msg(struct snd_sof_widget *swidget, struct sof_ipc4_msg *msg) { struct sof_ipc4_fw_module *fw_module; + uint32_t type; int ret; ret = sof_ipc4_widget_set_module_info(swidget); @@ -330,6 +331,9 @@ static int sof_ipc4_widget_setup_msg(struct snd_sof_widget *swidget, struct sof_ msg->extension = SOF_IPC4_MOD_EXT_PPL_ID(swidget->pipeline_id); msg->extension |= SOF_IPC4_MOD_EXT_CORE_ID(swidget->core); + type = fw_module->man4_module_entry.type & SOF_IPC4_MODULE_DP ? 1 : 0; + msg->extension |= SOF_IPC4_MOD_EXT_DOMAIN(type); + return 0; } @@ -1532,8 +1536,6 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget msg->extension &= ~SOF_IPC4_MOD_EXT_PARAM_SIZE_MASK; msg->extension |= ipc_size >> 2; - msg->extension &= ~SOF_IPC4_MOD_EXT_DOMAIN_MASK; - msg->extension |= SOF_IPC4_MOD_EXT_DOMAIN(pipeline->lp_mode); } dev_dbg(sdev->dev, "Create widget %s instance %d - pipe %d - core %d\n", swidget->widget->name, swidget->instance_id, swidget->pipeline_id, swidget->core); diff --git a/sound/soc/sof/ipc4-topology.h b/sound/soc/sof/ipc4-topology.h index 56ab80e722ceec..0aa87a8add5d39 100644 --- a/sound/soc/sof/ipc4-topology.h +++ b/sound/soc/sof/ipc4-topology.h @@ -15,7 +15,18 @@ #define SOF_IPC4_FW_PAGE(x) ((((x) + BIT(12) - 1) & ~(BIT(12) - 1)) >> 12) #define SOF_IPC4_FW_ROUNDUP(x) (((x) + BIT(6) - 1) & (~(BIT(6) - 1))) -#define SOF_IPC4_MODULE_LL BIT(5) +#define SOF_IPC4_MODULE_LOAD_TYPE GENMASK(3, 0) +#define SOF_IPC4_MODULE_AUTO_START BIT(4) +/* + * Two module schedule domains in fw : + * LL domain - Low latency domain + * DP domain - Data processing domain + * The LL setting should be equal to !DP setting + */ +#define SOF_IPC4_MODULE_LL BIT(5) +#define SOF_IPC4_MODULE_DP BIT(6) +#define SOF_IPC4_MODULE_LIB_CODE BIT(7) + #define SOF_IPC4_MODULE_INSTANCE_LIST_ITEM_SIZE 12 #define SOF_IPC4_PIPELINE_OBJECT_SIZE 448 #define SOF_IPC4_DATA_QUEUE_OBJECT_SIZE 128