OpenWrt – Rev 4

Subversion Repositories:
Rev:
From c35aec61e5bb0faafb2847a0d750ebd7345a4b0f Mon Sep 17 00:00:00 2001
From: Yangbo Lu <yangbo.lu@nxp.com>
Date: Wed, 17 Jan 2018 15:40:24 +0800
Subject: [PATCH 28/30] tty: serial: support layerscape

This is an integrated patch for layerscape uart support.

Signed-off-by: Nikita Yushchenko <nikita.yoush@cogentembedded.com>
Signed-off-by: Yuan Yao <yao.yuan@nxp.com>
Signed-off-by: Stefan Agner <stefan@agner.ch>
Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
---
 drivers/tty/serial/fsl_lpuart.c | 66 ++++++++++++++++++++++++++++-------------
 1 file changed, 46 insertions(+), 20 deletions(-)

--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -231,6 +231,8 @@
 #define DEV_NAME       "ttyLP"
 #define UART_NR                6
 
+static DECLARE_BITMAP(linemap, UART_NR);
+
 struct lpuart_port {
        struct uart_port        port;
        struct clk              *clk;
@@ -1348,6 +1350,18 @@ lpuart_set_termios(struct uart_port *por
        /* ask the core to calculate the divisor */
        baud = uart_get_baud_rate(port, termios, old, 50, port->uartclk / 16);
 
+       /*
+        * Need to update the Ring buffer length according to the selected
+        * baud rate and restart Rx DMA path.
+        *
+        * Since timer function acqures sport->port.lock, need to stop before
+        * acquring same lock because otherwise del_timer_sync() can deadlock.
+        */
+       if (old && sport->lpuart_dma_rx_use) {
+               del_timer_sync(&sport->lpuart_timer);
+               lpuart_dma_rx_free(&sport->port);
+       }
+
        spin_lock_irqsave(&sport->port.lock, flags);
 
        sport->port.read_status_mask = 0;
@@ -1397,22 +1411,11 @@ lpuart_set_termios(struct uart_port *por
        /* restore control register */
        writeb(old_cr2, sport->port.membase + UARTCR2);
 
-       /*
-        * If new baud rate is set, we will also need to update the Ring buffer
-        * length according to the selected baud rate and restart Rx DMA path.
-        */
-       if (old) {
-               if (sport->lpuart_dma_rx_use) {
-                       del_timer_sync(&sport->lpuart_timer);
-                       lpuart_dma_rx_free(&sport->port);
-               }
-
-               if (sport->dma_rx_chan && !lpuart_start_rx_dma(sport)) {
-                       sport->lpuart_dma_rx_use = true;
+       if (old && sport->lpuart_dma_rx_use) {
+               if (!lpuart_start_rx_dma(sport))
                        rx_dma_timer_init(sport);
-               } else {
+               else
                        sport->lpuart_dma_rx_use = false;
-               }
        }
 
        spin_unlock_irqrestore(&sport->port.lock, flags);
@@ -1640,6 +1643,13 @@ lpuart_console_write(struct console *co,
 {
        struct lpuart_port *sport = lpuart_ports[co->index];
        unsigned char  old_cr2, cr2;
+       unsigned long flags;
+       int locked = 1;
+
+       if (sport->port.sysrq || oops_in_progress)
+               locked = spin_trylock_irqsave(&sport->port.lock, flags);
+       else
+               spin_lock_irqsave(&sport->port.lock, flags);
 
        /* first save CR2 and then disable interrupts */
        cr2 = old_cr2 = readb(sport->port.membase + UARTCR2);
@@ -1654,6 +1664,9 @@ lpuart_console_write(struct console *co,
                barrier();
 
        writeb(old_cr2, sport->port.membase + UARTCR2);
+
+       if (locked)
+               spin_unlock_irqrestore(&sport->port.lock, flags);
 }
 
 static void
@@ -1661,6 +1674,13 @@ lpuart32_console_write(struct console *c
 {
        struct lpuart_port *sport = lpuart_ports[co->index];
        unsigned long  old_cr, cr;
+       unsigned long flags;
+       int locked = 1;
+
+       if (sport->port.sysrq || oops_in_progress)
+               locked = spin_trylock_irqsave(&sport->port.lock, flags);
+       else
+               spin_lock_irqsave(&sport->port.lock, flags);
 
        /* first save CR2 and then disable interrupts */
        cr = old_cr = lpuart32_read(sport->port.membase + UARTCTRL);
@@ -1675,6 +1695,9 @@ lpuart32_console_write(struct console *c
                barrier();
 
        lpuart32_write(old_cr, sport->port.membase + UARTCTRL);
+
+       if (locked)
+               spin_unlock_irqrestore(&sport->port.lock, flags);
 }
 
 /*
@@ -1899,13 +1922,13 @@ static int lpuart_probe(struct platform_
 
        ret = of_alias_get_id(np, "serial");
        if (ret < 0) {
-               dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret);
-               return ret;
-       }
-       if (ret >= ARRAY_SIZE(lpuart_ports)) {
-               dev_err(&pdev->dev, "serial%d out of range\n", ret);
-               return -EINVAL;
+               ret = find_first_zero_bit(linemap, UART_NR);
+               if (ret >= UART_NR) {
+                       dev_err(&pdev->dev, "port line is full, add device failed\n");
+                       return ret;
+               }
        }
+       set_bit(ret, linemap);
        sport->port.line = ret;
        sport->lpuart32 = of_device_is_compatible(np, "fsl,ls1021a-lpuart");
 
@@ -1987,6 +2010,7 @@ static int lpuart_remove(struct platform
        struct lpuart_port *sport = platform_get_drvdata(pdev);
 
        uart_remove_one_port(&lpuart_reg, &sport->port);
+       clear_bit(sport->port.line, linemap);
 
        clk_disable_unprepare(sport->clk);
 
@@ -2071,12 +2095,10 @@ static int lpuart_resume(struct device *
 
        if (sport->lpuart_dma_rx_use) {
                if (sport->port.irq_wake) {
-                       if (!lpuart_start_rx_dma(sport)) {
-                               sport->lpuart_dma_rx_use = true;
+                       if (!lpuart_start_rx_dma(sport))
                                rx_dma_timer_init(sport);
-                       } else {
+                       else
                                sport->lpuart_dma_rx_use = false;
-                       }
                }
        }