if (m_rt->direction == SDW_DATA_DIR_TX &&
m_rt->ch_count == slave_total_ch) { /* * Slave devices were configured to access all channels * of the stream, which indicates that they operate in * 'mirror mode'. Make sure we reset the port offset for * the next device in the list
*/
port_bo = t_data->block_offset;
}
}
}
EXPORT_SYMBOL(sdw_compute_slave_ports);
staticvoid _sdw_compute_port_params(struct sdw_bus *bus, struct sdw_group_params *params, int count)
{ struct sdw_master_runtime *m_rt; int port_bo, i, l; int 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]) continue; /* reset hstop for each lane */
hstop = bus->params.col - 1; for (i = 0; i < count; i++) { if (params[i].lane != l) continue;
port_bo = 1;
list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) { /* * Only runtimes with CONFIGURED, PREPARED, ENABLED, and DISABLED * states should be included in the bandwidth calculation.
*/ if (m_rt->stream->state > SDW_STREAM_DISABLED ||
m_rt->stream->state < SDW_STREAM_CONFIGURED) continue;
sdw_compute_master_ports(m_rt, ¶ms[i], &port_bo, hstop);
}
/* Calculate bandwidth per group */ for (i = 0; i < group->count; i++) {
params[i].rate = group->rates[i];
params[i].lane = group->lanes[i];
params[i].full_bw = bus->params.curr_dr_freq / params[i].rate;
}
list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) { if (m_rt->stream == stream) { /* Only runtime during prepare should be added */ if (stream->state != SDW_STREAM_CONFIGURED) continue;
} else { /* * Include runtimes with running (ENABLED/PREPARED state) and * paused (DISABLED state) streams
*/ if (m_rt->stream->state != SDW_STREAM_ENABLED &&
m_rt->stream->state != SDW_STREAM_PREPARED &&
m_rt->stream->state != SDW_STREAM_DISABLED) continue;
}
list_for_each_entry(p_rt, &m_rt->port_list, port_node) {
rate = m_rt->stream->params.rate;
bps = m_rt->stream->params.bps;
ch = hweight32(p_rt->ch_mask);
for (i = 0; i < group->count; i++) { if (rate == params[i].rate && p_rt->lane == params[i].lane)
params[i].payload_bw += bps * ch;
}
}
}
for (l = 0; l < SDW_MAX_LANES; l++) { if (l > 0 && !bus->lane_used_bandwidth[l]) continue; /* reset column_needed for each lane */
column_needed = 0; for (i = 0; i < group->count; i++) { if (params[i].lane != l) continue;
column_needed += params[i].hwidth; /* 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) return -EINVAL;
}
}
return 0;
}
staticint sdw_add_element_group_count(struct sdw_group *group, unsignedint rate, unsignedint lane)
{ int num = group->count; int i;
for (i = 0; i <= num; i++) { if (rate == group->rates[i] && lane == group->lanes[i]) break;
if (i != num) continue;
if (group->count >= group->max_size) { unsignedint *rates; unsignedint *lanes;
list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) { if (m_rt->stream->state == SDW_STREAM_DEPREPARED) continue;
rate = m_rt->stream->params.rate; if (m_rt == list_first_entry(&bus->m_rt_list, struct sdw_master_runtime,
bus_node)) {
group->rates[group->count++] = rate;
} /* * Different ports could use different lane, add group element * even if m_rt is the first entry
*/
list_for_each_entry(p_rt, &m_rt->port_list, port_node) {
ret = sdw_add_element_group_count(group, rate, p_rt->lane); if (ret < 0) {
kfree(group->rates);
kfree(group->lanes); return ret;
}
}
}
return ret;
}
/** * sdw_compute_port_params: Compute transport and port parameters * * @bus: SDW Bus instance * @stream: Soundwire stream
*/ staticint sdw_compute_port_params(struct sdw_bus *bus, struct sdw_stream_runtime *stream)
{ struct sdw_group_params *params = NULL; struct sdw_group group; int ret;
ret = sdw_get_group_count(bus, &group); if (ret < 0) return ret;
if (group.count == 0) goto out;
params = kcalloc(group.count, sizeof(*params), GFP_KERNEL); if (!params) {
ret = -ENOMEM; goto out;
}
/* Compute transport parameters for grouped streams */
ret = sdw_compute_group_params(bus, stream, params, &group); if (ret < 0) goto free_params;
list_for_each_entry(m_rt, &bus->m_rt_list, bus_node)
list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) if (!is_clock_scaling_supported_by_slave(s_rt->slave)) returnfalse;
returntrue;
}
/** * is_lane_connected_to_all_peripherals: Check if the given manager lane connects to all peripherals * So that all peripherals can use the manager lane. * * @m_rt: Manager runtime * @lane: Lane number
*/ staticbool is_lane_connected_to_all_peripherals(struct sdw_master_runtime *m_rt, unsignedint lane)
{ struct sdw_slave_prop *slave_prop; struct sdw_slave_runtime *s_rt; int i;
list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) {
slave_prop = &s_rt->slave->prop; for (i = 1; i < SDW_MAX_LANES; i++) { if (slave_prop->lane_maps[i] == lane) {
dev_dbg(&s_rt->slave->dev, "M lane %d is connected to P lane %d\n",
lane, i); break;
}
} if (i == SDW_MAX_LANES) {
dev_dbg(&s_rt->slave->dev, "M lane %d is not connected\n", lane); returnfalse;
}
} returntrue;
}
for (l = 1; l < SDW_MAX_LANES; l++) { if (!slave_prop->lane_maps[l]) continue;
required_bandwidth = 0;
list_for_each_entry(m_p_rt, &m_rt->port_list, port_node) {
required_bandwidth += m_rt->stream->params.rate *
hweight32(m_p_rt->ch_mask) *
m_rt->stream->params.bps;
} if (required_bandwidth <=
curr_dr_freq - bus->lane_used_bandwidth[l]) { /* Check if m_lane is connected to all Peripherals */ if (!is_lane_connected_to_all_peripherals(m_rt,
slave_prop->lane_maps[l])) {
dev_dbg(bus->dev, "Not all Peripherals are connected to M lane %d\n",
slave_prop->lane_maps[l]); continue;
}
m_lane = slave_prop->lane_maps[l];
dev_dbg(&s_rt->slave->dev, "M lane %d is used\n", m_lane);
bus->lane_used_bandwidth[l] += required_bandwidth; /* * Use non-zero manager lane, subtract the lane 0 * bandwidth that is already calculated
*/
bus->params.bandwidth -= required_bandwidth; return m_lane;
}
}
/* No available multi lane found, only lane 0 can be used */ return 0;
}
list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) { /* * 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 * multi-lane if we can't find any available lane for the first Peripheral.
*/
s_rt = list_first_entry(&m_rt->slave_rt_list, struct sdw_slave_runtime, m_rt_node);
/* * Find the available Manager lane that connected to the first Peripheral.
*/
m_lane = get_manager_lane(bus, m_rt, s_rt, curr_dr_freq); if (m_lane > 0) goto out;
}
/* * TODO: Check all the Slave(s) port(s) audio modes and find * whether given clock rate is supported with glitchless * transition.
*/
}
if (i == clk_values) {
dev_err(bus->dev, "%s: could not find clock value for bandwidth %d\n",
__func__, bus->params.bandwidth); return -EINVAL;
}
out: /* multilane can be used */ if (m_lane > 0) { /* Set Peripheral lanes */
list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) {
slave_prop = &s_rt->slave->prop; for (l = 1; l < SDW_MAX_LANES; l++) { if (slave_prop->lane_maps[l] == m_lane) {
list_for_each_entry(s_p_rt, &s_rt->port_list, port_node) {
s_p_rt->lane = l;
dev_dbg(&s_rt->slave->dev, "Set P lane %d for port %d\n",
l, s_p_rt->num);
} break;
}
}
} /* * Set Manager lanes. Configure the last m_rt in bus->m_rt_list only since * we don't want to touch other m_rts that are already working.
*/
list_for_each_entry(m_p_rt, &m_rt->port_list, port_node) {
m_p_rt->lane = m_lane;
}
}
if (!mstr_prop->default_frame_rate || !mstr_prop->default_row) return -EINVAL;
ret = sdw_select_row_col(bus, curr_dr_freq); if (ret < 0) {
dev_err(bus->dev, "%s: could not find frame configuration for bus dr_freq %d\n",
__func__, curr_dr_freq); return -EINVAL;
}
/** * sdw_compute_params: Compute bus, transport and port parameters * * @bus: SDW Bus instance * @stream: Soundwire stream
*/ int sdw_compute_params(struct sdw_bus *bus, struct sdw_stream_runtime *stream)
{ int ret;
/* Computes clock frequency, frame shape and frame frequency */
ret = sdw_compute_bus_params(bus); if (ret < 0) return ret;
if (stream->type == SDW_STREAM_BPT) {
sdw_compute_dp0_port_params(bus); return 0;
}
/* Compute transport and port params */
ret = sdw_compute_port_params(bus, stream); if (ret < 0) {
dev_err(bus->dev, "Compute transport params failed: %d\n", ret); return ret;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.