* [PATCH 1/2] tty: serial: fsl_lpuart: move the lpuart32_int() below
2023-07-10 1:38 [PATCH 0/2] fsl_lpuart: Add IDLE interrupt support for rx_dma on imx7ulp/imx8ulp/imx8qxp Sherry Sun
@ 2023-07-10 1:38 ` Sherry Sun
2023-07-10 1:38 ` [PATCH 2/2] tty: serial: fsl_lpuart: add IDLE interrupt support for rx_dma on imx7ulp/imx8ulp/imx8qxp Sherry Sun
1 sibling, 0 replies; 3+ messages in thread
From: Sherry Sun @ 2023-07-10 1:38 UTC (permalink / raw)
To: gregkh, jirislaby; +Cc: linux-serial, linux-kernel, linux-imx
Move the lpuart32_int() below lpuart_copy_rx_to_tty(), this is a
preparation patch for the next patch to avoid the function declaration,
no actual functional changes.
Signed-off-by: Sherry Sun <sherry.sun@nxp.com>
---
drivers/tty/serial/fsl_lpuart.c | 39 ++++++++++++++++-----------------
1 file changed, 19 insertions(+), 20 deletions(-)
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index 6c652d77f566..653cf8eb5a72 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -1066,26 +1066,6 @@ static irqreturn_t lpuart_int(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static irqreturn_t lpuart32_int(int irq, void *dev_id)
-{
- struct lpuart_port *sport = dev_id;
- unsigned long sts, rxcount;
-
- sts = lpuart32_read(&sport->port, UARTSTAT);
- rxcount = lpuart32_read(&sport->port, UARTWATER);
- rxcount = rxcount >> UARTWATER_RXCNT_OFF;
-
- if ((sts & UARTSTAT_RDRF || rxcount > 0) && !sport->lpuart_dma_rx_use)
- lpuart32_rxint(sport);
-
- if ((sts & UARTSTAT_TDRE) && !sport->lpuart_dma_tx_use)
- lpuart32_txint(sport);
-
- lpuart32_write(&sport->port, sts, UARTSTAT);
- return IRQ_HANDLED;
-}
-
-
static inline void lpuart_handle_sysrq_chars(struct uart_port *port,
unsigned char *p, int count)
{
@@ -1278,6 +1258,25 @@ static void lpuart_dma_rx_complete(void *arg)
lpuart_copy_rx_to_tty(sport);
}
+static irqreturn_t lpuart32_int(int irq, void *dev_id)
+{
+ struct lpuart_port *sport = dev_id;
+ unsigned long sts, rxcount;
+
+ sts = lpuart32_read(&sport->port, UARTSTAT);
+ rxcount = lpuart32_read(&sport->port, UARTWATER);
+ rxcount = rxcount >> UARTWATER_RXCNT_OFF;
+
+ if ((sts & UARTSTAT_RDRF || rxcount > 0) && !sport->lpuart_dma_rx_use)
+ lpuart32_rxint(sport);
+
+ if ((sts & UARTSTAT_TDRE) && !sport->lpuart_dma_tx_use)
+ lpuart32_txint(sport);
+
+ lpuart32_write(&sport->port, sts, UARTSTAT);
+ return IRQ_HANDLED;
+}
+
/*
* Timer function to simulate the hardware EOP (End Of Package) event.
* The timer callback is to check for new RX data and copy to TTY buffer.
--
2.17.1
^ permalink raw reply [flat|nested] 3+ messages in thread* [PATCH 2/2] tty: serial: fsl_lpuart: add IDLE interrupt support for rx_dma on imx7ulp/imx8ulp/imx8qxp
2023-07-10 1:38 [PATCH 0/2] fsl_lpuart: Add IDLE interrupt support for rx_dma on imx7ulp/imx8ulp/imx8qxp Sherry Sun
2023-07-10 1:38 ` [PATCH 1/2] tty: serial: fsl_lpuart: move the lpuart32_int() below Sherry Sun
@ 2023-07-10 1:38 ` Sherry Sun
1 sibling, 0 replies; 3+ messages in thread
From: Sherry Sun @ 2023-07-10 1:38 UTC (permalink / raw)
To: gregkh, jirislaby; +Cc: linux-serial, linux-kernel, linux-imx
Add IDLE interrupt support for receive dma on imx7ulp/imx8ulp/imx8qxp
platforms to replace the receive dma timer function, because the receive
dma timer has bigger latency than idle interrupt triggering, which may
cause the Bluetooth Firmware download timeout on Android platform(it
has a limited FW download time window).
Signed-off-by: Sherry Sun <sherry.sun@nxp.com>
---
drivers/tty/serial/fsl_lpuart.c | 44 +++++++++++++++++++++++++++++++--
1 file changed, 42 insertions(+), 2 deletions(-)
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index 653cf8eb5a72..c1980ea52666 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -290,6 +290,7 @@ struct lpuart_port {
wait_queue_head_t dma_wait;
bool is_cs7; /* Set to true when character size is 7 */
/* and the parity is enabled */
+ bool dma_idle_int;
};
struct lpuart_soc_data {
@@ -1248,7 +1249,8 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport)
spin_unlock_irqrestore(&sport->port.lock, flags);
tty_flip_buffer_push(port);
- mod_timer(&sport->lpuart_timer, jiffies + sport->dma_rx_timeout);
+ if (!sport->dma_idle_int)
+ mod_timer(&sport->lpuart_timer, jiffies + sport->dma_rx_timeout);
}
static void lpuart_dma_rx_complete(void *arg)
@@ -1258,6 +1260,28 @@ static void lpuart_dma_rx_complete(void *arg)
lpuart_copy_rx_to_tty(sport);
}
+static void lpuart32_dma_idleint(struct lpuart_port *sport)
+{
+ enum dma_status dmastat;
+ struct dma_chan *chan = sport->dma_rx_chan;
+ struct circ_buf *ring = &sport->rx_ring;
+ struct dma_tx_state state;
+ int count = 0;
+
+ dmastat = dmaengine_tx_status(chan, sport->dma_rx_cookie, &state);
+ if (dmastat == DMA_ERROR) {
+ dev_err(sport->port.dev, "Rx DMA transfer failed!\n");
+ return;
+ }
+
+ ring->head = sport->rx_sgl.length - state.residue;
+ count = CIRC_CNT(ring->head, ring->tail, sport->rx_sgl.length);
+
+ /* Check if new data received before copying */
+ if (count)
+ lpuart_copy_rx_to_tty(sport);
+}
+
static irqreturn_t lpuart32_int(int irq, void *dev_id)
{
struct lpuart_port *sport = dev_id;
@@ -1273,6 +1297,9 @@ static irqreturn_t lpuart32_int(int irq, void *dev_id)
if ((sts & UARTSTAT_TDRE) && !sport->lpuart_dma_tx_use)
lpuart32_txint(sport);
+ if ((sts & UARTSTAT_IDLE) && sport->lpuart_dma_rx_use && sport->dma_idle_int)
+ lpuart32_dma_idleint(sport);
+
lpuart32_write(&sport->port, sts, UARTSTAT);
return IRQ_HANDLED;
}
@@ -1394,6 +1421,12 @@ static inline int lpuart_start_rx_dma(struct lpuart_port *sport)
unsigned long temp = lpuart32_read(&sport->port, UARTBAUD);
lpuart32_write(&sport->port, temp | UARTBAUD_RDMAE, UARTBAUD);
+
+ if (sport->dma_idle_int) {
+ unsigned long ctrl = lpuart32_read(&sport->port, UARTCTRL);
+
+ lpuart32_write(&sport->port, ctrl | UARTCTRL_ILIE, UARTCTRL);
+ }
} else {
writeb(readb(sport->port.membase + UARTCR5) | UARTCR5_RDMAS,
sport->port.membase + UARTCR5);
@@ -1409,7 +1442,9 @@ static void lpuart_dma_rx_free(struct uart_port *port)
struct dma_chan *chan = sport->dma_rx_chan;
dmaengine_terminate_sync(chan);
- del_timer_sync(&sport->lpuart_timer);
+ if (!sport->dma_idle_int)
+ del_timer_sync(&sport->lpuart_timer);
+
dma_unmap_sg(chan->device->dev, &sport->rx_sgl, 1, DMA_FROM_DEVICE);
kfree(sport->rx_ring.buf);
sport->rx_ring.tail = 0;
@@ -1671,6 +1706,9 @@ static void lpuart32_setup_watermark_enable(struct lpuart_port *sport)
static void rx_dma_timer_init(struct lpuart_port *sport)
{
+ if (sport->dma_idle_int)
+ return;
+
timer_setup(&sport->lpuart_timer, lpuart_timer_func, 0);
sport->lpuart_timer.expires = jiffies + sport->dma_rx_timeout;
add_timer(&sport->lpuart_timer);
@@ -2833,6 +2871,8 @@ static int lpuart_probe(struct platform_device *pdev)
sport->port.type = PORT_LPUART;
sport->devtype = sdata->devtype;
sport->rx_watermark = sdata->rx_watermark;
+ sport->dma_idle_int = is_imx7ulp_lpuart(sport) || is_imx8ulp_lpuart(sport) ||
+ is_imx8qxp_lpuart(sport);
ret = platform_get_irq(pdev, 0);
if (ret < 0)
return ret;
--
2.17.1
^ permalink raw reply [flat|nested] 3+ messages in thread