/* * SuperH on-chip serial module support. (SCI with no FIFO / with FIFO) * * Copyright (C) 2002 - 2011 Paul Mundt * Modified to support SH7720 SCIF. Markus Brunner, Mark Jonas (Jul 2007). * * based off of the old drivers/char/sh-sci.c by: * * Copyright (C) 1999, 2000 Niibe Yutaka * Copyright (C) 2000 Sugioka Toshinobu * Modified to support multiple serial ports. Stuart Menefy (May 2000). * Modified to support SecureEdge. David McCullough (2002) * Modified to support SH7300 SCIF. Takashi Kusuda (Jun 2003). * Removed SH7300 support (Jul 2007). * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. */#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)#define SUPPORT_SYSRQ#endif #undef DEBUG #include <linux/module.h>#include <linux/errno.h>#include <linux/sh_dma.h>#include <linux/timer.h>#include <linux/interrupt.h>#include <linux/tty.h>#include <linux/tty_flip.h>#include <linux/serial.h>#include <linux/major.h>#include <linux/string.h>#include <linux/sysrq.h>#include <linux/ioport.h>#include <linux/mm.h>#include <linux/init.h>#include <linux/delay.h>#include <linux/console.h>#include <linux/platform_device.h>#include <linux/serial_sci.h>#include <linux/notifier.h>#include <linux/pm_runtime.h>#include <linux/cpufreq.h>#include <linux/clk.h>#include <linux/ctype.h>#include <linux/err.h>#include <linux/dmaengine.h>#include <linux/dma-mapping.h>#include <linux/scatterlist.h>#include <linux/slab.h>#include <linux/gpio.h> #ifdef CONFIG_SUPERH#include <asm/sh_bios.h>#endif #include "sh-sci.h" struct sci_port { struct uart_port port; /* Platform configuration */ struct plat_sci_port *cfg; /* Break timer */ struct timer_list break_timer; int break_flag; /* Interface clock */ struct clk *iclk; /* Function clock */ struct clk *fclk; char *irqstr[SCIx_NR_IRQS]; char *gpiostr[SCIx_NR_FNS]; struct dma_chan *chan_tx; struct dma_chan *chan_rx; #ifdef CONFIG_SERIAL_SH_SCI_DMA struct dma_async_tx_descriptor *desc_tx; struct dma_async_tx_descriptor *desc_rx[2]; dma_cookie_t cookie_tx; dma_cookie_t cookie_rx[2]; dma_cookie_t active_rx; struct scatterlist sg_tx; unsigned int sg_len_tx; struct scatterlist sg_rx[2]; size_t buf_len_rx; struct sh_dmae_slave param_tx; struct sh_dmae_slave param_rx; struct work_struct work_tx; struct work_struct work_rx; struct timer_list rx_timer; unsigned int rx_timeout;#endif struct notifier_block freq_transition;}; /* Function prototypes */static void sci_start_tx(struct uart_port *port);static void sci_stop_tx(struct uart_port *port);static void sci_start_rx(struct uart_port *port); #define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS static struct sci_port sci_ports[SCI_NPORTS];static struct uart_driver sci_uart_driver; static inline struct sci_port *to_sci_port(struct uart_port *uart){ return container_of(uart, struct sci_port, port);} struct plat_sci_reg { u8 offset, size;}; /* Helper for invalidating specific entries of an inherited map. */#define sci_reg_invalid { .offset = 0, .size = 0 } static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = { [SCIx_PROBE_REGTYPE] = { [0 ... SCIx_NR_REGS - 1] = sci_reg_invalid, }, /* * Common SCI definitions, dependent on the port's regshift * value. */ [SCIx_SCI_REGTYPE] = { [SCSMR] = { 0x00, 8 }, [SCBRR] = { 0x01, 8 }, [SCSCR] = { 0x02, 8 }, [SCxTDR] = { 0x03, 8 }, [SCxSR] = { 0x04, 8 }, [SCxRDR] = { 0x05, 8 }, [SCFCR] = sci_reg_invalid, [SCFDR] = sci_reg_invalid, [SCTFDR] = sci_reg_invalid, [SCRFDR] = sci_reg_invalid, [SCSPTR] = sci_reg_invalid, [SCLSR] = sci_reg_invalid, [HSSRR] = sci_reg_invalid, }, /* * Common definitions for legacy IrDA ports, dependent on * regshift value. */ [SCIx_IRDA_REGTYPE] = { [SCSMR] = { 0x00, 8 }, [SCBRR] = { 0x01, 8 }, [SCSCR] = { 0x02, 8 }, [SCxTDR] = { 0x03, 8 }, [SCxSR] = { 0x04, 8 }, [SCxRDR] = { 0x05, 8 }, [SCFCR] = { 0x06, 8 }, [SCFDR] = { 0x07, 16 }, [SCTFDR] = sci_reg_invalid, [SCRFDR] = sci_reg_invalid, [SCSPTR] = sci_reg_invalid, [SCLSR] = sci_reg_invalid, [HSSRR] = sci_reg_invalid, }, /* * Common SCIFA definitions. */ [SCIx_SCIFA_REGTYPE] = { [SCSMR] = { 0x00, 16 }, [SCBRR] = { 0x04, 8 }, [SCSCR] = { 0x08, 16 }, [SCxTDR] = { 0x20, 8 }, [SCxSR] = { 0x14, 16 }, [SCxRDR] = { 0x24, 8 }, [SCFCR] = { 0x18, 16 }, [SCFDR] = { 0x1c, 16 }, [SCTFDR] = sci_reg_invalid, [SCRFDR] = sci_reg_invalid, [SCSPTR] = sci_reg_invalid, [SCLSR] = sci_reg_invalid, [HSSRR] = sci_reg_invalid, }, /* * Common SCIFB definitions. */ [SCIx_SCIFB_REGTYPE] = { [SCSMR] = { 0x00, 16 }, [SCBRR] = { 0x04, 8 }, [SCSCR] = { 0x08, 16 }, [SCxTDR] = { 0x40, 8 }, [SCxSR] = { 0x14, 16 }, [SCxRDR] = { 0x60, 8 }, [SCFCR] = { 0x18, 16 }, [SCFDR] = sci_reg_invalid, [SCTFDR] = { 0x38, 16 }, [SCRFDR] = { 0x3c, 16 }, [SCSPTR] = sci_reg_invalid, [SCLSR] = sci_reg_invalid, [HSSRR] = sci_reg_invalid, }, /* * Common SH-2(A) SCIF definitions for ports with FIFO data * count registers. */ [SCIx_SH2_SCIF_FIFODATA_REGTYPE] = { [SCSMR] = { 0x00, 16 }, [SCBRR] = { 0x04, 8 }, [SCSCR] = { 0x08, 16 }, [SCxTDR] = { 0x0c, 8 }, [SCxSR] = { 0x10, 16 }, [SCxRDR] = { 0x14, 8 }, [SCFCR] = { 0x18, 16 }, [SCFDR] = { 0x1c, 16 }, [SCTFDR] = sci_reg_invalid, [SCRFDR] = sci_reg_invalid, [SCSPTR] = { 0x20, 16 }, [SCLSR] = { 0x24, 16 }, [HSSRR] = sci_reg_invalid, }, /* * Common SH-3 SCIF definitions. */ [SCIx_SH3_SCIF_REGTYPE] = { [SCSMR] = { 0x00, 8 }, [SCBRR] = { 0x02, 8 }, [SCSCR] = { 0x04, 8 }, [SCxTDR] = { 0x06, 8 }, [SCxSR] = { 0x08, 16 }, [SCxRDR] = { 0x0a, 8 }, [SCFCR] = { 0x0c, 8 }, [SCFDR] = { 0x0e, 16 }, [SCTFDR] = sci_reg_invalid, [SCRFDR] = sci_reg_invalid, [SCSPTR] = sci_reg_invalid, [SCLSR] = sci_reg_invalid, [HSSRR] = sci_reg_invalid, }, /* * Common SH-4(A) SCIF(B) definitions. */ [SCIx_SH4_SCIF_REGTYPE] = { [SCSMR] = { 0x00, 16 }, [SCBRR] = { 0x04, 8 }, [SCSCR] = { 0x08, 16 }, [SCxTDR] = { 0x0c, 8 }, [SCxSR] = { 0x10, 16 }, [SCxRDR] = { 0x14, 8 }, [SCFCR] = { 0x18, 16 }, [SCFDR] = { 0x1c, 16 }, [SCTFDR] = sci_reg_invalid, [SCRFDR] = sci_reg_invalid, [SCSPTR] = { 0x20, 16 }, [SCLSR] = { 0x24, 16 }, [HSSRR] = sci_reg_invalid, }, /* * Common HSCIF definitions. */ [SCIx_HSCIF_REGTYPE] = { [SCSMR] = { 0x00, 16 }, [SCBRR] = { 0x04, 8 }, [SCSCR] = { 0x08, 16 }, [SCxTDR] = { 0x0c, 8 }, [SCxSR] = { 0x10, 16 }, [SCxRDR] = { 0x14, 8 }, [SCFCR] = { 0x18, 16 }, [SCFDR] = { 0x1c, 16 }, [SCTFDR] = sci_reg_invalid, [SCRFDR] = sci_reg_invalid, [SCSPTR] = { 0x20, 16 }, [SCLSR] = { 0x24, 16 }, [HSSRR] = { 0x40, 16 }, }, /* * Common SH-4(A) SCIF(B) definitions for ports without an SCSPTR * register. */ [SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE] = { [SCSMR] = { 0x00, 16 }, [SCBRR] = { 0x04, 8 }, [SCSCR] = { 0x08, 16 }, [SCxTDR] = { 0x0c, 8 }, [SCxSR] = { 0x10, 16 }, [SCxRDR] = { 0x14, 8 }, [SCFCR] = { 0x18, 16 }, [SCFDR] = { 0x1c, 16 }, [SCTFDR] = sci_reg_invalid, [SCRFDR] = sci_reg_invalid, [SCSPTR] = sci_reg_invalid, [SCLSR] = { 0x24, 16 }, [HSSRR] = sci_reg_invalid, }, /* * Common SH-4(A) SCIF(B) definitions for ports with FIFO data * count registers. */ [SCIx_SH4_SCIF_FIFODATA_REGTYPE] = { [SCSMR] = { 0x00, 16 }, [SCBRR] = { 0x04, 8 }, [SCSCR] = { 0x08, 16 }, [SCxTDR] = { 0x0c, 8 }, [SCxSR] = { 0x10, 16 }, [SCxRDR] = { 0x14, 8 }, [SCFCR] = { 0x18, 16 }, [SCFDR] = { 0x1c, 16 }, [SCTFDR] = { 0x1c, 16 }, /* aliased to SCFDR */ [SCRFDR] = { 0x20, 16 }, [SCSPTR] = { 0x24, 16 }, [SCLSR] = { 0x28, 16 }, [HSSRR] = sci_reg_invalid, }, /* * SH7705-style SCIF(B) ports, lacking both SCSPTR and SCLSR * registers. */ [SCIx_SH7705_SCIF_REGTYPE] = { [SCSMR] = { 0x00, 16 }, [SCBRR] = { 0x04, 8 }, [SCSCR] = { 0x08, 16 }, [SCxTDR] = { 0x20, 8 }, [SCxSR] = { 0x14, 16 }, [SCxRDR] = { 0x24, 8 }, [SCFCR] = { 0x18, 16 }, [SCFDR] = { 0x1c, 16 }, [SCTFDR] = sci_reg_invalid, [SCRFDR] = sci_reg_invalid, [SCSPTR] = sci_reg_invalid, [SCLSR] = sci_reg_invalid, [HSSRR] = sci_reg_invalid, },}; #define sci_getreg(up, offset) (sci_regmap[to_sci_port(up)->cfg->regtype] + offset) /* * The "offset" here is rather misleading, in that it refers to an enum * value relative to the port mapping rather than the fixed offset * itself, which needs to be manually retrieved from the platform's * register map for the given port. */static unsigned int sci_serial_in(struct uart_port *p, int offset){ struct plat_sci_reg *reg = sci_getreg(p, offset); if (reg->size == 8) return ioread8(p->membase + (reg->offset << p->regshift)); else if (reg->size == 16) return ioread16(p->membase + (reg->offset << p->regshift)); else WARN(1, "Invalid register access\n"); return 0;} static void sci_serial_out(struct uart_port *p, int offset, int value){ struct plat_sci_reg *reg = sci_getreg(p, offset); if (reg->size == 8) iowrite8(value, p->membase + (reg->offset << p->regshift)); else if (reg->size == 16) iowrite16(value, p->membase + (reg->offset << p->regshift)); else WARN(1, "Invalid register access\n");} static int sci_probe_regmap(struct plat_sci_port *cfg){ switch (cfg->type) { case PORT_SCI: cfg->regtype = SCIx_SCI_REGTYPE; break; case PORT_IRDA: cfg->regtype = SCIx_IRDA_REGTYPE; break; case PORT_SCIFA: cfg->regtype = SCIx_SCIFA_REGTYPE; break; case PORT_SCIFB: cfg->regtype = SCIx_SCIFB_REGTYPE; break; case PORT_SCIF: /* * The SH-4 is a bit of a misnomer here, although that's * where this particular port layout originated. This * configuration (or some slight variation thereof) * remains the dominant model for all SCIFs. */ cfg->regtype = SCIx_SH4_SCIF_REGTYPE; break; case PORT_HSCIF: cfg->regtype = SCIx_HSCIF_REGTYPE; break; default: printk(KERN_ERR "Can't probe register map for given port\n"); return -EINVAL; } return 0;} static void sci_port_enable(struct sci_port *sci_port){ if (!sci_port->port.dev) return; pm_runtime_get_sync(sci_port->port.dev); clk_enable(sci_port->iclk); sci_port->port.uartclk = clk_get_rate(sci_port->iclk); clk_enable(sci_port->fclk);} static void sci_port_disable(struct sci_port *sci_port){ if (!sci_port->port.dev) return; clk_disable(sci_port->fclk); clk_disable(sci_port->iclk); pm_runtime_put_sync(sci_port->port.dev);} #if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_SH_SCI_CONSOLE) #ifdef CONFIG_CONSOLE_POLLstatic int sci_poll_get_char(struct uart_port *port){ unsigned short status; int c; do { status = serial_port_in(port, SCxSR); if (status & SCxSR_ERRORS(port)) { serial_port_out(port, SCxSR, SCxSR_ERROR_CLEAR(port)); continue; } break; } while (1); if (!(status & SCxSR_RDxF(port))) return NO_POLL_CHAR; c = serial_port_in(port, SCxRDR); /* Dummy read */ serial_port_in(port, SCxSR); serial_port_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); return c;}#endif static void sci_poll_put_char(struct uart_port *port, unsigned char c){ unsigned short status; do { status = serial_port_in(port, SCxSR); } while (!(status & SCxSR_TDxE(port))); serial_port_out(port, SCxTDR, c); serial_port_out(port, SCxSR, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port));}#endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE */ static void sci_init_pins(struct uart_port *port, unsigned int cflag){ struct sci_port *s = to_sci_port(port); struct plat_sci_reg *reg = sci_regmap[s->cfg->regtype] + SCSPTR; /* * Use port-specific handler if provided. */ if (s->cfg->ops && s->cfg->ops->init_pins) { s->cfg->ops->init_pins(port, cflag); return; } /* * For the generic path SCSPTR is necessary. Bail out if that's * unavailable, too. */ if (!reg->size)Lines 1–500 of 2573. Load more
/* * SuperH on-chip serial module support. (SCI with no FIFO / with FIFO) * * Copyright (C) 2002 - 2011 Paul Mundt * Modified to support SH7720 SCIF. Markus Brunner, Mark Jonas (Jul 2007). * * based off of the old drivers/char/sh-sci.c by: * * Copyright (C) 1999, 2000 Niibe Yutaka * Copyright (C) 2000 Sugioka Toshinobu * Modified to support multiple serial ports. Stuart Menefy (May 2000). * Modified to support SecureEdge. David McCullough (2002) * Modified to support SH7300 SCIF. Takashi Kusuda (Jun 2003). * Removed SH7300 support (Jul 2007). * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. */ #if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) #define SUPPORT_SYSRQ #endif #undef DEBUG #include <linux/module.h> #include <linux/errno.h> #include <linux/sh_dma.h> #include <linux/timer.h> #include <linux/interrupt.h> #include <linux/tty.h> #include <linux/tty_flip.h> #include <linux/serial.h> #include <linux/major.h> #include <linux/string.h> #include <linux/sysrq.h> #include <linux/ioport.h> #include <linux/mm.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/console.h> #include <linux/platform_device.h> #include <linux/serial_sci.h> #include <linux/notifier.h> #include <linux/pm_runtime.h> #include <linux/cpufreq.h> #include <linux/clk.h> #include <linux/ctype.h> #include <linux/err.h> #include <linux/dmaengine.h> #include <linux/dma-mapping.h> #include <linux/scatterlist.h> #include <linux/slab.h> #include <linux/gpio.h> #ifdef CONFIG_SUPERH #include <asm/sh_bios.h> #endif #include "sh-sci.h" struct sci_port { struct uart_port port; /* Platform configuration */ struct plat_sci_port *cfg; /* Break timer */ struct timer_list break_timer; int break_flag; /* Interface clock */ struct clk *iclk; /* Function clock */ struct clk *fclk; char *irqstr[SCIx_NR_IRQS]; char *gpiostr[SCIx_NR_FNS]; struct dma_chan *chan_tx; struct dma_chan *chan_rx; #ifdef CONFIG_SERIAL_SH_SCI_DMA struct dma_async_tx_descriptor *desc_tx; struct dma_async_tx_descriptor *desc_rx[2]; dma_cookie_t cookie_tx; dma_cookie_t cookie_rx[2]; dma_cookie_t active_rx; struct scatterlist sg_tx; unsigned int sg_len_tx; struct scatterlist sg_rx[2]; size_t buf_len_rx; struct sh_dmae_slave param_tx; struct sh_dmae_slave param_rx; struct work_struct work_tx; struct work_struct work_rx; struct timer_list rx_timer; unsigned int rx_timeout; #endif struct notifier_block freq_transition; }; /* Function prototypes */ static void sci_start_tx(struct uart_port *port); static void sci_stop_tx(struct uart_port *port); static void sci_start_rx(struct uart_port *port); #define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS static struct sci_port sci_ports[SCI_NPORTS]; static struct uart_driver sci_uart_driver; static inline struct sci_port * to_sci_port(struct uart_port *uart) { return container_of(uart, struct sci_port, port); } struct plat_sci_reg { u8 offset, size; }; /* Helper for invalidating specific entries of an inherited map. */ #define sci_reg_invalid { .offset = 0, .size = 0 } static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = { [SCIx_PROBE_REGTYPE] = { [0 ... SCIx_NR_REGS - 1] = sci_reg_invalid, }, /* * Common SCI definitions, dependent on the port's regshift * value. */ [SCIx_SCI_REGTYPE] = { [SCSMR] = { 0x00, 8 }, [SCBRR] = { 0x01, 8 }, [SCSCR] = { 0x02, 8 }, [SCxTDR] = { 0x03, 8 }, [SCxSR] = { 0x04, 8 }, [SCxRDR] = { 0x05, 8 }, [SCFCR] = sci_reg_invalid, [SCFDR] = sci_reg_invalid, [SCTFDR] = sci_reg_invalid, [SCRFDR] = sci_reg_invalid, [SCSPTR] = sci_reg_invalid, [SCLSR] = sci_reg_invalid, [HSSRR] = sci_reg_invalid, }, /* * Common definitions for legacy IrDA ports, dependent on * regshift value. */ [SCIx_IRDA_REGTYPE] = { [SCSMR] = { 0x00, 8 }, [SCBRR] = { 0x01, 8 }, [SCSCR] = { 0x02, 8 }, [SCxTDR] = { 0x03, 8 }, [SCxSR] = { 0x04, 8 }, [SCxRDR] = { 0x05, 8 }, [SCFCR] = { 0x06, 8 }, [SCFDR] = { 0x07, 16 }, [SCTFDR] = sci_reg_invalid, [SCRFDR] = sci_reg_invalid, [SCSPTR] = sci_reg_invalid, [SCLSR] = sci_reg_invalid, [HSSRR] = sci_reg_invalid, }, /* * Common SCIFA definitions. */ [SCIx_SCIFA_REGTYPE] = { [SCSMR] = { 0x00, 16 }, [SCBRR] = { 0x04, 8 }, [SCSCR] = { 0x08, 16 }, [SCxTDR] = { 0x20, 8 }, [SCxSR] = { 0x14, 16 }, [SCxRDR] = { 0x24, 8 }, [SCFCR] = { 0x18, 16 }, [SCFDR] = { 0x1c, 16 }, [SCTFDR] = sci_reg_invalid, [SCRFDR] = sci_reg_invalid, [SCSPTR] = sci_reg_invalid, [SCLSR] = sci_reg_invalid, [HSSRR] = sci_reg_invalid, }, /* * Common SCIFB definitions. */ [SCIx_SCIFB_REGTYPE] = { [SCSMR] = { 0x00, 16 }, [SCBRR] = { 0x04, 8 }, [SCSCR] = { 0x08, 16 }, [SCxTDR] = { 0x40, 8 }, [SCxSR] = { 0x14, 16 }, [SCxRDR] = { 0x60, 8 }, [SCFCR] = { 0x18, 16 }, [SCFDR] = sci_reg_invalid, [SCTFDR] = { 0x38, 16 }, [SCRFDR] = { 0x3c, 16 }, [SCSPTR] = sci_reg_invalid, [SCLSR] = sci_reg_invalid, [HSSRR] = sci_reg_invalid, }, /* * Common SH-2(A) SCIF definitions for ports with FIFO data * count registers. */ [SCIx_SH2_SCIF_FIFODATA_REGTYPE] = { [SCSMR] = { 0x00, 16 }, [SCBRR] = { 0x04, 8 }, [SCSCR] = { 0x08, 16 }, [SCxTDR] = { 0x0c, 8 }, [SCxSR] = { 0x10, 16 }, [SCxRDR] = { 0x14, 8 }, [SCFCR] = { 0x18, 16 }, [SCFDR] = { 0x1c, 16 }, [SCTFDR] = sci_reg_invalid, [SCRFDR] = sci_reg_invalid, [SCSPTR] = { 0x20, 16 }, [SCLSR] = { 0x24, 16 }, [HSSRR] = sci_reg_invalid, }, /* * Common SH-3 SCIF definitions. */ [SCIx_SH3_SCIF_REGTYPE] = { [SCSMR] = { 0x00, 8 }, [SCBRR] = { 0x02, 8 }, [SCSCR] = { 0x04, 8 }, [SCxTDR] = { 0x06, 8 }, [SCxSR] = { 0x08, 16 }, [SCxRDR] = { 0x0a, 8 }, [SCFCR] = { 0x0c, 8 }, [SCFDR] = { 0x0e, 16 }, [SCTFDR] = sci_reg_invalid, [SCRFDR] = sci_reg_invalid, [SCSPTR] = sci_reg_invalid, [SCLSR] = sci_reg_invalid, [HSSRR] = sci_reg_invalid, }, /* * Common SH-4(A) SCIF(B) definitions. */ [SCIx_SH4_SCIF_REGTYPE] = { [SCSMR] = { 0x00, 16 }, [SCBRR] = { 0x04, 8 }, [SCSCR] = { 0x08, 16 }, [SCxTDR] = { 0x0c, 8 }, [SCxSR] = { 0x10, 16 }, [SCxRDR] = { 0x14, 8 }, [SCFCR] = { 0x18, 16 }, [SCFDR] = { 0x1c, 16 }, [SCTFDR] = sci_reg_invalid, [SCRFDR] = sci_reg_invalid, [SCSPTR] = { 0x20, 16 }, [SCLSR] = { 0x24, 16 }, [HSSRR] = sci_reg_invalid, }, /* * Common HSCIF definitions. */ [SCIx_HSCIF_REGTYPE] = { [SCSMR] = { 0x00, 16 }, [SCBRR] = { 0x04, 8 }, [SCSCR] = { 0x08, 16 }, [SCxTDR] = { 0x0c, 8 }, [SCxSR] = { 0x10, 16 }, [SCxRDR] = { 0x14, 8 }, [SCFCR] = { 0x18, 16 }, [SCFDR] = { 0x1c, 16 }, [SCTFDR] = sci_reg_invalid, [SCRFDR] = sci_reg_invalid, [SCSPTR] = { 0x20, 16 }, [SCLSR] = { 0x24, 16 }, [HSSRR] = { 0x40, 16 }, }, /* * Common SH-4(A) SCIF(B) definitions for ports without an SCSPTR * register. */ [SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE] = { [SCSMR] = { 0x00, 16 }, [SCBRR] = { 0x04, 8 }, [SCSCR] = { 0x08, 16 }, [SCxTDR] = { 0x0c, 8 }, [SCxSR] = { 0x10, 16 }, [SCxRDR] = { 0x14, 8 }, [SCFCR] = { 0x18, 16 }, [SCFDR] = { 0x1c, 16 }, [SCTFDR] = sci_reg_invalid, [SCRFDR] = sci_reg_invalid, [SCSPTR] = sci_reg_invalid, [SCLSR] = { 0x24, 16 }, [HSSRR] = sci_reg_invalid, }, /* * Common SH-4(A) SCIF(B) definitions for ports with FIFO data * count registers. */ [SCIx_SH4_SCIF_FIFODATA_REGTYPE] = { [SCSMR] = { 0x00, 16 }, [SCBRR] = { 0x04, 8 }, [SCSCR] = { 0x08, 16 }, [SCxTDR] = { 0x0c, 8 }, [SCxSR] = { 0x10, 16 }, [SCxRDR] = { 0x14, 8 }, [SCFCR] = { 0x18, 16 }, [SCFDR] = { 0x1c, 16 }, [SCTFDR] = { 0x1c, 16 }, /* aliased to SCFDR */ [SCRFDR] = { 0x20, 16 }, [SCSPTR] = { 0x24, 16 }, [SCLSR] = { 0x28, 16 }, [HSSRR] = sci_reg_invalid, }, /* * SH7705-style SCIF(B) ports, lacking both SCSPTR and SCLSR * registers. */ [SCIx_SH7705_SCIF_REGTYPE] = { [SCSMR] = { 0x00, 16 }, [SCBRR] = { 0x04, 8 }, [SCSCR] = { 0x08, 16 }, [SCxTDR] = { 0x20, 8 }, [SCxSR] = { 0x14, 16 }, [SCxRDR] = { 0x24, 8 }, [SCFCR] = { 0x18, 16 }, [SCFDR] = { 0x1c, 16 }, [SCTFDR] = sci_reg_invalid, [SCRFDR] = sci_reg_invalid, [SCSPTR] = sci_reg_invalid, [SCLSR] = sci_reg_invalid, [HSSRR] = sci_reg_invalid, }, }; #define sci_getreg(up, offset) (sci_regmap[to_sci_port(up)->cfg->regtype] + offset) /* * The "offset" here is rather misleading, in that it refers to an enum * value relative to the port mapping rather than the fixed offset * itself, which needs to be manually retrieved from the platform's * register map for the given port. */ static unsigned int sci_serial_in(struct uart_port *p, int offset) { struct plat_sci_reg *reg = sci_getreg(p, offset); if (reg->size == 8) return ioread8(p->membase + (reg->offset << p->regshift)); else if (reg->size == 16) return ioread16(p->membase + (reg->offset << p->regshift)); else WARN(1, "Invalid register access\n"); return 0; } static void sci_serial_out(struct uart_port *p, int offset, int value) { struct plat_sci_reg *reg = sci_getreg(p, offset); if (reg->size == 8) iowrite8(value, p->membase + (reg->offset << p->regshift)); else if (reg->size == 16) iowrite16(value, p->membase + (reg->offset << p->regshift)); else WARN(1, "Invalid register access\n"); } static int sci_probe_regmap(struct plat_sci_port *cfg) { switch (cfg->type) { case PORT_SCI: cfg->regtype = SCIx_SCI_REGTYPE; break; case PORT_IRDA: cfg->regtype = SCIx_IRDA_REGTYPE; break; case PORT_SCIFA: cfg->regtype = SCIx_SCIFA_REGTYPE; break; case PORT_SCIFB: cfg->regtype = SCIx_SCIFB_REGTYPE; break; case PORT_SCIF: /* * The SH-4 is a bit of a misnomer here, although that's * where this particular port layout originated. This * configuration (or some slight variation thereof) * remains the dominant model for all SCIFs. */ cfg->regtype = SCIx_SH4_SCIF_REGTYPE; break; case PORT_HSCIF: cfg->regtype = SCIx_HSCIF_REGTYPE; break; default: printk(KERN_ERR "Can't probe register map for given port\n"); return -EINVAL; } return 0; } static void sci_port_enable(struct sci_port *sci_port) { if (!sci_port->port.dev) return; pm_runtime_get_sync(sci_port->port.dev); clk_enable(sci_port->iclk); sci_port->port.uartclk = clk_get_rate(sci_port->iclk); clk_enable(sci_port->fclk); } static void sci_port_disable(struct sci_port *sci_port) { if (!sci_port->port.dev) return; clk_disable(sci_port->fclk); clk_disable(sci_port->iclk); pm_runtime_put_sync(sci_port->port.dev); } #if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_SH_SCI_CONSOLE) #ifdef CONFIG_CONSOLE_POLL static int sci_poll_get_char(struct uart_port *port) { unsigned short status; int c; do { status = serial_port_in(port, SCxSR); if (status & SCxSR_ERRORS(port)) { serial_port_out(port, SCxSR, SCxSR_ERROR_CLEAR(port)); continue; } break; } while (1); if (!(status & SCxSR_RDxF(port))) return NO_POLL_CHAR; c = serial_port_in(port, SCxRDR); /* Dummy read */ serial_port_in(port, SCxSR); serial_port_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); return c; } #endif static void sci_poll_put_char(struct uart_port *port, unsigned char c) { unsigned short status; do { status = serial_port_in(port, SCxSR); } while (!(status & SCxSR_TDxE(port))); serial_port_out(port, SCxTDR, c); serial_port_out(port, SCxSR, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port)); } #endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE */ static void sci_init_pins(struct uart_port *port, unsigned int cflag) { struct sci_port *s = to_sci_port(port); struct plat_sci_reg *reg = sci_regmap[s->cfg->regtype] + SCSPTR; /* * Use port-specific handler if provided. */ if (s->cfg->ops && s->cfg->ops->init_pins) { s->cfg->ops->init_pins(port, cflag); return; } /* * For the generic path SCSPTR is necessary. Bail out if that's * unavailable, too. */ if (!reg->size)