From 3dd10d048bd6126b90cc213944f3952dc70e9e58 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Tue, 4 Nov 2025 14:20:05 +0800 Subject: [PATCH 1/8] 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 4fb4c1acd3bb90..8386aaaa006d71 100644 --- a/drivers/soundwire/generic_bandwidth_allocation.c +++ b/drivers/soundwire/generic_bandwidth_allocation.c @@ -566,8 +566,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++) { @@ -578,6 +582,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 a899661b343fae0f2eec59e504ce9176c9f8504d Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 3 Nov 2025 14:23:51 +0800 Subject: [PATCH 2/8] 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 8386aaaa006d71..97d1589e1f9c66 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); } @@ -355,6 +358,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 86c4ff7fd753aed693d9349d9b11a7b3746ff5b5 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Fri, 7 Nov 2025 11:40:15 +0800 Subject: [PATCH 3/8] 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 97d1589e1f9c66..0a65cb76c57648 100644 --- a/drivers/soundwire/generic_bandwidth_allocation.c +++ b/drivers/soundwire/generic_bandwidth_allocation.c @@ -597,6 +597,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 cbf7bd3d4e7bac..52b33929210aad 100644 --- a/drivers/soundwire/stream.c +++ b/drivers/soundwire/stream.c @@ -1497,8 +1497,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) { @@ -1787,6 +1790,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; @@ -1802,6 +1809,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 9539202fc0f99481c9d502347470ae6cc4c3eee6 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Fri, 7 Nov 2025 13:55:48 +0800 Subject: [PATCH 4/8] 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 0a65cb76c57648..b14a6d18bd1ced 100644 --- a/drivers/soundwire/generic_bandwidth_allocation.c +++ b/drivers/soundwire/generic_bandwidth_allocation.c @@ -580,7 +580,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 @@ -592,8 +597,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) { @@ -655,9 +662,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 2406848891b83c6cd7833b1d65b4d53c9a00c2e7 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Thu, 25 Jun 2026 19:47:47 +0800 Subject: [PATCH 5/8] 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 b14a6d18bd1ced..44846b9de12702 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); } } @@ -691,6 +691,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 642b33ab552606..76f0bba3771d30 100644 --- a/drivers/soundwire/intel_ace2x.c +++ b/drivers/soundwire/intel_ace2x.c @@ -159,7 +159,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) @@ -185,7 +185,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, max_data_per_frame, slave->prop.bra_block_alignment, &data_per_frame, &pdi0_buffer_size_, @@ -210,7 +210,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, max_data_per_frame, slave->prop.bra_block_alignment, &data_per_frame, &pdi0_buf_size_pre_frame, diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index 3e0d21132ef2f7..f84704a7f3311e 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -1003,6 +1003,7 @@ struct sdw_stream_runtime { * @stream_refcount: number of streams currently using this bus * @bpt_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 @@ -1043,6 +1044,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 e4f7b5a136e8195ef88463af8d61ecc79f9f8444 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 5 Nov 2025 22:10:21 +0800 Subject: [PATCH 6/8] 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 | 48 ++++++++++++++++--- 1 file changed, 41 insertions(+), 7 deletions(-) diff --git a/drivers/soundwire/generic_bandwidth_allocation.c b/drivers/soundwire/generic_bandwidth_allocation.c index 44846b9de12702..dd14209afecc00 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; + } } } } @@ -417,7 +427,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); @@ -676,6 +686,10 @@ static int sdw_compute_bus_params(struct sdw_bus *bus) return 0; } +#define SDW_DEFAULT_COL 4 +#define SDW_COL_RESERVED_FOR_AUDIO 2 + + /** * sdw_compute_params: Compute bus, transport and port parameters * @@ -691,10 +705,20 @@ 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; + if (stream->type == SDW_STREAM_BPT && stream->state == SDW_STREAM_CONFIGURED) { + /* + * Set the initial bpt_hstop when the BPT stream is preparing and it will be + * updated in sdw_compute_port_params() below. + */ + bus->bpt_hstop = bus->params.col - 1; + /* + * Reserve 2 columns for future audio stream if the bus->params.col is greater + * than SDW_DEFAULT_COL (4) + reserved columns (2). And don't reserve columns + * for future use otherwise. This ensures that the BPT stream will not meet the + * bandwidth issue when there is no audio stream is open. + */ + if (bus->params.col >= (SDW_DEFAULT_COL + SDW_COL_RESERVED_FOR_AUDIO)) + bus->bpt_hstop -= SDW_COL_RESERVED_FOR_AUDIO; } /* Compute transport and port params */ @@ -704,6 +728,16 @@ int sdw_compute_params(struct sdw_bus *bus, struct sdw_stream_runtime *stream) return ret; } + if (stream->type == SDW_STREAM_BPT) { + /* If there is only one column left, just use normal write. */ + 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 b0c55fa6f9f4f10f8f3e7de1ee8de946e0e52527 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Fri, 7 Nov 2025 14:11:22 +0800 Subject: [PATCH 7/8] 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 dd14209afecc00..ff322c26297d93 100644 --- a/drivers/soundwire/generic_bandwidth_allocation.c +++ b/drivers/soundwire/generic_bandwidth_allocation.c @@ -567,6 +567,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; @@ -609,8 +610,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 2e1bb1e42b827a39f23fd4afabd4170dcb15463d Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 25 Jun 2025 15:10:37 +0800 Subject: [PATCH 8/8] 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 52b33929210aad..4ae515c50a7543 100644 --- a/drivers/soundwire/stream.c +++ b/drivers/soundwire/stream.c @@ -1250,18 +1250,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_obj(*m_rt);