Add endianness handling to the FIFO access helpers i3c_readl_fifo() and i3c_writel_fifo(). This ensures correct data transfers on platforms where the FIFO registers are expected to be accessed in either big-endian or little-endian format.
Update the Synopsys, Cadence, and Renesas I3C master controller drivers to pass the appropriate endianness argument to these helpers. Signed-off-by: Manikanta Guntupalli <[email protected]> --- Changes since V7: This patch introduced in V7. --- drivers/i3c/internals.h | 35 +++++++++++++++++++++++----- drivers/i3c/master/dw-i3c-master.c | 9 ++++--- drivers/i3c/master/i3c-master-cdns.c | 9 ++++--- drivers/i3c/master/renesas-i3c.c | 12 ++++++---- 4 files changed, 49 insertions(+), 16 deletions(-) diff --git a/drivers/i3c/internals.h b/drivers/i3c/internals.h index 0d857cc68cc5..399bbf006dcd 100644 --- a/drivers/i3c/internals.h +++ b/drivers/i3c/internals.h @@ -24,21 +24,35 @@ int i3c_dev_request_ibi_locked(struct i3c_dev_desc *dev, const struct i3c_ibi_setup *req); void i3c_dev_free_ibi_locked(struct i3c_dev_desc *dev); +enum i3c_fifo_endian { + I3C_FIFO_LITTLE_ENDIAN, + I3C_FIFO_BIG_ENDIAN, +}; + /** * i3c_writel_fifo - Write data buffer to 32bit FIFO * @addr: FIFO Address to write to * @buf: Pointer to the data bytes to write * @nbytes: Number of bytes to write + * @endian: Endianness of FIFO write */ static inline void i3c_writel_fifo(void __iomem *addr, const void *buf, - int nbytes) + int nbytes, enum i3c_fifo_endian endian) { - writesl(addr, buf, nbytes / 4); + if (endian) + writesl_be(addr, buf, nbytes / 4); + else + writesl(addr, buf, nbytes / 4); + if (nbytes & 3) { u32 tmp = 0; memcpy(&tmp, buf + (nbytes & ~3), nbytes & 3); - writel(tmp, addr); + + if (endian) + writel_be(tmp, addr); + else + writel(tmp, addr); } } @@ -47,15 +61,24 @@ static inline void i3c_writel_fifo(void __iomem *addr, const void *buf, * @addr: FIFO Address to read from * @buf: Pointer to the buffer to store read bytes * @nbytes: Number of bytes to read + * @endian: Endianness of FIFO read */ static inline void i3c_readl_fifo(const void __iomem *addr, void *buf, - int nbytes) + int nbytes, enum i3c_fifo_endian endian) { - readsl(addr, buf, nbytes / 4); + if (endian) + readsl_be(addr, buf, nbytes / 4); + else + readsl(addr, buf, nbytes / 4); + if (nbytes & 3) { u32 tmp; - tmp = readl(addr); + if (endian) + tmp = readl_be(addr); + else + tmp = readl(addr); + memcpy(buf + (nbytes & ~3), &tmp, nbytes & 3); } } diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c index 974122b2d20e..5d723ac041c2 100644 --- a/drivers/i3c/master/dw-i3c-master.c +++ b/drivers/i3c/master/dw-i3c-master.c @@ -337,19 +337,22 @@ static int dw_i3c_master_get_free_pos(struct dw_i3c_master *master) static void dw_i3c_master_wr_tx_fifo(struct dw_i3c_master *master, const u8 *bytes, int nbytes) { - i3c_writel_fifo(master->regs + RX_TX_DATA_PORT, bytes, nbytes); + i3c_writel_fifo(master->regs + RX_TX_DATA_PORT, bytes, nbytes, + I3C_FIFO_LITTLE_ENDIAN); } static void dw_i3c_master_read_rx_fifo(struct dw_i3c_master *master, u8 *bytes, int nbytes) { - i3c_readl_fifo(master->regs + RX_TX_DATA_PORT, bytes, nbytes); + i3c_readl_fifo(master->regs + RX_TX_DATA_PORT, bytes, nbytes, + I3C_FIFO_LITTLE_ENDIAN); } static void dw_i3c_master_read_ibi_fifo(struct dw_i3c_master *master, u8 *bytes, int nbytes) { - i3c_readl_fifo(master->regs + IBI_QUEUE_STATUS, bytes, nbytes); + i3c_readl_fifo(master->regs + IBI_QUEUE_STATUS, bytes, nbytes, + I3C_FIFO_LITTLE_ENDIAN); } static struct dw_i3c_xfer * diff --git a/drivers/i3c/master/i3c-master-cdns.c b/drivers/i3c/master/i3c-master-cdns.c index 97b151564d3d..de3b5e894b4b 100644 --- a/drivers/i3c/master/i3c-master-cdns.c +++ b/drivers/i3c/master/i3c-master-cdns.c @@ -428,13 +428,15 @@ to_cdns_i3c_master(struct i3c_master_controller *master) static void cdns_i3c_master_wr_to_tx_fifo(struct cdns_i3c_master *master, const u8 *bytes, int nbytes) { - i3c_writel_fifo(master->regs + TX_FIFO, bytes, nbytes); + i3c_writel_fifo(master->regs + TX_FIFO, bytes, nbytes, + I3C_FIFO_LITTLE_ENDIAN); } static void cdns_i3c_master_rd_from_rx_fifo(struct cdns_i3c_master *master, u8 *bytes, int nbytes) { - i3c_readl_fifo(master->regs + RX_FIFO, bytes, nbytes); + i3c_readl_fifo(master->regs + RX_FIFO, bytes, nbytes, + I3C_FIFO_LITTLE_ENDIAN); } static bool cdns_i3c_master_supports_ccc_cmd(struct i3c_master_controller *m, @@ -1319,7 +1321,8 @@ static void cdns_i3c_master_handle_ibi(struct cdns_i3c_master *master, buf = slot->data; nbytes = IBIR_XFER_BYTES(ibir); - i3c_readl_fifo(master->regs + IBI_DATA_FIFO, buf, nbytes); + i3c_readl_fifo(master->regs + IBI_DATA_FIFO, buf, nbytes, + I3C_FIFO_LITTLE_ENDIAN); slot->len = min_t(unsigned int, IBIR_XFER_BYTES(ibir), dev->ibi->max_payload_len); diff --git a/drivers/i3c/master/renesas-i3c.c b/drivers/i3c/master/renesas-i3c.c index 174d3dc5d276..5610cf71740e 100644 --- a/drivers/i3c/master/renesas-i3c.c +++ b/drivers/i3c/master/renesas-i3c.c @@ -835,7 +835,8 @@ static int renesas_i3c_priv_xfers(struct i3c_dev_desc *dev, struct i3c_priv_xfer } if (!i3c_xfers[i].rnw && i3c_xfers[i].len > 4) { - i3c_writel_fifo(i3c->regs + NTDTBP0, cmd->tx_buf, cmd->len); + i3c_writel_fifo(i3c->regs + NTDTBP0, cmd->tx_buf, cmd->len, + I3C_FIFO_LITTLE_ENDIAN); if (cmd->len > NTDTBP0_DEPTH * sizeof(u32)) renesas_set_bit(i3c->regs, NTIE, NTIE_TDBEIE0); } @@ -1021,7 +1022,8 @@ static irqreturn_t renesas_i3c_tx_isr(int irq, void *data) /* Clear the Transmit Buffer Empty status flag. */ renesas_clear_bit(i3c->regs, NTST, NTST_TDBEF0); } else { - i3c_writel_fifo(i3c->regs + NTDTBP0, cmd->tx_buf, cmd->len); + i3c_writel_fifo(i3c->regs + NTDTBP0, cmd->tx_buf, cmd->len, + I3C_FIFO_LITTLE_ENDIAN); } } @@ -1061,7 +1063,8 @@ static irqreturn_t renesas_i3c_resp_isr(int irq, void *data) if (NDBSTLV0_RDBLV(renesas_readl(i3c->regs, NDBSTLV0)) && !cmd->err) bytes_remaining = data_len - cmd->rx_count; - i3c_readl_fifo(i3c->regs + NTDTBP0, cmd->rx_buf, bytes_remaining); + i3c_readl_fifo(i3c->regs + NTDTBP0, cmd->rx_buf, bytes_remaining, + I3C_FIFO_LITTLE_ENDIAN); renesas_clear_bit(i3c->regs, NTIE, NTIE_RDBFIE0); break; default: @@ -1203,7 +1206,8 @@ static irqreturn_t renesas_i3c_rx_isr(int irq, void *data) cmd->i2c_bytes_left--; } else { read_bytes = NDBSTLV0_RDBLV(renesas_readl(i3c->regs, NDBSTLV0)) * sizeof(u32); - i3c_readl_fifo(i3c->regs + NTDTBP0, cmd->rx_buf, read_bytes); + i3c_readl_fifo(i3c->regs + NTDTBP0, cmd->rx_buf, read_bytes, + I3C_FIFO_LITTLE_ENDIAN); cmd->rx_count = read_bytes; } -- 2.34.1
