aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVignesh Raghavendra <vigneshr@ti.com>2020-10-29 10:49:30 +0530
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2021-07-14 16:56:49 +0200
commite0e3e0b7dabf9399983c763325bfcd163833085f (patch)
tree1f4bbe27f4fa928d0afaa9f7c766f7b0a750a662
parent786461739ac4bcd87218478920ade53c7ca04ce9 (diff)
downloadlinux-e0e3e0b7dabf9399983c763325bfcd163833085f.tar.gz
serial: 8250: 8250_omap: Disable RX interrupt after DMA enable
[ Upstream commit 439c7183e5b97952bba1747f5ffc4dea45a6a18b ] UARTs on TI SoCs prior to J7200 don't provide independent control over RX FIFO not empty interrupt (RHR_IT) and RX timeout interrupt. Starting with J7200 SoC, its possible to disable RHR_IT independent of RX timeout interrupt using bit 2 of IER2 register. So disable RHR_IT once RX DMA is started so as to avoid spurious interrupt being raised when data is in the RX FIFO but is yet to be drained by DMA (a known errata in older SoCs). Signed-off-by: Vignesh Raghavendra <vigneshr@ti.com> Link: https://lore.kernel.org/r/20201029051930.7097-1-vigneshr@ti.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Sasha Levin <sashal@kernel.org>
-rw-r--r--drivers/tty/serial/8250/8250_omap.c42
1 files changed, 41 insertions, 1 deletions
diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
index f284c6f77a6c0..a9cfe1c576425 100644
--- a/drivers/tty/serial/8250/8250_omap.c
+++ b/drivers/tty/serial/8250/8250_omap.c
@@ -27,6 +27,7 @@
#include <linux/pm_qos.h>
#include <linux/pm_wakeirq.h>
#include <linux/dma-mapping.h>
+#include <linux/sys_soc.h>
#include "8250.h"
@@ -41,6 +42,7 @@
*/
#define UART_ERRATA_CLOCK_DISABLE (1 << 3)
#define UART_HAS_EFR2 BIT(4)
+#define UART_HAS_RHR_IT_DIS BIT(5)
#define OMAP_UART_FCR_RX_TRIG 6
#define OMAP_UART_FCR_TX_TRIG 4
@@ -94,6 +96,10 @@
#define OMAP_UART_REV_52 0x0502
#define OMAP_UART_REV_63 0x0603
+/* Interrupt Enable Register 2 */
+#define UART_OMAP_IER2 0x1B
+#define UART_OMAP_IER2_RHR_IT_DIS BIT(2)
+
/* Enhanced features register 2 */
#define UART_OMAP_EFR2 0x23
#define UART_OMAP_EFR2_TIMEOUT_BEHAVE BIT(6)
@@ -756,17 +762,27 @@ static void __dma_rx_do_complete(struct uart_8250_port *p)
{
struct uart_8250_dma *dma = p->dma;
struct tty_port *tty_port = &p->port.state->port;
+ struct omap8250_priv *priv = p->port.private_data;
struct dma_chan *rxchan = dma->rxchan;
dma_cookie_t cookie;
struct dma_tx_state state;
int count;
int ret;
+ u32 reg;
if (!dma->rx_running)
goto out;
cookie = dma->rx_cookie;
dma->rx_running = 0;
+
+ /* Re-enable RX FIFO interrupt now that transfer is complete */
+ if (priv->habit & UART_HAS_RHR_IT_DIS) {
+ reg = serial_in(p, UART_OMAP_IER2);
+ reg &= ~UART_OMAP_IER2_RHR_IT_DIS;
+ serial_out(p, UART_OMAP_IER2, UART_OMAP_IER2_RHR_IT_DIS);
+ }
+
dmaengine_tx_status(rxchan, cookie, &state);
count = dma->rx_size - state.residue + state.in_flight_bytes;
@@ -862,6 +878,7 @@ static int omap_8250_rx_dma(struct uart_8250_port *p)
int err = 0;
struct dma_async_tx_descriptor *desc;
unsigned long flags;
+ u32 reg;
if (priv->rx_dma_broken)
return -EINVAL;
@@ -897,6 +914,17 @@ static int omap_8250_rx_dma(struct uart_8250_port *p)
dma->rx_cookie = dmaengine_submit(desc);
+ /*
+ * Disable RX FIFO interrupt while RX DMA is enabled, else
+ * spurious interrupt may be raised when data is in the RX FIFO
+ * but is yet to be drained by DMA.
+ */
+ if (priv->habit & UART_HAS_RHR_IT_DIS) {
+ reg = serial_in(p, UART_OMAP_IER2);
+ reg |= UART_OMAP_IER2_RHR_IT_DIS;
+ serial_out(p, UART_OMAP_IER2, UART_OMAP_IER2_RHR_IT_DIS);
+ }
+
dma_async_issue_pending(dma->rxchan);
out:
spin_unlock_irqrestore(&priv->rx_dma_lock, flags);
@@ -1163,6 +1191,11 @@ static int omap8250_no_handle_irq(struct uart_port *port)
return 0;
}
+static const struct soc_device_attribute k3_soc_devices[] = {
+ { .family = "AM65X", },
+ { .family = "J721E", .revision = "SR1.0" },
+};
+
static struct omap8250_dma_params am654_dma = {
.rx_size = SZ_2K,
.rx_trigger = 1,
@@ -1177,7 +1210,7 @@ static struct omap8250_dma_params am33xx_dma = {
static struct omap8250_platdata am654_platdata = {
.dma_params = &am654_dma,
- .habit = UART_HAS_EFR2,
+ .habit = UART_HAS_EFR2 | UART_HAS_RHR_IT_DIS,
};
static struct omap8250_platdata am33xx_platdata = {
@@ -1367,6 +1400,13 @@ static int omap8250_probe(struct platform_device *pdev)
up.dma->rxconf.src_maxburst = RX_TRIGGER;
up.dma->txconf.dst_maxburst = TX_TRIGGER;
}
+
+ /*
+ * AM65x SR1.0, AM65x SR2.0 and J721e SR1.0 don't
+ * don't have RHR_IT_DIS bit in IER2 register
+ */
+ if (soc_device_match(k3_soc_devices))
+ priv->habit &= ~UART_HAS_RHR_IT_DIS;
}
#endif
ret = serial8250_register_8250_port(&up);