X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fserial%2Fsh-sci.c;h=c53b69610a51005c0b845eb9a63c00e900a311e7;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=44f6bf79bbe12725fc0ba499501ba49625bcda60;hpb=76828883507a47dae78837ab5dec5a5b4513c667;p=linux-2.6.git diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index 44f6bf79b..c53b69610 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -3,7 +3,7 @@ * * SuperH on-chip serial module support. (SCI with no FIFO / with FIFO) * - * Copyright (C) 2002, 2003, 2004 Paul Mundt + * Copyright (C) 2002 - 2006 Paul Mundt * * based off of the old drivers/char/sh-sci.c by: * @@ -20,11 +20,8 @@ #undef DEBUG -#include #include #include -#include -#include #include #include #include @@ -33,71 +30,77 @@ #include #include #include -#include -#include #include #include -#include #include #include #include -#include -#include +#include #ifdef CONFIG_CPU_FREQ #include #include #endif -#include -#include -#include -#include - #if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64) #include -#endif - -#ifdef CONFIG_SH_STANDARD_BIOS #include +#include #endif +#include + #if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) #define SUPPORT_SYSRQ #endif #include "sh-sci.h" -#ifdef CONFIG_SH_KGDB -#include +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]; + + /* Port pin configuration */ + void (*init_pins)(struct uart_port *port, + unsigned int cflag); -static int kgdb_get_char(struct sci_port *port); -static void kgdb_put_char(struct sci_port *port, char c); -static void kgdb_handle_error(struct sci_port *port); + /* 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; +}; + +#ifdef CONFIG_SH_KGDB static struct sci_port *kgdb_sci_port; -#endif /* CONFIG_SH_KGDB */ +#endif #ifdef CONFIG_SERIAL_SH_SCI_CONSOLE -static struct sci_port *serial_console_port = 0; -#endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */ +static struct sci_port *serial_console_port; +#endif /* Function prototypes */ static void sci_stop_tx(struct uart_port *port); -static void sci_start_tx(struct uart_port *port); -static void sci_start_rx(struct uart_port *port, unsigned int tty_start); -static void sci_stop_rx(struct uart_port *port); -static int sci_request_irq(struct sci_port *port); -static void sci_free_irq(struct sci_port *port); - -static struct sci_port sci_ports[]; -static struct uart_driver sci_uart_driver; -#define SCI_NPORTS sci_uart_driver.nr +#define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS -#if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB) +static struct sci_port sci_ports[SCI_NPORTS]; +static struct uart_driver sci_uart_driver; -static void handle_error(struct uart_port *port) -{ /* Clear error flags */ +#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) && \ + defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB) +static inline void handle_error(struct uart_port *port) +{ + /* Clear error flags */ sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port)); } @@ -107,8 +110,8 @@ static int get_char(struct uart_port *port) unsigned short status; int c; - local_irq_save(flags); - do { + spin_lock_irqsave(&port->lock, flags); + do { status = sci_in(port, SCxSR); if (status & SCxSR_ERRORS(port)) { handle_error(port); @@ -118,38 +121,19 @@ static int get_char(struct uart_port *port) c = sci_in(port, SCxRDR); sci_in(port, SCxSR); /* Dummy read */ sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); - local_irq_restore(flags); + spin_unlock_irqrestore(&port->lock, flags); return c; } - -/* Taken from sh-stub.c of GDB 4.18 */ -static const char hexchars[] = "0123456789abcdef"; - -static __inline__ char highhex(int x) -{ - return hexchars[(x >> 4) & 0xf]; -} - -static __inline__ char lowhex(int x) -{ - return hexchars[x & 0xf]; -} - #endif /* CONFIG_SH_STANDARD_BIOS || CONFIG_SH_KGDB */ -/* - * Send the packet in buffer. The host gets one chance to read it. - * This routine does not wait for a positive acknowledge. - */ - -#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE +#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) || defined(CONFIG_SH_KGDB) static void put_char(struct uart_port *port, char c) { unsigned long flags; unsigned short status; - local_irq_save(flags); + spin_lock_irqsave(&port->lock, flags); do { status = sci_in(port, SCxSR); @@ -159,9 +143,11 @@ static void put_char(struct uart_port *port, char c) sci_in(port, SCxSR); /* Dummy read */ sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port)); - local_irq_restore(flags); + spin_unlock_irqrestore(&port->lock, flags); } +#endif +#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE static void put_string(struct sci_port *sci_port, const char *buffer, int count) { struct uart_port *port = &sci_port->port; @@ -214,96 +200,28 @@ static void put_string(struct sci_port *sci_port, const char *buffer, int count) } #endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */ - #ifdef CONFIG_SH_KGDB - -/* Is the SCI ready, ie is there a char waiting? */ -static int kgdb_is_char_ready(struct sci_port *port) -{ - unsigned short status = sci_in(port, SCxSR); - - if (status & (SCxSR_ERRORS(port) | SCxSR_BRK(port))) - kgdb_handle_error(port); - - return (status & SCxSR_RDxF(port)); -} - -/* Write a char */ -static void kgdb_put_char(struct sci_port *port, char c) -{ - unsigned short status; - - do - status = sci_in(port, SCxSR); - while (!(status & SCxSR_TDxE(port))); - - sci_out(port, SCxTDR, c); - sci_in(port, SCxSR); /* Dummy read */ - sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port)); -} - -/* Get a char if there is one, else ret -1 */ -static int kgdb_get_char(struct sci_port *port) -{ - int c; - - if (kgdb_is_char_ready(port) == 0) - c = -1; - else { - c = sci_in(port, SCxRDR); - sci_in(port, SCxSR); /* Dummy read */ - sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); - } - - return c; -} - -/* Called from kgdbstub.c to get a character, i.e. is blocking */ static int kgdb_sci_getchar(void) { - volatile int c; + int c; /* Keep trying to read a character, this could be neater */ - while ((c = kgdb_get_char(kgdb_sci_port)) < 0); + while ((c = get_char(kgdb_sci_port)) < 0) + cpu_relax(); return c; } -/* Called from kgdbstub.c to put a character, just a wrapper */ -static void kgdb_sci_putchar(int c) +static inline void kgdb_sci_putchar(int c) { - - kgdb_put_char(kgdb_sci_port, c); + put_char(kgdb_sci_port, c); } - -/* Clear any errors on the SCI */ -static void kgdb_handle_error(struct sci_port *port) -{ - sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port)); /* Clear error flags */ -} - -/* Breakpoint if there's a break sent on the serial port */ -static void kgdb_break_interrupt(int irq, void *ptr, struct pt_regs *regs) -{ - struct sci_port *port = ptr; - unsigned short status = sci_in(port, SCxSR); - - if (status & SCxSR_BRK(port)) { - - /* Break into the debugger if a break is detected */ - BREAKPOINT(); - - /* Clear */ - sci_out(port, SCxSR, SCxSR_BREAK_CLEAR(port)); - } -} - #endif /* CONFIG_SH_KGDB */ #if defined(__H8300S__) enum { sci_disable, sci_enable }; -static void h8300_sci_enable(struct uart_port* port, unsigned int ctrl) +static void h8300_sci_config(struct uart_port* port, unsigned int ctrl) { volatile unsigned char *mstpcrl=(volatile unsigned char *)MSTPCRL; int ch = (port->mapbase - SMR0) >> 3; @@ -315,32 +233,66 @@ static void h8300_sci_enable(struct uart_port* port, unsigned int ctrl) *mstpcrl &= ~mask; } } + +static inline void h8300_sci_enable(struct uart_port *port) +{ + h8300_sci_config(port, sci_enable); +} + +static inline void h8300_sci_disable(struct uart_port *port) +{ + h8300_sci_config(port, sci_disable); +} #endif -#if defined(SCI_ONLY) || defined(SCI_AND_SCIF) -#if defined(__H8300H__) || defined(__H8300S__) +#if defined(SCI_ONLY) || defined(SCI_AND_SCIF) && \ + defined(__H8300H__) || defined(__H8300S__) static void sci_init_pins_sci(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); + 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; } +#else +#define sci_init_pins_sci NULL +#endif + +#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) +static void sci_init_pins_irda(struct uart_port *port, unsigned int cflag) +{ + unsigned int fcr_val = 0; + + if (cflag & CRTSCTS) + fcr_val |= SCFCR_MCE; + + sci_out(port, SCFCR, fcr_val); +} +#else +#define sci_init_pins_irda NULL #endif + +#ifdef SCI_ONLY +#define sci_init_pins_scif NULL #endif #if defined(SCIF_ONLY) || defined(SCI_AND_SCIF) -#if defined(CONFIG_CPU_SUBTYPE_SH7300) +#if defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7710) /* SH7300 doesn't use RTS/CTS */ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag) { sci_out(port, SCFCR, 0); } #elif defined(CONFIG_CPU_SH3) -/* For SH7705, SH7707, SH7709, SH7709A, SH7729 */ +/* For SH7705, SH7706, SH7707, SH7709, SH7709A, SH7729 */ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag) { unsigned int fcr_val = 0; @@ -367,20 +319,29 @@ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag) sci_out(port, SCFCR, fcr_val); } - -#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) -static void sci_init_pins_irda(struct uart_port *port, unsigned int cflag) +#elif defined(CONFIG_CPU_SUBTYPE_SH7722) +static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag) { unsigned int fcr_val = 0; - if (cflag & CRTSCTS) + if (cflag & CRTSCTS) { fcr_val |= SCFCR_MCE; + ctrl_outw(0x0000, PORT_PSCR); + } else { + unsigned short data; + + data = ctrl_inw(PORT_PSCR); + data &= 0x033f; + data |= 0x0400; + ctrl_outw(data, PORT_PSCR); + + ctrl_outw(ctrl_inw(SCSPTR0) & 0x17, SCSPTR0); + } + sci_out(port, SCFCR, fcr_val); } -#endif #else - /* For SH7750 */ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag) { @@ -389,7 +350,9 @@ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag) if (cflag & CRTSCTS) { fcr_val |= SCFCR_MCE; } else { -#ifdef CONFIG_CPU_SUBTYPE_SH7780 +#ifdef CONFIG_CPU_SUBTYPE_SH7343 + /* Nothing */ +#elif defined(CONFIG_CPU_SUBTYPE_SH7780) ctrl_outw(0x0080, SCSPTR0); /* Set RTS = 1 */ #else ctrl_outw(0x0080, SCSPTR2); /* Set RTS = 1 */ @@ -397,10 +360,41 @@ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag) } sci_out(port, SCFCR, fcr_val); } +#endif + +#if defined(CONFIG_CPU_SUBTYPE_SH7760) || defined(CONFIG_CPU_SUBTYPE_SH7780) +static inline int scif_txroom(struct uart_port *port) +{ + return SCIF_TXROOM_MAX - (sci_in(port, SCTFDR) & 0x7f); +} + +static inline int scif_rxroom(struct uart_port *port) +{ + return sci_in(port, SCRFDR) & 0x7f; +} +#else +static inline int scif_txroom(struct uart_port *port) +{ + return SCIF_TXROOM_MAX - (sci_in(port, SCFDR) >> 8); +} +static inline int scif_rxroom(struct uart_port *port) +{ + return sci_in(port, SCFDR) & SCIF_RFDC_MASK; +} #endif #endif /* SCIF_ONLY || SCI_AND_SCIF */ +static inline int sci_txroom(struct uart_port *port) +{ + return ((sci_in(port, SCxSR) & SCI_TDRE) != 0); +} + +static inline int sci_rxroom(struct uart_port *port) +{ + return ((sci_in(port, SCxSR) & SCxSR_RDxF(port)) != 0); +} + /* ********************************************************************** * * the interrupt related routines * * ********************************************************************** */ @@ -409,14 +403,12 @@ static void sci_transmit_chars(struct uart_port *port) { struct circ_buf *xmit = &port->info->xmit; unsigned int stopped = uart_tx_stopped(port); - unsigned long flags; unsigned short status; unsigned short ctrl; - int count, txroom; + int count; status = sci_in(port, SCxSR); if (!(status & SCxSR_TDxE(port))) { - local_irq_save(flags); ctrl = sci_in(port, SCSCR); if (uart_circ_empty(xmit)) { ctrl &= ~SCI_CTRL_FLAGS_TIE; @@ -424,25 +416,15 @@ static void sci_transmit_chars(struct uart_port *port) ctrl |= SCI_CTRL_FLAGS_TIE; } sci_out(port, SCSCR, ctrl); - local_irq_restore(flags); return; } -#if !defined(SCI_ONLY) - if (port->type == PORT_SCIF) { -#if defined(CONFIG_CPU_SUBTYPE_SH7760) || defined(CONFIG_CPU_SUBTYPE_SH7780) - txroom = SCIF_TXROOM_MAX - (sci_in(port, SCTFDR) & 0x7f); -#else - txroom = SCIF_TXROOM_MAX - (sci_in(port, SCFDR)>>8); -#endif - } else { - txroom = (sci_in(port, SCxSR) & SCI_TDRE)?1:0; - } -#else - txroom = (sci_in(port, SCxSR) & SCI_TDRE)?1:0; +#ifndef SCI_ONLY + if (port->type == PORT_SCIF) + count = scif_txroom(port); + else #endif - - count = txroom; + count = sci_txroom(port); do { unsigned char c; @@ -469,7 +451,6 @@ static void sci_transmit_chars(struct uart_port *port) if (uart_circ_empty(xmit)) { sci_stop_tx(port); } else { - local_irq_save(flags); ctrl = sci_in(port, SCSCR); #if !defined(SCI_ONLY) @@ -481,16 +462,15 @@ static void sci_transmit_chars(struct uart_port *port) ctrl |= SCI_CTRL_FLAGS_TIE; sci_out(port, SCSCR, ctrl); - local_irq_restore(flags); } } /* 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, - struct pt_regs *regs) +static inline void sci_receive_chars(struct uart_port *port) { + struct sci_port *sci_port = (struct sci_port *)port; struct tty_struct *tty = port->info->tty; int i, count, copied = 0; unsigned short status; @@ -502,18 +482,11 @@ static inline void sci_receive_chars(struct uart_port *port, while (1) { #if !defined(SCI_ONLY) - if (port->type == PORT_SCIF) { -#if defined(CONFIG_CPU_SUBTYPE_SH7760) || defined(CONFIG_CPU_SUBTYPE_SH7780) - count = sci_in(port, SCRFDR) & 0x7f; -#else - count = sci_in(port, SCFDR)&SCIF_RFDC_MASK ; -#endif - } else { - count = (sci_in(port, SCxSR)&SCxSR_RDxF(port))?1:0; - } -#else - count = (sci_in(port, SCxSR)&SCxSR_RDxF(port))?1:0; + if (port->type == PORT_SCIF) + count = scif_rxroom(port); + else #endif + count = sci_rxroom(port); /* Don't copy more bytes than there is room for in the buffer */ count = tty_buffer_request_room(tty, count); @@ -524,11 +497,10 @@ static inline void sci_receive_chars(struct uart_port *port, if (port->type == PORT_SCI) { char c = sci_in(port, SCxRDR); - if(((struct sci_port *)port)->break_flag - || uart_handle_sysrq_char(port, c, regs)) { + if (uart_handle_sysrq_char(port, c) || sci_port->break_flag) count = 0; - } else { - tty_insert_flip_char(tty, c, TTY_NORMAL); + else { + tty_insert_flip_char(tty, c, TTY_NORMAL); } } else { for (i=0; ibreak_flag) { + if (sci_port->break_flag) { if ((c == 0) && (status & SCxSR_FER(port))) { count--; i--; continue; } + /* Nonzero => end-of-break */ pr_debug("scif: debounce<%02x>\n", c); - ((struct sci_port *)port)->break_flag = 0; + sci_port->break_flag = 0; + if (STEPFN(c)) { count--; i--; continue; } } #endif /* CONFIG_CPU_SH3 */ - if (uart_handle_sysrq_char(port, c, regs)) { + if (uart_handle_sysrq_char(port, c)) { count--; i--; continue; } @@ -601,15 +575,17 @@ static void sci_schedule_break_timer(struct sci_port *port) /* 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) { + 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){ + 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; + sci_schedule_break_timer(port); + } else + port->break_flag = 0; } static inline int sci_handle_errors(struct uart_port *port) @@ -618,40 +594,41 @@ static inline int sci_handle_errors(struct uart_port *port) unsigned short status = sci_in(port, SCxSR); struct tty_struct *tty = port->info->tty; - if (status&SCxSR_ORER(port)) { + if (status & SCxSR_ORER(port)) { /* overrun error */ - if(tty_insert_flip_char(tty, 0, TTY_OVERRUN)) + if (tty_insert_flip_char(tty, 0, TTY_OVERRUN)) copied++; pr_debug("sci: overrun error\n"); } - if (status&SCxSR_FER(port)) { + if (status & SCxSR_FER(port)) { if (sci_rxd_in(port) == 0) { /* Notify of BREAK */ - struct sci_port * sci_port = (struct sci_port *)port; - if(!sci_port->break_flag) { - sci_port->break_flag = 1; - sci_schedule_break_timer((struct sci_port *)port); + struct sci_port *sci_port = (struct 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)) + if (uart_handle_break(port)) return 0; pr_debug("sci: BREAK detected\n"); - if(tty_insert_flip_char(tty, 0, TTY_BREAK)) + if (tty_insert_flip_char(tty, 0, TTY_BREAK)) copied++; } - } - else { + } else { /* frame error */ - if(tty_insert_flip_char(tty, 0, TTY_FRAME)) + if (tty_insert_flip_char(tty, 0, TTY_FRAME)) copied++; pr_debug("sci: frame error\n"); } } - if (status&SCxSR_PER(port)) { - if(tty_insert_flip_char(tty, 0, TTY_PARITY)) - copied++; + if (status & SCxSR_PER(port)) { /* parity error */ + if (tty_insert_flip_char(tty, 0, TTY_PARITY)) + copied++; pr_debug("sci: parity error\n"); } @@ -674,7 +651,7 @@ static inline int sci_handle_breaks(struct uart_port *port) s->break_flag = 1; #endif /* Notify of BREAK */ - if(tty_insert_flip_char(tty, 0, TTY_BREAK)) + if (tty_insert_flip_char(tty, 0, TTY_BREAK)) copied++; pr_debug("sci: BREAK detected\n"); } @@ -683,7 +660,7 @@ static inline int sci_handle_breaks(struct uart_port *port) /* XXX: Handle SCIF overrun error */ if (port->type == PORT_SCIF && (sci_in(port, SCLSR) & SCIF_ORER) != 0) { sci_out(port, SCLSR, 0); - if(tty_insert_flip_char(tty, 0, TTY_OVERRUN)) { + if (tty_insert_flip_char(tty, 0, TTY_OVERRUN)) { copied++; pr_debug("sci: overrun error\n"); } @@ -692,32 +669,33 @@ static inline int sci_handle_breaks(struct uart_port *port) if (copied) tty_flip_buffer_push(tty); + return copied; } -static irqreturn_t sci_rx_interrupt(int irq, void *ptr, struct pt_regs *regs) +static irqreturn_t sci_rx_interrupt(int irq, void *port) { - struct uart_port *port = ptr; - /* 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(port, regs); + sci_receive_chars(port); return IRQ_HANDLED; } -static irqreturn_t sci_tx_interrupt(int irq, void *ptr, struct pt_regs *regs) +static irqreturn_t sci_tx_interrupt(int irq, void *ptr) { struct uart_port *port = ptr; + spin_lock_irq(&port->lock); sci_transmit_chars(port); + spin_unlock_irq(&port->lock); return IRQ_HANDLED; } -static irqreturn_t sci_er_interrupt(int irq, void *ptr, struct pt_regs *regs) +static irqreturn_t sci_er_interrupt(int irq, void *ptr) { struct uart_port *port = ptr; @@ -739,29 +717,35 @@ static irqreturn_t sci_er_interrupt(int irq, void *ptr, struct pt_regs *regs) pr_debug("scif: overrun error\n"); } #endif - sci_rx_interrupt(irq, ptr, regs); + sci_rx_interrupt(irq, ptr); } sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port)); /* Kick the transmission */ - sci_tx_interrupt(irq, ptr, regs); + sci_tx_interrupt(irq, ptr); return IRQ_HANDLED; } -static irqreturn_t sci_br_interrupt(int irq, void *ptr, struct pt_regs *regs) +static irqreturn_t sci_br_interrupt(int irq, void *ptr) { struct uart_port *port = ptr; /* Handle BREAKs */ sci_handle_breaks(port); + +#ifdef CONFIG_SH_KGDB + /* Break into the debugger if a break is detected */ + BREAKPOINT(); +#endif + sci_out(port, SCxSR, SCxSR_BREAK_CLEAR(port)); return IRQ_HANDLED; } -static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr, struct pt_regs *regs) +static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr) { unsigned short ssr_status, scr_status; struct uart_port *port = ptr; @@ -770,17 +754,17 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr, struct pt_regs *regs) scr_status = sci_in(port,SCSCR); /* Tx Interrupt */ - if ((ssr_status&0x0020) && (scr_status&0x0080)) - sci_tx_interrupt(irq, ptr, regs); + if ((ssr_status & 0x0020) && (scr_status & 0x0080)) + sci_tx_interrupt(irq, ptr); /* Rx Interrupt */ - if ((ssr_status&0x0002) && (scr_status&0x0040)) - sci_rx_interrupt(irq, ptr, regs); + if ((ssr_status & 0x0002) && (scr_status & 0x0040)) + sci_rx_interrupt(irq, ptr); /* Error Interrupt */ - if ((ssr_status&0x0080) && (scr_status&0x0400)) - sci_er_interrupt(irq, ptr, regs); + if ((ssr_status & 0x0080) && (scr_status & 0x0400)) + sci_er_interrupt(irq, ptr); /* Break Interrupt */ - if ((ssr_status&0x0010) && (scr_status&0x0200)) - sci_br_interrupt(irq, ptr, regs); + if ((ssr_status & 0x0010) && (scr_status & 0x0200)) + sci_br_interrupt(irq, ptr); return IRQ_HANDLED; } @@ -790,7 +774,8 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr, struct pt_regs *regs) * 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) +static int sci_notifier(struct notifier_block *self, + unsigned long phase, void *p) { struct cpufreq_freqs *freqs = p; int i; @@ -812,13 +797,14 @@ static int sci_notifier(struct notifier_block *self, unsigned long phase, void * * * Clean this up later.. */ - clk = clk_get("module_clk"); + clk = clk_get(NULL, "module_clk"); port->uartclk = clk_get_rate(clk) * 16; clk_put(clk); } - printk("%s: got a postchange notification for cpu %d (old %d, new %d)\n", - __FUNCTION__, freqs->cpu, freqs->old, freqs->new); + printk(KERN_INFO "%s: got a postchange notification " + "for cpu %d (old %d, new %d)\n", + __FUNCTION__, freqs->cpu, freqs->old, freqs->new); } return NOTIFY_OK; @@ -830,7 +816,7 @@ static struct notifier_block sci_nb = { &sci_notifier, NULL, 0 }; static int sci_request_irq(struct sci_port *port) { int i; - irqreturn_t (*handlers[4])(int irq, void *ptr, struct pt_regs *regs) = { + irqreturn_t (*handlers[4])(int irq, void *ptr) = { sci_er_interrupt, sci_rx_interrupt, sci_tx_interrupt, sci_br_interrupt, }; @@ -842,8 +828,9 @@ static int sci_request_irq(struct sci_port *port) printk(KERN_ERR "sci: Cannot allocate irq.(IRQ=0)\n"); return -ENODEV; } - if (request_irq(port->irqs[0], sci_mpxed_interrupt, SA_INTERRUPT, - "sci", port)) { + + if (request_irq(port->irqs[0], sci_mpxed_interrupt, + IRQF_DISABLED, "sci", port)) { printk(KERN_ERR "sci: Cannot allocate irq.\n"); return -ENODEV; } @@ -851,8 +838,8 @@ static int sci_request_irq(struct sci_port *port) for (i = 0; i < ARRAY_SIZE(handlers); i++) { if (!port->irqs[i]) continue; - if (request_irq(port->irqs[i], handlers[i], SA_INTERRUPT, - desc[i], port)) { + if (request_irq(port->irqs[i], handlers[i], + IRQF_DISABLED, desc[i], port)) { printk(KERN_ERR "sci: Cannot allocate irq.\n"); return -ENODEV; } @@ -904,50 +891,42 @@ static unsigned int sci_get_mctrl(struct uart_port *port) static void sci_start_tx(struct uart_port *port) { - struct sci_port *s = &sci_ports[port->line]; + unsigned short ctrl; - disable_irq(s->irqs[SCIx_TXI_IRQ]); - sci_transmit_chars(port); - enable_irq(s->irqs[SCIx_TXI_IRQ]); + /* Set TIE (Transmit Interrupt Enable) bit in SCSCR */ + ctrl = sci_in(port, SCSCR); + ctrl |= SCI_CTRL_FLAGS_TIE; + sci_out(port, SCSCR, ctrl); } static void sci_stop_tx(struct uart_port *port) { - unsigned long flags; unsigned short ctrl; /* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */ - local_irq_save(flags); ctrl = sci_in(port, SCSCR); ctrl &= ~SCI_CTRL_FLAGS_TIE; sci_out(port, SCSCR, ctrl); - local_irq_restore(flags); } static void sci_start_rx(struct uart_port *port, unsigned int tty_start) { - unsigned long flags; unsigned short ctrl; /* Set RIE (Receive Interrupt Enable) bit in SCSCR */ - local_irq_save(flags); ctrl = sci_in(port, SCSCR); ctrl |= SCI_CTRL_FLAGS_RIE | SCI_CTRL_FLAGS_REIE; sci_out(port, SCSCR, ctrl); - local_irq_restore(flags); } static void sci_stop_rx(struct uart_port *port) { - unsigned long flags; unsigned short ctrl; /* Clear RIE (Receive Interrupt Enable) bit in SCSCR */ - local_irq_save(flags); ctrl = sci_in(port, SCSCR); ctrl &= ~(SCI_CTRL_FLAGS_RIE | SCI_CTRL_FLAGS_REIE); sci_out(port, SCSCR, ctrl); - local_irq_restore(flags); } static void sci_enable_ms(struct uart_port *port) @@ -964,9 +943,8 @@ static int sci_startup(struct uart_port *port) { struct sci_port *s = &sci_ports[port->line]; -#if defined(__H8300S__) - h8300_sci_enable(port, sci_enable); -#endif + if (s->enable) + s->enable(port); sci_request_irq(s); sci_start_tx(port); @@ -983,13 +961,12 @@ static void sci_shutdown(struct uart_port *port) sci_stop_tx(port); sci_free_irq(s); -#if defined(__H8300S__) - h8300_sci_enable(port, sci_disable); -#endif + if (s->disable) + s->disable(port); } -static void sci_set_termios(struct uart_port *port, struct termios *termios, - struct termios *old) +static void sci_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) { struct sci_port *s = &sci_ports[port->line]; unsigned int status, baud, smr_val; @@ -998,6 +975,23 @@ static void sci_set_termios(struct uart_port *port, struct termios *termios, baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); + switch (baud) { + case 0: + t = -1; + break; + default: + { +#if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64) + struct clk *clk = clk_get(NULL, "module_clk"); + t = SCBRR_VALUE(baud, clk_get_rate(clk)); + clk_put(clk); +#else + t = SCBRR_VALUE(baud); +#endif + } + break; + } + spin_lock_irqsave(&port->lock, flags); do { @@ -1007,9 +1001,8 @@ static void sci_set_termios(struct uart_port *port, struct termios *termios, sci_out(port, SCSCR, 0x00); /* TE=0, RE=0, CKE1=0 */ #if !defined(SCI_ONLY) - if (port->type == PORT_SCIF) { + if (port->type == PORT_SCIF) sci_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST); - } #endif smr_val = sci_in(port, SCSMR) & 3; @@ -1026,23 +1019,6 @@ static void sci_set_termios(struct uart_port *port, struct termios *termios, sci_out(port, SCSMR, smr_val); - switch (baud) { - case 0: - t = -1; - break; - default: - { -#if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64) - struct clk *clk = clk_get("module_clk"); - t = SCBRR_VALUE(baud, clk_get_rate(clk)); - clk_put(clk); -#else - t = SCBRR_VALUE(baud); -#endif - } - break; - } - if (t > 0) { if(t >= 256) { sci_out(port, SCSMR, (sci_in(port, SCSMR) & ~3) | 1); @@ -1093,11 +1069,23 @@ static void sci_config_port(struct uart_port *port, int flags) port->type = s->type; + switch (port->type) { + case PORT_SCI: + s->init_pins = sci_init_pins_sci; + break; + case PORT_SCIF: + s->init_pins = sci_init_pins_scif; + break; + case PORT_IRDA: + s->init_pins = sci_init_pins_irda; + break; + } + #if defined(CONFIG_CPU_SUBTYPE_SH5_101) || defined(CONFIG_CPU_SUBTYPE_SH5_103) if (port->mapbase == 0) port->mapbase = onchip_remap(SCIF_ADDR_SH5, 1024, "SCIF"); - port->membase = (void *)port->mapbase; + port->membase = (void __iomem *)port->mapbase; #endif } @@ -1133,412 +1121,61 @@ static struct uart_ops sci_uart_ops = { .verify_port = sci_verify_port, }; -static struct sci_port sci_ports[] = { -#if defined(CONFIG_CPU_SUBTYPE_SH7708) - { - .port = { - .membase = (void *)0xfffffe80, - .mapbase = 0xfffffe80, - .iotype = UPIO_MEM, - .irq = 25, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 0, - }, - .type = PORT_SCI, - .irqs = SCI_IRQS, - }, -#elif defined(CONFIG_CPU_SUBTYPE_SH7705) - { - .port = { - .membase = (void *)SCIF0, - .mapbase = SCIF0, - .iotype = UPIO_MEM, - .irq = 55, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 0, - }, - .type = PORT_SCIF, - .irqs = SH3_IRDA_IRQS, - .init_pins = sci_init_pins_scif, - }, - { - .port = { - .membase = (void *)SCIF2, - .mapbase = SCIF2, - .iotype = UPIO_MEM, - .irq = 59, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 1, - }, - .type = PORT_SCIF, - .irqs = SH3_SCIF_IRQS, - .init_pins = sci_init_pins_scif, - } -#elif defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) - { - .port = { - .membase = (void *)0xfffffe80, - .mapbase = 0xfffffe80, - .iotype = UPIO_MEM, - .irq = 25, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 0, - }, - .type = PORT_SCI, - .irqs = SCI_IRQS, - }, - { - .port = { - .membase = (void *)0xa4000150, - .mapbase = 0xa4000150, - .iotype = UPIO_MEM, - .irq = 59, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 1, - }, - .type = PORT_SCIF, - .irqs = SH3_SCIF_IRQS, - .init_pins = sci_init_pins_scif, - }, - { - .port = { - .membase = (void *)0xa4000140, - .mapbase = 0xa4000140, - .iotype = UPIO_MEM, - .irq = 55, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 2, - }, - .type = PORT_IRDA, - .irqs = SH3_IRDA_IRQS, - .init_pins = sci_init_pins_irda, - } -#elif defined(CONFIG_CPU_SUBTYPE_SH7300) - { - .port = { - .membase = (void *)0xA4430000, - .mapbase = 0xA4430000, - .iotype = UPIO_MEM, - .irq = 25, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 0, - }, - .type = PORT_SCIF, - .irqs = SH7300_SCIF0_IRQS, - .init_pins = sci_init_pins_scif, - }, -#elif defined(CONFIG_CPU_SUBTYPE_SH73180) - { - .port = { - .membase = (void *)0xffe00000, - .mapbase = 0xffe00000, - .iotype = UPIO_MEM, - .irq = 25, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 0, - }, - .type = PORT_SCIF, - .irqs = SH73180_SCIF_IRQS, - .init_pins = sci_init_pins_scif, - }, -#elif defined(CONFIG_CPU_SUBTYPE_SH4_202) - { - .port = { - .membase = (void *)0xffe80000, - .mapbase = 0xffe80000, - .iotype = UPIO_MEM, - .irq = 43, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 0, - }, - .type = PORT_SCIF, - .irqs = SH4_SCIF_IRQS, - .init_pins = sci_init_pins_scif, - }, -#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_SH7751) - { - .port = { - .membase = (void *)0xffe00000, - .mapbase = 0xffe00000, - .iotype = UPIO_MEM, - .irq = 25, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 0, - }, - .type = PORT_SCI, - .irqs = SCI_IRQS, - }, - { - .port = { - .membase = (void *)0xffe80000, - .mapbase = 0xffe80000, - .iotype = UPIO_MEM, - .irq = 43, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 1, - }, - .type = PORT_SCIF, - .irqs = SH4_SCIF_IRQS, - .init_pins = sci_init_pins_scif, - }, -#elif defined(CONFIG_CPU_SUBTYPE_SH7760) - { - .port = { - .membase = (void *)0xfe600000, - .mapbase = 0xfe600000, - .iotype = UPIO_MEM, - .irq = 55, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 0, - }, - .type = PORT_SCIF, - .irqs = SH7760_SCIF0_IRQS, - .init_pins = sci_init_pins_scif, - }, - { - .port = { - .membase = (void *)0xfe610000, - .mapbase = 0xfe610000, - .iotype = UPIO_MEM, - .irq = 75, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 1, - }, - .type = PORT_SCIF, - .irqs = SH7760_SCIF1_IRQS, - .init_pins = sci_init_pins_scif, - }, - { - .port = { - .membase = (void *)0xfe620000, - .mapbase = 0xfe620000, - .iotype = UPIO_MEM, - .irq = 79, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 2, - }, - .type = PORT_SCIF, - .irqs = SH7760_SCIF2_IRQS, - .init_pins = sci_init_pins_scif, - }, -#elif defined(CONFIG_CPU_SUBTYPE_ST40STB1) - { - .port = { - .membase = (void *)0xffe00000, - .mapbase = 0xffe00000, - .iotype = UPIO_MEM, - .irq = 26, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 0, - }, - .type = PORT_SCIF, - .irqs = STB1_SCIF1_IRQS, - .init_pins = sci_init_pins_scif, - }, - { - .port = { - .membase = (void *)0xffe80000, - .mapbase = 0xffe80000, - .iotype = UPIO_MEM, - .irq = 43, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 1, - }, - .type = PORT_SCIF, - .irqs = SH4_SCIF_IRQS, - .init_pins = sci_init_pins_scif, - }, -#elif defined(CONFIG_CPU_SUBTYPE_SH5_101) || defined(CONFIG_CPU_SUBTYPE_SH5_103) - { - .port = { - .iotype = UPIO_MEM, - .irq = 42, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 0, - }, - .type = PORT_SCIF, - .irqs = SH5_SCIF_IRQS, - .init_pins = sci_init_pins_scif, - }, -#elif defined(CONFIG_H83007) || defined(CONFIG_H83068) - { - .port = { - .membase = (void *)0x00ffffb0, - .mapbase = 0x00ffffb0, - .iotype = UPIO_MEM, - .irq = 54, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 0, - }, - .type = PORT_SCI, - .irqs = H8300H_SCI_IRQS0, - .init_pins = sci_init_pins_sci, - }, - { - .port = { - .membase = (void *)0x00ffffb8, - .mapbase = 0x00ffffb8, - .iotype = UPIO_MEM, - .irq = 58, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 1, - }, - .type = PORT_SCI, - .irqs = H8300H_SCI_IRQS1, - .init_pins = sci_init_pins_sci, - }, - { - .port = { - .membase = (void *)0x00ffffc0, - .mapbase = 0x00ffffc0, - .iotype = UPIO_MEM, - .irq = 62, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 2, - }, - .type = PORT_SCI, - .irqs = H8300H_SCI_IRQS2, - .init_pins = sci_init_pins_sci, - }, -#elif defined(CONFIG_H8S2678) - { - .port = { - .membase = (void *)0x00ffff78, - .mapbase = 0x00ffff78, - .iotype = UPIO_MEM, - .irq = 90, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 0, - }, - .type = PORT_SCI, - .irqs = H8S_SCI_IRQS0, - .init_pins = sci_init_pins_sci, - }, - { - .port = { - .membase = (void *)0x00ffff80, - .mapbase = 0x00ffff80, - .iotype = UPIO_MEM, - .irq = 94, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 1, - }, - .type = PORT_SCI, - .irqs = H8S_SCI_IRQS1, - .init_pins = sci_init_pins_sci, - }, - { - .port = { - .membase = (void *)0x00ffff88, - .mapbase = 0x00ffff88, - .iotype = UPIO_MEM, - .irq = 98, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 2, - }, - .type = PORT_SCI, - .irqs = H8S_SCI_IRQS2, - .init_pins = sci_init_pins_sci, - }, -#elif defined(CONFIG_CPU_SUBTYPE_SH7770) - { - .port = { - .membase = (void *)0xff923000, - .mapbase = 0xff923000, - .iotype = UPIO_MEM, - .irq = 61, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 0, - }, - .type = PORT_SCIF, - .irqs = SH7770_SCIF0_IRQS, - .init_pins = sci_init_pins_scif, - }, - { - .port = { - .membase = (void *)0xff924000, - .mapbase = 0xff924000, - .iotype = UPIO_MEM, - .irq = 62, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 1, - }, - .type = PORT_SCIF, - .irqs = SH7770_SCIF1_IRQS, - .init_pins = sci_init_pins_scif, - }, - { - .port = { - .membase = (void *)0xff925000, - .mapbase = 0xff925000, - .iotype = UPIO_MEM, - .irq = 63, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 2, - }, - .type = PORT_SCIF, - .irqs = SH7770_SCIF2_IRQS, - .init_pins = sci_init_pins_scif, - }, -#elif defined(CONFIG_CPU_SUBTYPE_SH7780) - { - .port = { - .membase = (void *)0xffe00000, - .mapbase = 0xffe00000, - .iotype = UPIO_MEM, - .irq = 43, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 0, - }, - .type = PORT_SCIF, - .irqs = SH7780_SCIF0_IRQS, - .init_pins = sci_init_pins_scif, - }, - { - .port = { - .membase = (void *)0xffe10000, - .mapbase = 0xffe10000, - .iotype = UPIO_MEM, - .irq = 79, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 1, - }, - .type = PORT_SCIF, - .irqs = SH7780_SCIF1_IRQS, - .init_pins = sci_init_pins_scif, - }, +static void __init sci_init_ports(void) +{ + static int first = 1; + int i; + + if (!first) + return; + + first = 0; + + for (i = 0; i < SCI_NPORTS; i++) { + sci_ports[i].port.ops = &sci_uart_ops; + sci_ports[i].port.iotype = UPIO_MEM; + sci_ports[i].port.line = i; + sci_ports[i].port.fifosize = 1; + +#if defined(__H8300H__) || defined(__H8300S__) +#ifdef __H8300S__ + sci_ports[i].enable = h8300_sci_enable; + sci_ports[i].disable = h8300_sci_disable; +#endif + sci_ports[i].port.uartclk = CONFIG_CPU_CLOCK; +#elif defined(CONFIG_SUPERH64) + sci_ports[i].port.uartclk = current_cpu_data.module_clock * 16; #else -#error "CPU subtype not defined" + /* + * XXX: We should use a proper SCI/SCIF clock + */ + { + struct clk *clk = clk_get(NULL, "module_clk"); + sci_ports[i].port.uartclk = clk_get_rate(clk) * 16; + clk_put(clk); + } #endif -}; + + sci_ports[i].break_timer.data = (unsigned long)&sci_ports[i]; + sci_ports[i].break_timer.function = sci_break_timer; + + init_timer(&sci_ports[i].break_timer); + } +} + +int __init early_sci_setup(struct uart_port *port) +{ + if (unlikely(port->line > SCI_NPORTS)) + return -ENODEV; + + sci_init_ports(); + + sci_ports[port->line].port.membase = port->membase; + sci_ports[port->line].port.mapbase = port->mapbase; + sci_ports[port->line].port.type = port->type; + + return 0; +} #ifdef CONFIG_SERIAL_SH_SCI_CONSOLE /* @@ -1560,34 +1197,38 @@ static int __init serial_console_setup(struct console *co, char *options) 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; + serial_console_port = &sci_ports[co->index]; port = &serial_console_port->port; - port->type = serial_console_port->type; - -#ifdef CONFIG_SUPERH64 - /* This is especially needed on sh64 to remap the SCIF */ - sci_config_port(port, 0); -#endif /* - * We need to set the initial uartclk here, since otherwise it will - * only ever be setup at sci_init() time. + * 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. */ -#if defined(__H8300H__) || defined(__H8300S__) - port->uartclk = CONFIG_CPU_CLOCK; + if (!port->type) + return -ENODEV; + if (!port->membase || !port->mapbase) + return -ENODEV; + + spin_lock_init(&port->lock); + + port->type = serial_console_port->type; + + if (port->flags & UPF_IOREMAP) + sci_config_port(port, 0); + + if (serial_console_port->enable) + serial_console_port->enable(port); -#if defined(__H8300S__) - h8300_sci_enable(port, sci_enable); -#endif -#elif defined(CONFIG_SUPERH64) - port->uartclk = current_cpu_info.module_clock * 16; -#else - { - struct clk *clk = clk_get("module_clk"); - port->uartclk = clk_get_rate(clk) * 16; - clk_put(clk); - } -#endif if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); @@ -1605,17 +1246,17 @@ static struct console serial_console = { .device = uart_console_device, .write = serial_console_write, .setup = serial_console_setup, - .flags = CON_PRINTBUFFER, + .flags = CON_PRINTBUFFER, .index = -1, .data = &sci_uart_driver, }; static int __init sci_console_init(void) { + sci_init_ports(); register_console(&serial_console); return 0; } - console_initcall(sci_console_init); #endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */ @@ -1650,6 +1291,8 @@ int __init kgdb_console_setup(struct console *co, char *options) int parity = 'n'; int flow = 'n'; + spin_lock_init(&port->lock); + if (co->index != kgdb_portnum) co->index = kgdb_portnum; @@ -1678,10 +1321,10 @@ static struct console kgdb_console = { /* Register the KGDB console so we get messages (d'oh!) */ static int __init kgdb_console_init(void) { + sci_init_ports(); register_console(&kgdb_console); return 0; } - console_initcall(kgdb_console_init); #endif /* CONFIG_SH_KGDB_CONSOLE */ @@ -1699,66 +1342,135 @@ static char banner[] __initdata = static struct uart_driver sci_uart_driver = { .owner = THIS_MODULE, .driver_name = "sci", -#ifdef CONFIG_DEVFS_FS - .devfs_name = "ttsc/", -#endif .dev_name = "ttySC", .major = SCI_MAJOR, .minor = SCI_MINOR_START, + .nr = SCI_NPORTS, .cons = SCI_CONSOLE, }; -static int __init sci_init(void) +/* + * 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) { - int chan, ret; + struct plat_sci_port *p = dev->dev.platform_data; + int i; - printk("%s", banner); + for (i = 0; p && p->flags != 0 && i < SCI_NPORTS; p++, i++) { + struct sci_port *sciport = &sci_ports[i]; - sci_uart_driver.nr = ARRAY_SIZE(sci_ports); + sciport->port.mapbase = p->mapbase; - ret = uart_register_driver(&sci_uart_driver); - if (ret == 0) { - for (chan = 0; chan < SCI_NPORTS; chan++) { - struct sci_port *sciport = &sci_ports[chan]; + /* + * For the simple (and majority of) cases where we don't need + * to do any remapping, just cast the cookie directly. + */ + if (p->mapbase && !p->membase && !(p->flags & UPF_IOREMAP)) + p->membase = (void __iomem *)p->mapbase; -#if defined(__H8300H__) || defined(__H8300S__) - sciport->port.uartclk = CONFIG_CPU_CLOCK; -#elif defined(CONFIG_SUPERH64) - sciport->port.uartclk = current_cpu_info.module_clock * 16; -#else - struct clk *clk = clk_get("module_clk"); - sciport->port.uartclk = clk_get_rate(clk) * 16; - clk_put(clk); -#endif - uart_add_one_port(&sci_uart_driver, &sciport->port); - sciport->break_timer.data = (unsigned long)sciport; - sciport->break_timer.function = sci_break_timer; - init_timer(&sciport->break_timer); - } + sciport->port.membase = p->membase; + + sciport->port.irq = p->irqs[SCIx_TXI_IRQ]; + sciport->port.flags = p->flags; + sciport->port.dev = &dev->dev; + + sciport->type = sciport->port.type = p->type; + + memcpy(&sciport->irqs, &p->irqs, sizeof(p->irqs)); + + uart_add_one_port(&sci_uart_driver, &sciport->port); } #ifdef CONFIG_CPU_FREQ cpufreq_register_notifier(&sci_nb, CPUFREQ_TRANSITION_NOTIFIER); - printk("sci: CPU frequency notifier registered\n"); + dev_info(&dev->dev, "sci: CPU frequency notifier registered\n"); #endif #ifdef CONFIG_SH_STANDARD_BIOS sh_bios_gdb_detach(); #endif - return ret; + return 0; } -static void __exit sci_exit(void) +static int __devexit sci_remove(struct platform_device *dev) +{ + int i; + + for (i = 0; i < SCI_NPORTS; i++) + uart_remove_one_port(&sci_uart_driver, &sci_ports[i].port); + + return 0; +} + +static int sci_suspend(struct platform_device *dev, pm_message_t state) { - int chan; + int i; + + for (i = 0; i < SCI_NPORTS; i++) { + struct sci_port *p = &sci_ports[i]; + + if (p->type != PORT_UNKNOWN && p->port.dev == &dev->dev) + uart_suspend_port(&sci_uart_driver, &p->port); + } - for (chan = 0; chan < SCI_NPORTS; chan++) - uart_remove_one_port(&sci_uart_driver, &sci_ports[chan].port); + return 0; +} +static int sci_resume(struct platform_device *dev) +{ + int i; + + for (i = 0; i < SCI_NPORTS; i++) { + struct sci_port *p = &sci_ports[i]; + + if (p->type != PORT_UNKNOWN && p->port.dev == &dev->dev) + uart_resume_port(&sci_uart_driver, &p->port); + } + + return 0; +} + +static struct platform_driver sci_driver = { + .probe = sci_probe, + .remove = __devexit_p(sci_remove), + .suspend = sci_suspend, + .resume = sci_resume, + .driver = { + .name = "sh-sci", + .owner = THIS_MODULE, + }, +}; + +static int __init sci_init(void) +{ + int ret; + + printk(banner); + + sci_init_ports(); + + 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); } module_init(sci_init); module_exit(sci_exit); +MODULE_LICENSE("GPL");