From e9b8b2a3a3e3d62c082caaa975312257ca492131 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Thu, 23 Oct 2025 13:25:40 +0800 Subject: [PATCH 01/14] ASoC: SOF: Intel: add hda_dsp_stream_pair_get/put helpers Currently, hda_dsp_stream_get/put are used to get/put the host dma. However, we may want to use a hda stream that both host and link dma are available. Add helper to find the hda stream and reserve/release it. Signed-off-by: Bard Liao --- sound/soc/sof/intel/hda-stream.c | 41 +++++++++++++++++++++++++++++--- sound/soc/sof/intel/hda.h | 3 +++ 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 9c3b3a9aaf83c9..85da1eb8f742e1 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -210,8 +210,8 @@ int hda_dsp_stream_spib_config(struct snd_sof_dev *sdev, } /* get next unused stream */ -struct hdac_ext_stream * -hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction, u32 flags) +static struct hdac_ext_stream * +_hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction, u32 flags, bool pair) { const struct sof_intel_dsp_desc *chip_info = get_chip_info(sdev->pdata); struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; @@ -233,7 +233,14 @@ hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction, u32 flags) if (hda_stream->host_reserved) continue; + if (pair && hext_stream->link_locked) + continue; + s->opened = true; + + if (pair) + hext_stream->link_locked = true; + break; } } @@ -264,14 +271,27 @@ hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction, u32 flags) return hext_stream; } +struct hdac_ext_stream * +hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction, u32 flags) +{ + return _hda_dsp_stream_get(sdev, direction, flags, false); +} + +struct hdac_ext_stream * +hda_dsp_stream_pair_get(struct snd_sof_dev *sdev, int direction, u32 flags) +{ + return _hda_dsp_stream_get(sdev, direction, flags, true); +} + /* free a stream */ -int hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int stream_tag) +static int _hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int stream_tag, bool pair) { const struct sof_intel_dsp_desc *chip_info = get_chip_info(sdev->pdata); struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; struct hdac_bus *bus = sof_to_bus(sdev); struct sof_intel_hda_stream *hda_stream; struct hdac_ext_stream *hext_stream; + struct hdac_ext_stream *link_stream; struct hdac_stream *s; bool dmi_l1_enable = true; bool found = false; @@ -292,6 +312,8 @@ int hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int stream_tag) if (s->direction == direction && s->stream_tag == stream_tag) { s->opened = false; found = true; + if (pair) + link_stream = hext_stream; } else if (!(hda_stream->flags & SOF_HDA_STREAM_DMI_L1_COMPATIBLE)) { dmi_l1_enable = false; } @@ -312,9 +334,22 @@ int hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int stream_tag) return -ENODEV; } + if (pair) + snd_hdac_ext_stream_release(link_stream, HDAC_EXT_STREAM_TYPE_LINK); + return 0; } +int hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int stream_tag) +{ + return _hda_dsp_stream_put(sdev, direction, stream_tag, false); +} + +int hda_dsp_stream_pair_put(struct snd_sof_dev *sdev, int direction, int stream_tag) +{ + return _hda_dsp_stream_put(sdev, direction, stream_tag, true); +} + static int hda_dsp_stream_reset(struct snd_sof_dev *sdev, struct hdac_stream *hstream) { int sd_offset = SOF_STREAM_SD_OFFSET(hstream); diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 562fe8be79c1e3..0b6340bba14603 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -694,7 +694,10 @@ u64 hda_dsp_get_stream_ldp(struct snd_sof_dev *sdev, struct hdac_ext_stream * hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction, u32 flags); +struct hdac_ext_stream * + hda_dsp_stream_pair_get(struct snd_sof_dev *sdev, int direction, u32 flags); int hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int stream_tag); +int hda_dsp_stream_pair_put(struct snd_sof_dev *sdev, int direction, int stream_tag); int hda_dsp_stream_spib_config(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream, int enable, u32 size); From 077445f84e58c6f421f59264419d09759d4f4d4a Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Tue, 4 Nov 2025 10:50:35 +0800 Subject: [PATCH 02/14] ASoC: SOF: Intel: add hda_dma_prepare/cleanup helpers SoundWire BPT stream needs to use link and host DMAs. Thus we need helpers to prepare and cleanup the link and host DMAs. Currently the SoundWire BPT stream uses hda_cl_prepare/cleanup helpers. It works fine because we assume the SwoundWire BPT will not run with audio streams simultaneously. The new helpers are copied from hda_cl_prepare/cleanup and add a flag to reserve the paired host and link DMAs. The new helpers will be used by both code loader and SoundWire BPT. Signed-off-by: Bard Liao --- sound/soc/sof/intel/hda-loader.c | 94 +------------------------ sound/soc/sof/intel/hda-stream.c | 116 +++++++++++++++++++++++++++++++ sound/soc/sof/intel/hda.h | 8 +++ 3 files changed, 127 insertions(+), 91 deletions(-) diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 2cc11d8b0f7080..995c8016bbcf06 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -53,65 +53,8 @@ hda_cl_prepare(struct device *dev, unsigned int format, unsigned int size, struct snd_dma_buffer *dmab, bool persistent_buffer, int direction, bool is_iccmax) { - struct snd_sof_dev *sdev = dev_get_drvdata(dev); - struct hdac_ext_stream *hext_stream; - struct hdac_stream *hstream; - int ret; - - hext_stream = hda_dsp_stream_get(sdev, direction, 0); - - if (!hext_stream) { - dev_err(sdev->dev, "error: no stream available\n"); - return ERR_PTR(-ENODEV); - } - hstream = &hext_stream->hstream; - hstream->substream = NULL; - - /* - * Allocate DMA buffer if it is temporary or if the buffer is intended - * to be persistent but not yet allocated. - * We cannot rely solely on !dmab->area as caller might use a struct on - * stack (when it is temporary) without clearing it to 0. - */ - if (!persistent_buffer || !dmab->area) { - ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, dev, size, dmab); - if (ret < 0) { - dev_err(sdev->dev, "%s: memory alloc failed: %d\n", - __func__, ret); - goto out_put; - } - } - - hstream->period_bytes = 0;/* initialize period_bytes */ - hstream->format_val = format; - hstream->bufsize = size; - - if (is_iccmax) { - ret = hda_dsp_iccmax_stream_hw_params(sdev, hext_stream, dmab, NULL); - if (ret < 0) { - dev_err(sdev->dev, "error: iccmax stream prepare failed: %d\n", ret); - goto out_free; - } - } else { - ret = hda_dsp_stream_hw_params(sdev, hext_stream, dmab, NULL); - if (ret < 0) { - dev_err(sdev->dev, "error: hdac prepare failed: %d\n", ret); - goto out_free; - } - hda_dsp_stream_spib_config(sdev, hext_stream, HDA_DSP_SPIB_ENABLE, size); - } - - return hext_stream; - -out_free: - snd_dma_free_pages(dmab); - dmab->area = NULL; - dmab->bytes = 0; - hstream->bufsize = 0; - hstream->format_val = 0; -out_put: - hda_dsp_stream_put(sdev, direction, hstream->stream_tag); - return ERR_PTR(ret); + return hda_dma_prepare(dev, format, size, dmab, persistent_buffer, + direction, is_iccmax, false); } EXPORT_SYMBOL_NS(hda_cl_prepare, "SND_SOC_SOF_INTEL_HDA_COMMON"); @@ -275,38 +218,7 @@ EXPORT_SYMBOL_NS(hda_cl_trigger, "SND_SOC_SOF_INTEL_HDA_COMMON"); int hda_cl_cleanup(struct device *dev, struct snd_dma_buffer *dmab, bool persistent_buffer, struct hdac_ext_stream *hext_stream) { - struct snd_sof_dev *sdev = dev_get_drvdata(dev); - struct hdac_stream *hstream = &hext_stream->hstream; - int sd_offset = SOF_STREAM_SD_OFFSET(hstream); - int ret = 0; - - if (hstream->direction == SNDRV_PCM_STREAM_PLAYBACK) - ret = hda_dsp_stream_spib_config(sdev, hext_stream, HDA_DSP_SPIB_DISABLE, 0); - else - snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset, - SOF_HDA_SD_CTL_DMA_START, 0); - - hda_dsp_stream_put(sdev, hstream->direction, hstream->stream_tag); - hstream->running = 0; - hstream->substream = NULL; - - /* reset BDL address */ - snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, - sd_offset + SOF_HDA_ADSP_REG_SD_BDLPL, 0); - snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, - sd_offset + SOF_HDA_ADSP_REG_SD_BDLPU, 0); - - snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, sd_offset, 0); - - if (!persistent_buffer) { - snd_dma_free_pages(dmab); - dmab->area = NULL; - dmab->bytes = 0; - hstream->bufsize = 0; - hstream->format_val = 0; - } - - return ret; + return hda_dma_cleanup(dev, dmab, persistent_buffer, hext_stream, false); } EXPORT_SYMBOL_NS(hda_cl_cleanup, "SND_SOC_SOF_INTEL_HDA_COMMON"); diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 85da1eb8f742e1..8eb5943a16c025 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -1246,3 +1246,119 @@ u64 hda_dsp_get_stream_ldp(struct snd_sof_dev *sdev, return ((u64)ldp_u << 32) | ldp_l; } EXPORT_SYMBOL_NS(hda_dsp_get_stream_ldp, "SND_SOC_SOF_INTEL_HDA_COMMON"); + +struct hdac_ext_stream * +hda_dma_prepare(struct device *dev, unsigned int format, unsigned int size, + struct snd_dma_buffer *dmab, bool persistent_buffer, int direction, + bool is_iccmax, bool pair) +{ + struct snd_sof_dev *sdev = dev_get_drvdata(dev); + struct hdac_ext_stream *hext_stream; + struct hdac_stream *hstream; + int ret; + + if (pair) + hext_stream = hda_dsp_stream_pair_get(sdev, direction, 0); + else + hext_stream = hda_dsp_stream_get(sdev, direction, 0); + + if (!hext_stream) { + dev_err(sdev->dev, "%s: no stream available\n", __func__); + return ERR_PTR(-ENODEV); + } + hstream = &hext_stream->hstream; + hstream->substream = NULL; + + /* + * Allocate DMA buffer if it is temporary or if the buffer is intended + * to be persistent but not yet allocated. + * We cannot rely solely on !dmab->area as caller might use a struct on + * stack (when it is temporary) without clearing it to 0. + */ + if (!persistent_buffer || !dmab->area) { + ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, dev, size, dmab); + if (ret < 0) { + dev_err(sdev->dev, "%s: memory alloc failed: %d\n", + __func__, ret); + goto out_put; + } + } + + hstream->period_bytes = 0; /* initialize period_bytes */ + hstream->format_val = format; + hstream->bufsize = size; + + if (is_iccmax) { + ret = hda_dsp_iccmax_stream_hw_params(sdev, hext_stream, dmab, NULL); + if (ret < 0) { + dev_err(sdev->dev, "%s: iccmax stream prepare failed: %d\n", + __func__, ret); + goto out_free; + } + } else { + ret = hda_dsp_stream_hw_params(sdev, hext_stream, dmab, NULL); + if (ret < 0) { + dev_err(sdev->dev, "%s: hdac prepare failed: %d\n", __func__, ret); + goto out_free; + } + hda_dsp_stream_spib_config(sdev, hext_stream, HDA_DSP_SPIB_ENABLE, size); + } + + return hext_stream; + +out_free: + snd_dma_free_pages(dmab); + dmab->area = NULL; + dmab->bytes = 0; + hstream->bufsize = 0; + hstream->format_val = 0; +out_put: + if (pair) + hda_dsp_stream_pair_put(sdev, direction, hstream->stream_tag); + else + hda_dsp_stream_put(sdev, direction, hstream->stream_tag); + return ERR_PTR(ret); +} +EXPORT_SYMBOL_NS(hda_dma_prepare, "SND_SOC_SOF_INTEL_HDA_COMMON"); + +int hda_dma_cleanup(struct device *dev, struct snd_dma_buffer *dmab, + bool persistent_buffer, struct hdac_ext_stream *hext_stream, bool pair) +{ + struct snd_sof_dev *sdev = dev_get_drvdata(dev); + struct hdac_stream *hstream = hdac_stream(hext_stream); + int sd_offset = SOF_STREAM_SD_OFFSET(hstream); + int ret = 0; + + if (hstream->direction == SNDRV_PCM_STREAM_PLAYBACK) + ret = hda_dsp_stream_spib_config(sdev, hext_stream, HDA_DSP_SPIB_DISABLE, 0); + else + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset, + SOF_HDA_SD_CTL_DMA_START, 0); + + if (pair) + hda_dsp_stream_pair_put(sdev, hstream->direction, hstream->stream_tag); + else + hda_dsp_stream_put(sdev, hstream->direction, hstream->stream_tag); + + hstream->running = 0; + hstream->substream = NULL; + + /* reset BDL address */ + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, + sd_offset + SOF_HDA_ADSP_REG_SD_BDLPL, 0); + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, + sd_offset + SOF_HDA_ADSP_REG_SD_BDLPU, 0); + + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, sd_offset, 0); + + if (!persistent_buffer) { + snd_dma_free_pages(dmab); + dmab->area = NULL; + dmab->bytes = 0; + hstream->bufsize = 0; + hstream->format_val = 0; + } + + return ret; +} +EXPORT_SYMBOL_NS(hda_dma_cleanup, "SND_SOC_SOF_INTEL_HDA_COMMON"); diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 0b6340bba14603..308a316da93614 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -905,6 +905,14 @@ int sdw_hda_dai_hw_free(struct snd_pcm_substream *substream, int sdw_hda_dai_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *cpu_dai); +struct hdac_ext_stream * +hda_dma_prepare(struct device *dev, unsigned int format, unsigned int size, + struct snd_dma_buffer *dmab, bool persistent_buffer, int direction, + bool is_iccmax, bool pair); + +int hda_dma_cleanup(struct device *dev, struct snd_dma_buffer *dmab, + bool persistent_buffer, struct hdac_ext_stream *hext_stream, bool pair); + /* common dai driver */ extern struct snd_soc_dai_driver skl_dai[]; int hda_dsp_dais_suspend(struct snd_sof_dev *sdev); From e47c6a8e808e9d9a3edb6a3e05eafaa6dd780c24 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 27 Oct 2025 16:59:08 +0800 Subject: [PATCH 03/14] ASoC: SOF: Intel: hda-sdw-bpt: support simultaneous audio and BPT streams Currently the SoundWire BPT stream uses the paired link DMA but not reserve it. It works without any issue because we assume the SoundWire BPT will not run with audio streams simultaneously. To support simultaneous audio and BPT streams, we need to use the hda_dma_prepare/cleanup helpers to reserve the pair link host DMA. Signed-off-by: Bard Liao --- sound/soc/sof/intel/hda-sdw-bpt.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/hda-sdw-bpt.c b/sound/soc/sof/intel/hda-sdw-bpt.c index ae2f8d55dbd087..7d81cb4401523a 100644 --- a/sound/soc/sof/intel/hda-sdw-bpt.c +++ b/sound/soc/sof/intel/hda-sdw-bpt.c @@ -118,7 +118,8 @@ static int hda_sdw_bpt_dma_prepare(struct device *dev, struct hdac_ext_stream ** dev_dbg(dev, "direction %d format_val %#x\n", direction, format); - bpt_stream = hda_cl_prepare(dev, format, bpt_num_bytes, dmab_bdl, false, direction, false); + bpt_stream = hda_dma_prepare(dev, format, bpt_num_bytes, dmab_bdl, + false, direction, false, true); if (IS_ERR(bpt_stream)) { dev_err(sdev->dev, "%s: SDW BPT DMA prepare failed: dir %d\n", __func__, direction); @@ -162,7 +163,7 @@ static int hda_sdw_bpt_dma_deprepare(struct device *dev, struct hdac_ext_stream u32 mask; int ret; - ret = hda_cl_cleanup(sdev->dev, dmab_bdl, false, sdw_bpt_stream); + ret = hda_dma_cleanup(sdev->dev, dmab_bdl, false, sdw_bpt_stream, true); if (ret < 0) { dev_err(sdev->dev, "%s: SDW BPT DMA cleanup failed\n", __func__); From b4db4cdf0e2f08730bd40f69f963675efa8d3f25 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Tue, 4 Nov 2025 14:20:05 +0800 Subject: [PATCH 04/14] soundwire: use maximum sdw bus rate when BPT stream is running We should get as much as bandwidth for the BPT stream. Signed-off-by: Bard Liao --- drivers/soundwire/generic_bandwidth_allocation.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/soundwire/generic_bandwidth_allocation.c b/drivers/soundwire/generic_bandwidth_allocation.c index ee607dd6802862..4a12c95ad88c0b 100644 --- a/drivers/soundwire/generic_bandwidth_allocation.c +++ b/drivers/soundwire/generic_bandwidth_allocation.c @@ -570,8 +570,12 @@ static int sdw_compute_bus_params(struct sdw_bus *bus) clk_buf = NULL; } - /* If dynamic scaling is not supported, don't try higher freq */ - if (!is_clock_scaling_supported(bus)) + /* + * If dynamic scaling is not supported, don't try higher freq. + * Use the maximum freq to get maximum bandwidth and no need to try another freq + * if BPT stream is running + */ + if (!is_clock_scaling_supported(bus) || bus->bpt_stream_refcount) clk_values = 1; for (i = 0; i < clk_values; i++) { @@ -582,6 +586,10 @@ static int sdw_compute_bus_params(struct sdw_bus *bus) (bus->params.max_dr_freq >> clk_buf[i]) : clk_buf[i] * SDW_DOUBLE_RATE_FACTOR; + /* Use maximum freq to get maximum bandwidth if BPT stream is running */ + if (bus->bpt_stream_refcount) + curr_dr_freq = bus->params.max_dr_freq; + if (curr_dr_freq * (mstr_prop->default_col - 1) >= bus->params.bandwidth * mstr_prop->default_col) break; From 7e64d3202eac01eb091e639baf3e0d6847f758d1 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 3 Nov 2025 14:23:51 +0800 Subject: [PATCH 05/14] soundwire: generic_bandwidth_allocation: don't deal with BRA stream The DP0 (BPT) params are computed in sdw_compute_dp0_port_params(). We should exclude the BPT stream when calculating the audio streams. Signed-off-by: Bard Liao --- drivers/soundwire/generic_bandwidth_allocation.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/soundwire/generic_bandwidth_allocation.c b/drivers/soundwire/generic_bandwidth_allocation.c index 4a12c95ad88c0b..9d66504b89c610 100644 --- a/drivers/soundwire/generic_bandwidth_allocation.c +++ b/drivers/soundwire/generic_bandwidth_allocation.c @@ -216,6 +216,9 @@ static void _sdw_compute_port_params(struct sdw_bus *bus, if (m_rt->stream->state > SDW_STREAM_DISABLED || m_rt->stream->state < SDW_STREAM_CONFIGURED) continue; + /* BPT stream is handled in sdw_compute_dp0_port_params */ + if (m_rt->stream->type == SDW_STREAM_BPT) + continue; sdw_compute_master_ports(m_rt, ¶ms[i], &port_bo, hstop); } @@ -359,6 +362,9 @@ static int sdw_get_group_count(struct sdw_bus *bus, } list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) { + if (m_rt->stream->type == SDW_STREAM_BPT) + continue; + if (m_rt->stream->state == SDW_STREAM_DEPREPARED) continue; From 71b41e7e08cf9364851e173ee7e5cdbe2f86b801 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Fri, 7 Nov 2025 11:40:15 +0800 Subject: [PATCH 06/14] soundwire: don't count BPT bandwidth We just need to conunt the audio stream bandwidth and BRA stream will use the remaining bandwidth. Signed-off-by: Bard Liao --- drivers/soundwire/generic_bandwidth_allocation.c | 3 +++ drivers/soundwire/stream.c | 12 ++++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/soundwire/generic_bandwidth_allocation.c b/drivers/soundwire/generic_bandwidth_allocation.c index 9d66504b89c610..075e29e7c79237 100644 --- a/drivers/soundwire/generic_bandwidth_allocation.c +++ b/drivers/soundwire/generic_bandwidth_allocation.c @@ -601,6 +601,9 @@ static int sdw_compute_bus_params(struct sdw_bus *bus) break; list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) { + /* BPT stream always uses lane 0 */ + if (m_rt->stream->type == SDW_STREAM_BPT) + continue; /* * Get the first s_rt that will be used to find the available lane that * can be used. No need to check all Peripherals because we can't use diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c index 66ec70930d77ca..4e5fe7def95e4d 100644 --- a/drivers/soundwire/stream.c +++ b/drivers/soundwire/stream.c @@ -1484,8 +1484,11 @@ static int _sdw_prepare_stream(struct sdw_stream_runtime *stream, if (update_params) { /* Increment cumulative bus bandwidth */ /* TODO: Update this during Device-Device support */ - bus->params.bandwidth += m_rt->stream->params.rate * - m_rt->ch_count * m_rt->stream->params.bps; + /* Don't count BPT stream bandwidth, it will use the remaining bandwidth */ + if (m_rt->stream->type != SDW_STREAM_BPT) { + bus->params.bandwidth += m_rt->stream->params.rate * + m_rt->ch_count * m_rt->stream->params.bps; + } /* Compute params */ if (bus->compute_params) { @@ -1774,6 +1777,10 @@ static int _sdw_deprepare_stream(struct sdw_stream_runtime *stream) multi_lane_bandwidth = 0; + /* Don't count BPT stream bandwidth, it will use the remaining bandwidth */ + if (m_rt->stream->type == SDW_STREAM_BPT) + goto skip_bpt_stream; + list_for_each_entry(p_rt, &m_rt->port_list, port_node) { if (!p_rt->lane) continue; @@ -1789,6 +1796,7 @@ static int _sdw_deprepare_stream(struct sdw_stream_runtime *stream) bandwidth = m_rt->stream->params.rate * m_rt->ch_count * m_rt->stream->params.bps; bus->params.bandwidth -= bandwidth - multi_lane_bandwidth; +skip_bpt_stream: /* Compute params */ if (bus->compute_params) { ret = bus->compute_params(bus, stream); From 16bc525506d0a2cdf1930aaa9c780a51d3215f8e Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Fri, 7 Nov 2025 13:55:48 +0800 Subject: [PATCH 07/14] soundwire: generic_bandwidth_allocation: check bandwidth with real colume The existing code assumes the column number will not change, but it could change if curr_dr_freq changes. Calculate the new column number before checking the bandwidth to make the checking be more accurate. Signed-off-by: Bard Liao --- drivers/soundwire/generic_bandwidth_allocation.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/soundwire/generic_bandwidth_allocation.c b/drivers/soundwire/generic_bandwidth_allocation.c index 075e29e7c79237..b94fee21272dcb 100644 --- a/drivers/soundwire/generic_bandwidth_allocation.c +++ b/drivers/soundwire/generic_bandwidth_allocation.c @@ -584,7 +584,12 @@ static int sdw_compute_bus_params(struct sdw_bus *bus) if (!is_clock_scaling_supported(bus) || bus->bpt_stream_refcount) clk_values = 1; + if (!mstr_prop->default_frame_rate || !mstr_prop->default_row) + return -EINVAL; + for (i = 0; i < clk_values; i++) { + int total_col; + if (!clk_buf) curr_dr_freq = bus->params.max_dr_freq; else @@ -596,8 +601,10 @@ static int sdw_compute_bus_params(struct sdw_bus *bus) if (bus->bpt_stream_refcount) curr_dr_freq = bus->params.max_dr_freq; - if (curr_dr_freq * (mstr_prop->default_col - 1) >= - bus->params.bandwidth * mstr_prop->default_col) + total_col = curr_dr_freq / mstr_prop->default_frame_rate / mstr_prop->default_row; + + if (curr_dr_freq * (total_col - 1) >= + bus->params.bandwidth * total_col) break; list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) { @@ -659,9 +666,6 @@ static int sdw_compute_bus_params(struct sdw_bus *bus) } } - if (!mstr_prop->default_frame_rate || !mstr_prop->default_row) - return -EINVAL; - mstr_prop->default_col = curr_dr_freq / mstr_prop->default_frame_rate / mstr_prop->default_row; From 38a04563878573aa0de0f32b4bce5ea6d61ad7a9 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Tue, 8 Jul 2025 21:43:19 +0800 Subject: [PATCH 08/14] soundwire: add bpt_hstop in struct sdw_bus To allow BPT and audio stream work simultaneously, we need to record the hstop of the BPT stream. And use column bpt_hstop + 1 to the last column for audio streams. No function changed since bus->bpt_hstop is set to bus->params.col - 1 for now. Will update bus->audio_stream_hstart in the follow up commit. Signed-off-by: Bard Liao --- drivers/soundwire/generic_bandwidth_allocation.c | 9 +++++---- drivers/soundwire/intel_ace2x.c | 6 +++--- include/linux/soundwire/sdw.h | 2 ++ 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/soundwire/generic_bandwidth_allocation.c b/drivers/soundwire/generic_bandwidth_allocation.c index b94fee21272dcb..8ad29a8a4f8cf1 100644 --- a/drivers/soundwire/generic_bandwidth_allocation.c +++ b/drivers/soundwire/generic_bandwidth_allocation.c @@ -97,9 +97,9 @@ static void sdw_compute_dp0_slave_ports(struct sdw_master_runtime *m_rt) list_for_each_entry(p_rt, &s_rt->port_list, port_node) { sdw_fill_xport_params(&p_rt->transport_params, p_rt->num, false, SDW_BLK_GRP_CNT_1, bus->params.col, 0, 0, 1, - bus->params.col - 1, SDW_BLK_PKG_PER_PORT, 0x0); + bus->bpt_hstop, SDW_BLK_PKG_PER_PORT, 0x0); - sdw_fill_port_params(&p_rt->port_params, p_rt->num, bus->params.col - 1, + sdw_fill_port_params(&p_rt->port_params, p_rt->num, bus->bpt_hstop, SDW_PORT_FLOW_MODE_ISOCH, SDW_PORT_DATA_MODE_NORMAL); } } @@ -113,9 +113,9 @@ static void sdw_compute_dp0_master_ports(struct sdw_master_runtime *m_rt) list_for_each_entry(p_rt, &m_rt->port_list, port_node) { sdw_fill_xport_params(&p_rt->transport_params, p_rt->num, false, SDW_BLK_GRP_CNT_1, bus->params.col, 0, 0, 1, - bus->params.col - 1, SDW_BLK_PKG_PER_PORT, 0x0); + bus->bpt_hstop, SDW_BLK_PKG_PER_PORT, 0x0); - sdw_fill_port_params(&p_rt->port_params, p_rt->num, bus->params.col - 1, + sdw_fill_port_params(&p_rt->port_params, p_rt->num, bus->bpt_hstop, SDW_PORT_FLOW_MODE_ISOCH, SDW_PORT_DATA_MODE_NORMAL); } } @@ -695,6 +695,7 @@ int sdw_compute_params(struct sdw_bus *bus, struct sdw_stream_runtime *stream) if (ret < 0) return ret; + bus->bpt_hstop = bus->params.col - 1; if (stream->type == SDW_STREAM_BPT) { sdw_compute_dp0_port_params(bus); return 0; diff --git a/drivers/soundwire/intel_ace2x.c b/drivers/soundwire/intel_ace2x.c index 1ed0251d259236..b1666c41af5618 100644 --- a/drivers/soundwire/intel_ace2x.c +++ b/drivers/soundwire/intel_ace2x.c @@ -153,7 +153,7 @@ static int intel_ace2x_bpt_open_stream(struct sdw_intel *sdw, struct sdw_slave * command = (msg->flags & SDW_MSG_FLAG_WRITE) ? 0 : 1; ret = sdw_cdns_bpt_find_bandwidth(command, cdns->bus.params.row, - cdns->bus.params.col, + cdns->bus.bpt_hstop + 1, prop->default_frame_rate, &tx_dma_bandwidth, &rx_dma_bandwidth); if (ret < 0) @@ -166,7 +166,7 @@ static int intel_ace2x_bpt_open_stream(struct sdw_intel *sdw, struct sdw_slave * /* Add up pdi buffer size and frame numbers of each BPT sections */ for (i = 0; i < msg->sections; i++) { ret = sdw_cdns_bpt_find_buffer_sizes(command, cdns->bus.params.row, - cdns->bus.params.col, + cdns->bus.bpt_hstop + 1, msg->sec[i].len, SDW_BPT_MSG_MAX_BYTES, &data_per_frame, &pdi0_buffer_size_, &pdi1_buffer_size_, &num_frames_); @@ -190,7 +190,7 @@ static int intel_ace2x_bpt_open_stream(struct sdw_intel *sdw, struct sdw_slave * if (command) { /* read */ /* Get buffer size of a full frame */ ret = sdw_cdns_bpt_find_buffer_sizes(command, cdns->bus.params.row, - cdns->bus.params.col, + cdns->bus.bpt_hstop + 1, data_per_frame, SDW_BPT_MSG_MAX_BYTES, &data_per_frame, &pdi0_buf_size_pre_frame, &pdi1_buf_size_pre_frame, &fake_num_frames); diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index e6a3476bcef1ae..b370f175784e84 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -985,6 +985,7 @@ struct sdw_stream_runtime { * @stream_refcount: number of streams currently using this bus * @btp_stream_refcount: number of BTP streams currently using this bus (should * be zero or one, multiple streams per link is not supported). + * @bpt_hstop: The hstop of the BPT stream. * @bpt_stream: pointer stored to handle BTP streams. * @ops: Master callback ops * @port_ops: Master port callback ops @@ -1025,6 +1026,7 @@ struct sdw_bus { struct sdw_bus_params params; int stream_refcount; int bpt_stream_refcount; + int bpt_hstop; struct sdw_stream_runtime *bpt_stream; const struct sdw_master_ops *ops; const struct sdw_master_port_ops *port_ops; From 6106a58383b4e4544570898cca65ede34775230c Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 5 Nov 2025 22:10:21 +0800 Subject: [PATCH 09/14] soundwire: generic_bandwidth_allocation: update bpt_hstop Update bus->bpt_hstop to record the hstop of the BPT stream. And return -EAGAIN when there is no bandwidth for the BPT stream. Signed-off-by: Bard Liao --- .../soundwire/generic_bandwidth_allocation.c | 36 ++++++++++++++----- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/drivers/soundwire/generic_bandwidth_allocation.c b/drivers/soundwire/generic_bandwidth_allocation.c index 8ad29a8a4f8cf1..56ddd668d34898 100644 --- a/drivers/soundwire/generic_bandwidth_allocation.c +++ b/drivers/soundwire/generic_bandwidth_allocation.c @@ -190,8 +190,8 @@ static void sdw_compute_master_ports(struct sdw_master_runtime *m_rt, sdw_compute_slave_ports(m_rt, &t_data); } -static void _sdw_compute_port_params(struct sdw_bus *bus, - struct sdw_group_params *params, int count) +static void _sdw_compute_port_params(struct sdw_bus *bus, struct sdw_group_params *params, + int count, bool update_bpt_hstop) { struct sdw_master_runtime *m_rt; int port_bo, i, l; @@ -223,6 +223,16 @@ static void _sdw_compute_port_params(struct sdw_bus *bus, } hstop = hstop - params[i].hwidth; + if (l == 0 && update_bpt_hstop && bus->bpt_hstop > hstop) { + /* Assume BPT stream uses lane 0 */ + /* + * hstart = hstop - params->hwidth + 1. + * At this point after hstop = hstop - params[i].hwidth above, + * the hstart is equal to hstop + 1, and bus->bpt_hstop should + * be hstart - 1. so we can set bpt_hstop to hstop directly. + */ + bus->bpt_hstop = hstop; + } } } } @@ -421,7 +431,7 @@ static int sdw_compute_port_params(struct sdw_bus *bus, struct sdw_stream_runtim if (ret < 0) goto free_params; - _sdw_compute_port_params(bus, params, group.count); + _sdw_compute_port_params(bus, params, group.count, stream->type == SDW_STREAM_BPT); free_params: kfree(params); @@ -695,11 +705,12 @@ int sdw_compute_params(struct sdw_bus *bus, struct sdw_stream_runtime *stream) if (ret < 0) return ret; - bus->bpt_hstop = bus->params.col - 1; - if (stream->type == SDW_STREAM_BPT) { - sdw_compute_dp0_port_params(bus); - return 0; - } + /* + * Reset the bpt_hstop and reserve 2 columes for audio stream. bpt_hstop will be updated + * in sdw_compute_port_params() below. + */ + if (stream->type == SDW_STREAM_BPT && stream->state != SDW_STREAM_DEPREPARED) + bus->bpt_hstop = bus->params.col - 3; /* Compute transport and port params */ ret = sdw_compute_port_params(bus, stream); @@ -708,6 +719,15 @@ int sdw_compute_params(struct sdw_bus *bus, struct sdw_stream_runtime *stream) return ret; } + if (stream->type == SDW_STREAM_BPT) { + if (bus->bpt_hstop < 1) { + dev_err(bus->dev, "%s: No bandwidth for BPT stream\n", + __func__); + return -EAGAIN; + } + sdw_compute_dp0_port_params(bus); + } + return 0; } EXPORT_SYMBOL(sdw_compute_params); From 87ad400e7e3d89c52bd2226a5f83df11b34e52f9 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Fri, 7 Nov 2025 14:11:22 +0800 Subject: [PATCH 10/14] soundwire: subtract BRA columns in bandwidth calculation When a BRA stream is running, we should subtract the columns that is used by the BRA stream in bandwidth calculation. Signed-off-by: Bard Liao --- drivers/soundwire/generic_bandwidth_allocation.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/soundwire/generic_bandwidth_allocation.c b/drivers/soundwire/generic_bandwidth_allocation.c index 56ddd668d34898..d358e10bd48b66 100644 --- a/drivers/soundwire/generic_bandwidth_allocation.c +++ b/drivers/soundwire/generic_bandwidth_allocation.c @@ -571,6 +571,7 @@ static int sdw_compute_bus_params(struct sdw_bus *bus) unsigned int curr_dr_freq = 0; int i, l, clk_values, ret; bool is_gear = false; + int available_col; int m_lane = 0; u32 *clk_buf; @@ -613,8 +614,14 @@ static int sdw_compute_bus_params(struct sdw_bus *bus) total_col = curr_dr_freq / mstr_prop->default_frame_rate / mstr_prop->default_row; - if (curr_dr_freq * (total_col - 1) >= - bus->params.bandwidth * total_col) + if (bus->bpt_stream_refcount) + available_col = total_col - bus->bpt_hstop - 1; + else + available_col = total_col; + + /* If the bandwidth of the available columns is sufficient, then we are good */ + if (curr_dr_freq * (available_col - 1) >= + bus->params.bandwidth * available_col) break; list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) { From f8849a6311fe8316e60dd3ac2807106f9c262410 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 25 Jun 2025 15:10:37 +0800 Subject: [PATCH 11/14] soundwire: allow BPT and audio stream run simultaneously Now the SoundWire BPT stream and the audio stream can share the SoundWire bus bandwidth. However, it is still not allowed to have more than 1 BPT stream running simultaneously. Signed-off-by: Bard Liao --- drivers/soundwire/stream.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c index 4e5fe7def95e4d..9ae9d9df544fa8 100644 --- a/drivers/soundwire/stream.c +++ b/drivers/soundwire/stream.c @@ -1237,18 +1237,10 @@ static struct sdw_master_runtime struct sdw_master_runtime *m_rt, *walk_m_rt; struct list_head *insert_after; - if (stream->type == SDW_STREAM_BPT) { - if (bus->stream_refcount > 0 || bus->bpt_stream_refcount > 0) { - dev_err(bus->dev, "%s: %d/%d audio/BPT stream already allocated\n", - __func__, bus->stream_refcount, bus->bpt_stream_refcount); - return ERR_PTR(-EBUSY); - } - } else { - if (bus->bpt_stream_refcount > 0) { - dev_err(bus->dev, "%s: BPT stream already allocated\n", - __func__); - return ERR_PTR(-EAGAIN); - } + if (stream->type == SDW_STREAM_BPT && bus->bpt_stream_refcount > 0) { + dev_err(bus->dev, "%s: BPT stream already allocated\n", + __func__); + return ERR_PTR(-EAGAIN); } m_rt = kzalloc(sizeof(*m_rt), GFP_KERNEL); From ae0db599f419f43d20dc0250a54a5666a37707f3 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Tue, 12 Aug 2025 12:53:10 +0800 Subject: [PATCH 12/14] ASoC: rt1320: add dp0 properties To support BRA. Signed-off-by: Bard Liao --- sound/soc/codecs/rt1320-sdw.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/soc/codecs/rt1320-sdw.c b/sound/soc/codecs/rt1320-sdw.c index e3f9b03df3aaeb..9e648807bb399b 100644 --- a/sound/soc/codecs/rt1320-sdw.c +++ b/sound/soc/codecs/rt1320-sdw.c @@ -720,6 +720,14 @@ static int rt1320_read_prop(struct sdw_slave *slave) j++; } + prop->dp0_prop = devm_kzalloc(&slave->dev, sizeof(*prop->dp0_prop), + GFP_KERNEL); + if (!prop->dp0_prop) + return -ENOMEM; + + prop->dp0_prop->simple_ch_prep_sm = true; + prop->dp0_prop->ch_prep_timeout = 10; + /* set the timeout values */ prop->clk_stop_timeout = 64; From 129ac4a02b376bc4a593b22fb135ab8875aad3de Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Tue, 4 Nov 2025 14:33:02 +0800 Subject: [PATCH 13/14] ASoC: rt722: add DP0 properties To test BRA Signed-off-by: Bard Liao --- sound/soc/codecs/rt722-sdca-sdw.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/soc/codecs/rt722-sdca-sdw.c b/sound/soc/codecs/rt722-sdca-sdw.c index 5ea40c1b159a80..f89ba944e7929b 100644 --- a/sound/soc/codecs/rt722-sdca-sdw.c +++ b/sound/soc/codecs/rt722-sdca-sdw.c @@ -299,6 +299,14 @@ static int rt722_sdca_read_prop(struct sdw_slave *slave) j++; } + prop->dp0_prop = devm_kzalloc(&slave->dev, sizeof(*prop->dp0_prop), + GFP_KERNEL); + if (!prop->dp0_prop) + return -ENOMEM; + + prop->dp0_prop->simple_ch_prep_sm = true; + prop->dp0_prop->ch_prep_timeout = 10; + /* set the timeout values */ prop->clk_stop_timeout = 900; From 946f2935b943491b57d9e8fa28a12ce90c1e9dbf Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Fri, 7 Nov 2025 16:11:25 +0800 Subject: [PATCH 14/14] WIP: need to cleanup Signed-off-by: Bard Liao --- .../soundwire/generic_bandwidth_allocation.c | 20 +++++++++++++++++-- drivers/soundwire/intel_ace2x.c | 1 + drivers/soundwire/stream.c | 8 ++++++++ sound/soc/sof/intel/hda-sdw-bpt.c | 1 + 4 files changed, 28 insertions(+), 2 deletions(-) diff --git a/drivers/soundwire/generic_bandwidth_allocation.c b/drivers/soundwire/generic_bandwidth_allocation.c index d358e10bd48b66..b028e15f6edfde 100644 --- a/drivers/soundwire/generic_bandwidth_allocation.c +++ b/drivers/soundwire/generic_bandwidth_allocation.c @@ -55,7 +55,7 @@ void sdw_compute_slave_ports(struct sdw_master_runtime *m_rt, ch = hweight32(p_rt->ch_mask); - dev_dbg(&s_rt->slave->dev, "%s p_rt->lane %d\n", __func__, p_rt->lane); + dev_dbg(&s_rt->slave->dev, "bard: %s p_rt->lane %d hstart %d\n", __func__, p_rt->lane, t_data->hstart); sdw_fill_xport_params(&p_rt->transport_params, p_rt->num, false, SDW_BLK_GRP_CNT_1, @@ -156,6 +156,9 @@ static void sdw_compute_master_ports(struct sdw_master_runtime *m_rt, hstart = hstop - params->hwidth + 1; t_data.hstart = hstart; + pr_err("bard: bpt_stream_refcount %d bpt_hstop %d hstart %d\n", + bus->bpt_stream_refcount, bus->bpt_hstop, hstart); + list_for_each_entry(p_rt, &m_rt->port_list, port_node) { if (p_rt->lane != params->lane) continue; @@ -197,6 +200,7 @@ static void _sdw_compute_port_params(struct sdw_bus *bus, struct sdw_group_param int port_bo, i, l; int hstop; + pr_err("bard: %s update_bpt_hstop %d\n", __func__, update_bpt_hstop); /* Run loop for all groups to compute transport parameters */ for (l = 0; l < SDW_MAX_LANES; l++) { if (l > 0 && !bus->lane_used_bandwidth[l]) @@ -223,6 +227,7 @@ static void _sdw_compute_port_params(struct sdw_bus *bus, struct sdw_group_param } hstop = hstop - params[i].hwidth; + pr_err("bard: bus->bpt_hstop %d hstop[%d] = %d\n", bus->bpt_hstop, i, hstop); if (l == 0 && update_bpt_hstop && bus->bpt_hstop > hstop) { /* Assume BPT stream uses lane 0 */ /* @@ -232,6 +237,7 @@ static void _sdw_compute_port_params(struct sdw_bus *bus, struct sdw_group_param * be hstart - 1. so we can set bpt_hstop to hstop directly. */ bus->bpt_hstop = hstop; + pr_err("bard: updated bpt_hstop to %d\n", bus->bpt_hstop); } } } @@ -447,6 +453,9 @@ static int sdw_select_row_col(struct sdw_bus *bus, int clk_freq) struct sdw_master_prop *prop = &bus->prop; int r, c; + pr_err("bard: %s clk_freq %d default_row %d default_col %d bandwidth %d\n", + __func__, clk_freq, prop->default_row, prop->default_col, + bus->params.bandwidth); for (c = 0; c < SDW_FRAME_COLS; c++) { for (r = 0; r < SDW_FRAME_ROWS; r++) { if (sdw_rows[r] != prop->default_row || @@ -619,10 +628,15 @@ static int sdw_compute_bus_params(struct sdw_bus *bus) else available_col = total_col; + pr_err("bard: %s available_col %d mstr_prop->default_col %d total_col %d bpt_stream_refcount %d\n", + __func__, available_col, mstr_prop->default_col, total_col, bus->bpt_stream_refcount); + /* If the bandwidth of the available columns is sufficient, then we are good */ if (curr_dr_freq * (available_col - 1) >= - bus->params.bandwidth * available_col) + bus->params.bandwidth * available_col) { + pr_err("bard: %s available_col %d break\n", __func__, available_col); break; + } list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) { /* BPT stream always uses lane 0 */ @@ -719,6 +733,8 @@ int sdw_compute_params(struct sdw_bus *bus, struct sdw_stream_runtime *stream) if (stream->type == SDW_STREAM_BPT && stream->state != SDW_STREAM_DEPREPARED) bus->bpt_hstop = bus->params.col - 3; + pr_err("bard: %s stream name %s type %d state %d bpt_stream_refcount %d bpt_hstop: %d and updating bpt_hstop\n", + __func__, stream->name, stream->type, stream->state, bus->bpt_stream_refcount, bus->bpt_hstop); /* Compute transport and port params */ ret = sdw_compute_port_params(bus, stream); if (ret < 0) { diff --git a/drivers/soundwire/intel_ace2x.c b/drivers/soundwire/intel_ace2x.c index b1666c41af5618..baca6a86da4eb4 100644 --- a/drivers/soundwire/intel_ace2x.c +++ b/drivers/soundwire/intel_ace2x.c @@ -152,6 +152,7 @@ static int intel_ace2x_bpt_open_stream(struct sdw_intel *sdw, struct sdw_slave * command = (msg->flags & SDW_MSG_FLAG_WRITE) ? 0 : 1; + pr_err("bard: %s bpt_hstop %d\n", __func__, cdns->bus.bpt_hstop); ret = sdw_cdns_bpt_find_bandwidth(command, cdns->bus.params.row, cdns->bus.bpt_hstop + 1, prop->default_frame_rate, diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c index 9ae9d9df544fa8..7b04e5a555baaa 100644 --- a/drivers/soundwire/stream.c +++ b/drivers/soundwire/stream.c @@ -1274,6 +1274,8 @@ static struct sdw_master_runtime if (stream->type == SDW_STREAM_BPT) bus->bpt_stream_refcount++; + pr_err("bard: %s update bpt_stream_refcount %d stream_refcount %d\n", + __func__, bus->bpt_stream_refcount, bus->stream_refcount); return m_rt; } @@ -1324,6 +1326,8 @@ static void sdw_master_rt_free(struct sdw_master_runtime *m_rt, if (stream->type == SDW_STREAM_BPT) bus->bpt_stream_refcount--; bus->stream_refcount--; + pr_err("bard: %s update bpt_stream_refcount %d stream_refcount %d\n", + __func__, bus->bpt_stream_refcount, bus->stream_refcount); } /** @@ -1482,6 +1486,8 @@ static int _sdw_prepare_stream(struct sdw_stream_runtime *stream, m_rt->ch_count * m_rt->stream->params.bps; } + pr_err("bard: %s: stream %s bus bandwidth %d\n", + __func__, stream->name, bus->params.bandwidth); /* Compute params */ if (bus->compute_params) { ret = bus->compute_params(bus, stream); @@ -1789,6 +1795,8 @@ static int _sdw_deprepare_stream(struct sdw_stream_runtime *stream) bus->params.bandwidth -= bandwidth - multi_lane_bandwidth; skip_bpt_stream: + pr_err("bard: %s stream %s bus bandwidth %d\n", + __func__, stream->name, bus->params.bandwidth); /* Compute params */ if (bus->compute_params) { ret = bus->compute_params(bus, stream); diff --git a/sound/soc/sof/intel/hda-sdw-bpt.c b/sound/soc/sof/intel/hda-sdw-bpt.c index 7d81cb4401523a..6610cfe7b0e7ec 100644 --- a/sound/soc/sof/intel/hda-sdw-bpt.c +++ b/sound/soc/sof/intel/hda-sdw-bpt.c @@ -337,6 +337,7 @@ int hda_sdw_bpt_send_async(struct device *dev, struct hdac_ext_stream *bpt_tx_st int ret1; int ret; + msleep(5000); ret = hda_sdw_bpt_dma_enable(dev, bpt_tx_stream); if (ret < 0) { dev_err(dev, "%s: hda_sdw_bpt_dma_enable failed for TX: %d\n",