| From 1866541492641c02874bf51f9d8712b5510f2c64 Mon Sep 17 00:00:00 2001 |
| From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= <u.kleine-koenig@pengutronix.de> |
| Date: Fri, 2 Mar 2018 11:07:28 +0100 |
| Subject: serial: imx: Fix handling of TC irq in combination with DMA |
| MIME-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| From: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> |
| |
| commit 1866541492641c02874bf51f9d8712b5510f2c64 upstream. |
| |
| When using RS485 half duplex the Transmitter Complete irq is needed to |
| determine the moment when the transmitter can be disabled. When using |
| DMA this irq must only be enabled when DMA has completed to transfer all |
| data. Otherwise the CPU might busily trigger this irq which is not |
| properly handled and so the also pending irq for the DMA transfer cannot |
| trigger. |
| |
| Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> |
| [Backport to v4.14] |
| Signed-off-by: Frieder Schrempf <frieder.schrempf@kontron.de> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/tty/serial/imx.c | 22 ++++++++++++++++++---- |
| 1 file changed, 18 insertions(+), 4 deletions(-) |
| |
| --- a/drivers/tty/serial/imx.c |
| +++ b/drivers/tty/serial/imx.c |
| @@ -538,6 +538,11 @@ static void dma_tx_callback(void *data) |
| |
| if (!uart_circ_empty(xmit) && !uart_tx_stopped(&sport->port)) |
| imx_dma_tx(sport); |
| + else if (sport->port.rs485.flags & SER_RS485_ENABLED) { |
| + temp = readl(sport->port.membase + UCR4); |
| + temp |= UCR4_TCEN; |
| + writel(temp, sport->port.membase + UCR4); |
| + } |
| |
| spin_unlock_irqrestore(&sport->port.lock, flags); |
| } |
| @@ -555,6 +560,10 @@ static void imx_dma_tx(struct imx_port * |
| if (sport->dma_is_txing) |
| return; |
| |
| + temp = readl(sport->port.membase + UCR4); |
| + temp &= ~UCR4_TCEN; |
| + writel(temp, sport->port.membase + UCR4); |
| + |
| sport->tx_bytes = uart_circ_chars_pending(xmit); |
| |
| if (xmit->tail < xmit->head || xmit->head == 0) { |
| @@ -617,10 +626,15 @@ static void imx_start_tx(struct uart_por |
| if (!(port->rs485.flags & SER_RS485_RX_DURING_TX)) |
| imx_stop_rx(port); |
| |
| - /* enable transmitter and shifter empty irq */ |
| - temp = readl(port->membase + UCR4); |
| - temp |= UCR4_TCEN; |
| - writel(temp, port->membase + UCR4); |
| + /* |
| + * Enable transmitter and shifter empty irq only if DMA is off. |
| + * In the DMA case this is done in the tx-callback. |
| + */ |
| + if (!sport->dma_is_enabled) { |
| + temp = readl(port->membase + UCR4); |
| + temp |= UCR4_TCEN; |
| + writel(temp, port->membase + UCR4); |
| + } |
| } |
| |
| if (!sport->dma_is_enabled) { |