diff options
Diffstat (limited to 'drivers/serial/serial_sh.c')
-rw-r--r-- | drivers/serial/serial_sh.c | 321 |
1 files changed, 219 insertions, 102 deletions
diff --git a/drivers/serial/serial_sh.c b/drivers/serial/serial_sh.c index 7c1f271376..3641c9f834 100644 --- a/drivers/serial/serial_sh.c +++ b/drivers/serial/serial_sh.c @@ -1,78 +1,21 @@ /* * SuperH SCIF device driver. * Copyright (C) 2013 Renesas Electronics Corporation - * Copyright (C) 2007,2008,2010 Nobuhiro Iwamatsu + * Copyright (C) 2007,2008,2010, 2014 Nobuhiro Iwamatsu * Copyright (C) 2002 - 2008 Paul Mundt * * SPDX-License-Identifier: GPL-2.0+ */ #include <common.h> +#include <errno.h> +#include <dm.h> #include <asm/io.h> #include <asm/processor.h> -#include "serial_sh.h" #include <serial.h> #include <linux/compiler.h> - -#if defined(CONFIG_CONS_SCIF0) -# define SCIF_BASE SCIF0_BASE -#elif defined(CONFIG_CONS_SCIF1) -# define SCIF_BASE SCIF1_BASE -#elif defined(CONFIG_CONS_SCIF2) -# define SCIF_BASE SCIF2_BASE -#elif defined(CONFIG_CONS_SCIF3) -# define SCIF_BASE SCIF3_BASE -#elif defined(CONFIG_CONS_SCIF4) -# define SCIF_BASE SCIF4_BASE -#elif defined(CONFIG_CONS_SCIF5) -# define SCIF_BASE SCIF5_BASE -#elif defined(CONFIG_CONS_SCIF6) -# define SCIF_BASE SCIF6_BASE -#elif defined(CONFIG_CONS_SCIF7) -# define SCIF_BASE SCIF7_BASE -#else -# error "Default SCIF doesn't set....." -#endif - -#if defined(CONFIG_SCIF_A) - #define SCIF_BASE_PORT PORT_SCIFA -#else - #define SCIF_BASE_PORT PORT_SCIF -#endif - -static struct uart_port sh_sci = { - .membase = (unsigned char*)SCIF_BASE, - .mapbase = SCIF_BASE, - .type = SCIF_BASE_PORT, -}; - -static void sh_serial_setbrg(void) -{ - DECLARE_GLOBAL_DATA_PTR; -#ifdef CONFIG_SCIF_USE_EXT_CLK - unsigned short dl = DL_VALUE(gd->baudrate, CONFIG_SH_SCIF_CLK_FREQ); - sci_out(&sh_sci, DL, dl); - /* Need wait: Clock * 1/dl × 1/16 */ - udelay((1000000 * dl * 16 / CONFIG_SYS_CLK_FREQ) * 1000 + 1); -#else - sci_out(&sh_sci, SCBRR, - SCBRR_VALUE(gd->baudrate, CONFIG_SH_SCIF_CLK_FREQ)); -#endif -} - -static int sh_serial_init(void) -{ - sci_out(&sh_sci, SCSCR , SCSCR_INIT(&sh_sci)); - sci_out(&sh_sci, SCSCR , SCSCR_INIT(&sh_sci)); - sci_out(&sh_sci, SCSMR, 0); - sci_out(&sh_sci, SCSMR, 0); - sci_out(&sh_sci, SCFCR, SCFCR_RFRST|SCFCR_TFRST); - sci_in(&sh_sci, SCFCR); - sci_out(&sh_sci, SCFCR, 0); - - serial_setbrg(); - return 0; -} +#include <dm/platform_data/serial_sh.h> +#include "serial_sh.h" #if defined(CONFIG_CPU_SH7760) || \ defined(CONFIG_CPU_SH7780) || \ @@ -86,7 +29,7 @@ static int scif_rxfill(struct uart_port *port) static int scif_rxfill(struct uart_port *port) { if ((port->mapbase == 0xffe00000) || - (port->mapbase == 0xffe08000)) { + (port->mapbase == 0xffe08000)) { /* SCIF0/1*/ return sci_in(port, SCRFDR) & 0xff; } else { @@ -109,80 +52,253 @@ static int scif_rxfill(struct uart_port *port) } #endif -static int serial_rx_fifo_level(void) +static void sh_serial_init_generic(struct uart_port *port) { - return scif_rxfill(&sh_sci); + sci_out(port, SCSCR , SCSCR_INIT(port)); + sci_out(port, SCSCR , SCSCR_INIT(port)); + sci_out(port, SCSMR, 0); + sci_out(port, SCSMR, 0); + sci_out(port, SCFCR, SCFCR_RFRST|SCFCR_TFRST); + sci_in(port, SCFCR); + sci_out(port, SCFCR, 0); } -static void handle_error(void) +static void +sh_serial_setbrg_generic(struct uart_port *port, int clk, int baudrate) { - sci_in(&sh_sci, SCxSR); - sci_out(&sh_sci, SCxSR, SCxSR_ERROR_CLEAR(&sh_sci)); - sci_in(&sh_sci, SCLSR); - sci_out(&sh_sci, SCLSR, 0x00); + if (port->clk_mode == EXT_CLK) { + unsigned short dl = DL_VALUE(baudrate, clk); + sci_out(port, DL, dl); + /* Need wait: Clock * 1/dl × 1/16 */ + udelay((1000000 * dl * 16 / clk) * 1000 + 1); + } else { + sci_out(port, SCBRR, SCBRR_VALUE(baudrate, clk)); + } } -static void serial_raw_putc(const char c) +static void handle_error(struct uart_port *port) { - while (1) { - /* Tx fifo is empty */ - if (sci_in(&sh_sci, SCxSR) & SCxSR_TEND(&sh_sci)) - break; - } + sci_in(port, SCxSR); + sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port)); + sci_in(port, SCLSR); + sci_out(port, SCLSR, 0x00); +} + +static int serial_raw_putc(struct uart_port *port, const char c) +{ + /* Tx fifo is empty */ + if (!(sci_in(port, SCxSR) & SCxSR_TEND(port))) + return -EAGAIN; - sci_out(&sh_sci, SCxTDR, c); - sci_out(&sh_sci, SCxSR, sci_in(&sh_sci, SCxSR) & ~SCxSR_TEND(&sh_sci)); + sci_out(port, SCxTDR, c); + sci_out(port, SCxSR, sci_in(port, SCxSR) & ~SCxSR_TEND(port)); + + return 0; } -static void sh_serial_putc(const char c) +static int serial_rx_fifo_level(struct uart_port *port) { - if (c == '\n') - serial_raw_putc('\r'); - serial_raw_putc(c); + return scif_rxfill(port); } -static int sh_serial_tstc(void) +static int sh_serial_tstc_generic(struct uart_port *port) { - if (sci_in(&sh_sci, SCxSR) & SCIF_ERRORS) { - handle_error(); + if (sci_in(port, SCxSR) & SCIF_ERRORS) { + handle_error(port); return 0; } - return serial_rx_fifo_level() ? 1 : 0; + return serial_rx_fifo_level(port) ? 1 : 0; } - -static int serial_getc_check(void) +static int serial_getc_check(struct uart_port *port) { unsigned short status; - status = sci_in(&sh_sci, SCxSR); + status = sci_in(port, SCxSR); if (status & SCIF_ERRORS) - handle_error(); - if (sci_in(&sh_sci, SCLSR) & SCxSR_ORER(&sh_sci)) - handle_error(); - return status & (SCIF_DR | SCxSR_RDxF(&sh_sci)); + handle_error(port); + if (sci_in(port, SCLSR) & SCxSR_ORER(port)) + handle_error(port); + return status & (SCIF_DR | SCxSR_RDxF(port)); } -static int sh_serial_getc(void) +static int sh_serial_getc_generic(struct uart_port *port) { unsigned short status; char ch; - while (!serial_getc_check()) - ; + if (!serial_getc_check(port)) + return -EAGAIN; - ch = sci_in(&sh_sci, SCxRDR); - status = sci_in(&sh_sci, SCxSR); + ch = sci_in(port, SCxRDR); + status = sci_in(port, SCxSR); - sci_out(&sh_sci, SCxSR, SCxSR_RDxF_CLEAR(&sh_sci)); + sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); if (status & SCIF_ERRORS) - handle_error(); + handle_error(port); + + if (sci_in(port, SCLSR) & SCxSR_ORER(port)) + handle_error(port); + + return ch; +} + +#ifdef CONFIG_DM_SERIAL + +static int sh_serial_pending(struct udevice *dev, bool input) +{ + struct uart_port *priv = dev_get_priv(dev); + + return sh_serial_tstc_generic(priv); +} + +static int sh_serial_putc(struct udevice *dev, const char ch) +{ + struct uart_port *priv = dev_get_priv(dev); + + return serial_raw_putc(priv, ch); +} + +static int sh_serial_getc(struct udevice *dev) +{ + struct uart_port *priv = dev_get_priv(dev); + + return sh_serial_getc_generic(priv); +} + +static int sh_serial_setbrg(struct udevice *dev, int baudrate) +{ + struct sh_serial_platdata *plat = dev_get_platdata(dev); + struct uart_port *priv = dev_get_priv(dev); + + sh_serial_setbrg_generic(priv, plat->clk, baudrate); + + return 0; +} + +static int sh_serial_probe(struct udevice *dev) +{ + struct sh_serial_platdata *plat = dev_get_platdata(dev); + struct uart_port *priv = dev_get_priv(dev); + + priv->membase = (unsigned char *)plat->base; + priv->mapbase = plat->base; + priv->type = plat->type; + priv->clk_mode = plat->clk_mode; + + sh_serial_init_generic(priv); + + return 0; +} + +static const struct dm_serial_ops sh_serial_ops = { + .putc = sh_serial_putc, + .pending = sh_serial_pending, + .getc = sh_serial_getc, + .setbrg = sh_serial_setbrg, +}; + +U_BOOT_DRIVER(serial_sh) = { + .name = "serial_sh", + .id = UCLASS_SERIAL, + .probe = sh_serial_probe, + .ops = &sh_serial_ops, + .flags = DM_FLAG_PRE_RELOC, + .priv_auto_alloc_size = sizeof(struct uart_port), +}; + +#else /* CONFIG_DM_SERIAL */ + +#if defined(CONFIG_CONS_SCIF0) +# define SCIF_BASE SCIF0_BASE +#elif defined(CONFIG_CONS_SCIF1) +# define SCIF_BASE SCIF1_BASE +#elif defined(CONFIG_CONS_SCIF2) +# define SCIF_BASE SCIF2_BASE +#elif defined(CONFIG_CONS_SCIF3) +# define SCIF_BASE SCIF3_BASE +#elif defined(CONFIG_CONS_SCIF4) +# define SCIF_BASE SCIF4_BASE +#elif defined(CONFIG_CONS_SCIF5) +# define SCIF_BASE SCIF5_BASE +#elif defined(CONFIG_CONS_SCIF6) +# define SCIF_BASE SCIF6_BASE +#elif defined(CONFIG_CONS_SCIF7) +# define SCIF_BASE SCIF7_BASE +#else +# error "Default SCIF doesn't set....." +#endif + +#if defined(CONFIG_SCIF_A) + #define SCIF_BASE_PORT PORT_SCIFA +#else + #define SCIF_BASE_PORT PORT_SCIF +#endif + +static struct uart_port sh_sci = { + .membase = (unsigned char *)SCIF_BASE, + .mapbase = SCIF_BASE, + .type = SCIF_BASE_PORT, +#ifdef CONFIG_SCIF_USE_EXT_CLK + .clk_mode = EXT_CLK, +#endif +}; + +static void sh_serial_setbrg(void) +{ + DECLARE_GLOBAL_DATA_PTR; + struct uart_port *port = &sh_sci; + + sh_serial_setbrg_generic(port, CONFIG_SH_SCIF_CLK_FREQ, gd->baudrate); +} + +static int sh_serial_init(void) +{ + struct uart_port *port = &sh_sci; + + sh_serial_init_generic(port); + serial_setbrg(); + + return 0; +} + +static void sh_serial_putc(const char c) +{ + struct uart_port *port = &sh_sci; + + if (c == '\n') { + while (1) { + if (serial_raw_putc(port, '\r') != -EAGAIN) + break; + } + } + while (1) { + if (serial_raw_putc(port, c) != -EAGAIN) + break; + } +} + +static int sh_serial_tstc(void) +{ + struct uart_port *port = &sh_sci; + + return sh_serial_tstc_generic(port); +} + +static int sh_serial_getc(void) +{ + struct uart_port *port = &sh_sci; + int ch; + + while (1) { + ch = sh_serial_getc_generic(port); + if (ch != -EAGAIN) + break; + } - if (sci_in(&sh_sci, SCLSR) & SCxSR_ORER(&sh_sci)) - handle_error(); return ch; } @@ -206,3 +322,4 @@ __weak struct serial_device *default_serial_console(void) { return &sh_serial_drv; } +#endif /* CONFIG_DM_SERIAL */ |