[PATCH] serial: uartlite: Add support to work with any endianness

Michal Simek monstr at monstr.eu
Mon Sep 14 11:25:13 CEST 2020


Hi,

čt 27. 8. 2020 v 14:10 odesílatel Michal Simek <michal.simek at xilinx.com> napsal:
>
> From: T Karthik Reddy <t.karthik.reddy at xilinx.com>
>
> This endinness changes are taken from linux uartlite driver.
> Reset TX fifo in control register and check TX fifo empty
> flag in lower byte of the status register to detect if it
> is a little endian system. Based on this check, program the
> registers with le32 or be32 through out the driver.
>
> Signed-off-by: T Karthik Reddy <t.karthik.reddy at xilinx.com>
> Signed-off-by: Ashok Reddy Soma <ashok.reddy.soma at xilinx.com>
> Signed-off-by: Michal Simek <michal.simek at xilinx.com>
> ---
>
>  drivers/serial/serial_xuartlite.c | 74 ++++++++++++++++++++++++++-----
>  1 file changed, 64 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/serial/serial_xuartlite.c b/drivers/serial/serial_xuartlite.c
> index 5116d13751de..e16642504b16 100644
> --- a/drivers/serial/serial_xuartlite.c
> +++ b/drivers/serial/serial_xuartlite.c
> @@ -32,17 +32,64 @@ struct uartlite {
>
>  struct uartlite_platdata {
>         struct uartlite *regs;
> +       const struct uartlite_reg_ops *reg_ops;
>  };
>
> +struct uartlite_reg_ops {
> +       u32 (*in)(void __iomem *addr);
> +       void (*out)(u32 val, void __iomem *addr);
> +};
> +
> +static u32 uartlite_inle32(void __iomem *addr)
> +{
> +       return in_le32(addr);
> +}
> +
> +static void uartlite_outle32(u32 val, void __iomem *addr)
> +{
> +       out_le32(addr, val);
> +}
> +
> +static const struct uartlite_reg_ops uartlite_le = {
> +       .in = uartlite_inle32,
> +       .out = uartlite_outle32,
> +};
> +
> +static u32 uartlite_inbe32(void __iomem *addr)
> +{
> +       return in_be32(addr);
> +}
> +
> +static void uartlite_outbe32(u32 val, void __iomem *addr)
> +{
> +       out_be32(addr, val);
> +}
> +
> +static const struct uartlite_reg_ops uartlite_be = {
> +       .in = uartlite_inbe32,
> +       .out = uartlite_outbe32,
> +};
> +
> +static u32 uart_in32(void __iomem *addr, struct uartlite_platdata *plat)
> +{
> +       return plat->reg_ops->in(addr);
> +}
> +
> +static void uart_out32(void __iomem *addr, u32 val,
> +                      struct uartlite_platdata *plat)
> +{
> +       plat->reg_ops->out(val, addr);
> +}
> +
>  static int uartlite_serial_putc(struct udevice *dev, const char ch)
>  {
>         struct uartlite_platdata *plat = dev_get_platdata(dev);
>         struct uartlite *regs = plat->regs;
>
> -       if (in_be32(&regs->status) & SR_TX_FIFO_FULL)
> +       if (uart_in32(&regs->status, plat) & SR_TX_FIFO_FULL)
>                 return -EAGAIN;
>
> -       out_be32(&regs->tx_fifo, ch & 0xff);
> +       uart_out32(&regs->tx_fifo, ch & 0xff, plat);
>
>         return 0;
>  }
> @@ -52,10 +99,10 @@ static int uartlite_serial_getc(struct udevice *dev)
>         struct uartlite_platdata *plat = dev_get_platdata(dev);
>         struct uartlite *regs = plat->regs;
>
> -       if (!(in_be32(&regs->status) & SR_RX_FIFO_VALID_DATA))
> +       if (!(uart_in32(&regs->status, plat) & SR_RX_FIFO_VALID_DATA))
>                 return -EAGAIN;
>
> -       return in_be32(&regs->rx_fifo) & 0xff;
> +       return uart_in32(&regs->rx_fifo, plat) & 0xff;
>  }
>
>  static int uartlite_serial_pending(struct udevice *dev, bool input)
> @@ -64,19 +111,26 @@ static int uartlite_serial_pending(struct udevice *dev, bool input)
>         struct uartlite *regs = plat->regs;
>
>         if (input)
> -               return in_be32(&regs->status) & SR_RX_FIFO_VALID_DATA;
> +               return uart_in32(&regs->status, plat) & SR_RX_FIFO_VALID_DATA;
>
> -       return !(in_be32(&regs->status) & SR_TX_FIFO_EMPTY);
> +       return !(uart_in32(&regs->status, plat) & SR_TX_FIFO_EMPTY);
>  }
>
>  static int uartlite_serial_probe(struct udevice *dev)
>  {
>         struct uartlite_platdata *plat = dev_get_platdata(dev);
>         struct uartlite *regs = plat->regs;
> -
> -       out_be32(&regs->control, 0);
> -       out_be32(&regs->control, ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX);
> -       in_be32(&regs->control);
> +       int ret;
> +
> +       plat->reg_ops = &uartlite_be;
> +       ret = uart_in32(&regs->control, plat);
> +       uart_out32(&regs->control, 0, plat);
> +       uart_out32(&regs->control,
> +                  ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX, plat);
> +       ret = uart_in32(&regs->status, plat);
> +       /* Endianness detection */
> +       if ((ret & SR_TX_FIFO_EMPTY) != SR_TX_FIFO_EMPTY)
> +               plat->reg_ops = &uartlite_le;
>
>         return 0;
>  }
> --
> 2.28.0
>

We found some issues with this patch that's why please ignore it - v2
will be sent.

Thanks,
Michal

-- 
Michal Simek, Ing. (M.Eng), OpenPGP -> KeyID: FE3D1F91
w: www.monstr.eu p: +42-0-721842854
Maintainer of Linux kernel - Xilinx Microblaze
Maintainer of Linux kernel - Xilinx Zynq ARM and ZynqMP ARM64 SoCs
U-Boot custodian - Xilinx Microblaze/Zynq/ZynqMP/Versal SoCs


More information about the U-Boot mailing list