linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/5] soundwire: qcom: various improvements
@ 2021-02-26 15:58 Srinivas Kandagatla
  2021-02-26 15:58 ` [PATCH v2 1/5] soundwire: qcom: add support to missing transport params Srinivas Kandagatla
                   ` (4 more replies)
  0 siblings, 5 replies; 11+ messages in thread
From: Srinivas Kandagatla @ 2021-02-26 15:58 UTC (permalink / raw)
  To: vkoul
  Cc: yung-chuan.liao, pierre-louis.bossart, sanyog.r.kale,
	linux-kernel, alsa-devel, Srinivas Kandagatla

Thanks for reviewing v1 of this patchset!

During testing SoundWire controller on SM8250 MTP, we found
few issues like all the interrupts are not handled,
all transport parameters are not read from device tree.

Other major issue was register read/writes which was interrupt based
was an overhead and puts lot of limitation on context it can be used from.

With previous approach number of interrupts generated
after enumeration are around 130:
$ cat /proc/interrupts  | grep soundwire
21: 130 0 0 0 0 0 0 0 GICv3 234 Edge      soundwire
    
after this patch they are just 3 interrupts
$ cat /proc/interrupts  | grep soundwire
21: 3 0 0 0 0 0 0 0 GICv3 234 Edge      soundwire

So this patchset add various improvements to the existing driver
to address above issues.

Tested it on SM8250 MTP with 2x WSA881x speakers, HeadPhones on
WCD938x via lpass-rx-macro and Analog MICs via lpass-tx-macro.
Also tested on DragonBoard DB845c with 2xWSA881x speakers.


Changes since v1:
	- changed bgp_count to blk_group_count as suggested by Pierre
	- used version raw value as suggested by VKoul
	- updated read fifo logic and interrupt handling to do while()
	- renamed some of the variable to make reading easy!
	- removed patch that parses version

Srinivas Kandagatla (5):
  soundwire: qcom: add support to missing transport params
  soundwire: qcom: set continue execution flag for ignored commands
  soundwire: qcom: start the clock during initialization
  soundwire: qcom: update register read/write routine
  soundwire: qcom: add support to new interrupts

 drivers/soundwire/qcom.c | 438 ++++++++++++++++++++++++++++++---------
 1 file changed, 335 insertions(+), 103 deletions(-)

-- 
2.21.0


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

* [PATCH v2 1/5] soundwire: qcom: add support to missing transport params
  2021-02-26 15:58 [PATCH v2 0/5] soundwire: qcom: various improvements Srinivas Kandagatla
@ 2021-02-26 15:58 ` Srinivas Kandagatla
  2021-02-26 16:45   ` Pierre-Louis Bossart
  2021-02-26 15:58 ` [PATCH v2 2/5] soundwire: qcom: set continue execution flag for ignored commands Srinivas Kandagatla
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 11+ messages in thread
From: Srinivas Kandagatla @ 2021-02-26 15:58 UTC (permalink / raw)
  To: vkoul
  Cc: yung-chuan.liao, pierre-louis.bossart, sanyog.r.kale,
	linux-kernel, alsa-devel, Srinivas Kandagatla

Some of the transport parameters derived from device tree
are not fully parsed by the driver.

This patch adds support to parse those missing parameters.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/soundwire/qcom.c | 99 ++++++++++++++++++++++++++++++++++++++--
 1 file changed, 95 insertions(+), 4 deletions(-)

diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c
index 6d22df01f354..fee7465c72c2 100644
--- a/drivers/soundwire/qcom.c
+++ b/drivers/soundwire/qcom.c
@@ -54,7 +54,13 @@
 #define SWRM_MCP_SLV_STATUS					0x1090
 #define SWRM_MCP_SLV_STATUS_MASK				GENMASK(1, 0)
 #define SWRM_DP_PORT_CTRL_BANK(n, m)	(0x1124 + 0x100 * (n - 1) + 0x40 * m)
+#define SWRM_DP_PORT_CTRL_2_BANK(n, m)	(0x1128 + 0x100 * (n - 1) + 0x40 * m)
+#define SWRM_DP_BLOCK_CTRL_1(n)		(0x112C + 0x100 * (n - 1))
+#define SWRM_DP_BLOCK_CTRL2_BANK(n, m)	(0x1130 + 0x100 * (n - 1) + 0x40 * m)
+#define SWRM_DP_PORT_HCTRL_BANK(n, m)	(0x1134 + 0x100 * (n - 1) + 0x40 * m)
 #define SWRM_DP_BLOCK_CTRL3_BANK(n, m)	(0x1138 + 0x100 * (n - 1) + 0x40 * m)
+#define SWRM_DIN_DPn_PCM_PORT_CTRL(n)	(0x1054 + 0x100 * (n - 1))
+
 #define SWRM_DP_PORT_CTRL_EN_CHAN_SHFT				0x18
 #define SWRM_DP_PORT_CTRL_OFFSET2_SHFT				0x10
 #define SWRM_DP_PORT_CTRL_OFFSET1_SHFT				0x08
@@ -73,12 +79,20 @@
 #define QCOM_SDW_MAX_PORTS	14
 #define DEFAULT_CLK_FREQ	9600000
 #define SWRM_MAX_DAIS		0xF
+#define SWR_INVALID_PARAM 0xFF
+#define SWR_HSTOP_MAX_VAL 0xF
+#define SWR_HSTART_MIN_VAL 0x0
 
 struct qcom_swrm_port_config {
 	u8 si;
 	u8 off1;
 	u8 off2;
 	u8 bp_mode;
+	u8 hstart;
+	u8 hstop;
+	u8 word_length;
+	u8 blk_group_count;
+	u8 lane_control;
 };
 
 struct qcom_swrm_ctrl {
@@ -396,7 +410,13 @@ static int qcom_swrm_port_params(struct sdw_bus *bus,
 				 struct sdw_port_params *p_params,
 				 unsigned int bank)
 {
-	/* TBD */
+	struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus);
+
+	if (p_params->bps != SWR_INVALID_PARAM)
+		return ctrl->reg_write(ctrl,
+				       SWRM_DP_BLOCK_CTRL_1(p_params->num),
+				       p_params->bps - 1);
+
 	return 0;
 }
 
@@ -415,10 +435,32 @@ static int qcom_swrm_transport_params(struct sdw_bus *bus,
 
 	ret = ctrl->reg_write(ctrl, reg, value);
 
-	if (!ret && params->blk_pkg_mode) {
-		reg = SWRM_DP_BLOCK_CTRL3_BANK(params->port_num, bank);
+	if (params->lane_ctrl != SWR_INVALID_PARAM) {
+		reg = SWRM_DP_PORT_CTRL_2_BANK(params->port_num, bank);
+		value = params->lane_ctrl;
+		ret = ctrl->reg_write(ctrl, reg, value);
+	}
 
-		ret = ctrl->reg_write(ctrl, reg, 1);
+	if (params->blk_grp_ctrl != SWR_INVALID_PARAM) {
+		reg = SWRM_DP_BLOCK_CTRL2_BANK(params->port_num, bank);
+		value = params->blk_grp_ctrl;
+		ret = ctrl->reg_write(ctrl, reg, value);
+	}
+
+	if (params->hstart != SWR_INVALID_PARAM
+			&& params->hstop != SWR_INVALID_PARAM) {
+		reg = SWRM_DP_PORT_HCTRL_BANK(params->port_num, bank);
+		value = (params->hstop << 4) | params->hstart;
+		ret = ctrl->reg_write(ctrl, reg, value);
+	} else {
+		reg = SWRM_DP_PORT_HCTRL_BANK(params->port_num, bank);
+		value = (SWR_HSTOP_MAX_VAL << 4) | SWR_HSTART_MIN_VAL;
+		ret = ctrl->reg_write(ctrl, reg, value);
+	}
+
+	if (params->blk_pkg_mode != SWR_INVALID_PARAM) {
+		reg = SWRM_DP_BLOCK_CTRL3_BANK(params->port_num, bank);
+		ret = ctrl->reg_write(ctrl, reg, params->blk_pkg_mode);
 	}
 
 	return ret;
@@ -470,6 +512,17 @@ static int qcom_swrm_compute_params(struct sdw_bus *bus)
 			p_rt->transport_params.offset1 = pcfg->off1;
 			p_rt->transport_params.offset2 = pcfg->off2;
 			p_rt->transport_params.blk_pkg_mode = pcfg->bp_mode;
+			p_rt->transport_params.blk_grp_ctrl = pcfg->blk_group_count;
+			p_rt->transport_params.hstart = pcfg->hstart;
+			p_rt->transport_params.hstop = pcfg->hstop;
+			p_rt->transport_params.lane_ctrl = pcfg->lane_control;
+			if (pcfg->word_length != SWR_INVALID_PARAM) {
+				sdw_fill_port_params(&p_rt->port_params,
+					     p_rt->num,  pcfg->word_length + 1,
+					     SDW_PORT_FLOW_MODE_ISOCH,
+					     SDW_PORT_DATA_MODE_NORMAL);
+			}
+
 		}
 
 		list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) {
@@ -481,6 +534,18 @@ static int qcom_swrm_compute_params(struct sdw_bus *bus)
 				p_rt->transport_params.offset1 = pcfg->off1;
 				p_rt->transport_params.offset2 = pcfg->off2;
 				p_rt->transport_params.blk_pkg_mode = pcfg->bp_mode;
+				p_rt->transport_params.blk_grp_ctrl = pcfg->blk_group_count;
+
+				p_rt->transport_params.hstart = pcfg->hstart;
+				p_rt->transport_params.hstop = pcfg->hstop;
+				p_rt->transport_params.lane_ctrl = pcfg->lane_control;
+				if (pcfg->word_length != SWR_INVALID_PARAM) {
+					sdw_fill_port_params(&p_rt->port_params,
+						     p_rt->num,
+						     pcfg->word_length + 1,
+						     SDW_PORT_FLOW_MODE_ISOCH,
+						     SDW_PORT_DATA_MODE_NORMAL);
+				}
 				i++;
 			}
 		}
@@ -728,6 +793,11 @@ static int qcom_swrm_get_port_config(struct qcom_swrm_ctrl *ctrl)
 	u8 off2[QCOM_SDW_MAX_PORTS];
 	u8 si[QCOM_SDW_MAX_PORTS];
 	u8 bp_mode[QCOM_SDW_MAX_PORTS] = { 0, };
+	u8 hstart[QCOM_SDW_MAX_PORTS];
+	u8 hstop[QCOM_SDW_MAX_PORTS];
+	u8 word_length[QCOM_SDW_MAX_PORTS];
+	u8 blk_group_count[QCOM_SDW_MAX_PORTS];
+	u8 lane_control[QCOM_SDW_MAX_PORTS];
 	int i, ret, nports, val;
 
 	ctrl->reg_read(ctrl, SWRM_COMP_PARAMS, &val);
@@ -772,11 +842,32 @@ static int qcom_swrm_get_port_config(struct qcom_swrm_ctrl *ctrl)
 
 	ret = of_property_read_u8_array(np, "qcom,ports-block-pack-mode",
 					bp_mode, nports);
+
+	memset(hstart, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS);
+	of_property_read_u8_array(np, "qcom,ports-hstart", hstart, nports);
+
+	memset(hstop, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS);
+	of_property_read_u8_array(np, "qcom,ports-hstop", hstop, nports);
+
+	memset(word_length, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS);
+	of_property_read_u8_array(np, "qcom,ports-word-length", word_length, nports);
+
+	memset(blk_group_count, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS);
+	of_property_read_u8_array(np, "qcom,ports-block-group-count", blk_group_count, nports);
+
+	memset(lane_control, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS);
+	of_property_read_u8_array(np, "qcom,ports-lane-control", lane_control, nports);
+
 	for (i = 0; i < nports; i++) {
 		ctrl->pconfig[i].si = si[i];
 		ctrl->pconfig[i].off1 = off1[i];
 		ctrl->pconfig[i].off2 = off2[i];
 		ctrl->pconfig[i].bp_mode = bp_mode[i];
+		ctrl->pconfig[i].hstart = hstart[i];
+		ctrl->pconfig[i].hstop = hstop[i];
+		ctrl->pconfig[i].word_length = word_length[i];
+		ctrl->pconfig[i].blk_group_count = blk_group_count[i];
+		ctrl->pconfig[i].lane_control = lane_control[i];
 	}
 
 	return 0;
-- 
2.21.0


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

* [PATCH v2 2/5] soundwire: qcom: set continue execution flag for ignored commands
  2021-02-26 15:58 [PATCH v2 0/5] soundwire: qcom: various improvements Srinivas Kandagatla
  2021-02-26 15:58 ` [PATCH v2 1/5] soundwire: qcom: add support to missing transport params Srinivas Kandagatla
@ 2021-02-26 15:58 ` Srinivas Kandagatla
  2021-02-26 15:58 ` [PATCH v2 3/5] soundwire: qcom: start the clock during initialization Srinivas Kandagatla
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 11+ messages in thread
From: Srinivas Kandagatla @ 2021-02-26 15:58 UTC (permalink / raw)
  To: vkoul
  Cc: yung-chuan.liao, pierre-louis.bossart, sanyog.r.kale,
	linux-kernel, alsa-devel, Srinivas Kandagatla

version 1.5.1 and higher IPs of this controller required to set
continue execution on ignored command flag. This patch sets this flag.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/soundwire/qcom.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c
index fee7465c72c2..14d91b17a2ca 100644
--- a/drivers/soundwire/qcom.c
+++ b/drivers/soundwire/qcom.c
@@ -40,6 +40,7 @@
 #define SWRM_CMD_FIFO_CMD					0x308
 #define SWRM_CMD_FIFO_STATUS					0x30C
 #define SWRM_CMD_FIFO_CFG_ADDR					0x314
+#define SWRM_CONTINUE_EXEC_ON_CMD_IGNORE			BIT(31)
 #define SWRM_RD_WR_CMD_RETRIES					0x7
 #define SWRM_CMD_FIFO_RD_FIFO_ADDR				0x318
 #define SWRM_ENUMERATOR_CFG_ADDR				0x500
@@ -343,7 +344,15 @@ static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl)
 	ctrl->reg_write(ctrl, SWRM_MCP_CFG_ADDR, val);
 
 	/* Configure number of retries of a read/write cmd */
-	ctrl->reg_write(ctrl, SWRM_CMD_FIFO_CFG_ADDR, SWRM_RD_WR_CMD_RETRIES);
+	if (ctrl->version > 0x01050001) {
+		/* Only for versions >= 1.5.1 */
+		ctrl->reg_write(ctrl, SWRM_CMD_FIFO_CFG_ADDR,
+				SWRM_RD_WR_CMD_RETRIES |
+				SWRM_CONTINUE_EXEC_ON_CMD_IGNORE);
+	} else {
+		ctrl->reg_write(ctrl, SWRM_CMD_FIFO_CFG_ADDR,
+				SWRM_RD_WR_CMD_RETRIES);
+	}
 
 	/* Set IRQ to PULSE */
 	ctrl->reg_write(ctrl, SWRM_COMP_CFG_ADDR,
-- 
2.21.0


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

* [PATCH v2 3/5] soundwire: qcom: start the clock during initialization
  2021-02-26 15:58 [PATCH v2 0/5] soundwire: qcom: various improvements Srinivas Kandagatla
  2021-02-26 15:58 ` [PATCH v2 1/5] soundwire: qcom: add support to missing transport params Srinivas Kandagatla
  2021-02-26 15:58 ` [PATCH v2 2/5] soundwire: qcom: set continue execution flag for ignored commands Srinivas Kandagatla
@ 2021-02-26 15:58 ` Srinivas Kandagatla
  2021-02-26 15:58 ` [PATCH v2 4/5] soundwire: qcom: update register read/write routine Srinivas Kandagatla
  2021-02-26 15:58 ` [PATCH v2 5/5] soundwire: qcom: add support to new interrupts Srinivas Kandagatla
  4 siblings, 0 replies; 11+ messages in thread
From: Srinivas Kandagatla @ 2021-02-26 15:58 UTC (permalink / raw)
  To: vkoul
  Cc: yung-chuan.liao, pierre-louis.bossart, sanyog.r.kale,
	linux-kernel, alsa-devel, Srinivas Kandagatla

Start the clock during initialization, doing this explicitly
will add more clarity when we are adding clock stop feature.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/soundwire/qcom.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c
index 14d91b17a2ca..6a7c0acc8d89 100644
--- a/drivers/soundwire/qcom.c
+++ b/drivers/soundwire/qcom.c
@@ -47,6 +47,8 @@
 #define SWRM_MCP_FRAME_CTRL_BANK_ADDR(m)		(0x101C + 0x40 * (m))
 #define SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_BMSK			GENMASK(2, 0)
 #define SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_BMSK			GENMASK(7, 3)
+#define SWRM_MCP_BUS_CTRL					0x1044
+#define SWRM_MCP_BUS_CLK_START					BIT(1)
 #define SWRM_MCP_CFG_ADDR					0x1048
 #define SWRM_MCP_CFG_MAX_NUM_OF_CMD_NO_PINGS_BMSK		GENMASK(21, 17)
 #define SWRM_DEF_CMD_NO_PINGS					0x1f
@@ -343,6 +345,7 @@ static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl)
 	u32p_replace_bits(&val, SWRM_DEF_CMD_NO_PINGS, SWRM_MCP_CFG_MAX_NUM_OF_CMD_NO_PINGS_BMSK);
 	ctrl->reg_write(ctrl, SWRM_MCP_CFG_ADDR, val);
 
+	ctrl->reg_write(ctrl, SWRM_MCP_BUS_CTRL, SWRM_MCP_BUS_CLK_START);
 	/* Configure number of retries of a read/write cmd */
 	if (ctrl->version > 0x01050001) {
 		/* Only for versions >= 1.5.1 */
-- 
2.21.0


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

* [PATCH v2 4/5] soundwire: qcom: update register read/write routine
  2021-02-26 15:58 [PATCH v2 0/5] soundwire: qcom: various improvements Srinivas Kandagatla
                   ` (2 preceding siblings ...)
  2021-02-26 15:58 ` [PATCH v2 3/5] soundwire: qcom: start the clock during initialization Srinivas Kandagatla
@ 2021-02-26 15:58 ` Srinivas Kandagatla
  2021-02-26 15:58 ` [PATCH v2 5/5] soundwire: qcom: add support to new interrupts Srinivas Kandagatla
  4 siblings, 0 replies; 11+ messages in thread
From: Srinivas Kandagatla @ 2021-02-26 15:58 UTC (permalink / raw)
  To: vkoul
  Cc: yung-chuan.liao, pierre-louis.bossart, sanyog.r.kale,
	linux-kernel, alsa-devel, Srinivas Kandagatla

In the existing code every soundwire register read and register write
are kinda blocked. Each of these are using a special command id that
generates interrupt after it successfully finishes. This is really
overhead, limiting and not really necessary unless we are doing
something special.

We can simply read/write the fifo that should also give exactly
what we need! This will also allow to read/write registers in
interrupt context, which was not possible with the special
command approach.

With previous approach number of interrupts generated
after enumeration are around 130:
$ cat /proc/interrupts  | grep soundwire
 21: 130 0 0 0 0 0 0 0 GICv3 234 Edge      soundwire

after this patch they are just 3 interrupts
$ cat /proc/interrupts  | grep soundwire
 21: 3 0 0 0 0 0 0 0 GICv3 234 Edge      soundwire

This has significantly not only reduced interrupting CPU during enumeration
but also during streaming!

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/soundwire/qcom.c | 178 ++++++++++++++++++++++-----------------
 1 file changed, 99 insertions(+), 79 deletions(-)

diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c
index 6a7c0acc8d89..e1cf821ea5e0 100644
--- a/drivers/soundwire/qcom.c
+++ b/drivers/soundwire/qcom.c
@@ -38,11 +38,13 @@
 #define SWRM_CMD_FIFO_WR_CMD					0x300
 #define SWRM_CMD_FIFO_RD_CMD					0x304
 #define SWRM_CMD_FIFO_CMD					0x308
+#define SWRM_CMD_FIFO_FLUSH					0x1
 #define SWRM_CMD_FIFO_STATUS					0x30C
 #define SWRM_CMD_FIFO_CFG_ADDR					0x314
 #define SWRM_CONTINUE_EXEC_ON_CMD_IGNORE			BIT(31)
 #define SWRM_RD_WR_CMD_RETRIES					0x7
 #define SWRM_CMD_FIFO_RD_FIFO_ADDR				0x318
+#define SWRM_RD_FIFO_CMD_ID_MASK				GENMASK(11, 8)
 #define SWRM_ENUMERATOR_CFG_ADDR				0x500
 #define SWRM_MCP_FRAME_CTRL_BANK_ADDR(m)		(0x101C + 0x40 * (m))
 #define SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_BMSK			GENMASK(2, 0)
@@ -78,13 +80,16 @@
 #define SWRM_SPECIAL_CMD_ID	0xF
 #define MAX_FREQ_NUM		1
 #define TIMEOUT_MS		(2 * HZ)
-#define QCOM_SWRM_MAX_RD_LEN	0xf
+#define QCOM_SWRM_MAX_RD_LEN	0x1
 #define QCOM_SDW_MAX_PORTS	14
 #define DEFAULT_CLK_FREQ	9600000
 #define SWRM_MAX_DAIS		0xF
 #define SWR_INVALID_PARAM 0xFF
 #define SWR_HSTOP_MAX_VAL 0xF
 #define SWR_HSTART_MIN_VAL 0x0
+#define SWR_BROADCAST_CMD_ID    0x0F
+#define SWR_MAX_CMD_ID	14
+#define MAX_FIFO_RD_RETRY 3
 
 struct qcom_swrm_port_config {
 	u8 si;
@@ -103,10 +108,8 @@ struct qcom_swrm_ctrl {
 	struct device *dev;
 	struct regmap *regmap;
 	void __iomem *mmio;
-	struct completion *comp;
+	struct completion broadcast;
 	struct work_struct slave_work;
-	/* read/write lock */
-	spinlock_t comp_lock;
 	/* Port alloc/free lock */
 	struct mutex port_lock;
 	struct clk *hclk;
@@ -120,6 +123,8 @@ struct qcom_swrm_ctrl {
 	int rows_index;
 	unsigned long dout_port_mask;
 	unsigned long din_port_mask;
+	u8 rcmd_id;
+	u8 wcmd_id;
 	struct qcom_swrm_port_config pconfig[QCOM_SDW_MAX_PORTS];
 	struct sdw_stream_runtime *sruntime[SWRM_MAX_DAIS];
 	enum sdw_slave_status status[SDW_MAX_DEVICES];
@@ -198,77 +203,105 @@ static int qcom_swrm_cpu_reg_write(struct qcom_swrm_ctrl *ctrl, int reg,
 	return SDW_CMD_OK;
 }
 
-static int qcom_swrm_cmd_fifo_wr_cmd(struct qcom_swrm_ctrl *ctrl, u8 cmd_data,
-				     u8 dev_addr, u16 reg_addr)
+static u32 swrm_get_packed_reg_val(u8 *cmd_id, u8 cmd_data,
+				   u8 dev_addr, u16 reg_addr)
 {
-	DECLARE_COMPLETION_ONSTACK(comp);
-	unsigned long flags;
 	u32 val;
-	int ret;
-
-	spin_lock_irqsave(&ctrl->comp_lock, flags);
-	ctrl->comp = &comp;
-	spin_unlock_irqrestore(&ctrl->comp_lock, flags);
-	val = SWRM_REG_VAL_PACK(cmd_data, dev_addr,
-				SWRM_SPECIAL_CMD_ID, reg_addr);
-	ret = ctrl->reg_write(ctrl, SWRM_CMD_FIFO_WR_CMD, val);
-	if (ret)
-		goto err;
-
-	ret = wait_for_completion_timeout(ctrl->comp,
-					  msecs_to_jiffies(TIMEOUT_MS));
+	u8 id = *cmd_id;
 
-	if (!ret)
-		ret = SDW_CMD_IGNORED;
-	else
-		ret = SDW_CMD_OK;
-err:
-	spin_lock_irqsave(&ctrl->comp_lock, flags);
-	ctrl->comp = NULL;
-	spin_unlock_irqrestore(&ctrl->comp_lock, flags);
+	if (id != SWR_BROADCAST_CMD_ID) {
+		if (id < SWR_MAX_CMD_ID)
+			id += 1;
+		else
+			id = 0;
+		*cmd_id = id;
+	}
+	val = SWRM_REG_VAL_PACK(cmd_data, dev_addr, id, reg_addr);
 
-	return ret;
+	return val;
 }
 
-static int qcom_swrm_cmd_fifo_rd_cmd(struct qcom_swrm_ctrl *ctrl,
-				     u8 dev_addr, u16 reg_addr,
-				     u32 len, u8 *rval)
+
+static int qcom_swrm_cmd_fifo_wr_cmd(struct qcom_swrm_ctrl *swrm, u8 cmd_data,
+				     u8 dev_addr, u16 reg_addr)
 {
-	int i, ret;
-	u32 val;
-	DECLARE_COMPLETION_ONSTACK(comp);
-	unsigned long flags;
 
-	spin_lock_irqsave(&ctrl->comp_lock, flags);
-	ctrl->comp = &comp;
-	spin_unlock_irqrestore(&ctrl->comp_lock, flags);
+	u32 val;
+	int ret = 0;
+	u8 cmd_id = 0x0;
 
-	val = SWRM_REG_VAL_PACK(len, dev_addr, SWRM_SPECIAL_CMD_ID, reg_addr);
-	ret = ctrl->reg_write(ctrl, SWRM_CMD_FIFO_RD_CMD, val);
-	if (ret)
-		goto err;
+	if (dev_addr == SDW_BROADCAST_DEV_NUM) {
+		cmd_id = SWR_BROADCAST_CMD_ID;
+		val = swrm_get_packed_reg_val(&cmd_id, cmd_data,
+					      dev_addr, reg_addr);
+	} else {
+		val = swrm_get_packed_reg_val(&swrm->wcmd_id, cmd_data,
+					      dev_addr, reg_addr);
+	}
 
-	ret = wait_for_completion_timeout(ctrl->comp,
-					  msecs_to_jiffies(TIMEOUT_MS));
+	swrm->reg_write(swrm, SWRM_CMD_FIFO_WR_CMD, val);
+
+	/* version 1.3 or less */
+	if (swrm->version <= 0x01030000)
+		usleep_range(150, 155);
+
+	if (cmd_id == SWR_BROADCAST_CMD_ID) {
+		/*
+		 * sleep for 10ms for MSM soundwire variant to allow broadcast
+		 * command to complete.
+		 */
+		ret = wait_for_completion_timeout(&swrm->broadcast,
+						  msecs_to_jiffies(TIMEOUT_MS));
+		if (!ret)
+			ret = SDW_CMD_IGNORED;
+		else
+			ret = SDW_CMD_OK;
 
-	if (!ret) {
-		ret = SDW_CMD_IGNORED;
-		goto err;
 	} else {
 		ret = SDW_CMD_OK;
 	}
+	return ret;
+}
 
-	for (i = 0; i < len; i++) {
-		ctrl->reg_read(ctrl, SWRM_CMD_FIFO_RD_FIFO_ADDR, &val);
-		rval[i] = val & 0xFF;
-	}
+static int qcom_swrm_cmd_fifo_rd_cmd(struct qcom_swrm_ctrl *swrm,
+				     u8 dev_addr, u16 reg_addr,
+				     u32 len, u8 *rval)
+{
+	u32 cmd_data, cmd_id, val, retry_attempt = 0;
+
+	val = swrm_get_packed_reg_val(&swrm->rcmd_id, len, dev_addr, reg_addr);
+
+	/* wait for FIFO RD to complete to avoid overflow */
+	usleep_range(100, 105);
+	swrm->reg_write(swrm, SWRM_CMD_FIFO_RD_CMD, val);
+	/* wait for FIFO RD CMD complete to avoid overflow */
+	usleep_range(250, 255);
+
+	do {
+		swrm->reg_read(swrm, SWRM_CMD_FIFO_RD_FIFO_ADDR, &cmd_data);
+		rval[0] = cmd_data & 0xFF;
+		cmd_id = FIELD_GET(SWRM_RD_FIFO_CMD_ID_MASK, cmd_data);
+
+		if (cmd_id != swrm->rcmd_id) {
+			if (retry_attempt < (MAX_FIFO_RD_RETRY - 1)) {
+				/* wait 500 us before retry on fifo read failure */
+				usleep_range(500, 505);
+				swrm->reg_write(swrm, SWRM_CMD_FIFO_CMD,
+						SWRM_CMD_FIFO_FLUSH);
+				swrm->reg_write(swrm, SWRM_CMD_FIFO_RD_CMD, val);
+			}
+			retry_attempt++;
+		} else {
+			return SDW_CMD_OK;
+		}
 
-err:
-	spin_lock_irqsave(&ctrl->comp_lock, flags);
-	ctrl->comp = NULL;
-	spin_unlock_irqrestore(&ctrl->comp_lock, flags);
+	} while (retry_attempt < MAX_FIFO_RD_RETRY);
 
-	return ret;
+	dev_err(swrm->dev, "failed to read fifo: reg: 0x%x, rcmd_id: 0x%x,\
+		dev_num: 0x%x, cmd_data: 0x%x\n",
+		reg_addr, swrm->rcmd_id, dev_addr, cmd_data);
+
+	return SDW_CMD_IGNORED;
 }
 
 static void qcom_swrm_get_device_status(struct qcom_swrm_ctrl *ctrl)
@@ -291,7 +324,6 @@ static irqreturn_t qcom_swrm_irq_handler(int irq, void *dev_id)
 {
 	struct qcom_swrm_ctrl *ctrl = dev_id;
 	u32 sts, value;
-	unsigned long flags;
 
 	ctrl->reg_read(ctrl, SWRM_INTERRUPT_STATUS, &sts);
 
@@ -304,8 +336,10 @@ static irqreturn_t qcom_swrm_irq_handler(int irq, void *dev_id)
 	}
 
 	if ((sts & SWRM_INTERRUPT_STATUS_NEW_SLAVE_ATTACHED) ||
-	    sts & SWRM_INTERRUPT_STATUS_CHANGE_ENUM_SLAVE_STATUS)
-		schedule_work(&ctrl->slave_work);
+	    sts & SWRM_INTERRUPT_STATUS_CHANGE_ENUM_SLAVE_STATUS) {
+		qcom_swrm_get_device_status(ctrl);
+		sdw_handle_slave_status(&ctrl->bus, ctrl->status);
+	}
 
 	/**
 	 * clear the interrupt before complete() is called, as complete can
@@ -314,15 +348,12 @@ static irqreturn_t qcom_swrm_irq_handler(int irq, void *dev_id)
 	 */
 	ctrl->reg_write(ctrl, SWRM_INTERRUPT_CLEAR, sts);
 
-	if (sts & SWRM_INTERRUPT_STATUS_SPECIAL_CMD_ID_FINISHED) {
-		spin_lock_irqsave(&ctrl->comp_lock, flags);
-		if (ctrl->comp)
-			complete(ctrl->comp);
-		spin_unlock_irqrestore(&ctrl->comp_lock, flags);
-	}
+	if (sts & SWRM_INTERRUPT_STATUS_SPECIAL_CMD_ID_FINISHED)
+		complete(&ctrl->broadcast);
 
 	return IRQ_HANDLED;
 }
+
 static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl)
 {
 	u32 val;
@@ -570,16 +601,6 @@ static u32 qcom_swrm_freq_tbl[MAX_FREQ_NUM] = {
 	DEFAULT_CLK_FREQ,
 };
 
-static void qcom_swrm_slave_wq(struct work_struct *work)
-{
-	struct qcom_swrm_ctrl *ctrl =
-			container_of(work, struct qcom_swrm_ctrl, slave_work);
-
-	qcom_swrm_get_device_status(ctrl);
-	sdw_handle_slave_status(&ctrl->bus, ctrl->status);
-}
-
-
 static void qcom_swrm_stream_free_ports(struct qcom_swrm_ctrl *ctrl,
 					struct sdw_stream_runtime *stream)
 {
@@ -936,9 +957,8 @@ static int qcom_swrm_probe(struct platform_device *pdev)
 
 	ctrl->dev = dev;
 	dev_set_drvdata(&pdev->dev, ctrl);
-	spin_lock_init(&ctrl->comp_lock);
 	mutex_init(&ctrl->port_lock);
-	INIT_WORK(&ctrl->slave_work, qcom_swrm_slave_wq);
+	init_completion(&ctrl->broadcast);
 
 	ctrl->bus.ops = &qcom_swrm_ops;
 	ctrl->bus.port_ops = &qcom_swrm_port_ops;
-- 
2.21.0


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

* [PATCH v2 5/5] soundwire: qcom: add support to new interrupts
  2021-02-26 15:58 [PATCH v2 0/5] soundwire: qcom: various improvements Srinivas Kandagatla
                   ` (3 preceding siblings ...)
  2021-02-26 15:58 ` [PATCH v2 4/5] soundwire: qcom: update register read/write routine Srinivas Kandagatla
@ 2021-02-26 15:58 ` Srinivas Kandagatla
  4 siblings, 0 replies; 11+ messages in thread
From: Srinivas Kandagatla @ 2021-02-26 15:58 UTC (permalink / raw)
  To: vkoul
  Cc: yung-chuan.liao, pierre-louis.bossart, sanyog.r.kale,
	linux-kernel, alsa-devel, Srinivas Kandagatla

Add support to new interrupts which includes reporting some of the
error interrupts and adding support to SLAVE pending interrupt!

This patch also changes the interrupt handler behaviour on handling
any pending interrupts by checking it before returning out of irq handler.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/soundwire/qcom.c | 161 ++++++++++++++++++++++++++++++++-------
 1 file changed, 135 insertions(+), 26 deletions(-)

diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c
index e1cf821ea5e0..8438f9812d7c 100644
--- a/drivers/soundwire/qcom.c
+++ b/drivers/soundwire/qcom.c
@@ -28,10 +28,21 @@
 #define SWRM_COMP_PARAMS_DIN_PORTS_MASK				GENMASK(9, 5)
 #define SWRM_INTERRUPT_STATUS					0x200
 #define SWRM_INTERRUPT_STATUS_RMSK				GENMASK(16, 0)
+#define SWRM_INTERRUPT_STATUS_SLAVE_PEND_IRQ			BIT(0)
 #define SWRM_INTERRUPT_STATUS_NEW_SLAVE_ATTACHED		BIT(1)
 #define SWRM_INTERRUPT_STATUS_CHANGE_ENUM_SLAVE_STATUS		BIT(2)
+#define SWRM_INTERRUPT_STATUS_MASTER_CLASH_DET			BIT(3)
+#define SWRM_INTERRUPT_STATUS_RD_FIFO_OVERFLOW			BIT(4)
+#define SWRM_INTERRUPT_STATUS_RD_FIFO_UNDERFLOW			BIT(5)
+#define SWRM_INTERRUPT_STATUS_WR_CMD_FIFO_OVERFLOW		BIT(6)
 #define SWRM_INTERRUPT_STATUS_CMD_ERROR				BIT(7)
+#define SWRM_INTERRUPT_STATUS_DOUT_PORT_COLLISION		BIT(8)
+#define SWRM_INTERRUPT_STATUS_READ_EN_RD_VALID_MISMATCH		BIT(9)
 #define SWRM_INTERRUPT_STATUS_SPECIAL_CMD_ID_FINISHED		BIT(10)
+#define SWRM_INTERRUPT_STATUS_BUS_RESET_FINISHED_V2             BIT(13)
+#define SWRM_INTERRUPT_STATUS_CLK_STOP_FINISHED_V2              BIT(14)
+#define SWRM_INTERRUPT_STATUS_EXT_CLK_STOP_WAKEUP               BIT(16)
+#define SWRM_INTERRUPT_MAX					17
 #define SWRM_INTERRUPT_MASK_ADDR				0x204
 #define SWRM_INTERRUPT_CLEAR					0x208
 #define SWRM_INTERRUPT_CPU_EN					0x210
@@ -58,6 +69,7 @@
 #define SWRM_MCP_STATUS_BANK_NUM_MASK				BIT(0)
 #define SWRM_MCP_SLV_STATUS					0x1090
 #define SWRM_MCP_SLV_STATUS_MASK				GENMASK(1, 0)
+#define SWRM_MCP_SLV_STATUS_SZ					2
 #define SWRM_DP_PORT_CTRL_BANK(n, m)	(0x1124 + 0x100 * (n - 1) + 0x40 * m)
 #define SWRM_DP_PORT_CTRL_2_BANK(n, m)	(0x1128 + 0x100 * (n - 1) + 0x40 * m)
 #define SWRM_DP_BLOCK_CTRL_1(n)		(0x112C + 0x100 * (n - 1))
@@ -123,6 +135,7 @@ struct qcom_swrm_ctrl {
 	int rows_index;
 	unsigned long dout_port_mask;
 	unsigned long din_port_mask;
+	u32 intr_mask;
 	u8 rcmd_id;
 	u8 wcmd_id;
 	struct qcom_swrm_port_config pconfig[QCOM_SDW_MAX_PORTS];
@@ -304,6 +317,25 @@ static int qcom_swrm_cmd_fifo_rd_cmd(struct qcom_swrm_ctrl *swrm,
 	return SDW_CMD_IGNORED;
 }
 
+static int qcom_swrm_get_alert_slave_dev_num(struct qcom_swrm_ctrl *ctrl)
+{
+	u32 val, status;
+	int dev_num;
+
+	ctrl->reg_read(ctrl, SWRM_MCP_SLV_STATUS, &val);
+
+	for (dev_num = 0; dev_num < SDW_MAX_DEVICES; dev_num++) {
+		status = (val >> (dev_num * SWRM_MCP_SLV_STATUS_SZ));
+
+		if ((status & SWRM_MCP_SLV_STATUS_MASK) == SDW_SLAVE_ALERT) {
+			ctrl->status[dev_num] = status;
+			return dev_num;
+		}
+	}
+
+	return -EINVAL;
+}
+
 static void qcom_swrm_get_device_status(struct qcom_swrm_ctrl *ctrl)
 {
 	u32 val;
@@ -322,36 +354,112 @@ static void qcom_swrm_get_device_status(struct qcom_swrm_ctrl *ctrl)
 
 static irqreturn_t qcom_swrm_irq_handler(int irq, void *dev_id)
 {
-	struct qcom_swrm_ctrl *ctrl = dev_id;
-	u32 sts, value;
+	struct qcom_swrm_ctrl *swrm = dev_id;
+	u32 value, intr_sts, intr_sts_masked;
+	u32 i;
+	u8 devnum = 0;
+	int ret = IRQ_HANDLED;
 
-	ctrl->reg_read(ctrl, SWRM_INTERRUPT_STATUS, &sts);
+	swrm->reg_read(swrm, SWRM_INTERRUPT_STATUS, &intr_sts);
+	intr_sts_masked = intr_sts & swrm->intr_mask;
 
-	if (sts & SWRM_INTERRUPT_STATUS_CMD_ERROR) {
-		ctrl->reg_read(ctrl, SWRM_CMD_FIFO_STATUS, &value);
-		dev_err_ratelimited(ctrl->dev,
-				    "CMD error, fifo status 0x%x\n",
-				     value);
-		ctrl->reg_write(ctrl, SWRM_CMD_FIFO_CMD, 0x1);
-	}
-
-	if ((sts & SWRM_INTERRUPT_STATUS_NEW_SLAVE_ATTACHED) ||
-	    sts & SWRM_INTERRUPT_STATUS_CHANGE_ENUM_SLAVE_STATUS) {
-		qcom_swrm_get_device_status(ctrl);
-		sdw_handle_slave_status(&ctrl->bus, ctrl->status);
-	}
-
-	/**
-	 * clear the interrupt before complete() is called, as complete can
-	 * schedule new read/writes which require interrupts, clearing the
-	 * interrupt would avoid missing interrupts in such cases.
-	 */
-	ctrl->reg_write(ctrl, SWRM_INTERRUPT_CLEAR, sts);
+	do {
+		for (i = 0; i < SWRM_INTERRUPT_MAX; i++) {
+			value = intr_sts_masked & (1 << i);
+			if (!value)
+				continue;
+
+			switch (value) {
+			case SWRM_INTERRUPT_STATUS_SLAVE_PEND_IRQ:
+				devnum = qcom_swrm_get_alert_slave_dev_num(swrm);
+				if (devnum < 0) {
+					dev_err_ratelimited(swrm->dev,
+					    "no slave alert found.spurious interrupt\n");
+				} else {
+					sdw_handle_slave_status(&swrm->bus, swrm->status);
+				}
 
-	if (sts & SWRM_INTERRUPT_STATUS_SPECIAL_CMD_ID_FINISHED)
-		complete(&ctrl->broadcast);
+				break;
+			case SWRM_INTERRUPT_STATUS_NEW_SLAVE_ATTACHED:
+			case SWRM_INTERRUPT_STATUS_CHANGE_ENUM_SLAVE_STATUS:
+				dev_err_ratelimited(swrm->dev, "%s: SWR new slave attached\n",
+					__func__);
+				qcom_swrm_get_device_status(swrm);
+				sdw_handle_slave_status(&swrm->bus, swrm->status);
+				break;
+			case SWRM_INTERRUPT_STATUS_MASTER_CLASH_DET:
+				dev_err_ratelimited(swrm->dev,
+						"%s: SWR bus clsh detected\n",
+						__func__);
+				swrm->intr_mask &= ~SWRM_INTERRUPT_STATUS_MASTER_CLASH_DET;
+				swrm->reg_write(swrm, SWRM_INTERRUPT_CPU_EN, swrm->intr_mask);
+				break;
+			case SWRM_INTERRUPT_STATUS_RD_FIFO_OVERFLOW:
+				swrm->reg_read(swrm, SWRM_CMD_FIFO_STATUS, &value);
+				dev_err_ratelimited(swrm->dev,
+					"%s: SWR read FIFO overflow fifo status 0x%x\n",
+					__func__, value);
+				break;
+			case SWRM_INTERRUPT_STATUS_RD_FIFO_UNDERFLOW:
+				swrm->reg_read(swrm, SWRM_CMD_FIFO_STATUS, &value);
+				dev_err_ratelimited(swrm->dev,
+					"%s: SWR read FIFO underflow fifo status 0x%x\n",
+					__func__, value);
+				break;
+			case SWRM_INTERRUPT_STATUS_WR_CMD_FIFO_OVERFLOW:
+				swrm->reg_read(swrm, SWRM_CMD_FIFO_STATUS, &value);
+				dev_err(swrm->dev,
+					"%s: SWR write FIFO overflow fifo status %x\n",
+					__func__, value);
+				swrm->reg_write(swrm, SWRM_CMD_FIFO_CMD, 0x1);
+				break;
+			case SWRM_INTERRUPT_STATUS_CMD_ERROR:
+				swrm->reg_read(swrm, SWRM_CMD_FIFO_STATUS, &value);
+				dev_err_ratelimited(swrm->dev,
+					"%s: SWR CMD error, fifo status 0x%x, flushing fifo\n",
+					__func__, value);
+				swrm->reg_write(swrm, SWRM_CMD_FIFO_CMD, 0x1);
+				break;
+			case SWRM_INTERRUPT_STATUS_DOUT_PORT_COLLISION:
+				dev_err_ratelimited(swrm->dev,
+						"%s: SWR Port collision detected\n",
+						__func__);
+				swrm->intr_mask &= ~SWRM_INTERRUPT_STATUS_DOUT_PORT_COLLISION;
+				swrm->reg_write(swrm,
+					SWRM_INTERRUPT_CPU_EN, swrm->intr_mask);
+				break;
+			case SWRM_INTERRUPT_STATUS_READ_EN_RD_VALID_MISMATCH:
+				dev_err_ratelimited(swrm->dev,
+					"%s: SWR read enable valid mismatch\n",
+					__func__);
+				swrm->intr_mask &=
+					~SWRM_INTERRUPT_STATUS_READ_EN_RD_VALID_MISMATCH;
+				swrm->reg_write(swrm,
+					SWRM_INTERRUPT_CPU_EN, swrm->intr_mask);
+				break;
+			case SWRM_INTERRUPT_STATUS_SPECIAL_CMD_ID_FINISHED:
+				complete(&swrm->broadcast);
+				break;
+			case SWRM_INTERRUPT_STATUS_BUS_RESET_FINISHED_V2:
+				break;
+			case SWRM_INTERRUPT_STATUS_CLK_STOP_FINISHED_V2:
+				break;
+			case SWRM_INTERRUPT_STATUS_EXT_CLK_STOP_WAKEUP:
+				break;
+			default:
+				dev_err_ratelimited(swrm->dev,
+						"%s: SWR unknown interrupt value: %d\n",
+						__func__, value);
+				ret = IRQ_NONE;
+				break;
+			}
+		}
+		swrm->reg_write(swrm, SWRM_INTERRUPT_CLEAR, intr_sts);
+		swrm->reg_read(swrm, SWRM_INTERRUPT_STATUS, &intr_sts);
+		intr_sts_masked = intr_sts & swrm->intr_mask;
+	} while (intr_sts_masked);
 
-	return IRQ_HANDLED;
+	return ret;
 }
 
 static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl)
@@ -367,6 +475,7 @@ static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl)
 	/* Disable Auto enumeration */
 	ctrl->reg_write(ctrl, SWRM_ENUMERATOR_CFG_ADDR, 0);
 
+	ctrl->intr_mask = SWRM_INTERRUPT_STATUS_RMSK;
 	/* Mask soundwire interrupts */
 	ctrl->reg_write(ctrl, SWRM_INTERRUPT_MASK_ADDR,
 			SWRM_INTERRUPT_STATUS_RMSK);
-- 
2.21.0


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

* Re: [PATCH v2 1/5] soundwire: qcom: add support to missing transport params
  2021-02-26 15:58 ` [PATCH v2 1/5] soundwire: qcom: add support to missing transport params Srinivas Kandagatla
@ 2021-02-26 16:45   ` Pierre-Louis Bossart
  2021-03-02 10:13     ` Srinivas Kandagatla
  0 siblings, 1 reply; 11+ messages in thread
From: Pierre-Louis Bossart @ 2021-02-26 16:45 UTC (permalink / raw)
  To: Srinivas Kandagatla, vkoul
  Cc: yung-chuan.liao, sanyog.r.kale, linux-kernel, alsa-devel



On 2/26/21 9:58 AM, Srinivas Kandagatla wrote:
> Some of the transport parameters derived from device tree
> are not fully parsed by the driver.
> 
> This patch adds support to parse those missing parameters.
> 
> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> ---
>   drivers/soundwire/qcom.c | 99 ++++++++++++++++++++++++++++++++++++++--
>   1 file changed, 95 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c
> index 6d22df01f354..fee7465c72c2 100644
> --- a/drivers/soundwire/qcom.c
> +++ b/drivers/soundwire/qcom.c
> @@ -54,7 +54,13 @@
>   #define SWRM_MCP_SLV_STATUS					0x1090
>   #define SWRM_MCP_SLV_STATUS_MASK				GENMASK(1, 0)
>   #define SWRM_DP_PORT_CTRL_BANK(n, m)	(0x1124 + 0x100 * (n - 1) + 0x40 * m)
> +#define SWRM_DP_PORT_CTRL_2_BANK(n, m)	(0x1128 + 0x100 * (n - 1) + 0x40 * m)
> +#define SWRM_DP_BLOCK_CTRL_1(n)		(0x112C + 0x100 * (n - 1))
> +#define SWRM_DP_BLOCK_CTRL2_BANK(n, m)	(0x1130 + 0x100 * (n - 1) + 0x40 * m)
> +#define SWRM_DP_PORT_HCTRL_BANK(n, m)	(0x1134 + 0x100 * (n - 1) + 0x40 * m)
>   #define SWRM_DP_BLOCK_CTRL3_BANK(n, m)	(0x1138 + 0x100 * (n - 1) + 0x40 * m)
> +#define SWRM_DIN_DPn_PCM_PORT_CTRL(n)	(0x1054 + 0x100 * (n - 1))
> +
>   #define SWRM_DP_PORT_CTRL_EN_CHAN_SHFT				0x18
>   #define SWRM_DP_PORT_CTRL_OFFSET2_SHFT				0x10
>   #define SWRM_DP_PORT_CTRL_OFFSET1_SHFT				0x08
> @@ -73,12 +79,20 @@
>   #define QCOM_SDW_MAX_PORTS	14
>   #define DEFAULT_CLK_FREQ	9600000
>   #define SWRM_MAX_DAIS		0xF
> +#define SWR_INVALID_PARAM 0xFF
> +#define SWR_HSTOP_MAX_VAL 0xF
> +#define SWR_HSTART_MIN_VAL 0x0
>   
>   struct qcom_swrm_port_config {
>   	u8 si;
>   	u8 off1;
>   	u8 off2;
>   	u8 bp_mode;
> +	u8 hstart;
> +	u8 hstop;
> +	u8 word_length;
> +	u8 blk_group_count;
> +	u8 lane_control;
>   };
>   
>   struct qcom_swrm_ctrl {
> @@ -396,7 +410,13 @@ static int qcom_swrm_port_params(struct sdw_bus *bus,
>   				 struct sdw_port_params *p_params,
>   				 unsigned int bank)
>   {
> -	/* TBD */
> +	struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus);
> +
> +	if (p_params->bps != SWR_INVALID_PARAM)

this is odd. sdw_port_params is a structure in 
include/linux/soundwire/sdw.h, but here you are comparing the value with 
a private qualcomm-defined value.

The Word length of the port is limited by the standard (64), so your 
choice of 0xFF for SWR_INVALID_PARAM is legit, but it should be a 
'public' define.

> +		return ctrl->reg_write(ctrl,
> +				       SWRM_DP_BLOCK_CTRL_1(p_params->num),
> +				       p_params->bps - 1);
> +
>   	return 0;
>   }
>   
> @@ -415,10 +435,32 @@ static int qcom_swrm_transport_params(struct sdw_bus *bus,
>   
>   	ret = ctrl->reg_write(ctrl, reg, value);
>   
> -	if (!ret && params->blk_pkg_mode) {
> -		reg = SWRM_DP_BLOCK_CTRL3_BANK(params->port_num, bank);
> +	if (params->lane_ctrl != SWR_INVALID_PARAM) {
> +		reg = SWRM_DP_PORT_CTRL_2_BANK(params->port_num, bank);
> +		value = params->lane_ctrl;
> +		ret = ctrl->reg_write(ctrl, reg, value);
> +	}
>   
> -		ret = ctrl->reg_write(ctrl, reg, 1);
> +	if (params->blk_grp_ctrl != SWR_INVALID_PARAM) {
> +		reg = SWRM_DP_BLOCK_CTRL2_BANK(params->port_num, bank);
> +		value = params->blk_grp_ctrl;
> +		ret = ctrl->reg_write(ctrl, reg, value);
> +	}
> +
> +	if (params->hstart != SWR_INVALID_PARAM
> +			&& params->hstop != SWR_INVALID_PARAM) {
> +		reg = SWRM_DP_PORT_HCTRL_BANK(params->port_num, bank);
> +		value = (params->hstop << 4) | params->hstart;
> +		ret = ctrl->reg_write(ctrl, reg, value);
> +	} else {
> +		reg = SWRM_DP_PORT_HCTRL_BANK(params->port_num, bank);
> +		value = (SWR_HSTOP_MAX_VAL << 4) | SWR_HSTART_MIN_VAL;
> +		ret = ctrl->reg_write(ctrl, reg, value);
> +	}
> +
> +	if (params->blk_pkg_mode != SWR_INVALID_PARAM) {
> +		reg = SWRM_DP_BLOCK_CTRL3_BANK(params->port_num, bank);
> +		ret = ctrl->reg_write(ctrl, reg, params->blk_pkg_mode);
>   	}

same comments here, you should define a public define for all those 
parameters.

>   	return ret;
> @@ -470,6 +512,17 @@ static int qcom_swrm_compute_params(struct sdw_bus *bus)
>   			p_rt->transport_params.offset1 = pcfg->off1;
>   			p_rt->transport_params.offset2 = pcfg->off2;
>   			p_rt->transport_params.blk_pkg_mode = pcfg->bp_mode;
> +			p_rt->transport_params.blk_grp_ctrl = pcfg->blk_group_count;
> +			p_rt->transport_params.hstart = pcfg->hstart;
> +			p_rt->transport_params.hstop = pcfg->hstop;
> +			p_rt->transport_params.lane_ctrl = pcfg->lane_control;
> +			if (pcfg->word_length != SWR_INVALID_PARAM) {
> +				sdw_fill_port_params(&p_rt->port_params,
> +					     p_rt->num,  pcfg->word_length + 1,
> +					     SDW_PORT_FLOW_MODE_ISOCH,
> +					     SDW_PORT_DATA_MODE_NORMAL);
> +			}
> +
>   		}
>   
>   		list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) {
> @@ -481,6 +534,18 @@ static int qcom_swrm_compute_params(struct sdw_bus *bus)
>   				p_rt->transport_params.offset1 = pcfg->off1;
>   				p_rt->transport_params.offset2 = pcfg->off2;
>   				p_rt->transport_params.blk_pkg_mode = pcfg->bp_mode;
> +				p_rt->transport_params.blk_grp_ctrl = pcfg->blk_group_count;
> +
> +				p_rt->transport_params.hstart = pcfg->hstart;
> +				p_rt->transport_params.hstop = pcfg->hstop;
> +				p_rt->transport_params.lane_ctrl = pcfg->lane_control;
> +				if (pcfg->word_length != SWR_INVALID_PARAM) {
> +					sdw_fill_port_params(&p_rt->port_params,
> +						     p_rt->num,
> +						     pcfg->word_length + 1,
> +						     SDW_PORT_FLOW_MODE_ISOCH,
> +						     SDW_PORT_DATA_MODE_NORMAL);
> +				}
>   				i++;
>   			}
>   		}
> @@ -728,6 +793,11 @@ static int qcom_swrm_get_port_config(struct qcom_swrm_ctrl *ctrl)
>   	u8 off2[QCOM_SDW_MAX_PORTS];
>   	u8 si[QCOM_SDW_MAX_PORTS];
>   	u8 bp_mode[QCOM_SDW_MAX_PORTS] = { 0, };
> +	u8 hstart[QCOM_SDW_MAX_PORTS];
> +	u8 hstop[QCOM_SDW_MAX_PORTS];
> +	u8 word_length[QCOM_SDW_MAX_PORTS];
> +	u8 blk_group_count[QCOM_SDW_MAX_PORTS];
> +	u8 lane_control[QCOM_SDW_MAX_PORTS];
>   	int i, ret, nports, val;
>   
>   	ctrl->reg_read(ctrl, SWRM_COMP_PARAMS, &val);
> @@ -772,11 +842,32 @@ static int qcom_swrm_get_port_config(struct qcom_swrm_ctrl *ctrl)
>   
>   	ret = of_property_read_u8_array(np, "qcom,ports-block-pack-mode",
>   					bp_mode, nports);
> +
> +	memset(hstart, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS);
> +	of_property_read_u8_array(np, "qcom,ports-hstart", hstart, nports);
> +
> +	memset(hstop, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS);
> +	of_property_read_u8_array(np, "qcom,ports-hstop", hstop, nports);
> +
> +	memset(word_length, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS);
> +	of_property_read_u8_array(np, "qcom,ports-word-length", word_length, nports);
> +
> +	memset(blk_group_count, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS);
> +	of_property_read_u8_array(np, "qcom,ports-block-group-count", blk_group_count, nports);
> +
> +	memset(lane_control, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS);
> +	of_property_read_u8_array(np, "qcom,ports-lane-control", lane_control, nports);
> +
>   	for (i = 0; i < nports; i++) {
>   		ctrl->pconfig[i].si = si[i];
>   		ctrl->pconfig[i].off1 = off1[i];
>   		ctrl->pconfig[i].off2 = off2[i];
>   		ctrl->pconfig[i].bp_mode = bp_mode[i];
> +		ctrl->pconfig[i].hstart = hstart[i];
> +		ctrl->pconfig[i].hstop = hstop[i];
> +		ctrl->pconfig[i].word_length = word_length[i];
> +		ctrl->pconfig[i].blk_group_count = blk_group_count[i];
> +		ctrl->pconfig[i].lane_control = lane_control[i];
>   	}

I don't get why you test the values parsed from DT before writing the 
registers. Why do test them here? if some values are incorrect it's much 
better to provide an error log instead of writing a partially valid 
setup to hardware, no?
>   
>   	return 0;
> 

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

* Re: [PATCH v2 1/5] soundwire: qcom: add support to missing transport params
  2021-02-26 16:45   ` Pierre-Louis Bossart
@ 2021-03-02 10:13     ` Srinivas Kandagatla
  2021-03-02 14:29       ` Pierre-Louis Bossart
  0 siblings, 1 reply; 11+ messages in thread
From: Srinivas Kandagatla @ 2021-03-02 10:13 UTC (permalink / raw)
  To: Pierre-Louis Bossart, vkoul
  Cc: yung-chuan.liao, sanyog.r.kale, linux-kernel, alsa-devel

Thanks Pierre for reviewing the patches!

On 26/02/2021 16:45, Pierre-Louis Bossart wrote:
> 
> 
> On 2/26/21 9:58 AM, Srinivas Kandagatla wrote:
>> Some of the transport parameters derived from device tree
>> are not fully parsed by the driver.
>>
>> This patch adds support to parse those missing parameters.
>>
>> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
>> ---
>>   drivers/soundwire/qcom.c | 99 ++++++++++++++++++++++++++++++++++++++--
>>   1 file changed, 95 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c
>> index 6d22df01f354..fee7465c72c2 100644
>> --- a/drivers/soundwire/qcom.c
>> +++ b/drivers/soundwire/qcom.c
>> @@ -54,7 +54,13 @@
>>   #define SWRM_MCP_SLV_STATUS                    0x1090
>>   #define SWRM_MCP_SLV_STATUS_MASK                GENMASK(1, 0)
>>   #define SWRM_DP_PORT_CTRL_BANK(n, m)    (0x1124 + 0x100 * (n - 1) + 
>> 0x40 * m)
>> +#define SWRM_DP_PORT_CTRL_2_BANK(n, m)    (0x1128 + 0x100 * (n - 1) + 
>> 0x40 * m)
>> +#define SWRM_DP_BLOCK_CTRL_1(n)        (0x112C + 0x100 * (n - 1))
>> +#define SWRM_DP_BLOCK_CTRL2_BANK(n, m)    (0x1130 + 0x100 * (n - 1) + 
>> 0x40 * m)
>> +#define SWRM_DP_PORT_HCTRL_BANK(n, m)    (0x1134 + 0x100 * (n - 1) + 
>> 0x40 * m)
>>   #define SWRM_DP_BLOCK_CTRL3_BANK(n, m)    (0x1138 + 0x100 * (n - 1) 
>> + 0x40 * m)
>> +#define SWRM_DIN_DPn_PCM_PORT_CTRL(n)    (0x1054 + 0x100 * (n - 1))
>> +
>>   #define SWRM_DP_PORT_CTRL_EN_CHAN_SHFT                0x18
>>   #define SWRM_DP_PORT_CTRL_OFFSET2_SHFT                0x10
>>   #define SWRM_DP_PORT_CTRL_OFFSET1_SHFT                0x08
>> @@ -73,12 +79,20 @@
>>   #define QCOM_SDW_MAX_PORTS    14
>>   #define DEFAULT_CLK_FREQ    9600000
>>   #define SWRM_MAX_DAIS        0xF
>> +#define SWR_INVALID_PARAM 0xFF
>> +#define SWR_HSTOP_MAX_VAL 0xF
>> +#define SWR_HSTART_MIN_VAL 0x0
>>   struct qcom_swrm_port_config {
>>       u8 si;
>>       u8 off1;
>>       u8 off2;
>>       u8 bp_mode;
>> +    u8 hstart;
>> +    u8 hstop;
>> +    u8 word_length;
>> +    u8 blk_group_count;
>> +    u8 lane_control;
>>   };
>>   struct qcom_swrm_ctrl {
>> @@ -396,7 +410,13 @@ static int qcom_swrm_port_params(struct sdw_bus 
>> *bus,
>>                    struct sdw_port_params *p_params,
>>                    unsigned int bank)
>>   {
>> -    /* TBD */
>> +    struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus);
>> +
>> +    if (p_params->bps != SWR_INVALID_PARAM)
> 
> this is odd. sdw_port_params is a structure in 
> include/linux/soundwire/sdw.h, but here you are comparing the value with 
> a private qualcomm-defined value.
> 
> The Word length of the port is limited by the standard (64), so your 
> choice of 0xFF for SWR_INVALID_PARAM is legit, but it should be a 
> 'public' define.
> 
Am not sure if this really make sense to add it as a public define!

This is more of how the parameters are marked as not applicable for some 
ports while passing these values from device tree.


But I agree with your comments, now I have modified the code to look at 
the qcom_swrm_port_config instead of checking the "struct 
sdw_port_params" or "struct sdw_transport_params" which should make this 
INVALID flag not relevant to these data-structures anymore!


>> +        return ctrl->reg_write(ctrl,
>> +                       SWRM_DP_BLOCK_CTRL_1(p_params->num),
>> +                       p_params->bps - 1);
>> +
>>       return 0;
>>   }
>> @@ -415,10 +435,32 @@ static int qcom_swrm_transport_params(struct 
>> sdw_bus *bus,
>>       ret = ctrl->reg_write(ctrl, reg, value);
>> -    if (!ret && params->blk_pkg_mode) {
>> -        reg = SWRM_DP_BLOCK_CTRL3_BANK(params->port_num, bank);
>> +    if (params->lane_ctrl != SWR_INVALID_PARAM) {
>> +        reg = SWRM_DP_PORT_CTRL_2_BANK(params->port_num, bank);
>> +        value = params->lane_ctrl;
>> +        ret = ctrl->reg_write(ctrl, reg, value);
>> +    }
>> -        ret = ctrl->reg_write(ctrl, reg, 1);
>> +    if (params->blk_grp_ctrl != SWR_INVALID_PARAM) {
>> +        reg = SWRM_DP_BLOCK_CTRL2_BANK(params->port_num, bank);
>> +        value = params->blk_grp_ctrl;
>> +        ret = ctrl->reg_write(ctrl, reg, value);
>> +    }
>> +
>> +    if (params->hstart != SWR_INVALID_PARAM
>> +            && params->hstop != SWR_INVALID_PARAM) {
>> +        reg = SWRM_DP_PORT_HCTRL_BANK(params->port_num, bank);
>> +        value = (params->hstop << 4) | params->hstart;
>> +        ret = ctrl->reg_write(ctrl, reg, value);
>> +    } else {
>> +        reg = SWRM_DP_PORT_HCTRL_BANK(params->port_num, bank);
>> +        value = (SWR_HSTOP_MAX_VAL << 4) | SWR_HSTART_MIN_VAL;
>> +        ret = ctrl->reg_write(ctrl, reg, value);
>> +    }
>> +
>> +    if (params->blk_pkg_mode != SWR_INVALID_PARAM) {
>> +        reg = SWRM_DP_BLOCK_CTRL3_BANK(params->port_num, bank);
>> +        ret = ctrl->reg_write(ctrl, reg, params->blk_pkg_mode);
>>       }
> 
> same comments here, you should define a public define for all those 
> parameters.
> 
>>       return ret;
>> @@ -470,6 +512,17 @@ static int qcom_swrm_compute_params(struct 
>> sdw_bus *bus)
>>               p_rt->transport_params.offset1 = pcfg->off1;
>>               p_rt->transport_params.offset2 = pcfg->off2;
>>               p_rt->transport_params.blk_pkg_mode = pcfg->bp_mode;
>> +            p_rt->transport_params.blk_grp_ctrl = pcfg->blk_group_count;
>> +            p_rt->transport_params.hstart = pcfg->hstart;
>> +            p_rt->transport_params.hstop = pcfg->hstop;
>> +            p_rt->transport_params.lane_ctrl = pcfg->lane_control;
>> +            if (pcfg->word_length != SWR_INVALID_PARAM) {
>> +                sdw_fill_port_params(&p_rt->port_params,
>> +                         p_rt->num,  pcfg->word_length + 1,
>> +                         SDW_PORT_FLOW_MODE_ISOCH,
>> +                         SDW_PORT_DATA_MODE_NORMAL);
>> +            }
>> +
>>           }
>>           list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) {
>> @@ -481,6 +534,18 @@ static int qcom_swrm_compute_params(struct 
>> sdw_bus *bus)
>>                   p_rt->transport_params.offset1 = pcfg->off1;
>>                   p_rt->transport_params.offset2 = pcfg->off2;
>>                   p_rt->transport_params.blk_pkg_mode = pcfg->bp_mode;
>> +                p_rt->transport_params.blk_grp_ctrl = 
>> pcfg->blk_group_count;
>> +
>> +                p_rt->transport_params.hstart = pcfg->hstart;
>> +                p_rt->transport_params.hstop = pcfg->hstop;
>> +                p_rt->transport_params.lane_ctrl = pcfg->lane_control;
>> +                if (pcfg->word_length != SWR_INVALID_PARAM) {
>> +                    sdw_fill_port_params(&p_rt->port_params,
>> +                             p_rt->num,
>> +                             pcfg->word_length + 1,
>> +                             SDW_PORT_FLOW_MODE_ISOCH,
>> +                             SDW_PORT_DATA_MODE_NORMAL);
>> +                }
>>                   i++;
>>               }
>>           }
>> @@ -728,6 +793,11 @@ static int qcom_swrm_get_port_config(struct 
>> qcom_swrm_ctrl *ctrl)
>>       u8 off2[QCOM_SDW_MAX_PORTS];
>>       u8 si[QCOM_SDW_MAX_PORTS];
>>       u8 bp_mode[QCOM_SDW_MAX_PORTS] = { 0, };
>> +    u8 hstart[QCOM_SDW_MAX_PORTS];
>> +    u8 hstop[QCOM_SDW_MAX_PORTS];
>> +    u8 word_length[QCOM_SDW_MAX_PORTS];
>> +    u8 blk_group_count[QCOM_SDW_MAX_PORTS];
>> +    u8 lane_control[QCOM_SDW_MAX_PORTS];
>>       int i, ret, nports, val;
>>       ctrl->reg_read(ctrl, SWRM_COMP_PARAMS, &val);
>> @@ -772,11 +842,32 @@ static int qcom_swrm_get_port_config(struct 
>> qcom_swrm_ctrl *ctrl)
>>       ret = of_property_read_u8_array(np, "qcom,ports-block-pack-mode",
>>                       bp_mode, nports);
>> +
>> +    memset(hstart, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS);
>> +    of_property_read_u8_array(np, "qcom,ports-hstart", hstart, nports);
>> +
>> +    memset(hstop, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS);
>> +    of_property_read_u8_array(np, "qcom,ports-hstop", hstop, nports);
>> +
>> +    memset(word_length, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS);
>> +    of_property_read_u8_array(np, "qcom,ports-word-length", 
>> word_length, nports);
>> +
>> +    memset(blk_group_count, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS);
>> +    of_property_read_u8_array(np, "qcom,ports-block-group-count", 
>> blk_group_count, nports);
>> +
>> +    memset(lane_control, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS);
>> +    of_property_read_u8_array(np, "qcom,ports-lane-control", 
>> lane_control, nports);
>> +
>>       for (i = 0; i < nports; i++) {
>>           ctrl->pconfig[i].si = si[i];
>>           ctrl->pconfig[i].off1 = off1[i];
>>           ctrl->pconfig[i].off2 = off2[i];
>>           ctrl->pconfig[i].bp_mode = bp_mode[i];
>> +        ctrl->pconfig[i].hstart = hstart[i];
>> +        ctrl->pconfig[i].hstop = hstop[i];
>> +        ctrl->pconfig[i].word_length = word_length[i];
>> +        ctrl->pconfig[i].blk_group_count = blk_group_count[i];
>> +        ctrl->pconfig[i].lane_control = lane_control[i];
>>       }
> 
> I don't get why you test the values parsed from DT before writing the 
> registers. Why do test them here? if some values are incorrect it's much 
> better to provide an error log instead of writing a partially valid 
> setup to hardware, no?

from DT we pass parameters for all the master ports, however some of 
these parameters are not really applicable for some of the ports! so the 
way we handle this is by marking them as 0xFF which means these values 
are not applicable for those ports! Having said that I think I should 
probably redefine SWR_INVALID_PARAM to QCOM_SWR_PARAM_NA or something on 
those lines!


--srini
>>       return 0;
>>

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

* Re: [PATCH v2 1/5] soundwire: qcom: add support to missing transport params
  2021-03-02 10:13     ` Srinivas Kandagatla
@ 2021-03-02 14:29       ` Pierre-Louis Bossart
  2021-03-03  9:36         ` Srinivas Kandagatla
  0 siblings, 1 reply; 11+ messages in thread
From: Pierre-Louis Bossart @ 2021-03-02 14:29 UTC (permalink / raw)
  To: Srinivas Kandagatla, vkoul
  Cc: sanyog.r.kale, yung-chuan.liao, linux-kernel, alsa-devel


>>>       for (i = 0; i < nports; i++) {
>>>           ctrl->pconfig[i].si = si[i];
>>>           ctrl->pconfig[i].off1 = off1[i];
>>>           ctrl->pconfig[i].off2 = off2[i];
>>>           ctrl->pconfig[i].bp_mode = bp_mode[i];
>>> +        ctrl->pconfig[i].hstart = hstart[i];
>>> +        ctrl->pconfig[i].hstop = hstop[i];
>>> +        ctrl->pconfig[i].word_length = word_length[i];
>>> +        ctrl->pconfig[i].blk_group_count = blk_group_count[i];
>>> +        ctrl->pconfig[i].lane_control = lane_control[i];
>>>       }
>>
>> I don't get why you test the values parsed from DT before writing the 
>> registers. Why do test them here? if some values are incorrect it's 
>> much better to provide an error log instead of writing a partially 
>> valid setup to hardware, no?
> 
> from DT we pass parameters for all the master ports, however some of 
> these parameters are not really applicable for some of the ports! so the 
> way we handle this is by marking them as 0xFF which means these values 
> are not applicable for those ports! Having said that I think I should 
> probably redefine SWR_INVALID_PARAM to QCOM_SWR_PARAM_NA or something on 
> those lines!

Humm, do you have an example here? It's a bit odd to define DT 
properties that may or may not be valid. If this is intentional and 
desired, this should still be captured somehow, e.g. in the bindings 
documentation or in the code with a comment, no?

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

* Re: [PATCH v2 1/5] soundwire: qcom: add support to missing transport params
  2021-03-02 14:29       ` Pierre-Louis Bossart
@ 2021-03-03  9:36         ` Srinivas Kandagatla
  2021-03-03 16:16           ` Pierre-Louis Bossart
  0 siblings, 1 reply; 11+ messages in thread
From: Srinivas Kandagatla @ 2021-03-03  9:36 UTC (permalink / raw)
  To: Pierre-Louis Bossart, vkoul
  Cc: sanyog.r.kale, yung-chuan.liao, linux-kernel, alsa-devel



On 02/03/2021 14:29, Pierre-Louis Bossart wrote:
> 
>>>>       for (i = 0; i < nports; i++) {
>>>>           ctrl->pconfig[i].si = si[i];
>>>>           ctrl->pconfig[i].off1 = off1[i];
>>>>           ctrl->pconfig[i].off2 = off2[i];
>>>>           ctrl->pconfig[i].bp_mode = bp_mode[i];
>>>> +        ctrl->pconfig[i].hstart = hstart[i];
>>>> +        ctrl->pconfig[i].hstop = hstop[i];
>>>> +        ctrl->pconfig[i].word_length = word_length[i];
>>>> +        ctrl->pconfig[i].blk_group_count = blk_group_count[i];
>>>> +        ctrl->pconfig[i].lane_control = lane_control[i];
>>>>       }
>>>
>>> I don't get why you test the values parsed from DT before writing the 
>>> registers. Why do test them here? if some values are incorrect it's 
>>> much better to provide an error log instead of writing a partially 
>>> valid setup to hardware, no?
>>
>> from DT we pass parameters for all the master ports, however some of 
>> these parameters are not really applicable for some of the ports! so 
>> the way we handle this is by marking them as 0xFF which means these 
>> values are not applicable for those ports! Having said that I think I 
>> should probably redefine SWR_INVALID_PARAM to QCOM_SWR_PARAM_NA or 
>> something on those lines!
> 
> Humm, do you have an example here? It's a bit odd to define DT 



In DT we describe parameters for each port in an array so, parameters 
for ports that are not applicable/available for that platform can be 
marked with 0xFF.

Most importantly, Some of these registers are only implemented based on 
the data ports. Ex: GROUP_CONTROL register is only implemented for data 
ports that support Group Count other than 0. Like wise for HSTART/STOP 
for Full Data ports only!
So avoiding reading/writing to registers by passing 
invalid/not-applicable value 0xFF made more sense!

Here are some examples of controller instances on SM8250 SoC.

soundwire-controller@3230000 {
	reg = <0 0x3230000 0 0x2000>;
	compatible = "qcom,soundwire-v1.5.1";
	interrupts-extended = <&intc GIC_SPI 297 IRQ_TYPE_LEVEL_HIGH>,
			<&pdc 109 IRQ_TYPE_LEVEL_HIGH>;
	interrupt-names = "core", "wakeup";

	qcom,clock-stop-mode0;
	clocks = <&txmacro>;
	clock-names = "iface";

	qcom,din-ports = <5>;
	qcom,dout-ports = <0>;
	qcom,ports-sinterval-low = /bits/ 8 <0xFF 0x01 0x01 0x03 0x03>;
	qcom,ports-offset1 = /bits/ 8 <0xFF 0x01 0x00 0x02 0x00>;
	qcom,ports-offset2 = /bits/ 8 <0xFF 0x00 0x00 0x00 0x00>;
	qcom,ports-block-pack-mode = /bits/ 8 <0xFF 0xFF 0xFF 0xFF 0xFF>;
	qcom,ports-hstart = /bits/ 8 <0xFF 0xFF 0xFF 0xFF 0xFF>;
	qcom,ports-hstop = /bits/ 8 <0xFF 0xFF 0xFF 0xFF 0xFF>;
	qcom,ports-word-length = /bits/ 8 <0xFF 0xFF 0xFF 0xFF 0xFF>;
	qcom,ports-block-group-count = /bits/ 8 <0xFF 0xFF 0xFF 0xFF 0xFF>;
	qcom,ports-lane-control = /bits/ 8 <0xFF 0x00 0x01 0x00 0x01>;
	qcom,port-offset = <1>;
	#sound-dai-cells = <1>;
	#address-cells = <2>;
	#size-cells = <0>;
};


soundwire-controller@3210000 {
	reg = <0 0x3210000 0 0x2000>;
	compatible = "qcom,soundwire-v1.5.1";
	interrupts = <GIC_SPI 298 IRQ_TYPE_LEVEL_HIGH>;
	clocks = <&rxmacro>;
	clock-names = "iface";
	qcom,clock-stop-mode0;
	qcom,din-ports = <0>;
	qcom,dout-ports = <5>;

	qcom,ports-sinterval-low = /bits/ 8 <0x03 0x1F 0x1F 0x07 0x00>;
	qcom,ports-offset1 = /bits/ 8 <0x00 0x00 0x0B 0x01 0x00>;
	qcom,ports-offset2 = /bits/ 8 <0x00 0x00 0x0B 0x00 0x00>;
	qcom,ports-hstart = /bits/ 8 <0xFF 0x03 0xFF 0xFF 0xFF>;
	qcom,ports-hstop = /bits/ 8 <0xFF 0x06 0xFF 0xFF 0xFF>;
	qcom,ports-word-length = /bits/ 8 <0x01 0x07 0x04 0xFF 0xFF>;
	qcom,ports-block-pack-mode = /bits/ 8 <0xFF 0x00 0x01 0xFF 0xFF>;
	qcom,ports-lane-control = /bits/ 8 <0x01 0x00 0x00 0x00 0x00>;
	qcom,ports-block-group-count = /bits/ 8 <0xFF 0xFF 0xFF 0xFF 0x00>;

	#sound-dai-cells = <1>;
	#address-cells = <2>;
	#size-cells = <0>;
};
> properties that may or may not be valid. If this is intentional and 
> desired, this should still be captured somehow, e.g. in the bindings 
> documentation or in the code with a comment, no?

Yes, I agree with you on this, I should document this in bindings!

--srini



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

* Re: [PATCH v2 1/5] soundwire: qcom: add support to missing transport params
  2021-03-03  9:36         ` Srinivas Kandagatla
@ 2021-03-03 16:16           ` Pierre-Louis Bossart
  0 siblings, 0 replies; 11+ messages in thread
From: Pierre-Louis Bossart @ 2021-03-03 16:16 UTC (permalink / raw)
  To: Srinivas Kandagatla, vkoul
  Cc: sanyog.r.kale, yung-chuan.liao, linux-kernel, alsa-devel


> soundwire-controller@3210000 {
>      reg = <0 0x3210000 0 0x2000>;
>      compatible = "qcom,soundwire-v1.5.1";
>      interrupts = <GIC_SPI 298 IRQ_TYPE_LEVEL_HIGH>;
>      clocks = <&rxmacro>;
>      clock-names = "iface";
>      qcom,clock-stop-mode0;
>      qcom,din-ports = <0>;
>      qcom,dout-ports = <5>;
> 
>      qcom,ports-sinterval-low = /bits/ 8 <0x03 0x1F 0x1F 0x07 0x00>;
>      qcom,ports-offset1 = /bits/ 8 <0x00 0x00 0x0B 0x01 0x00>;
>      qcom,ports-offset2 = /bits/ 8 <0x00 0x00 0x0B 0x00 0x00>;
>      qcom,ports-hstart = /bits/ 8 <0xFF 0x03 0xFF 0xFF 0xFF>;
>      qcom,ports-hstop = /bits/ 8 <0xFF 0x06 0xFF 0xFF 0xFF>;
>      qcom,ports-word-length = /bits/ 8 <0x01 0x07 0x04 0xFF 0xFF>;
>      qcom,ports-block-pack-mode = /bits/ 8 <0xFF 0x00 0x01 0xFF 0xFF>;
>      qcom,ports-lane-control = /bits/ 8 <0x01 0x00 0x00 0x00 0x00>;
>      qcom,ports-block-group-count = /bits/ 8 <0xFF 0xFF 0xFF 0xFF 0x00>;
> 
>      #sound-dai-cells = <1>;
>      #address-cells = <2>;
>      #size-cells = <0>;
> };
>> properties that may or may not be valid. If this is intentional and 
>> desired, this should still be captured somehow, e.g. in the bindings 
>> documentation or in the code with a comment, no?
> 
> Yes, I agree with you on this, I should document this in bindings!

thanks for the explanations, it'd be useful indeed to document what this 
magic 0xFF value means.


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

end of thread, other threads:[~2021-03-04  0:09 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-02-26 15:58 [PATCH v2 0/5] soundwire: qcom: various improvements Srinivas Kandagatla
2021-02-26 15:58 ` [PATCH v2 1/5] soundwire: qcom: add support to missing transport params Srinivas Kandagatla
2021-02-26 16:45   ` Pierre-Louis Bossart
2021-03-02 10:13     ` Srinivas Kandagatla
2021-03-02 14:29       ` Pierre-Louis Bossart
2021-03-03  9:36         ` Srinivas Kandagatla
2021-03-03 16:16           ` Pierre-Louis Bossart
2021-02-26 15:58 ` [PATCH v2 2/5] soundwire: qcom: set continue execution flag for ignored commands Srinivas Kandagatla
2021-02-26 15:58 ` [PATCH v2 3/5] soundwire: qcom: start the clock during initialization Srinivas Kandagatla
2021-02-26 15:58 ` [PATCH v2 4/5] soundwire: qcom: update register read/write routine Srinivas Kandagatla
2021-02-26 15:58 ` [PATCH v2 5/5] soundwire: qcom: add support to new interrupts Srinivas Kandagatla

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).