From: Paul Mundt Date: Wed, 26 Jan 2011 09:23:27 +0000 (+0900) Subject: Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux... X-Git-Tag: firefly_0821_release~7613^2~2184^2~17^3 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=6b620478e58677bb3f4ec884abb29ef9d68c7821;p=firefly-linux-kernel-4.4.55.git Merge branch 'master' of git://git./linux/kernel/git/torvalds/linux-2.6 into common/serial-rework --- 6b620478e58677bb3f4ec884abb29ef9d68c7821 diff --cc drivers/tty/serial/sh-sci.c index 000000000000,92c91c83edde..0257fd5ede52 mode 000000,100644..100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@@ -1,0 -1,2079 +1,2066 @@@ + /* + * drivers/serial/sh-sci.c + * + * 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 + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include -#include + #include + #include + #include + + #ifdef CONFIG_SUPERH + #include + #endif + + #ifdef CONFIG_H8300 + #include + #endif + + #include "sh-sci.h" + + struct sci_port { + struct uart_port port; + - /* Port type */ - unsigned int type; - - /* Port IRQs: ERI, RXI, TXI, BRI (optional) */ - unsigned int irqs[SCIx_NR_IRQS]; ++ /* Platform configuration */ ++ struct plat_sci_port *cfg; + + /* Port enable callback */ + void (*enable)(struct uart_port *port); + + /* Port disable callback */ + void (*disable)(struct uart_port *port); + + /* Break timer */ + struct timer_list break_timer; + int break_flag; + - /* SCSCR initialization */ - unsigned int scscr; - - /* SCBRR calculation algo */ - unsigned int scbrr_algo_id; - + /* Interface clock */ + struct clk *iclk; + /* Function clock */ + struct clk *fclk; + - struct list_head node; - + struct dma_chan *chan_tx; + struct dma_chan *chan_rx; + + #ifdef CONFIG_SERIAL_SH_SCI_DMA - struct device *dma_dev; - unsigned int slave_tx; - unsigned int slave_rx; + 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 sh_sci_priv { - spinlock_t lock; - struct list_head ports; - struct notifier_block clk_nb; ++ 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); + } + + #if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_SH_SCI_CONSOLE) + + #ifdef CONFIG_CONSOLE_POLL -static inline void handle_error(struct uart_port *port) -{ - /* Clear error flags */ - sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port)); -} - + static int sci_poll_get_char(struct uart_port *port) + { + unsigned short status; + int c; + + do { + status = sci_in(port, SCxSR); + if (status & SCxSR_ERRORS(port)) { - handle_error(port); ++ sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port)); + continue; + } + break; + } while (1); + + if (!(status & SCxSR_RDxF(port))) + return NO_POLL_CHAR; + + c = sci_in(port, SCxRDR); + + /* Dummy read */ + sci_in(port, SCxSR); + sci_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 = sci_in(port, SCxSR); + } while (!(status & SCxSR_TDxE(port))); + + sci_out(port, SCxTDR, c); + sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port)); + } + #endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE */ + + #if defined(__H8300H__) || defined(__H8300S__) + static void sci_init_pins(struct uart_port *port, unsigned int cflag) + { + int ch = (port->mapbase - SMR0) >> 3; + + /* set DDR regs */ + H8300_GPIO_DDR(h8300_sci_pins[ch].port, + h8300_sci_pins[ch].rx, + H8300_GPIO_INPUT); + H8300_GPIO_DDR(h8300_sci_pins[ch].port, + h8300_sci_pins[ch].tx, + H8300_GPIO_OUTPUT); + + /* tx mark output*/ + H8300_SCI_DR(ch) |= h8300_sci_pins[ch].tx; + } + #elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712) + static inline void sci_init_pins(struct uart_port *port, unsigned int cflag) + { + if (port->mapbase == 0xA4400000) { + __raw_writew(__raw_readw(PACR) & 0xffc0, PACR); + __raw_writew(__raw_readw(PBCR) & 0x0fff, PBCR); + } else if (port->mapbase == 0xA4410000) + __raw_writew(__raw_readw(PBCR) & 0xf003, PBCR); + } + #elif defined(CONFIG_CPU_SUBTYPE_SH7720) || defined(CONFIG_CPU_SUBTYPE_SH7721) + static inline void sci_init_pins(struct uart_port *port, unsigned int cflag) + { + unsigned short data; + + if (cflag & CRTSCTS) { + /* enable RTS/CTS */ + if (port->mapbase == 0xa4430000) { /* SCIF0 */ + /* Clear PTCR bit 9-2; enable all scif pins but sck */ + data = __raw_readw(PORT_PTCR); + __raw_writew((data & 0xfc03), PORT_PTCR); + } else if (port->mapbase == 0xa4438000) { /* SCIF1 */ + /* Clear PVCR bit 9-2 */ + data = __raw_readw(PORT_PVCR); + __raw_writew((data & 0xfc03), PORT_PVCR); + } + } else { + if (port->mapbase == 0xa4430000) { /* SCIF0 */ + /* Clear PTCR bit 5-2; enable only tx and rx */ + data = __raw_readw(PORT_PTCR); + __raw_writew((data & 0xffc3), PORT_PTCR); + } else if (port->mapbase == 0xa4438000) { /* SCIF1 */ + /* Clear PVCR bit 5-2 */ + data = __raw_readw(PORT_PVCR); + __raw_writew((data & 0xffc3), PORT_PVCR); + } + } + } + #elif defined(CONFIG_CPU_SH3) + /* For SH7705, SH7706, SH7707, SH7709, SH7709A, SH7729 */ + static inline void sci_init_pins(struct uart_port *port, unsigned int cflag) + { + unsigned short data; + + /* We need to set SCPCR to enable RTS/CTS */ + data = __raw_readw(SCPCR); + /* Clear out SCP7MD1,0, SCP6MD1,0, SCP4MD1,0*/ + __raw_writew(data & 0x0fcf, SCPCR); + + if (!(cflag & CRTSCTS)) { + /* We need to set SCPCR to enable RTS/CTS */ + data = __raw_readw(SCPCR); + /* Clear out SCP7MD1,0, SCP4MD1,0, + Set SCP6MD1,0 = {01} (output) */ + __raw_writew((data & 0x0fcf) | 0x1000, SCPCR); + + data = __raw_readb(SCPDR); + /* Set /RTS2 (bit6) = 0 */ + __raw_writeb(data & 0xbf, SCPDR); + } + } + #elif defined(CONFIG_CPU_SUBTYPE_SH7722) + static inline void sci_init_pins(struct uart_port *port, unsigned int cflag) + { + unsigned short data; + + if (port->mapbase == 0xffe00000) { + data = __raw_readw(PSCR); + data &= ~0x03cf; + if (!(cflag & CRTSCTS)) + data |= 0x0340; + + __raw_writew(data, PSCR); + } + } + #elif defined(CONFIG_CPU_SUBTYPE_SH7757) || \ + defined(CONFIG_CPU_SUBTYPE_SH7763) || \ + defined(CONFIG_CPU_SUBTYPE_SH7780) || \ + defined(CONFIG_CPU_SUBTYPE_SH7785) || \ + defined(CONFIG_CPU_SUBTYPE_SH7786) || \ + defined(CONFIG_CPU_SUBTYPE_SHX3) + static inline void sci_init_pins(struct uart_port *port, unsigned int cflag) + { + if (!(cflag & CRTSCTS)) + __raw_writew(0x0080, SCSPTR0); /* Set RTS = 1 */ + } + #elif defined(CONFIG_CPU_SH4) && !defined(CONFIG_CPU_SH4A) + static inline void sci_init_pins(struct uart_port *port, unsigned int cflag) + { + if (!(cflag & CRTSCTS)) + __raw_writew(0x0080, SCSPTR2); /* Set RTS = 1 */ + } + #else + static inline void sci_init_pins(struct uart_port *port, unsigned int cflag) + { + /* Nothing to do */ + } + #endif + + #if defined(CONFIG_CPU_SUBTYPE_SH7760) || \ + defined(CONFIG_CPU_SUBTYPE_SH7780) || \ + defined(CONFIG_CPU_SUBTYPE_SH7785) || \ + defined(CONFIG_CPU_SUBTYPE_SH7786) + static int scif_txfill(struct uart_port *port) + { + return sci_in(port, SCTFDR) & 0xff; + } + + static int scif_txroom(struct uart_port *port) + { + return SCIF_TXROOM_MAX - scif_txfill(port); + } + + static int scif_rxfill(struct uart_port *port) + { + return sci_in(port, SCRFDR) & 0xff; + } + #elif defined(CONFIG_CPU_SUBTYPE_SH7763) + static int scif_txfill(struct uart_port *port) + { + if (port->mapbase == 0xffe00000 || + port->mapbase == 0xffe08000) + /* SCIF0/1*/ + return sci_in(port, SCTFDR) & 0xff; + else + /* SCIF2 */ + return sci_in(port, SCFDR) >> 8; + } + + static int scif_txroom(struct uart_port *port) + { + if (port->mapbase == 0xffe00000 || + port->mapbase == 0xffe08000) + /* SCIF0/1*/ + return SCIF_TXROOM_MAX - scif_txfill(port); + else + /* SCIF2 */ + return SCIF2_TXROOM_MAX - scif_txfill(port); + } + + 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_txfill(struct uart_port *port) + { + if (port->type == PORT_SCIFA) + return sci_in(port, SCFDR) >> 8; + else + return sci_in(port, SCTFDR); + } + + static int scif_txroom(struct uart_port *port) + { + return port->fifosize - scif_txfill(port); + } + + 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_txfill(struct uart_port *port) + { + return sci_in(port, SCFDR) >> 8; + } + + static int scif_txroom(struct uart_port *port) + { + return SCIF_TXROOM_MAX - scif_txfill(port); + } + + static int scif_rxfill(struct uart_port *port) + { + return sci_in(port, SCFDR) & SCIF_RFDC_MASK; + } + #endif + + static int sci_txfill(struct uart_port *port) + { + return !(sci_in(port, SCxSR) & SCI_TDRE); + } + + static int sci_txroom(struct uart_port *port) + { + return !sci_txfill(port); + } + + static int sci_rxfill(struct uart_port *port) + { + return (sci_in(port, SCxSR) & SCxSR_RDxF(port)) != 0; + } + + /* ********************************************************************** * + * the interrupt related routines * + * ********************************************************************** */ + + static void sci_transmit_chars(struct uart_port *port) + { + struct circ_buf *xmit = &port->state->xmit; + unsigned int stopped = uart_tx_stopped(port); + unsigned short status; + unsigned short ctrl; + int count; + + status = sci_in(port, SCxSR); + if (!(status & SCxSR_TDxE(port))) { + ctrl = sci_in(port, SCSCR); + if (uart_circ_empty(xmit)) + ctrl &= ~SCSCR_TIE; + else + ctrl |= SCSCR_TIE; + sci_out(port, SCSCR, ctrl); + return; + } + + if (port->type == PORT_SCI) + count = sci_txroom(port); + else + count = scif_txroom(port); + + do { + unsigned char c; + + if (port->x_char) { + c = port->x_char; + port->x_char = 0; + } else if (!uart_circ_empty(xmit) && !stopped) { + c = xmit->buf[xmit->tail]; + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + } else { + break; + } + + sci_out(port, SCxTDR, c); + + port->icount.tx++; + } while (--count > 0); + + sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port)); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + if (uart_circ_empty(xmit)) { + sci_stop_tx(port); + } else { + ctrl = sci_in(port, SCSCR); + + if (port->type != PORT_SCI) { + sci_in(port, SCxSR); /* Dummy read */ + sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port)); + } + + ctrl |= SCSCR_TIE; + sci_out(port, SCSCR, ctrl); + } + } + + /* On SH3, SCIF may read end-of-break as a space->mark char */ + #define STEPFN(c) ({int __c = (c); (((__c-1)|(__c)) == -1); }) + -static inline void sci_receive_chars(struct uart_port *port) ++static void sci_receive_chars(struct uart_port *port) + { + struct sci_port *sci_port = to_sci_port(port); + struct tty_struct *tty = port->state->port.tty; + int i, count, copied = 0; + unsigned short status; + unsigned char flag; + + status = sci_in(port, SCxSR); + if (!(status & SCxSR_RDxF(port))) + return; + + while (1) { + if (port->type == PORT_SCI) + count = sci_rxfill(port); + else + count = scif_rxfill(port); + + /* Don't copy more bytes than there is room for in the buffer */ + count = tty_buffer_request_room(tty, count); + + /* If for any reason we can't copy more data, we're done! */ + if (count == 0) + break; + + if (port->type == PORT_SCI) { + char c = sci_in(port, SCxRDR); + if (uart_handle_sysrq_char(port, c) || + sci_port->break_flag) + count = 0; + else + tty_insert_flip_char(tty, c, TTY_NORMAL); + } else { + for (i = 0; i < count; i++) { + char c = sci_in(port, SCxRDR); + status = sci_in(port, SCxSR); + #if defined(CONFIG_CPU_SH3) + /* Skip "chars" during break */ + if (sci_port->break_flag) { + if ((c == 0) && + (status & SCxSR_FER(port))) { + count--; i--; + continue; + } + + /* Nonzero => end-of-break */ + dev_dbg(port->dev, "debounce<%02x>\n", c); + sci_port->break_flag = 0; + + if (STEPFN(c)) { + count--; i--; + continue; + } + } + #endif /* CONFIG_CPU_SH3 */ + if (uart_handle_sysrq_char(port, c)) { + count--; i--; + continue; + } + + /* Store data and status */ + if (status & SCxSR_FER(port)) { + flag = TTY_FRAME; + dev_notice(port->dev, "frame error\n"); + } else if (status & SCxSR_PER(port)) { + flag = TTY_PARITY; + dev_notice(port->dev, "parity error\n"); + } else + flag = TTY_NORMAL; + + tty_insert_flip_char(tty, c, flag); + } + } + + sci_in(port, SCxSR); /* dummy read */ + sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); + + copied += count; + port->icount.rx += count; + } + + if (copied) { + /* Tell the rest of the system the news. New characters! */ + tty_flip_buffer_push(tty); + } else { + sci_in(port, SCxSR); /* dummy read */ + sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); + } + } + + #define SCI_BREAK_JIFFIES (HZ/20) -/* The sci generates interrupts during the break, ++ ++/* ++ * The sci generates interrupts during the break, + * 1 per millisecond or so during the break period, for 9600 baud. + * So dont bother disabling interrupts. + * But dont want more than 1 break event. + * Use a kernel timer to periodically poll the rx line until + * the break is finished. + */ -static void sci_schedule_break_timer(struct sci_port *port) ++static inline void sci_schedule_break_timer(struct sci_port *port) + { - port->break_timer.expires = jiffies + SCI_BREAK_JIFFIES; - add_timer(&port->break_timer); ++ mod_timer(&port->break_timer, jiffies + SCI_BREAK_JIFFIES); + } ++ + /* Ensure that two consecutive samples find the break over. */ + static void sci_break_timer(unsigned long data) + { + struct sci_port *port = (struct sci_port *)data; + + if (sci_rxd_in(&port->port) == 0) { + port->break_flag = 1; + sci_schedule_break_timer(port); + } else if (port->break_flag == 1) { + /* break is over. */ + port->break_flag = 2; + sci_schedule_break_timer(port); + } else + port->break_flag = 0; + } + -static inline int sci_handle_errors(struct uart_port *port) ++static int sci_handle_errors(struct uart_port *port) + { + int copied = 0; + unsigned short status = sci_in(port, SCxSR); + struct tty_struct *tty = port->state->port.tty; + + if (status & SCxSR_ORER(port)) { + /* overrun error */ + if (tty_insert_flip_char(tty, 0, TTY_OVERRUN)) + copied++; + + dev_notice(port->dev, "overrun error"); + } + + if (status & SCxSR_FER(port)) { + if (sci_rxd_in(port) == 0) { + /* Notify of BREAK */ + struct sci_port *sci_port = to_sci_port(port); + + if (!sci_port->break_flag) { + sci_port->break_flag = 1; + sci_schedule_break_timer(sci_port); + + /* Do sysrq handling. */ + if (uart_handle_break(port)) + return 0; + + dev_dbg(port->dev, "BREAK detected\n"); + + if (tty_insert_flip_char(tty, 0, TTY_BREAK)) + copied++; + } + + } else { + /* frame error */ + if (tty_insert_flip_char(tty, 0, TTY_FRAME)) + copied++; + + dev_notice(port->dev, "frame error\n"); + } + } + + if (status & SCxSR_PER(port)) { + /* parity error */ + if (tty_insert_flip_char(tty, 0, TTY_PARITY)) + copied++; + + dev_notice(port->dev, "parity error"); + } + + if (copied) + tty_flip_buffer_push(tty); + + return copied; + } + -static inline int sci_handle_fifo_overrun(struct uart_port *port) ++static int sci_handle_fifo_overrun(struct uart_port *port) + { + struct tty_struct *tty = port->state->port.tty; + int copied = 0; + + if (port->type != PORT_SCIF) + return 0; + + if ((sci_in(port, SCLSR) & SCIF_ORER) != 0) { + sci_out(port, SCLSR, 0); + + tty_insert_flip_char(tty, 0, TTY_OVERRUN); + tty_flip_buffer_push(tty); + + dev_notice(port->dev, "overrun error\n"); + copied++; + } + + return copied; + } + -static inline int sci_handle_breaks(struct uart_port *port) ++static int sci_handle_breaks(struct uart_port *port) + { + int copied = 0; + unsigned short status = sci_in(port, SCxSR); + struct tty_struct *tty = port->state->port.tty; + struct sci_port *s = to_sci_port(port); + + if (uart_handle_break(port)) + return 0; + + if (!s->break_flag && status & SCxSR_BRK(port)) { + #if defined(CONFIG_CPU_SH3) + /* Debounce break */ + s->break_flag = 1; + #endif + /* Notify of BREAK */ + if (tty_insert_flip_char(tty, 0, TTY_BREAK)) + copied++; + + dev_dbg(port->dev, "BREAK detected\n"); + } + + if (copied) + tty_flip_buffer_push(tty); + + copied += sci_handle_fifo_overrun(port); + + return copied; + } + + static irqreturn_t sci_rx_interrupt(int irq, void *ptr) + { + #ifdef CONFIG_SERIAL_SH_SCI_DMA + struct uart_port *port = ptr; + struct sci_port *s = to_sci_port(port); + + if (s->chan_rx) { + u16 scr = sci_in(port, SCSCR); + u16 ssr = sci_in(port, SCxSR); + + /* Disable future Rx interrupts */ + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { + disable_irq_nosync(irq); + scr |= 0x4000; + } else { + scr &= ~SCSCR_RIE; + } + sci_out(port, SCSCR, scr); + /* Clear current interrupt */ + sci_out(port, SCxSR, ssr & ~(1 | SCxSR_RDxF(port))); + dev_dbg(port->dev, "Rx IRQ %lu: setup t-out in %u jiffies\n", + jiffies, s->rx_timeout); + mod_timer(&s->rx_timer, jiffies + s->rx_timeout); + + return IRQ_HANDLED; + } + #endif + + /* I think sci_receive_chars has to be called irrespective + * of whether the I_IXOFF is set, otherwise, how is the interrupt + * to be disabled? + */ + sci_receive_chars(ptr); + + return IRQ_HANDLED; + } + + static irqreturn_t sci_tx_interrupt(int irq, void *ptr) + { + struct uart_port *port = ptr; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + sci_transmit_chars(port); + spin_unlock_irqrestore(&port->lock, flags); + + return IRQ_HANDLED; + } + + static irqreturn_t sci_er_interrupt(int irq, void *ptr) + { + struct uart_port *port = ptr; + + /* Handle errors */ + if (port->type == PORT_SCI) { + if (sci_handle_errors(port)) { + /* discard character in rx buffer */ + sci_in(port, SCxSR); + sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); + } + } else { + sci_handle_fifo_overrun(port); + sci_rx_interrupt(irq, ptr); + } + + sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port)); + + /* Kick the transmission */ + sci_tx_interrupt(irq, ptr); + + return IRQ_HANDLED; + } + + static irqreturn_t sci_br_interrupt(int irq, void *ptr) + { + struct uart_port *port = ptr; + + /* Handle BREAKs */ + sci_handle_breaks(port); + sci_out(port, SCxSR, SCxSR_BREAK_CLEAR(port)); + + return IRQ_HANDLED; + } + + static inline unsigned long port_rx_irq_mask(struct uart_port *port) + { + /* + * Not all ports (such as SCIFA) will support REIE. Rather than + * special-casing the port type, we check the port initialization + * IRQ enable mask to see whether the IRQ is desired at all. If + * it's unset, it's logically inferred that there's no point in + * testing for it. + */ - return SCSCR_RIE | (to_sci_port(port)->scscr & SCSCR_REIE); ++ return SCSCR_RIE | (to_sci_port(port)->cfg->scscr & SCSCR_REIE); + } + + static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr) + { + unsigned short ssr_status, scr_status, err_enabled; + struct uart_port *port = ptr; + struct sci_port *s = to_sci_port(port); + irqreturn_t ret = IRQ_NONE; + + ssr_status = sci_in(port, SCxSR); + scr_status = sci_in(port, SCSCR); + err_enabled = scr_status & port_rx_irq_mask(port); + + /* Tx Interrupt */ + if ((ssr_status & SCxSR_TDxE(port)) && (scr_status & SCSCR_TIE) && + !s->chan_tx) + ret = sci_tx_interrupt(irq, ptr); + + /* + * Rx Interrupt: if we're using DMA, the DMA controller clears RDF / + * DR flags + */ + if (((ssr_status & SCxSR_RDxF(port)) || s->chan_rx) && + (scr_status & SCSCR_RIE)) + ret = sci_rx_interrupt(irq, ptr); + + /* Error Interrupt */ + if ((ssr_status & SCxSR_ERRORS(port)) && err_enabled) + ret = sci_er_interrupt(irq, ptr); + + /* Break Interrupt */ + if ((ssr_status & SCxSR_BRK(port)) && err_enabled) + ret = sci_br_interrupt(irq, ptr); + + return ret; + } + + /* + * Here we define a transistion notifier so that we can update all of our + * ports' baud rate when the peripheral clock changes. + */ + static int sci_notifier(struct notifier_block *self, + unsigned long phase, void *p) + { - struct sh_sci_priv *priv = container_of(self, - struct sh_sci_priv, clk_nb); + struct sci_port *sci_port; + unsigned long flags; + ++ sci_port = container_of(self, struct sci_port, freq_transition); ++ + if ((phase == CPUFREQ_POSTCHANGE) || + (phase == CPUFREQ_RESUMECHANGE)) { - spin_lock_irqsave(&priv->lock, flags); - list_for_each_entry(sci_port, &priv->ports, node) - sci_port->port.uartclk = clk_get_rate(sci_port->iclk); - spin_unlock_irqrestore(&priv->lock, flags); ++ struct uart_port *port = &sci_port->port; ++ ++ spin_lock_irqsave(&port->lock, flags); ++ port->uartclk = clk_get_rate(sci_port->iclk); ++ spin_unlock_irqrestore(&port->lock, flags); + } + + return NOTIFY_OK; + } + + static void sci_clk_enable(struct uart_port *port) + { + struct sci_port *sci_port = to_sci_port(port); + + clk_enable(sci_port->iclk); + sci_port->port.uartclk = clk_get_rate(sci_port->iclk); + clk_enable(sci_port->fclk); + } + + static void sci_clk_disable(struct uart_port *port) + { + struct sci_port *sci_port = to_sci_port(port); + + clk_disable(sci_port->fclk); + clk_disable(sci_port->iclk); + } + + static int sci_request_irq(struct sci_port *port) + { + int i; + irqreturn_t (*handlers[4])(int irq, void *ptr) = { + sci_er_interrupt, sci_rx_interrupt, sci_tx_interrupt, + sci_br_interrupt, + }; + const char *desc[] = { "SCI Receive Error", "SCI Receive Data Full", + "SCI Transmit Data Empty", "SCI Break" }; + - if (port->irqs[0] == port->irqs[1]) { - if (unlikely(!port->irqs[0])) ++ if (port->cfg->irqs[0] == port->cfg->irqs[1]) { ++ if (unlikely(!port->cfg->irqs[0])) + return -ENODEV; + - if (request_irq(port->irqs[0], sci_mpxed_interrupt, ++ if (request_irq(port->cfg->irqs[0], sci_mpxed_interrupt, + IRQF_DISABLED, "sci", port)) { + dev_err(port->port.dev, "Can't allocate IRQ\n"); + return -ENODEV; + } + } else { + for (i = 0; i < ARRAY_SIZE(handlers); i++) { - if (unlikely(!port->irqs[i])) ++ if (unlikely(!port->cfg->irqs[i])) + continue; + - if (request_irq(port->irqs[i], handlers[i], ++ if (request_irq(port->cfg->irqs[i], handlers[i], + IRQF_DISABLED, desc[i], port)) { + dev_err(port->port.dev, "Can't allocate IRQ\n"); + return -ENODEV; + } + } + } + + return 0; + } + + static void sci_free_irq(struct sci_port *port) + { + int i; + - if (port->irqs[0] == port->irqs[1]) - free_irq(port->irqs[0], port); ++ if (port->cfg->irqs[0] == port->cfg->irqs[1]) ++ free_irq(port->cfg->irqs[0], port); + else { - for (i = 0; i < ARRAY_SIZE(port->irqs); i++) { - if (!port->irqs[i]) ++ for (i = 0; i < ARRAY_SIZE(port->cfg->irqs); i++) { ++ if (!port->cfg->irqs[i]) + continue; + - free_irq(port->irqs[i], port); ++ free_irq(port->cfg->irqs[i], port); + } + } + } + + static unsigned int sci_tx_empty(struct uart_port *port) + { + unsigned short status = sci_in(port, SCxSR); + unsigned short in_tx_fifo = scif_txfill(port); + + return (status & SCxSR_TEND(port)) && !in_tx_fifo ? TIOCSER_TEMT : 0; + } + + static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl) + { + /* This routine is used for seting signals of: DTR, DCD, CTS/RTS */ + /* We use SCIF's hardware for CTS/RTS, so don't need any for that. */ + /* If you have signals for DTR and DCD, please implement here. */ + } + + static unsigned int sci_get_mctrl(struct uart_port *port) + { + /* This routine is used for getting signals of: DTR, DCD, DSR, RI, + and CTS/RTS */ + + return TIOCM_DTR | TIOCM_RTS | TIOCM_DSR; + } + + #ifdef CONFIG_SERIAL_SH_SCI_DMA + static void sci_dma_tx_complete(void *arg) + { + struct sci_port *s = arg; + struct uart_port *port = &s->port; + struct circ_buf *xmit = &port->state->xmit; + unsigned long flags; + + dev_dbg(port->dev, "%s(%d)\n", __func__, port->line); + + spin_lock_irqsave(&port->lock, flags); + + xmit->tail += sg_dma_len(&s->sg_tx); + xmit->tail &= UART_XMIT_SIZE - 1; + + port->icount.tx += sg_dma_len(&s->sg_tx); + + async_tx_ack(s->desc_tx); + s->cookie_tx = -EINVAL; + s->desc_tx = NULL; + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + + if (!uart_circ_empty(xmit)) { + schedule_work(&s->work_tx); + } else if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { + u16 ctrl = sci_in(port, SCSCR); + sci_out(port, SCSCR, ctrl & ~SCSCR_TIE); + } + + spin_unlock_irqrestore(&port->lock, flags); + } + + /* Locking: called with port lock held */ + static int sci_dma_rx_push(struct sci_port *s, struct tty_struct *tty, + size_t count) + { + struct uart_port *port = &s->port; + int i, active, room; + + room = tty_buffer_request_room(tty, count); + + if (s->active_rx == s->cookie_rx[0]) { + active = 0; + } else if (s->active_rx == s->cookie_rx[1]) { + active = 1; + } else { + dev_err(port->dev, "cookie %d not found!\n", s->active_rx); + return 0; + } + + if (room < count) + dev_warn(port->dev, "Rx overrun: dropping %u bytes\n", + count - room); + if (!room) + return room; + + for (i = 0; i < room; i++) + tty_insert_flip_char(tty, ((u8 *)sg_virt(&s->sg_rx[active]))[i], + TTY_NORMAL); + + port->icount.rx += room; + + return room; + } + + static void sci_dma_rx_complete(void *arg) + { + struct sci_port *s = arg; + struct uart_port *port = &s->port; + struct tty_struct *tty = port->state->port.tty; + unsigned long flags; + int count; + + dev_dbg(port->dev, "%s(%d) active #%d\n", __func__, port->line, s->active_rx); + + spin_lock_irqsave(&port->lock, flags); + + count = sci_dma_rx_push(s, tty, s->buf_len_rx); + + mod_timer(&s->rx_timer, jiffies + s->rx_timeout); + + spin_unlock_irqrestore(&port->lock, flags); + + if (count) + tty_flip_buffer_push(tty); + + schedule_work(&s->work_rx); + } + -static void sci_start_rx(struct uart_port *port); -static void sci_start_tx(struct uart_port *port); - + static void sci_rx_dma_release(struct sci_port *s, bool enable_pio) + { + struct dma_chan *chan = s->chan_rx; + struct uart_port *port = &s->port; + + s->chan_rx = NULL; + s->cookie_rx[0] = s->cookie_rx[1] = -EINVAL; + dma_release_channel(chan); + if (sg_dma_address(&s->sg_rx[0])) + dma_free_coherent(port->dev, s->buf_len_rx * 2, + sg_virt(&s->sg_rx[0]), sg_dma_address(&s->sg_rx[0])); + if (enable_pio) + sci_start_rx(port); + } + + static void sci_tx_dma_release(struct sci_port *s, bool enable_pio) + { + struct dma_chan *chan = s->chan_tx; + struct uart_port *port = &s->port; + + s->chan_tx = NULL; + s->cookie_tx = -EINVAL; + dma_release_channel(chan); + if (enable_pio) + sci_start_tx(port); + } + + static void sci_submit_rx(struct sci_port *s) + { + struct dma_chan *chan = s->chan_rx; + int i; + + for (i = 0; i < 2; i++) { + struct scatterlist *sg = &s->sg_rx[i]; + struct dma_async_tx_descriptor *desc; + + desc = chan->device->device_prep_slave_sg(chan, + sg, 1, DMA_FROM_DEVICE, DMA_PREP_INTERRUPT); + + if (desc) { + s->desc_rx[i] = desc; + desc->callback = sci_dma_rx_complete; + desc->callback_param = s; + s->cookie_rx[i] = desc->tx_submit(desc); + } + + if (!desc || s->cookie_rx[i] < 0) { + if (i) { + async_tx_ack(s->desc_rx[0]); + s->cookie_rx[0] = -EINVAL; + } + if (desc) { + async_tx_ack(desc); + s->cookie_rx[i] = -EINVAL; + } + dev_warn(s->port.dev, + "failed to re-start DMA, using PIO\n"); + sci_rx_dma_release(s, true); + return; + } + dev_dbg(s->port.dev, "%s(): cookie %d to #%d\n", __func__, + s->cookie_rx[i], i); + } + + s->active_rx = s->cookie_rx[0]; + + dma_async_issue_pending(chan); + } + + static void work_fn_rx(struct work_struct *work) + { + struct sci_port *s = container_of(work, struct sci_port, work_rx); + struct uart_port *port = &s->port; + struct dma_async_tx_descriptor *desc; + int new; + + if (s->active_rx == s->cookie_rx[0]) { + new = 0; + } else if (s->active_rx == s->cookie_rx[1]) { + new = 1; + } else { + dev_err(port->dev, "cookie %d not found!\n", s->active_rx); + return; + } + desc = s->desc_rx[new]; + + if (dma_async_is_tx_complete(s->chan_rx, s->active_rx, NULL, NULL) != + DMA_SUCCESS) { + /* Handle incomplete DMA receive */ + struct tty_struct *tty = port->state->port.tty; + struct dma_chan *chan = s->chan_rx; + struct sh_desc *sh_desc = container_of(desc, struct sh_desc, + async_tx); + unsigned long flags; + int count; + + chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); + dev_dbg(port->dev, "Read %u bytes with cookie %d\n", + sh_desc->partial, sh_desc->cookie); + + spin_lock_irqsave(&port->lock, flags); + count = sci_dma_rx_push(s, tty, sh_desc->partial); + spin_unlock_irqrestore(&port->lock, flags); + + if (count) + tty_flip_buffer_push(tty); + + sci_submit_rx(s); + + return; + } + + s->cookie_rx[new] = desc->tx_submit(desc); + if (s->cookie_rx[new] < 0) { + dev_warn(port->dev, "Failed submitting Rx DMA descriptor\n"); + sci_rx_dma_release(s, true); + return; + } + + s->active_rx = s->cookie_rx[!new]; + + dev_dbg(port->dev, "%s: cookie %d #%d, new active #%d\n", __func__, + s->cookie_rx[new], new, s->active_rx); + } + + static void work_fn_tx(struct work_struct *work) + { + struct sci_port *s = container_of(work, struct sci_port, work_tx); + struct dma_async_tx_descriptor *desc; + struct dma_chan *chan = s->chan_tx; + struct uart_port *port = &s->port; + struct circ_buf *xmit = &port->state->xmit; + struct scatterlist *sg = &s->sg_tx; + + /* + * DMA is idle now. + * Port xmit buffer is already mapped, and it is one page... Just adjust + * offsets and lengths. Since it is a circular buffer, we have to + * transmit till the end, and then the rest. Take the port lock to get a + * consistent xmit buffer state. + */ + spin_lock_irq(&port->lock); + sg->offset = xmit->tail & (UART_XMIT_SIZE - 1); + sg_dma_address(sg) = (sg_dma_address(sg) & ~(UART_XMIT_SIZE - 1)) + + sg->offset; + sg_dma_len(sg) = min((int)CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE), + CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE)); + spin_unlock_irq(&port->lock); + + BUG_ON(!sg_dma_len(sg)); + + desc = chan->device->device_prep_slave_sg(chan, + sg, s->sg_len_tx, DMA_TO_DEVICE, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) { + /* switch to PIO */ + sci_tx_dma_release(s, true); + return; + } + + dma_sync_sg_for_device(port->dev, sg, 1, DMA_TO_DEVICE); + + spin_lock_irq(&port->lock); + s->desc_tx = desc; + desc->callback = sci_dma_tx_complete; + desc->callback_param = s; + spin_unlock_irq(&port->lock); + s->cookie_tx = desc->tx_submit(desc); + if (s->cookie_tx < 0) { + dev_warn(port->dev, "Failed submitting Tx DMA descriptor\n"); + /* switch to PIO */ + sci_tx_dma_release(s, true); + return; + } + + dev_dbg(port->dev, "%s: %p: %d...%d, cookie %d\n", __func__, + xmit->buf, xmit->tail, xmit->head, s->cookie_tx); + + dma_async_issue_pending(chan); + } + #endif + + static void sci_start_tx(struct uart_port *port) + { + struct sci_port *s = to_sci_port(port); + unsigned short ctrl; + + #ifdef CONFIG_SERIAL_SH_SCI_DMA + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { + u16 new, scr = sci_in(port, SCSCR); + if (s->chan_tx) + new = scr | 0x8000; + else + new = scr & ~0x8000; + if (new != scr) + sci_out(port, SCSCR, new); + } + + if (s->chan_tx && !uart_circ_empty(&s->port.state->xmit) && + s->cookie_tx < 0) + schedule_work(&s->work_tx); + #endif + + if (!s->chan_tx || port->type == PORT_SCIFA || port->type == PORT_SCIFB) { + /* Set TIE (Transmit Interrupt Enable) bit in SCSCR */ + ctrl = sci_in(port, SCSCR); + sci_out(port, SCSCR, ctrl | SCSCR_TIE); + } + } + + static void sci_stop_tx(struct uart_port *port) + { + unsigned short ctrl; + + /* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */ + ctrl = sci_in(port, SCSCR); + + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) + ctrl &= ~0x8000; + + ctrl &= ~SCSCR_TIE; + + sci_out(port, SCSCR, ctrl); + } + + static void sci_start_rx(struct uart_port *port) + { + unsigned short ctrl; + + ctrl = sci_in(port, SCSCR) | port_rx_irq_mask(port); + + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) + ctrl &= ~0x4000; + + sci_out(port, SCSCR, ctrl); + } + + static void sci_stop_rx(struct uart_port *port) + { + unsigned short ctrl; + + ctrl = sci_in(port, SCSCR); + + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) + ctrl &= ~0x4000; + + ctrl &= ~port_rx_irq_mask(port); + + sci_out(port, SCSCR, ctrl); + } + + static void sci_enable_ms(struct uart_port *port) + { + /* Nothing here yet .. */ + } + + static void sci_break_ctl(struct uart_port *port, int break_state) + { + /* Nothing here yet .. */ + } + + #ifdef CONFIG_SERIAL_SH_SCI_DMA + static bool filter(struct dma_chan *chan, void *slave) + { + struct sh_dmae_slave *param = slave; + + dev_dbg(chan->device->dev, "%s: slave ID %d\n", __func__, + param->slave_id); + + if (param->dma_dev == chan->device->dev) { + chan->private = param; + return true; + } else { + return false; + } + } + + static void rx_timer_fn(unsigned long arg) + { + struct sci_port *s = (struct sci_port *)arg; + struct uart_port *port = &s->port; + u16 scr = sci_in(port, SCSCR); + + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { + scr &= ~0x4000; - enable_irq(s->irqs[1]); ++ enable_irq(s->cfg->irqs[1]); + } + sci_out(port, SCSCR, scr | SCSCR_RIE); + dev_dbg(port->dev, "DMA Rx timed out\n"); + schedule_work(&s->work_rx); + } + + static void sci_request_dma(struct uart_port *port) + { + struct sci_port *s = to_sci_port(port); + struct sh_dmae_slave *param; + struct dma_chan *chan; + dma_cap_mask_t mask; + int nent; + + dev_dbg(port->dev, "%s: port %d DMA %p\n", __func__, - port->line, s->dma_dev); ++ port->line, s->cfg->dma_dev); + - if (!s->dma_dev) ++ if (!s->cfg->dma_dev) + return; + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + + param = &s->param_tx; + + /* Slave ID, e.g., SHDMA_SLAVE_SCIF0_TX */ - param->slave_id = s->slave_tx; - param->dma_dev = s->dma_dev; ++ param->slave_id = s->cfg->dma_slave_tx; ++ param->dma_dev = s->cfg->dma_dev; + + s->cookie_tx = -EINVAL; + chan = dma_request_channel(mask, filter, param); + dev_dbg(port->dev, "%s: TX: got channel %p\n", __func__, chan); + if (chan) { + s->chan_tx = chan; + sg_init_table(&s->sg_tx, 1); + /* UART circular tx buffer is an aligned page. */ + BUG_ON((int)port->state->xmit.buf & ~PAGE_MASK); + sg_set_page(&s->sg_tx, virt_to_page(port->state->xmit.buf), + UART_XMIT_SIZE, (int)port->state->xmit.buf & ~PAGE_MASK); + nent = dma_map_sg(port->dev, &s->sg_tx, 1, DMA_TO_DEVICE); + if (!nent) + sci_tx_dma_release(s, false); + else + dev_dbg(port->dev, "%s: mapped %d@%p to %x\n", __func__, + sg_dma_len(&s->sg_tx), + port->state->xmit.buf, sg_dma_address(&s->sg_tx)); + + s->sg_len_tx = nent; + + INIT_WORK(&s->work_tx, work_fn_tx); + } + + param = &s->param_rx; + + /* Slave ID, e.g., SHDMA_SLAVE_SCIF0_RX */ - param->slave_id = s->slave_rx; - param->dma_dev = s->dma_dev; ++ param->slave_id = s->cfg->dma_slave_rx; ++ param->dma_dev = s->cfg->dma_dev; + + chan = dma_request_channel(mask, filter, param); + dev_dbg(port->dev, "%s: RX: got channel %p\n", __func__, chan); + if (chan) { + dma_addr_t dma[2]; + void *buf[2]; + int i; + + s->chan_rx = chan; + + s->buf_len_rx = 2 * max(16, (int)port->fifosize); + buf[0] = dma_alloc_coherent(port->dev, s->buf_len_rx * 2, + &dma[0], GFP_KERNEL); + + if (!buf[0]) { + dev_warn(port->dev, + "failed to allocate dma buffer, using PIO\n"); + sci_rx_dma_release(s, true); + return; + } + + buf[1] = buf[0] + s->buf_len_rx; + dma[1] = dma[0] + s->buf_len_rx; + + for (i = 0; i < 2; i++) { + struct scatterlist *sg = &s->sg_rx[i]; + + sg_init_table(sg, 1); + sg_set_page(sg, virt_to_page(buf[i]), s->buf_len_rx, + (int)buf[i] & ~PAGE_MASK); + sg_dma_address(sg) = dma[i]; + } + + INIT_WORK(&s->work_rx, work_fn_rx); + setup_timer(&s->rx_timer, rx_timer_fn, (unsigned long)s); + + sci_submit_rx(s); + } + } + + static void sci_free_dma(struct uart_port *port) + { + struct sci_port *s = to_sci_port(port); + - if (!s->dma_dev) ++ if (!s->cfg->dma_dev) + return; + + if (s->chan_tx) + sci_tx_dma_release(s, false); + if (s->chan_rx) + sci_rx_dma_release(s, false); + } ++#else ++static inline void sci_request_dma(struct uart_port *port) ++{ ++} ++ ++static inline void sci_free_dma(struct uart_port *port) ++{ ++} + #endif + + static int sci_startup(struct uart_port *port) + { + struct sci_port *s = to_sci_port(port); ++ int ret; + + dev_dbg(port->dev, "%s(%d)\n", __func__, port->line); + + if (s->enable) + s->enable(port); + - sci_request_irq(s); -#ifdef CONFIG_SERIAL_SH_SCI_DMA ++ ret = sci_request_irq(s); ++ if (unlikely(ret < 0)) ++ return ret; ++ + sci_request_dma(port); -#endif ++ + sci_start_tx(port); + sci_start_rx(port); + + return 0; + } + + static void sci_shutdown(struct uart_port *port) + { + struct sci_port *s = to_sci_port(port); + + dev_dbg(port->dev, "%s(%d)\n", __func__, port->line); + + sci_stop_rx(port); + sci_stop_tx(port); -#ifdef CONFIG_SERIAL_SH_SCI_DMA ++ + sci_free_dma(port); -#endif + sci_free_irq(s); + + if (s->disable) + s->disable(port); + } + + static unsigned int sci_scbrr_calc(unsigned int algo_id, unsigned int bps, + unsigned long freq) + { + switch (algo_id) { + case SCBRR_ALGO_1: + return ((freq + 16 * bps) / (16 * bps) - 1); + case SCBRR_ALGO_2: + return ((freq + 16 * bps) / (32 * bps) - 1); + case SCBRR_ALGO_3: + return (((freq * 2) + 16 * bps) / (16 * bps) - 1); + case SCBRR_ALGO_4: + return (((freq * 2) + 16 * bps) / (32 * bps) - 1); + case SCBRR_ALGO_5: + return (((freq * 1000 / 32) / bps) - 1); + } + + /* Warn, but use a safe default */ + WARN_ON(1); ++ + return ((freq + 16 * bps) / (32 * bps) - 1); + } + + static void sci_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) + { + struct sci_port *s = to_sci_port(port); + unsigned int status, baud, smr_val, max_baud; + int t = -1; + u16 scfcr = 0; + + /* + * earlyprintk comes here early on with port->uartclk set to zero. + * the clock framework is not up and running at this point so here + * we assume that 115200 is the maximum baud rate. please note that + * the baud rate is not programmed during earlyprintk - it is assumed + * that the previous boot loader has enabled required clocks and + * setup the baud rate generator hardware for us already. + */ + max_baud = port->uartclk ? port->uartclk / 16 : 115200; + + baud = uart_get_baud_rate(port, termios, old, 0, max_baud); + if (likely(baud && port->uartclk)) - t = sci_scbrr_calc(s->scbrr_algo_id, baud, port->uartclk); ++ t = sci_scbrr_calc(s->cfg->scbrr_algo_id, baud, port->uartclk); + + do { + status = sci_in(port, SCxSR); + } while (!(status & SCxSR_TEND(port))); + + sci_out(port, SCSCR, 0x00); /* TE=0, RE=0, CKE1=0 */ + + if (port->type != PORT_SCI) + sci_out(port, SCFCR, scfcr | SCFCR_RFRST | SCFCR_TFRST); + + smr_val = sci_in(port, SCSMR) & 3; ++ + if ((termios->c_cflag & CSIZE) == CS7) + smr_val |= 0x40; + if (termios->c_cflag & PARENB) + smr_val |= 0x20; + if (termios->c_cflag & PARODD) + smr_val |= 0x30; + if (termios->c_cflag & CSTOPB) + smr_val |= 0x08; + + uart_update_timeout(port, termios->c_cflag, baud); + + sci_out(port, SCSMR, smr_val); + + dev_dbg(port->dev, "%s: SMR %x, t %x, SCSCR %x\n", __func__, smr_val, t, - s->scscr); ++ s->cfg->scscr); + + if (t > 0) { + if (t >= 256) { + sci_out(port, SCSMR, (sci_in(port, SCSMR) & ~3) | 1); + t >>= 2; + } else + sci_out(port, SCSMR, sci_in(port, SCSMR) & ~3); + + sci_out(port, SCBRR, t); + udelay((1000000+(baud-1)) / baud); /* Wait one bit interval */ + } + + sci_init_pins(port, termios->c_cflag); + sci_out(port, SCFCR, scfcr | ((termios->c_cflag & CRTSCTS) ? SCFCR_MCE : 0)); + - sci_out(port, SCSCR, s->scscr); ++ sci_out(port, SCSCR, s->cfg->scscr); + + #ifdef CONFIG_SERIAL_SH_SCI_DMA + /* + * Calculate delay for 1.5 DMA buffers: see + * drivers/serial/serial_core.c::uart_update_timeout(). With 10 bits + * (CS8), 250Hz, 115200 baud and 64 bytes FIFO, the above function + * calculates 1 jiffie for the data plus 5 jiffies for the "slop(e)." + * Then below we calculate 3 jiffies (12ms) for 1.5 DMA buffers (3 FIFO + * sizes), but it has been found out experimentally, that this is not + * enough: the driver too often needlessly runs on a DMA timeout. 20ms + * as a minimum seem to work perfectly. + */ + if (s->chan_rx) { + s->rx_timeout = (port->timeout - HZ / 50) * s->buf_len_rx * 3 / + port->fifosize / 2; + dev_dbg(port->dev, + "DMA Rx t-out %ums, tty t-out %u jiffies\n", + s->rx_timeout * 1000 / HZ, port->timeout); + if (s->rx_timeout < msecs_to_jiffies(20)) + s->rx_timeout = msecs_to_jiffies(20); + } + #endif + + if ((termios->c_cflag & CREAD) != 0) + sci_start_rx(port); + } + + static const char *sci_type(struct uart_port *port) + { + switch (port->type) { + case PORT_IRDA: + return "irda"; + case PORT_SCI: + return "sci"; + case PORT_SCIF: + return "scif"; + case PORT_SCIFA: + return "scifa"; + case PORT_SCIFB: + return "scifb"; + } + + return NULL; + } + -static void sci_release_port(struct uart_port *port) ++static inline unsigned long sci_port_size(struct uart_port *port) + { - /* Nothing here yet .. */ -} - -static int sci_request_port(struct uart_port *port) -{ - /* Nothing here yet .. */ - return 0; ++ /* ++ * Pick an arbitrary size that encapsulates all of the base ++ * registers by default. This can be optimized later, or derived ++ * from platform resource data at such a time that ports begin to ++ * behave more erratically. ++ */ ++ return 64; + } + -static void sci_config_port(struct uart_port *port, int flags) ++static int sci_remap_port(struct uart_port *port) + { - struct sci_port *s = to_sci_port(port); - - port->type = s->type; ++ unsigned long size = sci_port_size(port); + ++ /* ++ * Nothing to do if there's already an established membase. ++ */ + if (port->membase) - return; ++ return 0; + + if (port->flags & UPF_IOREMAP) { - port->membase = ioremap_nocache(port->mapbase, 0x40); - - if (IS_ERR(port->membase)) ++ port->membase = ioremap_nocache(port->mapbase, size); ++ if (unlikely(!port->membase)) { + dev_err(port->dev, "can't remap port#%d\n", port->line); ++ return -ENXIO; ++ } + } else { + /* + * For the simple (and majority of) cases where we don't + * need to do any remapping, just cast the cookie + * directly. + */ + port->membase = (void __iomem *)port->mapbase; + } ++ ++ return 0; ++} ++ ++static void sci_release_port(struct uart_port *port) ++{ ++ if (port->flags & UPF_IOREMAP) { ++ iounmap(port->membase); ++ port->membase = NULL; ++ } ++ ++ release_mem_region(port->mapbase, sci_port_size(port)); ++} ++ ++static int sci_request_port(struct uart_port *port) ++{ ++ unsigned long size = sci_port_size(port); ++ struct resource *res; ++ int ret; ++ ++ res = request_mem_region(port->mapbase, size, dev_name(port->dev)); ++ if (unlikely(res == NULL)) ++ return -EBUSY; ++ ++ ret = sci_remap_port(port); ++ if (unlikely(ret != 0)) { ++ release_resource(res); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void sci_config_port(struct uart_port *port, int flags) ++{ ++ if (flags & UART_CONFIG_TYPE) { ++ struct sci_port *sport = to_sci_port(port); ++ ++ port->type = sport->cfg->type; ++ sci_request_port(port); ++ } + } + + static int sci_verify_port(struct uart_port *port, struct serial_struct *ser) + { + struct sci_port *s = to_sci_port(port); + - if (ser->irq != s->irqs[SCIx_TXI_IRQ] || ser->irq > nr_irqs) ++ if (ser->irq != s->cfg->irqs[SCIx_TXI_IRQ] || ser->irq > nr_irqs) + return -EINVAL; + if (ser->baud_base < 2400) + /* No paper tape reader for Mitch.. */ + return -EINVAL; + + return 0; + } + + static struct uart_ops sci_uart_ops = { + .tx_empty = sci_tx_empty, + .set_mctrl = sci_set_mctrl, + .get_mctrl = sci_get_mctrl, + .start_tx = sci_start_tx, + .stop_tx = sci_stop_tx, + .stop_rx = sci_stop_rx, + .enable_ms = sci_enable_ms, + .break_ctl = sci_break_ctl, + .startup = sci_startup, + .shutdown = sci_shutdown, + .set_termios = sci_set_termios, + .type = sci_type, + .release_port = sci_release_port, + .request_port = sci_request_port, + .config_port = sci_config_port, + .verify_port = sci_verify_port, + #ifdef CONFIG_CONSOLE_POLL + .poll_get_char = sci_poll_get_char, + .poll_put_char = sci_poll_put_char, + #endif + }; + + static int __devinit sci_init_single(struct platform_device *dev, + struct sci_port *sci_port, + unsigned int index, + struct plat_sci_port *p) + { + struct uart_port *port = &sci_port->port; + + port->ops = &sci_uart_ops; + port->iotype = UPIO_MEM; + port->line = index; + + switch (p->type) { + case PORT_SCIFB: + port->fifosize = 256; + break; + case PORT_SCIFA: + port->fifosize = 64; + break; + case PORT_SCIF: + port->fifosize = 16; + break; + default: + port->fifosize = 1; + break; + } + + if (dev) { + sci_port->iclk = clk_get(&dev->dev, "sci_ick"); + if (IS_ERR(sci_port->iclk)) { + sci_port->iclk = clk_get(&dev->dev, "peripheral_clk"); + if (IS_ERR(sci_port->iclk)) { + dev_err(&dev->dev, "can't get iclk\n"); + return PTR_ERR(sci_port->iclk); + } + } + + /* + * The function clock is optional, ignore it if we can't + * find it. + */ + sci_port->fclk = clk_get(&dev->dev, "sci_fck"); + if (IS_ERR(sci_port->fclk)) + sci_port->fclk = NULL; + + sci_port->enable = sci_clk_enable; + sci_port->disable = sci_clk_disable; + port->dev = &dev->dev; + } + + sci_port->break_timer.data = (unsigned long)sci_port; + sci_port->break_timer.function = sci_break_timer; + init_timer(&sci_port->break_timer); + - port->mapbase = p->mapbase; - port->membase = p->membase; ++ sci_port->cfg = p; + - port->irq = p->irqs[SCIx_TXI_IRQ]; ++ port->mapbase = p->mapbase; ++ port->type = p->type; + port->flags = p->flags; - sci_port->type = port->type = p->type; - sci_port->scscr = p->scscr; - sci_port->scbrr_algo_id = p->scbrr_algo_id; + -#ifdef CONFIG_SERIAL_SH_SCI_DMA - sci_port->dma_dev = p->dma_dev; - sci_port->slave_tx = p->dma_slave_tx; - sci_port->slave_rx = p->dma_slave_rx; ++ /* ++ * The UART port needs an IRQ value, so we peg this to the TX IRQ ++ * for the multi-IRQ ports, which is where we are primarily ++ * concerned with the shutdown path synchronization. ++ * ++ * For the muxed case there's nothing more to do. ++ */ ++ port->irq = p->irqs[SCIx_TXI_IRQ]; + - dev_dbg(port->dev, "%s: DMA device %p, tx %d, rx %d\n", __func__, - p->dma_dev, p->dma_slave_tx, p->dma_slave_rx); -#endif ++ if (p->dma_dev) ++ dev_dbg(port->dev, "DMA device %p, tx %d, rx %d\n", ++ p->dma_dev, p->dma_slave_tx, p->dma_slave_rx); + - memcpy(&sci_port->irqs, &p->irqs, sizeof(p->irqs)); + return 0; + } + + #ifdef CONFIG_SERIAL_SH_SCI_CONSOLE -static struct tty_driver *serial_console_device(struct console *co, int *index) -{ - struct uart_driver *p = &sci_uart_driver; - *index = co->index; - return p->tty_driver; -} - + static void serial_console_putchar(struct uart_port *port, int ch) + { + sci_poll_put_char(port, ch); + } + + /* + * Print a string to the serial port trying not to disturb + * any possible real use of the port... + */ + static void serial_console_write(struct console *co, const char *s, + unsigned count) + { - struct uart_port *port = co->data; - struct sci_port *sci_port = to_sci_port(port); ++ struct sci_port *sci_port = &sci_ports[co->index]; ++ struct uart_port *port = &sci_port->port; + unsigned short bits; + + if (sci_port->enable) + sci_port->enable(port); + + uart_console_write(port, s, count, serial_console_putchar); + + /* wait until fifo is empty and last bit has been transmitted */ + bits = SCxSR_TDxE(port) | SCxSR_TEND(port); + while ((sci_in(port, SCxSR) & bits) != bits) + cpu_relax(); + + if (sci_port->disable) + sci_port->disable(port); + } + + static int __devinit serial_console_setup(struct console *co, char *options) + { + struct sci_port *sci_port; + struct uart_port *port; + int baud = 115200; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + int ret; + + /* - * Check whether an invalid uart number has been specified, and - * if so, search for the first available port that does have - * console support. - */ - if (co->index >= SCI_NPORTS) - co->index = 0; - - if (co->data) { - port = co->data; - sci_port = to_sci_port(port); - } else { - sci_port = &sci_ports[co->index]; - port = &sci_port->port; - co->data = port; - } - - /* - * Also need to check port->type, we don't actually have any - * UPIO_PORT ports, but uart_report_port() handily misreports - * it anyways if we don't have a port available by the time this is - * called. ++ * Refuse to handle any bogus ports. + */ - if (!port->type) ++ if (co->index < 0 || co->index >= SCI_NPORTS) + return -ENODEV; + - sci_config_port(port, 0); ++ sci_port = &sci_ports[co->index]; ++ port = &sci_port->port; ++ ++ ret = sci_remap_port(port); ++ if (unlikely(ret != 0)) ++ return ret; + + if (sci_port->enable) + sci_port->enable(port); + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + ret = uart_set_options(port, co, baud, parity, bits, flow); + #if defined(__H8300H__) || defined(__H8300S__) + /* disable rx interrupt */ + if (ret == 0) + sci_stop_rx(port); + #endif + /* TODO: disable clock */ + return ret; + } + + static struct console serial_console = { + .name = "ttySC", - .device = serial_console_device, ++ .device = uart_console_device, + .write = serial_console_write, + .setup = serial_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, ++ .data = &sci_uart_driver, + }; + + static int __init sci_console_init(void) + { + register_console(&serial_console); + return 0; + } + console_initcall(sci_console_init); + -static struct sci_port early_serial_port; + static struct console early_serial_console = { + .name = "early_ttySC", + .write = serial_console_write, + .flags = CON_PRINTBUFFER, ++ .index = -1, + }; ++ + static char early_serial_buf[32]; + ++static int __devinit sci_probe_earlyprintk(struct platform_device *pdev) ++{ ++ struct plat_sci_port *cfg = pdev->dev.platform_data; ++ ++ if (early_serial_console.data) ++ return -EEXIST; ++ ++ early_serial_console.index = pdev->id; ++ ++ sci_init_single(NULL, &sci_ports[pdev->id], pdev->id, cfg); ++ ++ serial_console_setup(&early_serial_console, early_serial_buf); ++ ++ if (!strstr(early_serial_buf, "keep")) ++ early_serial_console.flags |= CON_BOOT; ++ ++ register_console(&early_serial_console); ++ return 0; ++} ++#else ++static inline int __devinit sci_probe_earlyprintk(struct platform_device *pdev) ++{ ++ return -EINVAL; ++} + #endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */ + + #if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) + #define SCI_CONSOLE (&serial_console) + #else + #define SCI_CONSOLE 0 + #endif + + static char banner[] __initdata = + KERN_INFO "SuperH SCI(F) driver initialized\n"; + + static struct uart_driver sci_uart_driver = { + .owner = THIS_MODULE, + .driver_name = "sci", + .dev_name = "ttySC", + .major = SCI_MAJOR, + .minor = SCI_MINOR_START, + .nr = SCI_NPORTS, + .cons = SCI_CONSOLE, + }; + - + static int sci_remove(struct platform_device *dev) + { - struct sh_sci_priv *priv = platform_get_drvdata(dev); - struct sci_port *p; - unsigned long flags; ++ struct sci_port *port = platform_get_drvdata(dev); + - cpufreq_unregister_notifier(&priv->clk_nb, CPUFREQ_TRANSITION_NOTIFIER); ++ cpufreq_unregister_notifier(&port->freq_transition, ++ CPUFREQ_TRANSITION_NOTIFIER); + - spin_lock_irqsave(&priv->lock, flags); - list_for_each_entry(p, &priv->ports, node) { - uart_remove_one_port(&sci_uart_driver, &p->port); - clk_put(p->iclk); - clk_put(p->fclk); - } - spin_unlock_irqrestore(&priv->lock, flags); ++ uart_remove_one_port(&sci_uart_driver, &port->port); ++ ++ clk_put(port->iclk); ++ clk_put(port->fclk); + - kfree(priv); + return 0; + } + + static int __devinit sci_probe_single(struct platform_device *dev, + unsigned int index, + struct plat_sci_port *p, + struct sci_port *sciport) + { - struct sh_sci_priv *priv = platform_get_drvdata(dev); - unsigned long flags; + int ret; + + /* Sanity check */ + if (unlikely(index >= SCI_NPORTS)) { + dev_notice(&dev->dev, "Attempting to register port " + "%d when only %d are available.\n", + index+1, SCI_NPORTS); + dev_notice(&dev->dev, "Consider bumping " + "CONFIG_SERIAL_SH_SCI_NR_UARTS!\n"); + return 0; + } + + ret = sci_init_single(dev, sciport, index, p); + if (ret) + return ret; + - ret = uart_add_one_port(&sci_uart_driver, &sciport->port); - if (ret) - return ret; - - INIT_LIST_HEAD(&sciport->node); - - spin_lock_irqsave(&priv->lock, flags); - list_add(&sciport->node, &priv->ports); - spin_unlock_irqrestore(&priv->lock, flags); - - return 0; ++ return uart_add_one_port(&sci_uart_driver, &sciport->port); + } + -/* - * Register a set of serial devices attached to a platform device. The - * list is terminated with a zero flags entry, which means we expect - * all entries to have at least UPF_BOOT_AUTOCONF set. Platforms that need - * remapping (such as sh64) should also set UPF_IOREMAP. - */ + static int __devinit sci_probe(struct platform_device *dev) + { + struct plat_sci_port *p = dev->dev.platform_data; - struct sh_sci_priv *priv; - int i, ret = -EINVAL; ++ struct sci_port *sp = &sci_ports[dev->id]; ++ int ret; + -#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE - if (is_early_platform_device(dev)) { - if (dev->id == -1) - return -ENOTSUPP; - early_serial_console.index = dev->id; - early_serial_console.data = &early_serial_port.port; - sci_init_single(NULL, &early_serial_port, dev->id, p); - serial_console_setup(&early_serial_console, early_serial_buf); - if (!strstr(early_serial_buf, "keep")) - early_serial_console.flags |= CON_BOOT; - register_console(&early_serial_console); - return 0; - } -#endif ++ /* ++ * If we've come here via earlyprintk initialization, head off to ++ * the special early probe. We don't have sufficient device state ++ * to make it beyond this yet. ++ */ ++ if (is_early_platform_device(dev)) ++ return sci_probe_earlyprintk(dev); + - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; ++ platform_set_drvdata(dev, sp); + - INIT_LIST_HEAD(&priv->ports); - spin_lock_init(&priv->lock); - platform_set_drvdata(dev, priv); ++ ret = sci_probe_single(dev, dev->id, p, sp); ++ if (ret) ++ goto err_unreg; + - priv->clk_nb.notifier_call = sci_notifier; - cpufreq_register_notifier(&priv->clk_nb, CPUFREQ_TRANSITION_NOTIFIER); ++ sp->freq_transition.notifier_call = sci_notifier; + - if (dev->id != -1) { - ret = sci_probe_single(dev, dev->id, p, &sci_ports[dev->id]); - if (ret) - goto err_unreg; - } else { - for (i = 0; p && p->flags != 0; p++, i++) { - ret = sci_probe_single(dev, i, p, &sci_ports[i]); - if (ret) - goto err_unreg; - } - } ++ ret = cpufreq_register_notifier(&sp->freq_transition, ++ CPUFREQ_TRANSITION_NOTIFIER); ++ if (unlikely(ret < 0)) ++ goto err_unreg; + + #ifdef CONFIG_SH_STANDARD_BIOS + sh_bios_gdb_detach(); + #endif + + return 0; + + err_unreg: + sci_remove(dev); + return ret; + } + + static int sci_suspend(struct device *dev) + { - struct sh_sci_priv *priv = dev_get_drvdata(dev); - struct sci_port *p; - unsigned long flags; ++ struct sci_port *sport = dev_get_drvdata(dev); + - spin_lock_irqsave(&priv->lock, flags); - list_for_each_entry(p, &priv->ports, node) - uart_suspend_port(&sci_uart_driver, &p->port); - spin_unlock_irqrestore(&priv->lock, flags); ++ if (sport) ++ uart_suspend_port(&sci_uart_driver, &sport->port); + + return 0; + } + + static int sci_resume(struct device *dev) + { - struct sh_sci_priv *priv = dev_get_drvdata(dev); - struct sci_port *p; - unsigned long flags; ++ struct sci_port *sport = dev_get_drvdata(dev); + - spin_lock_irqsave(&priv->lock, flags); - list_for_each_entry(p, &priv->ports, node) - uart_resume_port(&sci_uart_driver, &p->port); - spin_unlock_irqrestore(&priv->lock, flags); ++ if (sport) ++ uart_resume_port(&sci_uart_driver, &sport->port); + + return 0; + } + + static const struct dev_pm_ops sci_dev_pm_ops = { + .suspend = sci_suspend, + .resume = sci_resume, + }; + + static struct platform_driver sci_driver = { + .probe = sci_probe, + .remove = sci_remove, + .driver = { + .name = "sh-sci", + .owner = THIS_MODULE, + .pm = &sci_dev_pm_ops, + }, + }; + + static int __init sci_init(void) + { + int ret; + + printk(banner); + + ret = uart_register_driver(&sci_uart_driver); + if (likely(ret == 0)) { + ret = platform_driver_register(&sci_driver); + if (unlikely(ret)) + uart_unregister_driver(&sci_uart_driver); + } + + return ret; + } + + static void __exit sci_exit(void) + { + platform_driver_unregister(&sci_driver); + uart_unregister_driver(&sci_uart_driver); + } + + #ifdef CONFIG_SERIAL_SH_SCI_CONSOLE + early_platform_init_buffer("earlyprintk", &sci_driver, + early_serial_buf, ARRAY_SIZE(early_serial_buf)); + #endif + module_init(sci_init); + module_exit(sci_exit); + + MODULE_LICENSE("GPL"); + MODULE_ALIAS("platform:sh-sci"); diff --cc drivers/tty/serial/sh-sci.h index 000000000000,b223d6cbf33a..5fefed53fa42 mode 000000,100644..100644 --- a/drivers/tty/serial/sh-sci.h +++ b/drivers/tty/serial/sh-sci.h @@@ -1,0 -1,507 +1,468 @@@ + #include + #include + #include + + #if defined(CONFIG_H83007) || defined(CONFIG_H83068) + #include + #endif + #if defined(CONFIG_H8S2678) + #include + #endif + + #if defined(CONFIG_CPU_SUBTYPE_SH7706) || \ + defined(CONFIG_CPU_SUBTYPE_SH7707) || \ + defined(CONFIG_CPU_SUBTYPE_SH7708) || \ + defined(CONFIG_CPU_SUBTYPE_SH7709) + # define SCPCR 0xA4000116 /* 16 bit SCI and SCIF */ + # define SCPDR 0xA4000136 /* 8 bit SCI and SCIF */ + #elif defined(CONFIG_CPU_SUBTYPE_SH7705) + # define SCIF0 0xA4400000 + # define SCIF2 0xA4410000 + # define SCPCR 0xA4000116 + # define SCPDR 0xA4000136 + #elif defined(CONFIG_CPU_SUBTYPE_SH7720) || \ + defined(CONFIG_CPU_SUBTYPE_SH7721) || \ + defined(CONFIG_ARCH_SH73A0) || \ + defined(CONFIG_ARCH_SH7367) || \ + defined(CONFIG_ARCH_SH7377) || \ + defined(CONFIG_ARCH_SH7372) + # define PORT_PTCR 0xA405011EUL + # define PORT_PVCR 0xA4050122UL + # define SCIF_ORER 0x0200 /* overrun error bit */ + #elif defined(CONFIG_SH_RTS7751R2D) + # define SCSPTR1 0xFFE0001C /* 8 bit SCIF */ + # define SCSPTR2 0xFFE80020 /* 16 bit SCIF */ + # define SCIF_ORER 0x0001 /* overrun error bit */ + #elif defined(CONFIG_CPU_SUBTYPE_SH7750) || \ + defined(CONFIG_CPU_SUBTYPE_SH7750R) || \ + defined(CONFIG_CPU_SUBTYPE_SH7750S) || \ + defined(CONFIG_CPU_SUBTYPE_SH7091) || \ + defined(CONFIG_CPU_SUBTYPE_SH7751) || \ + defined(CONFIG_CPU_SUBTYPE_SH7751R) + # define SCSPTR1 0xffe0001c /* 8 bit SCI */ + # define SCSPTR2 0xFFE80020 /* 16 bit SCIF */ + # define SCIF_ORER 0x0001 /* overrun error bit */ + #elif defined(CONFIG_CPU_SUBTYPE_SH7760) + # define SCSPTR0 0xfe600024 /* 16 bit SCIF */ + # define SCSPTR1 0xfe610024 /* 16 bit SCIF */ + # define SCSPTR2 0xfe620024 /* 16 bit SCIF */ + # define SCIF_ORER 0x0001 /* overrun error bit */ + #elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712) + # define SCSPTR0 0xA4400000 /* 16 bit SCIF */ + # define SCIF_ORER 0x0001 /* overrun error bit */ + # define PACR 0xa4050100 + # define PBCR 0xa4050102 + #elif defined(CONFIG_CPU_SUBTYPE_SH7343) + # define SCSPTR0 0xffe00010 /* 16 bit SCIF */ -# define SCSPTR1 0xffe10010 /* 16 bit SCIF */ -# define SCSPTR2 0xffe20010 /* 16 bit SCIF */ -# define SCSPTR3 0xffe30010 /* 16 bit SCIF */ + #elif defined(CONFIG_CPU_SUBTYPE_SH7722) + # define PADR 0xA4050120 + # define PSDR 0xA405013e + # define PWDR 0xA4050166 + # define PSCR 0xA405011E + # define SCIF_ORER 0x0001 /* overrun error bit */ + #elif defined(CONFIG_CPU_SUBTYPE_SH7366) + # define SCPDR0 0xA405013E /* 16 bit SCIF0 PSDR */ + # define SCSPTR0 SCPDR0 + # define SCIF_ORER 0x0001 /* overrun error bit */ + #elif defined(CONFIG_CPU_SUBTYPE_SH7723) + # define SCSPTR0 0xa4050160 -# define SCSPTR1 0xa405013e -# define SCSPTR2 0xa4050160 -# define SCSPTR3 0xa405013e -# define SCSPTR4 0xa4050128 -# define SCSPTR5 0xa4050128 + # define SCIF_ORER 0x0001 /* overrun error bit */ + #elif defined(CONFIG_CPU_SUBTYPE_SH7724) + # define SCIF_ORER 0x0001 /* overrun error bit */ + #elif defined(CONFIG_CPU_SUBTYPE_SH4_202) + # define SCSPTR2 0xffe80020 /* 16 bit SCIF */ + # define SCIF_ORER 0x0001 /* overrun error bit */ -#elif defined(CONFIG_CPU_SUBTYPE_SH5_101) || defined(CONFIG_CPU_SUBTYPE_SH5_103) -# define SCIF_PTR2_OFFS 0x0000020 -# define SCSPTR2 ((port->mapbase)+SCIF_PTR2_OFFS) /* 16 bit SCIF */ + #elif defined(CONFIG_H83007) || defined(CONFIG_H83068) + # define H8300_SCI_DR(ch) *(volatile char *)(P1DR + h8300_sci_pins[ch].port) + #elif defined(CONFIG_H8S2678) + # define H8300_SCI_DR(ch) *(volatile char *)(P1DR + h8300_sci_pins[ch].port) + #elif defined(CONFIG_CPU_SUBTYPE_SH7757) + # define SCSPTR0 0xfe4b0020 -# define SCSPTR1 0xfe4b0020 -# define SCSPTR2 0xfe4b0020 + # define SCIF_ORER 0x0001 -# define SCIF_ONLY + #elif defined(CONFIG_CPU_SUBTYPE_SH7763) + # define SCSPTR0 0xffe00024 /* 16 bit SCIF */ -# define SCSPTR1 0xffe08024 /* 16 bit SCIF */ -# define SCSPTR2 0xffe10020 /* 16 bit SCIF/IRDA */ + # define SCIF_ORER 0x0001 /* overrun error bit */ + #elif defined(CONFIG_CPU_SUBTYPE_SH7770) + # define SCSPTR0 0xff923020 /* 16 bit SCIF */ -# define SCSPTR1 0xff924020 /* 16 bit SCIF */ -# define SCSPTR2 0xff925020 /* 16 bit SCIF */ + # define SCIF_ORER 0x0001 /* overrun error bit */ + #elif defined(CONFIG_CPU_SUBTYPE_SH7780) + # define SCSPTR0 0xffe00024 /* 16 bit SCIF */ -# define SCSPTR1 0xffe10024 /* 16 bit SCIF */ + # define SCIF_ORER 0x0001 /* Overrun error bit */ + #elif defined(CONFIG_CPU_SUBTYPE_SH7785) || \ + defined(CONFIG_CPU_SUBTYPE_SH7786) + # define SCSPTR0 0xffea0024 /* 16 bit SCIF */ -# define SCSPTR1 0xffeb0024 /* 16 bit SCIF */ -# define SCSPTR2 0xffec0024 /* 16 bit SCIF */ -# define SCSPTR3 0xffed0024 /* 16 bit SCIF */ -# define SCSPTR4 0xffee0024 /* 16 bit SCIF */ -# define SCSPTR5 0xffef0024 /* 16 bit SCIF */ + # define SCIF_ORER 0x0001 /* Overrun error bit */ + #elif defined(CONFIG_CPU_SUBTYPE_SH7201) || \ + defined(CONFIG_CPU_SUBTYPE_SH7203) || \ + defined(CONFIG_CPU_SUBTYPE_SH7206) || \ + defined(CONFIG_CPU_SUBTYPE_SH7263) + # define SCSPTR0 0xfffe8020 /* 16 bit SCIF */ -# define SCSPTR1 0xfffe8820 /* 16 bit SCIF */ -# define SCSPTR2 0xfffe9020 /* 16 bit SCIF */ -# define SCSPTR3 0xfffe9820 /* 16 bit SCIF */ -# if defined(CONFIG_CPU_SUBTYPE_SH7201) -# define SCSPTR4 0xfffeA020 /* 16 bit SCIF */ -# define SCSPTR5 0xfffeA820 /* 16 bit SCIF */ -# define SCSPTR6 0xfffeB020 /* 16 bit SCIF */ -# define SCSPTR7 0xfffeB820 /* 16 bit SCIF */ -# endif + #elif defined(CONFIG_CPU_SUBTYPE_SH7619) + # define SCSPTR0 0xf8400020 /* 16 bit SCIF */ -# define SCSPTR1 0xf8410020 /* 16 bit SCIF */ -# define SCSPTR2 0xf8420020 /* 16 bit SCIF */ + # define SCIF_ORER 0x0001 /* overrun error bit */ + #elif defined(CONFIG_CPU_SUBTYPE_SHX3) + # define SCSPTR0 0xffc30020 /* 16 bit SCIF */ -# define SCSPTR1 0xffc40020 /* 16 bit SCIF */ -# define SCSPTR2 0xffc50020 /* 16 bit SCIF */ -# define SCSPTR3 0xffc60020 /* 16 bit SCIF */ + # define SCIF_ORER 0x0001 /* Overrun error bit */ + #else + # error CPU subtype not defined + #endif + + /* SCxSR SCI */ + #define SCI_TDRE 0x80 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ + #define SCI_RDRF 0x40 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ + #define SCI_ORER 0x20 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ + #define SCI_FER 0x10 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ + #define SCI_PER 0x08 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ + #define SCI_TEND 0x04 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ + /* SCI_MPB 0x02 * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ + /* SCI_MPBT 0x01 * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ + + #define SCI_ERRORS ( SCI_PER | SCI_FER | SCI_ORER) + + /* SCxSR SCIF */ + #define SCIF_ER 0x0080 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */ + #define SCIF_TEND 0x0040 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */ + #define SCIF_TDFE 0x0020 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */ + #define SCIF_BRK 0x0010 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */ + #define SCIF_FER 0x0008 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */ + #define SCIF_PER 0x0004 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */ + #define SCIF_RDF 0x0002 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */ + #define SCIF_DR 0x0001 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */ + + #if defined(CONFIG_CPU_SUBTYPE_SH7705) || \ + defined(CONFIG_CPU_SUBTYPE_SH7720) || \ + defined(CONFIG_CPU_SUBTYPE_SH7721) || \ + defined(CONFIG_ARCH_SH73A0) || \ + defined(CONFIG_ARCH_SH7367) || \ + defined(CONFIG_ARCH_SH7377) || \ + defined(CONFIG_ARCH_SH7372) + # define SCIF_ORER 0x0200 + # define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK | SCIF_ORER) + # define SCIF_RFDC_MASK 0x007f + # define SCIF_TXROOM_MAX 64 + #elif defined(CONFIG_CPU_SUBTYPE_SH7763) + # define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK ) + # define SCIF_RFDC_MASK 0x007f + # define SCIF_TXROOM_MAX 64 + /* SH7763 SCIF2 support */ + # define SCIF2_RFDC_MASK 0x001f + # define SCIF2_TXROOM_MAX 16 + #else + # define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK) + # define SCIF_RFDC_MASK 0x001f + # define SCIF_TXROOM_MAX 16 + #endif + + #ifndef SCIF_ORER + #define SCIF_ORER 0x0000 + #endif + + #define SCxSR_TEND(port) (((port)->type == PORT_SCI) ? SCI_TEND : SCIF_TEND) + #define SCxSR_ERRORS(port) (((port)->type == PORT_SCI) ? SCI_ERRORS : SCIF_ERRORS) + #define SCxSR_RDxF(port) (((port)->type == PORT_SCI) ? SCI_RDRF : SCIF_RDF) + #define SCxSR_TDxE(port) (((port)->type == PORT_SCI) ? SCI_TDRE : SCIF_TDFE) + #define SCxSR_FER(port) (((port)->type == PORT_SCI) ? SCI_FER : SCIF_FER) + #define SCxSR_PER(port) (((port)->type == PORT_SCI) ? SCI_PER : SCIF_PER) + #define SCxSR_BRK(port) (((port)->type == PORT_SCI) ? 0x00 : SCIF_BRK) + #define SCxSR_ORER(port) (((port)->type == PORT_SCI) ? SCI_ORER : SCIF_ORER) + + #if defined(CONFIG_CPU_SUBTYPE_SH7705) || \ + defined(CONFIG_CPU_SUBTYPE_SH7720) || \ + defined(CONFIG_CPU_SUBTYPE_SH7721) || \ + defined(CONFIG_ARCH_SH73A0) || \ + defined(CONFIG_ARCH_SH7367) || \ + defined(CONFIG_ARCH_SH7377) || \ + defined(CONFIG_ARCH_SH7372) + # define SCxSR_RDxF_CLEAR(port) (sci_in(port, SCxSR) & 0xfffc) + # define SCxSR_ERROR_CLEAR(port) (sci_in(port, SCxSR) & 0xfd73) + # define SCxSR_TDxE_CLEAR(port) (sci_in(port, SCxSR) & 0xffdf) + # define SCxSR_BREAK_CLEAR(port) (sci_in(port, SCxSR) & 0xffe3) + #else + # define SCxSR_RDxF_CLEAR(port) (((port)->type == PORT_SCI) ? 0xbc : 0x00fc) + # define SCxSR_ERROR_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x0073) + # define SCxSR_TDxE_CLEAR(port) (((port)->type == PORT_SCI) ? 0x78 : 0x00df) + # define SCxSR_BREAK_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x00e3) + #endif + + /* SCFCR */ + #define SCFCR_RFRST 0x0002 + #define SCFCR_TFRST 0x0004 + #define SCFCR_MCE 0x0008 + + #define SCI_MAJOR 204 + #define SCI_MINOR_START 8 + + #define SCI_IN(size, offset) \ + if ((size) == 8) { \ + return ioread8(port->membase + (offset)); \ + } else { \ + return ioread16(port->membase + (offset)); \ + } + #define SCI_OUT(size, offset, value) \ + if ((size) == 8) { \ + iowrite8(value, port->membase + (offset)); \ + } else if ((size) == 16) { \ + iowrite16(value, port->membase + (offset)); \ + } + + #define CPU_SCIx_FNS(name, sci_offset, sci_size, scif_offset, scif_size)\ + static inline unsigned int sci_##name##_in(struct uart_port *port) \ + { \ + if (port->type == PORT_SCIF || port->type == PORT_SCIFB) { \ + SCI_IN(scif_size, scif_offset) \ + } else { /* PORT_SCI or PORT_SCIFA */ \ + SCI_IN(sci_size, sci_offset); \ + } \ + } \ + static inline void sci_##name##_out(struct uart_port *port, unsigned int value) \ + { \ + if (port->type == PORT_SCIF || port->type == PORT_SCIFB) { \ + SCI_OUT(scif_size, scif_offset, value) \ + } else { /* PORT_SCI or PORT_SCIFA */ \ + SCI_OUT(sci_size, sci_offset, value); \ + } \ + } + + #ifdef CONFIG_H8300 + /* h8300 don't have SCIF */ + #define CPU_SCIF_FNS(name) \ + static inline unsigned int sci_##name##_in(struct uart_port *port) \ + { \ + return 0; \ + } \ + static inline void sci_##name##_out(struct uart_port *port, unsigned int value) \ + { \ + } + #else + #define CPU_SCIF_FNS(name, scif_offset, scif_size) \ + static inline unsigned int sci_##name##_in(struct uart_port *port) \ + { \ + SCI_IN(scif_size, scif_offset); \ + } \ + static inline void sci_##name##_out(struct uart_port *port, unsigned int value) \ + { \ + SCI_OUT(scif_size, scif_offset, value); \ + } + #endif + + #define CPU_SCI_FNS(name, sci_offset, sci_size) \ + static inline unsigned int sci_##name##_in(struct uart_port* port) \ + { \ + SCI_IN(sci_size, sci_offset); \ + } \ + static inline void sci_##name##_out(struct uart_port* port, unsigned int value) \ + { \ + SCI_OUT(sci_size, sci_offset, value); \ + } + + #if defined(CONFIG_CPU_SH3) || \ + defined(CONFIG_ARCH_SH73A0) || \ + defined(CONFIG_ARCH_SH7367) || \ + defined(CONFIG_ARCH_SH7377) || \ + defined(CONFIG_ARCH_SH7372) + #if defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712) + #define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \ + sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \ + h8_sci_offset, h8_sci_size) \ + CPU_SCIx_FNS(name, sh4_sci_offset, sh4_sci_size, sh4_scif_offset, sh4_scif_size) + #define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \ + CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size) + #elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \ + defined(CONFIG_CPU_SUBTYPE_SH7720) || \ + defined(CONFIG_CPU_SUBTYPE_SH7721) || \ + defined(CONFIG_ARCH_SH73A0) || \ + defined(CONFIG_ARCH_SH7367) || \ + defined(CONFIG_ARCH_SH7377) + #define SCIF_FNS(name, scif_offset, scif_size) \ + CPU_SCIF_FNS(name, scif_offset, scif_size) + #elif defined(CONFIG_ARCH_SH7372) + #define SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scifb_offset, sh4_scifb_size) \ + CPU_SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scifb_offset, sh4_scifb_size) + #define SCIF_FNS(name, scif_offset, scif_size) \ + CPU_SCIF_FNS(name, scif_offset, scif_size) + #else + #define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \ + sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \ + h8_sci_offset, h8_sci_size) \ + CPU_SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh3_scif_offset, sh3_scif_size) + #define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \ + CPU_SCIF_FNS(name, sh3_scif_offset, sh3_scif_size) + #endif + #elif defined(__H8300H__) || defined(__H8300S__) + #define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \ + sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \ + h8_sci_offset, h8_sci_size) \ + CPU_SCI_FNS(name, h8_sci_offset, h8_sci_size) + #define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \ + CPU_SCIF_FNS(name) + #elif defined(CONFIG_CPU_SUBTYPE_SH7723) ||\ + defined(CONFIG_CPU_SUBTYPE_SH7724) + #define SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scif_offset, sh4_scif_size) \ + CPU_SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scif_offset, sh4_scif_size) + #define SCIF_FNS(name, sh4_scif_offset, sh4_scif_size) \ + CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size) + #else + #define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \ + sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \ + h8_sci_offset, h8_sci_size) \ + CPU_SCIx_FNS(name, sh4_sci_offset, sh4_sci_size, sh4_scif_offset, sh4_scif_size) + #define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \ + CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size) + #endif + + #if defined(CONFIG_CPU_SUBTYPE_SH7705) || \ + defined(CONFIG_CPU_SUBTYPE_SH7720) || \ + defined(CONFIG_CPU_SUBTYPE_SH7721) || \ + defined(CONFIG_ARCH_SH73A0) || \ + defined(CONFIG_ARCH_SH7367) || \ + defined(CONFIG_ARCH_SH7377) + + SCIF_FNS(SCSMR, 0x00, 16) + SCIF_FNS(SCBRR, 0x04, 8) + SCIF_FNS(SCSCR, 0x08, 16) + SCIF_FNS(SCxSR, 0x14, 16) + SCIF_FNS(SCFCR, 0x18, 16) + SCIF_FNS(SCFDR, 0x1c, 16) + SCIF_FNS(SCxTDR, 0x20, 8) + SCIF_FNS(SCxRDR, 0x24, 8) + SCIF_FNS(SCLSR, 0x00, 0) + #elif defined(CONFIG_ARCH_SH7372) + SCIF_FNS(SCSMR, 0x00, 16) + SCIF_FNS(SCBRR, 0x04, 8) + SCIF_FNS(SCSCR, 0x08, 16) + SCIF_FNS(SCTDSR, 0x0c, 16) + SCIF_FNS(SCFER, 0x10, 16) + SCIF_FNS(SCxSR, 0x14, 16) + SCIF_FNS(SCFCR, 0x18, 16) + SCIF_FNS(SCFDR, 0x1c, 16) + SCIF_FNS(SCTFDR, 0x38, 16) + SCIF_FNS(SCRFDR, 0x3c, 16) + SCIx_FNS(SCxTDR, 0x20, 8, 0x40, 8) + SCIx_FNS(SCxRDR, 0x24, 8, 0x60, 8) + SCIF_FNS(SCLSR, 0x00, 0) + #elif defined(CONFIG_CPU_SUBTYPE_SH7723) ||\ + defined(CONFIG_CPU_SUBTYPE_SH7724) + SCIx_FNS(SCSMR, 0x00, 16, 0x00, 16) + SCIx_FNS(SCBRR, 0x04, 8, 0x04, 8) + SCIx_FNS(SCSCR, 0x08, 16, 0x08, 16) + SCIx_FNS(SCxTDR, 0x20, 8, 0x0c, 8) + SCIx_FNS(SCxSR, 0x14, 16, 0x10, 16) + SCIx_FNS(SCxRDR, 0x24, 8, 0x14, 8) + SCIx_FNS(SCSPTR, 0, 0, 0, 0) + SCIF_FNS(SCFCR, 0x18, 16) + SCIF_FNS(SCFDR, 0x1c, 16) + SCIF_FNS(SCLSR, 0x24, 16) + #else + /* reg SCI/SH3 SCI/SH4 SCIF/SH3 SCIF/SH4 SCI/H8*/ + /* name off sz off sz off sz off sz off sz*/ + SCIx_FNS(SCSMR, 0x00, 8, 0x00, 8, 0x00, 8, 0x00, 16, 0x00, 8) + SCIx_FNS(SCBRR, 0x02, 8, 0x04, 8, 0x02, 8, 0x04, 8, 0x01, 8) + SCIx_FNS(SCSCR, 0x04, 8, 0x08, 8, 0x04, 8, 0x08, 16, 0x02, 8) + SCIx_FNS(SCxTDR, 0x06, 8, 0x0c, 8, 0x06, 8, 0x0C, 8, 0x03, 8) + SCIx_FNS(SCxSR, 0x08, 8, 0x10, 8, 0x08, 16, 0x10, 16, 0x04, 8) + SCIx_FNS(SCxRDR, 0x0a, 8, 0x14, 8, 0x0A, 8, 0x14, 8, 0x05, 8) + SCIF_FNS(SCFCR, 0x0c, 8, 0x18, 16) + #if defined(CONFIG_CPU_SUBTYPE_SH7760) || \ + defined(CONFIG_CPU_SUBTYPE_SH7780) || \ + defined(CONFIG_CPU_SUBTYPE_SH7785) || \ + defined(CONFIG_CPU_SUBTYPE_SH7786) + SCIF_FNS(SCFDR, 0x0e, 16, 0x1C, 16) + SCIF_FNS(SCTFDR, 0x0e, 16, 0x1C, 16) + SCIF_FNS(SCRFDR, 0x0e, 16, 0x20, 16) + SCIF_FNS(SCSPTR, 0, 0, 0x24, 16) + SCIF_FNS(SCLSR, 0, 0, 0x28, 16) + #elif defined(CONFIG_CPU_SUBTYPE_SH7763) + SCIF_FNS(SCFDR, 0, 0, 0x1C, 16) -SCIF_FNS(SCSPTR2, 0, 0, 0x20, 16) + SCIF_FNS(SCTFDR, 0x0e, 16, 0x1C, 16) + SCIF_FNS(SCRFDR, 0x0e, 16, 0x20, 16) + SCIF_FNS(SCSPTR, 0, 0, 0x24, 16) + SCIF_FNS(SCLSR, 0, 0, 0x28, 16) + #else + SCIF_FNS(SCFDR, 0x0e, 16, 0x1C, 16) + #if defined(CONFIG_CPU_SUBTYPE_SH7722) + SCIF_FNS(SCSPTR, 0, 0, 0, 0) + #else + SCIF_FNS(SCSPTR, 0, 0, 0x20, 16) + #endif + SCIF_FNS(SCLSR, 0, 0, 0x24, 16) + #endif + #endif + #define sci_in(port, reg) sci_##reg##_in(port) + #define sci_out(port, reg, value) sci_##reg##_out(port, value) + + /* H8/300 series SCI pins assignment */ + #if defined(__H8300H__) || defined(__H8300S__) + static const struct __attribute__((packed)) { + int port; /* GPIO port no */ + unsigned short rx,tx; /* GPIO bit no */ + } h8300_sci_pins[] = { + #if defined(CONFIG_H83007) || defined(CONFIG_H83068) + { /* SCI0 */ + .port = H8300_GPIO_P9, + .rx = H8300_GPIO_B2, + .tx = H8300_GPIO_B0, + }, + { /* SCI1 */ + .port = H8300_GPIO_P9, + .rx = H8300_GPIO_B3, + .tx = H8300_GPIO_B1, + }, + { /* SCI2 */ + .port = H8300_GPIO_PB, + .rx = H8300_GPIO_B7, + .tx = H8300_GPIO_B6, + } + #elif defined(CONFIG_H8S2678) + { /* SCI0 */ + .port = H8300_GPIO_P3, + .rx = H8300_GPIO_B2, + .tx = H8300_GPIO_B0, + }, + { /* SCI1 */ + .port = H8300_GPIO_P3, + .rx = H8300_GPIO_B3, + .tx = H8300_GPIO_B1, + }, + { /* SCI2 */ + .port = H8300_GPIO_P5, + .rx = H8300_GPIO_B1, + .tx = H8300_GPIO_B0, + } + #endif + }; + #endif + + #if defined(CONFIG_CPU_SUBTYPE_SH7706) || \ + defined(CONFIG_CPU_SUBTYPE_SH7707) || \ + defined(CONFIG_CPU_SUBTYPE_SH7708) || \ + defined(CONFIG_CPU_SUBTYPE_SH7709) + static inline int sci_rxd_in(struct uart_port *port) + { + if (port->mapbase == 0xfffffe80) + return __raw_readb(SCPDR)&0x01 ? 1 : 0; /* SCI */ + return 1; + } + #elif defined(CONFIG_CPU_SUBTYPE_SH7750) || \ + defined(CONFIG_CPU_SUBTYPE_SH7751) || \ + defined(CONFIG_CPU_SUBTYPE_SH7751R) || \ + defined(CONFIG_CPU_SUBTYPE_SH7750R) || \ + defined(CONFIG_CPU_SUBTYPE_SH7750S) || \ + defined(CONFIG_CPU_SUBTYPE_SH7091) + static inline int sci_rxd_in(struct uart_port *port) + { + if (port->mapbase == 0xffe00000) + return __raw_readb(SCSPTR1)&0x01 ? 1 : 0; /* SCI */ + return 1; + } + #elif defined(__H8300H__) || defined(__H8300S__) + static inline int sci_rxd_in(struct uart_port *port) + { + int ch = (port->mapbase - SMR0) >> 3; + return (H8300_SCI_DR(ch) & h8300_sci_pins[ch].rx) ? 1 : 0; + } + #else /* default case for non-SCI processors */ + static inline int sci_rxd_in(struct uart_port *port) + { + return 1; + } + #endif