From a92d4cb89dd6655629a9f36c36123f2e79623606 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 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 6216cf4d3d7d49bc36ba118c326edf9205ba7deb 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 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 1d624239a7814153c61b54f644d7dcbe16244570 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 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 06cf17615bd8a86cb6d4a3f596d673d124f2bb7b 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 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 283f407dbec73a84cb1558b157c446770c6c159f Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Tue, 8 Jul 2025 21:43:19 +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 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 1e46802acfe4799890e172a2db5994bf121614ab 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 8ad29a8a4f8cf1..02366b0aff9b19 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); @@ -680,6 +690,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 * @@ -695,10 +709,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 */ @@ -708,6 +732,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 61c7a7d0176974063d243040af0161f12ed746c5 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 02366b0aff9b19..3d58f2a1a3044a 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 7a5ec9205c5945139016faa851f0cac01af98522 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 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);