Message ID | 20220117031953.16098-1-yschu@nuvoton.com |
---|---|
State | Superseded |
Delegated to: | Tom Rini |
Headers | show |
Series | [v1] serial: npcm: Add support for Nuvoton NPCM SoCs | expand |
Hi Stanley, On Sun, 16 Jan 2022 at 20:20, Stanley Chu <stanley.chuys@gmail.com> wrote: > > Add Nuvoton BMC NPCM7xx/NPCM8xx uart driver > > Signed-off-by: Stanley Chu <yschu@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
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) + 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; +}; + +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); + else + return !(readb(&uart->lsr) & LSR_THRE); +} + +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)) + ; + + 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)) + ; + + 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"); + 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, +};
Add Nuvoton BMC NPCM7xx/NPCM8xx uart driver Signed-off-by: Stanley Chu <yschu@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