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;
 }
 
 /****************************************************************************

Reply via email to