diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2020-10-01 22:59:55 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2020-10-01 22:59:55 +0200 |
commit | 4cb1a880e7f774e59c2ebb68187d4811ad9d0c4e (patch) | |
tree | caa439723e5fc5cdc473bdd519a0a5f4ac27d201 /drivers/soundwire/qcom.c | |
parent | MAINTAINERS: exclude char maintainers from things they do not maintain (diff) | |
parent | soundwire: sysfs: add slave status and device number before probe (diff) | |
download | linux-4cb1a880e7f774e59c2ebb68187d4811ad9d0c4e.tar.xz linux-4cb1a880e7f774e59c2ebb68187d4811ad9d0c4e.zip |
Merge tag 'soundwire-5.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire into char-misc-next
Vinod writes:
soundwire updates for 5.10-rc1
This round of update includes:
- Generic bandwidth allocation algorithm from Intel folks
- PM support for Intel chipsets
- Updates to Intel drivers which makes sdw usable on latest laptops
- Support for MMIO SDW controllers found in QC chipsets
- Update to subsystem to use helpers in bitfield.h to manage register
bits
* tag 'soundwire-5.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire: (66 commits)
soundwire: sysfs: add slave status and device number before probe
soundwire: bus: add enumerated Slave device to device list
soundwire: remove an unnecessary NULL check
soundwire: cadence: add data port test fail interrupt
soundwire: intel: enable test modes
soundwire: enable Data Port test modes
soundwire: intel: use {u32|u16}p_replace_bits
soundwire: cadence: use u32p_replace_bits
soundwire: qcom: get max rows and cols info from compatible
soundwire: qcom: add support to block packing mode
soundwire: qcom: clear BIT FIELDs before value set.
soundwire: Add generic bandwidth allocation algorithm
soundwire: cadence: add parity error injection through debugfs
soundwire: bus: export broadcast read/write capability for tests
ASoC: codecs: realtek-soundwire: ignore initial PARITY errors
soundwire: bus: use quirk to filter out invalid parity errors
soundwire: slave: add first_interrupt_done status
soundwire: bus: filter-out unwanted interrupt reports
ASoC/soundwire: bus: use property to set interrupt masks
soundwire: qcom: fix SLIBMUS/SLIMBUS typo
...
Diffstat (limited to 'drivers/soundwire/qcom.c')
-rw-r--r-- | drivers/soundwire/qcom.c | 118 |
1 files changed, 86 insertions, 32 deletions
diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c index 915c2cf0c274..fbca4ebf63e9 100644 --- a/drivers/soundwire/qcom.c +++ b/drivers/soundwire/qcom.c @@ -34,6 +34,7 @@ #define SWRM_INTERRUPT_STATUS_SPECIAL_CMD_ID_FINISHED BIT(10) #define SWRM_INTERRUPT_MASK_ADDR 0x204 #define SWRM_INTERRUPT_CLEAR 0x208 +#define SWRM_INTERRUPT_CPU_EN 0x210 #define SWRM_CMD_FIFO_WR_CMD 0x300 #define SWRM_CMD_FIFO_RD_CMD 0x304 #define SWRM_CMD_FIFO_CMD 0x308 @@ -43,19 +44,17 @@ #define SWRM_CMD_FIFO_RD_FIFO_ADDR 0x318 #define SWRM_ENUMERATOR_CFG_ADDR 0x500 #define SWRM_MCP_FRAME_CTRL_BANK_ADDR(m) (0x101C + 0x40 * (m)) -#define SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_SHFT 3 #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_FRAME_CTRL_BANK_COL_CTRL_SHFT 0 #define SWRM_MCP_CFG_ADDR 0x1048 #define SWRM_MCP_CFG_MAX_NUM_OF_CMD_NO_PINGS_BMSK GENMASK(21, 17) -#define SWRM_MCP_CFG_MAX_NUM_OF_CMD_NO_PINGS_SHFT 0x11 #define SWRM_DEF_CMD_NO_PINGS 0x1f #define SWRM_MCP_STATUS 0x104C #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_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 @@ -67,11 +66,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) @@ -84,12 +78,14 @@ struct qcom_swrm_port_config { u8 si; u8 off1; u8 off2; + u8 bp_mode; }; struct qcom_swrm_ctrl { struct sdw_bus bus; struct device *dev; struct regmap *regmap; + void __iomem *mmio; struct completion *comp; struct work_struct slave_work; /* read/write lock */ @@ -103,6 +99,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]; @@ -112,9 +110,24 @@ struct qcom_swrm_ctrl { int (*reg_write)(struct qcom_swrm_ctrl *ctrl, int reg, int val); }; +struct qcom_swrm_data { + u32 default_cols; + u32 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_abh_reg_read(struct qcom_swrm_ctrl *ctrl, int reg, +static int qcom_swrm_ahb_reg_read(struct qcom_swrm_ctrl *ctrl, int reg, u32 *val) { struct regmap *wcd_regmap = ctrl->regmap; @@ -154,6 +167,20 @@ static int qcom_swrm_ahb_reg_write(struct qcom_swrm_ctrl *ctrl, return SDW_CMD_OK; } +static int qcom_swrm_cpu_reg_read(struct qcom_swrm_ctrl *ctrl, int reg, + u32 *val) +{ + *val = readl(ctrl->mmio + reg); + return SDW_CMD_OK; +} + +static int qcom_swrm_cpu_reg_write(struct qcom_swrm_ctrl *ctrl, int reg, + int val) +{ + writel(val, ctrl->mmio + 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) { @@ -284,8 +311,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 = FIELD_PREP(SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_BMSK, ctrl->rows_index); + val |= FIELD_PREP(SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_BMSK, ctrl->cols_index); ctrl->reg_write(ctrl, SWRM_MCP_FRAME_CTRL_BANK_ADDR(0), val); @@ -298,9 +325,7 @@ static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl) /* Configure No pings */ ctrl->reg_read(ctrl, SWRM_MCP_CFG_ADDR, &val); - val &= ~SWRM_MCP_CFG_MAX_NUM_OF_CMD_NO_PINGS_BMSK; - val |= (SWRM_DEF_CMD_NO_PINGS << - SWRM_MCP_CFG_MAX_NUM_OF_CMD_NO_PINGS_SHFT); + 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); /* Configure number of retries of a read/write cmd */ @@ -310,6 +335,12 @@ static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl) ctrl->reg_write(ctrl, SWRM_COMP_CFG_ADDR, SWRM_COMP_CFG_IRQ_LEVEL_OR_PULSE_MSK | SWRM_COMP_CFG_ENABLE_MSK); + + /* enable CPU IRQs */ + if (ctrl->mmio) { + ctrl->reg_write(ctrl, SWRM_INTERRUPT_CPU_EN, + SWRM_INTERRUPT_STATUS_RMSK); + } return 0; } @@ -355,11 +386,8 @@ static int qcom_swrm_pre_bank_switch(struct sdw_bus *bus) ctrl->reg_read(ctrl, reg, &val); - 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); + u32p_replace_bits(&val, ctrl->cols_index, SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_BMSK); + u32p_replace_bits(&val, ctrl->rows_index, SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_BMSK); return ctrl->reg_write(ctrl, reg, val); } @@ -378,14 +406,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, @@ -433,6 +469,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) { @@ -443,6 +480,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++; } } @@ -689,12 +727,13 @@ 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); - ctrl->num_dout_ports = val & SWRM_COMP_PARAMS_DOUT_PORTS_MASK; - ctrl->num_din_ports = (val & SWRM_COMP_PARAMS_DIN_PORTS_MASK) >> 5; + ctrl->num_dout_ports = FIELD_GET(SWRM_COMP_PARAMS_DOUT_PORTS_MASK, val); + ctrl->num_din_ports = FIELD_GET(SWRM_COMP_PARAMS_DIN_PORTS_MASK, val); ret = of_property_read_u32(np, "qcom,din-ports", &val); if (ret) @@ -731,10 +770,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; @@ -746,6 +788,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; int ret; u32 val; @@ -753,15 +796,25 @@ 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); +#if IS_ENABLED(CONFIG_SLIMBUS) if (dev->parent->bus == &slimbus_bus) { - ctrl->reg_read = qcom_swrm_abh_reg_read; +#else + if (false) { +#endif + ctrl->reg_read = qcom_swrm_ahb_reg_read; ctrl->reg_write = qcom_swrm_ahb_reg_write; ctrl->regmap = dev_get_regmap(dev->parent, NULL); if (!ctrl->regmap) return -EINVAL; } else { - /* Only WCD based SoundWire controller is supported */ - return -ENOTSUPP; + ctrl->reg_read = qcom_swrm_cpu_reg_read; + ctrl->reg_write = qcom_swrm_cpu_reg_write; + ctrl->mmio = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(ctrl->mmio)) + return PTR_ERR(ctrl->mmio); } ctrl->irq = of_irq_get(dev->of_node, 0); @@ -795,8 +848,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; @@ -806,8 +859,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); @@ -858,7 +911,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.3.0", .data = &swrm_v1_3_data }, + { .compatible = "qcom,soundwire-v1.5.1", .data = &swrm_v1_5_data }, {/* sentinel */}, }; |