Skip to content

Commit

Permalink
serial: 8250: 8250_omap: Disable RX interrupt after DMA enable
Browse files Browse the repository at this point in the history
[ Upstream commit 439c718 ]

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>
  • Loading branch information
r-vignesh authored and gregkh committed Jul 14, 2021
1 parent 7864617 commit e0e3e0b
Showing 1 changed file with 41 additions and 1 deletion.
42 changes: 41 additions & 1 deletion drivers/tty/serial/8250/8250_omap.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand All @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand All @@ -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 = {
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit e0e3e0b

Please sign in to comment.