serial: tegra_hsuart: fix receive DMA, RTS, timeout, and tx trigger
authorJay Cheng <jacheng@nvidia.com>
Thu, 19 Aug 2010 11:09:49 +0000 (07:09 -0400)
committerColin Cross <ccross@android.com>
Wed, 6 Oct 2010 23:28:09 +0000 (16:28 -0700)
initialize baud rate and configuration settings to safe default values
when receive DMA is in use, so that the DMA request may be enqueued at
initialization time

re-enqueue the receive DMA buffer immediately it is dequeued by the
DMA threshold callback and the receive ISR, rather than waiting for the
DMA complete callback

originally fixed by Gary King <gking@nvidia.com>

Fixing tx trigger level setting:

On tegra uart, the FCR setting for different tx trigger level
is not same as the 16550 tx trigger level setting. The tegra
uart have the setting in reverse direction on tx fifo attention
level:
b00 for 16 bytes attention level.
b01 for 8 byte attention level.
b10 for 4 byte attention level
b11 for 1 byte attention level.

The rx trigger attention level match with the standard uart
FCR register setttings.

Also fixing the typo in code when setting DTR.
originally fixed by Laxman Dewangan (ldewangan@nvidia.com)

Change-Id: Iea00478f143e61c604828035c6c92d614fa7cccb
Signed-off-by: Jay Cheng <jacheng@nvidia.com>
drivers/serial/tegra_hsuart.c

index 2433a85552709f6fe1e68ede58cae9c42f55751d..33f4592cf6ac7f5495d6d2a31ebdf3a3f688717e 100644 (file)
@@ -73,6 +73,13 @@ const int dma_req_sel[] = {
 #define TEGRA_UART_MIN_DMA             16
 #define TEGRA_UART_FIFO_SIZE           8
 
+/* Tx fifo trigger level setting in tegra uart is in
+ * reverse way then conventional uart */
+#define TEGRA_UART_TX_TRIG_16B 0x00
+#define TEGRA_UART_TX_TRIG_8B  0x10
+#define TEGRA_UART_TX_TRIG_4B  0x20
+#define TEGRA_UART_TX_TRIG_1B  0x30
+
 struct tegra_uart_port {
        struct uart_port        uport;
        char                    port_name[32];
@@ -158,7 +165,7 @@ static void tegra_start_pio_tx(struct tegra_uart_port *t, unsigned int bytes)
                bytes = TEGRA_UART_FIFO_SIZE;
 
        t->fcr_shadow &= ~UART_FCR_T_TRIG_11;
-       t->fcr_shadow |= UART_FCR_T_TRIG_10;
+       t->fcr_shadow |= TEGRA_UART_TX_TRIG_8B;
        uart_writeb(t, t->fcr_shadow, UART_FCR);
        t->tx_in_progress = TEGRA_TX_PIO;
        t->tx_bytes = bytes;
@@ -175,7 +182,7 @@ static void tegra_start_dma_tx(struct tegra_uart_port *t, unsigned long bytes)
                UART_XMIT_SIZE, DMA_TO_DEVICE);
 
        t->fcr_shadow &= ~UART_FCR_T_TRIG_11;
-       t->fcr_shadow |= UART_FCR_T_TRIG_01;
+       t->fcr_shadow |= TEGRA_UART_TX_TRIG_4B;
        uart_writeb(t, t->fcr_shadow, UART_FCR);
 
        t->tx_bytes = bytes & ~(sizeof(u32)-1);
@@ -251,6 +258,10 @@ static void tegra_rx_dma_threshold_callback(struct tegra_dma_req *req)
        if (t->rts_active)
                set_rts(t, false);
        tegra_dma_dequeue(t->rx_dma);
+
+       /* enqueue the request again */
+       tegra_start_dma_rx(t);
+
        if (t->rts_active)
                set_rts(t, true);
 
@@ -293,8 +304,6 @@ static void tegra_rx_dma_complete_callback(struct tegra_dma_req *req)
        spin_unlock(&u->lock);
        tty_flip_buffer_push(u->state->port.tty);
        spin_lock(&u->lock);
-
-       tegra_start_dma_rx(t);
 }
 
 /* Lock already taken */
@@ -303,6 +312,8 @@ static void do_handle_rx_dma(struct tegra_uart_port *t)
        if (t->rts_active)
                set_rts(t, false);
        tegra_dma_dequeue(t->rx_dma);
+       /* enqueue the request again */
+       tegra_start_dma_rx(t);
        if (t->rts_active)
                set_rts(t, true);
 }
@@ -530,6 +541,20 @@ static void tegra_uart_hw_deinit(struct tegra_uart_port *t)
        t->baud = 0;
 }
 
+static void tegra_uart_free_rx_dma(struct tegra_uart_port *t)
+{
+       if (!t->use_rx_dma)
+               return;
+
+       tegra_dma_free_channel(t->rx_dma);
+
+       if (likely(t->rx_dma_req.dest_addr))
+               dma_free_coherent(t->uport.dev, t->rx_dma_req.size,
+                       t->rx_dma_req.virt_addr, t->rx_dma_req.dest_addr);
+
+       t->use_rx_dma = false;
+}
+
 static int tegra_uart_hw_init(struct tegra_uart_port *t)
 {
        unsigned char fcr;
@@ -557,7 +582,7 @@ static int tegra_uart_hw_init(struct tegra_uart_port *t)
        uart_writeb(t, fcr, UART_FCR);
 
        udelay(100);
-       uart_writeb(t, fcr, UART_FCR);
+       uart_writeb(t, t->fcr_shadow, UART_FCR);
        udelay(100);
 
        /* Set the trigger level
@@ -582,12 +607,25 @@ static int tegra_uart_hw_init(struct tegra_uart_port *t)
         *  programmed in the DMA registers.
         * */
        t->fcr_shadow |= UART_FCR_R_TRIG_01;
-       t->fcr_shadow |= UART_FCR_T_TRIG_10;
+       t->fcr_shadow |= TEGRA_UART_TX_TRIG_8B;
        uart_writeb(t, t->fcr_shadow, UART_FCR);
 
-       if (t->use_rx_dma)
-               t->fcr_shadow |= UART_FCR_DMA_SELECT;
-       uart_writeb(t, t->fcr_shadow, UART_FCR);
+       if (t->use_rx_dma) {
+               /* initialize the UART for a simple default configuration
+                 * so that the receive DMA buffer may be enqueued */
+               t->lcr_shadow = 3;  /* no parity, stop, 8 data bits */
+               tegra_set_baudrate(t, 9600);
+                t->fcr_shadow |= UART_FCR_DMA_SELECT;
+               uart_writeb(t, t->fcr_shadow, UART_FCR);
+               if (tegra_start_dma_rx(t)) {
+                       dev_err(t->uport.dev, "Rx DMA enqueue failed\n");
+                       tegra_uart_free_rx_dma(t);
+                       t->fcr_shadow &= ~UART_FCR_DMA_SELECT;
+                       uart_writeb(t, t->fcr_shadow, UART_FCR);
+               }
+       }
+       else
+               uart_writeb(t, t->fcr_shadow, UART_FCR);
 
        /*
         *  Enable IE_RXS for the receive status interrupts like line errros.
@@ -656,10 +694,7 @@ static int tegra_uart_init_rx_dma(struct tegra_uart_port *t)
 
        return 0;
 fail:
-       tegra_dma_free_channel(t->rx_dma);
-       if (t->rx_dma_req.dest_addr)
-               dma_free_coherent(t->uport.dev, t->rx_dma_req.size,
-                       t->rx_dma_req.virt_addr, t->rx_dma_req.dest_addr);
+       tegra_uart_free_rx_dma(t);
        return -ENODEV;
 }
 
@@ -707,9 +742,6 @@ static int tegra_startup(struct uart_port *u)
        if (ret)
                goto fail;
 
-       if (t->use_rx_dma)
-               tegra_start_dma_rx(t);
-
        dev_dbg(u->dev, "Requesting IRQ %d\n", u->irq);
        msleep(1);
 
@@ -738,12 +770,7 @@ static void tegra_shutdown(struct uart_port *u)
 
        tegra_uart_hw_deinit(t);
        spin_unlock_irqrestore(&u->lock, flags);
-       if (t->use_rx_dma) {
-               tegra_dma_free_channel(t->rx_dma);
-               dma_free_coherent(u->dev, t->rx_dma_req.size,
-                       t->rx_dma_req.virt_addr, t->rx_dma_req.dest_addr);
-       }
-
+       tegra_uart_free_rx_dma(t);
        if (t->use_tx_dma)
                tegra_dma_free_channel(t->tx_dma);
 
@@ -788,7 +815,7 @@ static void set_dtr(struct tegra_uart_port *t, bool active)
        if (active)
                mcr |= UART_MCR_DTR;
        else
-               mcr &= UART_MCR_DTR;
+               mcr &= ~UART_MCR_DTR;
        if (mcr != t->mcr_shadow) {
                uart_writeb(t, mcr, UART_MCR);
                t->mcr_shadow = mcr;
@@ -926,6 +953,10 @@ static void tegra_set_termios(struct uart_port *u, struct ktermios *termios,
 
        spin_lock_irqsave(&u->lock, flags);
 
+       /* Changing configuration, it is safe to stop any rx now */
+       if (t->rts_active)
+               set_rts(t, false);
+
        /* Baud rate */
        baud = uart_get_baud_rate(u, termios, oldtermios, 200, 4000000);
        tegra_set_baudrate(t, baud);
@@ -981,6 +1012,9 @@ static void tegra_set_termios(struct uart_port *u, struct ktermios *termios,
                t->mcr_shadow = mcr;
                uart_writeb(t, mcr, UART_MCR);
                t->use_cts_control = true;
+               /* if top layer has asked to set rts active then do so here */
+               if (t->rts_active)
+                       set_rts(t, true);
        } else {
                mcr = t->mcr_shadow;
                mcr &= ~UART_MCR_CTS_EN;
@@ -990,6 +1024,9 @@ static void tegra_set_termios(struct uart_port *u, struct ktermios *termios,
                t->use_cts_control = false;
        }
 
+       /* update the port timeout based on new settings */
+       uart_update_timeout(u, termios->c_cflag, baud);
+
        spin_unlock_irqrestore(&u->lock, flags);
        dev_vdbg(t->uport.dev, "-tegra_set_termios\n");
        return;
@@ -1141,6 +1178,7 @@ static int tegra_uart_probe(struct platform_device *pdev)
        u->line = pdev->id;
        u->ops = &tegra_uart_ops;
        u->type = ~PORT_UNKNOWN;
+       u->fifosize = 32;
        u->mapbase = pdata->mapbase;
        u->membase = pdata->membase;
        u->irq = pdata->irq;