Skip to content
136 changes: 118 additions & 18 deletions drivers/soundwire/generic_bandwidth_allocation.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Expand All @@ -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);
}
}
Expand Down Expand Up @@ -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;
Expand All @@ -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, &params[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;
}
}
}
}
Expand Down Expand Up @@ -254,9 +267,22 @@ static int sdw_compute_group_params(struct sdw_bus *bus,
*/
if (m_rt->stream->state != SDW_STREAM_ENABLED &&
m_rt->stream->state != SDW_STREAM_PREPARED &&
m_rt->stream->state != SDW_STREAM_DISABLED)
m_rt->stream->state != SDW_STREAM_DISABLED) {
continue;
} else if (m_rt->stream->type == SDW_STREAM_BPT) {
/*
* If any BPT stream is running, exclude the BPT columns
* BPT: col 0.. bus->bpt_hstop
* Audio: col bus->bpt_hstop + 1 .. bus->params.col - 1
*/
sel_col = bus->params.col - bus->bpt_hstop - 1;
}
}

/* Don't count BPT stream bandwidth, it will use the remaining bandwidth */
if (m_rt->stream->type == SDW_STREAM_BPT)
continue;

list_for_each_entry(p_rt, &m_rt->port_list, port_node) {
rate = m_rt->stream->params.rate;
Comment thread
bardliao marked this conversation as resolved.
bps = m_rt->stream->params.bps;
Expand Down Expand Up @@ -285,8 +311,13 @@ static int sdw_compute_group_params(struct sdw_bus *bus,
/* There is no control column for lane 1 and above */
if (column_needed > sel_col)
return -EINVAL;
/* Column 0 is control column on lane 0 */
if (params[i].lane == 0 && column_needed > sel_col - 1)
/*
* Column 0 is the control column on lane 0. However, when sel_col is
* reduced (e.g. due to a running BPT stream), sel_col already represents
* usable audio columns.
*/
if (sel_col == bus->params.col && params[i].lane == 0 &&
column_needed > sel_col - 1)
return -EINVAL;
}
}
Expand Down Expand Up @@ -355,6 +386,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;

Comment thread
bardliao marked this conversation as resolved.
if (m_rt->stream->state == SDW_STREAM_DEPREPARED)
continue;

Expand Down Expand Up @@ -411,7 +445,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);
Expand Down Expand Up @@ -549,8 +583,10 @@ static int sdw_compute_bus_params(struct sdw_bus *bus)
struct sdw_master_runtime *m_rt;
struct sdw_slave_runtime *s_rt;
unsigned int curr_dr_freq = 0;
bool is_bpt_running = false;
int i, l, clk_values, ret;
bool is_gear = false;
int available_col;
int m_lane = 0;
u32 *clk_buf;

Expand All @@ -566,23 +602,65 @@ static int sdw_compute_bus_params(struct sdw_bus *bus)
clk_buf = NULL;
}

/*
* Use the maximum freq to get maximum bandwidth and no need to try another freq
* if any BPT stream is running
*/
list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) {
if (m_rt->stream->type == SDW_STREAM_BPT &&
m_rt->stream->state < SDW_STREAM_DEPREPARED) {
clk_values = 1;
clk_buf = NULL;
/*
* If any BPT stream is active, the available audio columns should exclude
* the BPT columns
*/
if (m_rt->stream->state >= SDW_STREAM_PREPARED)
is_bpt_running = true;
}
Comment thread
bardliao marked this conversation as resolved.
}

/* If dynamic scaling is not supported, don't try higher freq */
if (!is_clock_scaling_supported(bus))
clk_values = 1;
Comment thread
bardliao marked this conversation as resolved.

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
curr_dr_freq = (is_gear) ?
(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)
total_col = curr_dr_freq / mstr_prop->default_frame_rate / mstr_prop->default_row;

/*
* available columns for audio stream on lane 0:
* - exclude control column 0
* - if BPT is active, also exclude columns 1..bpt_hstop used by DP0
*/
if (is_bpt_running)
available_col = total_col - bus->bpt_hstop - 1;
else
available_col = total_col - 1;

if (available_col <= 0)
continue;

/* Keep formula consistent with sdw_select_row_col() */
if (curr_dr_freq * available_col >=
bus->params.bandwidth * total_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
Expand Down Expand Up @@ -638,9 +716,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;

Expand All @@ -655,6 +730,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
*
Expand All @@ -670,9 +749,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.
*/
Comment thread
bardliao marked this conversation as resolved.
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 */
Expand All @@ -682,6 +772,16 @@ int sdw_compute_params(struct sdw_bus *bus, struct sdw_stream_runtime *stream)
return ret;
}

if (stream->type == SDW_STREAM_BPT && stream->state == SDW_STREAM_CONFIGURED) {
/* No usable data columns left */
if (bus->bpt_hstop < 1) {
Comment thread
bardliao marked this conversation as resolved.
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);
Expand Down
6 changes: 3 additions & 3 deletions drivers/soundwire/intel_ace2x.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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_,
Expand All @@ -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,
Expand Down
Loading
Loading