diff options
Diffstat (limited to 'drivers/serial')
-rw-r--r-- | drivers/serial/Kconfig | 12 | ||||
-rw-r--r-- | drivers/serial/Makefile | 7 | ||||
-rw-r--r-- | drivers/serial/ns16550.c | 17 | ||||
-rw-r--r-- | drivers/serial/serial-uclass.c | 107 | ||||
-rw-r--r-- | drivers/serial/serial.c | 10 | ||||
-rw-r--r-- | drivers/serial/serial_coreboot.c | 38 | ||||
-rw-r--r-- | drivers/serial/serial_mxc.c | 170 | ||||
-rw-r--r-- | drivers/serial/serial_ns16550.c | 21 | ||||
-rw-r--r-- | drivers/serial/serial_omap.c | 47 | ||||
-rw-r--r-- | drivers/serial/serial_pl01x.c | 373 | ||||
-rw-r--r-- | drivers/serial/serial_pl01x_internal.h (renamed from drivers/serial/serial_pl01x.h) | 0 | ||||
-rw-r--r-- | drivers/serial/serial_s3c24x0.c | 10 | ||||
-rw-r--r-- | drivers/serial/serial_s5p.c | 255 | ||||
-rw-r--r-- | drivers/serial/serial_sh.c | 4 | ||||
-rw-r--r-- | drivers/serial/serial_uniphier.c | 199 |
15 files changed, 715 insertions, 555 deletions
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index e69de29..a0b6e02 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -0,0 +1,12 @@ +config DM_SERIAL + bool "Enable Driver Model for serial drivers" + depends on DM + help + If you want to use driver model for serial drivers, say Y. + To use legacy serial drivers, say N. + +config UNIPHIER_SERIAL + bool "UniPhier on-chip UART support" + depends on ARCH_UNIPHIER && DM_SERIAL + help + Support for the on-chip UARTs on the Panasonic UniPhier platform. diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index b4f299b..2c19ebc 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -7,8 +7,11 @@ ifdef CONFIG_DM_SERIAL obj-y += serial-uclass.o +obj-$(CONFIG_PL01X_SERIAL) += serial_pl01x.o else obj-y += serial.o +obj-$(CONFIG_PL010_SERIAL) += serial_pl01x.o +obj-$(CONFIG_PL011_SERIAL) += serial_pl01x.o obj-$(CONFIG_SYS_NS16550_SERIAL) += serial_ns16550.o endif @@ -25,8 +28,6 @@ obj-$(CONFIG_IMX_SERIAL) += serial_imx.o obj-$(CONFIG_KS8695_SERIAL) += serial_ks8695.o obj-$(CONFIG_MAX3100_SERIAL) += serial_max3100.o obj-$(CONFIG_MXC_UART) += serial_mxc.o -obj-$(CONFIG_PL010_SERIAL) += serial_pl01x.o -obj-$(CONFIG_PL011_SERIAL) += serial_pl01x.o obj-$(CONFIG_PXA_SERIAL) += serial_pxa.o obj-$(CONFIG_SA1100_SERIAL) += serial_sa1100.o obj-$(CONFIG_S3C24X0_SERIAL) += serial_s3c24x0.o @@ -40,6 +41,8 @@ obj-$(CONFIG_MXS_AUART) += mxs_auart.o obj-$(CONFIG_ARC_SERIAL) += serial_arc.o obj-$(CONFIG_TEGRA_SERIAL) += serial_tegra.o obj-$(CONFIG_UNIPHIER_SERIAL) += serial_uniphier.o +obj-$(CONFIG_OMAP_SERIAL) += serial_omap.o +obj-$(CONFIG_COREBOOT_SERIAL) += serial_coreboot.o ifndef CONFIG_SPL_BUILD obj-$(CONFIG_USB_TTY) += usbtty.o diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c index 63a9ef6..8f05191 100644 --- a/drivers/serial/ns16550.c +++ b/drivers/serial/ns16550.c @@ -61,13 +61,13 @@ static void ns16550_writeb(NS16550_t port, int offset, int value) unsigned char *addr; offset *= 1 << plat->reg_shift; - addr = plat->base + offset; + addr = map_sysmem(plat->base, 0) + offset; /* * As far as we know it doesn't make sense to support selection of * these options at run-time, so use the existing CONFIG options. */ #ifdef CONFIG_SYS_NS16550_PORT_MAPPED - outb(value, addr); + outb(value, (ulong)addr); #elif defined(CONFIG_SYS_NS16550_MEM32) && !defined(CONFIG_SYS_BIG_ENDIAN) out_le32(addr, value); #elif defined(CONFIG_SYS_NS16550_MEM32) && defined(CONFIG_SYS_BIG_ENDIAN) @@ -85,9 +85,9 @@ static int ns16550_readb(NS16550_t port, int offset) unsigned char *addr; offset *= 1 << plat->reg_shift; - addr = plat->base + offset; + addr = map_sysmem(plat->base, 0) + offset; #ifdef CONFIG_SYS_NS16550_PORT_MAPPED - return inb(addr); + return inb((ulong)addr); #elif defined(CONFIG_SYS_NS16550_MEM32) && !defined(CONFIG_SYS_BIG_ENDIAN) return in_le32(addr); #elif defined(CONFIG_SYS_NS16550_MEM32) && defined(CONFIG_SYS_BIG_ENDIAN) @@ -253,7 +253,7 @@ static int ns16550_serial_getc(struct udevice *dev) { struct NS16550 *const com_port = dev_get_priv(dev); - if (!serial_in(&com_port->lsr) & UART_LSR_DR) + if (!(serial_in(&com_port->lsr) & UART_LSR_DR)) return -EAGAIN; return serial_in(&com_port->rbr); @@ -276,14 +276,15 @@ int ns16550_serial_probe(struct udevice *dev) { struct NS16550 *const com_port = dev_get_priv(dev); + com_port->plat = dev_get_platdata(dev); NS16550_init(com_port, -1); return 0; } +#ifdef CONFIG_OF_CONTROL int ns16550_serial_ofdata_to_platdata(struct udevice *dev) { - struct NS16550 *const com_port = dev_get_priv(dev); struct ns16550_platdata *plat = dev->platdata; fdt_addr_t addr; @@ -291,13 +292,13 @@ int ns16550_serial_ofdata_to_platdata(struct udevice *dev) if (addr == FDT_ADDR_T_NONE) return -EINVAL; - plat->base = (unsigned char *)addr; + plat->base = addr; plat->reg_shift = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "reg-shift", 1); - com_port->plat = plat; return 0; } +#endif const struct dm_serial_ops ns16550_serial_ops = { .putc = ns16550_serial_putc, diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c index 6dde4ea..71f1a5c 100644 --- a/drivers/serial/serial-uclass.c +++ b/drivers/serial/serial-uclass.c @@ -11,9 +11,12 @@ #include <os.h> #include <serial.h> #include <stdio_dev.h> +#include <watchdog.h> #include <dm/lists.h> #include <dm/device-internal.h> +#include <ns16550.h> + DECLARE_GLOBAL_DATA_PTR; /* The currently-selected console serial device */ @@ -47,13 +50,22 @@ static void serial_find_console_or_panic(void) } #endif /* + * Try to use CONFIG_CONS_INDEX if available (it is numbered from 1!). + * * Failing that, get the device with sequence number 0, or in extremis * just the first serial device we can find. But we insist on having * a console (even if it is silent). */ - if (uclass_get_device_by_seq(UCLASS_SERIAL, 0, &cur_dev) && +#ifdef CONFIG_CONS_INDEX +#define INDEX (CONFIG_CONS_INDEX - 1) +#else +#define INDEX 0 +#endif + if (uclass_get_device_by_seq(UCLASS_SERIAL, INDEX, &cur_dev) && + uclass_get_device(UCLASS_SERIAL, INDEX, &cur_dev) && (uclass_first_device(UCLASS_SERIAL, &cur_dev) || !cur_dev)) panic("No serial driver found"); +#undef INDEX } /* Called prior to relocation */ @@ -71,95 +83,98 @@ void serial_initialize(void) serial_find_console_or_panic(); } -void serial_putc(char ch) +static void _serial_putc(struct udevice *dev, char ch) { - struct dm_serial_ops *ops = serial_get_ops(cur_dev); + struct dm_serial_ops *ops = serial_get_ops(dev); int err; do { - err = ops->putc(cur_dev, ch); + err = ops->putc(dev, ch); } while (err == -EAGAIN); if (ch == '\n') - serial_putc('\r'); + _serial_putc(dev, '\r'); } -void serial_setbrg(void) +static void _serial_puts(struct udevice *dev, const char *str) { - struct dm_serial_ops *ops = serial_get_ops(cur_dev); - - if (ops->setbrg) - ops->setbrg(cur_dev, gd->baudrate); + while (*str) + _serial_putc(dev, *str++); } -void serial_puts(const char *str) +static int _serial_getc(struct udevice *dev) { - while (*str) - serial_putc(*str++); + struct dm_serial_ops *ops = serial_get_ops(dev); + int err; + + do { + err = ops->getc(dev); + if (err == -EAGAIN) + WATCHDOG_RESET(); + } while (err == -EAGAIN); + + return err >= 0 ? err : 0; } -int serial_tstc(void) +static int _serial_tstc(struct udevice *dev) { - struct dm_serial_ops *ops = serial_get_ops(cur_dev); + struct dm_serial_ops *ops = serial_get_ops(dev); if (ops->pending) - return ops->pending(cur_dev, true); + return ops->pending(dev, true); return 1; } +void serial_putc(char ch) +{ + _serial_putc(cur_dev, ch); +} + +void serial_puts(const char *str) +{ + _serial_puts(cur_dev, str); +} + int serial_getc(void) { - struct dm_serial_ops *ops = serial_get_ops(cur_dev); - int err; + return _serial_getc(cur_dev); +} - do { - err = ops->getc(cur_dev); - } while (err == -EAGAIN); +int serial_tstc(void) +{ + return _serial_tstc(cur_dev); +} - return err >= 0 ? err : 0; +void serial_setbrg(void) +{ + struct dm_serial_ops *ops = serial_get_ops(cur_dev); + + if (ops->setbrg) + ops->setbrg(cur_dev, gd->baudrate); } void serial_stdio_init(void) { } -void serial_stub_putc(struct stdio_dev *sdev, const char ch) +static void serial_stub_putc(struct stdio_dev *sdev, const char ch) { - struct udevice *dev = sdev->priv; - struct dm_serial_ops *ops = serial_get_ops(dev); - - ops->putc(dev, ch); + _serial_putc(sdev->priv, ch); } void serial_stub_puts(struct stdio_dev *sdev, const char *str) { - while (*str) - serial_stub_putc(sdev, *str++); + _serial_puts(sdev->priv, str); } int serial_stub_getc(struct stdio_dev *sdev) { - struct udevice *dev = sdev->priv; - struct dm_serial_ops *ops = serial_get_ops(dev); - - int err; - - do { - err = ops->getc(dev); - } while (err == -EAGAIN); - - return err >= 0 ? err : 0; + return _serial_getc(sdev->priv); } int serial_stub_tstc(struct stdio_dev *sdev) { - struct udevice *dev = sdev->priv; - struct dm_serial_ops *ops = serial_get_ops(dev); - - if (ops->pending) - return ops->pending(dev, true); - - return 1; + return _serial_tstc(sdev->priv); } static int serial_post_probe(struct udevice *dev) diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c index 82fbbd9..18e41b2 100644 --- a/drivers/serial/serial.c +++ b/drivers/serial/serial.c @@ -157,7 +157,6 @@ serial_initfunc(sh_serial_initialize); serial_initfunc(arm_dcc_initialize); serial_initfunc(mxs_auart_initialize); serial_initfunc(arc_serial_initialize); -serial_initfunc(uniphier_serial_initialize); /** * serial_register() - Register serial driver with serial driver core @@ -251,33 +250,32 @@ void serial_initialize(void) arm_dcc_initialize(); mxs_auart_initialize(); arc_serial_initialize(); - uniphier_serial_initialize(); serial_assign(default_serial_console()->name); } -int serial_stub_start(struct stdio_dev *sdev) +static int serial_stub_start(struct stdio_dev *sdev) { struct serial_device *dev = sdev->priv; return dev->start(); } -int serial_stub_stop(struct stdio_dev *sdev) +static int serial_stub_stop(struct stdio_dev *sdev) { struct serial_device *dev = sdev->priv; return dev->stop(); } -void serial_stub_putc(struct stdio_dev *sdev, const char ch) +static void serial_stub_putc(struct stdio_dev *sdev, const char ch) { struct serial_device *dev = sdev->priv; dev->putc(ch); } -void serial_stub_puts(struct stdio_dev *sdev, const char *str) +static void serial_stub_puts(struct stdio_dev *sdev, const char *str) { struct serial_device *dev = sdev->priv; diff --git a/drivers/serial/serial_coreboot.c b/drivers/serial/serial_coreboot.c new file mode 100644 index 0000000..5c6a76c --- /dev/null +++ b/drivers/serial/serial_coreboot.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2014 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <ns16550.h> +#include <serial.h> + +static const struct udevice_id coreboot_serial_ids[] = { + { .compatible = "coreboot-uart" }, + { } +}; + +static int coreboot_serial_ofdata_to_platdata(struct udevice *dev) +{ + struct ns16550_platdata *plat = dev_get_platdata(dev); + int ret; + + ret = ns16550_serial_ofdata_to_platdata(dev); + if (ret) + return ret; + plat->clock = 1843200; + + return 0; +} +U_BOOT_DRIVER(serial_ns16550) = { + .name = "serial_coreboot", + .id = UCLASS_SERIAL, + .of_match = coreboot_serial_ids, + .ofdata_to_platdata = coreboot_serial_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct ns16550_platdata), + .priv_auto_alloc_size = sizeof(struct NS16550), + .probe = ns16550_serial_probe, + .ops = &ns16550_serial_ops, +}; diff --git a/drivers/serial/serial_mxc.c b/drivers/serial/serial_mxc.c index 313d560..d6cf1d8 100644 --- a/drivers/serial/serial_mxc.c +++ b/drivers/serial/serial_mxc.c @@ -5,37 +5,15 @@ */ #include <common.h> +#include <dm.h> +#include <errno.h> #include <watchdog.h> #include <asm/arch/imx-regs.h> #include <asm/arch/clock.h> +#include <dm/platform_data/serial_mxc.h> #include <serial.h> #include <linux/compiler.h> -#define __REG(x) (*((volatile u32 *)(x))) - -#ifndef CONFIG_MXC_UART_BASE -#error "define CONFIG_MXC_UART_BASE to use the MXC UART driver" -#endif - -#define UART_PHYS CONFIG_MXC_UART_BASE - -/* Register definitions */ -#define URXD 0x0 /* Receiver Register */ -#define UTXD 0x40 /* Transmitter Register */ -#define UCR1 0x80 /* Control Register 1 */ -#define UCR2 0x84 /* Control Register 2 */ -#define UCR3 0x88 /* Control Register 3 */ -#define UCR4 0x8c /* Control Register 4 */ -#define UFCR 0x90 /* FIFO Control Register */ -#define USR1 0x94 /* Status Register 1 */ -#define USR2 0x98 /* Status Register 2 */ -#define UESC 0x9c /* Escape Character Register */ -#define UTIM 0xa0 /* Escape Timer Register */ -#define UBIR 0xa4 /* BRM Incremental Register */ -#define UBMR 0xa8 /* BRM Modulator Register */ -#define UBRC 0xac /* Baud Rate Count Register */ -#define UTS 0xb4 /* UART Test Register (mx31) */ - /* UART Control Register Bit Fields.*/ #define URXD_CHARRDY (1<<15) #define URXD_ERR (1<<14) @@ -128,6 +106,33 @@ #define UTS_RXFULL (1<<3) /* RxFIFO full */ #define UTS_SOFTRST (1<<0) /* Software reset */ +#ifndef CONFIG_DM_SERIAL + +#ifndef CONFIG_MXC_UART_BASE +#error "define CONFIG_MXC_UART_BASE to use the MXC UART driver" +#endif + +#define UART_PHYS CONFIG_MXC_UART_BASE + +#define __REG(x) (*((volatile u32 *)(x))) + +/* Register definitions */ +#define URXD 0x0 /* Receiver Register */ +#define UTXD 0x40 /* Transmitter Register */ +#define UCR1 0x80 /* Control Register 1 */ +#define UCR2 0x84 /* Control Register 2 */ +#define UCR3 0x88 /* Control Register 3 */ +#define UCR4 0x8c /* Control Register 4 */ +#define UFCR 0x90 /* FIFO Control Register */ +#define USR1 0x94 /* Status Register 1 */ +#define USR2 0x98 /* Status Register 2 */ +#define UESC 0x9c /* Escape Character Register */ +#define UTIM 0xa0 /* Escape Timer Register */ +#define UBIR 0xa4 /* BRM Incremental Register */ +#define UBMR 0xa8 /* BRM Modulator Register */ +#define UBRC 0xac /* Baud Rate Count Register */ +#define UTS 0xb4 /* UART Test Register (mx31) */ + DECLARE_GLOBAL_DATA_PTR; static void mxc_serial_setbrg(void) @@ -222,3 +227,118 @@ __weak struct serial_device *default_serial_console(void) { return &mxc_serial_drv; } +#endif + +#ifdef CONFIG_DM_SERIAL + +struct mxc_uart { + u32 rxd; + u32 spare0[15]; + + u32 txd; + u32 spare1[15]; + + u32 cr1; + u32 cr2; + u32 cr3; + u32 cr4; + + u32 fcr; + u32 sr1; + u32 sr2; + u32 esc; + + u32 tim; + u32 bir; + u32 bmr; + u32 brc; + + u32 onems; + u32 ts; +}; + +int mxc_serial_setbrg(struct udevice *dev, int baudrate) +{ + struct mxc_serial_platdata *plat = dev->platdata; + struct mxc_uart *const uart = plat->reg; + u32 clk = imx_get_uartclk(); + + writel(4 << 7, &uart->fcr); /* divide input clock by 2 */ + writel(0xf, &uart->bir); + writel(clk / (2 * baudrate), &uart->bmr); + + writel(UCR2_WS | UCR2_IRTS | UCR2_RXEN | UCR2_TXEN | UCR2_SRST, + &uart->cr2); + writel(UCR1_UARTEN, &uart->cr1); + + return 0; +} + +static int mxc_serial_probe(struct udevice *dev) +{ + struct mxc_serial_platdata *plat = dev->platdata; + struct mxc_uart *const uart = plat->reg; + + writel(0, &uart->cr1); + writel(0, &uart->cr2); + while (!(readl(&uart->cr2) & UCR2_SRST)); + writel(0x704 | UCR3_ADNIMP, &uart->cr3); + writel(0x8000, &uart->cr4); + writel(0x2b, &uart->esc); + writel(0, &uart->tim); + writel(0, &uart->ts); + + return 0; +} + +static int mxc_serial_getc(struct udevice *dev) +{ + struct mxc_serial_platdata *plat = dev->platdata; + struct mxc_uart *const uart = plat->reg; + + if (readl(&uart->ts) & UTS_RXEMPTY) + return -EAGAIN; + + return readl(&uart->rxd) & URXD_RX_DATA; +} + +static int mxc_serial_putc(struct udevice *dev, const char ch) +{ + struct mxc_serial_platdata *plat = dev->platdata; + struct mxc_uart *const uart = plat->reg; + + if (!(readl(&uart->ts) & UTS_TXEMPTY)) + return -EAGAIN; + + writel(ch, &uart->txd); + + return 0; +} + +static int mxc_serial_pending(struct udevice *dev, bool input) +{ + struct mxc_serial_platdata *plat = dev->platdata; + struct mxc_uart *const uart = plat->reg; + uint32_t sr2 = readl(&uart->sr2); + + if (input) + return sr2 & USR2_RDR ? 1 : 0; + else + return sr2 & USR2_TXDC ? 0 : 1; +} + +static const struct dm_serial_ops mxc_serial_ops = { + .putc = mxc_serial_putc, + .pending = mxc_serial_pending, + .getc = mxc_serial_getc, + .setbrg = mxc_serial_setbrg, +}; + +U_BOOT_DRIVER(serial_mxc) = { + .name = "serial_mxc", + .id = UCLASS_SERIAL, + .probe = mxc_serial_probe, + .ops = &mxc_serial_ops, + .flags = DM_FLAG_PRE_RELOC, +}; +#endif diff --git a/drivers/serial/serial_ns16550.c b/drivers/serial/serial_ns16550.c index 632da4c..799ef6a 100644 --- a/drivers/serial/serial_ns16550.c +++ b/drivers/serial/serial_ns16550.c @@ -119,8 +119,7 @@ static NS16550_t serial_ports[6] = { .puts = eserial##port##_puts, \ } -void -_serial_putc(const char c,const int port) +static void _serial_putc(const char c, const int port) { if (c == '\n') NS16550_putc(PORT, '\r'); @@ -128,35 +127,29 @@ _serial_putc(const char c,const int port) NS16550_putc(PORT, c); } -void -_serial_putc_raw(const char c,const int port) +static void _serial_putc_raw(const char c, const int port) { NS16550_putc(PORT, c); } -void -_serial_puts (const char *s,const int port) +static void _serial_puts(const char *s, const int port) { while (*s) { - _serial_putc (*s++,port); + _serial_putc(*s++, port); } } - -int -_serial_getc(const int port) +static int _serial_getc(const int port) { return NS16550_getc(PORT); } -int -_serial_tstc(const int port) +static int _serial_tstc(const int port) { return NS16550_tstc(PORT); } -void -_serial_setbrg (const int port) +static void _serial_setbrg(const int port) { int clock_divisor; diff --git a/drivers/serial/serial_omap.c b/drivers/serial/serial_omap.c new file mode 100644 index 0000000..265fe00 --- /dev/null +++ b/drivers/serial/serial_omap.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2014 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <fdtdec.h> +#include <ns16550.h> +#include <serial.h> + +DECLARE_GLOBAL_DATA_PTR; + +#ifdef CONFIG_OF_CONTROL +static const struct udevice_id omap_serial_ids[] = { + { .compatible = "ti,omap3-uart" }, + { } +}; + +static int omap_serial_ofdata_to_platdata(struct udevice *dev) +{ + struct ns16550_platdata *plat = dev_get_platdata(dev); + int ret; + + ret = ns16550_serial_ofdata_to_platdata(dev); + if (ret) + return ret; + plat->clock = fdtdec_get_int(gd->fdt_blob, dev->of_offset, + "clock-frequency", -1); + plat->reg_shift = 2; + + return 0; +} +#endif + +U_BOOT_DRIVER(serial_omap_ns16550) = { + .name = "serial_omap", + .id = UCLASS_SERIAL, + .of_match = of_match_ptr(omap_serial_ids), + .ofdata_to_platdata = of_match_ptr(omap_serial_ofdata_to_platdata), + .platdata_auto_alloc_size = sizeof(struct ns16550_platdata), + .priv_auto_alloc_size = sizeof(struct NS16550), + .probe = ns16550_serial_probe, + .ops = &ns16550_serial_ops, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/serial/serial_pl01x.c b/drivers/serial/serial_pl01x.c index dfb610e..38dda91 100644 --- a/drivers/serial/serial_pl01x.c +++ b/drivers/serial/serial_pl01x.c @@ -12,125 +12,90 @@ /* Simple U-Boot driver for the PrimeCell PL010/PL011 UARTs */ #include <common.h> +#include <dm.h> +#include <errno.h> #include <watchdog.h> #include <asm/io.h> #include <serial.h> +#include <dm/platform_data/serial_pl01x.h> #include <linux/compiler.h> -#include "serial_pl01x.h" +#include "serial_pl01x_internal.h" + +#ifndef CONFIG_DM_SERIAL -/* - * Integrator AP has two UARTs, we use the first one, at 38400-8-N-1 - * Integrator CP has two UARTs, use the first one, at 38400-8-N-1 - * Versatile PB has four UARTs. - */ -#define CONSOLE_PORT CONFIG_CONS_INDEX static volatile unsigned char *const port[] = CONFIG_PL01x_PORTS; +static enum pl01x_type pl01x_type __attribute__ ((section(".data"))); +static struct pl01x_regs *base_regs __attribute__ ((section(".data"))); #define NUM_PORTS (sizeof(port)/sizeof(port[0])) -static void pl01x_putc (int portnum, char c); -static int pl01x_getc (int portnum); -static int pl01x_tstc (int portnum); -unsigned int baudrate = CONFIG_BAUDRATE; DECLARE_GLOBAL_DATA_PTR; +#endif -static struct pl01x_regs *pl01x_get_regs(int portnum) -{ - return (struct pl01x_regs *) port[portnum]; -} - -#ifdef CONFIG_PL010_SERIAL - -static int pl01x_serial_init(void) +static int pl01x_putc(struct pl01x_regs *regs, char c) { - struct pl01x_regs *regs = pl01x_get_regs(CONSOLE_PORT); - unsigned int divisor; - - /* First, disable everything */ - writel(0, ®s->pl010_cr); + /* Wait until there is space in the FIFO */ + if (readl(®s->fr) & UART_PL01x_FR_TXFF) + return -EAGAIN; - /* Set baud rate */ - switch (baudrate) { - case 9600: - divisor = UART_PL010_BAUD_9600; - break; + /* Send the character */ + writel(c, ®s->dr); - case 19200: - divisor = UART_PL010_BAUD_9600; - break; + return 0; +} - case 38400: - divisor = UART_PL010_BAUD_38400; - break; +static int pl01x_getc(struct pl01x_regs *regs) +{ + unsigned int data; - case 57600: - divisor = UART_PL010_BAUD_57600; - break; + /* Wait until there is data in the FIFO */ + if (readl(®s->fr) & UART_PL01x_FR_RXFE) + return -EAGAIN; - case 115200: - divisor = UART_PL010_BAUD_115200; - break; + data = readl(®s->dr); - default: - divisor = UART_PL010_BAUD_38400; + /* Check for an error flag */ + if (data & 0xFFFFFF00) { + /* Clear the error */ + writel(0xFFFFFFFF, ®s->ecr); + return -1; } - writel((divisor & 0xf00) >> 8, ®s->pl010_lcrm); - writel(divisor & 0xff, ®s->pl010_lcrl); - - /* Set the UART to be 8 bits, 1 stop bit, no parity, fifo enabled */ - writel(UART_PL010_LCRH_WLEN_8 | UART_PL010_LCRH_FEN, ®s->pl010_lcrh); - - /* Finally, enable the UART */ - writel(UART_PL010_CR_UARTEN, ®s->pl010_cr); - - return 0; + return (int) data; } -#endif /* CONFIG_PL010_SERIAL */ - -#ifdef CONFIG_PL011_SERIAL +static int pl01x_tstc(struct pl01x_regs *regs) +{ + WATCHDOG_RESET(); + return !(readl(®s->fr) & UART_PL01x_FR_RXFE); +} -static int pl01x_serial_init(void) +static int pl01x_generic_serial_init(struct pl01x_regs *regs, + enum pl01x_type type) { - struct pl01x_regs *regs = pl01x_get_regs(CONSOLE_PORT); - unsigned int temp; - unsigned int divider; - unsigned int remainder; - unsigned int fraction; unsigned int lcr; #ifdef CONFIG_PL011_SERIAL_FLUSH_ON_INIT - /* Empty RX fifo if necessary */ - if (readl(®s->pl011_cr) & UART_PL011_CR_UARTEN) { - while (!(readl(®s->fr) & UART_PL01x_FR_RXFE)) - readl(®s->dr); + if (type == TYPE_PL011) { + /* Empty RX fifo if necessary */ + if (readl(®s->pl011_cr) & UART_PL011_CR_UARTEN) { + while (!(readl(®s->fr) & UART_PL01x_FR_RXFE)) + readl(®s->dr); + } } #endif /* First, disable everything */ - writel(0, ®s->pl011_cr); - - /* - * Set baud rate - * - * IBRD = UART_CLK / (16 * BAUD_RATE) - * FBRD = RND((64 * MOD(UART_CLK,(16 * BAUD_RATE))) / (16 * BAUD_RATE)) - */ - temp = 16 * baudrate; - divider = CONFIG_PL011_CLOCK / temp; - remainder = CONFIG_PL011_CLOCK % temp; - temp = (8 * remainder) / baudrate; - fraction = (temp >> 1) + (temp & 1); - - writel(divider, ®s->pl011_ibrd); - writel(fraction, ®s->pl011_fbrd); + writel(0, ®s->pl010_cr); /* Set the UART to be 8 bits, 1 stop bit, no parity, fifo enabled */ lcr = UART_PL011_LCRH_WLEN_8 | UART_PL011_LCRH_FEN; writel(lcr, ®s->pl011_lcrh); + switch (type) { + case TYPE_PL010: + break; + case TYPE_PL011: { #ifdef CONFIG_PL011_SERIAL_RLCR - { int i; /* @@ -144,90 +109,151 @@ static int pl01x_serial_init(void) writel(lcr, ®s->pl011_rlcr); /* lcrh needs to be set again for change to be effective */ writel(lcr, ®s->pl011_lcrh); - } #endif - /* Finally, enable the UART */ - writel(UART_PL011_CR_UARTEN | UART_PL011_CR_TXE | UART_PL011_CR_RXE | - UART_PL011_CR_RTS, ®s->pl011_cr); + break; + } + default: + return -EINVAL; + } return 0; } -#endif /* CONFIG_PL011_SERIAL */ - -static void pl01x_serial_putc(const char c) +static int pl01x_generic_setbrg(struct pl01x_regs *regs, enum pl01x_type type, + int clock, int baudrate) { - if (c == '\n') - pl01x_putc (CONSOLE_PORT, '\r'); + switch (type) { + case TYPE_PL010: { + unsigned int divisor; + + switch (baudrate) { + case 9600: + divisor = UART_PL010_BAUD_9600; + break; + case 19200: + divisor = UART_PL010_BAUD_9600; + break; + case 38400: + divisor = UART_PL010_BAUD_38400; + break; + case 57600: + divisor = UART_PL010_BAUD_57600; + break; + case 115200: + divisor = UART_PL010_BAUD_115200; + break; + default: + divisor = UART_PL010_BAUD_38400; + } + + writel((divisor & 0xf00) >> 8, ®s->pl010_lcrm); + writel(divisor & 0xff, ®s->pl010_lcrl); + + /* Finally, enable the UART */ + writel(UART_PL010_CR_UARTEN, ®s->pl010_cr); + break; + } + case TYPE_PL011: { + unsigned int temp; + unsigned int divider; + unsigned int remainder; + unsigned int fraction; - pl01x_putc (CONSOLE_PORT, c); -} + /* + * Set baud rate + * + * IBRD = UART_CLK / (16 * BAUD_RATE) + * FBRD = RND((64 * MOD(UART_CLK,(16 * BAUD_RATE))) + * / (16 * BAUD_RATE)) + */ + temp = 16 * baudrate; + divider = clock / temp; + remainder = clock % temp; + temp = (8 * remainder) / baudrate; + fraction = (temp >> 1) + (temp & 1); + + writel(divider, ®s->pl011_ibrd); + writel(fraction, ®s->pl011_fbrd); + + /* Finally, enable the UART */ + writel(UART_PL011_CR_UARTEN | UART_PL011_CR_TXE | + UART_PL011_CR_RXE | UART_PL011_CR_RTS, ®s->pl011_cr); + break; + } + default: + return -EINVAL; + } -static int pl01x_serial_getc(void) -{ - return pl01x_getc (CONSOLE_PORT); + return 0; } -static int pl01x_serial_tstc(void) +#ifndef CONFIG_DM_SERIAL +static void pl01x_serial_init_baud(int baudrate) { - return pl01x_tstc (CONSOLE_PORT); + int clock = 0; + +#if defined(CONFIG_PL010_SERIAL) + pl01x_type = TYPE_PL010; +#elif defined(CONFIG_PL011_SERIAL) + pl01x_type = TYPE_PL011; + clock = CONFIG_PL011_CLOCK; +#endif + base_regs = (struct pl01x_regs *)port[CONFIG_CONS_INDEX]; + + pl01x_generic_serial_init(base_regs, pl01x_type); + pl01x_generic_setbrg(base_regs, TYPE_PL010, clock, baudrate); } -static void pl01x_serial_setbrg(void) +/* + * Integrator AP has two UARTs, we use the first one, at 38400-8-N-1 + * Integrator CP has two UARTs, use the first one, at 38400-8-N-1 + * Versatile PB has four UARTs. + */ +int pl01x_serial_init(void) { - struct pl01x_regs *regs = pl01x_get_regs(CONSOLE_PORT); + pl01x_serial_init_baud(CONFIG_BAUDRATE); - baudrate = gd->baudrate; - /* - * Flush FIFO and wait for non-busy before changing baudrate to avoid - * crap in console - */ - while (!(readl(®s->fr) & UART_PL01x_FR_TXFE)) - WATCHDOG_RESET(); - while (readl(®s->fr) & UART_PL01x_FR_BUSY) - WATCHDOG_RESET(); - serial_init(); + return 0; } -static void pl01x_putc (int portnum, char c) +static void pl01x_serial_putc(const char c) { - struct pl01x_regs *regs = pl01x_get_regs(portnum); - - /* Wait until there is space in the FIFO */ - while (readl(®s->fr) & UART_PL01x_FR_TXFF) - WATCHDOG_RESET(); + if (c == '\n') + while (pl01x_putc(base_regs, '\r') == -EAGAIN); - /* Send the character */ - writel(c, ®s->dr); + while (pl01x_putc(base_regs, c) == -EAGAIN); } -static int pl01x_getc (int portnum) +static int pl01x_serial_getc(void) { - struct pl01x_regs *regs = pl01x_get_regs(portnum); - unsigned int data; + while (1) { + int ch = pl01x_getc(base_regs); - /* Wait until there is data in the FIFO */ - while (readl(®s->fr) & UART_PL01x_FR_RXFE) - WATCHDOG_RESET(); - - data = readl(®s->dr); + if (ch == -EAGAIN) { + WATCHDOG_RESET(); + continue; + } - /* Check for an error flag */ - if (data & 0xFFFFFF00) { - /* Clear the error */ - writel(0xFFFFFFFF, ®s->ecr); - return -1; + return ch; } - - return (int) data; } -static int pl01x_tstc (int portnum) +static int pl01x_serial_tstc(void) { - struct pl01x_regs *regs = pl01x_get_regs(portnum); + return pl01x_tstc(base_regs); +} - WATCHDOG_RESET(); - return !(readl(®s->fr) & UART_PL01x_FR_RXFE); +static void pl01x_serial_setbrg(void) +{ + /* + * Flush FIFO and wait for non-busy before changing baudrate to avoid + * crap in console + */ + while (!(readl(&base_regs->fr) & UART_PL01x_FR_TXFE)) + WATCHDOG_RESET(); + while (readl(&base_regs->fr) & UART_PL01x_FR_BUSY) + WATCHDOG_RESET(); + pl01x_serial_init_baud(gd->baudrate); } static struct serial_device pl01x_serial_drv = { @@ -250,3 +276,74 @@ __weak struct serial_device *default_serial_console(void) { return &pl01x_serial_drv; } + +#endif /* nCONFIG_DM_SERIAL */ + +#ifdef CONFIG_DM_SERIAL + +struct pl01x_priv { + struct pl01x_regs *regs; + enum pl01x_type type; +}; + +static int pl01x_serial_setbrg(struct udevice *dev, int baudrate) +{ + struct pl01x_serial_platdata *plat = dev_get_platdata(dev); + struct pl01x_priv *priv = dev_get_priv(dev); + + pl01x_generic_setbrg(priv->regs, priv->type, plat->clock, baudrate); + + return 0; +} + +static int pl01x_serial_probe(struct udevice *dev) +{ + struct pl01x_serial_platdata *plat = dev_get_platdata(dev); + struct pl01x_priv *priv = dev_get_priv(dev); + + priv->regs = (struct pl01x_regs *)plat->base; + priv->type = plat->type; + return pl01x_generic_serial_init(priv->regs, priv->type); +} + +static int pl01x_serial_getc(struct udevice *dev) +{ + struct pl01x_priv *priv = dev_get_priv(dev); + + return pl01x_getc(priv->regs); +} + +static int pl01x_serial_putc(struct udevice *dev, const char ch) +{ + struct pl01x_priv *priv = dev_get_priv(dev); + + return pl01x_putc(priv->regs, ch); +} + +static int pl01x_serial_pending(struct udevice *dev, bool input) +{ + struct pl01x_priv *priv = dev_get_priv(dev); + unsigned int fr = readl(&priv->regs->fr); + + if (input) + return pl01x_tstc(priv->regs); + else + return fr & UART_PL01x_FR_TXFF ? 0 : 1; +} + +static const struct dm_serial_ops pl01x_serial_ops = { + .putc = pl01x_serial_putc, + .pending = pl01x_serial_pending, + .getc = pl01x_serial_getc, + .setbrg = pl01x_serial_setbrg, +}; + +U_BOOT_DRIVER(serial_pl01x) = { + .name = "serial_pl01x", + .id = UCLASS_SERIAL, + .probe = pl01x_serial_probe, + .ops = &pl01x_serial_ops, + .flags = DM_FLAG_PRE_RELOC, +}; + +#endif diff --git a/drivers/serial/serial_pl01x.h b/drivers/serial/serial_pl01x_internal.h index 288a4f1..288a4f1 100644 --- a/drivers/serial/serial_pl01x.h +++ b/drivers/serial/serial_pl01x_internal.h diff --git a/drivers/serial/serial_s3c24x0.c b/drivers/serial/serial_s3c24x0.c index c07f4c9..7afc504 100644 --- a/drivers/serial/serial_s3c24x0.c +++ b/drivers/serial/serial_s3c24x0.c @@ -69,7 +69,7 @@ DECLARE_GLOBAL_DATA_PTR; static int hwflow; #endif -void _serial_setbrg(const int dev_index) +static void _serial_setbrg(const int dev_index) { struct s3c24x0_uart *uart = s3c24x0_get_base_uart(dev_index); unsigned int reg = 0; @@ -131,7 +131,7 @@ static int serial_init_dev(const int dev_index) * otherwise. When the function is succesfull, the character read is * written into its argument c. */ -int _serial_getc(const int dev_index) +static int _serial_getc(const int dev_index) { struct s3c24x0_uart *uart = s3c24x0_get_base_uart(dev_index); @@ -181,7 +181,7 @@ void enable_putc(void) /* * Output a single byte to the serial port. */ -void _serial_putc(const char c, const int dev_index) +static void _serial_putc(const char c, const int dev_index) { struct s3c24x0_uart *uart = s3c24x0_get_base_uart(dev_index); #ifdef CONFIG_MODEM_SUPPORT @@ -212,7 +212,7 @@ static inline void serial_putc_dev(unsigned int dev_index, const char c) /* * Test whether a character is in the RX buffer */ -int _serial_tstc(const int dev_index) +static int _serial_tstc(const int dev_index) { struct s3c24x0_uart *uart = s3c24x0_get_base_uart(dev_index); @@ -224,7 +224,7 @@ static inline int serial_tstc_dev(unsigned int dev_index) return _serial_tstc(dev_index); } -void _serial_puts(const char *s, const int dev_index) +static void _serial_puts(const char *s, const int dev_index) { while (*s) { _serial_putc(*s++, dev_index); diff --git a/drivers/serial/serial_s5p.c b/drivers/serial/serial_s5p.c index 98c62b4..8469afd 100644 --- a/drivers/serial/serial_s5p.c +++ b/drivers/serial/serial_s5p.c @@ -9,6 +9,8 @@ */ #include <common.h> +#include <dm.h> +#include <errno.h> #include <fdtdec.h> #include <linux/compiler.h> #include <asm/io.h> @@ -18,26 +20,18 @@ DECLARE_GLOBAL_DATA_PTR; -#define RX_FIFO_COUNT_MASK 0xff -#define RX_FIFO_FULL_MASK (1 << 8) -#define TX_FIFO_FULL_MASK (1 << 24) +#define RX_FIFO_COUNT_SHIFT 0 +#define RX_FIFO_COUNT_MASK (0xff << RX_FIFO_COUNT_SHIFT) +#define RX_FIFO_FULL (1 << 8) +#define TX_FIFO_COUNT_SHIFT 16 +#define TX_FIFO_COUNT_MASK (0xff << TX_FIFO_COUNT_SHIFT) +#define TX_FIFO_FULL (1 << 24) /* Information about a serial port */ -struct fdt_serial { - u32 base_addr; /* address of registers in physical memory */ +struct s5p_serial_platdata { + struct s5p_uart *reg; /* address of registers in physical memory */ u8 port_id; /* uart port number */ - u8 enabled; /* 1 if enabled, 0 if disabled */ -} config __attribute__ ((section(".data"))); - -static inline struct s5p_uart *s5p_get_base_uart(int dev_index) -{ -#ifdef CONFIG_OF_CONTROL - return (struct s5p_uart *)(config.base_addr); -#else - u32 offset = dev_index * sizeof(struct s5p_uart); - return (struct s5p_uart *)(samsung_get_base_uart() + offset); -#endif -} +}; /* * The coefficient, used to calculate the baudrate on S5P UARTs is @@ -65,23 +59,13 @@ static const int udivslot[] = { 0xffdf, }; -static void serial_setbrg_dev(const int dev_index) +int s5p_serial_setbrg(struct udevice *dev, int baudrate) { - struct s5p_uart *const uart = s5p_get_base_uart(dev_index); - u32 uclk = get_uart_clk(dev_index); - u32 baudrate = gd->baudrate; + struct s5p_serial_platdata *plat = dev->platdata; + struct s5p_uart *const uart = plat->reg; + u32 uclk = get_uart_clk(plat->port_id); u32 val; -#if defined(CONFIG_SILENT_CONSOLE) && \ - defined(CONFIG_OF_CONTROL) && \ - !defined(CONFIG_SPL_BUILD) - if (fdtdec_get_config_int(gd->fdt_blob, "silent_console", 0)) - gd->flags |= GD_FLG_SILENT; -#endif - - if (!config.enabled) - return; - val = uclk / baudrate; writel(val / 16 - 1, &uart->ubrdiv); @@ -90,15 +74,14 @@ static void serial_setbrg_dev(const int dev_index) writew(udivslot[val % 16], &uart->rest.slot); else writeb(val % 16, &uart->rest.value); + + return 0; } -/* - * Initialise the serial port with the given baudrate. The settings - * are always 8 data bits, no parity, 1 stop bit, no start bits. - */ -static int serial_init_dev(const int dev_index) +static int s5p_serial_probe(struct udevice *dev) { - struct s5p_uart *const uart = s5p_get_base_uart(dev_index); + struct s5p_serial_platdata *plat = dev->platdata; + struct s5p_uart *const uart = plat->reg; /* enable FIFOs, auto clear Rx FIFO */ writel(0x3, &uart->ufcon); @@ -108,14 +91,11 @@ static int serial_init_dev(const int dev_index) /* No interrupts, no DMA, pure polling */ writel(0x245, &uart->ucon); - serial_setbrg_dev(dev_index); - return 0; } -static int serial_err_check(const int dev_index, int op) +static int serial_err_check(const struct s5p_uart *const uart, int op) { - struct s5p_uart *const uart = s5p_get_base_uart(dev_index); unsigned int mask; /* @@ -133,169 +113,78 @@ static int serial_err_check(const int dev_index, int op) return readl(&uart->uerstat) & mask; } -/* - * Read a single byte from the serial port. Returns 1 on success, 0 - * otherwise. When the function is succesfull, the character read is - * written into its argument c. - */ -static int serial_getc_dev(const int dev_index) +static int s5p_serial_getc(struct udevice *dev) { - struct s5p_uart *const uart = s5p_get_base_uart(dev_index); - - if (!config.enabled) - return 0; + struct s5p_serial_platdata *plat = dev->platdata; + struct s5p_uart *const uart = plat->reg; - /* wait for character to arrive */ - while (!(readl(&uart->ufstat) & (RX_FIFO_COUNT_MASK | - RX_FIFO_FULL_MASK))) { - if (serial_err_check(dev_index, 0)) - return 0; - } + if (!(readl(&uart->ufstat) & RX_FIFO_COUNT_MASK)) + return -EAGAIN; + serial_err_check(uart, 0); return (int)(readb(&uart->urxh) & 0xff); } -/* - * Output a single byte to the serial port. - */ -static void serial_putc_dev(const char c, const int dev_index) +static int s5p_serial_putc(struct udevice *dev, const char ch) { - struct s5p_uart *const uart = s5p_get_base_uart(dev_index); - - if (!config.enabled) - return; - - /* wait for room in the tx FIFO */ - while ((readl(&uart->ufstat) & TX_FIFO_FULL_MASK)) { - if (serial_err_check(dev_index, 1)) - return; - } + struct s5p_serial_platdata *plat = dev->platdata; + struct s5p_uart *const uart = plat->reg; - writeb(c, &uart->utxh); + if (readl(&uart->ufstat) & TX_FIFO_FULL) + return -EAGAIN; - /* If \n, also do \r */ - if (c == '\n') - serial_putc('\r'); -} - -/* - * Test whether a character is in the RX buffer - */ -static int serial_tstc_dev(const int dev_index) -{ - struct s5p_uart *const uart = s5p_get_base_uart(dev_index); + writeb(ch, &uart->utxh); + serial_err_check(uart, 1); - if (!config.enabled) - return 0; - - return (int)(readl(&uart->utrstat) & 0x1); + return 0; } -static void serial_puts_dev(const char *s, const int dev_index) +static int s5p_serial_pending(struct udevice *dev, bool input) { - while (*s) - serial_putc_dev(*s++, dev_index); -} + struct s5p_serial_platdata *plat = dev->platdata; + struct s5p_uart *const uart = plat->reg; + uint32_t ufstat = readl(&uart->ufstat); -/* Multi serial device functions */ -#define DECLARE_S5P_SERIAL_FUNCTIONS(port) \ -static int s5p_serial##port##_init(void) { return serial_init_dev(port); } \ -static void s5p_serial##port##_setbrg(void) { serial_setbrg_dev(port); } \ -static int s5p_serial##port##_getc(void) { return serial_getc_dev(port); } \ -static int s5p_serial##port##_tstc(void) { return serial_tstc_dev(port); } \ -static void s5p_serial##port##_putc(const char c) { serial_putc_dev(c, port); } \ -static void s5p_serial##port##_puts(const char *s) { serial_puts_dev(s, port); } - -#define INIT_S5P_SERIAL_STRUCTURE(port, __name) { \ - .name = __name, \ - .start = s5p_serial##port##_init, \ - .stop = NULL, \ - .setbrg = s5p_serial##port##_setbrg, \ - .getc = s5p_serial##port##_getc, \ - .tstc = s5p_serial##port##_tstc, \ - .putc = s5p_serial##port##_putc, \ - .puts = s5p_serial##port##_puts, \ + if (input) + return (ufstat & RX_FIFO_COUNT_MASK) >> RX_FIFO_COUNT_SHIFT; + else + return (ufstat & TX_FIFO_COUNT_MASK) >> TX_FIFO_COUNT_SHIFT; } -DECLARE_S5P_SERIAL_FUNCTIONS(0); -struct serial_device s5p_serial0_device = - INIT_S5P_SERIAL_STRUCTURE(0, "s5pser0"); -DECLARE_S5P_SERIAL_FUNCTIONS(1); -struct serial_device s5p_serial1_device = - INIT_S5P_SERIAL_STRUCTURE(1, "s5pser1"); -DECLARE_S5P_SERIAL_FUNCTIONS(2); -struct serial_device s5p_serial2_device = - INIT_S5P_SERIAL_STRUCTURE(2, "s5pser2"); -DECLARE_S5P_SERIAL_FUNCTIONS(3); -struct serial_device s5p_serial3_device = - INIT_S5P_SERIAL_STRUCTURE(3, "s5pser3"); - -#ifdef CONFIG_OF_CONTROL -int fdtdec_decode_console(int *index, struct fdt_serial *uart) +static int s5p_serial_ofdata_to_platdata(struct udevice *dev) { - const void *blob = gd->fdt_blob; - int node; + struct s5p_serial_platdata *plat = dev->platdata; + fdt_addr_t addr; - node = fdt_path_offset(blob, "console"); - if (node < 0) - return node; + addr = fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg"); + if (addr == FDT_ADDR_T_NONE) + return -EINVAL; - uart->base_addr = fdtdec_get_addr(blob, node, "reg"); - if (uart->base_addr == FDT_ADDR_T_NONE) - return -FDT_ERR_NOTFOUND; - - uart->port_id = fdtdec_get_int(blob, node, "id", -1); - uart->enabled = fdtdec_get_is_enabled(blob, node); + plat->reg = (struct s5p_uart *)addr; + plat->port_id = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "id", -1); return 0; } -#endif -__weak struct serial_device *default_serial_console(void) -{ -#ifdef CONFIG_OF_CONTROL - int index = 0; - - if ((!config.base_addr) && (fdtdec_decode_console(&index, &config))) { - debug("Cannot decode default console node\n"); - return NULL; - } - - switch (config.port_id) { - case 0: - return &s5p_serial0_device; - case 1: - return &s5p_serial1_device; - case 2: - return &s5p_serial2_device; - case 3: - return &s5p_serial3_device; - default: - debug("Unknown config.port_id: %d", config.port_id); - break; - } - - return NULL; -#else - config.enabled = 1; -#if defined(CONFIG_SERIAL0) - return &s5p_serial0_device; -#elif defined(CONFIG_SERIAL1) - return &s5p_serial1_device; -#elif defined(CONFIG_SERIAL2) - return &s5p_serial2_device; -#elif defined(CONFIG_SERIAL3) - return &s5p_serial3_device; -#else -#error "CONFIG_SERIAL? missing." -#endif -#endif -} +static const struct dm_serial_ops s5p_serial_ops = { + .putc = s5p_serial_putc, + .pending = s5p_serial_pending, + .getc = s5p_serial_getc, + .setbrg = s5p_serial_setbrg, +}; -void s5p_serial_initialize(void) -{ - serial_register(&s5p_serial0_device); - serial_register(&s5p_serial1_device); - serial_register(&s5p_serial2_device); - serial_register(&s5p_serial3_device); -} +static const struct udevice_id s5p_serial_ids[] = { + { .compatible = "samsung,exynos4210-uart" }, + { } +}; + +U_BOOT_DRIVER(serial_s5p) = { + .name = "serial_s5p", + .id = UCLASS_SERIAL, + .of_match = s5p_serial_ids, + .ofdata_to_platdata = s5p_serial_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct s5p_serial_platdata), + .probe = s5p_serial_probe, + .ops = &s5p_serial_ops, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/serial/serial_sh.c b/drivers/serial/serial_sh.c index 144a925..7c1f271 100644 --- a/drivers/serial/serial_sh.c +++ b/drivers/serial/serial_sh.c @@ -122,7 +122,7 @@ static void handle_error(void) sci_out(&sh_sci, SCLSR, 0x00); } -void serial_raw_putc(const char c) +static void serial_raw_putc(const char c) { while (1) { /* Tx fifo is empty */ @@ -152,7 +152,7 @@ static int sh_serial_tstc(void) } -int serial_getc_check(void) +static int serial_getc_check(void) { unsigned short status; diff --git a/drivers/serial/serial_uniphier.c b/drivers/serial/serial_uniphier.c index f8c9d92..9114b3e 100644 --- a/drivers/serial/serial_uniphier.c +++ b/drivers/serial/serial_uniphier.c @@ -2,14 +2,14 @@ * Copyright (C) 2012-2014 Panasonic Corporation * Author: Masahiro Yamada <yamada.m@jp.panasonic.com> * - * Based on serial_ns16550.c - * (C) Copyright 2000 - * Rob Taylor, Flying Pig Systems. robt@flyingpig.com. - * * SPDX-License-Identifier: GPL-2.0+ */ #include <common.h> +#include <asm/io.h> +#include <asm/errno.h> +#include <dm/device.h> +#include <dm/platform_data/serial-uniphier.h> #include <serial.h> #define UART_REG(x) \ @@ -48,157 +48,104 @@ struct uniphier_serial { #define UART_LSR_DR 0x01 /* Data ready */ #define UART_LSR_THRE 0x20 /* Xmit holding register empty */ -DECLARE_GLOBAL_DATA_PTR; +struct uniphier_serial_private_data { + struct uniphier_serial __iomem *membase; +}; + +#define uniphier_serial_port(dev) \ + ((struct uniphier_serial_private_data *)dev_get_priv(dev))->membase -static void uniphier_serial_init(struct uniphier_serial *port) +int uniphier_serial_setbrg(struct udevice *dev, int baudrate) { + struct uniphier_serial_platform_data *plat = dev_get_platdata(dev); + struct uniphier_serial __iomem *port = uniphier_serial_port(dev); const unsigned int mode_x_div = 16; unsigned int divisor; writeb(UART_LCR_WLS_8, &port->lcr); - divisor = DIV_ROUND_CLOSEST(CONFIG_SYS_UNIPHIER_UART_CLK, - mode_x_div * gd->baudrate); + divisor = DIV_ROUND_CLOSEST(plat->uartclk, mode_x_div * baudrate); writew(divisor, &port->dlr); -} -static void uniphier_serial_setbrg(struct uniphier_serial *port) -{ - uniphier_serial_init(port); + return 0; } -static int uniphier_serial_tstc(struct uniphier_serial *port) +static int uniphier_serial_getc(struct udevice *dev) { - return (readb(&port->lsr) & UART_LSR_DR) != 0; -} + struct uniphier_serial __iomem *port = uniphier_serial_port(dev); -static int uniphier_serial_getc(struct uniphier_serial *port) -{ - while (!uniphier_serial_tstc(port)) - ; + if (!(readb(&port->lsr) & UART_LSR_DR)) + return -EAGAIN; return readb(&port->rbr); } -static void uniphier_serial_putc(struct uniphier_serial *port, const char c) +static int uniphier_serial_putc(struct udevice *dev, const char c) { - if (c == '\n') - uniphier_serial_putc(port, '\r'); + struct uniphier_serial __iomem *port = uniphier_serial_port(dev); - while (!(readb(&port->lsr) & UART_LSR_THRE)) - ; + if (!(readb(&port->lsr) & UART_LSR_THRE)) + return -EAGAIN; writeb(c, &port->thr); + + return 0; } -static struct uniphier_serial *serial_ports[4] = { -#ifdef CONFIG_SYS_UNIPHIER_SERIAL_BASE0 - (struct uniphier_serial *)CONFIG_SYS_UNIPHIER_SERIAL_BASE0, -#else - NULL, -#endif -#ifdef CONFIG_SYS_UNIPHIER_SERIAL_BASE1 - (struct uniphier_serial *)CONFIG_SYS_UNIPHIER_SERIAL_BASE1, -#else - NULL, -#endif -#ifdef CONFIG_SYS_UNIPHIER_SERIAL_BASE2 - (struct uniphier_serial *)CONFIG_SYS_UNIPHIER_SERIAL_BASE2, -#else - NULL, -#endif -#ifdef CONFIG_SYS_UNIPHIER_SERIAL_BASE3 - (struct uniphier_serial *)CONFIG_SYS_UNIPHIER_SERIAL_BASE3, -#else - NULL, -#endif -}; +int uniphier_serial_probe(struct udevice *dev) +{ + struct uniphier_serial_private_data *priv = dev_get_priv(dev); + struct uniphier_serial_platform_data *plat = dev_get_platdata(dev); -/* Multi serial device functions */ -#define DECLARE_ESERIAL_FUNCTIONS(port) \ - static int eserial##port##_init(void) \ - { \ - uniphier_serial_init(serial_ports[port]); \ - return 0 ; \ - } \ - static void eserial##port##_setbrg(void) \ - { \ - uniphier_serial_setbrg(serial_ports[port]); \ - } \ - static int eserial##port##_getc(void) \ - { \ - return uniphier_serial_getc(serial_ports[port]); \ - } \ - static int eserial##port##_tstc(void) \ - { \ - return uniphier_serial_tstc(serial_ports[port]); \ - } \ - static void eserial##port##_putc(const char c) \ - { \ - uniphier_serial_putc(serial_ports[port], c); \ - } - -/* Serial device descriptor */ -#define INIT_ESERIAL_STRUCTURE(port, __name) { \ - .name = __name, \ - .start = eserial##port##_init, \ - .stop = NULL, \ - .setbrg = eserial##port##_setbrg, \ - .getc = eserial##port##_getc, \ - .tstc = eserial##port##_tstc, \ - .putc = eserial##port##_putc, \ - .puts = default_serial_puts, \ -} + priv->membase = map_sysmem(plat->base, sizeof(struct uniphier_serial)); -#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE0) -DECLARE_ESERIAL_FUNCTIONS(0); -struct serial_device uniphier_serial0_device = - INIT_ESERIAL_STRUCTURE(0, "ttyS0"); -#endif -#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE1) -DECLARE_ESERIAL_FUNCTIONS(1); -struct serial_device uniphier_serial1_device = - INIT_ESERIAL_STRUCTURE(1, "ttyS1"); -#endif -#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE2) -DECLARE_ESERIAL_FUNCTIONS(2); -struct serial_device uniphier_serial2_device = - INIT_ESERIAL_STRUCTURE(2, "ttyS2"); -#endif -#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE3) -DECLARE_ESERIAL_FUNCTIONS(3); -struct serial_device uniphier_serial3_device = - INIT_ESERIAL_STRUCTURE(3, "ttyS3"); -#endif + if (!priv->membase) + return -ENOMEM; -__weak struct serial_device *default_serial_console(void) + return 0; +} + +int uniphier_serial_remove(struct udevice *dev) { -#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE0) - return &uniphier_serial0_device; -#elif defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE1) - return &uniphier_serial1_device; -#elif defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE2) - return &uniphier_serial2_device; -#elif defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE3) - return &uniphier_serial3_device; -#else -#error "No uniphier serial ports configured." -#endif + unmap_sysmem(uniphier_serial_port(dev)); + + return 0; } -void uniphier_serial_initialize(void) +#ifdef CONFIG_OF_CONTROL +static const struct udevice_id uniphier_uart_of_match = { + { .compatible = "panasonic,uniphier-uart"}, + {}, +}; + +static int uniphier_serial_ofdata_to_platdata(struct udevice *dev) { -#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE0) - serial_register(&uniphier_serial0_device); -#endif -#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE1) - serial_register(&uniphier_serial1_device); -#endif -#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE2) - serial_register(&uniphier_serial2_device); -#endif -#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE3) - serial_register(&uniphier_serial3_device); -#endif + /* + * TODO: Masahiro Yamada (yamada.m@jp.panasonic.com) + * + * Implement conversion code from DTB to platform data + * when supporting CONFIG_OF_CONTROL on UniPhir platform. + */ } +#endif + +static const struct dm_serial_ops uniphier_serial_ops = { + .setbrg = uniphier_serial_setbrg, + .getc = uniphier_serial_getc, + .putc = uniphier_serial_putc, +}; + +U_BOOT_DRIVER(uniphier_serial) = { + .name = DRIVER_NAME, + .id = UCLASS_SERIAL, + .of_match = of_match_ptr(uniphier_uart_of_match), + .ofdata_to_platdata = of_match_ptr(uniphier_serial_ofdata_to_platdata), + .probe = uniphier_serial_probe, + .remove = uniphier_serial_remove, + .priv_auto_alloc_size = sizeof(struct uniphier_serial_private_data), + .platdata_auto_alloc_size = + sizeof(struct uniphier_serial_platform_data), + .ops = &uniphier_serial_ops, + .flags = DM_FLAG_PRE_RELOC, +}; |