/* MN10300 On-chip serial port UART driver * * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence * as published by the Free Software Foundation; either version * 2 of the Licence, or (at your option) any later version. */ static const char serial_name[] = "MN10300 Serial driver"; static const char serial_version[] = "mn10300_serial-1.0"; static const char serial_revdate[] = "2007-11-06"; #if defined(CONFIG_MN10300_TTYSM_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) #define SUPPORT_SYSRQ #endif #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 "mn10300-serial.h" #ifdef CONFIG_SMP #undef GxICR #define GxICR(X) CROSS_GxICR(X, 0) #endif /* CONFIG_SMP */ #define kenter(FMT, ...) \ printk(KERN_DEBUG "-->%s(" FMT ")\n", __func__, ##__VA_ARGS__) #define _enter(FMT, ...) \ no_printk(KERN_DEBUG "-->%s(" FMT ")\n", __func__, ##__VA_ARGS__) #define kdebug(FMT, ...) \ printk(KERN_DEBUG "--- " FMT "\n", ##__VA_ARGS__) #define _debug(FMT, ...) \ no_printk(KERN_DEBUG "--- " FMT "\n", ##__VA_ARGS__) #define kproto(FMT, ...) \ printk(KERN_DEBUG "### MNSERIAL " FMT " ###\n", ##__VA_ARGS__) #define _proto(FMT, ...) \ no_printk(KERN_DEBUG "### MNSERIAL " FMT " ###\n", ##__VA_ARGS__) #ifndef CODMSB /* c_cflag bit meaning */ #define CODMSB 004000000000 /* change Transfer bit-order */ #endif #define NR_UARTS 3 #ifdef CONFIG_MN10300_TTYSM_CONSOLE static void mn10300_serial_console_write(struct console *co, const char *s, unsigned count); static int __init mn10300_serial_console_setup(struct console *co, char *options); static struct uart_driver mn10300_serial_driver; static struct console mn10300_serial_console = { .name = "ttySM", .write = mn10300_serial_console_write, .device = uart_console_device, .setup = mn10300_serial_console_setup, .flags = CON_PRINTBUFFER, .index = -1, .data = &mn10300_serial_driver, }; #endif static struct uart_driver mn10300_serial_driver = { .owner = NULL, .driver_name = "mn10300-serial", .dev_name = "ttySM", .major = TTY_MAJOR, .minor = 128, .nr = NR_UARTS, #ifdef CONFIG_MN10300_TTYSM_CONSOLE .cons = &mn10300_serial_console, #endif }; static unsigned int mn10300_serial_tx_empty(struct uart_port *); static void mn10300_serial_set_mctrl(struct uart_port *, unsigned int mctrl); static unsigned int mn10300_serial_get_mctrl(struct uart_port *); static void mn10300_serial_stop_tx(struct uart_port *); static void mn10300_serial_start_tx(struct uart_port *); static void mn10300_serial_send_xchar(struct uart_port *, char ch); static void mn10300_serial_stop_rx(struct uart_port *); static void mn10300_serial_enable_ms(struct uart_port *); static void mn10300_serial_break_ctl(struct uart_port *, int ctl); static int mn10300_serial_startup(struct uart_port *); static void mn10300_serial_shutdown(struct uart_port *); static void mn10300_serial_set_termios(struct uart_port *, struct ktermios *new, struct ktermios *old); static const char *mn10300_serial_type(struct uart_port *); static void mn10300_serial_release_port(struct uart_port *); static int mn10300_serial_request_port(struct uart_port *); static void mn10300_serial_config_port(struct uart_port *, int); static int mn10300_serial_verify_port(struct uart_port *, struct serial_struct *); static const struct uart_ops mn10300_serial_ops = { .tx_empty = mn10300_serial_tx_empty, .set_mctrl = mn10300_serial_set_mctrl, .get_mctrl = mn10300_serial_get_mctrl, .stop_tx = mn10300_serial_stop_tx, .start_tx = mn10300_serial_start_tx, .send_xchar = mn10300_serial_send_xchar, .stop_rx = mn10300_serial_stop_rx, .enable_ms = mn10300_serial_enable_ms, .break_ctl = mn10300_serial_break_ctl, .startup = mn10300_serial_startup, .shutdown = mn10300_serial_shutdown, .set_termios = mn10300_serial_set_termios, .type = mn10300_serial_type, .release_port = mn10300_serial_release_port, .request_port = mn10300_serial_request_port, .config_port = mn10300_serial_config_port, .verify_port = mn10300_serial_verify_port, }; static irqreturn_t mn10300_serial_interrupt(int irq, void *dev_id); /* * the first on-chip serial port: ttySM0 (aka SIF0) */ #ifdef CONFIG_MN10300_TTYSM0 struct mn10300_serial_port mn10300_serial_port_sif0 = { .uart.ops = &mn10300_serial_ops, .uart.membase = (void __iomem *) &SC0CTR, .uart.mapbase = (unsigned long) &SC0CTR, .uart.iotype = UPIO_MEM, .uart.irq = 0, .uart.uartclk = 0, /* MN10300_IOCLK, */ .uart.fifosize = 1, .uart.flags = UPF_BOOT_AUTOCONF, .uart.line = 0, .uart.type = PORT_MN10300, .uart.lock = __SPIN_LOCK_UNLOCKED(mn10300_serial_port_sif0.uart.lock), .name = "ttySM0", ._iobase = &SC0CTR, ._control = &SC0CTR, ._status = (volatile u8 *)&SC0STR, ._intr = &SC0ICR, ._rxb = &SC0RXB, ._txb = &SC0TXB, .rx_name = "ttySM0:Rx", .tx_name = "ttySM0:Tx", #if defined(CONFIG_MN10300_TTYSM0_TIMER8) .tm_name = "ttySM0:Timer8", ._tmxmd = &TM8MD, ._tmxbr = &TM8BR, ._tmicr = &TM8ICR, .tm_irq = TM8IRQ, .div_timer = MNSCx_DIV_TIMER_16BIT, #elif defined(CONFIG_MN10300_TTYSM0_TIMER0) .tm_name = "ttySM0:Timer0", ._tmxmd = &TM0MD, ._tmxbr = (volatile u16 *)&TM0BR, ._tmicr = &TM0ICR, .tm_irq = TM0IRQ, .div_timer = MNSCx_DIV_TIMER_8BIT, #elif defined(CONFIG_MN10300_TTYSM0_TIMER2) .tm_name = "ttySM0:Timer2", ._tmxmd = &TM2MD, ._tmxbr = (volatile u16 *)&TM2BR, ._tmicr = &TM2ICR, .tm_irq = TM2IRQ, .div_timer = MNSCx_DIV_TIMER_8BIT, #else #error "Unknown config for ttySM0" #endif .rx_irq = SC0RXIRQ, .tx_irq = SC0TXIRQ, .rx_icr = &GxICR(SC0RXIRQ), .tx_icr = &GxICR(SC0TXIRQ), .clock_src = MNSCx_CLOCK_SRC_IOCLK, .options = 0, #ifdef CONFIG_GDBSTUB_ON_TTYSM0 .gdbstub = 1, #endif }; #endif /* CONFIG_MN10300_TTYSM0 */ /* * the second on-chip serial port: ttySM1 (aka SIF1) */ #ifdef CONFIG_MN10300_TTYSM1 struct mn10300_serial_port mn10300_serial_port_sif1 = { .uart.ops = &mn10300_serial_ops, .uart.membase = (void __iomem *) &SC1CTR, .uart.mapbase = (unsigned long) &SC1CTR, .uart.iotype = UPIO_MEM, .uart.irq = 0, .uart.uartclk = 0, /* MN10300_IOCLK, */ .uart.fifosize = 1, .uart.flags = UPF_BOOT_AUTOCONF, .uart.line = 1, .uart.type = PORT_MN10300, .uart.lock = __SPIN_LOCK_UNLOCKED(mn10300_serial_port_sif1.uart.lock), .name = "ttySM1", ._iobase = &SC1CTR, ._control = &SC1CTR, ._status = (volatile u8 *)&SC1STR, ._intr = &SC1ICR, ._rxb = &SC1RXB, ._txb = &SC1TXB, .rx_name = "ttySM1:Rx", .tx_name = "ttySM1:Tx", #if defined(CONFIG_MN10300_TTYSM1_TIMER9) .tm_name = "ttySM1:Timer9", ._tmxmd = &TM9MD, ._tmxbr = &TM9BR, ._tmicr = &TM9ICR, .tm_irq = TM9IRQ, .div_timer = MNSCx_DIV_TIMER_16BIT, #elif defined(CONFIG_MN10300_TTYSM1_TIMER3) .tm_name = "ttySM1:Timer3", ._tmxmd = &TM3MD, ._tmxbr = (volatile u16 *)&TM3BR, ._tmicr = &TM3ICR, .tm_irq = TM3IRQ, .div_timer = MNSCx_DIV_TIMER_8BIT, #elif defined(CONFIG_MN10300_TTYSM1_TIMER12) .tm_name = "ttySM1/Timer12", ._tmxmd = &TM12MD, ._tmxbr = &TM12BR, ._tmicr = &TM12ICR, .tm_irq = TM12IRQ, .div_timer = MNSCx_DIV_TIMER_16BIT, #else #error "Unknown config for ttySM1" #endif .rx_irq = SC1RXIRQ, .tx_irq = SC1TXIRQ, .rx_icr = &GxICR(SC1RXIRQ), .tx_icr = &GxICR(SC1TXIRQ), .clock_src = MNSCx_CLOCK_SRC_IOCLK, .options = 0, #ifdef CONFIG_GDBSTUB_ON_TTYSM1 .gdbstub = 1, #endif }; #endif /* CONFIG_MN10300_TTYSM1 */ /* * the third on-chip serial port: ttySM2 (aka SIF2) */ #ifdef CONFIG_MN10300_TTYSM2 struct mn10300_serial_port mn10300_serial_port_sif2 = { .uart.ops = &mn10300_serial_ops, .uart.membase = (void __iomem *) &SC2CTR, .uart.mapbase = (unsigned long) &SC2CTR, .uart.iotype = UPIO_MEM, .uart.irq = 0, .uart.uartclk = 0, /* MN10300_IOCLK, */ .uart.fifosize = 1, .uart.flags = UPF_BOOT_AUTOCONF, .uart.line = 2, #ifdef CONFIG_MN10300_TTYSM2_CTS .uart.type = PORT_MN10300_CTS, #else .uart.type = PORT_MN10300, #endif .uart.lock = __SPIN_LOCK_UNLOCKED(mn10300_serial_port_sif2.uart.lock), .name = "ttySM2", ._iobase = &SC2CTR, ._control = &SC2CTR, ._status = (volatile u8 *)&SC2STR, ._intr = &SC2ICR, ._rxb = &SC2RXB, ._txb = &SC2TXB, .rx_name = "ttySM2:Rx", .tx_name = "ttySM2:Tx", #if defined(CONFIG_MN10300_TTYSM2_TIMER10) .tm_name = "ttySM2/Timer10", ._tmxmd = &TM10MD, ._tmxbr = &TM10BR, ._tmicr = &TM10ICR, .tm_irq = TM10IRQ, .div_timer = MNSCx_DIV_TIMER_16BIT, #elif defined(CONFIG_MN10300_TTYSM2_TIMER9) .tm_name = "ttySM2/Timer9", ._tmxmd = &TM9MD, ._tmxbr = &TM9BR, ._tmicr = &TM9ICR, .tm_irq = TM9IRQ, .div_timer = MNSCx_DIV_TIMER_16BIT, #elif defined(CONFIG_MN10300_TTYSM2_TIMER1) .tm_name = "ttySM2/Timer1", ._tmxmd = &TM1MD, ._tmxbr = (volatile u16 *)&TM1BR, ._tmicr = &TM1ICR, .tm_irq = TM1IRQ, .div_timer = MNSCx_DIV_TIMER_8BIT, #elif defined(CONFIG_MN10300_TTYSM2_TIMER3) .tm_name = "ttySM2/Timer3", ._tmxmd = &TM3MD, ._tmxbr = (volatile u16 *)&TM3BR, ._tmicr = &TM3ICR, .tm_irq = TM3IRQ, .div_timer = MNSCx_DIV_TIMER_8BIT, #else #error "Unknown config for ttySM2" #endif .rx_irq = SC2RXIRQ, .tx_irq = SC2TXIRQ, .rx_icr = &GxICR(SC2RXIRQ), .tx_icr = &GxICR(SC2TXIRQ), .clock_src = MNSCx_CLOCK_SRC_IOCLK, #ifdef CONFIG_MN10300_TTYSM2_CTS .options = MNSCx_OPT_CTS, #else .options = 0, #endif #ifdef CONFIG_GDBSTUB_ON_TTYSM2 .gdbstub = 1, #endif }; #endif /* CONFIG_MN10300_TTYSM2 */ /* * list of available serial ports */ struct mn10300_serial_port *mn10300_serial_ports[NR_UARTS + 1] = { #ifdef CONFIG_MN10300_TTYSM0 [0] = &mn10300_serial_port_sif0, #endif #ifdef CONFIG_MN10300_TTYSM1 [1] = &mn10300_serial_port_sif1, #endif #ifdef CONFIG_MN10300_TTYSM2 [2] = &mn10300_serial_port_sif2, #endif [NR_UARTS] = NULL, }; /* * we abuse the serial ports' baud timers' interrupt lines to get the ability * to deliver interrupts to userspace as we use the ports' interrupt lines to * do virtual DMA on account of the ports having no hardware FIFOs * * we can generate an interrupt manually in the assembly stubs by writing to * the enable and detect bits in the interrupt control register, so all we need * to do here is disable the interrupt line * * note that we can't just leave the line enabled as the baud rate timer *also* * generates interrupts */ static void mn10300_serial_mask_ack(unsigned int irq) { unsigned long flags; u16 tmp; flags = arch_local_cli_save(); GxICR(irq) = GxICR_LEVEL_6; tmp = GxICR(irq); /* flush write buffer */ arch_local_irq_restore(flags); } static void mn10300_serial_nop(unsigned int irq) { } static struct irq_chip mn10300_serial_pic = { .name = "mnserial", .ack = mn10300_serial_mask_ack, .mask = mn10300_serial_mask_ack, .mask_ack = mn10300_serial_mask_ack, .unmask = mn10300_serial_nop, }; /* * serial virtual DMA interrupt jump table */ struct mn10300_serial_int mn10300_serial_int_tbl[NR_IRQS]; static void mn10300_serial_dis_tx_intr(struct mn10300_serial_port *port) { unsigned long flags; u16 x; flags = arch_local_cli_save(); *port->tx_icr = NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL); x = *port->tx_icr; arch_local_irq_restore(flags); } static void mn10300_serial_en_tx_intr(struct mn10300_serial_port *port) { unsigned long flags; u16 x; flags = arch_local_cli_save(); *port->tx_icr = NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL) | GxICR_ENABLE; x = *port->tx_icr; arch_local_irq_restore(flags); } static void mn10300_serial_dis_rx_intr(struct mn10300_serial_port *port) { unsigned long flags; u16 x; flags = arch_local_cli_save(); *port->rx_icr = NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL); x = *port->rx_icr; arch_local_irq_restore(flags); } /* * multi-bit equivalent of test_and_clear_bit() */ static int mask_test_and_clear(volatile u8 *ptr, u8 mask) { u32 epsw; asm volatile(" bclr %1,(%2) \n" " mov epsw,%0 \n" : "=d"(epsw) : "d"(mask), "a"(ptr) : "cc", "memory"); return !(epsw & EPSW_FLAG_Z); } /* * receive chars from the ring buffer for this serial port * - must do break detection here (not done in the UART) */ static void mn10300_serial_receive_interrupt(struct mn10300_serial_port *port) { struct uart_icount *icount = &port->uart.icount; struct tty_struct *tty = port->uart.state->port.tty; unsigned ix; int count; u8 st, ch, push, status, overrun; _enter("%s", port->name); push = 0; count = CIRC_CNT(port->rx_inp, port->rx_outp, MNSC_BUFFER_SIZE); count = tty_buffer_request_room(tty, count); if (count == 0) { if (!tty->low_latency) tty_flip_buffer_push(tty); return; } try_again: /* pull chars out of the hat */ ix = port->rx_outp; if (ix == port->rx_inp) { if (push && !tty->low_latency) tty_flip_buffer_push(tty); return; } ch = port->rx_buffer[ix++]; st = port->rx_buffer[ix++]; smp_rmb(); port->rx_outp = ix & (MNSC_BUFFER_SIZE - 1); port->uart.icount.rx++; st &= SC01STR_FEF | SC01STR_PEF | SC01STR_OEF; status = 0; overrun = 0; /* the UART doesn't detect BREAK, so we have to do that ourselves * - it starts as a framing error on a NUL character * - then we count another two NUL characters before issuing TTY_BREAK * - then we end on a normal char or one that has all the bottom bits * zero and the top bits set */ switch (port->rx_brk) { case 0: /* not breaking at the moment */ break; case 1: if (st & SC01STR_FEF && ch == 0) { port->rx_brk = 2; goto try_again; } goto not_break; case 2: if (st & SC01STR_FEF && ch == 0) { port->rx_brk = 3; _proto("Rx Break Detected"); icount->brk++; if (uart_handle_break(&port->uart)) goto ignore_char; status |= 1 << TTY_BREAK; goto insert; } goto not_break; default: if (st & (SC01STR_FEF | SC01STR_PEF | SC01STR_OEF)) goto try_again; /* still breaking */ port->rx_brk = 0; /* end of the break */ switch (ch) { case 0xFF: case 0xFE: case 0xFC: case 0xF8: case 0xF0: case 0xE0: case 0xC0: case 0x80: case 0x00: /* discard char at probable break end */ goto try_again; } break; } process_errors: /* handle framing error */ if (st & SC01STR_FEF) { if (ch == 0) { /* framing error with NUL char is probably a BREAK */ port->rx_brk = 1; goto try_again; } _proto("Rx Framing Error"); icount->frame++; status |= 1 << TTY_FRAME; } /* handle parity error */ if (st & SC01STR_PEF) { _proto("Rx Parity Error"); icount->parity++; status = TTY_PARITY; } /* handle normal char */ if (status == 0) { if (uart_handle_sysrq_char(&port->uart, ch)) goto ignore_char; status = (1 << TTY_NORMAL); } /* handle overrun error */ if (st & SC01STR_OEF) { if (port->rx_brk) goto try_again; _proto("Rx Overrun Error"); icount->overrun++; overrun = 1; } insert: status &= port->uart.read_status_mask; if (!overrun && !(status & port->uart.ignore_status_mask)) { int flag; if (status & (1 << TTY_BREAK)) flag = TTY_BREAK; else if (status & (1 << TTY_PARITY)) flag = TTY_PARITY; else if (status & (1 << TTY_FRAME)) flag = TTY_FRAME; else flag = TTY_NORMAL; tty_insert_flip_char(tty, ch, flag); } /* overrun is special, since it's reported immediately, and doesn't * affect the current character */ if (overrun) tty_insert_flip_char(tty, 0, TTY_OVERRUN); count--; if (count <= 0) { if (!tty->low_latency) tty_flip_buffer_push(tty); return; } ignore_char: push = 1; goto try_again; not_break: port->rx_brk = 0; goto process_errors; } /* * handle an interrupt from the serial transmission "virtual DMA" driver * - note: the interrupt routine will disable its own interrupts when the Tx * buffer is empty */ static void mn10300_serial_transmit_interrupt(struct mn10300_serial_port *port) { _enter("%s", port->name); if (!port->uart.state || !port->uart.state->port.tty) { mn10300_serial_dis_tx_intr(port); return; } if (uart_tx_stopped(&port->uart) || uart_circ_empty(&port->uart.state->xmit)) mn10300_serial_dis_tx_intr(port); if (uart_circ_chars_pending(&port->uart.state->xmit) < WAKEUP_CHARS) uart_write_wakeup(&port->uart); } /* * deal with a change in the status of the CTS line */ static void mn10300_serial_cts_changed(struct mn10300_serial_port *port, u8 st) { u16 ctr; port->tx_cts = st; port->uart.icount.cts++; /* flip the CTS state selector flag to interrupt when it changes * back */ ctr = *port->_control; ctr ^= SC2CTR_TWS; *port->_control = ctr; uart_handle_cts_change(&port->uart, st & SC2STR_CTS); wake_up_interruptible(&port->uart.state->port.delta_msr_wait); } /* * handle a virtual interrupt generated by the lower level "virtual DMA" * routines (irq is the baud timer interrupt) */ static irqreturn_t mn10300_serial_interrupt(int irq, void *dev_id) { struct mn10300_serial_port *port = dev_id; u8 st; spin_lock(&port->uart.lock); if (port->intr_flags) { _debug("INT %s: %x", port->name, port->intr_flags); if (mask_test_and_clear(&port->intr_flags, MNSCx_RX_AVAIL)) mn10300_serial_receive_interrupt(port); if (mask_test_and_clear(&port->intr_flags, MNSCx_TX_SPACE | MNSCx_TX_EMPTY)) mn10300_serial_transmit_interrupt(port); } /* the only modem control line amongst the whole lot is CTS on * serial port 2 */ if (port->type == PORT_MN10300_CTS) { st = *port->_status; if ((port->tx_cts ^ st) & SC2STR_CTS) mn10300_serial_cts_changed(port, st); } spin_unlock(&port->uart.lock); return IRQ_HANDLED; } /* * return indication of whether the hardware transmit buffer is empty */ static unsigned int mn10300_serial_tx_empty(struct uart_port *_port) { struct mn10300_serial_port *port = container_of(_port, struct mn10300_serial_port, uart); _enter("%s", port->name); return (*port->_status & (SC01STR_TXF | SC01STR_TBF)) ? 0 : TIOCSER_TEMT; } /* * set the modem control lines (we don't have any) */ static void mn10300_serial_set_mctrl(struct uart_port *_port, unsigned int mctrl) { struct mn10300_serial_port *port __attribute__ ((unused)) = container_of(_port, struct mn10300_serial_port, uart); _enter("%s,%x", port->name, mctrl); } /* * get the modem control line statuses */ static unsigned int mn10300_serial_get_mctrl(struct uart_port *_port) { struct mn10300_serial_port *port = container_of(_port, struct mn10300_serial_port, uart); _enter("%s", port->name); if (port->type == PORT_MN10300_CTS && !(*port->_status & SC2STR_CTS)) return TIOCM_CAR | TIOCM_DSR; return TIOCM_CAR | TIOCM_CTS | TIOCM_DSR; } /* * stop transmitting characters */ static void mn10300_serial_stop_tx(struct uart_port *_port) { struct mn10300_serial_port *port = container_of(_port, struct mn10300_serial_port, uart); _enter("%s", port->name); /* disable the virtual DMA */ mn10300_serial_dis_tx_intr(port); } /* * start transmitting characters * - jump-start transmission if it has stalled * - enable the serial Tx interrupt (used by the virtual DMA controller) * - force an interrupt to happen if necessary */ static void mn10300_serial_start_tx(struct uart_port *_port) { struct mn10300_serial_port *port = container_of(_port, struct mn10300_serial_port, uart); u16 x; _enter("%s{%lu}", port->name, CIRC_CNT(&port->uart.state->xmit.head, &port->uart.state->xmit.tail, UART_XMIT_SIZE)); /* kick the virtual DMA controller */ arch_local_cli(); x = *port->tx_icr; x |= GxICR_ENABLE; if (*port->_status & SC01STR_TBF) x &= ~(GxICR_REQUEST | GxICR_DETECT); else x |= GxICR_REQUEST | GxICR_DETECT; _debug("CTR=%04hx ICR=%02hx STR=%04x TMD=%02hx TBR=%04hx ICR=%04hx", *port->_control, *port->_intr, *port->_status, *port->_tmxmd, (port->div_timer == MNSCx_DIV_TIMER_8BIT) ? *(volatile u8 *)port->_tmxbr : *port->_tmxbr, *port->tx_icr); *port->tx_icr = x; x = *port->tx_icr; arch_local_sti(); } /* * transmit a high-priority XON/XOFF character */ static void mn10300_serial_send_xchar(struct uart_port *_port, char ch) { struct mn10300_serial_port *port = container_of(_port, struct mn10300_serial_port, uart); _enter("%s,%02x", port->name, ch); if (likely(port->gdbstub)) { port->tx_xchar = ch; if (ch) mn10300_serial_en_tx_intr(port); } } /* * stop receiving characters * - called whilst the port is being closed */ static void mn10300_serial_stop_rx(struct uart_port *_port) { struct mn10300_serial_port *port = container_of(_port, struct mn10300_serial_port, uart); u16 ctr; _enter("%s", port->name); ctr = *port->_control; ctr &= ~SC01CTR_RXE; *port->_control = ctr; mn10300_serial_dis_rx_intr(port); } /* * enable modem status interrupts */ static void mn10300_serial_enable_ms(struct uart_port *_port) { struct mn10300_serial_port *port = container_of(_port, struct mn10300_serial_port, uart); u16 ctr, cts; _enter("%s", port->name); if (port->type == PORT_MN10300_CTS) { /* want to interrupt when CTS goes low if CTS is now high and * vice versa */ port->tx_cts = *port->_status; cts = (port->tx_cts & SC2STR_CTS) ? SC2CTR_TWE : SC2CTR_TWE | SC2CTR_TWS; ctr = *port->_control; ctr &= ~SC2CTR_TWS; ctr |= cts; *port->_control = ctr; mn10300_serial_en_tx_intr(port); } } /* * transmit or cease transmitting a break signal */ static void mn10300_serial_break_ctl(struct uart_port *_port, int ctl) { struct mn10300_serial_port *port = container_of(_port, struct mn10300_serial_port, uart); _enter("%s,%d", port->name, ctl); if (ctl) { /* tell the virtual DMA handler to assert BREAK */ port->tx_break = 1; mn10300_serial_en_tx_intr(port); } else { port->tx_break = 0; *port->_control &= ~SC01CTR_BKE; mn10300_serial_en_tx_intr(port); } } /* * grab the interrupts and enable the port for reception */ static int mn10300_serial_startup(struct uart_port *_port) { struct mn10300_serial_port *port = container_of(_port, struct mn10300_serial_port, uart); struct mn10300_serial_int *pint; _enter("%s{%d}", port->name, port->gdbstub); if (unlikely(port->gdbstub)) return -EBUSY; /* allocate an Rx buffer for the virtual DMA handler */ port->rx_buffer = kmalloc(MNSC_BUFFER_SIZE, GFP_KERNEL); if (!port->rx_buffer) return -ENOMEM; port->rx_inp = port->rx_outp = 0; /* finally, enable the device */ *port->_intr = SC01ICR_TI; *port->_control |= SC01CTR_TXE | SC01CTR_RXE; pint = &mn10300_serial_int_tbl[port->rx_irq]; pint->port = port; pint->vdma = mn10300_serial_vdma_rx_handler; pint = &mn10300_serial_int_tbl[port->tx_irq]; pint->port = port; pint->vdma = mn10300_serial_vdma_tx_handler; set_intr_level(port->rx_irq, NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL)); set_intr_level(port->tx_irq, NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL)); set_irq_chip(port->tm_irq, &mn10300_serial_pic); if (request_irq(port->rx_irq, mn10300_serial_interrupt, IRQF_DISABLED, port->rx_name, port) < 0) goto error; if (request_irq(port->tx_irq, mn10300_serial_interrupt, IRQF_DISABLED, port->tx_name, port) < 0) goto error2; if (request_irq(port->tm_irq, mn10300_serial_interrupt, IRQF_DISABLED, port->tm_name, port) < 0) goto error3; mn10300_serial_mask_ack(port->tm_irq); return 0; error3: free_irq(port->tx_irq, port); error2: free_irq(port->rx_irq, port); error: kfree(port->rx_buffer); port->rx_buffer = NULL; return -EBUSY; } /* * shutdown the port and release interrupts */ static void mn10300_serial_shutdown(struct uart_port *_port) { u16 x; struct mn10300_serial_port *port = container_of(_port, struct mn10300_serial_port, uart); _enter("%s", port->name); /* disable the serial port and its baud rate timer */ port->tx_break = 0; *port->_control &= ~(SC01CTR_TXE | SC01CTR_RXE | SC01CTR_BKE); *port->_tmxmd = 0; if (port->rx_buffer) { void *buf = port->rx_buffer; port->rx_buffer = NULL; kfree(buf); } /* disable all intrs */ free_irq(port->tm_irq, port); free_irq(port->rx_irq, port); free_irq(port->tx_irq, port); arch_local_cli(); *port->rx_icr = NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL); x = *port->rx_icr; *port->tx_icr = NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL); x = *port->tx_icr; arch_local_sti(); } /* * this routine is called to set the UART divisor registers to match the * specified baud rate for a serial port. */ static void mn10300_serial_change_speed(struct mn10300_serial_port *port, struct ktermios *new, struct ktermios *old) { unsigned long flags; unsigned long ioclk = port->ioclk; unsigned cflag; int baud, bits, xdiv, tmp; u16 tmxbr, scxctr; u8 tmxmd, battempt; u8 div_timer = port->div_timer; _enter("%s{%lu}", port->name, ioclk); /* byte size and parity */ cflag = new->c_cflag; switch (cflag & CSIZE) { case CS7: scxctr = SC01CTR_CLN_7BIT; bits = 9; break; case CS8: scxctr = SC01CTR_CLN_8BIT; bits = 10; break; default: scxctr = SC01CTR_CLN_8BIT; bits = 10; break; } if (cflag & CSTOPB) { scxctr |= SC01CTR_STB_2BIT; bits++; } if (cflag & PARENB) { bits++; if (cflag & PARODD) scxctr |= SC01CTR_PB_ODD; #ifdef CMSPAR else if (cflag & CMSPAR) scxctr |= SC01CTR_PB_FIXED0; #endif else scxctr |= SC01CTR_PB_EVEN; } /* Determine divisor based on baud rate */ battempt = 0; switch (port->uart.line) { #ifdef CONFIG_MN10300_TTYSM0 case 0: /* ttySM0 */ #if defined(CONFIG_MN10300_TTYSM0_TIMER8) scxctr |= SC0CTR_CK_TM8UFLOW_8; #elif defined(CONFIG_MN10300_TTYSM0_TIMER0) scxctr |= SC0CTR_CK_TM0UFLOW_8; #elif defined(CONFIG_MN10300_TTYSM0_TIMER2) scxctr |= SC0CTR_CK_TM2UFLOW_8; #else #error "Unknown config for ttySM0" #endif break; #endif /* CONFIG_MN10300_TTYSM0 */ #ifdef CONFIG_MN10300_TTYSM1 case 1: /* ttySM1 */ #if defined(CONFIG_AM33_2) || defined(CONFIG_AM33_3) #if defined(CONFIG_MN10300_TTYSM1_TIMER9) scxctr |= SC1CTR_CK_TM9UFLOW_8; #elif defined(CONFIG_MN10300_TTYSM1_TIMER3) scxctr |= SC1CTR_CK_TM3UFLOW_8; #else #error "Unknown config for ttySM1" #endif #else /* CONFIG_AM33_2 || CONFIG_AM33_3 */ #if defined(CONFIG_MN10300_TTYSM1_TIMER12) scxctr |= SC1CTR_CK_TM12UFLOW_8; #else #error "Unknown config for ttySM1" #endif #endif /* CONFIG_AM33_2 || CONFIG_AM33_3 */ break; #endif /* CONFIG_MN10300_TTYSM1 */ #ifdef CONFIG_MN10300_TTYSM2 case 2: /* ttySM2 */ #if defined(CONFIG_AM33_2) #if defined(CONFIG_MN10300_TTYSM2_TIMER10) scxctr |= SC2CTR_CK_TM10UFLOW; #else #error "Unknown config for ttySM2" #endif #else /* CONFIG_AM33_2 */ #if defined(CONFIG_MN10300_TTYSM2_TIMER9) scxctr |= SC2CTR_CK_TM9UFLOW_8; #elif defined(CONFIG_MN10300_TTYSM2_TIMER1) scxctr |= SC2CTR_CK_TM1UFLOW_8; #elif defined(CONFIG_MN10300_TTYSM2_TIMER3) scxctr |= SC2CTR_CK_TM3UFLOW_8; #else #error "Unknown config for ttySM2" #endif #endif /* CONFIG_AM33_2 */ break; #endif /* CONFIG_MN10300_TTYSM2 */ default: break; } try_alternative: baud = uart_get_baud_rate(&port->uart, new, old, 0, port->ioclk / 8); _debug("ALT %d [baud %d]", battempt, baud); if (!baud) baud = 9600; /* B0 transition handled in rs_set_termios */ xdiv = 1; if (baud == 134) { baud = 269; /* 134 is really 134.5 */ xdiv = 2; } if (baud == 38400 && (port->uart.flags & UPF_SPD_MASK) == UPF_SPD_CUST ) { _debug("CUSTOM %u", port->uart.custom_divisor); if (div_timer == MNSCx_DIV_TIMER_16BIT) { if (port->uart.custom_divisor <= 65535) { tmxmd = TM8MD_SRC_IOCLK; tmxbr = port->uart.custom_divisor; port->uart.uartclk = ioclk; goto timer_okay; } if (port->uart.custom_divisor / 8 <= 65535) { tmxmd = TM8MD_SRC_IOCLK_8; tmxbr = port->uart.custom_divisor / 8; port->uart.custom_divisor = tmxbr * 8; port->uart.uartclk = ioclk / 8; goto timer_okay; } if (port->uart.custom_divisor / 32 <= 65535) { tmxmd = TM8MD_SRC_IOCLK_32; tmxbr = port->uart.custom_divisor / 32; port->uart.custom_divisor = tmxbr * 32; port->uart.uartclk = ioclk / 32; goto timer_okay; } } else if (div_timer == MNSCx_DIV_TIMER_8BIT) { if (port->uart.custom_divisor <= 255) { tmxmd = TM2MD_SRC_IOCLK; tmxbr = port->uart.custom_divisor; port->uart.uartclk = ioclk; goto timer_okay; } if (port->uart.custom_divisor / 8 <= 255) { tmxmd = TM2MD_SRC_IOCLK_8; tmxbr = port->uart.custom_divisor / 8; port->uart.custom_divisor = tmxbr * 8; port->uart.uartclk = ioclk / 8; goto timer_okay; } if (port->uart.custom_divisor / 32 <= 255) { tmxmd = TM2MD_SRC_IOCLK_32; tmxbr = port->uart.custom_divisor / 32; port->uart.custom_divisor = tmxbr * 32; port->uart.uartclk = ioclk / 32; goto timer_okay; } } } switch (div_timer) { case MNSCx_DIV_TIMER_16BIT: port->uart.uartclk = ioclk; tmxmd = TM8MD_SRC_IOCLK; tmxbr = tmp = (ioclk / (baud * xdiv) + 4) / 8 - 1; if (tmp > 0 && tmp <= 65535) goto timer_okay; port->uart.uartclk = ioclk / 8; tmxmd = TM8MD_SRC_IOCLK_8; tmxbr = tmp = (ioclk / (baud * 8 * xdiv) + 4) / 8 - 1; if (tmp > 0 && tmp <= 65535) goto timer_okay; port->uart.uartclk = ioclk / 32; tmxmd = TM8MD_SRC_IOCLK_32; tmxbr = tmp = (ioclk / (baud * 32 * xdiv) + 4) / 8 - 1; if (tmp > 0 && tmp <= 65535) goto timer_okay; break; case MNSCx_DIV_TIMER_8BIT: port->uart.uartclk = ioclk; tmxmd = TM2MD_SRC_IOCLK; tmxbr = tmp = (ioclk / (baud * xdiv) + 4) / 8 - 1; if (tmp > 0 && tmp <= 255) goto timer_okay; port->uart.uartclk = ioclk / 8; tmxmd = TM2MD_SRC_IOCLK_8; tmxbr = tmp = (ioclk / (baud * 8 * xdiv) + 4) / 8 - 1; if (tmp > 0 && tmp <= 255) goto timer_okay; port->uart.uartclk = ioclk / 32; tmxmd = TM2MD_SRC_IOCLK_32; tmxbr = tmp = (ioclk / (baud * 32 * xdiv) + 4) / 8 - 1; if (tmp > 0 && tmp <= 255) goto timer_okay; break; default: BUG(); return; } /* refuse to change to a baud rate we can't support */ _debug("CAN'T SUPPORT"); switch (battempt) { case 0: if (old) { new->c_cflag &= ~CBAUD; new->c_cflag |= (old->c_cflag & CBAUD); battempt = 1; goto try_alternative; } case 1: /* as a last resort, if the quotient is zero, default to 9600 * bps */ new->c_cflag &= ~CBAUD; new->c_cflag |= B9600; battempt = 2; goto try_alternative; default: /* hmmm... can't seem to support 9600 either * - we could try iterating through the speeds we know about to * find the lowest */ new->c_cflag &= ~CBAUD; new->c_cflag |= B0; if (div_timer == MNSCx_DIV_TIMER_16BIT) tmxmd = TM8MD_SRC_IOCLK_32; else if (div_timer == MNSCx_DIV_TIMER_8BIT) tmxmd = TM2MD_SRC_IOCLK_32; tmxbr = 1; port->uart.uartclk = ioclk / 32; break; } timer_okay: _debug("UARTCLK: %u / %hu", port->uart.uartclk, tmxbr); /* make the changes */ spin_lock_irqsave(&port->uart.lock, flags); uart_update_timeout(&port->uart, new->c_cflag, baud); /* set the timer to produce the required baud rate */ switch (div_timer) { case MNSCx_DIV_TIMER_16BIT: *port->_tmxmd = 0; *port->_tmxbr = tmxbr; *port->_tmxmd = TM8MD_INIT_COUNTER; *port->_tmxmd = tmxmd | TM8MD_COUNT_ENABLE; break; case MNSCx_DIV_TIMER_8BIT: *port->_tmxmd = 0; *(volatile u8 *) port->_tmxbr = (u8) tmxbr; *port->_tmxmd = TM2MD_INIT_COUNTER; *port->_tmxmd = tmxmd | TM2MD_COUNT_ENABLE; break; } /* CTS flow control flag and modem status interrupts */ scxctr &= ~(SC2CTR_TWE | SC2CTR_TWS); if (port->type == PORT_MN10300_CTS && cflag & CRTSCTS) { /* want to interrupt when CTS goes low if CTS is now * high and vice versa */ port->tx_cts = *port->_status; if (port->tx_cts & SC2STR_CTS) scxctr |= SC2CTR_TWE; else scxctr |= SC2CTR_TWE | SC2CTR_TWS; } /* set up parity check flag */ port->uart.read_status_mask = (1 << TTY_NORMAL) | (1 << TTY_OVERRUN); if (new->c_iflag & INPCK) port->uart.read_status_mask |= (1 << TTY_PARITY) | (1 << TTY_FRAME); if (new->c_iflag & (BRKINT | PARMRK)) port->uart.read_status_mask |= (1 << TTY_BREAK); /* characters to ignore */ port->uart.ignore_status_mask = 0; if (new->c_iflag & IGNPAR) port->uart.ignore_status_mask |= (1 << TTY_PARITY) | (1 << TTY_FRAME); if (new->c_iflag & IGNBRK) { port->uart.ignore_status_mask |= (1 << TTY_BREAK); /* * If we're ignoring parity and break indicators, * ignore overruns to (for real raw support). */ if (new->c_iflag & IGNPAR) port->uart.ignore_status_mask |= (1 << TTY_OVERRUN); } /* Ignore all characters if CREAD is not set */ if ((new->c_cflag & CREAD) == 0) port->uart.ignore_status_mask |= (1 << TTY_NORMAL); scxctr |= *port->_control & (SC01CTR_TXE | SC01CTR_RXE | SC01CTR_BKE); *port->_control = scxctr; spin_unlock_irqrestore(&port->uart.lock, flags); } /* * set the terminal I/O parameters */ static void mn10300_serial_set_termios(struct uart_port *_port, struct ktermios *new, struct ktermios *old) { struct mn10300_serial_port *port = container_of(_port, struct mn10300_serial_port, uart); _enter("%s,%p,%p", port->name, new, old); mn10300_serial_change_speed(port, new, old); /* handle turning off CRTSCTS */ if (!(new->c_cflag & CRTSCTS)) { u16 ctr = *port->_control; ctr &= ~SC2CTR_TWE; *port->_control = ctr; } /* change Transfer bit-order (LSB/MSB) */ if (new->c_cflag & CODMSB) *port->_control |= SC01CTR_OD_MSBFIRST; /* MSB MODE */ else *port->_control &= ~SC01CTR_OD_MSBFIRST; /* LSB MODE */ } /* * return description of port type */ static const char *mn10300_serial_type(struct uart_port *_port) { struct mn10300_serial_port *port = container_of(_port, struct mn10300_serial_port, uart); if (port->uart.type == PORT_MN10300_CTS) return "MN10300 SIF_CTS"; return "MN10300 SIF"; } /* * release I/O and memory regions in use by port */ static void mn10300_serial_release_port(struct uart_port *_port) { struct mn10300_serial_port *port = container_of(_port, struct mn10300_serial_port, uart); _enter("%s", port->name); release_mem_region((unsigned long) port->_iobase, 16); } /* * request I/O and memory regions for port */ static int mn10300_serial_request_port(struct uart_port *_port) { struct mn10300_serial_port *port = container_of(_port, struct mn10300_serial_port, uart); _enter("%s", port->name); request_mem_region((unsigned long) port->_iobase, 16, port->name); return 0; } /* * configure the type and reserve the ports */ static void mn10300_serial_config_port(struct uart_port *_port, int type) { struct mn10300_serial_port *port = container_of(_port, struct mn10300_serial_port, uart); _enter("%s", port->name); port->uart.type = PORT_MN10300; if (port->options & MNSCx_OPT_CTS) port->uart.type = PORT_MN10300_CTS; mn10300_serial_request_port(_port); } /* * verify serial parameters are suitable for this port type */ static int mn10300_serial_verify_port(struct uart_port *_port, struct serial_struct *ss) { struct mn10300_serial_port *port = container_of(_port, struct mn10300_serial_port, uart); void *mapbase = (void *) (unsigned long) port->uart.mapbase; _enter("%s", port->name); /* these things may not be changed */ if (ss->irq != port->uart.irq || ss->port != port->uart.iobase || ss->io_type != port->uart.iotype || ss->iomem_base != mapbase || ss->iomem_reg_shift != port->uart.regshift || ss->hub6 != port->uart.hub6 || ss->xmit_fifo_size != port->uart.fifosize) return -EINVAL; /* type may be changed on a port that supports CTS */ if (ss->type != port->uart.type) { if (!(port->options & MNSCx_OPT_CTS)) return -EINVAL; if (ss->type != PORT_MN10300 && ss->type != PORT_MN10300_CTS) return -EINVAL; } return 0; } /* * initialise the MN10300 on-chip UARTs */ static int __init mn10300_serial_init(void) { struct mn10300_serial_port *port; int ret, i; printk(KERN_INFO "%s version %s (%s)\n", serial_name, serial_version, serial_revdate); #if defined(CONFIG_MN10300_TTYSM2) && defined(CONFIG_AM33_2) { int tmp; SC2TIM = 8; /* make the baud base of timer 2 IOCLK/8 */ tmp = SC2TIM; } #endif set_intr_stub(NUM2EXCEP_IRQ_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL), mn10300_serial_vdma_interrupt); ret = uart_register_driver(&mn10300_serial_driver); if (!ret) { for (i = 0 ; i < NR_PORTS ; i++) { port = mn10300_serial_ports[i]; if (!port || port->gdbstub) continue; switch (port->clock_src) { case MNSCx_CLOCK_SRC_IOCLK: port->ioclk = MN10300_IOCLK; break; #ifdef MN10300_IOBCLK case MNSCx_CLOCK_SRC_IOBCLK: port->ioclk = MN10300_IOBCLK; break; #endif default: BUG(); } ret = uart_add_one_port(&mn10300_serial_driver, &port->uart); if (ret < 0) { _debug("ERROR %d", -ret); break; } } if (ret) uart_unregister_driver(&mn10300_serial_driver); } return ret; } __initcall(mn10300_serial_init); #ifdef CONFIG_MN10300_TTYSM_CONSOLE /* * print a string to the serial port without disturbing the real user of the * port too much * - the console must be locked by the caller */ static void mn10300_serial_console_write(struct console *co, const char *s, unsigned count) { struct mn10300_serial_port *port; unsigned i; u16 scxctr, txicr, tmp; u8 tmxmd; port = mn10300_serial_ports[co->index]; /* firstly hijack the serial port from the "virtual DMA" controller */ arch_local_cli(); txicr = *port->tx_icr; *port->tx_icr = NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL); tmp = *port->tx_icr; arch_local_sti(); /* the transmitter may be disabled */ scxctr = *port->_control; if (!(scxctr & SC01CTR_TXE)) { /* restart the UART clock */ tmxmd = *port->_tmxmd; switch (port->div_timer) { case MNSCx_DIV_TIMER_16BIT: *port->_tmxmd = 0; *port->_tmxmd = TM8MD_INIT_COUNTER; *port->_tmxmd = tmxmd | TM8MD_COUNT_ENABLE; break; case MNSCx_DIV_TIMER_8BIT: *port->_tmxmd = 0; *port->_tmxmd = TM2MD_INIT_COUNTER; *port->_tmxmd = tmxmd | TM2MD_COUNT_ENABLE; break; } /* enable the transmitter */ *port->_control = (scxctr & ~SC01CTR_BKE) | SC01CTR_TXE; } else if (scxctr & SC01CTR_BKE) { /* stop transmitting BREAK */ *port->_control = (scxctr & ~SC01CTR_BKE); } /* send the chars into the serial port (with LF -> LFCR conversion) */ for (i = 0; i < count; i++) { char ch = *s++; while (*port->_status & SC01STR_TBF) continue; *(u8 *) port->_txb = ch; if (ch == 0x0a) { while (*port->_status & SC01STR_TBF) continue; *(u8 *) port->_txb = 0xd; } } /* can't let the transmitter be turned off if it's actually * transmitting */ while (*port->_status & (SC01STR_TXF | SC01STR_TBF)) continue; /* disable the transmitter if we re-enabled it */ if (!(scxctr & SC01CTR_TXE)) *port->_control = scxctr; arch_local_cli(); *port->tx_icr = txicr; tmp = *port->tx_icr; arch_local_sti(); } /* * set up a serial port as a console * - construct a cflag setting for the first rs_open() * - initialize the serial port * - return non-zero if we didn't find a serial port. */ static int __init mn10300_serial_console_setup(struct console *co, char *options) { struct mn10300_serial_port *port; int i, parity = 'n', baud = 9600, bits = 8, flow = 0; for (i = 0 ; i < NR_PORTS ; i++) { port = mn10300_serial_ports[i]; if (port && !port->gdbstub && port->uart.line == co->index) goto found_device; } return -ENODEV; found_device: switch (port->clock_src) { case MNSCx_CLOCK_SRC_IOCLK: port->ioclk = MN10300_IOCLK; break; #ifdef MN10300_IOBCLK case MNSCx_CLOCK_SRC_IOBCLK: port->ioclk = MN10300_IOBCLK; break; #endif default: BUG(); } if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); return uart_set_options(&port->uart, co, baud, parity, bits, flow); } /* * register console */ static int __init mn10300_serial_console_init(void) { register_console(&mn10300_serial_console); return 0; } console_initcall(mn10300_serial_console_init); #endif