diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/serial/serial_uniphier.c | 199 |
1 files changed, 73 insertions, 126 deletions
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, +}; |