From 7dc06d5feee7d72fb1d3415b58f492f2ec53a564 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Fri, 19 Jan 2024 15:26:23 +0800 Subject: [PATCH 1/7] Revert "ASoC: SOF: Intel: hda-dai-ops: reset device count for SoundWire DAIs" This reverts commit 699e146d9ebf42ee2a5d4e4e28f7a49c4aef0105. Don't reset device_count as we will use the multi-gateway firmware configuration. Signed-off-by: Bard Liao --- sound/soc/sof/intel/hda-dai-ops.c | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/sound/soc/sof/intel/hda-dai-ops.c b/sound/soc/sof/intel/hda-dai-ops.c index e2da955ea7f526..fcd6023d8be991 100644 --- a/sound/soc/sof/intel/hda-dai-ops.c +++ b/sound/soc/sof/intel/hda-dai-ops.c @@ -454,28 +454,6 @@ static int hda_ipc4_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *c return ret; } -static struct hdac_ext_stream *sdw_hda_ipc4_get_hext_stream(struct snd_sof_dev *sdev, - struct snd_soc_dai *cpu_dai, - struct snd_pcm_substream *substream) -{ - struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream); - struct snd_sof_widget *swidget = w->dobj.private; - struct snd_sof_dai *dai = swidget->private; - struct sof_ipc4_copier *ipc4_copier = dai->private; - struct sof_ipc4_alh_configuration_blob *blob; - - blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config; - - /* - * Starting with ACE_2_0, re-setting the device_count is mandatory to avoid using - * the multi-gateway firmware configuration. The DMA hardware can take care of - * multiple links without needing any firmware assistance - */ - blob->alh_cfg.device_count = 1; - - return hda_ipc4_get_hext_stream(sdev, cpu_dai, substream); -} - static const struct hda_dai_widget_dma_ops hda_ipc4_dma_ops = { .get_hext_stream = hda_ipc4_get_hext_stream, .assign_hext_stream = hda_assign_hext_stream, @@ -517,7 +495,7 @@ static const struct hda_dai_widget_dma_ops dmic_ipc4_dma_ops = { }; static const struct hda_dai_widget_dma_ops sdw_ipc4_dma_ops = { - .get_hext_stream = sdw_hda_ipc4_get_hext_stream, + .get_hext_stream = hda_ipc4_get_hext_stream, .assign_hext_stream = hda_assign_hext_stream, .release_hext_stream = hda_release_hext_stream, .setup_hext_stream = hda_setup_hext_stream, From c6235d94bf112891cf26ef677e5d2a4f0372ad4e Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Fri, 29 Dec 2023 19:45:20 +0800 Subject: [PATCH 2/7] ASoC: SOF: make dma_config_tlv be an array Each stream needs a dma_config_tlv. We will handle multi dma_config_tlv in the follow up commits. Signed-off-by: Bard Liao --- sound/soc/sof/intel/hda-dai.c | 2 +- sound/soc/sof/ipc4-topology.c | 25 ++++++++++++------------- sound/soc/sof/ipc4-topology.h | 2 +- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index 043888bdf0a627..ae42ea01b01003 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -393,7 +393,7 @@ static int non_hda_dai_hw_params(struct snd_pcm_substream *substream, /* configure TLV */ ipc4_copier = widget_to_copier(w); - dma_config_tlv = &ipc4_copier->dma_config_tlv; + dma_config_tlv = &ipc4_copier->dma_config_tlv[0]; dma_config_tlv->type = SOF_IPC4_GTW_DMA_CONFIG_ID; /* dma_config_priv_size is zero */ dma_config_tlv->length = sizeof(dma_config_tlv->dma_config); diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index d8c7fbe946ef95..2637abe9ff5d28 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -1463,6 +1463,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, u32 deep_buffer_dma_ms = 0; int output_fmt_index; bool single_output_format; + int i; dev_dbg(sdev->dev, "copier %s, type %d", swidget->widget->name, swidget->id); @@ -1688,7 +1689,6 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, u32 ch_map; u32 step; u32 mask; - int i; blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config; @@ -1798,19 +1798,18 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, gtw_cfg_config_length = copier_data->gtw_cfg.config_length * 4; ipc_size = sizeof(*copier_data) + gtw_cfg_config_length; - if (ipc4_copier->dma_config_tlv.type == SOF_IPC4_GTW_DMA_CONFIG_ID && - ipc4_copier->dma_config_tlv.length) { - dma_config_tlv_size = sizeof(ipc4_copier->dma_config_tlv) + - ipc4_copier->dma_config_tlv.dma_config.dma_priv_config_size; - - /* paranoia check on TLV size/length */ - if (dma_config_tlv_size != ipc4_copier->dma_config_tlv.length + - sizeof(uint32_t) * 2) { - dev_err(sdev->dev, "Invalid configuration, TLV size %d length %d\n", - dma_config_tlv_size, ipc4_copier->dma_config_tlv.length); - return -EINVAL; - } + dma_config_tlv_size = 0; + for (i = 0; i < SOF_IPC4_DMA_DEVICE_MAX_COUNT; i++) { + if (ipc4_copier->dma_config_tlv[i].type != SOF_IPC4_GTW_DMA_CONFIG_ID) + continue; + dma_config_tlv_size += ipc4_copier->dma_config_tlv[i].length; + dma_config_tlv_size += + ipc4_copier->dma_config_tlv[i].dma_config.dma_priv_config_size; + dma_config_tlv_size += (sizeof(ipc4_copier->dma_config_tlv[i]) - + sizeof(ipc4_copier->dma_config_tlv[i].dma_config)); + } + if (dma_config_tlv_size) { ipc_size += dma_config_tlv_size; /* we also need to increase the size at the gtw level */ diff --git a/sound/soc/sof/ipc4-topology.h b/sound/soc/sof/ipc4-topology.h index dce174a190ddc6..aa5122c3721d3a 100644 --- a/sound/soc/sof/ipc4-topology.h +++ b/sound/soc/sof/ipc4-topology.h @@ -313,7 +313,7 @@ struct sof_ipc4_copier { struct sof_ipc4_gtw_attributes *gtw_attr; u32 dai_type; int dai_index; - struct sof_ipc4_dma_config_tlv dma_config_tlv; + struct sof_ipc4_dma_config_tlv dma_config_tlv[SOF_IPC4_DMA_DEVICE_MAX_COUNT]; }; /** From 24170d145c9540cb420e1a2db3466cabfd0df662 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Fri, 26 Jan 2024 18:08:44 +0800 Subject: [PATCH 3/7] ASoC: SOF: Intel: hda-dai: set lowest N bits in ch_mask We always use the lowest N channels of stream. So, set ch_mask to GENMASK(params_channels(params) - 1, 0). Signed-off-by: Bard Liao --- sound/soc/sof/intel/hda-dai.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index ae42ea01b01003..85c0f9ad9ae798 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -442,7 +442,6 @@ int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream, 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; @@ -450,7 +449,6 @@ int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream, int cpu_dai_id; int ch_mask; int ret; - int j; ret = non_hda_dai_hw_params(substream, params, cpu_dai); if (ret < 0) { @@ -480,11 +478,7 @@ int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream, 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; - } + ch_mask = GENMASK(params_channels(params) - 1, 0); ret = hdac_bus_eml_sdw_map_stream_ch(sof_to_bus(sdev), link_id, cpu_dai->id, ch_mask, From 590f70d48610f208d28eee97480e59bf1bd7a532 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Fri, 29 Dec 2023 20:24:33 +0800 Subject: [PATCH 4/7] ASoC: SOF: Intel: hda-dai: set dma_stream_channel_map device sof_ipc4_dma_config_tlv{} is required for ACE2.x. The patch follow the convention to set the dma_stream_channel_map.mapping device as "link_id << 8 | pdi_id". And the mapping in sof_ipc4_alh_configuration_blob{} should be the same as dma_stream_channel_map.mapping in sof_ipc4_dma_config{}. The purposes of device id is to map DMA tlv. Signed-off-by: Bard Liao --- sound/soc/sof/intel/hda-dai.c | 36 +++++++++++++++++++++++++++++++++-- sound/soc/sof/ipc4-topology.c | 13 +++++++++++++ 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index 85c0f9ad9ae798..288cfa894b47e9 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -347,6 +347,7 @@ static int non_hda_dai_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { 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); struct sof_ipc4_dma_config_tlv *dma_config_tlv; const struct hda_dai_widget_dma_ops *ops; struct sof_ipc4_dma_config *dma_config; @@ -354,6 +355,8 @@ static int non_hda_dai_hw_params(struct snd_pcm_substream *substream, struct hdac_ext_stream *hext_stream; struct hdac_stream *hstream; struct snd_sof_dev *sdev; + struct snd_soc_dai *dai; + int cpu_dai_id; int stream_id; int ret; @@ -393,7 +396,12 @@ static int non_hda_dai_hw_params(struct snd_pcm_substream *substream, /* configure TLV */ ipc4_copier = widget_to_copier(w); - dma_config_tlv = &ipc4_copier->dma_config_tlv[0]; + for_each_rtd_cpu_dais(rtd, cpu_dai_id, dai) { + if (dai == cpu_dai) + break; + } + + dma_config_tlv = &ipc4_copier->dma_config_tlv[cpu_dai_id]; dma_config_tlv->type = SOF_IPC4_GTW_DMA_CONFIG_ID; /* dma_config_priv_size is zero */ dma_config_tlv->length = sizeof(dma_config_tlv->dma_config); @@ -404,7 +412,11 @@ static int non_hda_dai_hw_params(struct snd_pcm_substream *substream, dma_config->pre_allocated_by_host = 1; dma_config->dma_channel_id = stream_id - 1; dma_config->stream_id = stream_id; - dma_config->dma_stream_channel_map.device_count = 0; /* mapping not used */ + /* + * Currently we use a DMA for each device in ALH blob. The device will + * be copied in sof_ipc4_prepare_copier_module. + */ + dma_config->dma_stream_channel_map.device_count = 1; dma_config->dma_priv_config_size = 0; skip_tlv: @@ -441,7 +453,10 @@ int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream, { 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); + struct sof_ipc4_dma_config_tlv *dma_config_tlv; const struct hda_dai_widget_dma_ops *ops; + struct sof_ipc4_dma_config *dma_config; + struct sof_ipc4_copier *ipc4_copier; struct hdac_ext_stream *hext_stream; struct snd_soc_dai *dai; struct snd_sof_dev *sdev; @@ -449,6 +464,7 @@ int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream, int cpu_dai_id; int ch_mask; int ret; + int i; ret = non_hda_dai_hw_params(substream, params, cpu_dai); if (ret < 0) { @@ -490,6 +506,22 @@ int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream, return ret; } + ipc4_copier = widget_to_copier(w); + dma_config_tlv = &ipc4_copier->dma_config_tlv[cpu_dai_id]; + dma_config = &dma_config_tlv->dma_config; + dma_config->dma_stream_channel_map.mapping[0].device = link_id << 8 | cpu_dai->id; + dma_config->dma_stream_channel_map.mapping[0].channel_mask = ch_mask; + + /* + * copy the dma_config_tlv to all ipc4_copier in the same link. Because only one copier + * will be handled in sof_ipc4_prepare_copier_module. + */ + for_each_rtd_cpu_dais(rtd, i, dai) { + w = snd_soc_dai_get_widget(dai, substream->stream); + ipc4_copier = widget_to_copier(w); + memcpy(&ipc4_copier->dma_config_tlv[cpu_dai_id], dma_config_tlv, + sizeof(*dma_config_tlv)); + } return 0; } EXPORT_SYMBOL_NS(sdw_hda_dai_hw_params, SND_SOC_SOF_INTEL_HDA_COMMON); diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 2637abe9ff5d28..ebed00b1368efb 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -1681,6 +1681,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, */ if (ipc4_copier->dai_type == SOF_DAI_INTEL_ALH) { struct sof_ipc4_alh_configuration_blob *blob; + struct sof_ipc4_dma_config *dma_config; struct sof_ipc4_copier_data *alh_data; struct sof_ipc4_copier *alh_copier; struct snd_sof_widget *w; @@ -1720,6 +1721,18 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, alh_copier = (struct sof_ipc4_copier *)dai->private; alh_data = &alh_copier->data; blob->alh_cfg.mapping[i].device = alh_data->gtw_cfg.node_id; + + /* + * The mapping[i] device in ALH blob should be the same as the + * dma_config_tlv[i] mapping device if a dma_config_tlv is present. + * The device id will be used for DMA tlv mapping purposes. + */ + if (ipc4_copier->dma_config_tlv[i].length) { + dma_config = &ipc4_copier->dma_config_tlv[i].dma_config; + blob->alh_cfg.mapping[i].device = + dma_config->dma_stream_channel_map.mapping[0].device; + } + /* * Set the same channel mask for playback as the audio data is * duplicated for all speakers. For capture, split the channels From 462c0a72922042f34ab77982ef26386bae057854 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 29 Jan 2024 20:23:47 +0800 Subject: [PATCH 5/7] Revert "ASoC: SOF: Intel: hda-dai-ops: only allocate/release streams for first CPU DAI" This reverts commit f8ba62ac863c33fc0d8ac3f1270985c2b77f4377. The SoundWire aggregated solution was to use one DMA on multiple links. But, the solution changed to use one DMA for each link. It means that we should assign HDaudio stream_tag for each cpu_dai. Signed-off-by: Bard Liao --- sound/soc/sof/intel/hda-dai-ops.c | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/sound/soc/sof/intel/hda-dai-ops.c b/sound/soc/sof/intel/hda-dai-ops.c index fcd6023d8be991..b96b36ba88ad08 100644 --- a/sound/soc/sof/intel/hda-dai-ops.c +++ b/sound/soc/sof/intel/hda-dai-ops.c @@ -145,17 +145,9 @@ static struct hdac_ext_stream *hda_assign_hext_stream(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai *dai; struct hdac_ext_stream *hext_stream; - /* only allocate a stream_tag for the first DAI in the dailink */ - dai = snd_soc_rtd_to_cpu(rtd, 0); - if (dai == cpu_dai) - hext_stream = hda_link_stream_assign(sof_to_bus(sdev), substream); - else - hext_stream = snd_soc_dai_get_dma_data(dai, substream); - + hext_stream = hda_link_stream_assign(sof_to_bus(sdev), substream); if (!hext_stream) return NULL; @@ -168,14 +160,9 @@ static void hda_release_hext_stream(struct snd_sof_dev *sdev, struct snd_soc_dai struct snd_pcm_substream *substream) { struct hdac_ext_stream *hext_stream = hda_get_hext_stream(sdev, cpu_dai, substream); - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai *dai; - /* only release a stream_tag for the first DAI in the dailink */ - dai = snd_soc_rtd_to_cpu(rtd, 0); - if (dai == cpu_dai) - snd_hdac_ext_stream_release(hext_stream, HDAC_EXT_STREAM_TYPE_LINK); snd_soc_dai_set_dma_data(cpu_dai, substream, NULL); + snd_hdac_ext_stream_release(hext_stream, HDAC_EXT_STREAM_TYPE_LINK); } static void hda_setup_hext_stream(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream, From 21bb3b97d6d08c2bdce94ba87245db42a4eff31c Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Tue, 19 Dec 2023 19:16:25 +0800 Subject: [PATCH 6/7] ASoC: SOF: ipc4-topology: set config_length based on device_count Set ipc4_copier->data.gtw_cfg.config_length dynamically based on blob->alh_cfg.device_count to align with the other OS. Signed-off-by: Bard Liao --- sound/soc/sof/ipc4-topology.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index ebed00b1368efb..55875ec7f80a05 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -601,7 +601,11 @@ static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget) } ipc4_copier->copier_config = (uint32_t *)blob; - ipc4_copier->data.gtw_cfg.config_length = sizeof(*blob) >> 2; + /* set data.gtw_cfg.config_length based on device_count */ + ipc4_copier->data.gtw_cfg.config_length = (sizeof(blob->gw_attr) + + sizeof(blob->alh_cfg.device_count) + + sizeof(*blob->alh_cfg.mapping) * + blob->alh_cfg.device_count) >> 2; break; } case SOF_DAI_INTEL_SSP: From 99493491993559d91c686cfe3999bd1cfbe6a9fd Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 29 Jan 2024 14:58:57 +0800 Subject: [PATCH 7/7] Revert "ASoC: SOF: Intel: hda-dai-ops: fix HDaudio link format" This reverts commit 7f9512a31dc2a3737f1a78ab410d4d2c6ca6b8b2. commit 7f9512a31dc2 ("ASoC: SOF: Intel: hda-dai-ops: fix HDaudio link format") added up all DAIs channels for SoundWire aggregation mode. That was correct because we used a DMA for all DAIs. But, it is not valid anymore after we use a DMA for each DAI. Signed-off-by: Bard Liao --- sound/soc/sof/intel/hda-dai-ops.c | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/sound/soc/sof/intel/hda-dai-ops.c b/sound/soc/sof/intel/hda-dai-ops.c index b96b36ba88ad08..01e5f0617ae5b9 100644 --- a/sound/soc/sof/intel/hda-dai-ops.c +++ b/sound/soc/sof/intel/hda-dai-ops.c @@ -226,34 +226,16 @@ static unsigned int generic_calc_stream_format(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai_link_ch_map *ch_maps; unsigned int format_val; unsigned int bits; - int num_channels; - u32 ch_mask = 0; - int i; - - /* - * if the multiple dais are handled by the same dailink, we may need to update the - * stream channel count - the params are modified in soc-pcm based on the ch_maps info - */ - for_each_link_ch_maps(rtd->dai_link, i, ch_maps) - ch_mask |= ch_maps->ch_mask; - - num_channels = ch_mask ? hweight_long(ch_mask) : params_channels(params); - - if (num_channels != params_channels(params)) - dev_dbg(sdev->dev, "configuring stream format for %d channels, params_channels was %d\n", - num_channels, params_channels(params)); bits = snd_hdac_stream_format_bits(params_format(params), SNDRV_PCM_SUBFORMAT_STD, params_physical_width(params)); - format_val = snd_hdac_stream_format(num_channels, bits, params_rate(params)); + format_val = snd_hdac_stream_format(params_channels(params), bits, params_rate(params)); dev_dbg(sdev->dev, "format_val=%#x, rate=%d, ch=%d, format=%d\n", format_val, - params_rate(params), num_channels, params_format(params)); + params_rate(params), params_channels(params), params_format(params)); return format_val; }