VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[linux-2.6.git] / drivers / serial / sh-sci.c
index f5f3e08..a6639f4 100644 (file)
@@ -90,12 +90,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 +332,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 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 +360,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 +421,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 +489,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 +672,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 +726,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.count<TTY_FLIPBUF_SIZE) {
+                               *tty->flip.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 +761,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
@@ -797,14 +834,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 +863,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 +929,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 +942,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 +1032,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 +1082,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)
@@ -1119,6 +1182,36 @@ 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_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   = {
@@ -1220,6 +1313,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 +1444,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 +1485,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;
 }
 
@@ -1452,7 +1552,6 @@ static struct console kgdb_console = {
 static int __init kgdb_console_init(void)
 {
         register_console(&kgdb_console);
-
        return 0;
 }