Linux Sound subsystem development
 help / color / mirror / Atom feed
* [PATCH v2 00/14] soundwire: add multi-lane support
@ 2024-12-03 13:17 Bard Liao
  2024-12-03 13:18 ` [PATCH v2 01/14] soundwire: add lane field in sdw_port_runtime Bard Liao
                   ` (13 more replies)
  0 siblings, 14 replies; 17+ messages in thread
From: Bard Liao @ 2024-12-03 13:17 UTC (permalink / raw)
  To: linux-sound, vkoul
  Cc: vinod.koul, linux-kernel, pierre-louis.bossart, bard.liao

This series adds multi-lane support for SoundWire. We will get the lane
connection information from ACPI and use multiple lanes if the bandwidth
is not enough.

v2:
 - add 2 commits to fix the issue of starting streams simultaneously

Bard Liao (12):
  soundwire: add lane field in sdw_port_runtime
  soundwire: mipi_disco: read lane mapping properties from ACPI
  soundwire: add lane_used_bandwidth in struct sdw_bus
  Soundwire: add sdw_slave_get_scale_index helper
  Soundwire: stream: program BUSCLOCK_SCALE
  Soundwire: generic_bandwidth_allocation: set frame shape on fly
  soundwire: generic_bandwidth_allocation: correct clk_freq check in
    sdw_select_row_col
  soundwire: generic_bandwidth_allocation: check required freq
    accurately
  soundwire: generic_bandwidth_allocation: select data lane
  soundwire: generic_bandwidth_allocation: add lane in sdw_group_params
  SoundWire: pass stream to compute_params()
  soundwire: generic_bandwidth_allocation: count the bandwidth of active
    streams only

Pierre-Louis Bossart (2):
  soundwire: stream: set DEPREPARED state earlier
  soundwire: generic_bandwidth_allocation: skip DEPREPARED streams

 drivers/soundwire/amd_manager.c               |   4 +-
 drivers/soundwire/bus.c                       |  65 ++--
 drivers/soundwire/bus.h                       |   3 +
 .../soundwire/generic_bandwidth_allocation.c  | 316 +++++++++++++++---
 drivers/soundwire/mipi_disco.c                |  40 ++-
 drivers/soundwire/qcom.c                      |   2 +-
 drivers/soundwire/stream.c                    |  67 +++-
 include/linux/soundwire/sdw.h                 | 192 ++++++-----
 8 files changed, 519 insertions(+), 170 deletions(-)

-- 
2.43.0


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH v2 01/14] soundwire: add lane field in sdw_port_runtime
  2024-12-03 13:17 [PATCH v2 00/14] soundwire: add multi-lane support Bard Liao
@ 2024-12-03 13:18 ` Bard Liao
  2024-12-03 13:18 ` [PATCH v2 02/14] soundwire: mipi_disco: read lane mapping properties from ACPI Bard Liao
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 17+ messages in thread
From: Bard Liao @ 2024-12-03 13:18 UTC (permalink / raw)
  To: linux-sound, vkoul
  Cc: vinod.koul, linux-kernel, pierre-louis.bossart, bard.liao

Currently, lane_ctrl is always 0. Add a lane field in sdw_port_runtime
to indicate the data lane of the data port.
They are 0 by default.

Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
---
 drivers/soundwire/amd_manager.c                  | 2 +-
 drivers/soundwire/bus.h                          | 2 ++
 drivers/soundwire/generic_bandwidth_allocation.c | 4 ++--
 3 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/soundwire/amd_manager.c b/drivers/soundwire/amd_manager.c
index 5a4bfaef65fb..f47d4cd656ae 100644
--- a/drivers/soundwire/amd_manager.c
+++ b/drivers/soundwire/amd_manager.c
@@ -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,
diff --git a/drivers/soundwire/bus.h b/drivers/soundwire/bus.h
index fda6b24ac2da..ff03b97f1d8b 100644
--- a/drivers/soundwire/bus.h
+++ b/drivers/soundwire/bus.h
@@ -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;
 };
 
 /**
diff --git a/drivers/soundwire/generic_bandwidth_allocation.c b/drivers/soundwire/generic_bandwidth_allocation.c
index b9316207c3ab..abf9b85daa52 100644
--- a/drivers/soundwire/generic_bandwidth_allocation.c
+++ b/drivers/soundwire/generic_bandwidth_allocation.c
@@ -56,7 +56,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,
@@ -109,7 +109,7 @@ static void sdw_compute_master_ports(struct sdw_master_runtime *m_rt,
 		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,
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v2 02/14] soundwire: mipi_disco: read lane mapping properties from ACPI
  2024-12-03 13:17 [PATCH v2 00/14] soundwire: add multi-lane support Bard Liao
  2024-12-03 13:18 ` [PATCH v2 01/14] soundwire: add lane field in sdw_port_runtime Bard Liao
@ 2024-12-03 13:18 ` Bard Liao
  2024-12-03 13:18 ` [PATCH v2 03/14] soundwire: add lane_used_bandwidth in struct sdw_bus Bard Liao
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 17+ messages in thread
From: Bard Liao @ 2024-12-03 13:18 UTC (permalink / raw)
  To: linux-sound, vkoul
  Cc: vinod.koul, linux-kernel, pierre-louis.bossart, bard.liao

The DisCo for SoundWire 2.0 added support for the
'mipi-sdw-lane-<n>-mapping' property.

Co-developed-by: Chao Song <chao.song@linux.intel.com>
Signed-off-by: Chao Song <chao.song@linux.intel.com>
Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
---
 drivers/soundwire/mipi_disco.c | 40 +++++++++++++++++++++++++++++++++-
 include/linux/soundwire/sdw.h  |  5 +++++
 2 files changed, 44 insertions(+), 1 deletion(-)

diff --git a/drivers/soundwire/mipi_disco.c b/drivers/soundwire/mipi_disco.c
index 9d59f486edbe..65afb28ef8fa 100644
--- a/drivers/soundwire/mipi_disco.c
+++ b/drivers/soundwire/mipi_disco.c
@@ -366,6 +366,44 @@ static int sdw_slave_read_dpn(struct sdw_slave *slave,
 	return 0;
 }
 
+/*
+ * In MIPI DisCo spec for SoundWire, lane mapping for a slave device is done with
+ * mipi-sdw-lane-x-mapping properties, where x is 1..7, and the values for those
+ * properties are mipi-sdw-manager-lane-x or mipi-sdw-peripheral-link-y, where x
+ * is an integer between 1 to 7 if the lane is connected to a manager lane, y is a
+ * character between A to E if the lane is connected to another peripheral lane.
+ */
+int sdw_slave_read_lane_mapping(struct sdw_slave *slave)
+{
+	struct sdw_slave_prop *prop = &slave->prop;
+	struct device *dev = &slave->dev;
+	char prop_name[30];
+	const char *prop_val;
+	size_t len;
+	int ret, i;
+	u8 lane;
+
+	for (i = 0; i < SDW_MAX_LANES; i++) {
+		snprintf(prop_name, sizeof(prop_name), "mipi-sdw-lane-%d-mapping", i);
+		ret = device_property_read_string(dev, prop_name, &prop_val);
+		if (ret)
+			continue;
+
+		len = strlen(prop_val);
+		if (len < 1)
+			return -EINVAL;
+
+		/* The last character is enough to identify the connection */
+		ret = kstrtou8(&prop_val[len - 1], 10, &lane);
+		if (ret)
+			return ret;
+		if (in_range(lane, 1, SDW_MAX_LANES - 1))
+			prop->lane_maps[i] = lane;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(sdw_slave_read_lane_mapping);
+
 /**
  * sdw_slave_read_prop() - Read Slave properties
  * @slave: SDW Slave
@@ -486,6 +524,6 @@ int sdw_slave_read_prop(struct sdw_slave *slave)
 	sdw_slave_read_dpn(slave, prop->sink_dpn_prop, nval,
 			   prop->sink_ports, "sink");
 
-	return 0;
+	return sdw_slave_read_lane_mapping(slave);
 }
 EXPORT_SYMBOL(sdw_slave_read_prop);
diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h
index bd9836690da6..bb4e33a4db17 100644
--- a/include/linux/soundwire/sdw.h
+++ b/include/linux/soundwire/sdw.h
@@ -54,6 +54,8 @@ struct sdw_slave;
 #define SDW_MAX_PORTS			15
 #define SDW_VALID_PORT_RANGE(n)		((n) < SDW_MAX_PORTS && (n) >= 1)
 
+#define SDW_MAX_LANES		8
+
 enum {
 	SDW_PORT_DIRN_SINK = 0,
 	SDW_PORT_DIRN_SOURCE,
@@ -356,6 +358,7 @@ struct sdw_dpn_prop {
  * and masks are supported
  * @commit_register_supported: is PCP_Commit register supported
  * @scp_int1_mask: SCP_INT1_MASK desired settings
+ * @lane_maps: Lane mapping for the slave, only valid if lane_control_support is set
  * @clock_reg_supported: the Peripheral implements the clock base and scale
  * registers introduced with the SoundWire 1.2 specification. SDCA devices
  * do not need to set this boolean property as the registers are required.
@@ -385,6 +388,7 @@ struct sdw_slave_prop {
 	u32 sdca_interrupt_register_list;
 	u8 commit_register_supported;
 	u8 scp_int1_mask;
+	u8 lane_maps[SDW_MAX_LANES];
 	bool clock_reg_supported;
 	bool use_domain_irq;
 };
@@ -450,6 +454,7 @@ struct sdw_master_prop {
 
 int sdw_master_read_prop(struct sdw_bus *bus);
 int sdw_slave_read_prop(struct sdw_slave *slave);
+int sdw_slave_read_lane_mapping(struct sdw_slave *slave);
 
 /*
  * SDW Slave Structures and APIs
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v2 03/14] soundwire: add lane_used_bandwidth in struct sdw_bus
  2024-12-03 13:17 [PATCH v2 00/14] soundwire: add multi-lane support Bard Liao
  2024-12-03 13:18 ` [PATCH v2 01/14] soundwire: add lane field in sdw_port_runtime Bard Liao
  2024-12-03 13:18 ` [PATCH v2 02/14] soundwire: mipi_disco: read lane mapping properties from ACPI Bard Liao
@ 2024-12-03 13:18 ` Bard Liao
  2024-12-03 13:18 ` [PATCH v2 04/14] soundwire: stream: set DEPREPARED state earlier Bard Liao
                   ` (10 subsequent siblings)
  13 siblings, 0 replies; 17+ messages in thread
From: Bard Liao @ 2024-12-03 13:18 UTC (permalink / raw)
  To: linux-sound, vkoul
  Cc: vinod.koul, linux-kernel, pierre-louis.bossart, bard.liao

To support multi-lane, we need to know how much bandwidth
is used on each lane. And to use the lane that has enough
bandwidth.

Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
---
 include/linux/soundwire/sdw.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h
index bb4e33a4db17..ae38ac848d38 100644
--- a/include/linux/soundwire/sdw.h
+++ b/include/linux/soundwire/sdw.h
@@ -893,6 +893,7 @@ struct sdw_master_ops {
  * @multi_link: Store bus property that indicates if multi links
  * are supported. This flag is populated by drivers after reading
  * appropriate firmware (ACPI/DT).
+ * @lane_used_bandwidth: how much bandwidth in bits per second is used by each lane
  */
 struct sdw_bus {
 	struct device *dev;
@@ -924,6 +925,7 @@ struct sdw_bus {
 	struct dentry *debugfs;
 #endif
 	bool multi_link;
+	unsigned int lane_used_bandwidth[SDW_MAX_LANES];
 };
 
 int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent,
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v2 04/14] soundwire: stream: set DEPREPARED state earlier
  2024-12-03 13:17 [PATCH v2 00/14] soundwire: add multi-lane support Bard Liao
                   ` (2 preceding siblings ...)
  2024-12-03 13:18 ` [PATCH v2 03/14] soundwire: add lane_used_bandwidth in struct sdw_bus Bard Liao
@ 2024-12-03 13:18 ` Bard Liao
  2024-12-03 13:18 ` [PATCH v2 05/14] soundwire: generic_bandwidth_allocation: skip DEPREPARED streams Bard Liao
                   ` (9 subsequent siblings)
  13 siblings, 0 replies; 17+ messages in thread
From: Bard Liao @ 2024-12-03 13:18 UTC (permalink / raw)
  To: linux-sound, vkoul
  Cc: vinod.koul, linux-kernel, pierre-louis.bossart, bard.liao

From: Pierre-Louis Bossart <pierre-louis.bossart@linux.dev>

The existing logic is problematic in that we deprepare all the ports,
but still take into account the stream for bit allocation by just
walking through the bus->m_rt list.

This patch sets the state earlier, so that such DEPREPARED streams can
be skipped in the bandwidth allocation (to be implemented in a
follow-up patch).

Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.dev>
Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
---
 drivers/soundwire/stream.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c
index 7aa4900dcf31..795017c8081a 100644
--- a/drivers/soundwire/stream.c
+++ b/drivers/soundwire/stream.c
@@ -1643,8 +1643,15 @@ static int _sdw_deprepare_stream(struct sdw_stream_runtime *stream)
 {
 	struct sdw_master_runtime *m_rt;
 	struct sdw_bus *bus;
+	int state = stream->state;
 	int ret = 0;
 
+	/*
+	 * first mark the state as DEPREPARED so that it is not taken into account
+	 * for bit allocation
+	 */
+	stream->state = SDW_STREAM_DEPREPARED;
+
 	list_for_each_entry(m_rt, &stream->master_list, stream_node) {
 		bus = m_rt->bus;
 		/* De-prepare port(s) */
@@ -1652,6 +1659,7 @@ static int _sdw_deprepare_stream(struct sdw_stream_runtime *stream)
 		if (ret < 0) {
 			dev_err(bus->dev,
 				"De-prepare port(s) failed: %d\n", ret);
+			stream->state = state;
 			return ret;
 		}
 
@@ -1665,6 +1673,7 @@ static int _sdw_deprepare_stream(struct sdw_stream_runtime *stream)
 			if (ret < 0) {
 				dev_err(bus->dev, "Compute params failed: %d\n",
 					ret);
+				stream->state = state;
 				return ret;
 			}
 		}
@@ -1673,11 +1682,11 @@ static int _sdw_deprepare_stream(struct sdw_stream_runtime *stream)
 		ret = sdw_program_params(bus, false);
 		if (ret < 0) {
 			dev_err(bus->dev, "%s: Program params failed: %d\n", __func__, ret);
+			stream->state = state;
 			return ret;
 		}
 	}
 
-	stream->state = SDW_STREAM_DEPREPARED;
 	return do_bank_switch(stream);
 }
 
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v2 05/14] soundwire: generic_bandwidth_allocation: skip DEPREPARED streams
  2024-12-03 13:17 [PATCH v2 00/14] soundwire: add multi-lane support Bard Liao
                   ` (3 preceding siblings ...)
  2024-12-03 13:18 ` [PATCH v2 04/14] soundwire: stream: set DEPREPARED state earlier Bard Liao
@ 2024-12-03 13:18 ` Bard Liao
  2024-12-03 13:18 ` [PATCH v2 06/14] Soundwire: add sdw_slave_get_scale_index helper Bard Liao
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 17+ messages in thread
From: Bard Liao @ 2024-12-03 13:18 UTC (permalink / raw)
  To: linux-sound, vkoul
  Cc: vinod.koul, linux-kernel, pierre-louis.bossart, bard.liao

From: Pierre-Louis Bossart <pierre-louis.bossart@linux.dev>

We should not blindly walk through all the m_rt list, since it will
have the side effect of accounting for deprepared streams.

This behavior is the result of the split implementation where the
dailink hw_free() handles the stream state change and the bit
allocation, and the dai hw_free() modifies the m_rt list. The bit
allocation ends-up using m_rt entries in zombie state, no longer
relevant but still used.

Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.dev>
Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
---
 drivers/soundwire/generic_bandwidth_allocation.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/soundwire/generic_bandwidth_allocation.c b/drivers/soundwire/generic_bandwidth_allocation.c
index abf9b85daa52..2950a3d002ce 100644
--- a/drivers/soundwire/generic_bandwidth_allocation.c
+++ b/drivers/soundwire/generic_bandwidth_allocation.c
@@ -238,6 +238,9 @@ static int sdw_get_group_count(struct sdw_bus *bus,
 		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,
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v2 06/14] Soundwire: add sdw_slave_get_scale_index helper
  2024-12-03 13:17 [PATCH v2 00/14] soundwire: add multi-lane support Bard Liao
                   ` (4 preceding siblings ...)
  2024-12-03 13:18 ` [PATCH v2 05/14] soundwire: generic_bandwidth_allocation: skip DEPREPARED streams Bard Liao
@ 2024-12-03 13:18 ` Bard Liao
  2024-12-03 13:18 ` [PATCH v2 07/14] Soundwire: stream: program BUSCLOCK_SCALE Bard Liao
                   ` (7 subsequent siblings)
  13 siblings, 0 replies; 17+ messages in thread
From: Bard Liao @ 2024-12-03 13:18 UTC (permalink / raw)
  To: linux-sound, vkoul
  Cc: vinod.koul, linux-kernel, pierre-louis.bossart, bard.liao

Currently, we only set peripheral frequency when the peripheral is
initialized. However, curr_dr_freq may change to get required bandwidth.
For example, curr_dr_freq may increase from 4.8MHz to 9.6MHz when the
4th stream is opened. Add a helper to get the scale index so that we can
get the scale index and program it.

Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
---
 drivers/soundwire/bus.c       | 55 ++++++++++++++++++++++-------------
 include/linux/soundwire/sdw.h |  2 ++
 2 files changed, 36 insertions(+), 21 deletions(-)

diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c
index d1dc62c34f1c..215630d602ad 100644
--- a/drivers/soundwire/bus.c
+++ b/drivers/soundwire/bus.c
@@ -1276,23 +1276,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 +1300,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 +1343,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 +1390,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;
 }
 
diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h
index ae38ac848d38..05a85e2bd96d 100644
--- a/include/linux/soundwire/sdw.h
+++ b/include/linux/soundwire/sdw.h
@@ -1052,6 +1052,8 @@ int sdw_stream_add_slave(struct sdw_slave *slave,
 int sdw_stream_remove_slave(struct sdw_slave *slave,
 			    struct sdw_stream_runtime *stream);
 
+int sdw_slave_get_scale_index(struct sdw_slave *slave, u8 *base);
+
 /* messaging and data APIs */
 int sdw_read(struct sdw_slave *slave, u32 addr);
 int sdw_write(struct sdw_slave *slave, u32 addr, u8 value);
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v2 07/14] Soundwire: stream: program BUSCLOCK_SCALE
  2024-12-03 13:17 [PATCH v2 00/14] soundwire: add multi-lane support Bard Liao
                   ` (5 preceding siblings ...)
  2024-12-03 13:18 ` [PATCH v2 06/14] Soundwire: add sdw_slave_get_scale_index helper Bard Liao
@ 2024-12-03 13:18 ` Bard Liao
  2024-12-03 13:51   ` Richard Fitzgerald
  2024-12-03 13:18 ` [PATCH v2 08/14] Soundwire: generic_bandwidth_allocation: set frame shape on fly Bard Liao
                   ` (6 subsequent siblings)
  13 siblings, 1 reply; 17+ messages in thread
From: Bard Liao @ 2024-12-03 13:18 UTC (permalink / raw)
  To: linux-sound, vkoul
  Cc: vinod.koul, linux-kernel, pierre-louis.bossart, bard.liao

We need to program bus clock scale to adjust the bus clock if current
bus clock doesn't fit the bandwidth.

Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
---
 drivers/soundwire/bus.c       | 10 ++++++++++
 drivers/soundwire/stream.c    | 32 ++++++++++++++++++++++++++++++++
 include/linux/soundwire/sdw.h |  1 +
 3 files changed, 43 insertions(+)

diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c
index 215630d602ad..9b295fc9acd5 100644
--- a/drivers/soundwire/bus.c
+++ b/drivers/soundwire/bus.c
@@ -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};
diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c
index 795017c8081a..a4a668135d16 100644
--- a/drivers/soundwire/stream.c
+++ b/drivers/soundwire/stream.c
@@ -629,8 +629,40 @@ static int sdw_notify_config(struct sdw_master_runtime *m_rt)
 static int sdw_program_params(struct sdw_bus *bus, bool prepare)
 {
 	struct sdw_master_runtime *m_rt;
+	struct sdw_slave *slave;
 	int ret = 0;
+	u32 addr1;
 
+	/* Check if all Peripherals comply with SDCA */
+	list_for_each_entry(slave, &bus->slaves, node) {
+		if (!is_clock_scaling_supported_by_slave(slave)) {
+			dev_dbg(&slave->dev, "The Peripheral doesn't comply with SDCA\n");
+			goto manager_runtime;
+		}
+	}
+
+	if (bus->params.next_bank)
+		addr1 = SDW_SCP_BUSCLOCK_SCALE_B1;
+	else
+		addr1 = SDW_SCP_BUSCLOCK_SCALE_B0;
+
+	/* Program SDW_SCP_BUSCLOCK_SCALE if all Peripherals comply with SDCA */
+	list_for_each_entry(slave, &bus->slaves, node) {
+		int scale_index;
+		u8 base;
+
+		scale_index = sdw_slave_get_scale_index(slave, &base);
+		if (scale_index < 0)
+			return scale_index;
+
+		ret = sdw_write_no_pm(slave, addr1, scale_index);
+		if (ret < 0) {
+			dev_err(&slave->dev, "SDW_SCP_BUSCLOCK_SCALE register write failed\n");
+			return ret;
+		}
+	}
+
+manager_runtime:
 	list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) {
 
 		/*
diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h
index 05a85e2bd96d..fc0a203c3ae0 100644
--- a/include/linux/soundwire/sdw.h
+++ b/include/linux/soundwire/sdw.h
@@ -1041,6 +1041,7 @@ int sdw_bus_exit_clk_stop(struct sdw_bus *bus);
 
 int sdw_compare_devid(struct sdw_slave *slave, struct sdw_slave_id id);
 void sdw_extract_slave_id(struct sdw_bus *bus, u64 addr, struct sdw_slave_id *id);
+bool is_clock_scaling_supported_by_slave(struct sdw_slave *slave);
 
 #if IS_ENABLED(CONFIG_SOUNDWIRE)
 
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v2 08/14] Soundwire: generic_bandwidth_allocation: set frame shape on fly
  2024-12-03 13:17 [PATCH v2 00/14] soundwire: add multi-lane support Bard Liao
                   ` (6 preceding siblings ...)
  2024-12-03 13:18 ` [PATCH v2 07/14] Soundwire: stream: program BUSCLOCK_SCALE Bard Liao
@ 2024-12-03 13:18 ` Bard Liao
  2024-12-03 13:18 ` [PATCH v2 09/14] soundwire: generic_bandwidth_allocation: correct clk_freq check in sdw_select_row_col Bard Liao
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 17+ messages in thread
From: Bard Liao @ 2024-12-03 13:18 UTC (permalink / raw)
  To: linux-sound, vkoul
  Cc: vinod.koul, linux-kernel, pierre-louis.bossart, bard.liao

We need to recalculate frame shape when sdw bus clock is changed.
And need to make sure all Peripherals connected to the Manager support
dynamic clock change.

Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
---
 .../soundwire/generic_bandwidth_allocation.c  | 23 +++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/drivers/soundwire/generic_bandwidth_allocation.c b/drivers/soundwire/generic_bandwidth_allocation.c
index 2950a3d002ce..d847413141d3 100644
--- a/drivers/soundwire/generic_bandwidth_allocation.c
+++ b/drivers/soundwire/generic_bandwidth_allocation.c
@@ -327,6 +327,19 @@ 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;
+}
+
 /**
  * sdw_compute_bus_params: Compute bus parameters
  *
@@ -352,6 +365,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;
@@ -378,6 +395,12 @@ static int sdw_compute_bus_params(struct sdw_bus *bus)
 		return -EINVAL;
 	}
 
+	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) {
 		dev_err(bus->dev, "%s: could not find frame configuration for bus dr_freq %d\n",
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v2 09/14] soundwire: generic_bandwidth_allocation: correct clk_freq check in sdw_select_row_col
  2024-12-03 13:17 [PATCH v2 00/14] soundwire: add multi-lane support Bard Liao
                   ` (7 preceding siblings ...)
  2024-12-03 13:18 ` [PATCH v2 08/14] Soundwire: generic_bandwidth_allocation: set frame shape on fly Bard Liao
@ 2024-12-03 13:18 ` Bard Liao
  2024-12-03 13:18 ` [PATCH v2 10/14] soundwire: generic_bandwidth_allocation: check required freq accurately Bard Liao
                   ` (4 subsequent siblings)
  13 siblings, 0 replies; 17+ messages in thread
From: Bard Liao @ 2024-12-03 13:18 UTC (permalink / raw)
  To: linux-sound, vkoul
  Cc: vinod.koul, linux-kernel, pierre-louis.bossart, bard.liao

The bits in Column 0 of Rows 0 to 47 are for control word and cannot be
used for audio. In practice, entire Column 0 is skipped.

Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
---
 drivers/soundwire/generic_bandwidth_allocation.c | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/drivers/soundwire/generic_bandwidth_allocation.c b/drivers/soundwire/generic_bandwidth_allocation.c
index d847413141d3..5c4dac36ad1a 100644
--- a/drivers/soundwire/generic_bandwidth_allocation.c
+++ b/drivers/soundwire/generic_bandwidth_allocation.c
@@ -302,7 +302,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++) {
@@ -311,11 +310,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];
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v2 10/14] soundwire: generic_bandwidth_allocation: check required freq accurately
  2024-12-03 13:17 [PATCH v2 00/14] soundwire: add multi-lane support Bard Liao
                   ` (8 preceding siblings ...)
  2024-12-03 13:18 ` [PATCH v2 09/14] soundwire: generic_bandwidth_allocation: correct clk_freq check in sdw_select_row_col Bard Liao
@ 2024-12-03 13:18 ` Bard Liao
  2024-12-03 13:18 ` [PATCH v2 11/14] soundwire: generic_bandwidth_allocation: select data lane Bard Liao
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 17+ messages in thread
From: Bard Liao @ 2024-12-03 13:18 UTC (permalink / raw)
  To: linux-sound, vkoul
  Cc: vinod.koul, linux-kernel, pierre-louis.bossart, bard.liao

Currently, we check curr_dr_freq roughly by "if (curr_dr_freq <=
bus->params.bandwidth)" in sdw_compute_bus_params() and check it
accurately in sdw_select_row_col(). It works if we only support one
freq. But, we need to check it accurately in sdw_select_row_col() to
give it a chance to use a higher freq or use multi-lane.

Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
---
 drivers/soundwire/generic_bandwidth_allocation.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/soundwire/generic_bandwidth_allocation.c b/drivers/soundwire/generic_bandwidth_allocation.c
index 5c4dac36ad1a..d2632af9c8af 100644
--- a/drivers/soundwire/generic_bandwidth_allocation.c
+++ b/drivers/soundwire/generic_bandwidth_allocation.c
@@ -373,7 +373,8 @@ 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)
+		if (curr_dr_freq * (mstr_prop->default_col - 1) <
+		    bus->params.bandwidth * mstr_prop->default_col)
 			continue;
 
 		break;
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v2 11/14] soundwire: generic_bandwidth_allocation: select data lane
  2024-12-03 13:17 [PATCH v2 00/14] soundwire: add multi-lane support Bard Liao
                   ` (9 preceding siblings ...)
  2024-12-03 13:18 ` [PATCH v2 10/14] soundwire: generic_bandwidth_allocation: check required freq accurately Bard Liao
@ 2024-12-03 13:18 ` Bard Liao
  2024-12-03 13:18 ` [PATCH v2 12/14] soundwire: generic_bandwidth_allocation: add lane in sdw_group_params Bard Liao
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 17+ messages in thread
From: Bard Liao @ 2024-12-03 13:18 UTC (permalink / raw)
  To: linux-sound, vkoul
  Cc: vinod.koul, linux-kernel, pierre-louis.bossart, bard.liao

If a peripheral supports multi-lane, we can use data lane x to extend
the bandwidth. The patch suggests to select data lane x where x > 0
when bandwidth is not enough on data lane 0.

Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
---
 .../soundwire/generic_bandwidth_allocation.c  | 133 +++++++++++++++++-
 drivers/soundwire/stream.c                    |  20 ++-
 2 files changed, 146 insertions(+), 7 deletions(-)

diff --git a/drivers/soundwire/generic_bandwidth_allocation.c b/drivers/soundwire/generic_bandwidth_allocation.c
index d2632af9c8af..39b4d25ab19e 100644
--- a/drivers/soundwire/generic_bandwidth_allocation.c
+++ b/drivers/soundwire/generic_bandwidth_allocation.c
@@ -336,6 +336,82 @@ static bool is_clock_scaling_supported(struct sdw_bus *bus)
 	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
  *
@@ -343,10 +419,16 @@ static bool is_clock_scaling_supported(struct sdw_bus *bus)
  */
 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) {
@@ -373,11 +455,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) <
+		if (curr_dr_freq * (mstr_prop->default_col - 1) >=
 		    bus->params.bandwidth * mstr_prop->default_col)
-			continue;
+			break;
 
-		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
@@ -391,6 +488,32 @@ 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;
diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c
index a4a668135d16..b0868f71b63e 100644
--- a/drivers/soundwire/stream.c
+++ b/drivers/soundwire/stream.c
@@ -1674,6 +1674,9 @@ EXPORT_SYMBOL(sdw_disable_stream);
 static int _sdw_deprepare_stream(struct sdw_stream_runtime *stream)
 {
 	struct sdw_master_runtime *m_rt;
+	struct sdw_port_runtime *p_rt;
+	unsigned int multi_lane_bandwidth;
+	unsigned int bandwidth;
 	struct sdw_bus *bus;
 	int state = stream->state;
 	int ret = 0;
@@ -1695,9 +1698,22 @@ static int _sdw_deprepare_stream(struct sdw_stream_runtime *stream)
 			return ret;
 		}
 
+		multi_lane_bandwidth = 0;
+
+		list_for_each_entry(p_rt, &m_rt->port_list, port_node) {
+			if (!p_rt->lane)
+				continue;
+
+			bandwidth = m_rt->stream->params.rate * hweight32(p_rt->ch_mask) *
+				    m_rt->stream->params.bps;
+			multi_lane_bandwidth += bandwidth;
+			bus->lane_used_bandwidth[p_rt->lane] -= bandwidth;
+			if (!bus->lane_used_bandwidth[p_rt->lane])
+				p_rt->lane = 0;
+		}
 		/* TODO: Update this during Device-Device support */
-		bus->params.bandwidth -= m_rt->stream->params.rate *
-			m_rt->ch_count * m_rt->stream->params.bps;
+		bandwidth = m_rt->stream->params.rate * m_rt->ch_count * m_rt->stream->params.bps;
+		bus->params.bandwidth -= bandwidth - multi_lane_bandwidth;
 
 		/* Compute params */
 		if (bus->compute_params) {
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v2 12/14] soundwire: generic_bandwidth_allocation: add lane in sdw_group_params
  2024-12-03 13:17 [PATCH v2 00/14] soundwire: add multi-lane support Bard Liao
                   ` (10 preceding siblings ...)
  2024-12-03 13:18 ` [PATCH v2 11/14] soundwire: generic_bandwidth_allocation: select data lane Bard Liao
@ 2024-12-03 13:18 ` Bard Liao
  2024-12-03 13:18 ` [PATCH v2 13/14] SoundWire: pass stream to compute_params() Bard Liao
  2024-12-03 13:18 ` [PATCH v2 14/14] soundwire: generic_bandwidth_allocation: count the bandwidth of active streams only Bard Liao
  13 siblings, 0 replies; 17+ messages in thread
From: Bard Liao @ 2024-12-03 13:18 UTC (permalink / raw)
  To: linux-sound, vkoul
  Cc: vinod.koul, linux-kernel, pierre-louis.bossart, bard.liao

All active streams with the same parameters are grouped together and the
params are stored in the sdw_group struct. We compute the required
bandwidth for each group. However, each lane has individual bandwidth.
Therefore, we should separate different lanes in different params groups.
Add lane variable to separate params groups.

Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
---
 drivers/soundwire/bus.h                       |   1 +
 .../soundwire/generic_bandwidth_allocation.c  | 122 +++++++++++++-----
 2 files changed, 90 insertions(+), 33 deletions(-)

diff --git a/drivers/soundwire/bus.h b/drivers/soundwire/bus.h
index ff03b97f1d8b..fc990171b3f7 100644
--- a/drivers/soundwire/bus.h
+++ b/drivers/soundwire/bus.h
@@ -151,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,
diff --git a/drivers/soundwire/generic_bandwidth_allocation.c b/drivers/soundwire/generic_bandwidth_allocation.c
index 39b4d25ab19e..faf04d82ba0a 100644
--- a/drivers/soundwire/generic_bandwidth_allocation.c
+++ b/drivers/soundwire/generic_bandwidth_allocation.c
@@ -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,
@@ -105,6 +110,8 @@ 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,
@@ -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,69 +146,93 @@ 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 (i = 0; i < count; i++) {
-		port_bo = 1;
+	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) {
-			sdw_compute_master_ports(m_rt, &params[i], &port_bo, hstop);
+			list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) {
+				sdw_compute_master_ports(m_rt, &params[i], &port_bo, hstop);
+			}
+
+			hstop = hstop - params[i].hwidth;
 		}
-
-		hstop = hstop - params[i].hwidth;
 	}
 }
 
 static int sdw_compute_group_params(struct sdw_bus *bus,
 				    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) {
-		rate = m_rt->stream->params.rate;
-		bps = m_rt->stream->params.bps;
-		ch = m_rt->ch_count;
+		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 < count; i++) {
-			if (rate == params[i].rate)
-				params[i].payload_bw += bps * ch;
+			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;
 
-		column_needed += params[i].hwidth;
+			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 +240,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 +248,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 +271,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,6 +281,13 @@ 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;
@@ -246,11 +297,16 @@ static int sdw_get_group_count(struct sdw_bus *bus,
 					     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;
 			}
 		}
@@ -284,8 +340,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, params, &group);
 	if (ret < 0)
 		goto free_params;
 
@@ -295,6 +350,7 @@ static int sdw_compute_port_params(struct sdw_bus *bus)
 	kfree(params);
 out:
 	kfree(group.rates);
+	kfree(group.lanes);
 
 	return ret;
 }
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v2 13/14] SoundWire: pass stream to compute_params()
  2024-12-03 13:17 [PATCH v2 00/14] soundwire: add multi-lane support Bard Liao
                   ` (11 preceding siblings ...)
  2024-12-03 13:18 ` [PATCH v2 12/14] soundwire: generic_bandwidth_allocation: add lane in sdw_group_params Bard Liao
@ 2024-12-03 13:18 ` Bard Liao
  2024-12-03 13:18 ` [PATCH v2 14/14] soundwire: generic_bandwidth_allocation: count the bandwidth of active streams only Bard Liao
  13 siblings, 0 replies; 17+ messages in thread
From: Bard Liao @ 2024-12-03 13:18 UTC (permalink / raw)
  To: linux-sound, vkoul
  Cc: vinod.koul, linux-kernel, pierre-louis.bossart, bard.liao

The stream parameter will be used in the follow up commit.
No function change.

Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com>
---
 drivers/soundwire/amd_manager.c               |   2 +-
 .../soundwire/generic_bandwidth_allocation.c  |  11 +-
 drivers/soundwire/qcom.c                      |   2 +-
 drivers/soundwire/stream.c                    |   4 +-
 include/linux/soundwire/sdw.h                 | 182 +++++++++---------
 5 files changed, 102 insertions(+), 99 deletions(-)

diff --git a/drivers/soundwire/amd_manager.c b/drivers/soundwire/amd_manager.c
index f47d4cd656ae..0ee792176f22 100644
--- a/drivers/soundwire/amd_manager.c
+++ b/drivers/soundwire/amd_manager.c
@@ -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;
diff --git a/drivers/soundwire/generic_bandwidth_allocation.c b/drivers/soundwire/generic_bandwidth_allocation.c
index faf04d82ba0a..062e7488b226 100644
--- a/drivers/soundwire/generic_bandwidth_allocation.c
+++ b/drivers/soundwire/generic_bandwidth_allocation.c
@@ -170,6 +170,7 @@ static void _sdw_compute_port_params(struct sdw_bus *bus,
 }
 
 static int sdw_compute_group_params(struct sdw_bus *bus,
+				    struct sdw_stream_runtime *stream,
 				    struct sdw_group_params *params,
 				    struct sdw_group *group)
 {
@@ -319,8 +320,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;
@@ -340,7 +342,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);
+	ret = sdw_compute_group_params(bus, stream, params, &group);
 	if (ret < 0)
 		goto free_params;
 
@@ -592,8 +594,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;
 
@@ -603,7 +606,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;
diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c
index 2b403b14066c..fd98f05bf56d 100644
--- a/drivers/soundwire/qcom.c
+++ b/drivers/soundwire/qcom.c
@@ -1072,7 +1072,7 @@ static const struct sdw_master_ops qcom_swrm_ops = {
 	.pre_bank_switch = qcom_swrm_pre_bank_switch,
 };
 
-static int qcom_swrm_compute_params(struct sdw_bus *bus)
+static int qcom_swrm_compute_params(struct sdw_bus *bus, struct sdw_stream_runtime *stream)
 {
 	struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus);
 	struct sdw_master_runtime *m_rt;
diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c
index b0868f71b63e..48b637f3c189 100644
--- a/drivers/soundwire/stream.c
+++ b/drivers/soundwire/stream.c
@@ -1415,7 +1415,7 @@ static int _sdw_prepare_stream(struct sdw_stream_runtime *stream,
 
 			/* Compute params */
 			if (bus->compute_params) {
-				ret = bus->compute_params(bus);
+				ret = bus->compute_params(bus, stream);
 				if (ret < 0) {
 					dev_err(bus->dev, "Compute params failed: %d\n",
 						ret);
@@ -1717,7 +1717,7 @@ static int _sdw_deprepare_stream(struct sdw_stream_runtime *stream)
 
 		/* Compute params */
 		if (bus->compute_params) {
-			ret = bus->compute_params(bus);
+			ret = bus->compute_params(bus, stream);
 			if (ret < 0) {
 				dev_err(bus->dev, "Compute params failed: %d\n",
 					ret);
diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h
index fc0a203c3ae0..2d6c30317792 100644
--- a/include/linux/soundwire/sdw.h
+++ b/include/linux/soundwire/sdw.h
@@ -855,6 +855,95 @@ struct sdw_master_ops {
 					int dev_num);
 };
 
+int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent,
+		       struct fwnode_handle *fwnode);
+void sdw_bus_master_delete(struct sdw_bus *bus);
+
+void sdw_show_ping_status(struct sdw_bus *bus, bool sync_delay);
+
+/**
+ * sdw_port_config: Master or Slave Port configuration
+ *
+ * @num: Port number
+ * @ch_mask: channels mask for port
+ */
+struct sdw_port_config {
+	unsigned int num;
+	unsigned int ch_mask;
+};
+
+/**
+ * sdw_stream_config: Master or Slave stream configuration
+ *
+ * @frame_rate: Audio frame rate of the stream, in Hz
+ * @ch_count: Channel count of the stream
+ * @bps: Number of bits per audio sample
+ * @direction: Data direction
+ * @type: Stream type PCM or PDM
+ */
+struct sdw_stream_config {
+	unsigned int frame_rate;
+	unsigned int ch_count;
+	unsigned int bps;
+	enum sdw_data_direction direction;
+	enum sdw_stream_type type;
+};
+
+/**
+ * sdw_stream_state: Stream states
+ *
+ * @SDW_STREAM_ALLOCATED: New stream allocated.
+ * @SDW_STREAM_CONFIGURED: Stream configured
+ * @SDW_STREAM_PREPARED: Stream prepared
+ * @SDW_STREAM_ENABLED: Stream enabled
+ * @SDW_STREAM_DISABLED: Stream disabled
+ * @SDW_STREAM_DEPREPARED: Stream de-prepared
+ * @SDW_STREAM_RELEASED: Stream released
+ */
+enum sdw_stream_state {
+	SDW_STREAM_ALLOCATED = 0,
+	SDW_STREAM_CONFIGURED = 1,
+	SDW_STREAM_PREPARED = 2,
+	SDW_STREAM_ENABLED = 3,
+	SDW_STREAM_DISABLED = 4,
+	SDW_STREAM_DEPREPARED = 5,
+	SDW_STREAM_RELEASED = 6,
+};
+
+/**
+ * sdw_stream_params: Stream parameters
+ *
+ * @rate: Sampling frequency, in Hz
+ * @ch_count: Number of channels
+ * @bps: bits per channel sample
+ */
+struct sdw_stream_params {
+	unsigned int rate;
+	unsigned int ch_count;
+	unsigned int bps;
+};
+
+/**
+ * sdw_stream_runtime: Runtime stream parameters
+ *
+ * @name: SoundWire stream name
+ * @params: Stream parameters
+ * @state: Current state of the stream
+ * @type: Stream type PCM or PDM
+ * @m_rt_count: Count of Master runtime(s) in this stream
+ * @master_list: List of Master runtime(s) in this stream.
+ * master_list can contain only one m_rt per Master instance
+ * for a stream
+ */
+struct sdw_stream_runtime {
+	const char *name;
+	struct sdw_stream_params params;
+	enum sdw_stream_state state;
+	enum sdw_stream_type type;
+	int m_rt_count;
+	struct list_head master_list;
+};
+
 /**
  * struct sdw_bus - SoundWire bus
  * @dev: Shortcut to &bus->md->dev to avoid changing the entire code.
@@ -915,7 +1004,7 @@ struct sdw_bus {
 	int controller_id;
 	unsigned int link_id;
 	int id;
-	int (*compute_params)(struct sdw_bus *bus);
+	int (*compute_params)(struct sdw_bus *bus, struct sdw_stream_runtime *stream);
 	DECLARE_BITMAP(assigned, SDW_MAX_DEVICES);
 	unsigned int clk_stop_timeout;
 	u32 bank_switch_timeout;
@@ -928,99 +1017,10 @@ struct sdw_bus {
 	unsigned int lane_used_bandwidth[SDW_MAX_LANES];
 };
 
-int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent,
-		       struct fwnode_handle *fwnode);
-void sdw_bus_master_delete(struct sdw_bus *bus);
-
-void sdw_show_ping_status(struct sdw_bus *bus, bool sync_delay);
-
-/**
- * sdw_port_config: Master or Slave Port configuration
- *
- * @num: Port number
- * @ch_mask: channels mask for port
- */
-struct sdw_port_config {
-	unsigned int num;
-	unsigned int ch_mask;
-};
-
-/**
- * sdw_stream_config: Master or Slave stream configuration
- *
- * @frame_rate: Audio frame rate of the stream, in Hz
- * @ch_count: Channel count of the stream
- * @bps: Number of bits per audio sample
- * @direction: Data direction
- * @type: Stream type PCM or PDM
- */
-struct sdw_stream_config {
-	unsigned int frame_rate;
-	unsigned int ch_count;
-	unsigned int bps;
-	enum sdw_data_direction direction;
-	enum sdw_stream_type type;
-};
-
-/**
- * sdw_stream_state: Stream states
- *
- * @SDW_STREAM_ALLOCATED: New stream allocated.
- * @SDW_STREAM_CONFIGURED: Stream configured
- * @SDW_STREAM_PREPARED: Stream prepared
- * @SDW_STREAM_ENABLED: Stream enabled
- * @SDW_STREAM_DISABLED: Stream disabled
- * @SDW_STREAM_DEPREPARED: Stream de-prepared
- * @SDW_STREAM_RELEASED: Stream released
- */
-enum sdw_stream_state {
-	SDW_STREAM_ALLOCATED = 0,
-	SDW_STREAM_CONFIGURED = 1,
-	SDW_STREAM_PREPARED = 2,
-	SDW_STREAM_ENABLED = 3,
-	SDW_STREAM_DISABLED = 4,
-	SDW_STREAM_DEPREPARED = 5,
-	SDW_STREAM_RELEASED = 6,
-};
-
-/**
- * sdw_stream_params: Stream parameters
- *
- * @rate: Sampling frequency, in Hz
- * @ch_count: Number of channels
- * @bps: bits per channel sample
- */
-struct sdw_stream_params {
-	unsigned int rate;
-	unsigned int ch_count;
-	unsigned int bps;
-};
-
-/**
- * sdw_stream_runtime: Runtime stream parameters
- *
- * @name: SoundWire stream name
- * @params: Stream parameters
- * @state: Current state of the stream
- * @type: Stream type PCM or PDM
- * @m_rt_count: Count of Master runtime(s) in this stream
- * @master_list: List of Master runtime(s) in this stream.
- * master_list can contain only one m_rt per Master instance
- * for a stream
- */
-struct sdw_stream_runtime {
-	const char *name;
-	struct sdw_stream_params params;
-	enum sdw_stream_state state;
-	enum sdw_stream_type type;
-	int m_rt_count;
-	struct list_head master_list;
-};
-
 struct sdw_stream_runtime *sdw_alloc_stream(const char *stream_name);
 void sdw_release_stream(struct sdw_stream_runtime *stream);
 
-int sdw_compute_params(struct sdw_bus *bus);
+int sdw_compute_params(struct sdw_bus *bus, struct sdw_stream_runtime *stream);
 
 int sdw_stream_add_master(struct sdw_bus *bus,
 			  struct sdw_stream_config *stream_config,
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v2 14/14] soundwire: generic_bandwidth_allocation: count the bandwidth of active streams only
  2024-12-03 13:17 [PATCH v2 00/14] soundwire: add multi-lane support Bard Liao
                   ` (12 preceding siblings ...)
  2024-12-03 13:18 ` [PATCH v2 13/14] SoundWire: pass stream to compute_params() Bard Liao
@ 2024-12-03 13:18 ` Bard Liao
  13 siblings, 0 replies; 17+ messages in thread
From: Bard Liao @ 2024-12-03 13:18 UTC (permalink / raw)
  To: linux-sound, vkoul
  Cc: vinod.koul, linux-kernel, pierre-louis.bossart, bard.liao

sdw_compute_group_params() should only count payload bandwidth of the
active streams which is in the ENABLED and DISABLED state in the bus.
And add the payload bandwidth of the stream that calls
sdw_compute_group_params() in sdw_prepare_stream().

Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com>
---
 drivers/soundwire/generic_bandwidth_allocation.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/drivers/soundwire/generic_bandwidth_allocation.c b/drivers/soundwire/generic_bandwidth_allocation.c
index 062e7488b226..59965f43c2fb 100644
--- a/drivers/soundwire/generic_bandwidth_allocation.c
+++ b/drivers/soundwire/generic_bandwidth_allocation.c
@@ -188,6 +188,19 @@ static int sdw_compute_group_params(struct sdw_bus *bus,
 	}
 
 	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;
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [PATCH v2 07/14] Soundwire: stream: program BUSCLOCK_SCALE
  2024-12-03 13:18 ` [PATCH v2 07/14] Soundwire: stream: program BUSCLOCK_SCALE Bard Liao
@ 2024-12-03 13:51   ` Richard Fitzgerald
  2024-12-04  2:44     ` Liao, Bard
  0 siblings, 1 reply; 17+ messages in thread
From: Richard Fitzgerald @ 2024-12-03 13:51 UTC (permalink / raw)
  To: Bard Liao, linux-sound, vkoul
  Cc: vinod.koul, linux-kernel, pierre-louis.bossart, bard.liao

On 3/12/24 13:18, Bard Liao wrote:
> We need to program bus clock scale to adjust the bus clock if current
> bus clock doesn't fit the bandwidth.
> 
> Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
> Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
> ---
>   drivers/soundwire/bus.c       | 10 ++++++++++
>   drivers/soundwire/stream.c    | 32 ++++++++++++++++++++++++++++++++
>   include/linux/soundwire/sdw.h |  1 +
>   3 files changed, 43 insertions(+)
> 

Does this still have the bug I reported here that breaks on systems
that have peripherals listed in ACPI that don't really exist?

https://github.com/thesofproject/linux/issues/5257


^ permalink raw reply	[flat|nested] 17+ messages in thread

* RE: [PATCH v2 07/14] Soundwire: stream: program BUSCLOCK_SCALE
  2024-12-03 13:51   ` Richard Fitzgerald
@ 2024-12-04  2:44     ` Liao, Bard
  0 siblings, 0 replies; 17+ messages in thread
From: Liao, Bard @ 2024-12-04  2:44 UTC (permalink / raw)
  To: Richard Fitzgerald, Bard Liao, linux-sound@vger.kernel.org,
	vkoul@kernel.org
  Cc: vinod.koul@linaro.org, linux-kernel@vger.kernel.org,
	pierre-louis.bossart@linux.dev



> -----Original Message-----
> From: Richard Fitzgerald <rf@opensource.cirrus.com>
> Sent: Tuesday, December 3, 2024 9:52 PM
> To: Bard Liao <yung-chuan.liao@linux.intel.com>; linux-
> sound@vger.kernel.org; vkoul@kernel.org
> Cc: vinod.koul@linaro.org; linux-kernel@vger.kernel.org; pierre-
> louis.bossart@linux.dev; Liao, Bard <bard.liao@intel.com>
> Subject: Re: [PATCH v2 07/14] Soundwire: stream: program BUSCLOCK_SCALE
> 
> On 3/12/24 13:18, Bard Liao wrote:
> > We need to program bus clock scale to adjust the bus clock if current
> > bus clock doesn't fit the bandwidth.
> >
> > Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
> > Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
> > ---
> >   drivers/soundwire/bus.c       | 10 ++++++++++
> >   drivers/soundwire/stream.c    | 32
> ++++++++++++++++++++++++++++++++
> >   include/linux/soundwire/sdw.h |  1 +
> >   3 files changed, 43 insertions(+)
> >
> 
> Does this still have the bug I reported here that breaks on systems
> that have peripherals listed in ACPI that don't really exist?
> 
> https://github.com/thesofproject/linux/issues/5257

Thanks for reporting the issue. I will look into it.



^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2024-12-04  2:44 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-12-03 13:17 [PATCH v2 00/14] soundwire: add multi-lane support Bard Liao
2024-12-03 13:18 ` [PATCH v2 01/14] soundwire: add lane field in sdw_port_runtime Bard Liao
2024-12-03 13:18 ` [PATCH v2 02/14] soundwire: mipi_disco: read lane mapping properties from ACPI Bard Liao
2024-12-03 13:18 ` [PATCH v2 03/14] soundwire: add lane_used_bandwidth in struct sdw_bus Bard Liao
2024-12-03 13:18 ` [PATCH v2 04/14] soundwire: stream: set DEPREPARED state earlier Bard Liao
2024-12-03 13:18 ` [PATCH v2 05/14] soundwire: generic_bandwidth_allocation: skip DEPREPARED streams Bard Liao
2024-12-03 13:18 ` [PATCH v2 06/14] Soundwire: add sdw_slave_get_scale_index helper Bard Liao
2024-12-03 13:18 ` [PATCH v2 07/14] Soundwire: stream: program BUSCLOCK_SCALE Bard Liao
2024-12-03 13:51   ` Richard Fitzgerald
2024-12-04  2:44     ` Liao, Bard
2024-12-03 13:18 ` [PATCH v2 08/14] Soundwire: generic_bandwidth_allocation: set frame shape on fly Bard Liao
2024-12-03 13:18 ` [PATCH v2 09/14] soundwire: generic_bandwidth_allocation: correct clk_freq check in sdw_select_row_col Bard Liao
2024-12-03 13:18 ` [PATCH v2 10/14] soundwire: generic_bandwidth_allocation: check required freq accurately Bard Liao
2024-12-03 13:18 ` [PATCH v2 11/14] soundwire: generic_bandwidth_allocation: select data lane Bard Liao
2024-12-03 13:18 ` [PATCH v2 12/14] soundwire: generic_bandwidth_allocation: add lane in sdw_group_params Bard Liao
2024-12-03 13:18 ` [PATCH v2 13/14] SoundWire: pass stream to compute_params() Bard Liao
2024-12-03 13:18 ` [PATCH v2 14/14] soundwire: generic_bandwidth_allocation: count the bandwidth of active streams only Bard Liao

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox