SH: extend SCI DMA support to work on SCIFA ports
[pandora-kernel.git] / drivers / serial / sh-sci.c
index cd52dd6..304a877 100644 (file)
@@ -106,6 +106,7 @@ struct sci_port {
        struct work_struct              work_tx;
        struct work_struct              work_rx;
        struct timer_list               rx_timer;
+       unsigned int                    rx_timeout;
 #endif
 };
 
@@ -673,22 +674,22 @@ static irqreturn_t sci_rx_interrupt(int irq, void *ptr)
        struct sci_port *s = to_sci_port(port);
 
        if (s->chan_rx) {
-               unsigned long tout;
                u16 scr = sci_in(port, SCSCR);
                u16 ssr = sci_in(port, SCxSR);
 
                /* Disable future Rx interrupts */
-               sci_out(port, SCSCR, scr & ~SCI_CTRL_FLAGS_RIE);
+               if (port->type == PORT_SCIFA) {
+                       disable_irq_nosync(irq);
+                       scr |= 0x4000;
+               } else {
+                       scr &= ~SCI_CTRL_FLAGS_RIE;
+               }
+               sci_out(port, SCSCR, scr);
                /* Clear current interrupt */
                sci_out(port, SCxSR, ssr & ~(1 | SCxSR_RDxF(port)));
-               /* Calculate delay for 1.5 DMA buffers */
-               tout = (port->timeout - HZ / 50) * s->buf_len_rx * 3 /
-                       port->fifosize / 2;
-               dev_dbg(port->dev, "Rx IRQ: setup timeout in %lu ms\n",
-                       tout * 1000 / HZ);
-               if (tout < 2)
-                       tout = 2;
-               mod_timer(&s->rx_timer, jiffies + tout);
+               dev_dbg(port->dev, "Rx IRQ %lu: setup t-out in %u jiffies\n",
+                       jiffies, s->rx_timeout);
+               mod_timer(&s->rx_timer, jiffies + s->rx_timeout);
 
                return IRQ_HANDLED;
        }
@@ -925,13 +926,17 @@ static void sci_dma_tx_complete(void *arg)
        s->cookie_tx = -EINVAL;
        s->desc_tx = NULL;
 
-       spin_unlock_irqrestore(&port->lock, flags);
-
        if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
                uart_write_wakeup(port);
 
-       if (uart_circ_chars_pending(xmit))
+       if (!uart_circ_empty(xmit)) {
                schedule_work(&s->work_tx);
+       } else if (port->type == PORT_SCIFA) {
+               u16 ctrl = sci_in(port, SCSCR);
+               sci_out(port, SCSCR, ctrl & ~SCI_CTRL_FLAGS_TIE);
+       }
+
+       spin_unlock_irqrestore(&port->lock, flags);
 }
 
 /* Locking: called with port lock held */
@@ -975,13 +980,13 @@ static void sci_dma_rx_complete(void *arg)
        unsigned long flags;
        int count;
 
-       dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
+       dev_dbg(port->dev, "%s(%d) active #%d\n", __func__, port->line, s->active_rx);
 
        spin_lock_irqsave(&port->lock, flags);
 
        count = sci_dma_rx_push(s, tty, s->buf_len_rx);
 
-       mod_timer(&s->rx_timer, jiffies + msecs_to_jiffies(5));
+       mod_timer(&s->rx_timer, jiffies + s->rx_timeout);
 
        spin_unlock_irqrestore(&port->lock, flags);
 
@@ -1053,6 +1058,8 @@ static void sci_submit_rx(struct sci_port *s)
                        sci_rx_dma_release(s, true);
                        return;
                }
+               dev_dbg(s->port.dev, "%s(): cookie %d to #%d\n", __func__,
+                       s->cookie_rx[i], i);
        }
 
        s->active_rx = s->cookie_rx[0];
@@ -1110,10 +1117,10 @@ static void work_fn_rx(struct work_struct *work)
                return;
        }
 
-       dev_dbg(port->dev, "%s: cookie %d #%d\n", __func__,
-               s->cookie_rx[new], new);
-
        s->active_rx = s->cookie_rx[!new];
+
+       dev_dbg(port->dev, "%s: cookie %d #%d, new active #%d\n", __func__,
+               s->cookie_rx[new], new, s->active_rx);
 }
 
 static void work_fn_tx(struct work_struct *work)
@@ -1175,23 +1182,28 @@ static void work_fn_tx(struct work_struct *work)
 
 static void sci_start_tx(struct uart_port *port)
 {
+       struct sci_port *s = to_sci_port(port);
        unsigned short ctrl;
 
 #ifdef CONFIG_SERIAL_SH_SCI_DMA
-       struct sci_port *s = to_sci_port(port);
-
-       if (s->chan_tx) {
-               if (!uart_circ_empty(&s->port.state->xmit) && s->cookie_tx < 0)
-                       schedule_work(&s->work_tx);
-
-               return;
+       if (port->type == PORT_SCIFA) {
+               u16 new, scr = sci_in(port, SCSCR);
+               if (s->chan_tx)
+                       new = scr | 0x8000;
+               else
+                       new = scr & ~0x8000;
+               if (new != scr)
+                       sci_out(port, SCSCR, new);
        }
+       if (s->chan_tx && !uart_circ_empty(&s->port.state->xmit) &&
+           s->cookie_tx < 0)
+               schedule_work(&s->work_tx);
 #endif
-
-       /* Set TIE (Transmit Interrupt Enable) bit in SCSCR */
-       ctrl = sci_in(port, SCSCR);
-       ctrl |= SCI_CTRL_FLAGS_TIE;
-       sci_out(port, SCSCR, ctrl);
+       if (!s->chan_tx || port->type == PORT_SCIFA) {
+               /* Set TIE (Transmit Interrupt Enable) bit in SCSCR */
+               ctrl = sci_in(port, SCSCR);
+               sci_out(port, SCSCR, ctrl | SCI_CTRL_FLAGS_TIE);
+       }
 }
 
 static void sci_stop_tx(struct uart_port *port)
@@ -1200,6 +1212,8 @@ static void sci_stop_tx(struct uart_port *port)
 
        /* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */
        ctrl = sci_in(port, SCSCR);
+       if (port->type == PORT_SCIFA)
+               ctrl &= ~0x8000;
        ctrl &= ~SCI_CTRL_FLAGS_TIE;
        sci_out(port, SCSCR, ctrl);
 }
@@ -1210,6 +1224,8 @@ static void sci_start_rx(struct uart_port *port)
 
        /* Set RIE (Receive Interrupt Enable) bit in SCSCR */
        ctrl |= sci_in(port, SCSCR);
+       if (port->type == PORT_SCIFA)
+               ctrl &= ~0x4000;
        sci_out(port, SCSCR, ctrl);
 }
 
@@ -1219,6 +1235,8 @@ static void sci_stop_rx(struct uart_port *port)
 
        /* Clear RIE (Receive Interrupt Enable) bit in SCSCR */
        ctrl = sci_in(port, SCSCR);
+       if (port->type == PORT_SCIFA)
+               ctrl &= ~0x4000;
        ctrl &= ~(SCI_CTRL_FLAGS_RIE | SCI_CTRL_FLAGS_REIE);
        sci_out(port, SCSCR, ctrl);
 }
@@ -1253,8 +1271,12 @@ static void rx_timer_fn(unsigned long arg)
 {
        struct sci_port *s = (struct sci_port *)arg;
        struct uart_port *port = &s->port;
-
        u16 scr = sci_in(port, SCSCR);
+
+       if (port->type == PORT_SCIFA) {
+               scr &= ~0x4000;
+               enable_irq(s->irqs[1]);
+       }
        sci_out(port, SCSCR, scr | SCI_CTRL_FLAGS_RIE);
        dev_dbg(port->dev, "DMA Rx timed out\n");
        schedule_work(&s->work_rx);
@@ -1404,8 +1426,12 @@ static void sci_shutdown(struct uart_port *port)
 static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
                            struct ktermios *old)
 {
+#ifdef CONFIG_SERIAL_SH_SCI_DMA
+       struct sci_port *s = to_sci_port(port);
+#endif
        unsigned int status, baud, smr_val, max_baud;
        int t = -1;
+       u16 scfcr = 0;
 
        /*
         * earlyprintk comes here early on with port->uartclk set to zero.
@@ -1428,7 +1454,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
        sci_out(port, SCSCR, 0x00);     /* TE=0, RE=0, CKE1=0 */
 
        if (port->type != PORT_SCI)
-               sci_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST);
+               sci_out(port, SCFCR, scfcr | SCFCR_RFRST | SCFCR_TFRST);
 
        smr_val = sci_in(port, SCSMR) & 3;
        if ((termios->c_cflag & CSIZE) == CS7)
@@ -1459,10 +1485,32 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
        }
 
        sci_init_pins(port, termios->c_cflag);
-       sci_out(port, SCFCR, (termios->c_cflag & CRTSCTS) ? SCFCR_MCE : 0);
+       sci_out(port, SCFCR, scfcr | ((termios->c_cflag & CRTSCTS) ? SCFCR_MCE : 0));
 
        sci_out(port, SCSCR, SCSCR_INIT(port));
 
+#ifdef CONFIG_SERIAL_SH_SCI_DMA
+       /*
+        * Calculate delay for 1.5 DMA buffers: see
+        * drivers/serial/serial_core.c::uart_update_timeout(). With 10 bits
+        * (CS8), 250Hz, 115200 baud and 64 bytes FIFO, the above function
+        * calculates 1 jiffie for the data plus 5 jiffies for the "slop(e)."
+        * Then below we calculate 3 jiffies (12ms) for 1.5 DMA buffers (3 FIFO
+        * sizes), but it has been found out experimentally, that this is not
+        * enough: the driver too often needlessly runs on a DMA timeout. 20ms
+        * as a minimum seem to work perfectly.
+        */
+       if (s->chan_rx) {
+               s->rx_timeout = (port->timeout - HZ / 50) * s->buf_len_rx * 3 /
+                       port->fifosize / 2;
+               dev_dbg(port->dev,
+                       "DMA Rx t-out %ums, tty t-out %u jiffies\n",
+                       s->rx_timeout * 1000 / HZ, port->timeout);
+               if (s->rx_timeout < msecs_to_jiffies(20))
+                       s->rx_timeout = msecs_to_jiffies(20);
+       }
+#endif
+
        if ((termios->c_cflag & CREAD) != 0)
                sci_start_rx(port);
 }