serial: imx: Support sw flow control in DMA mode
authorJiada Wang <jiada_wang@mentor.com>
Tue, 9 Dec 2014 09:11:36 +0000 (18:11 +0900)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 9 Jan 2015 22:23:59 +0000 (14:23 -0800)
This patch adds Software flow control support in DMA mode.

Signed-off-by: Jiada Wang <jiada_wang@mentor.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/tty/serial/imx.c

index 5a7da019f01a30072e3e1288dbcb7d9353e31202..72b800b296b1830020dabd4ec9626dfe55260b27 100644 (file)
@@ -464,9 +464,11 @@ static void imx_enable_ms(struct uart_port *port)
        mod_timer(&sport->timer, jiffies);
 }
 
+static void imx_dma_tx(struct imx_port *sport);
 static inline void imx_transmit_buffer(struct imx_port *sport)
 {
        struct circ_buf *xmit = &sport->port.state->xmit;
+       unsigned long temp;
 
        if (sport->port.x_char) {
                /* Send next char */
@@ -481,6 +483,22 @@ static inline void imx_transmit_buffer(struct imx_port *sport)
                return;
        }
 
+       if (sport->dma_is_enabled) {
+               /*
+                * We've just sent a X-char Ensure the TX DMA is enabled
+                * and the TX IRQ is disabled.
+                **/
+               temp = readl(sport->port.membase + UCR1);
+               temp &= ~UCR1_TXMPTYEN;
+               if (sport->dma_is_txing) {
+                       temp |= UCR1_TDMAEN;
+                       writel(temp, sport->port.membase + UCR1);
+               } else {
+                       writel(temp, sport->port.membase + UCR1);
+                       imx_dma_tx(sport);
+               }
+       }
+
        while (!uart_circ_empty(xmit) &&
               !(readl(sport->port.membase + uts_reg(sport)) & UTS_TXFULL)) {
                /* send xmit->buf[xmit->tail]
@@ -497,7 +515,6 @@ static inline void imx_transmit_buffer(struct imx_port *sport)
                imx_stop_tx(&sport->port);
 }
 
-static void imx_dma_tx(struct imx_port *sport);
 static void dma_tx_callback(void *data)
 {
        struct imx_port *sport = data;
@@ -630,7 +647,16 @@ static void imx_start_tx(struct uart_port *port)
        }
 
        if (sport->dma_is_enabled) {
-               /* FIXME: port->x_char must be transmitted if != 0 */
+               if (sport->port.x_char) {
+                       /* We have X-char to send, so enable TX IRQ and
+                        * disable TX DMA to let TX interrupt to send X-char */
+                       temp = readl(sport->port.membase + UCR1);
+                       temp &= ~UCR1_TDMAEN;
+                       temp |= UCR1_TXMPTYEN;
+                       writel(temp, sport->port.membase + UCR1);
+                       return;
+               }
+
                if (!uart_circ_empty(&port->state->xmit) &&
                    !uart_tx_stopped(port))
                        imx_dma_tx(sport);