Commit 83104551 authored by Pierre-Louis Bossart's avatar Pierre-Louis Bossart Committed by Mark Brown

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: 2960ee5c ("ASoC: SOF: Intel: hda-dai: add helpers for SoundWire callbacks")
Reviewed-by: default avatarBard Liao <yung-chuan.liao@linux.intel.com>
Reviewed-by: default avatarRander Wang <rander.wang@intel.com>
Signed-off-by: default avatarPierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Link: https://msgid.link/r/20240402151828.175002-2-pierre-louis.bossart@linux.intel.comSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent 2ae143fb
...@@ -439,10 +439,17 @@ int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream, ...@@ -439,10 +439,17 @@ int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream,
int link_id) int link_id)
{ {
struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream); 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; const struct hda_dai_widget_dma_ops *ops;
struct snd_soc_dai_link_ch_map *ch_maps;
struct hdac_ext_stream *hext_stream; struct hdac_ext_stream *hext_stream;
struct snd_soc_dai *dai;
struct snd_sof_dev *sdev; struct snd_sof_dev *sdev;
bool cpu_dai_found = false;
int cpu_dai_id;
int ch_mask;
int ret; int ret;
int j;
ret = non_hda_dai_hw_params(substream, params, cpu_dai); ret = non_hda_dai_hw_params(substream, params, cpu_dai);
if (ret < 0) { if (ret < 0) {
...@@ -457,9 +464,29 @@ int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream, ...@@ -457,9 +464,29 @@ int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream,
if (!hext_stream) if (!hext_stream)
return -ENODEV; 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, 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, hdac_stream(hext_stream)->stream_tag,
substream->stream); substream->stream);
if (ret < 0) { if (ret < 0) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment