This is an automated email from the ASF dual-hosted git repository. xiaoxiang pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 62194400f933d31d29e5dada616c6e8c81707732 Author: Jukka Laitinen <[email protected]> AuthorDate: Mon Oct 28 09:32:16 2024 +0200 imx9/serial: Take proper use of RX/TX FIFOs, clean up interrupt service routine - i.MX93 LPUARTs have 16-byte RX and TX FIFOs. Take those into use and correct some related register definitions - There is no reason to loop inside interrupt handler, remove the looping Signed-off-by: Jukka Laitinen <[email protected]> --- arch/arm64/src/imx9/hardware/imx9_lpuart.h | 24 ++--- arch/arm64/src/imx9/imx9_lowputc.c | 5 + arch/arm64/src/imx9/imx9_lpuart.c | 155 ++++++++++++++--------------- 3 files changed, 93 insertions(+), 91 deletions(-) diff --git a/arch/arm64/src/imx9/hardware/imx9_lpuart.h b/arch/arm64/src/imx9/hardware/imx9_lpuart.h index c688d5966a..f29cde48a2 100644 --- a/arch/arm64/src/imx9/hardware/imx9_lpuart.h +++ b/arch/arm64/src/imx9/hardware/imx9_lpuart.h @@ -287,22 +287,22 @@ /* LPUART Watermark Register (WATER) */ -#define LPUART_WATER_TXWATER_SHIFT (0) /* Bits 0-1: Transmit Watermark (TXWATER) */ -#define LPUART_WATER_TXWATER_MASK (0x03 << LPUART_WATER_TXWATER_SHIFT) +#define LPUART_WATER_TXWATER_SHIFT (0) /* Bits 0-3: Transmit Watermark (TXWATER) */ +#define LPUART_WATER_TXWATER_MASK (0x0f << LPUART_WATER_TXWATER_SHIFT) # define LPUART_WATER_TXWATER(n) ((n) << LPUART_WATER_TXWATER_SHIFT) - /* Bits 2-7: Reserved */ -#define LPUART_WATER_TXCOUNT_SHIFT (8) /* Bits 8-10: Transmit Counter (TXCOUNT) */ -#define LPUART_WATER_TXCOUNT_MASK (0x07 << LPUART_WATER_TXCOUNT_SHIFT) + /* Bits 4-7: Reserved */ +#define LPUART_WATER_TXCOUNT_SHIFT (8) /* Bits 8-12: Transmit Counter (TXCOUNT) */ +#define LPUART_WATER_TXCOUNT_MASK (0x1f << LPUART_WATER_TXCOUNT_SHIFT) # define LPUART_WATER_TXCOUNT(n) ((n) << LPUART_WATER_TXCOUNT_SHIFT) - /* Bits 11-15: Reserved */ -#define LPUART_WATER_RXWATER_SHIFT (16) /* Bits 16-17: Receive Watermark (RXWATER) */ -#define LPUART_WATER_RXWATER_MASK (0x03 << LPUART_WATER_RXWATER_SHIFT) + /* Bits 13-15: Reserved */ +#define LPUART_WATER_RXWATER_SHIFT (16) /* Bits 16-19: Receive Watermark (RXWATER) */ +#define LPUART_WATER_RXWATER_MASK (0x0f << LPUART_WATER_RXWATER_SHIFT) # define LPUART_WATER_RXWATER(n) ((n) << LPUART_WATER_RXWATER_SHIFT) - /* Bits 18-23: Reserved */ -#define LPUART_WATER_RXCOUNT_SHIFT (24) /* Bits 24-26: Receive Counter (RXCOUNT) */ -#define LPUART_WATER_RXCOUNT_MASK (0x07 << LPUART_WATER_RXCOUNT_SHIFT) + /* Bits 20-23: Reserved */ +#define LPUART_WATER_RXCOUNT_SHIFT (24) /* Bits 24-28: Receive Counter (RXCOUNT) */ +#define LPUART_WATER_RXCOUNT_MASK (0x1f << LPUART_WATER_RXCOUNT_SHIFT) # define LPUART_WATER_RXCOUNT(n) ((n) << LPUART_WATER_RXCOUNT_SHIFT) - /* Bits 27-31: Reserved */ + /* Bits 29-31: Reserved */ /* Data read-only Register (DATARO) */ diff --git a/arch/arm64/src/imx9/imx9_lowputc.c b/arch/arm64/src/imx9/imx9_lowputc.c index a6448ddcb5..b81494374d 100644 --- a/arch/arm64/src/imx9/imx9_lowputc.c +++ b/arch/arm64/src/imx9/imx9_lowputc.c @@ -387,6 +387,11 @@ int imx9_lpuart_configure(uint32_t base, int uartnum, regval &= ~LPUART_GLOBAL_RST; putreg32(regval, base + IMX9_LPUART_GLOBAL_OFFSET); + /* Enable RX and TX FIFOs */ + + putreg32(LPUART_FIFO_RXFE | LPUART_FIFO_TXFE, + base + IMX9_LPUART_FIFO_OFFSET); + /* Construct MODIR register */ regval = 0; diff --git a/arch/arm64/src/imx9/imx9_lpuart.c b/arch/arm64/src/imx9/imx9_lpuart.c index b41bc66cf4..848c2ad7a2 100644 --- a/arch/arm64/src/imx9/imx9_lpuart.c +++ b/arch/arm64/src/imx9/imx9_lpuart.c @@ -1473,8 +1473,6 @@ static int imx9_interrupt(int irq, void *context, void *arg) struct imx9_uart_s *priv; uint32_t usr; uint32_t lsr; - int passes = 0; - bool handled; DEBUGASSERT(dev != NULL && dev != NULL); priv = (struct imx9_uart_s *)dev; @@ -1485,96 +1483,82 @@ static int imx9_interrupt(int irq, void *context, void *arg) pm_activity(PM_IDLE_DOMAIN, CONFIG_IMX9_PM_SERIAL_ACTIVITY); #endif - /* Loop until there are no characters to be transferred or, - * until we have been looping for a long time. + /* Get the current UART status and check for loop + * termination conditions */ - handled = true; - for (passes = 0; passes < 256 && handled; passes++) - { - handled = false; - - /* Get the current UART status and check for loop - * termination conditions - */ + usr = imx9_serialin(priv, IMX9_LPUART_STAT_OFFSET); - usr = imx9_serialin(priv, IMX9_LPUART_STAT_OFFSET); + /* Removed all W1C from the last sr */ - /* Removed all W1C from the last sr */ + lsr = usr & ~(LPUART_STAT_LBKDIF | LPUART_STAT_RXEDGIF | + LPUART_STAT_IDLE | LPUART_STAT_OR | + LPUART_STAT_NF | LPUART_STAT_FE | + LPUART_STAT_PF | LPUART_STAT_MA1F | + LPUART_STAT_MA2F); - lsr = usr & ~(LPUART_STAT_LBKDIF | LPUART_STAT_RXEDGIF | - LPUART_STAT_IDLE | LPUART_STAT_OR | - LPUART_STAT_NF | LPUART_STAT_FE | - LPUART_STAT_PF | LPUART_STAT_MA1F | - LPUART_STAT_MA2F); + /* Keep what we will service */ - /* Keep what we will service */ + usr &= (LPUART_STAT_RDRF | LPUART_STAT_TDRE | LPUART_STAT_OR | + LPUART_STAT_FE | LPUART_STAT_NF | LPUART_STAT_PF | + LPUART_STAT_IDLE); - usr &= (LPUART_STAT_RDRF | LPUART_STAT_TDRE | LPUART_STAT_OR | - LPUART_STAT_FE | LPUART_STAT_NF | LPUART_STAT_PF | - LPUART_STAT_IDLE); + /* Clear serial overrun, parity and framing errors */ - /* Clear serial overrun, parity and framing errors */ - - if ((usr & LPUART_STAT_OR) != 0) - { - imx9_serialout(priv, IMX9_LPUART_STAT_OFFSET, - LPUART_STAT_OR | lsr); - } + if ((usr & LPUART_STAT_OR) != 0) + { + imx9_serialout(priv, IMX9_LPUART_STAT_OFFSET, + LPUART_STAT_OR | lsr); + } - if ((usr & LPUART_STAT_NF) != 0) - { - imx9_serialout(priv, IMX9_LPUART_STAT_OFFSET, - LPUART_STAT_NF | lsr); - } + if ((usr & LPUART_STAT_NF) != 0) + { + imx9_serialout(priv, IMX9_LPUART_STAT_OFFSET, + LPUART_STAT_NF | lsr); + } - if ((usr & LPUART_STAT_PF) != 0) - { - imx9_serialout(priv, IMX9_LPUART_STAT_OFFSET, - LPUART_STAT_PF | lsr); - } + if ((usr & LPUART_STAT_PF) != 0) + { + imx9_serialout(priv, IMX9_LPUART_STAT_OFFSET, + LPUART_STAT_PF | lsr); + } - if ((usr & LPUART_STAT_FE) != 0) - { - imx9_serialout(priv, IMX9_LPUART_STAT_OFFSET, - LPUART_STAT_FE | lsr); - } + if ((usr & LPUART_STAT_FE) != 0) + { + imx9_serialout(priv, IMX9_LPUART_STAT_OFFSET, + LPUART_STAT_FE | lsr); + } - if ((usr & (LPUART_STAT_FE | LPUART_STAT_PF | LPUART_STAT_NF)) != 0) - { - /* Discard data */ + if ((usr & (LPUART_STAT_FE | LPUART_STAT_PF | LPUART_STAT_NF)) != 0) + { + /* Discard data */ - imx9_serialin(priv, IMX9_LPUART_DATA_OFFSET); - } + imx9_serialin(priv, IMX9_LPUART_DATA_OFFSET); + } #ifdef SERIAL_HAVE_RXDMA - /* The line going to idle, deliver any fractions of RX data */ + /* The line going to idle, deliver any fractions of RX data */ - if ((usr & LPUART_STAT_IDLE) != 0) - { - imx9_serialout(priv, IMX9_LPUART_STAT_OFFSET, - LPUART_STAT_IDLE | lsr); - imx9_dma_rxcallback(priv->rxdma, priv, false, LPUART_STAT_IDLE); - } + if ((usr & LPUART_STAT_IDLE) != 0) + { + imx9_serialout(priv, IMX9_LPUART_STAT_OFFSET, + LPUART_STAT_IDLE | lsr); + imx9_dma_rxcallback(priv->rxdma, priv, false, LPUART_STAT_IDLE); + } #endif - /* Handle incoming, receive bytes */ + /* Handle incoming, receive bytes */ - if ((usr & LPUART_STAT_RDRF) != 0 && - (priv->ie & LPUART_CTRL_RIE) != 0) - { - uart_recvchars(dev); - handled = true; - } + if ((priv->ie & LPUART_CTRL_RIE) != 0 && imx9_rxavailable(&priv->dev)) + { + uart_recvchars(dev); + } - /* Handle outgoing, transmit bytes */ + /* Handle outgoing, transmit bytes */ - if ((usr & LPUART_STAT_TDRE) != 0 && - (priv->ie & LPUART_CTRL_TIE) != 0) - { - uart_xmitchars(dev); - handled = true; - } + if ((priv->ie & LPUART_CTRL_TIE) != 0) + { + uart_xmitchars(dev); } return OK; @@ -1947,8 +1931,8 @@ static bool imx9_rxavailable(struct uart_dev_s *dev) /* Return true is data is ready in the Rx FIFO */ - regval = imx9_serialin(priv, IMX9_LPUART_STAT_OFFSET); - return ((regval & LPUART_STAT_RDRF) != 0); + regval = imx9_serialin(priv, IMX9_LPUART_WATER_OFFSET); + return ((regval & LPUART_WATER_RXCOUNT_MASK) != 0); } #endif @@ -2356,7 +2340,7 @@ static void imx9_txint(struct uart_dev_s *dev, bool enable) * Name: imx9_txready * * Description: - * Return true if the transmit register is available to be written to + * Return true if the transmit fifo is available to be written to * ****************************************************************************/ @@ -2364,16 +2348,29 @@ static bool imx9_txready(struct uart_dev_s *dev) { struct imx9_uart_s *priv = (struct imx9_uart_s *)dev; uint32_t regval; + uint32_t fifo_size; + uint32_t fifo_count; + + /* Read the fifo size and current fill ratio. Return true if fifo is not + * full + */ + + regval = imx9_serialin(priv, IMX9_LPUART_FIFO_OFFSET); + fifo_size = (regval & LPUART_FIFO_TXFIFOSIZE_MASK) >> + LPUART_FIFO_TXFIFOSIZE_SHIFT; + fifo_size = fifo_size == 0 ? 1 : (1 << (fifo_size + 1)); + regval = imx9_serialin(priv, IMX9_LPUART_WATER_OFFSET); + fifo_count = (regval & LPUART_WATER_TXCOUNT_MASK) >> + LPUART_WATER_TXCOUNT_SHIFT; - regval = imx9_serialin(priv, IMX9_LPUART_STAT_OFFSET); - return ((regval & LPUART_STAT_TDRE) != 0); + return fifo_count < fifo_size; } /**************************************************************************** * Name: imx9_txempty * * Description: - * Return true if the transmit reg is empty + * Return true if the transmit fifo is empty * ****************************************************************************/ @@ -2382,8 +2379,8 @@ static bool imx9_txempty(struct uart_dev_s *dev) struct imx9_uart_s *priv = (struct imx9_uart_s *)dev; uint32_t regval; - regval = imx9_serialin(priv, IMX9_LPUART_STAT_OFFSET); - return ((regval & LPUART_STAT_TDRE) != 0); + regval = imx9_serialin(priv, IMX9_LPUART_WATER_OFFSET); + return (regval & LPUART_WATER_TXCOUNT_MASK) == 0; } /****************************************************************************
