X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fserial%2Fsh-sci.c;h=ad5b776d779b3ca56a8db712ddd89defefe2dbce;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=f5f3e08bf3e9458f0451005aff9c6fddffcaaf80;hpb=9213980e6a70d8473e0ffd4b39ab5b6caaba9ff5;p=linux-2.6.git diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index f5f3e08bf..ad5b776d7 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 Paul Mundt + * Copyright (C) 2002, 2003, 2004 Paul Mundt * * based off of the old drivers/char/sh-sci.c by: * @@ -18,7 +18,8 @@ * for more details. */ -#define DEBUG +#undef DEBUG + #include #include #include @@ -40,6 +41,7 @@ #include #include #include +#include #ifdef CONFIG_CPU_FREQ #include @@ -50,7 +52,6 @@ #include #include #include -#include #include @@ -90,12 +91,12 @@ static struct uart_driver sci_uart_driver; #if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB) -static void handle_error(struct sci_port *port) +static void handle_error(struct uart_port *port) { /* Clear error flags */ sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port)); } -static int get_char(struct sci_port *port) +static int get_char(struct uart_port *port) { unsigned long flags; unsigned short status; @@ -332,11 +333,11 @@ static void sci_init_pins_sci(struct uart_port *port, unsigned int cflag) #if defined(SCIF_ONLY) || defined(SCI_AND_SCIF) #if defined(CONFIG_CPU_SH3) -/* For SH7707, SH7709, SH7709A, SH7729 */ +/* For SH7705, SH7707, SH7709, SH7709A, SH7729, SH7300*/ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag) { unsigned int fcr_val = 0; - +#if !defined(CONFIG_CPU_SUBTYPE_SH7300) /* SH7300 doesn't use RTS/CTS */ { unsigned short data; @@ -360,6 +361,7 @@ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag) /* Set /RTS2 (bit6) = 0 */ ctrl_outb(data&0xbf, SCPDR); } +#endif sci_out(port, SCFCR, fcr_val); } @@ -420,7 +422,7 @@ static void sci_transmit_chars(struct uart_port *port) #if !defined(SCI_ONLY) if (port->type == PORT_SCIF) { - txroom = 16 - (sci_in(port, SCFDR)>>8); + txroom = SCIF_TXROOM_MAX - (sci_in(port, SCFDR)>>8); } else { txroom = (sci_in(port, SCxSR) & SCI_TDRE)?1:0; } @@ -488,7 +490,7 @@ static inline void sci_receive_chars(struct uart_port *port, while (1) { #if !defined(SCI_ONLY) if (port->type == PORT_SCIF) { - count = sci_in(port, SCFDR)&0x001f; + count = sci_in(port, SCFDR)&SCIF_RFDC_MASK ; } else { count = (sci_in(port, SCxSR)&SCxSR_RDxF(port))?1:0; } @@ -671,8 +673,7 @@ static inline int sci_handle_breaks(struct uart_port *port) pr_debug("sci: BREAK detected\n"); } -#if defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_ST40STB1) || \ - defined(CONFIG_CPU_SUBTYPE_SH7760) +#if defined(SCIF_ORER) /* XXX: Handle SCIF overrun error */ if (port->type == PORT_SCIF && (sci_in(port, SCLSR) & SCIF_ORER) != 0) { sci_out(port, SCLSR, 0); @@ -726,6 +727,19 @@ static irqreturn_t sci_er_interrupt(int irq, void *ptr, struct pt_regs *regs) sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); } } else { +#if defined(SCIF_ORER) + if((sci_in(port, SCLSR) & SCIF_ORER) != 0) { + struct tty_struct *tty = port->info->tty; + + sci_out(port, SCLSR, 0); + if(tty->flip.countflip.flag_buf_ptr++ = TTY_OVERRUN; + tty->flip.count++; + tty_flip_buffer_push(tty); + pr_debug("scif: overrun error\n"); + } + } +#endif sci_rx_interrupt(irq, ptr, regs); } @@ -748,6 +762,30 @@ static irqreturn_t sci_br_interrupt(int irq, void *ptr, struct pt_regs *regs) return IRQ_HANDLED; } +static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr, struct pt_regs *regs) +{ + unsigned short ssr_status, scr_status; + struct uart_port *port = ptr; + + ssr_status = sci_in(port,SCxSR); + scr_status = sci_in(port,SCSCR); + + /* Tx Interrupt */ + if ((ssr_status&0x0020) && (scr_status&0x0080)) + sci_tx_interrupt(irq, ptr, regs); + /* Rx Interrupt */ + if ((ssr_status&0x0002) && (scr_status&0x0040)) + sci_rx_interrupt(irq, ptr, regs); + /* Error Interrupt */ + if ((ssr_status&0x0080) && (scr_status&0x0400)) + sci_er_interrupt(irq, ptr, regs); + /* Break Interrupt */ + if ((ssr_status&0x0010) && (scr_status&0x0200)) + sci_br_interrupt(irq, ptr, regs); + + return IRQ_HANDLED; +} + #ifdef CONFIG_CPU_FREQ /* * Here we define a transistion notifier so that we can update all of our @@ -761,7 +799,7 @@ static int sci_notifier(struct notifier_block *self, unsigned long phase, void * if ((phase == CPUFREQ_POSTCHANGE) || (phase == CPUFREQ_RESUMECHANGE)){ for (i = 0; i < SCI_NPORTS; i++) { - struct uart_port *port = &sci_ports[i]; + struct uart_port *port = &sci_ports[i].port; /* * Update the uartclk per-port if frequency has @@ -797,14 +835,26 @@ static int sci_request_irq(struct sci_port *port) const char *desc[] = { "SCI Receive Error", "SCI Receive Data Full", "SCI Transmit Data Empty", "SCI Break" }; - 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 (port->irqs[0] == port->irqs[1]) { + if (!port->irqs[0]) { + 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)) { printk(KERN_ERR "sci: Cannot allocate irq.\n"); return -ENODEV; } + } else { + 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)) { + printk(KERN_ERR "sci: Cannot allocate irq.\n"); + return -ENODEV; + } + } } return 0; @@ -814,11 +864,18 @@ static void sci_free_irq(struct sci_port *port) { int i; - for (i = 0; i < ARRAY_SIZE(port->irqs); i++) { - if (!port->irqs[i]) - continue; - - free_irq(port->irqs[i], port); + if (port->irqs[0] == port->irqs[1]) { + if (!port->irqs[0]) + printk("sci: sci_free_irq error\n"); + else + free_irq(port->irqs[0], port); + } else { + for (i = 0; i < ARRAY_SIZE(port->irqs); i++) { + if (!port->irqs[i]) + continue; + + free_irq(port->irqs[i], port); + } } } @@ -873,7 +930,7 @@ static void sci_start_rx(struct uart_port *port, unsigned int tty_start) /* Set RIE (Receive Interrupt Enable) bit in SCSCR */ local_irq_save(flags); ctrl = sci_in(port, SCSCR); - ctrl |= SCI_CTRL_FLAGS_RIE; + ctrl |= SCI_CTRL_FLAGS_RIE | SCI_CTRL_FLAGS_REIE; sci_out(port, SCSCR, ctrl); local_irq_restore(flags); } @@ -886,7 +943,7 @@ static void sci_stop_rx(struct uart_port *port) /* Clear RIE (Receive Interrupt Enable) bit in SCSCR */ local_irq_save(flags); ctrl = sci_in(port, SCSCR); - ctrl &= ~SCI_CTRL_FLAGS_RIE; + ctrl &= ~(SCI_CTRL_FLAGS_RIE | SCI_CTRL_FLAGS_REIE); sci_out(port, SCSCR, ctrl); local_irq_restore(flags); } @@ -976,7 +1033,7 @@ static void sci_set_termios(struct uart_port *port, struct termios *termios, case 38400: t = BPS_38400; break; case 57600: t = BPS_57600; break; case 115200: t = BPS_115200; break; - default: t = BPS_115200; break; + default: t = SCBRR_VALUE(baud); break; } if (t > 0) { @@ -1026,6 +1083,13 @@ static void sci_config_port(struct uart_port *port, int flags) struct sci_port *s = &sci_ports[port->line]; port->type = s->type; + +#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; +#endif } static int sci_verify_port(struct uart_port *port, struct serial_struct *ser) @@ -1076,6 +1140,35 @@ static struct sci_port sci_ports[SCI_NPORTS] = { .irqs = SCI_IRQS, .init_pins = sci_init_pins_sci, }, +#elif defined(CONFIG_CPU_SUBTYPE_SH7705) + { + .port = { + .membase = (void *)SCIF0, + .mapbase = SCIF0, + .iotype = SERIAL_IO_MEM, + .irq = 55, + .ops = &sci_uart_ops, + .flags = ASYNC_BOOT_AUTOCONF, + .line = 0, + }, + .type = PORT_SCIF, + .irqs = SH3_IRDA_IRQS, + .init_pins = sci_init_pins_scif, + }, + { + .port = { + .membase = (void *)SCIF2, + .mapbase = SCIF2, + .iotype = SERIAL_IO_MEM, + .irq = 59, + .ops = &sci_uart_ops, + .flags = ASYNC_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 = { @@ -1119,6 +1212,51 @@ static struct sci_port sci_ports[SCI_NPORTS] = { .irqs = SH3_IRDA_IRQS, .init_pins = sci_init_pins_irda, } +#elif defined(CONFIG_CPU_SUBTYPE_SH7300) + { + .port = { + .membase = (void *)0xA4430000, + .mapbase = 0xA4430000, + .iotype = SERIAL_IO_MEM, + .irq = 25, + .ops = &sci_uart_ops, + .flags = ASYNC_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 = SERIAL_IO_MEM, + .irq = 25, + .ops = &sci_uart_ops, + .flags = ASYNC_BOOT_AUTOCONF, + .line = 0, + }, + .type = PORT_SCIF, + .irqs = SH73180_SCIF_IRQS, + .init_pins = sci_init_pins_scif, + }, +#elif defined(CONFIG_SH_RTS7751R2D) + { + .port = { + .membase = (void *)0xffe80000, + .mapbase = 0xffe80000, + .iotype = SERIAL_IO_MEM, + .irq = 43, + .ops = &sci_uart_ops, + .flags = ASYNC_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 = { @@ -1191,6 +1329,21 @@ static struct sci_port sci_ports[SCI_NPORTS] = { .irqs = SH7760_SCIF2_IRQS, .init_pins = sci_init_pins_scif, }, +#elif defined(CONFIG_CPU_SUBTYPE_SH4_202) + { + .port = { + .membase = (void *)0xffe80000, + .mapbase = 0xffe80000, + .iotype = SERIAL_IO_MEM, + .irq = 43, + .ops = &sci_uart_ops, + .flags = ASYNC_BOOT_AUTOCONF, + .line = 0, + }, + .type = PORT_SCIF, + .irqs = SH4_SCIF_IRQS, + .init_pins = sci_init_pins_scif, + }, #elif defined(CONFIG_CPU_SUBTYPE_ST40STB1) { .port = { @@ -1220,6 +1373,19 @@ static struct sci_port sci_ports[SCI_NPORTS] = { .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 = SERIAL_IO_MEM, + .irq = 42, + .ops = &sci_uart_ops, + .flags = ASYNC_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 = { @@ -1338,6 +1504,11 @@ static int __init serial_console_setup(struct console *co, char *options) 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. @@ -1374,18 +1545,7 @@ static struct console serial_console = { static int __init sci_console_init(void) { -#ifdef CONFIG_SH_EARLY_PRINTK - extern void sh_console_unregister(void); - - /* - * Now that the real console is available, unregister the one we - * used while first booting. - */ - sh_console_unregister(); -#endif - register_console(&serial_console); - return 0; } @@ -1451,8 +1611,7 @@ static struct console kgdb_console = { /* Register the KGDB console so we get messages (d'oh!) */ static int __init kgdb_console_init(void) { - register_console(&kgdb_console); - + register_console(&kgdb_console); return 0; }