aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/layerscape/patches-4.9/816-tty-serial-support-layerscape.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/layerscape/patches-4.9/816-tty-serial-support-layerscape.patch')
-rw-r--r--target/linux/layerscape/patches-4.9/816-tty-serial-support-layerscape.patch163
1 files changed, 163 insertions, 0 deletions
diff --git a/target/linux/layerscape/patches-4.9/816-tty-serial-support-layerscape.patch b/target/linux/layerscape/patches-4.9/816-tty-serial-support-layerscape.patch
new file mode 100644
index 0000000000..3e0d30f61d
--- /dev/null
+++ b/target/linux/layerscape/patches-4.9/816-tty-serial-support-layerscape.patch
@@ -0,0 +1,163 @@
+From 469daac0faff06209bc1d1390571b860d153a82b Mon Sep 17 00:00:00 2001
+From: Yangbo Lu <yangbo.lu@nxp.com>
+Date: Wed, 27 Sep 2017 10:33:47 +0800
+Subject: [PATCH] tty: serial: support layerscape
+
+This is a 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(-)
+
+diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
+index 76103f2c..61453820 100644
+--- 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 *port, struct ktermios *termios,
+ /* 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 *port, struct ktermios *termios,
+ /* 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, const char *s, unsigned int count)
+ {
+ 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, const char *s, unsigned int count)
+ 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 *co, const char *s, unsigned int count)
+ {
+ 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 *co, const char *s, unsigned int count)
+ barrier();
+
+ lpuart32_write(old_cr, sport->port.membase + UARTCTRL);
++
++ if (locked)
++ spin_unlock_irqrestore(&sport->port.lock, flags);
+ }
+
+ /*
+@@ -1899,9 +1922,13 @@ static int lpuart_probe(struct platform_device *pdev)
+
+ 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;
++ 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");
+
+@@ -1983,6 +2010,7 @@ static int lpuart_remove(struct platform_device *pdev)
+ 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);
+
+@@ -2067,12 +2095,10 @@ static int lpuart_resume(struct device *dev)
+
+ 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;
+- }
+ }
+ }
+
+--
+2.14.1
+