X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=drivers%2Fserial%2Fserial_sh.c;h=5f45d58e5800bc0bd79af480ecb754b5bb2c76db;hb=c05ed00afb95fa5237f16962fccf5810437317bf;hp=ff2cdc58472c8c8c918e5037f79fc6da3f040949;hpb=8b485ba12b0defa0c4ed3559789250238f8331a8;p=oweals%2Fu-boot.git diff --git a/drivers/serial/serial_sh.c b/drivers/serial/serial_sh.c index ff2cdc5847..5f45d58e58 100644 --- a/drivers/serial/serial_sh.c +++ b/drivers/serial/serial_sh.c @@ -1,17 +1,252 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * SuperH SCIF device driver. - * Copyright (C) 2007,2008,2010 Nobuhiro Iwamatsu + * Copyright (C) 2013 Renesas Electronics Corporation + * Copyright (C) 2007,2008,2010, 2014 Nobuhiro Iwamatsu * Copyright (C) 2002 - 2008 Paul Mundt - * - * SPDX-License-Identifier: GPL-2.0+ */ #include +#include +#include +#include #include #include -#include "serial_sh.h" #include #include +#include +#include +#include "serial_sh.h" + +DECLARE_GLOBAL_DATA_PTR; + +#if defined(CONFIG_CPU_SH7780) +static int scif_rxfill(struct uart_port *port) +{ + return sci_in(port, SCRFDR) & 0xff; +} +#elif defined(CONFIG_CPU_SH7763) +static int scif_rxfill(struct uart_port *port) +{ + if ((port->mapbase == 0xffe00000) || + (port->mapbase == 0xffe08000)) { + /* SCIF0/1*/ + return sci_in(port, SCRFDR) & 0xff; + } else { + /* SCIF2 */ + return sci_in(port, SCFDR) & SCIF2_RFDC_MASK; + } +} +#else +static int scif_rxfill(struct uart_port *port) +{ + return sci_in(port, SCFDR) & SCIF_RFDC_MASK; +} +#endif + +static void sh_serial_init_generic(struct uart_port *port) +{ + 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); +#if defined(CONFIG_RZA1) + sci_out(port, SCSPTR, 0x0003); +#endif +} + +static void +sh_serial_setbrg_generic(struct uart_port *port, int clk, int baudrate) +{ + 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 handle_error(struct uart_port *port) +{ + 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(port, SCxTDR, c); + sci_out(port, SCxSR, sci_in(port, SCxSR) & ~SCxSR_TEND(port)); + + return 0; +} + +static int serial_rx_fifo_level(struct uart_port *port) +{ + return scif_rxfill(port); +} + +static int sh_serial_tstc_generic(struct uart_port *port) +{ + if (sci_in(port, SCxSR) & SCIF_ERRORS) { + handle_error(port); + return 0; + } + + return serial_rx_fifo_level(port) ? 1 : 0; +} + +static int serial_getc_check(struct uart_port *port) +{ + unsigned short status; + + status = sci_in(port, SCxSR); + + if (status & SCIF_ERRORS) + 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_generic(struct uart_port *port) +{ + unsigned short status; + char ch; + + if (!serial_getc_check(port)) + return -EAGAIN; + + ch = sci_in(port, SCxRDR); + status = sci_in(port, SCxSR); + + sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); + + if (status & SCIF_ERRORS) + handle_error(port); + + if (sci_in(port, SCLSR) & SCxSR_ORER(port)) + handle_error(port); + + return ch; +} + +#if CONFIG_IS_ENABLED(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, +}; + +#if CONFIG_IS_ENABLED(OF_CONTROL) +static const struct udevice_id sh_serial_id[] ={ + {.compatible = "renesas,sci", .data = PORT_SCI}, + {.compatible = "renesas,scif", .data = PORT_SCIF}, + {.compatible = "renesas,scifa", .data = PORT_SCIFA}, + {} +}; + +static int sh_serial_ofdata_to_platdata(struct udevice *dev) +{ + struct sh_serial_platdata *plat = dev_get_platdata(dev); + struct clk sh_serial_clk; + fdt_addr_t addr; + int ret; + + addr = devfdt_get_addr(dev); + if (!addr) + return -EINVAL; + + plat->base = addr; + + ret = clk_get_by_name(dev, "fck", &sh_serial_clk); + if (!ret) { + ret = clk_enable(&sh_serial_clk); + if (!ret) + plat->clk = clk_get_rate(&sh_serial_clk); + } else { + plat->clk = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), + "clock", 1); + } + + plat->type = dev_get_driver_data(dev); + return 0; +} +#endif + +U_BOOT_DRIVER(serial_sh) = { + .name = "serial_sh", + .id = UCLASS_SERIAL, + .of_match = of_match_ptr(sh_serial_id), + .ofdata_to_platdata = of_match_ptr(sh_serial_ofdata_to_platdata), + .platdata_auto_alloc_size = sizeof(struct sh_serial_platdata), + .probe = sh_serial_probe, + .ops = &sh_serial_ops, +#if !CONFIG_IS_ENABLED(OF_CONTROL) + .flags = DM_FLAG_PRE_RELOC, +#endif + .priv_auto_alloc_size = sizeof(struct uart_port), +}; + +#else /* CONFIG_DM_SERIAL */ #if defined(CONFIG_CONS_SCIF0) # define SCIF_BASE SCIF0_BASE @@ -29,151 +264,81 @@ # define SCIF_BASE SCIF6_BASE #elif defined(CONFIG_CONS_SCIF7) # define SCIF_BASE SCIF7_BASE +#elif defined(CONFIG_CONS_SCIFA0) +# define SCIF_BASE SCIFA0_BASE #else # error "Default SCIF doesn't set....." #endif #if defined(CONFIG_SCIF_A) #define SCIF_BASE_PORT PORT_SCIFA +#elif defined(CONFIG_SCI) + #define SCIF_BASE_PORT PORT_SCI #else #define SCIF_BASE_PORT PORT_SCIF #endif static struct uart_port sh_sci = { - .membase = (unsigned char*)SCIF_BASE, + .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; - sci_out(&sh_sci, SCBRR, SCBRR_VALUE(gd->baudrate, CONFIG_SYS_CLK_FREQ)); + struct uart_port *port = &sh_sci; + + sh_serial_setbrg_generic(port, CONFIG_SH_SCIF_CLK_FREQ, gd->baudrate); } 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); + struct uart_port *port = &sh_sci; + sh_serial_init_generic(port); serial_setbrg(); - return 0; -} - -#if defined(CONFIG_CPU_SH7760) || \ - defined(CONFIG_CPU_SH7780) || \ - defined(CONFIG_CPU_SH7785) || \ - defined(CONFIG_CPU_SH7786) -static int scif_rxfill(struct uart_port *port) -{ - return sci_in(port, SCRFDR) & 0xff; -} -#elif defined(CONFIG_CPU_SH7763) -static int scif_rxfill(struct uart_port *port) -{ - if ((port->mapbase == 0xffe00000) || - (port->mapbase == 0xffe08000)) { - /* SCIF0/1*/ - return sci_in(port, SCRFDR) & 0xff; - } else { - /* SCIF2 */ - return sci_in(port, SCFDR) & SCIF2_RFDC_MASK; - } -} -#elif defined(CONFIG_ARCH_SH7372) -static int scif_rxfill(struct uart_port *port) -{ - if (port->type == PORT_SCIFA) - return sci_in(port, SCFDR) & SCIF_RFDC_MASK; - else - return sci_in(port, SCRFDR); -} -#else -static int scif_rxfill(struct uart_port *port) -{ - return sci_in(port, SCFDR) & SCIF_RFDC_MASK; -} -#endif -static int serial_rx_fifo_level(void) -{ - return scif_rxfill(&sh_sci); + return 0; } -static void handle_error(void) +static void sh_serial_putc(const char c) { - 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); -} + struct uart_port *port = &sh_sci; -void serial_raw_putc(const char c) -{ + if (c == '\n') { + while (1) { + if (serial_raw_putc(port, '\r') != -EAGAIN) + break; + } + } while (1) { - /* Tx fifo is empty */ - if (sci_in(&sh_sci, SCxSR) & SCxSR_TEND(&sh_sci)) + if (serial_raw_putc(port, c) != -EAGAIN) break; } - - sci_out(&sh_sci, SCxTDR, c); - sci_out(&sh_sci, SCxSR, sci_in(&sh_sci, SCxSR) & ~SCxSR_TEND(&sh_sci)); -} - -static void sh_serial_putc(const char c) -{ - if (c == '\n') - serial_raw_putc('\r'); - serial_raw_putc(c); } static int sh_serial_tstc(void) { - if (sci_in(&sh_sci, SCxSR) & SCIF_ERRORS) { - handle_error(); - return 0; - } - - return serial_rx_fifo_level() ? 1 : 0; -} - - -int serial_getc_check(void) -{ - unsigned short status; + struct uart_port *port = &sh_sci; - status = sci_in(&sh_sci, 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)); + return sh_serial_tstc_generic(port); } static int sh_serial_getc(void) { - unsigned short status; - char ch; - - while (!serial_getc_check()) - ; - - ch = sci_in(&sh_sci, SCxRDR); - status = sci_in(&sh_sci, SCxSR); + struct uart_port *port = &sh_sci; + int ch; - sci_out(&sh_sci, SCxSR, SCxSR_RDxF_CLEAR(&sh_sci)); - - if (status & SCIF_ERRORS) - handle_error(); + 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; } @@ -197,3 +362,4 @@ __weak struct serial_device *default_serial_console(void) { return &sh_serial_drv; } +#endif /* CONFIG_DM_SERIAL */