summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Walleij <linus.walleij@linaro.org>2012-03-13 13:27:23 +0100
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-04-22 15:31:11 -0700
commitdc39a21db504923b95cf2db14280a5105a296c36 (patch)
tree4d2794faf04879a0b25dd140602f87f5226c3d7e
parent39e853a4bb7115e7c1a79a3e1432743d51b27766 (diff)
serial: PL011: clear pending interrupts
commit 9b96fbacda34079dea0638ee1e92c56286f6114a upstream. Chanho Min reported that when the boot loader transfers control to the kernel, there may be pending interrupts causing the UART to lock up in an eternal loop trying to pick tokens from the FIFO (since the RX interrupt flag indicates there are tokens) while in practice there are no tokens - in fact there is only a pending IRQ flag. This patch address the issue with a combination of two patches suggested by Russell King that clears and mask all interrupts at probe() and clears any pending error and RX interrupts at port startup time. We suspect the spurious interrupts are a side-effect of switching the UART from FIFO to non-FIFO mode. Cc: Shreshtha Kumar Sahu <shreshthakumar.sahu@stericsson.com> Reported-by: Chanho Min <chanho0207@gmail.com> Suggested-by: Russell King <linux@arm.linux.org.uk> Signed-off-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Jong-Sung Kim <neidhard.kim@lge.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/tty/serial/amba-pl011.c15
1 files changed, 11 insertions, 4 deletions
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 8e009261e83d..dddc3f27b687 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -1380,6 +1380,10 @@ static int pl011_startup(struct uart_port *port)
uap->port.uartclk = clk_get_rate(uap->clk);
+ /* Clear pending error and receive interrupts */
+ writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS |
+ UART011_RTIS | UART011_RXIS, uap->port.membase + UART011_ICR);
+
/*
* Allocate the IRQ
*/
@@ -1414,10 +1418,6 @@ static int pl011_startup(struct uart_port *port)
cr = UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE;
writew(cr, uap->port.membase + UART011_CR);
- /* Clear pending error interrupts */
- writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS,
- uap->port.membase + UART011_ICR);
-
/*
* initialise the old status of the modem signals
*/
@@ -1432,6 +1432,9 @@ static int pl011_startup(struct uart_port *port)
* as well.
*/
spin_lock_irq(&uap->port.lock);
+ /* Clear out any spuriously appearing RX interrupts */
+ writew(UART011_RTIS | UART011_RXIS,
+ uap->port.membase + UART011_ICR);
uap->im = UART011_RTIM;
if (!pl011_dma_rx_running(uap))
uap->im |= UART011_RXIM;
@@ -1916,6 +1919,10 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
goto unmap;
}
+ /* Ensure interrupts from this UART are masked and cleared */
+ writew(0, uap->port.membase + UART011_IMSC);
+ writew(0xffff, uap->port.membase + UART011_ICR);
+
uap->vendor = vendor;
uap->lcrh_rx = vendor->lcrh_rx;
uap->lcrh_tx = vendor->lcrh_tx;