diff options
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.patch | 163 |
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 + |