You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
162 lines
4.8 KiB
162 lines
4.8 KiB
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;
|
|
@@ -1349,6 +1351,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;
|
|
@@ -1398,22 +1412,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);
|
|
@@ -1641,6 +1644,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);
|
|
@@ -1655,6 +1665,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
|
|
@@ -1662,6 +1675,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);
|
|
@@ -1676,6 +1696,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);
|
|
}
|
|
|
|
/*
|
|
@@ -1900,13 +1923,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");
|
|
|
|
@@ -1988,6 +2011,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);
|
|
|
|
@@ -2072,12 +2096,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;
|
|
- }
|
|
}
|
|
}
|
|
|
|
|