summaryrefslogtreecommitdiff
path: root/drivers/tty
diff options
context:
space:
mode:
authorStefan Agner <stefan.agner@toradex.com>2019-07-29 22:52:03 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2019-09-04 13:43:46 +0300
commit656321793ff419eda148d91dd02b167d6da819e4 (patch)
tree37b9b479cece4a26099f470f809feaf3a1dda23b /drivers/tty
parentb777b5de6aaa98df37c0fe1f7a33fa1c63d0e326 (diff)
downloadlinux-656321793ff419eda148d91dd02b167d6da819e4.tar.xz
tty: serial: fsl_lpuart: fix framing error handling when using DMA
When using DMA framing error get cleared properly. However, due to the additional read from the data register, an underflow in the receive FIFO buffer occurs (the FIFO pointer gets out of sync). Clear the FIFO in case an underflow has occurred. Also disable the receiver during this operation and when reading the data register to minimize potential interference. Signed-off-by: Stefan Agner <stefan.agner@toradex.com> Acked-by: Max Krummenacher <max.krummenacher@toradex.com> Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com> Cc: Stefan Agner <stefan@agner.ch> Cc: Bhuvanchandra DV <bhuvanchandra.dv@toradex.com> Cc: Chris Healy <cphealy@gmail.com> Cc: Cory Tusar <cory.tusar@zii.aero> Cc: Lucas Stach <l.stach@pengutronix.de> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Jiri Slaby <jslaby@suse.com> Cc: linux-imx@nxp.com Cc: linux-serial@vger.kernel.org Cc: linux-kernel@vger.kernel.org Link: https://lore.kernel.org/r/20190729195226.8862-2-andrew.smirnov@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty')
-rw-r--r--drivers/tty/serial/fsl_lpuart.c26
1 files changed, 26 insertions, 0 deletions
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index d15e65f88214..0643fa368d35 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -983,6 +983,13 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport)
unsigned char sr = readb(sport->port.membase + UARTSR1);
if (sr & (UARTSR1_PE | UARTSR1_FE)) {
+ unsigned char cr2;
+
+ /* Disable receiver during this operation... */
+ cr2 = readb(sport->port.membase + UARTCR2);
+ cr2 &= ~UARTCR2_RE;
+ writeb(cr2, sport->port.membase + UARTCR2);
+
/* Read DR to clear the error flags */
readb(sport->port.membase + UARTDR);
@@ -990,6 +997,25 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport)
sport->port.icount.parity++;
else if (sr & UARTSR1_FE)
sport->port.icount.frame++;
+ /*
+ * At this point parity/framing error is
+ * cleared However, since the DMA already read
+ * the data register and we had to read it
+ * again after reading the status register to
+ * properly clear the flags, the FIFO actually
+ * underflowed... This requires a clearing of
+ * the FIFO...
+ */
+ if (readb(sport->port.membase + UARTSFIFO) &
+ UARTSFIFO_RXUF) {
+ writeb(UARTSFIFO_RXUF,
+ sport->port.membase + UARTSFIFO);
+ writeb(UARTCFIFO_RXFLUSH,
+ sport->port.membase + UARTCFIFO);
+ }
+
+ cr2 |= UARTCR2_RE;
+ writeb(cr2, sport->port.membase + UARTCR2);
}
}