From ef24388225f87f2604522fe86fafacc271ec4a29 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 21 Aug 2023 14:36:26 +0300 Subject: [PATCH 1/4] ASoC: SOF: ipc4-topology: Modify pipeline params based on SRC output format Modify the pipeline_params based on the SRC output format and set the sink_rate in the IPC data. Signed-off-by: Ranjani Sridharan Reviewed-by: Bard Liao Reviewed-by: Pierre-Louis Bossart Reviewed-by: Seppo Ingalsuo Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20230821113629.5017-2-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-topology.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 633f6040d712..8bc12f12888d 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -1838,10 +1838,10 @@ static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget, struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct sof_ipc4_src *src = swidget->private; struct sof_ipc4_available_audio_format *available_fmt = &src->available_fmt; + struct sof_ipc4_audio_format *out_audio_fmt; struct sof_ipc4_audio_format *in_fmt; u32 out_ref_rate, out_ref_channels, out_ref_valid_bits; - struct snd_interval *rate; - int ret; + int ret, output_format_index; ret = sof_ipc4_init_input_audio_fmt(sdev, swidget, &src->base_config, pipeline_params, available_fmt); @@ -1853,22 +1853,23 @@ static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget, out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg); out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg); - ret = sof_ipc4_init_output_audio_fmt(sdev, &src->base_config, available_fmt, - out_ref_rate, out_ref_channels, out_ref_valid_bits); - if (ret < 0) { + output_format_index = sof_ipc4_init_output_audio_fmt(sdev, &src->base_config, + available_fmt, out_ref_rate, + out_ref_channels, out_ref_valid_bits); + if (output_format_index < 0) { dev_err(sdev->dev, "Failed to initialize output format for %s", swidget->widget->name); + return output_format_index; } /* update pipeline memory usage */ sof_ipc4_update_resource_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; + out_audio_fmt = &available_fmt->output_pin_fmts[output_format_index].audio_fmt; + src->sink_rate = out_audio_fmt->sampling_frequency; - return 0; + /* update pipeline_params for sink widgets */ + return sof_ipc4_update_hw_params(sdev, pipeline_params, out_audio_fmt); } static int From 56ecc164040b3685f6cb36b4d513d73d0f88140b Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 21 Aug 2023 14:36:27 +0300 Subject: [PATCH 2/4] ASoC: SOF: ipc4-topology: Fix the output reference params for SRC For playback, the SRC sink rate must be configured based on the requested output format which is restricted to only handle DAI's that support a single audio format for now. For capture, the SRC module should convert the rate to match the rate requested by the PCM hw_params. Signed-off-by: Ranjani Sridharan Reviewed-by: Bard Liao Reviewed-by: Pierre-Louis Bossart Reviewed-by: Seppo Ingalsuo Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20230821113629.5017-3-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-topology.c | 40 ++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 8bc12f12888d..39649fddf16a 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -1839,19 +1839,39 @@ static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget, struct sof_ipc4_src *src = swidget->private; struct sof_ipc4_available_audio_format *available_fmt = &src->available_fmt; struct sof_ipc4_audio_format *out_audio_fmt; - struct sof_ipc4_audio_format *in_fmt; + struct sof_ipc4_audio_format *in_audio_fmt; u32 out_ref_rate, out_ref_channels, out_ref_valid_bits; - int ret, output_format_index; + int output_format_index, input_format_index; - ret = sof_ipc4_init_input_audio_fmt(sdev, swidget, &src->base_config, - pipeline_params, available_fmt); - if (ret < 0) - return ret; + input_format_index = sof_ipc4_init_input_audio_fmt(sdev, swidget, &src->base_config, + pipeline_params, available_fmt); + if (input_format_index < 0) + return input_format_index; - in_fmt = &available_fmt->input_pin_fmts[ret].audio_fmt; - out_ref_rate = in_fmt->sampling_frequency; - out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg); - out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg); + /* + * For playback, the SRC sink rate will be configured based on the requested output + * format, which is restricted to only deal with DAI's with a single format for now. + */ + if (dir == SNDRV_PCM_STREAM_PLAYBACK && available_fmt->num_output_formats > 1) { + dev_err(sdev->dev, "Invalid number of output formats: %d for SRC %s\n", + available_fmt->num_output_formats, swidget->widget->name); + return -EINVAL; + } + + /* + * SRC does not perform format conversion, so the output channels and valid bit depth must + * be the same as that of the input. + */ + in_audio_fmt = &available_fmt->input_pin_fmts[input_format_index].audio_fmt; + out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_audio_fmt->fmt_cfg); + out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_audio_fmt->fmt_cfg); + + /* + * For capture, the SRC module should convert the rate to match the rate requested by the + * PCM hw_params. Set the reference params based on the fe_params unconditionally as it + * will be ignored for playback anyway. + */ + out_ref_rate = params_rate(fe_params); output_format_index = sof_ipc4_init_output_audio_fmt(sdev, &src->base_config, available_fmt, out_ref_rate, From 769e8f6cd7182c95d4bd37491e13300ff067c7a7 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 21 Aug 2023 14:36:28 +0300 Subject: [PATCH 3/4] ASoC: SOF: ipc4-topology: Fix pipeline params at the output of copier When we walk the list of connected widgets from the source to the sink to prepare all widgets, the pipeline_params must be modified to reflect the output audio format at each widget. But, the copier only modifies the sample format in the pipeline_params. So, fix it to also modify the rate and channels. Signed-off-by: Ranjani Sridharan Reviewed-by: Bard Liao Reviewed-by: Pierre-Louis Bossart Reviewed-by: Seppo Ingalsuo Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20230821113629.5017-4-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-topology.c | 27 +-------------------------- 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 39649fddf16a..310aadd97d28 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -1349,25 +1349,6 @@ static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_s } #endif -static int ipc4_set_fmt_mask(struct snd_mask *fmt, unsigned int bit_depth) -{ - switch (bit_depth) { - case 16: - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE); - break; - case 24: - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); - break; - case 32: - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE); - break; - default: - return -EINVAL; - } - - return 0; -} - static int sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, struct snd_pcm_hw_params *fe_params, @@ -1381,8 +1362,6 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, struct snd_pcm_hw_params *ref_params; struct sof_ipc4_copier *ipc4_copier; struct snd_sof_dai *dai; - struct snd_mask *fmt; - int out_sample_valid_bits; u32 gtw_cfg_config_length; u32 dma_config_tlv_size = 0; void **ipc_config_data; @@ -1664,11 +1643,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, } /* modify the input params for the next widget */ - fmt = hw_param_mask(pipeline_params, SNDRV_PCM_HW_PARAM_FORMAT); - out_sample_valid_bits = - SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(copier_data->out_format.fmt_cfg); - snd_mask_none(fmt); - ret = ipc4_set_fmt_mask(fmt, out_sample_valid_bits); + ret = sof_ipc4_update_hw_params(sdev, pipeline_params, &copier_data->out_format); if (ret) return ret; From 70b0924b22efe2135222a2c7141a83dfe0c78779 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 21 Aug 2023 14:36:29 +0300 Subject: [PATCH 4/4] ASoC: SOF: ipc4-topology: Modify the reference output valid_bits for copier If the copier has only output valid_bits across all its output formats, the reference for selecting the output format must be set that instead of the valid_bits from the selected input format. Signed-off-by: Ranjani Sridharan Reviewed-by: Bard Liao Reviewed-by: Seppo Ingalsuo Reviewed-by: Pierre-Louis Bossart Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20230821113629.5017-5-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-topology.c | 58 ++++++++++++++++++++++++++++++++--- 1 file changed, 53 insertions(+), 5 deletions(-) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 310aadd97d28..eff43635a88f 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -1349,6 +1349,31 @@ static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_s } #endif +static bool sof_ipc4_copier_is_single_format(struct snd_sof_dev *sdev, + struct sof_ipc4_pin_format *pin_fmts, + u32 pin_fmts_size) +{ + struct sof_ipc4_audio_format *fmt; + u32 valid_bits; + int i; + + fmt = &pin_fmts[0].audio_fmt; + valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg); + + /* check if all output formats in topology are the same */ + for (i = 1; i < pin_fmts_size; i++) { + u32 _valid_bits; + + fmt = &pin_fmts[i].audio_fmt; + _valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg); + + if (_valid_bits != valid_bits) + return false; + } + + return true; +} + static int sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, struct snd_pcm_hw_params *fe_params, @@ -1371,6 +1396,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, u32 out_ref_rate, out_ref_channels; u32 deep_buffer_dma_ms = 0; int output_fmt_index; + bool single_output_format; dev_dbg(sdev->dev, "copier %s, type %d", swidget->widget->name, swidget->id); @@ -1504,6 +1530,9 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, return ret; /* set the reference params for output format selection */ + single_output_format = sof_ipc4_copier_is_single_format(sdev, + available_fmt->output_pin_fmts, + available_fmt->num_output_formats); switch (swidget->id) { case snd_soc_dapm_aif_in: case snd_soc_dapm_dai_out: @@ -1514,17 +1543,21 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, in_fmt = &available_fmt->input_pin_fmts[ret].audio_fmt; out_ref_rate = in_fmt->sampling_frequency; out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg); - out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg); + + if (!single_output_format) + out_ref_valid_bits = + SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg); break; } case snd_soc_dapm_aif_out: case snd_soc_dapm_dai_in: - out_ref_valid_bits = sof_ipc4_get_valid_bits(sdev, fe_params); - if (out_ref_valid_bits < 0) - return out_ref_valid_bits; - out_ref_rate = params_rate(fe_params); out_ref_channels = params_channels(fe_params); + if (!single_output_format) { + out_ref_valid_bits = sof_ipc4_get_valid_bits(sdev, fe_params); + if (out_ref_valid_bits < 0) + return out_ref_valid_bits; + } break; default: /* @@ -1534,6 +1567,21 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, return -EINVAL; } + /* + * if the output format is the same across all available output formats, choose + * that as the reference. + */ + if (single_output_format) { + struct sof_ipc4_audio_format *out_fmt; + + out_fmt = &available_fmt->output_pin_fmts[0].audio_fmt; + out_ref_valid_bits = + SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(out_fmt->fmt_cfg); + } + + dev_dbg(sdev->dev, "copier %s: reference output rate %d, channels %d valid_bits %d\n", + swidget->widget->name, out_ref_rate, out_ref_channels, out_ref_valid_bits); + output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, &copier_data->base_config, available_fmt, out_ref_rate, out_ref_channels, out_ref_valid_bits);