]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/serial/8250.c
sc1200: remove redundant warning message from sc1200_tune_chipset()
[linux-2.6-omap-h63xx.git] / drivers / serial / 8250.c
index 48e259a0167d180c1f212d3d0f723133dc5ff797..f94109cbb46e683a6a6f7d2fee29d7915b21cc93 100644 (file)
@@ -129,7 +129,16 @@ struct uart_8250_port {
        unsigned char           mcr;
        unsigned char           mcr_mask;       /* mask of user bits */
        unsigned char           mcr_force;      /* mask of forced bits */
-       unsigned char           lsr_break_flag;
+
+       /*
+        * Some bits in registers are cleared on a read, so they must
+        * be saved whenever the register is read but the bits will not
+        * be immediately processed.
+        */
+#define LSR_SAVE_FLAGS UART_LSR_BRK_ERROR_BITS
+       unsigned char           lsr_saved_flags;
+#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
+       unsigned char           msr_saved_flags;
 
        /*
         * We provide a per-port pm hook.
@@ -894,7 +903,7 @@ static void autoconfig_16550a(struct uart_8250_port *up)
                        quot = serial_dl_read(up);
                        quot <<= 3;
 
-                       status1 = serial_in(up, 0x04); /* EXCR1 */
+                       status1 = serial_in(up, 0x04); /* EXCR2 */
                        status1 &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */
                        status1 |= 0x10;  /* 1.625 divisor for baud_base --> 921600 */
                        serial_outp(up, 0x04, status1);
@@ -1238,6 +1247,7 @@ static void serial8250_start_tx(struct uart_port *port)
                if (up->bugs & UART_BUG_TXEN) {
                        unsigned char lsr, iir;
                        lsr = serial_in(up, UART_LSR);
+                       up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
                        iir = serial_in(up, UART_IIR) & 0x0f;
                        if ((up->port.type == PORT_RM9000) ?
                                (lsr & UART_LSR_THRE &&
@@ -1290,18 +1300,10 @@ receive_chars(struct uart_8250_port *up, unsigned int *status)
                flag = TTY_NORMAL;
                up->port.icount.rx++;
 
-#ifdef CONFIG_SERIAL_8250_CONSOLE
-               /*
-                * Recover the break flag from console xmit
-                */
-               if (up->port.line == up->port.cons->index) {
-                       lsr |= up->lsr_break_flag;
-                       up->lsr_break_flag = 0;
-               }
-#endif
+               lsr |= up->lsr_saved_flags;
+               up->lsr_saved_flags = 0;
 
-               if (unlikely(lsr & (UART_LSR_BI | UART_LSR_PE |
-                                   UART_LSR_FE | UART_LSR_OE))) {
+               if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) {
                        /*
                         * For statistics only
                         */
@@ -1392,6 +1394,8 @@ static unsigned int check_modem_status(struct uart_8250_port *up)
 {
        unsigned int status = serial_in(up, UART_MSR);
 
+       status |= up->msr_saved_flags;
+       up->msr_saved_flags = 0;
        if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI &&
            up->port.info != NULL) {
                if (status & UART_MSR_TERI)
@@ -1591,7 +1595,8 @@ static void serial8250_timeout(unsigned long data)
 static void serial8250_backup_timeout(unsigned long data)
 {
        struct uart_8250_port *up = (struct uart_8250_port *)data;
-       unsigned int iir, ier = 0;
+       unsigned int iir, ier = 0, lsr;
+       unsigned long flags;
 
        /*
         * Must disable interrupts or else we risk racing with the interrupt
@@ -1610,9 +1615,13 @@ static void serial8250_backup_timeout(unsigned long data)
         * the "Diva" UART used on the management processor on many HP
         * ia64 and parisc boxes.
         */
+       spin_lock_irqsave(&up->port.lock, flags);
+       lsr = serial_in(up, UART_LSR);
+       up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
+       spin_unlock_irqrestore(&up->port.lock, flags);
        if ((iir & UART_IIR_NO_INT) && (up->ier & UART_IER_THRI) &&
            (!uart_circ_empty(&up->port.info->xmit) || up->port.x_char) &&
-           (serial_in(up, UART_LSR) & UART_LSR_THRE)) {
+           (lsr & UART_LSR_THRE)) {
                iir &= ~(UART_IIR_ID | UART_IIR_NO_INT);
                iir |= UART_IIR_THRI;
        }
@@ -1631,13 +1640,14 @@ static unsigned int serial8250_tx_empty(struct uart_port *port)
 {
        struct uart_8250_port *up = (struct uart_8250_port *)port;
        unsigned long flags;
-       unsigned int ret;
+       unsigned int lsr;
 
        spin_lock_irqsave(&up->port.lock, flags);
-       ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
+       lsr = serial_in(up, UART_LSR);
+       up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
        spin_unlock_irqrestore(&up->port.lock, flags);
 
-       return ret;
+       return lsr & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
 }
 
 static unsigned int serial8250_get_mctrl(struct uart_port *port)
@@ -1708,8 +1718,7 @@ static inline void wait_for_xmitr(struct uart_8250_port *up, int bits)
        do {
                status = serial_in(up, UART_LSR);
 
-               if (status & UART_LSR_BI)
-                       up->lsr_break_flag = UART_LSR_BI;
+               up->lsr_saved_flags |= status & LSR_SAVE_FLAGS;
 
                if (--tmout == 0)
                        break;
@@ -1718,8 +1727,12 @@ static inline void wait_for_xmitr(struct uart_8250_port *up, int bits)
 
        /* Wait up to 1s for flow control if necessary */
        if (up->port.flags & UPF_CONS_FLOW) {
-               tmout = 1000000;
-               while (!(serial_in(up, UART_MSR) & UART_MSR_CTS) && --tmout) {
+               unsigned int tmout;
+               for (tmout = 1000000; tmout; tmout--) {
+                       unsigned int msr = serial_in(up, UART_MSR);
+                       up->msr_saved_flags |= msr & MSR_SAVE_FLAGS;
+                       if (msr & UART_MSR_CTS)
+                               break;
                        udelay(1);
                        touch_nmi_watchdog();
                }
@@ -1888,6 +1901,18 @@ static int serial8250_startup(struct uart_port *port)
 
        spin_unlock_irqrestore(&up->port.lock, flags);
 
+       /*
+        * Clear the interrupt registers again for luck, and clear the
+        * saved flags to avoid getting false values from polling
+        * routines or the previous session.
+        */
+       serial_inp(up, UART_LSR);
+       serial_inp(up, UART_RX);
+       serial_inp(up, UART_IIR);
+       serial_inp(up, UART_MSR);
+       up->lsr_saved_flags = 0;
+       up->msr_saved_flags = 0;
+
        /*
         * Finally, enable interrupts.  Note: Modem status interrupts
         * are set via set_termios(), which will be occurring imminently
@@ -1906,14 +1931,6 @@ static int serial8250_startup(struct uart_port *port)
                (void) inb_p(icp);
        }
 
-       /*
-        * And clear the interrupt registers again for luck.
-        */
-       (void) serial_inp(up, UART_LSR);
-       (void) serial_inp(up, UART_RX);
-       (void) serial_inp(up, UART_IIR);
-       (void) serial_inp(up, UART_MSR);
-
        return 0;
 }
 
@@ -2484,6 +2501,16 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count)
        wait_for_xmitr(up, BOTH_EMPTY);
        serial_out(up, UART_IER, ier);
 
+       /*
+        *      The receive handling will happen properly because the
+        *      receive ready bit will still be set; it is not cleared
+        *      on read.  However, modem control will not, we must
+        *      call it if we have saved something in the saved flags
+        *      while processing with interrupts off.
+        */
+       if (up->msr_saved_flags)
+               check_modem_status(up);
+
        if (locked)
                spin_unlock(&up->port.lock);
        local_irq_restore(flags);
@@ -2514,12 +2541,18 @@ static int __init serial8250_console_setup(struct console *co, char *options)
        return uart_set_options(port, co, baud, parity, bits, flow);
 }
 
+static int serial8250_console_early_setup(void)
+{
+       return serial8250_find_port_for_earlycon();
+}
+
 static struct uart_driver serial8250_reg;
 static struct console serial8250_console = {
        .name           = "ttyS",
        .write          = serial8250_console_write,
        .device         = uart_console_device,
        .setup          = serial8250_console_setup,
+       .early_setup    = serial8250_console_early_setup,
        .flags          = CON_PRINTBUFFER,
        .index          = -1,
        .data           = &serial8250_reg,
@@ -2533,7 +2566,7 @@ static int __init serial8250_console_init(void)
 }
 console_initcall(serial8250_console_init);
 
-static int __init find_port(struct uart_port *p)
+int serial8250_find_port(struct uart_port *p)
 {
        int line;
        struct uart_port *port;
@@ -2546,26 +2579,6 @@ static int __init find_port(struct uart_port *p)
        return -ENODEV;
 }
 
-int __init serial8250_start_console(struct uart_port *port, char *options)
-{
-       int line;
-
-       line = find_port(port);
-       if (line < 0)
-               return -ENODEV;
-
-       add_preferred_console("ttyS", line, options);
-       printk("Adding console on ttyS%d at %s 0x%lx (options '%s')\n",
-               line, port->iotype == UPIO_MEM ? "MMIO" : "I/O port",
-               port->iotype == UPIO_MEM ? (unsigned long) port->mapbase :
-                   (unsigned long) port->iobase, options);
-       if (!(serial8250_console.flags & CON_ENABLED)) {
-               serial8250_console.flags &= ~CON_PRINTBUFFER;
-               register_console(&serial8250_console);
-       }
-       return line;
-}
-
 #define SERIAL8250_CONSOLE     &serial8250_console
 #else
 #define SERIAL8250_CONSOLE     NULL
@@ -2617,7 +2630,22 @@ void serial8250_suspend_port(int line)
  */
 void serial8250_resume_port(int line)
 {
-       uart_resume_port(&serial8250_reg, &serial8250_ports[line].port);
+       struct uart_8250_port *up = &serial8250_ports[line];
+
+       if (up->capabilities & UART_NATSEMI) {
+               unsigned char tmp;
+
+               /* Ensure it's still in high speed mode */
+               serial_outp(up, UART_LCR, 0xE0);
+
+               tmp = serial_in(up, 0x04); /* EXCR2 */
+               tmp &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */
+               tmp |= 0x10;  /* 1.625 divisor for baud_base --> 921600 */
+               serial_outp(up, 0x04, tmp);
+
+               serial_outp(up, UART_LCR, 0);
+       }
+       uart_resume_port(&serial8250_reg, &up->port);
 }
 
 /*
@@ -2649,8 +2677,9 @@ static int __devinit serial8250_probe(struct platform_device *dev)
                ret = serial8250_register_port(&port);
                if (ret < 0) {
                        dev_err(&dev->dev, "unable to register port at index %d "
-                               "(IO%lx MEM%lx IRQ%d): %d\n", i,
-                               p->iobase, p->mapbase, p->irq, ret);
+                               "(IO%lx MEM%llx IRQ%d): %d\n", i,
+                               p->iobase, (unsigned long long)p->mapbase,
+                               p->irq, ret);
                }
        }
        return 0;
@@ -2694,7 +2723,7 @@ static int serial8250_resume(struct platform_device *dev)
                struct uart_8250_port *up = &serial8250_ports[i];
 
                if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev)
-                       uart_resume_port(&serial8250_reg, &up->port);
+                       serial8250_resume_port(i);
        }
 
        return 0;