ASoC: SOF: ipc4-topology: Correct DAI copier config and NHLT blob request

In case of capture and when the DAI copier have single bit depth supported
on it's input side we should use this format instead of the one in
fe_params.

Regardless of the stream direction for the NHLT blob lookup when the DAI
copier only supports single bit depth on the DAI side we should only look
for a blob which matches with this single configuration.

For DMIC if the DAI copier supports multiple bit depths, try to request
32-bit blob first if the requested bit depth is 16-bit.
If the 32-bit blob is available then look for marching (32-bit) copier
format to make sure that both the blob and copier have correct parameters.

Reviewed-by: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Link: https://lore.kernel.org/r/20240503133253.108201-4-pierre-louis.bossart@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Peter Ujfalusi 2024-05-03 08:32:53 -05:00 committed by Mark Brown
parent b679302526
commit f9209644ae
No known key found for this signature in database
GPG key ID: 24D68B725D5487D0

View file

@ -1420,13 +1420,16 @@ static int snd_sof_get_hw_config_params(struct snd_sof_dev *sdev, struct snd_sof
return 0; return 0;
} }
static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, static int
struct snd_pcm_hw_params *params, u32 dai_index, snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai,
u32 linktype, u8 dir, u32 **dst, u32 *len) bool single_format,
struct snd_pcm_hw_params *params, u32 dai_index,
u32 linktype, u8 dir, u32 **dst, u32 *len)
{ {
struct sof_ipc4_fw_data *ipc4_data = sdev->private; struct sof_ipc4_fw_data *ipc4_data = sdev->private;
struct nhlt_specific_cfg *cfg; struct nhlt_specific_cfg *cfg;
int sample_rate, channel_count; int sample_rate, channel_count;
bool format_change = false;
int bit_depth, ret; int bit_depth, ret;
u32 nhlt_type; u32 nhlt_type;
int dev_type = 0; int dev_type = 0;
@ -1435,9 +1438,18 @@ static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_s
switch (linktype) { switch (linktype) {
case SOF_DAI_INTEL_DMIC: case SOF_DAI_INTEL_DMIC:
nhlt_type = NHLT_LINK_DMIC; nhlt_type = NHLT_LINK_DMIC;
bit_depth = params_width(params);
channel_count = params_channels(params); channel_count = params_channels(params);
sample_rate = params_rate(params); sample_rate = params_rate(params);
bit_depth = params_width(params);
/*
* Look for 32-bit blob first instead of 16-bit if copier
* supports multiple formats
*/
if (bit_depth == 16 && !single_format) {
dev_dbg(sdev->dev, "Looking for 32-bit blob first for DMIC\n");
format_change = true;
bit_depth = 32;
}
break; break;
case SOF_DAI_INTEL_SSP: case SOF_DAI_INTEL_SSP:
nhlt_type = NHLT_LINK_SSP; nhlt_type = NHLT_LINK_SSP;
@ -1471,22 +1483,56 @@ static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_s
dir, dev_type); dir, dev_type);
if (!cfg) { if (!cfg) {
if (format_change) {
/*
* The 32-bit blob was not found in NHLT table, try to
* look for one based on the params
*/
bit_depth = params_width(params);
format_change = false;
cfg = intel_nhlt_get_endpoint_blob(sdev->dev, ipc4_data->nhlt,
dai_index, nhlt_type,
bit_depth, bit_depth,
channel_count, sample_rate,
dir, dev_type);
if (cfg)
goto out;
}
dev_err(sdev->dev, dev_err(sdev->dev,
"no matching blob for sample rate: %d sample width: %d channels: %d\n", "no matching blob for sample rate: %d sample width: %d channels: %d\n",
sample_rate, bit_depth, channel_count); sample_rate, bit_depth, channel_count);
return -EINVAL; return -EINVAL;
} }
out:
/* config length should be in dwords */ /* config length should be in dwords */
*len = cfg->size >> 2; *len = cfg->size >> 2;
*dst = (u32 *)cfg->caps; *dst = (u32 *)cfg->caps;
if (format_change) {
/*
* Update the params to reflect that we have loaded 32-bit blob
* instead of the 16-bit.
* This information is going to be used by the caller to find
* matching copier format on the dai side.
*/
struct snd_mask *m;
m = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
snd_mask_none(m);
snd_mask_set_format(m, SNDRV_PCM_FORMAT_S32_LE);
}
return 0; return 0;
} }
#else #else
static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, static int
struct snd_pcm_hw_params *params, u32 dai_index, snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai,
u32 linktype, u8 dir, u32 **dst, u32 *len) bool single_format,
struct snd_pcm_hw_params *params, u32 dai_index,
u32 linktype, u8 dir, u32 **dst, u32 *len)
{ {
return 0; return 0;
} }
@ -1517,6 +1563,68 @@ bool sof_ipc4_copier_is_single_format(struct snd_sof_dev *sdev,
return true; return true;
} }
static int
sof_ipc4_prepare_dai_copier(struct snd_sof_dev *sdev, struct snd_sof_dai *dai,
struct snd_pcm_hw_params *params, int dir)
{
struct sof_ipc4_available_audio_format *available_fmt;
struct snd_pcm_hw_params dai_params = *params;
struct sof_ipc4_copier_data *copier_data;
struct sof_ipc4_copier *ipc4_copier;
bool single_format;
int ret;
ipc4_copier = dai->private;
copier_data = &ipc4_copier->data;
available_fmt = &ipc4_copier->available_fmt;
/*
* If the copier on the DAI side supports only single bit depth then
* this depth (format) should be used to look for the NHLT blob (if
* needed) and in case of capture this should be used for the input
* format lookup
*/
if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
single_format = sof_ipc4_copier_is_single_format(sdev,
available_fmt->output_pin_fmts,
available_fmt->num_output_formats);
/* Update the dai_params with the only supported format */
if (single_format) {
ret = sof_ipc4_update_hw_params(sdev, &dai_params,
&available_fmt->output_pin_fmts[0].audio_fmt,
BIT(SNDRV_PCM_HW_PARAM_FORMAT));
if (ret)
return ret;
}
} else {
single_format = sof_ipc4_copier_is_single_format(sdev,
available_fmt->input_pin_fmts,
available_fmt->num_input_formats);
/* Update the dai_params with the only supported format */
if (single_format) {
ret = sof_ipc4_update_hw_params(sdev, &dai_params,
&available_fmt->input_pin_fmts[0].audio_fmt,
BIT(SNDRV_PCM_HW_PARAM_FORMAT));
if (ret)
return ret;
}
}
ret = snd_sof_get_nhlt_endpoint_data(sdev, dai, single_format,
&dai_params,
ipc4_copier->dai_index,
ipc4_copier->dai_type, dir,
&ipc4_copier->copier_config,
&copier_data->gtw_cfg.config_length);
/* Update the params to reflect the changes made in this function */
if (!ret)
*params = dai_params;
return ret;
}
static int static int
sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
struct snd_pcm_hw_params *fe_params, struct snd_pcm_hw_params *fe_params,
@ -1527,7 +1635,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
struct snd_soc_component *scomp = swidget->scomp; struct snd_soc_component *scomp = swidget->scomp;
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct sof_ipc4_copier_data *copier_data; struct sof_ipc4_copier_data *copier_data;
struct snd_pcm_hw_params *ref_params; struct snd_pcm_hw_params ref_params;
struct sof_ipc4_copier *ipc4_copier; struct sof_ipc4_copier *ipc4_copier;
struct snd_sof_dai *dai; struct snd_sof_dai *dai;
u32 gtw_cfg_config_length; u32 gtw_cfg_config_length;
@ -1605,9 +1713,9 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
* for capture. * for capture.
*/ */
if (dir == SNDRV_PCM_STREAM_PLAYBACK) if (dir == SNDRV_PCM_STREAM_PLAYBACK)
ref_params = fe_params; ref_params = *fe_params;
else else
ref_params = pipeline_params; ref_params = *pipeline_params;
copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK; copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
copier_data->gtw_cfg.node_id |= copier_data->gtw_cfg.node_id |=
@ -1633,23 +1741,25 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
available_fmt = &ipc4_copier->available_fmt; available_fmt = &ipc4_copier->available_fmt;
/* /*
* When there is format conversion within a pipeline, the number of supported * Use the fe_params as a base for the copier configuration.
* output formats is typically limited to just 1 for the DAI copiers. But when there * The ref_params might get updated to reflect what format is
* is no format conversion, the DAI copiers input format must match that of the * supported by the copier on the DAI side.
* FE hw_params for capture and the pipeline params for playback. *
* In case of capture the ref_params returned will be used to
* find the input configuration of the copier.
*/ */
if (dir == SNDRV_PCM_STREAM_PLAYBACK) ref_params = *fe_params;
ref_params = pipeline_params; ret = sof_ipc4_prepare_dai_copier(sdev, dai, &ref_params, dir);
else
ref_params = fe_params;
ret = snd_sof_get_nhlt_endpoint_data(sdev, dai, fe_params, ipc4_copier->dai_index,
ipc4_copier->dai_type, dir,
&ipc4_copier->copier_config,
&copier_data->gtw_cfg.config_length);
if (ret < 0) if (ret < 0)
return ret; return ret;
/*
* For playback the pipeline_params needs to be used to find the
* input configuration of the copier.
*/
if (dir == SNDRV_PCM_STREAM_PLAYBACK)
ref_params = *pipeline_params;
break; break;
} }
case snd_soc_dapm_buffer: case snd_soc_dapm_buffer:
@ -1657,7 +1767,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
ipc4_copier = (struct sof_ipc4_copier *)swidget->private; ipc4_copier = (struct sof_ipc4_copier *)swidget->private;
copier_data = &ipc4_copier->data; copier_data = &ipc4_copier->data;
available_fmt = &ipc4_copier->available_fmt; available_fmt = &ipc4_copier->available_fmt;
ref_params = pipeline_params; ref_params = *pipeline_params;
break; break;
} }
@ -1668,8 +1778,8 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
} }
/* set input and output audio formats */ /* set input and output audio formats */
ret = sof_ipc4_init_input_audio_fmt(sdev, swidget, &copier_data->base_config, ref_params, ret = sof_ipc4_init_input_audio_fmt(sdev, swidget, &copier_data->base_config,
available_fmt); &ref_params, available_fmt);
if (ret < 0) if (ret < 0)
return ret; return ret;