diff options
Diffstat (limited to 'drivers/soundwire/cadence_master.c')
-rw-r--r-- | drivers/soundwire/cadence_master.c | 139 |
1 files changed, 85 insertions, 54 deletions
diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index e835dabb516c..39502bc75712 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -27,32 +27,36 @@ module_param_named(cnds_mcp_int_mask, interrupt_mask, int, 0444); MODULE_PARM_DESC(cdns_mcp_int_mask, "Cadence MCP IntMask"); #define CDNS_MCP_CONFIG 0x0 - -#define CDNS_MCP_CONFIG_MCMD_RETRY GENMASK(27, 24) -#define CDNS_MCP_CONFIG_MPREQ_DELAY GENMASK(20, 16) -#define CDNS_MCP_CONFIG_MMASTER BIT(7) #define CDNS_MCP_CONFIG_BUS_REL BIT(6) -#define CDNS_MCP_CONFIG_SNIFFER BIT(5) -#define CDNS_MCP_CONFIG_SSPMOD BIT(4) -#define CDNS_MCP_CONFIG_CMD BIT(3) -#define CDNS_MCP_CONFIG_OP GENMASK(2, 0) -#define CDNS_MCP_CONFIG_OP_NORMAL 0 + +#define CDNS_IP_MCP_CONFIG 0x0 /* IP offset added at run-time */ + +#define CDNS_IP_MCP_CONFIG_MCMD_RETRY GENMASK(27, 24) +#define CDNS_IP_MCP_CONFIG_MPREQ_DELAY GENMASK(20, 16) +#define CDNS_IP_MCP_CONFIG_MMASTER BIT(7) +#define CDNS_IP_MCP_CONFIG_SNIFFER BIT(5) +#define CDNS_IP_MCP_CONFIG_CMD BIT(3) +#define CDNS_IP_MCP_CONFIG_OP GENMASK(2, 0) +#define CDNS_IP_MCP_CONFIG_OP_NORMAL 0 #define CDNS_MCP_CONTROL 0x4 -#define CDNS_MCP_CONTROL_RST_DELAY GENMASK(10, 8) #define CDNS_MCP_CONTROL_CMD_RST BIT(7) #define CDNS_MCP_CONTROL_SOFT_RST BIT(6) -#define CDNS_MCP_CONTROL_SW_RST BIT(5) #define CDNS_MCP_CONTROL_HW_RST BIT(4) -#define CDNS_MCP_CONTROL_CLK_PAUSE BIT(3) #define CDNS_MCP_CONTROL_CLK_STOP_CLR BIT(2) -#define CDNS_MCP_CONTROL_CMD_ACCEPT BIT(1) -#define CDNS_MCP_CONTROL_BLOCK_WAKEUP BIT(0) -#define CDNS_MCP_CMDCTRL 0x8 +#define CDNS_IP_MCP_CONTROL 0x4 /* IP offset added at run-time */ + +#define CDNS_IP_MCP_CONTROL_RST_DELAY GENMASK(10, 8) +#define CDNS_IP_MCP_CONTROL_SW_RST BIT(5) +#define CDNS_IP_MCP_CONTROL_CLK_PAUSE BIT(3) +#define CDNS_IP_MCP_CONTROL_CMD_ACCEPT BIT(1) +#define CDNS_IP_MCP_CONTROL_BLOCK_WAKEUP BIT(0) -#define CDNS_MCP_CMDCTRL_INSERT_PARITY_ERR BIT(2) +#define CDNS_IP_MCP_CMDCTRL 0x8 /* IP offset added at run-time */ + +#define CDNS_IP_MCP_CMDCTRL_INSERT_PARITY_ERR BIT(2) #define CDNS_MCP_SSPSTAT 0xC #define CDNS_MCP_FRAME_SHAPE 0x10 @@ -125,8 +129,8 @@ MODULE_PARM_DESC(cdns_mcp_int_mask, "Cadence MCP IntMask"); #define CDNS_MCP_FIFOSTAT 0x7C #define CDNS_MCP_RX_FIFO_AVAIL GENMASK(5, 0) -#define CDNS_MCP_CMD_BASE 0x80 -#define CDNS_MCP_RESP_BASE 0x80 +#define CDNS_IP_MCP_CMD_BASE 0x80 /* IP offset added at run-time */ +#define CDNS_IP_MCP_RESP_BASE 0x80 /* IP offset added at run-time */ /* FIFO can hold 8 commands */ #define CDNS_MCP_CMD_LEN 8 #define CDNS_MCP_CMD_WORD_LEN 0x4 @@ -206,6 +210,16 @@ static inline void cdns_writel(struct sdw_cdns *cdns, int offset, u32 value) writel(value, cdns->registers + offset); } +static inline u32 cdns_ip_readl(struct sdw_cdns *cdns, int offset) +{ + return cdns_readl(cdns, cdns->ip_offset + offset); +} + +static inline void cdns_ip_writel(struct sdw_cdns *cdns, int offset, u32 value) +{ + return cdns_writel(cdns, cdns->ip_offset + offset, value); +} + static inline void cdns_updatel(struct sdw_cdns *cdns, int offset, u32 mask, u32 val) { @@ -216,6 +230,12 @@ static inline void cdns_updatel(struct sdw_cdns *cdns, cdns_writel(cdns, offset, tmp); } +static inline void cdns_ip_updatel(struct sdw_cdns *cdns, + int offset, u32 mask, u32 val) +{ + cdns_updatel(cdns, cdns->ip_offset + offset, mask, val); +} + static int cdns_set_wait(struct sdw_cdns *cdns, int offset, u32 mask, u32 value) { int timeout = 10; @@ -408,9 +428,9 @@ static int cdns_parity_error_injection(void *data, u64 value) mutex_lock(&bus->bus_lock); /* program hardware to inject parity error */ - cdns_updatel(cdns, CDNS_MCP_CMDCTRL, - CDNS_MCP_CMDCTRL_INSERT_PARITY_ERR, - CDNS_MCP_CMDCTRL_INSERT_PARITY_ERR); + cdns_ip_updatel(cdns, CDNS_IP_MCP_CMDCTRL, + CDNS_IP_MCP_CMDCTRL_INSERT_PARITY_ERR, + CDNS_IP_MCP_CMDCTRL_INSERT_PARITY_ERR); /* commit changes */ cdns_updatel(cdns, CDNS_MCP_CONFIG_UPDATE, @@ -422,9 +442,9 @@ static int cdns_parity_error_injection(void *data, u64 value) dev_info(cdns->dev, "parity error injection, read: %d\n", ret); /* program hardware to disable parity error */ - cdns_updatel(cdns, CDNS_MCP_CMDCTRL, - CDNS_MCP_CMDCTRL_INSERT_PARITY_ERR, - 0); + cdns_ip_updatel(cdns, CDNS_IP_MCP_CMDCTRL, + CDNS_IP_MCP_CMDCTRL_INSERT_PARITY_ERR, + 0); /* commit changes */ cdns_updatel(cdns, CDNS_MCP_CONFIG_UPDATE, @@ -570,10 +590,10 @@ static void cdns_read_response(struct sdw_cdns *cdns) num_resp = ARRAY_SIZE(cdns->response_buf); } - cmd_base = CDNS_MCP_CMD_BASE; + cmd_base = CDNS_IP_MCP_CMD_BASE; for (i = 0; i < num_resp; i++) { - cdns->response_buf[i] = cdns_readl(cdns, cmd_base); + cdns->response_buf[i] = cdns_ip_readl(cdns, cmd_base); cmd_base += CDNS_MCP_CMD_WORD_LEN; } } @@ -592,7 +612,7 @@ _cdns_xfer_msg(struct sdw_cdns *cdns, struct sdw_msg *msg, int cmd, cdns->msg_count = count; } - base = CDNS_MCP_CMD_BASE; + base = CDNS_IP_MCP_CMD_BASE; addr = msg->addr + offset; for (i = 0; i < count; i++) { @@ -605,7 +625,7 @@ _cdns_xfer_msg(struct sdw_cdns *cdns, struct sdw_msg *msg, int cmd, data |= msg->buf[i + offset]; data |= FIELD_PREP(CDNS_MCP_CMD_SSP_TAG, msg->ssp_sync); - cdns_writel(cdns, base, data); + cdns_ip_writel(cdns, base, data); base += CDNS_MCP_CMD_WORD_LEN; } @@ -653,10 +673,10 @@ cdns_program_scp_addr(struct sdw_cdns *cdns, struct sdw_msg *msg) data[0] |= msg->addr_page1; data[1] |= msg->addr_page2; - base = CDNS_MCP_CMD_BASE; - cdns_writel(cdns, base, data[0]); + base = CDNS_IP_MCP_CMD_BASE; + cdns_ip_writel(cdns, base, data[0]); base += CDNS_MCP_CMD_WORD_LEN; - cdns_writel(cdns, base, data[1]); + cdns_ip_writel(cdns, base, data[1]); time = wait_for_completion_timeout(&cdns->tx_complete, msecs_to_jiffies(CDNS_TX_TIMEOUT)); @@ -1033,6 +1053,7 @@ update_status: void sdw_cdns_check_self_clearing_bits(struct sdw_cdns *cdns, const char *string, bool initial_delay, int reset_iterations) { + u32 ip_mcp_control; u32 mcp_control; u32 mcp_config_update; int i; @@ -1040,6 +1061,12 @@ void sdw_cdns_check_self_clearing_bits(struct sdw_cdns *cdns, const char *string if (initial_delay) usleep_range(1000, 1500); + ip_mcp_control = cdns_ip_readl(cdns, CDNS_IP_MCP_CONTROL); + + /* the following bits should be cleared immediately */ + if (ip_mcp_control & CDNS_IP_MCP_CONTROL_SW_RST) + dev_err(cdns->dev, "%s failed: IP_MCP_CONTROL_SW_RST is not cleared\n", string); + mcp_control = cdns_readl(cdns, CDNS_MCP_CONTROL); /* the following bits should be cleared immediately */ @@ -1047,10 +1074,9 @@ void sdw_cdns_check_self_clearing_bits(struct sdw_cdns *cdns, const char *string dev_err(cdns->dev, "%s failed: MCP_CONTROL_CMD_RST is not cleared\n", string); if (mcp_control & CDNS_MCP_CONTROL_SOFT_RST) dev_err(cdns->dev, "%s failed: MCP_CONTROL_SOFT_RST is not cleared\n", string); - if (mcp_control & CDNS_MCP_CONTROL_SW_RST) - dev_err(cdns->dev, "%s failed: MCP_CONTROL_SW_RST is not cleared\n", string); if (mcp_control & CDNS_MCP_CONTROL_CLK_STOP_CLR) dev_err(cdns->dev, "%s failed: MCP_CONTROL_CLK_STOP_CLR is not cleared\n", string); + mcp_config_update = cdns_readl(cdns, CDNS_MCP_CONFIG_UPDATE); if (mcp_config_update & CDNS_MCP_CONFIG_UPDATE_BIT) dev_err(cdns->dev, "%s failed: MCP_CONFIG_UPDATE_BIT is not cleared\n", string); @@ -1327,34 +1353,39 @@ int sdw_cdns_init(struct sdw_cdns *cdns) CDNS_MCP_CONTROL_CMD_RST); /* Set cmd accept mode */ - cdns_updatel(cdns, CDNS_MCP_CONTROL, CDNS_MCP_CONTROL_CMD_ACCEPT, - CDNS_MCP_CONTROL_CMD_ACCEPT); + cdns_ip_updatel(cdns, CDNS_IP_MCP_CONTROL, CDNS_IP_MCP_CONTROL_CMD_ACCEPT, + CDNS_IP_MCP_CONTROL_CMD_ACCEPT); /* Configure mcp config */ val = cdns_readl(cdns, CDNS_MCP_CONFIG); + /* Disable auto bus release */ + val &= ~CDNS_MCP_CONFIG_BUS_REL; + + cdns_writel(cdns, CDNS_MCP_CONFIG, val); + + /* Configure IP mcp config */ + val = cdns_ip_readl(cdns, CDNS_IP_MCP_CONFIG); + /* enable bus operations with clock and data */ - val &= ~CDNS_MCP_CONFIG_OP; - val |= CDNS_MCP_CONFIG_OP_NORMAL; + val &= ~CDNS_IP_MCP_CONFIG_OP; + val |= CDNS_IP_MCP_CONFIG_OP_NORMAL; /* Set cmd mode for Tx and Rx cmds */ - val &= ~CDNS_MCP_CONFIG_CMD; + val &= ~CDNS_IP_MCP_CONFIG_CMD; /* Disable sniffer mode */ - val &= ~CDNS_MCP_CONFIG_SNIFFER; - - /* Disable auto bus release */ - val &= ~CDNS_MCP_CONFIG_BUS_REL; + val &= ~CDNS_IP_MCP_CONFIG_SNIFFER; if (cdns->bus.multi_link) /* Set Multi-master mode to take gsync into account */ - val |= CDNS_MCP_CONFIG_MMASTER; + val |= CDNS_IP_MCP_CONFIG_MMASTER; /* leave frame delay to hardware default of 0x1F */ /* leave command retry to hardware default of 0 */ - cdns_writel(cdns, CDNS_MCP_CONFIG, val); + cdns_ip_writel(cdns, CDNS_IP_MCP_CONFIG, val); /* changes will be committed later */ return 0; @@ -1584,9 +1615,9 @@ int sdw_cdns_clock_stop(struct sdw_cdns *cdns, bool block_wake) * in clock stop state */ if (block_wake) - cdns_updatel(cdns, CDNS_MCP_CONTROL, - CDNS_MCP_CONTROL_BLOCK_WAKEUP, - CDNS_MCP_CONTROL_BLOCK_WAKEUP); + cdns_ip_updatel(cdns, CDNS_IP_MCP_CONTROL, + CDNS_IP_MCP_CONTROL_BLOCK_WAKEUP, + CDNS_IP_MCP_CONTROL_BLOCK_WAKEUP); list_for_each_entry(slave, &cdns->bus.slaves, node) { if (slave->status == SDW_SLAVE_ATTACHED || @@ -1659,18 +1690,18 @@ int sdw_cdns_clock_restart(struct sdw_cdns *cdns, bool bus_reset) return ret; } - cdns_updatel(cdns, CDNS_MCP_CONTROL, - CDNS_MCP_CONTROL_BLOCK_WAKEUP, 0); + cdns_ip_updatel(cdns, CDNS_IP_MCP_CONTROL, + CDNS_IP_MCP_CONTROL_BLOCK_WAKEUP, 0); - cdns_updatel(cdns, CDNS_MCP_CONTROL, CDNS_MCP_CONTROL_CMD_ACCEPT, - CDNS_MCP_CONTROL_CMD_ACCEPT); + cdns_ip_updatel(cdns, CDNS_IP_MCP_CONTROL, CDNS_IP_MCP_CONTROL_CMD_ACCEPT, + CDNS_IP_MCP_CONTROL_CMD_ACCEPT); if (!bus_reset) { /* enable bus operations with clock and data */ - cdns_updatel(cdns, CDNS_MCP_CONFIG, - CDNS_MCP_CONFIG_OP, - CDNS_MCP_CONFIG_OP_NORMAL); + cdns_ip_updatel(cdns, CDNS_IP_MCP_CONFIG, + CDNS_IP_MCP_CONFIG_OP, + CDNS_IP_MCP_CONFIG_OP_NORMAL); ret = cdns_config_update(cdns); if (ret < 0) { |