diff --git a/drivers/soundwire/generic_bandwidth_allocation.c b/drivers/soundwire/generic_bandwidth_allocation.c index ee607dd6802862..3d58f2a1a3044a 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); } } @@ -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; @@ -216,10 +216,23 @@ 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); } 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; + } } } } @@ -359,6 +372,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; @@ -415,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); @@ -555,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; @@ -570,11 +587,20 @@ 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; + 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 @@ -582,11 +608,26 @@ 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; - if (curr_dr_freq * (mstr_prop->default_col - 1) >= - bus->params.bandwidth * mstr_prop->default_col) + /* 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; + + total_col = curr_dr_freq / mstr_prop->default_frame_rate / mstr_prop->default_row; + + 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) { + /* 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 @@ -642,9 +683,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; @@ -659,6 +697,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 * @@ -674,9 +716,20 @@ int sdw_compute_params(struct sdw_bus *bus, struct sdw_stream_runtime *stream) if (ret < 0) return ret; - 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 */ @@ -686,6 +739,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); 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/drivers/soundwire/stream.c b/drivers/soundwire/stream.c index 66ec70930d77ca..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); @@ -1484,8 +1476,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 +1769,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 +1788,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); 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;