On Tue, Sep 23, 2025 at 09:15:50PM +0530, Manikanta Guntupalli wrote:
> 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]>
> ---

Reviewed-by: Frank Li <[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
>

Reply via email to