[PATCH v1] serial: npcm: Add support for Nuvoton NPCM SoCs

Simon Glass sjg at chromium.org
Fri Jan 21 16:20:47 CET 2022


Hi Stanley,

On Sun, 16 Jan 2022 at 20:20, Stanley Chu <stanley.chuys at gmail.com> wrote:
>
> Add Nuvoton BMC NPCM7xx/NPCM8xx uart driver
>
> Signed-off-by: Stanley Chu <yschu at nuvoton.com>
> ---
>  drivers/serial/Kconfig       |   7 ++
>  drivers/serial/Makefile      |   1 +
>  drivers/serial/serial_npcm.c | 151 +++++++++++++++++++++++++++++++++++
>  3 files changed, 159 insertions(+)
>  create mode 100644 drivers/serial/serial_npcm.c
>
> diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
> index 6c8fdda9a0..8daaef61b3 100644
> --- a/drivers/serial/Kconfig
> +++ b/drivers/serial/Kconfig
> @@ -920,6 +920,13 @@ config MPC8XX_CONS
>         depends on MPC8xx
>         default y
>
> +config NPCM_SERIAL
> +       bool "UART driver for Nuvoton NPCM BMC"
> +       depends on DM_SERIAL
> +       help
> +         Select this to enable UART support for Nuvoton BMCs
> +         (NPCM7xx and NPCM8xx)

What features does it support? Please expand this a bit.

> +
>  config XEN_SERIAL
>         bool "XEN serial support"
>         depends on XEN
> diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
> index 8168af640f..866495e416 100644
> --- a/drivers/serial/Makefile
> +++ b/drivers/serial/Makefile
> @@ -73,6 +73,7 @@ obj-$(CONFIG_OWL_SERIAL) += serial_owl.o
>  obj-$(CONFIG_OMAP_SERIAL) += serial_omap.o
>  obj-$(CONFIG_MTK_SERIAL) += serial_mtk.o
>  obj-$(CONFIG_MT7620_SERIAL) += serial_mt7620.o
> +obj-$(CONFIG_NPCM_SERIAL) += serial_npcm.o
>  obj-$(CONFIG_SIFIVE_SERIAL) += serial_sifive.o
>  obj-$(CONFIG_XEN_SERIAL) += serial_xen.o
>
> diff --git a/drivers/serial/serial_npcm.c b/drivers/serial/serial_npcm.c
> new file mode 100644
> index 0000000000..67343e5805
> --- /dev/null
> +++ b/drivers/serial/serial_npcm.c
> @@ -0,0 +1,151 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (c) 2021 Nuvoton Technology Corp.
> + */
> +
> +#include <common.h>
> +#include <clk.h>
> +#include <dm.h>
> +#include <serial.h>
> +
> +struct npcm_uart {
> +       union {
> +               u32     rbr;
> +               u32     thr;
> +               u32     dll;
> +       };
> +       union {
> +               u32     ier;
> +               u32     dlm;
> +       };
> +       union {
> +               u32     iir;
> +               u32     fcr;
> +       };
> +       u32     lcr;
> +       u32     mcr;
> +       u32     lsr;
> +       u32     msr;
> +       u32     tor;
> +};
> +
> +#define LCR_WLS_8BITS  3
> +#define        FCR_TFR         BIT(2)
> +#define        FCR_RFR         BIT(1)
> +#define        FCR_FME         BIT(0)
> +#define        LSR_THRE        BIT(5)
> +#define        LSR_RFDR        BIT(0)
> +#define        LCR_DLAB        BIT(7)
> +
> +struct npcm_serial_plat {
> +       struct npcm_uart *reg;
> +       u32 uart_clk;

comment that

> +};
> +
> +static int npcm_serial_pending(struct udevice *dev, bool input)
> +{
> +       struct npcm_serial_plat *plat = dev_get_plat(dev);
> +       struct npcm_uart *uart = plat->reg;
> +
> +       if (input)
> +               return (readb(&uart->lsr) & LSR_RFDR);

drop outer brackets

> +       else
> +               return !(readb(&uart->lsr) & LSR_THRE);

and here

> +}
> +
> +static int npcm_serial_putc(struct udevice *dev, const char ch)
> +{
> +       struct npcm_serial_plat *plat = dev_get_plat(dev);
> +       struct npcm_uart *uart = plat->reg;
> +
> +       while (!(readb(&uart->lsr) & LSR_THRE))
> +               ;

You cannot loop here. Return -EAGAIN instead if you cannot print.

> +
> +       writeb(ch, &uart->thr);
> +
> +       return 0;
> +}
> +
> +static int npcm_serial_getc(struct udevice *dev)
> +{
> +       struct npcm_serial_plat *plat = dev_get_plat(dev);
> +       struct npcm_uart *uart = plat->reg;
> +
> +       while (!(readb(&uart->lsr) & LSR_RFDR))
> +               ;

You cannot loop here. Return -EAGAIN instead. See __serial_getc()

> +
> +       return readb(&uart->rbr);
> +}
> +
> +static int npcm_serial_setbrg(struct udevice *dev, int baudrate)
> +{
> +       struct npcm_serial_plat *plat = dev_get_plat(dev);
> +       struct npcm_uart *uart = plat->reg;
> +       u16 divisor;
> +
> +       /* BaudOut = UART Clock  / (16 * [Divisor + 2]) */
> +       divisor = DIV_ROUND_CLOSEST(plat->uart_clk, 16 * baudrate + 2) - 2;
> +
> +       setbits_8(&uart->lcr, LCR_DLAB);
> +       writeb(divisor & 0xff, &uart->dll);
> +       writeb(divisor >> 8, &uart->dlm);
> +       clrbits_8(&uart->lcr, LCR_DLAB);
> +
> +       return 0;
> +}
> +
> +static int npcm_serial_probe(struct udevice *dev)
> +{
> +       struct npcm_serial_plat *plat = dev_get_plat(dev);
> +       struct npcm_uart *uart = plat->reg;
> +       struct clk clk;
> +       u32 freq;
> +       int ret;
> +
> +       plat->reg = dev_read_addr_ptr(dev);
> +       freq = dev_read_u32_default(dev, "clock-frequency", 0);
> +
> +       ret = clk_get_by_index(dev, 0, &clk);
> +       if (ret < 0) {
> +               printf("Cannot get clk for uart\n");

log_debug() would be better to avoid increasing code size

> +               return ret;
> +       }
> +       ret = clk_set_rate(&clk, freq);
> +       if (ret < 0)
> +               return ret;
> +       plat->uart_clk = ret;
> +
> +       /* Disable all interrupt */
> +       writeb(0, &uart->ier);
> +
> +       /* Set 8 bit, 1 stop, no parity */
> +       writeb(LCR_WLS_8BITS, &uart->lcr);
> +
> +       /* Reset RX/TX FIFO */
> +       writeb(FCR_FME | FCR_RFR | FCR_TFR, &uart->fcr);
> +
> +       return 0;
> +}
> +
> +static const struct dm_serial_ops npcm_serial_ops = {
> +       .getc = npcm_serial_getc,
> +       .setbrg = npcm_serial_setbrg,
> +       .putc = npcm_serial_putc,
> +       .pending = npcm_serial_pending,
> +};
> +
> +static const struct udevice_id npcm_serial_ids[] = {
> +       { .compatible = "nuvoton,npcm750-uart" },
> +       { .compatible = "nuvoton,npcm845-uart" },
> +       { }
> +};
> +
> +U_BOOT_DRIVER(serial_npcm) = {
> +       .name   = "serial_npcm",
> +       .id     = UCLASS_SERIAL,
> +       .of_match = npcm_serial_ids,
> +       .plat_auto  = sizeof(struct npcm_serial_plat),
> +       .probe = npcm_serial_probe,
> +       .ops    = &npcm_serial_ops,
> +       .flags = DM_FLAG_PRE_RELOC,
> +};
> --
> 2.17.1
>

Regards,
Simon


More information about the U-Boot mailing list