[PATCH 0/2] soundwire: qcom: fix IP version v1.5.1 support

While testing Qualcomm soundwire controller version 1.5.1, found two issue, Firstly the frame shape information configured vs the bus parameters are out of sync. secondly some ports on this ip version require block packing mode support.
With this two patches on top of https://lkml.org/lkml/2020/9/5/220 ("[PATCH v2 0/4] soundwire: qcom: add support for mmio soundwire master") patchset I was able to test 2 WSA speakers! This patchset depends on this above patchset!
thanks, srini
Srinivas Kandagatla (2): soundwire: qcom: add support to block packing mode soundwire: qcom: get max rows and cols info from compatible
drivers/soundwire/qcom.c | 68 +++++++++++++++++++++++++++++----------- 1 file changed, 50 insertions(+), 18 deletions(-)

This patch adds support to block pack mode, which is required on Qcom soundwire controllers v1.5.x on few ports!
Signed-off-by: Srinivas Kandagatla srinivas.kandagatla@linaro.org --- drivers/soundwire/qcom.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-)
diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c index 4b3ef7559e6a..1ec0ee931f5b 100644 --- a/drivers/soundwire/qcom.c +++ b/drivers/soundwire/qcom.c @@ -57,6 +57,7 @@ #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_BLOCK_CTRL3_BANK(n, m) (0x1138 + 0x100 * (n - 1) + 0x40 * m) #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 @@ -85,6 +86,7 @@ struct qcom_swrm_port_config { u8 si; u8 off1; u8 off2; + u8 bp_mode; };
struct qcom_swrm_ctrl { @@ -400,14 +402,22 @@ static int qcom_swrm_transport_params(struct sdw_bus *bus, { struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus); u32 value; + int reg = SWRM_DP_PORT_CTRL_BANK((params->port_num), bank); + int ret;
value = params->offset1 << SWRM_DP_PORT_CTRL_OFFSET1_SHFT; value |= params->offset2 << SWRM_DP_PORT_CTRL_OFFSET2_SHFT; value |= params->sample_interval - 1;
- return ctrl->reg_write(ctrl, - SWRM_DP_PORT_CTRL_BANK((params->port_num), bank), - value); + ret = ctrl->reg_write(ctrl, reg, value); + + if (!ret && params->blk_pkg_mode) { + reg = SWRM_DP_BLOCK_CTRL3_BANK(params->port_num, bank); + + ret = ctrl->reg_write(ctrl, reg, 1); + } + + return ret; }
static int qcom_swrm_port_enable(struct sdw_bus *bus, @@ -455,6 +465,7 @@ static int qcom_swrm_compute_params(struct sdw_bus *bus) p_rt->transport_params.sample_interval = pcfg->si + 1; p_rt->transport_params.offset1 = pcfg->off1; p_rt->transport_params.offset2 = pcfg->off2; + p_rt->transport_params.blk_pkg_mode = pcfg->bp_mode; }
list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) { @@ -465,6 +476,7 @@ static int qcom_swrm_compute_params(struct sdw_bus *bus) pcfg->si + 1; p_rt->transport_params.offset1 = pcfg->off1; p_rt->transport_params.offset2 = pcfg->off2; + p_rt->transport_params.blk_pkg_mode = pcfg->bp_mode; i++; } } @@ -711,6 +723,7 @@ static int qcom_swrm_get_port_config(struct qcom_swrm_ctrl *ctrl) u8 off1[QCOM_SDW_MAX_PORTS]; u8 off2[QCOM_SDW_MAX_PORTS]; u8 si[QCOM_SDW_MAX_PORTS]; + u8 bp_mode[QCOM_SDW_MAX_PORTS] = { 0, }; int i, ret, nports, val;
ctrl->reg_read(ctrl, SWRM_COMP_PARAMS, &val); @@ -753,10 +766,13 @@ static int qcom_swrm_get_port_config(struct qcom_swrm_ctrl *ctrl) if (ret) return ret;
+ ret = of_property_read_u8_array(np, "qcom,ports-block-pack-mode", + bp_mode, 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]; }
return 0;

currently the max rows and cols values are hardcoded. In reality these values depend on the IP version. So get these based on device tree compatible strings.
Signed-off-by: Srinivas Kandagatla srinivas.kandagatla@linaro.org --- drivers/soundwire/qcom.c | 46 +++++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 15 deletions(-)
diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c index 1ec0ee931f5b..03c5bc05fc6e 100644 --- a/drivers/soundwire/qcom.c +++ b/drivers/soundwire/qcom.c @@ -69,11 +69,6 @@ #define SWRM_REG_VAL_PACK(data, dev, id, reg) \ ((reg) | ((id) << 16) | ((dev) << 20) | ((data) << 24))
-#define SWRM_MAX_ROW_VAL 0 /* Rows = 48 */ -#define SWRM_DEFAULT_ROWS 48 -#define SWRM_MIN_COL_VAL 0 /* Cols = 2 */ -#define SWRM_DEFAULT_COL 16 -#define SWRM_MAX_COL_VAL 7 #define SWRM_SPECIAL_CMD_ID 0xF #define MAX_FREQ_NUM 1 #define TIMEOUT_MS (2 * HZ) @@ -107,6 +102,8 @@ struct qcom_swrm_ctrl { unsigned int version; int num_din_ports; int num_dout_ports; + int cols_index; + int rows_index; unsigned long dout_port_mask; unsigned long din_port_mask; struct qcom_swrm_port_config pconfig[QCOM_SDW_MAX_PORTS]; @@ -116,6 +113,21 @@ struct qcom_swrm_ctrl { int (*reg_write)(struct qcom_swrm_ctrl *ctrl, int reg, int val); };
+struct qcom_swrm_data { + int default_cols; + int default_rows; +}; + +static struct qcom_swrm_data swrm_v1_3_data = { + .default_rows = 48, + .default_cols = 16, +}; + +static struct qcom_swrm_data swrm_v1_5_data = { + .default_rows = 50, + .default_cols = 16, +}; + #define to_qcom_sdw(b) container_of(b, struct qcom_swrm_ctrl, bus)
static int qcom_swrm_ahb_reg_read(struct qcom_swrm_ctrl *ctrl, int reg, @@ -302,8 +314,8 @@ static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl) u32 val;
/* Clear Rows and Cols */ - val = (SWRM_MAX_ROW_VAL << SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_SHFT | - SWRM_MIN_COL_VAL << SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_SHFT); + val = ctrl->rows_index << SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_SHFT | + ctrl->cols_index << SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_SHFT;
ctrl->reg_write(ctrl, SWRM_MCP_FRAME_CTRL_BANK_ADDR(0), val);
@@ -382,8 +394,8 @@ static int qcom_swrm_pre_bank_switch(struct sdw_bus *bus) val &= ~SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_BMSK; val &= ~SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_BMSK;
- val |= (SWRM_MAX_ROW_VAL << SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_SHFT | - SWRM_MAX_COL_VAL << SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_SHFT); + val |= ctrl->rows_index << SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_SHFT | + ctrl->cols_index << SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_SHFT;
return ctrl->reg_write(ctrl, reg, val); } @@ -784,6 +796,7 @@ static int qcom_swrm_probe(struct platform_device *pdev) struct sdw_master_prop *prop; struct sdw_bus_params *params; struct qcom_swrm_ctrl *ctrl; + const struct qcom_swrm_data *data; struct resource *res; int ret; u32 val; @@ -792,6 +805,9 @@ static int qcom_swrm_probe(struct platform_device *pdev) if (!ctrl) return -ENOMEM;
+ data = of_device_get_match_data(dev); + ctrl->rows_index = sdw_find_row_index(data->default_rows); + ctrl->cols_index = sdw_find_col_index(data->default_cols); #ifdef CONFIG_SLIMBUS if (dev->parent->bus == &slimbus_bus) { #else @@ -844,8 +860,8 @@ static int qcom_swrm_probe(struct platform_device *pdev) params = &ctrl->bus.params; params->max_dr_freq = DEFAULT_CLK_FREQ; params->curr_dr_freq = DEFAULT_CLK_FREQ; - params->col = SWRM_DEFAULT_COL; - params->row = SWRM_DEFAULT_ROWS; + params->col = data->default_cols; + params->row = data->default_rows; ctrl->reg_read(ctrl, SWRM_MCP_STATUS, &val); params->curr_bank = val & SWRM_MCP_STATUS_BANK_NUM_MASK; params->next_bank = !params->curr_bank; @@ -855,8 +871,8 @@ static int qcom_swrm_probe(struct platform_device *pdev) prop->num_clk_gears = 0; prop->num_clk_freq = MAX_FREQ_NUM; prop->clk_freq = &qcom_swrm_freq_tbl[0]; - prop->default_col = SWRM_DEFAULT_COL; - prop->default_row = SWRM_DEFAULT_ROWS; + prop->default_col = data->default_cols; + prop->default_row = data->default_rows;
ctrl->reg_read(ctrl, SWRM_COMP_HW_VERSION, &ctrl->version);
@@ -907,8 +923,8 @@ static int qcom_swrm_remove(struct platform_device *pdev) }
static const struct of_device_id qcom_swrm_of_match[] = { - { .compatible = "qcom,soundwire-v1.3.0", }, - { .compatible = "qcom,soundwire-v1.5.1", }, + { .compatible = "qcom,soundwire-v1.3.0", .data = &swrm_v1_3_data }, + { .compatible = "qcom,soundwire-v1.5.1", .data = &swrm_v1_5_data }, {/* sentinel */}, };

On 09-09-20, 17:09, Srinivas Kandagatla wrote:
currently the max rows and cols values are hardcoded. In reality these values depend on the IP version. So get these based on device tree compatible strings.
Signed-off-by: Srinivas Kandagatla srinivas.kandagatla@linaro.org
drivers/soundwire/qcom.c | 46 +++++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 15 deletions(-)
diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c index 1ec0ee931f5b..03c5bc05fc6e 100644 --- a/drivers/soundwire/qcom.c +++ b/drivers/soundwire/qcom.c @@ -69,11 +69,6 @@ #define SWRM_REG_VAL_PACK(data, dev, id, reg) \ ((reg) | ((id) << 16) | ((dev) << 20) | ((data) << 24))
-#define SWRM_MAX_ROW_VAL 0 /* Rows = 48 */ -#define SWRM_DEFAULT_ROWS 48 -#define SWRM_MIN_COL_VAL 0 /* Cols = 2 */ -#define SWRM_DEFAULT_COL 16 -#define SWRM_MAX_COL_VAL 7 #define SWRM_SPECIAL_CMD_ID 0xF #define MAX_FREQ_NUM 1 #define TIMEOUT_MS (2 * HZ) @@ -107,6 +102,8 @@ struct qcom_swrm_ctrl { unsigned int version; int num_din_ports; int num_dout_ports;
- int cols_index;
- int rows_index; unsigned long dout_port_mask; unsigned long din_port_mask; struct qcom_swrm_port_config pconfig[QCOM_SDW_MAX_PORTS];
@@ -116,6 +113,21 @@ struct qcom_swrm_ctrl { int (*reg_write)(struct qcom_swrm_ctrl *ctrl, int reg, int val); };
+struct qcom_swrm_data {
- int default_cols;
- int default_rows;
unsigned int for these?
+};
+static struct qcom_swrm_data swrm_v1_3_data = {
- .default_rows = 48,
- .default_cols = 16,
+};
+static struct qcom_swrm_data swrm_v1_5_data = {
- .default_rows = 50,
- .default_cols = 16,
+};
#define to_qcom_sdw(b) container_of(b, struct qcom_swrm_ctrl, bus)
static int qcom_swrm_ahb_reg_read(struct qcom_swrm_ctrl *ctrl, int reg, @@ -302,8 +314,8 @@ static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl) u32 val;
/* Clear Rows and Cols */
- val = (SWRM_MAX_ROW_VAL << SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_SHFT |
SWRM_MIN_COL_VAL << SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_SHFT);
- val = ctrl->rows_index << SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_SHFT |
ctrl->cols_index << SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_SHFT;
use FIELD_{GET|SET} / u32_encode_bits for these
Please rebase on sdw-next, this has already been updated in next
ctrl->reg_write(ctrl, SWRM_MCP_FRAME_CTRL_BANK_ADDR(0), val);
@@ -382,8 +394,8 @@ static int qcom_swrm_pre_bank_switch(struct sdw_bus *bus) val &= ~SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_BMSK; val &= ~SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_BMSK;
- val |= (SWRM_MAX_ROW_VAL << SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_SHFT |
SWRM_MAX_COL_VAL << SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_SHFT);
val |= ctrl->rows_index << SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_SHFT |
ctrl->cols_index << SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_SHFT;
return ctrl->reg_write(ctrl, reg, val);
} @@ -784,6 +796,7 @@ static int qcom_swrm_probe(struct platform_device *pdev) struct sdw_master_prop *prop; struct sdw_bus_params *params; struct qcom_swrm_ctrl *ctrl;
- const struct qcom_swrm_data *data; struct resource *res; int ret; u32 val;
@@ -792,6 +805,9 @@ static int qcom_swrm_probe(struct platform_device *pdev) if (!ctrl) return -ENOMEM;
- data = of_device_get_match_data(dev);
how about checking data is valid?
- ctrl->rows_index = sdw_find_row_index(data->default_rows);
- ctrl->cols_index = sdw_find_col_index(data->default_cols);
#ifdef CONFIG_SLIMBUS if (dev->parent->bus == &slimbus_bus) { #else @@ -844,8 +860,8 @@ static int qcom_swrm_probe(struct platform_device *pdev) params = &ctrl->bus.params; params->max_dr_freq = DEFAULT_CLK_FREQ; params->curr_dr_freq = DEFAULT_CLK_FREQ;
- params->col = SWRM_DEFAULT_COL;
- params->row = SWRM_DEFAULT_ROWS;
- params->col = data->default_cols;
- params->row = data->default_rows; ctrl->reg_read(ctrl, SWRM_MCP_STATUS, &val); params->curr_bank = val & SWRM_MCP_STATUS_BANK_NUM_MASK; params->next_bank = !params->curr_bank;
@@ -855,8 +871,8 @@ static int qcom_swrm_probe(struct platform_device *pdev) prop->num_clk_gears = 0; prop->num_clk_freq = MAX_FREQ_NUM; prop->clk_freq = &qcom_swrm_freq_tbl[0];
- prop->default_col = SWRM_DEFAULT_COL;
- prop->default_row = SWRM_DEFAULT_ROWS;
prop->default_col = data->default_cols;
prop->default_row = data->default_rows;
ctrl->reg_read(ctrl, SWRM_COMP_HW_VERSION, &ctrl->version);
@@ -907,8 +923,8 @@ static int qcom_swrm_remove(struct platform_device *pdev) }
static const struct of_device_id qcom_swrm_of_match[] = {
- { .compatible = "qcom,soundwire-v1.3.0", },
- { .compatible = "qcom,soundwire-v1.5.1", },
- { .compatible = "qcom,soundwire-v1.3.0", .data = &swrm_v1_3_data },
- { .compatible = "qcom,soundwire-v1.5.1", .data = &swrm_v1_5_data }, {/* sentinel */},
};
-- 2.21.0

On 10/09/2020 07:39, Vinod Koul wrote:
On 09-09-20, 17:09, Srinivas Kandagatla wrote:
currently the max rows and cols values are hardcoded. In reality these values depend on the IP version. So get these based on device tree compatible strings.
Signed-off-by: Srinivas Kandagatla srinivas.kandagatla@linaro.org
drivers/soundwire/qcom.c | 46 +++++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 15 deletions(-)
diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c index 1ec0ee931f5b..03c5bc05fc6e 100644 --- a/drivers/soundwire/qcom.c +++ b/drivers/soundwire/qcom.c @@ -69,11 +69,6 @@ #define SWRM_REG_VAL_PACK(data, dev, id, reg) \ ((reg) | ((id) << 16) | ((dev) << 20) | ((data) << 24))
-#define SWRM_MAX_ROW_VAL 0 /* Rows = 48 */ -#define SWRM_DEFAULT_ROWS 48 -#define SWRM_MIN_COL_VAL 0 /* Cols = 2 */ -#define SWRM_DEFAULT_COL 16 -#define SWRM_MAX_COL_VAL 7 #define SWRM_SPECIAL_CMD_ID 0xF #define MAX_FREQ_NUM 1 #define TIMEOUT_MS (2 * HZ) @@ -107,6 +102,8 @@ struct qcom_swrm_ctrl { unsigned int version; int num_din_ports; int num_dout_ports;
- int cols_index;
- int rows_index; unsigned long dout_port_mask; unsigned long din_port_mask; struct qcom_swrm_port_config pconfig[QCOM_SDW_MAX_PORTS];
@@ -116,6 +113,21 @@ struct qcom_swrm_ctrl { int (*reg_write)(struct qcom_swrm_ctrl *ctrl, int reg, int val); };
+struct qcom_swrm_data {
- int default_cols;
- int default_rows;
unsigned int for these?
Yes, we could do that but does it really add anything, given the range is up to 256.
+};
+static struct qcom_swrm_data swrm_v1_3_data = {
- .default_rows = 48,
- .default_cols = 16,
+};
+static struct qcom_swrm_data swrm_v1_5_data = {
- .default_rows = 50,
- .default_cols = 16,
+};
#define to_qcom_sdw(b) container_of(b, struct qcom_swrm_ctrl, bus)
static int qcom_swrm_ahb_reg_read(struct qcom_swrm_ctrl *ctrl, int reg,
@@ -302,8 +314,8 @@ static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl) u32 val;
/* Clear Rows and Cols */
- val = (SWRM_MAX_ROW_VAL << SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_SHFT |
SWRM_MIN_COL_VAL << SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_SHFT);
- val = ctrl->rows_index << SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_SHFT |
ctrl->cols_index << SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_SHFT;
use FIELD_{GET|SET} / u32_encode_bits for these
Please rebase on sdw-next, this has already been updated in next
Yes, I will do that!
ctrl->reg_write(ctrl, SWRM_MCP_FRAME_CTRL_BANK_ADDR(0), val);
@@ -382,8 +394,8 @@ static int qcom_swrm_pre_bank_switch(struct sdw_bus *bus) val &= ~SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_BMSK; val &= ~SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_BMSK;
- val |= (SWRM_MAX_ROW_VAL << SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_SHFT |
SWRM_MAX_COL_VAL << SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_SHFT);
val |= ctrl->rows_index << SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_SHFT |
ctrl->cols_index << SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_SHFT;
return ctrl->reg_write(ctrl, reg, val); }
@@ -784,6 +796,7 @@ static int qcom_swrm_probe(struct platform_device *pdev) struct sdw_master_prop *prop; struct sdw_bus_params *params; struct qcom_swrm_ctrl *ctrl;
- const struct qcom_swrm_data *data; struct resource *res; int ret; u32 val;
@@ -792,6 +805,9 @@ static int qcom_swrm_probe(struct platform_device *pdev) if (!ctrl) return -ENOMEM;
- data = of_device_get_match_data(dev);
how about checking data is valid?
I think the check would be unnecessary here, as we would not endup here without a matching compatible!
--srini
- ctrl->rows_index = sdw_find_row_index(data->default_rows);
- ctrl->cols_index = sdw_find_col_index(data->default_cols); #ifdef CONFIG_SLIMBUS if (dev->parent->bus == &slimbus_bus) { #else
@@ -844,8 +860,8 @@ static int qcom_swrm_probe(struct platform_device *pdev) params = &ctrl->bus.params; params->max_dr_freq = DEFAULT_CLK_FREQ; params->curr_dr_freq = DEFAULT_CLK_FREQ;
- params->col = SWRM_DEFAULT_COL;
- params->row = SWRM_DEFAULT_ROWS;
- params->col = data->default_cols;
- params->row = data->default_rows; ctrl->reg_read(ctrl, SWRM_MCP_STATUS, &val); params->curr_bank = val & SWRM_MCP_STATUS_BANK_NUM_MASK; params->next_bank = !params->curr_bank;
@@ -855,8 +871,8 @@ static int qcom_swrm_probe(struct platform_device *pdev) prop->num_clk_gears = 0; prop->num_clk_freq = MAX_FREQ_NUM; prop->clk_freq = &qcom_swrm_freq_tbl[0];
- prop->default_col = SWRM_DEFAULT_COL;
- prop->default_row = SWRM_DEFAULT_ROWS;
prop->default_col = data->default_cols;
prop->default_row = data->default_rows;
ctrl->reg_read(ctrl, SWRM_COMP_HW_VERSION, &ctrl->version);
@@ -907,8 +923,8 @@ static int qcom_swrm_remove(struct platform_device *pdev) }
static const struct of_device_id qcom_swrm_of_match[] = {
- { .compatible = "qcom,soundwire-v1.3.0", },
- { .compatible = "qcom,soundwire-v1.5.1", },
- { .compatible = "qcom,soundwire-v1.3.0", .data = &swrm_v1_3_data },
- { .compatible = "qcom,soundwire-v1.5.1", .data = &swrm_v1_5_data }, {/* sentinel */}, };
-- 2.21.0
participants (2)
-
Srinivas Kandagatla
-
Vinod Koul