X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=drivers%2Fserial%2Fserial_uniphier.c;h=74547eb692b19eedfbe9de2aabb30aafaebe3595;hb=122d805fd4bd478bb83536348291d34ae648364b;hp=f8c9d921e283028c5fe199efa7b081bbfc08d09f;hpb=3cc83f9d08a80fddf4c1e8e766eff8273f30814c;p=u-boot diff --git a/drivers/serial/serial_uniphier.c b/drivers/serial/serial_uniphier.c index f8c9d921e2..74547eb692 100644 --- a/drivers/serial/serial_uniphier.c +++ b/drivers/serial/serial_uniphier.c @@ -1,204 +1,156 @@ /* - * Copyright (C) 2012-2014 Panasonic Corporation - * Author: Masahiro Yamada - * - * Based on serial_ns16550.c - * (C) Copyright 2000 - * Rob Taylor, Flying Pig Systems. robt@flyingpig.com. + * Copyright (C) 2012-2015 Panasonic Corporation + * Copyright (C) 2015 Socionext Inc. + * Author: Masahiro Yamada * * SPDX-License-Identifier: GPL-2.0+ */ -#include +#include +#include +#include +#include +#include +#include #include - -#define UART_REG(x) \ - u8 x; \ - u8 postpad_##x[3]; +#include /* * Note: Register map is slightly different from that of 16550. */ struct uniphier_serial { - UART_REG(rbr); /* 0x00 */ - UART_REG(ier); /* 0x04 */ - UART_REG(iir); /* 0x08 */ - UART_REG(fcr); /* 0x0c */ - u8 mcr; /* 0x10 */ - u8 lcr; - u16 __postpad; - UART_REG(lsr); /* 0x14 */ - UART_REG(msr); /* 0x18 */ - u32 __none1; - u32 __none2; - u16 dlr; - u16 __postpad2; + u32 rx; /* In: Receive buffer */ +#define tx rx /* Out: Transmit buffer */ + u32 ier; /* Interrupt Enable Register */ + u32 iir; /* In: Interrupt ID Register */ + u32 char_fcr; /* Charactor / FIFO Control Register */ + u32 lcr_mcr; /* Line/Modem Control Register */ +#define LCR_SHIFT 8 +#define LCR_MASK (0xff << (LCR_SHIFT)) + u32 lsr; /* In: Line Status Register */ + u32 msr; /* In: Modem Status Register */ + u32 __rsv0; + u32 __rsv1; + u32 dlr; /* Divisor Latch Register */ }; -#define thr rbr - -/* - * These are the definitions for the Line Control Register - */ -#define UART_LCR_WLS_8 0x03 /* 8 bit character length */ - -/* - * These are the definitions for the Line Status Register - */ -#define UART_LSR_DR 0x01 /* Data ready */ -#define UART_LSR_THRE 0x20 /* Xmit holding register empty */ +struct uniphier_serial_private_data { + struct uniphier_serial __iomem *membase; +}; -DECLARE_GLOBAL_DATA_PTR; +#define uniphier_serial_port(dev) \ + ((struct uniphier_serial_private_data *)dev_get_priv(dev))->membase -static void uniphier_serial_init(struct uniphier_serial *port) +static 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(plat->uartclk, mode_x_div * baudrate); - divisor = DIV_ROUND_CLOSEST(CONFIG_SYS_UNIPHIER_UART_CLK, - mode_x_div * gd->baudrate); + writel(divisor, &port->dlr); - writew(divisor, &port->dlr); + return 0; } -static void uniphier_serial_setbrg(struct uniphier_serial *port) +static int uniphier_serial_getc(struct udevice *dev) { - uniphier_serial_init(port); + struct uniphier_serial __iomem *port = uniphier_serial_port(dev); + + if (!(readl(&port->lsr) & UART_LSR_DR)) + return -EAGAIN; + + return readl(&port->rx); } -static int uniphier_serial_tstc(struct uniphier_serial *port) +static int uniphier_serial_putc(struct udevice *dev, const char c) { - return (readb(&port->lsr) & UART_LSR_DR) != 0; + struct uniphier_serial __iomem *port = uniphier_serial_port(dev); + + if (!(readl(&port->lsr) & UART_LSR_THRE)) + return -EAGAIN; + + writel(c, &port->tx); + + return 0; } -static int uniphier_serial_getc(struct uniphier_serial *port) +static int uniphier_serial_pending(struct udevice *dev, bool input) { - while (!uniphier_serial_tstc(port)) - ; + struct uniphier_serial __iomem *port = uniphier_serial_port(dev); - return readb(&port->rbr); + if (input) + return readl(&port->lsr) & UART_LSR_DR; + else + return !(readl(&port->lsr) & UART_LSR_THRE); } -static void uniphier_serial_putc(struct uniphier_serial *port, const char c) +static int uniphier_serial_probe(struct udevice *dev) { - if (c == '\n') - uniphier_serial_putc(port, '\r'); + u32 tmp; + struct uniphier_serial_private_data *priv = dev_get_priv(dev); + struct uniphier_serial_platform_data *plat = dev_get_platdata(dev); + struct uniphier_serial __iomem *port; - while (!(readb(&port->lsr) & UART_LSR_THRE)) - ; + port = map_sysmem(plat->base, sizeof(struct uniphier_serial)); + if (!port) + return -ENOMEM; - writeb(c, &port->thr); -} + priv->membase = port; -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 -}; + tmp = readl(&port->lcr_mcr); + tmp &= ~LCR_MASK; + tmp |= UART_LCR_WLEN8 << LCR_SHIFT; + writel(tmp, &port->lcr_mcr); -/* 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, \ + return 0; } -#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 - -__weak struct serial_device *default_serial_console(void) +static 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 = "socionext,uniphier-uart" }, + { /* sentinel */ } +}; + +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 + struct uniphier_serial_platform_data *plat = dev_get_platdata(dev); + DECLARE_GLOBAL_DATA_PTR; + + plat->base = fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg"); + plat->uartclk = fdtdec_get_int(gd->fdt_blob, dev->of_offset, + "clock-frequency", 0); + + return 0; } +#endif + +static const struct dm_serial_ops uniphier_serial_ops = { + .setbrg = uniphier_serial_setbrg, + .getc = uniphier_serial_getc, + .putc = uniphier_serial_putc, + .pending = uniphier_serial_pending, +}; + +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, +};