Commit 72deda0a authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull soundwire updates from Vinod Koul:

 - SoundWire multi lane support to use multiple lanes if supported

 - Stream handling of DEPREPARED state

 - AMD wake register programming for power off mode

* tag 'soundwire-6.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire:
  soundwire: amd: clear wake enable register for power off mode
  soundwire: generic_bandwidth_allocation: count the bandwidth of active streams only
  SoundWire: pass stream to compute_params()
  soundwire: generic_bandwidth_allocation: add lane in sdw_group_params
  soundwire: generic_bandwidth_allocation: select data lane
  soundwire: generic_bandwidth_allocation: check required freq accurately
  soundwire: generic_bandwidth_allocation: correct clk_freq check in sdw_select_row_col
  Soundwire: generic_bandwidth_allocation: set frame shape on fly
  Soundwire: stream: program BUSCLOCK_SCALE
  Soundwire: add sdw_slave_get_scale_index helper
  soundwire: generic_bandwidth_allocation: skip DEPREPARED streams
  soundwire: stream: set DEPREPARED state earlier
  soundwire: add lane_used_bandwidth in struct sdw_bus
  soundwire: mipi_disco: read lane mapping properties from ACPI
  soundwire: add lane field in sdw_port_runtime
  soundwire: bus: Move irq mapping cleanup into devres
parents 9f10e7fb 74148bb5
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -384,7 +384,7 @@ static u32 amd_sdw_read_ping_status(struct sdw_bus *bus)
	return slave_stat;
}

static int amd_sdw_compute_params(struct sdw_bus *bus)
static int amd_sdw_compute_params(struct sdw_bus *bus, struct sdw_stream_runtime *stream)
{
	struct sdw_transport_data t_data = {0};
	struct sdw_master_runtime *m_rt;
@@ -410,7 +410,7 @@ static int amd_sdw_compute_params(struct sdw_bus *bus)
			sdw_fill_xport_params(&p_rt->transport_params, p_rt->num,
					      false, SDW_BLK_GRP_CNT_1, sample_int,
					      port_bo, port_bo >> 8, hstart, hstop,
					      SDW_BLK_PKG_PER_PORT, 0x0);
					      SDW_BLK_PKG_PER_PORT, p_rt->lane);

			sdw_fill_port_params(&p_rt->port_params,
					     p_rt->num, bps,
@@ -1190,6 +1190,7 @@ static int __maybe_unused amd_resume_runtime(struct device *dev)
	if (amd_manager->power_mode_mask & AMD_SDW_CLK_STOP_MODE) {
		return amd_sdw_clock_stop_exit(amd_manager);
	} else if (amd_manager->power_mode_mask & AMD_SDW_POWER_OFF_MODE) {
		writel(0x00, amd_manager->acp_mmio + ACP_SW_WAKE_EN(amd_manager->instance));
		val = readl(amd_manager->mmio + ACP_SW_CLK_RESUME_CTRL);
		if (val) {
			val |= AMD_SDW_CLK_RESUME_REQ;
+44 −21
Original line number Diff line number Diff line
@@ -813,6 +813,16 @@ void sdw_extract_slave_id(struct sdw_bus *bus,
}
EXPORT_SYMBOL(sdw_extract_slave_id);

bool is_clock_scaling_supported_by_slave(struct sdw_slave *slave)
{
	/*
	 * Dynamic scaling is a defined by SDCA. However, some devices expose the class ID but
	 * can't support dynamic scaling. We might need a quirk to handle such devices.
	 */
	return slave->id.class_id;
}
EXPORT_SYMBOL(is_clock_scaling_supported_by_slave);

static int sdw_program_device_num(struct sdw_bus *bus, bool *programmed)
{
	u8 buf[SDW_NUM_DEV_ID_REGISTERS] = {0};
@@ -1276,23 +1286,12 @@ int sdw_configure_dpn_intr(struct sdw_slave *slave,
	return ret;
}

static int sdw_slave_set_frequency(struct sdw_slave *slave)
int sdw_slave_get_scale_index(struct sdw_slave *slave, u8 *base)
{
	u32 mclk_freq = slave->bus->prop.mclk_freq;
	u32 curr_freq = slave->bus->params.curr_dr_freq >> 1;
	unsigned int scale;
	u8 scale_index;
	u8 base;
	int ret;

	/*
	 * frequency base and scale registers are required for SDCA
	 * devices. They may also be used for 1.2+/non-SDCA devices.
	 * Driver can set the property, we will need a DisCo property
	 * to discover this case from platform firmware.
	 */
	if (!slave->id.class_id && !slave->prop.clock_reg_supported)
		return 0;

	if (!mclk_freq) {
		dev_err(&slave->dev,
@@ -1311,19 +1310,19 @@ static int sdw_slave_set_frequency(struct sdw_slave *slave)
	 */
	if (!(19200000 % mclk_freq)) {
		mclk_freq = 19200000;
		base = SDW_SCP_BASE_CLOCK_19200000_HZ;
		*base = SDW_SCP_BASE_CLOCK_19200000_HZ;
	} else if (!(22579200 % mclk_freq)) {
		mclk_freq = 22579200;
		base = SDW_SCP_BASE_CLOCK_22579200_HZ;
		*base = SDW_SCP_BASE_CLOCK_22579200_HZ;
	} else if (!(24576000 % mclk_freq)) {
		mclk_freq = 24576000;
		base = SDW_SCP_BASE_CLOCK_24576000_HZ;
		*base = SDW_SCP_BASE_CLOCK_24576000_HZ;
	} else if (!(32000000 % mclk_freq)) {
		mclk_freq = 32000000;
		base = SDW_SCP_BASE_CLOCK_32000000_HZ;
		*base = SDW_SCP_BASE_CLOCK_32000000_HZ;
	} else if (!(96000000 % mclk_freq)) {
		mclk_freq = 24000000;
		base = SDW_SCP_BASE_CLOCK_24000000_HZ;
		*base = SDW_SCP_BASE_CLOCK_24000000_HZ;
	} else {
		dev_err(&slave->dev,
			"Unsupported clock base, mclk %d\n",
@@ -1354,6 +1353,34 @@ static int sdw_slave_set_frequency(struct sdw_slave *slave)
	}
	scale_index++;

	dev_dbg(&slave->dev,
		"Configured bus base %d, scale %d, mclk %d, curr_freq %d\n",
		*base, scale_index, mclk_freq, curr_freq);

	return scale_index;
}
EXPORT_SYMBOL(sdw_slave_get_scale_index);

static int sdw_slave_set_frequency(struct sdw_slave *slave)
{
	int scale_index;
	u8 base;
	int ret;

	/*
	 * frequency base and scale registers are required for SDCA
	 * devices. They may also be used for 1.2+/non-SDCA devices.
	 * Driver can set the property directly, for now there's no
	 * DisCo property to discover support for the scaling registers
	 * from platform firmware.
	 */
	if (!slave->id.class_id && !slave->prop.clock_reg_supported)
		return 0;

	scale_index = sdw_slave_get_scale_index(slave, &base);
	if (scale_index < 0)
		return scale_index;

	ret = sdw_write_no_pm(slave, SDW_SCP_BUS_CLOCK_BASE, base);
	if (ret < 0) {
		dev_err(&slave->dev,
@@ -1373,10 +1400,6 @@ static int sdw_slave_set_frequency(struct sdw_slave *slave)
		dev_err(&slave->dev,
			"SDW_SCP_BUSCLOCK_SCALE_B1 write failed:%d\n", ret);

	dev_dbg(&slave->dev,
		"Configured bus base %d, scale %d, mclk %d, curr_freq %d\n",
		base, scale_index, mclk_freq, curr_freq);

	return ret;
}

+3 −0
Original line number Diff line number Diff line
@@ -90,6 +90,7 @@ int sdw_find_col_index(int col);
 * @transport_params: Transport parameters
 * @port_params: Port parameters
 * @port_node: List node for Master or Slave port_list
 * @lane: Which lane is used
 *
 * SoundWire spec has no mention of ports for Master interface but the
 * concept is logically extended.
@@ -100,6 +101,7 @@ struct sdw_port_runtime {
	struct sdw_transport_params transport_params;
	struct sdw_port_params port_params;
	struct list_head port_node;
	unsigned int lane;
};

/**
@@ -149,6 +151,7 @@ struct sdw_transport_data {
	int hstop;
	int block_offset;
	int sub_block_offset;
	unsigned int lane;
};

struct sdw_dpn_prop *sdw_get_slave_dpn_prop(struct sdw_slave *slave,
+0 −3
Original line number Diff line number Diff line
@@ -167,9 +167,6 @@ static int sdw_drv_remove(struct device *dev)

	slave->probed = false;

	if (slave->prop.use_domain_irq)
		sdw_irq_dispose_mapping(slave);

	mutex_unlock(&slave->sdw_dev_lock);

	if (drv->remove)
+267 −49
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@

struct sdw_group_params {
	unsigned int rate;
	unsigned int lane;
	int full_bw;
	int payload_bw;
	int hwidth;
@@ -27,6 +28,7 @@ struct sdw_group {
	unsigned int count;
	unsigned int max_size;
	unsigned int *rates;
	unsigned int *lanes;
};

void sdw_compute_slave_ports(struct sdw_master_runtime *m_rt,
@@ -48,6 +50,9 @@ void sdw_compute_slave_ports(struct sdw_master_runtime *m_rt,
		slave_total_ch = 0;

		list_for_each_entry(p_rt, &s_rt->port_list, port_node) {
			if (p_rt->lane != t_data->lane)
				continue;

			ch = hweight32(p_rt->ch_mask);

			sdw_fill_xport_params(&p_rt->transport_params,
@@ -56,7 +61,7 @@ void sdw_compute_slave_ports(struct sdw_master_runtime *m_rt,
					      sample_int, port_bo, port_bo >> 8,
					      t_data->hstart,
					      t_data->hstop,
					      SDW_BLK_PKG_PER_PORT, 0x0);
					      SDW_BLK_PKG_PER_PORT, p_rt->lane);

			sdw_fill_port_params(&p_rt->port_params,
					     p_rt->num, bps,
@@ -105,11 +110,13 @@ static void sdw_compute_master_ports(struct sdw_master_runtime *m_rt,
	t_data.hstart = hstart;

	list_for_each_entry(p_rt, &m_rt->port_list, port_node) {
		if (p_rt->lane != params->lane)
			continue;

		sdw_fill_xport_params(&p_rt->transport_params, p_rt->num,
				      false, SDW_BLK_GRP_CNT_1, sample_int,
				      *port_bo, (*port_bo) >> 8, hstart, hstop,
				      SDW_BLK_PKG_PER_PORT, 0x0);
				      SDW_BLK_PKG_PER_PORT, p_rt->lane);

		sdw_fill_port_params(&p_rt->port_params,
				     p_rt->num, bps,
@@ -131,6 +138,7 @@ static void sdw_compute_master_ports(struct sdw_master_runtime *m_rt,
		(*port_bo) += bps * ch;
	}

	t_data.lane = params->lane;
	sdw_compute_slave_ports(m_rt, &t_data);
}

@@ -138,11 +146,18 @@ static void _sdw_compute_port_params(struct sdw_bus *bus,
				     struct sdw_group_params *params, int count)
{
	struct sdw_master_runtime *m_rt;
	int hstop = bus->params.col - 1;
	int port_bo, i;
	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) {
@@ -152,55 +167,86 @@ static void _sdw_compute_port_params(struct sdw_bus *bus,
			hstop = hstop - params[i].hwidth;
		}
	}
}

static int sdw_compute_group_params(struct sdw_bus *bus,
				    struct sdw_stream_runtime *stream,
				    struct sdw_group_params *params,
				    int *rates, int count)
				    struct sdw_group *group)
{
	struct sdw_master_runtime *m_rt;
	struct sdw_port_runtime *p_rt;
	int sel_col = bus->params.col;
	unsigned int rate, bps, ch;
	int i, column_needed = 0;
	int i, l, column_needed;

	/* Calculate bandwidth per group */
	for (i = 0; i < count; i++) {
		params[i].rate = rates[i];
	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 state) and paused (DISABLED state)
			 * streams
			 */
			if (m_rt->stream->state != SDW_STREAM_ENABLED &&
			    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 = m_rt->ch_count;
			ch = hweight32(p_rt->ch_mask);

		for (i = 0; i < count; i++) {
			if (rate == params[i].rate)
			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 (i = 0; i < count; i++) {
		params[i].hwidth = (sel_col *
			params[i].payload_bw + params[i].full_bw - 1) /
			params[i].full_bw;
	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;

			params[i].hwidth = (sel_col * params[i].payload_bw +
					    params[i].full_bw - 1) / params[i].full_bw;

			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;
		}
	}

	if (column_needed > sel_col - 1)
		return -EINVAL;

	return 0;
}

static int sdw_add_element_group_count(struct sdw_group *group,
				       unsigned int rate)
				       unsigned int rate, unsigned int lane)
{
	int num = group->count;
	int i;

	for (i = 0; i <= num; i++) {
		if (rate == group->rates[i])
		if (rate == group->rates[i] && lane == group->lanes[i])
			break;

		if (i != num)
@@ -208,6 +254,7 @@ static int sdw_add_element_group_count(struct sdw_group *group,

		if (group->count >= group->max_size) {
			unsigned int *rates;
			unsigned int *lanes;

			group->max_size += 1;
			rates = krealloc(group->rates,
@@ -215,10 +262,20 @@ static int sdw_add_element_group_count(struct sdw_group *group,
					 GFP_KERNEL);
			if (!rates)
				return -ENOMEM;

			group->rates = rates;

			lanes = krealloc(group->lanes,
					 (sizeof(int) * group->max_size),
					 GFP_KERNEL);
			if (!lanes)
				return -ENOMEM;

			group->lanes = lanes;
		}

		group->rates[group->count++] = rate;
		group->rates[group->count] = rate;
		group->lanes[group->count++] = lane;
	}

	return 0;
@@ -228,6 +285,7 @@ static int sdw_get_group_count(struct sdw_bus *bus,
			       struct sdw_group *group)
{
	struct sdw_master_runtime *m_rt;
	struct sdw_port_runtime *p_rt;
	unsigned int rate;
	int ret = 0;

@@ -237,17 +295,32 @@ static int sdw_get_group_count(struct sdw_bus *bus,
	if (!group->rates)
		return -ENOMEM;

	group->lanes = kcalloc(group->max_size, sizeof(int), GFP_KERNEL);
	if (!group->lanes) {
		kfree(group->rates);
		group->rates = NULL;
		return -ENOMEM;
	}

	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;

		} else {
			ret = sdw_add_element_group_count(group, 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;
			}
		}
@@ -260,8 +333,9 @@ static int sdw_get_group_count(struct sdw_bus *bus,
 * sdw_compute_port_params: Compute transport and port parameters
 *
 * @bus: SDW Bus instance
 * @stream: Soundwire stream
 */
static int sdw_compute_port_params(struct sdw_bus *bus)
static int sdw_compute_port_params(struct sdw_bus *bus, struct sdw_stream_runtime *stream)
{
	struct sdw_group_params *params = NULL;
	struct sdw_group group;
@@ -281,8 +355,7 @@ static int sdw_compute_port_params(struct sdw_bus *bus)
	}

	/* Compute transport parameters for grouped streams */
	ret = sdw_compute_group_params(bus, params,
				       &group.rates[0], group.count);
	ret = sdw_compute_group_params(bus, stream, params, &group);
	if (ret < 0)
		goto free_params;

@@ -292,6 +365,7 @@ static int sdw_compute_port_params(struct sdw_bus *bus)
	kfree(params);
out:
	kfree(group.rates);
	kfree(group.lanes);

	return ret;
}
@@ -299,7 +373,6 @@ static int sdw_compute_port_params(struct sdw_bus *bus)
static int sdw_select_row_col(struct sdw_bus *bus, int clk_freq)
{
	struct sdw_master_prop *prop = &bus->prop;
	int frame_int, frame_freq;
	int r, c;

	for (c = 0; c < SDW_FRAME_COLS; c++) {
@@ -308,11 +381,8 @@ static int sdw_select_row_col(struct sdw_bus *bus, int clk_freq)
			    sdw_cols[c] != prop->default_col)
				continue;

			frame_int = sdw_rows[r] * sdw_cols[c];
			frame_freq = clk_freq / frame_int;

			if ((clk_freq - (frame_freq * SDW_FRAME_CTRL_BITS)) <
			    bus->params.bandwidth)
			if (clk_freq * (sdw_cols[c] - 1) <
			    bus->params.bandwidth * sdw_cols[c])
				continue;

			bus->params.row = sdw_rows[r];
@@ -324,6 +394,95 @@ static int sdw_select_row_col(struct sdw_bus *bus, int clk_freq)
	return -EINVAL;
}

static bool is_clock_scaling_supported(struct sdw_bus *bus)
{
	struct sdw_master_runtime *m_rt;
	struct sdw_slave_runtime *s_rt;

	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))
				return false;

	return true;
}

/**
 * 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
 */
static bool is_lane_connected_to_all_peripherals(struct sdw_master_runtime *m_rt, unsigned int 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);
			return false;
		}
	}
	return true;
}

static int get_manager_lane(struct sdw_bus *bus, struct sdw_master_runtime *m_rt,
			    struct sdw_slave_runtime *s_rt, unsigned int curr_dr_freq)
{
	struct sdw_slave_prop *slave_prop = &s_rt->slave->prop;
	struct sdw_port_runtime *m_p_rt;
	unsigned int required_bandwidth;
	int m_lane;
	int l;

	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;
}

/**
 * sdw_compute_bus_params: Compute bus parameters
 *
@@ -331,10 +490,16 @@ static int sdw_select_row_col(struct sdw_bus *bus, int clk_freq)
 */
static int sdw_compute_bus_params(struct sdw_bus *bus)
{
	unsigned int curr_dr_freq = 0;
	struct sdw_master_prop *mstr_prop = &bus->prop;
	int i, clk_values, ret;
	struct sdw_slave_prop *slave_prop;
	struct sdw_port_runtime *m_p_rt;
	struct sdw_port_runtime *s_p_rt;
	struct sdw_master_runtime *m_rt;
	struct sdw_slave_runtime *s_rt;
	unsigned int curr_dr_freq = 0;
	int i, l, clk_values, ret;
	bool is_gear = false;
	int m_lane = 0;
	u32 *clk_buf;

	if (mstr_prop->num_clk_gears) {
@@ -349,6 +514,10 @@ 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))
		clk_values = 1;

	for (i = 0; i < clk_values; i++) {
		if (!clk_buf)
			curr_dr_freq = bus->params.max_dr_freq;
@@ -357,11 +526,27 @@ 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 <= bus->params.bandwidth)
			continue;

		if (curr_dr_freq * (mstr_prop->default_col - 1) >=
		    bus->params.bandwidth * mstr_prop->default_col)
			break;

		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
@@ -374,6 +559,38 @@ static int sdw_compute_bus_params(struct sdw_bus *bus)
			__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;

	mstr_prop->default_col = curr_dr_freq / mstr_prop->default_frame_rate /
				 mstr_prop->default_row;

	ret = sdw_select_row_col(bus, curr_dr_freq);
	if (ret < 0) {
@@ -390,8 +607,9 @@ static int sdw_compute_bus_params(struct sdw_bus *bus)
 * sdw_compute_params: Compute bus, transport and port parameters
 *
 * @bus: SDW Bus instance
 * @stream: Soundwire stream
 */
int sdw_compute_params(struct sdw_bus *bus)
int sdw_compute_params(struct sdw_bus *bus, struct sdw_stream_runtime *stream)
{
	int ret;

@@ -401,7 +619,7 @@ int sdw_compute_params(struct sdw_bus *bus)
		return ret;

	/* Compute transport and port params */
	ret = sdw_compute_port_params(bus);
	ret = sdw_compute_port_params(bus, stream);
	if (ret < 0) {
		dev_err(bus->dev, "Compute transport params failed: %d\n", ret);
		return ret;
Loading