From: Peter Ujfalusi Date: Thu, 19 Jun 2025 10:26:57 +0000 (+0300) Subject: ASoC: SOF: ipc4-pcm: Look for best matching hw_config for SSP X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8a07944a77e962b625c582696497964c393a3489;p=thirdparty%2Fkernel%2Flinux.git ASoC: SOF: ipc4-pcm: Look for best matching hw_config for SSP Instead of just looking for a hw_config with matching rate only it sounds better to try to find the best matching configuration. If we have multiple hw_configurations with the same rate, but each with different format for example then we have been picking the first config with the matching rate, which can be a problem and it wil depend on how the configs are ordered. Instead we should be trying to find the best match out of the configs 1. rate + format + channels are matching 2. rate + format are matching 3. rate matching Signed-off-by: Peter Ujfalusi Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Link: https://patch.msgid.link/20250619102657.12109-1-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c index 8eee3e1aadf93..a5b365ab19454 100644 --- a/sound/soc/sof/ipc4-pcm.c +++ b/sound/soc/sof/ipc4-pcm.c @@ -557,12 +557,15 @@ static int sof_ipc4_pcm_hw_free(struct snd_soc_component *component, return sof_ipc4_trigger_pipelines(component, substream, SOF_IPC4_PIPE_RESET, 0); } -static void ipc4_ssp_dai_config_pcm_params_match(struct snd_sof_dev *sdev, const char *link_name, - struct snd_pcm_hw_params *params) +static int ipc4_ssp_dai_config_pcm_params_match(struct snd_sof_dev *sdev, + const char *link_name, + struct snd_pcm_hw_params *params) { struct snd_sof_dai_link *slink; struct snd_sof_dai *dai; bool dai_link_found = false; + int current_config = -1; + bool partial_match; int i; list_for_each_entry(slink, &sdev->dai_link_list, list) { @@ -573,19 +576,50 @@ static void ipc4_ssp_dai_config_pcm_params_match(struct snd_sof_dev *sdev, const } if (!dai_link_found) - return; + return 0; + /* + * Find the first best matching hardware config: + * rate + format + channels are matching + * rate + channel are matching + * + * The copier cannot do rate and/or channel conversion. + */ for (i = 0; i < slink->num_hw_configs; i++) { struct snd_soc_tplg_hw_config *hw_config = &slink->hw_configs[i]; - if (params_rate(params) == le32_to_cpu(hw_config->fsync_rate)) { - /* set current config for all DAI's with matching name */ - list_for_each_entry(dai, &sdev->dai_list, list) - if (!strcmp(slink->link->name, dai->name)) - dai->current_config = le32_to_cpu(hw_config->id); + if (params_rate(params) == le32_to_cpu(hw_config->fsync_rate) && + params_width(params) == le32_to_cpu(hw_config->tdm_slot_width) && + params_channels(params) == le32_to_cpu(hw_config->tdm_slots)) { + current_config = le32_to_cpu(hw_config->id); + partial_match = false; + /* best match found */ break; + } else if (current_config < 0 && + params_rate(params) == le32_to_cpu(hw_config->fsync_rate) && + params_channels(params) == le32_to_cpu(hw_config->tdm_slots)) { + current_config = le32_to_cpu(hw_config->id); + partial_match = true; + /* keep looking for better match */ } } + + if (current_config < 0) { + dev_err(sdev->dev, + "%s: No suitable hw_config found for %s (num_hw_configs: %d)\n", + __func__, slink->link->name, slink->num_hw_configs); + return -EINVAL; + } + + dev_dbg(sdev->dev, + "hw_config for %s: %d (num_hw_configs: %d) with %s match\n", + slink->link->name, current_config, slink->num_hw_configs, + partial_match ? "partial" : "full"); + list_for_each_entry(dai, &sdev->dai_list, list) + if (!strcmp(slink->link->name, dai->name)) + dai->current_config = current_config; + + return 0; } /* @@ -728,13 +762,10 @@ static int sof_ipc4_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, break; } - switch (ipc4_copier->dai_type) { - case SOF_DAI_INTEL_SSP: - ipc4_ssp_dai_config_pcm_params_match(sdev, (char *)rtd->dai_link->name, params); - break; - default: - break; - } + if (ipc4_copier->dai_type == SOF_DAI_INTEL_SSP) + return ipc4_ssp_dai_config_pcm_params_match(sdev, + (char *)rtd->dai_link->name, + params); return 0; }