ASoC: SOF: Intel: hda-dai: fix channel map configuration for aggregated dailink

The existing code derives the channel map used to program the HDaudio
link DMA from the hw_params, but that is not quite right in the case
of aggregation. The code in soc-pcm.c splits the hw_params depending
on the codec_ch_map, and we need to reconstruct the channel-map to
insert the data in the right places.

This issue is seen only on amplifier feedback capture where the data
from the second amplifier was replaced by that of the first amplifier.

Note that the loop iterator of the macro for_each_rtd_cpu_dais() is
reused in a following loop. This is different to all existing usages
of that macro, hence the use of a boolean flag to avoid an access to
an uninitialized variable.

Fixes: 2960ee5c48 ("ASoC: SOF: Intel: hda-dai: add helpers for SoundWire callbacks")
Reviewed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Reviewed-by: Rander Wang <rander.wang@intel.com>
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Link: https://msgid.link/r/20240402151828.175002-2-pierre-louis.bossart@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Pierre-Louis Bossart 2024-04-02 10:18:12 -05:00 committed by Mark Brown
parent 2ae143fb3a
commit 831045513c
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0

View File

@ -439,10 +439,17 @@ int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream,
int link_id)
{
struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
const struct hda_dai_widget_dma_ops *ops;
struct snd_soc_dai_link_ch_map *ch_maps;
struct hdac_ext_stream *hext_stream;
struct snd_soc_dai *dai;
struct snd_sof_dev *sdev;
bool cpu_dai_found = false;
int cpu_dai_id;
int ch_mask;
int ret;
int j;
ret = non_hda_dai_hw_params(substream, params, cpu_dai);
if (ret < 0) {
@ -457,9 +464,29 @@ int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream,
if (!hext_stream)
return -ENODEV;
/* in the case of SoundWire we need to program the PCMSyCM registers */
/*
* in the case of SoundWire we need to program the PCMSyCM registers. In case
* of aggregated devices, we need to define the channel mask for each sublink
* by reconstructing the split done in soc-pcm.c
*/
for_each_rtd_cpu_dais(rtd, cpu_dai_id, dai) {
if (dai == cpu_dai) {
cpu_dai_found = true;
break;
}
}
if (!cpu_dai_found)
return -ENODEV;
ch_mask = 0;
for_each_link_ch_maps(rtd->dai_link, j, ch_maps) {
if (ch_maps->cpu == cpu_dai_id)
ch_mask |= ch_maps->ch_mask;
}
ret = hdac_bus_eml_sdw_map_stream_ch(sof_to_bus(sdev), link_id, cpu_dai->id,
GENMASK(params_channels(params) - 1, 0),
ch_mask,
hdac_stream(hext_stream)->stream_tag,
substream->stream);
if (ret < 0) {