You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2021/05/05 08:30:14 UTC

[incubator-nuttx] 01/04: xtensa/esp32: Replace serialout/in and fixes the fifo counter issue

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/incubator-nuttx.git

commit afd6b262321cf6f97dac3f37a8b066c905a35d86
Author: Sara Souza <sa...@espressif.com>
AuthorDate: Fri Apr 16 18:35:29 2021 -0300

    xtensa/esp32: Replace serialout/in and fixes the fifo counter issue
---
 arch/xtensa/src/esp32/esp32_serial.c        | 222 +++++++++++++++++++++-------
 arch/xtensa/src/esp32/hardware/esp32_soc.h  |   9 ++
 arch/xtensa/src/esp32/hardware/esp32_uart.h |  22 ++-
 3 files changed, 196 insertions(+), 57 deletions(-)

diff --git a/arch/xtensa/src/esp32/esp32_serial.c b/arch/xtensa/src/esp32/esp32_serial.c
index 623c19a..b211074 100644
--- a/arch/xtensa/src/esp32/esp32_serial.c
+++ b/arch/xtensa/src/esp32/esp32_serial.c
@@ -130,7 +130,7 @@
 
 struct esp32_config_s
 {
-  const uint32_t uartbase;      /* Base address of UART registers */
+  const uint8_t id;             /* UART id */
   uint8_t  periph;              /* UART peripheral ID */
   uint8_t  irq;                 /* IRQ number assigned to the peripheral */
   uint8_t  txpin;               /* Tx pin number (0-39) */
@@ -183,6 +183,10 @@ static bool esp32_txempty(struct uart_dev_s *dev);
  * Private Data
  ****************************************************************************/
 
+#define UART_TX_FIFO_SIZE        128
+#define UART_RX_FIFO_FULL_THRHD  112
+#define UART_RX_TOUT_THRHD_VALUE 0x02
+
 static const struct uart_ops_s g_uart_ops =
 {
   .setup          = esp32_setup,
@@ -222,7 +226,7 @@ static char g_uart2txbuffer[CONFIG_UART2_TXBUFSIZE];
 #ifdef CONFIG_ESP32_UART0
 static const struct esp32_config_s g_uart0config =
 {
-  .uartbase       = DR_REG_UART_BASE,
+  .id             = 0,
   .periph         = ESP32_PERIPH_UART,
   .irq            = ESP32_IRQ_UART,
   .txpin          = CONFIG_ESP32_UART0_TXPIN,
@@ -268,7 +272,7 @@ static uart_dev_t g_uart0port =
 #ifdef CONFIG_ESP32_UART1
 static const struct esp32_config_s g_uart1config =
 {
-  .uartbase       = DR_REG_UART1_BASE,
+  .id             = 1,
   .periph         = ESP32_PERIPH_UART1,
   .irq            = ESP32_IRQ_UART1,
   .txpin          = CONFIG_ESP32_UART1_TXPIN,
@@ -314,7 +318,7 @@ static uart_dev_t g_uart1port =
 #ifdef CONFIG_ESP32_UART2
 static const struct esp32_config_s g_uart2config =
 {
-  .uartbase       = DR_REG_UART2_BASE,
+  .id             = 2,
   .periph         = ESP32_PERIPH_UART2,
   .irq            = ESP32_IRQ_UART2,
   .txpin          = CONFIG_ESP32_UART2_TXPIN,
@@ -360,22 +364,106 @@ static uart_dev_t g_uart2port =
  ****************************************************************************/
 
 /****************************************************************************
- * Name: esp32_serialin
+ * Name: esp32_reset_rx_fifo
+ *
+ * Description:
+ *   Resets the RX FIFO. 
+ *   NOTE: We can not use rxfifo_rst to reset the hardware RX FIFO.
+ *
+ * Parameters:
+ *   priv        -  Pointer to the serial driver struct.
+ *
  ****************************************************************************/
 
-static inline uint32_t esp32_serialin(struct esp32_dev_s *priv, int offset)
+static void esp32_reset_rx_fifo(struct esp32_dev_s *priv)
 {
-  return getreg32(priv->config->uartbase + offset);
+  uint32_t rx_status_reg = getreg32(UART_STATUS_REG(priv->config->id));
+  uint32_t fifo_cnt = REG_MASK(rx_status_reg, UART_RXFIFO_CNT);
+  uint32_t mem_rx_status_reg = getreg32(UART_MEM_RX_STATUS_REG
+                                        (priv->config->id));
+  uint32_t rd_address = REG_MASK(mem_rx_status_reg, UART_RD_ADDRESS);
+  uint32_t wr_address = REG_MASK(mem_rx_status_reg, UART_WR_ADDRESS);
+
+  while ((fifo_cnt != 0) || (rd_address != wr_address))
+    {
+      getreg32(DR_UART_FIFO_REG(priv->config->id));
+
+      rx_status_reg     = getreg32(UART_STATUS_REG(priv->config->id));
+      fifo_cnt = REG_MASK(rx_status_reg, UART_RXFIFO_CNT);
+      mem_rx_status_reg = getreg32(UART_MEM_RX_STATUS_REG(priv->config->id));
+      rd_address = REG_MASK(mem_rx_status_reg, UART_RD_ADDRESS);
+      wr_address = REG_MASK(mem_rx_status_reg, UART_WR_ADDRESS);
+    }
 }
 
 /****************************************************************************
- * Name: esp32_serialout
+ * Name: esp32_reset_tx_fifo
+ *
+ * Description:
+ *   Resets the TX FIFO. 
+ *
+ * Parameters:
+ *   priv        -  Pointer to the serial driver struct.
+ *
  ****************************************************************************/
 
-static inline void esp32_serialout(struct esp32_dev_s *priv, int offset,
-                                   uint32_t value)
+static void esp32_reset_tx_fifo(struct esp32_dev_s *priv)
 {
-  putreg32(value, priv->config->uartbase + offset);
+  modifyreg32(UART_CONF0_REG(priv->config->id), 0, UART_TXFIFO_RST_M);
+  modifyreg32(UART_CONF0_REG(priv->config->id), UART_TXFIFO_RST_M, 0);
+}
+
+/****************************************************************************
+ * Name: esp32_get_rx_fifo_len
+ *
+ * Description:
+ *   Get the real value on rx fixo.
+ *   RX_FIFO_CNT shouldn't be used alone accordingly to:
+ *   https://www.espressif.com/sites/default/files/documentation/eco_
+ *   and_workarounds_for_bugs_in_esp32_en.pdf.
+ *   So, some arithmetic with the read and write RX FIFO pointers are
+ *   necessary.
+ *
+ * Parameters:
+ *   priv        -  Pointer to the serial driver struct.
+ *
+ * Return:
+ *   The number of bytes in RX fifo.
+ *
+ ****************************************************************************/
+
+static uint32_t esp32_get_rx_fifo_len(struct esp32_dev_s *priv)
+{
+  uint32_t rd_address;
+  uint32_t wr_address;
+  uint32_t fifo_cnt;
+  uint32_t mem_rx_status_reg;
+  uint32_t rx_status_reg;
+  uint32_t len;
+
+  mem_rx_status_reg = getreg32(UART_MEM_RX_STATUS_REG(priv->config->id));
+  rd_address        = ((mem_rx_status_reg & UART_RD_ADDRESS_M) 
+                       >> UART_RD_ADDRESS_S);
+  wr_address        = ((mem_rx_status_reg & UART_WR_ADDRESS_M) 
+                       >> UART_WR_ADDRESS_S);
+  rx_status_reg     = getreg32(UART_STATUS_REG(priv->config->id)); 
+  fifo_cnt          = ((rx_status_reg & UART_RXFIFO_CNT_M)
+                       >> UART_RXFIFO_CNT_S);
+
+  if (wr_address > rd_address)
+    {
+      len = wr_address - rd_address;
+    }
+  else if (wr_address < rd_address)
+    {
+      len = (wr_address + 128) - rd_address;
+    }
+  else 
+    {
+      len = fifo_cnt > 0 ? 128 : 0;
+    }
+
+  return len;
 }
 
 /****************************************************************************
@@ -389,7 +477,7 @@ static inline void esp32_restoreuartint(struct esp32_dev_s *priv,
    * (assuming all interrupts disabled)
    */
 
-  esp32_serialout(priv, UART_INT_ENA_OFFSET, intena);
+  putreg32(intena, UART_INT_ENA_REG(priv->config->id));
 }
 
 /****************************************************************************
@@ -408,12 +496,12 @@ static void esp32_disableallints(struct esp32_dev_s *priv, uint32_t *intena)
     {
       /* Return the current interrupt mask */
 
-      *intena = esp32_serialin(priv, UART_INT_ENA_OFFSET);
+      *intena = getreg32(UART_INT_ENA_REG(priv->config->id));
     }
 
   /* Disable all interrupts */
 
-  esp32_serialout(priv, UART_INT_ENA_OFFSET, 0);
+  putreg32(0, UART_INT_ENA_REG(priv->config->id));
   leave_critical_section(flags);
 }
 
@@ -504,7 +592,7 @@ static int esp32_setup(struct uart_dev_s *dev)
 
   regval  = (clkdiv >> 4) << UART_CLKDIV_S;
   regval |= (clkdiv & 15) << UART_CLKDIV_FRAG_S;
-  esp32_serialout(priv, UART_CLKDIV_OFFSET, regval);
+  putreg32(regval, UART_CLKDIV_REG(priv->config->id));
 
   /* Configure UART pins
    *
@@ -530,17 +618,22 @@ static int esp32_setup(struct uart_dev_s *dev)
 
   regval = UART_RXFIFO_FULL_INT_ENA | UART_FRM_ERR_INT_ENA |
            UART_RXFIFO_TOUT_INT_ENA;
-  esp32_serialout(priv, UART_INT_ENA_OFFSET, regval);
+  putreg32(regval, UART_INT_ENA_REG(priv->config->id));
+
+  putreg32(UINT32_MAX, UART_INT_CLR_REG(priv->config->id));
 
-  esp32_serialout(priv, UART_INT_CLR_OFFSET, 0xffffffff);
+  /* Reset the RX and TX FIFO */
+
+  esp32_reset_rx_fifo(priv);
+  esp32_reset_tx_fifo(priv);
 
   /* Configure and enable the UART */
 
-  esp32_serialout(priv, UART_CONF0_OFFSET, conf0);
-  regval = (112 << UART_RXFIFO_FULL_THRHD_S) |
-           (0x02 << UART_RX_TOUT_THRHD_S) |
-            UART_RX_TOUT_EN;
-  esp32_serialout(priv, UART_CONF1_OFFSET, regval);
+  putreg32(conf0, UART_CONF0_REG(priv->config->id));
+  regval = (UART_RX_FIFO_FULL_THRHD << UART_RXFIFO_FULL_THRHD_S) |
+           (UART_RX_TOUT_THRHD_VALUE << UART_RX_TOUT_THRHD_S) |
+           UART_RX_TOUT_EN;
+  putreg32(regval, UART_CONF1_REG(priv->config->id));
 #endif
 
   return OK;
@@ -569,7 +662,7 @@ static void esp32_shutdown(struct uart_dev_s *dev)
 
   do
     {
-      status = esp32_serialin(priv, UART_STATUS_OFFSET);
+      status = getreg32(UART_STATUS_REG(priv->config->id));
     }
   while ((status & UART_TXFIFO_CNT_M) != 0);
 
@@ -598,11 +691,11 @@ static void esp32_shutdown(struct uart_dev_s *dev)
 
   /* Unconfigure and disable the UART */
 
-  esp32_serialout(priv, UART_CONF0_OFFSET, 0);
-  esp32_serialout(priv, UART_CONF1_OFFSET, 0);
+  putreg32(0, UART_CONF0_REG(priv->config->id));
+  putreg32(0, UART_CONF1_REG(priv->config->id));
 
-  esp32_serialout(priv, UART_INT_ENA_OFFSET, 0);
-  esp32_serialout(priv, UART_INT_CLR_OFFSET, 0xffffffff);
+  putreg32(0, UART_INT_ENA_REG(priv->config->id));
+  putreg32(UINT32_MAX, UART_INT_CLR_REG(priv->config->id));
 }
 
 /****************************************************************************
@@ -734,16 +827,16 @@ static int esp32_interrupt(int cpuint, void *context, FAR void *arg)
   for (passes = 0; passes < 256 && handled; passes++)
     {
       handled      = false;
-      priv->status = esp32_serialin(priv, UART_INT_RAW_OFFSET);
-      status       = esp32_serialin(priv, UART_STATUS_OFFSET);
-      enabled      = esp32_serialin(priv, UART_INT_ENA_OFFSET);
+      priv->status = getreg32(UART_INT_RAW_REG(priv->config->id));
+      status       = getreg32(UART_STATUS_REG(priv->config->id));
+      enabled      = getreg32(UART_INT_ENA_REG(priv->config->id));
 
       /* Clear pending interrupts */
 
       regval = (UART_RXFIFO_FULL_INT_CLR | UART_FRM_ERR_INT_CLR |
                 UART_RXFIFO_TOUT_INT_CLR | UART_TX_DONE_INT_CLR |
                 UART_TXFIFO_EMPTY_INT_CLR);
-      esp32_serialout(priv, UART_INT_CLR_OFFSET, regval);
+      putreg32(regval, UART_INT_CLR_REG(priv->config->id));
 
       /* Are Rx interrupts enabled?  The upper layer may hold off Rx input
        * by disabling the Rx interrupts if there is no place to saved the
@@ -755,7 +848,7 @@ static int esp32_interrupt(int cpuint, void *context, FAR void *arg)
         {
           /* Is there any data waiting in the Rx FIFO? */
 
-          nfifo = (status & UART_RXFIFO_CNT_M) >> UART_RXFIFO_CNT_S;
+          nfifo = esp32_get_rx_fifo_len(priv);
           if (nfifo > 0)
             {
               /* Received data in the RXFIFO! ... Process incoming bytes */
@@ -1000,6 +1093,7 @@ static int esp32_ioctl(struct file *filep, int cmd, unsigned long arg)
 static int  esp32_receive(struct uart_dev_s *dev, unsigned int *status)
 {
   struct esp32_dev_s *priv = (struct esp32_dev_s *)dev->priv;
+  uint32_t rx_fifo;
 
   /* Return the error information in the saved status */
 
@@ -1008,8 +1102,9 @@ static int  esp32_receive(struct uart_dev_s *dev, unsigned int *status)
 
   /* Then return the actual received byte */
 
-  return (int)(esp32_serialin(priv, UART_FIFO_OFFSET) &
-               UART_RXFIFO_RD_BYTE_M);
+  rx_fifo = getreg32(DR_UART_FIFO_REG(priv->config->id));
+
+  return (int)(rx_fifo & UART_RXFIFO_RD_BYTE_M);
 }
 
 /****************************************************************************
@@ -1035,20 +1130,20 @@ static void esp32_rxint(struct uart_dev_s *dev, bool enable)
        */
 
 #ifndef CONFIG_SUPPRESS_SERIAL_INTS
-      regval  = esp32_serialin(priv, UART_INT_ENA_OFFSET);
+      regval  = getreg32(UART_INT_ENA_REG(priv->config->id));
       regval |= (UART_RXFIFO_FULL_INT_ENA | UART_FRM_ERR_INT_ENA |
                  UART_RXFIFO_TOUT_INT_ENA);
-      esp32_serialout(priv, UART_INT_ENA_OFFSET, regval);
+      putreg32(regval, UART_INT_ENA_REG(priv->config->id));
 #endif
     }
   else
     {
       /* Disable the RX interrupts */
 
-      regval  = esp32_serialin(priv, UART_INT_ENA_OFFSET);
+      regval  = getreg32(UART_INT_ENA_REG(priv->config->id));
       regval &= ~(UART_RXFIFO_FULL_INT_ENA | UART_FRM_ERR_INT_ENA |
                   UART_RXFIFO_TOUT_INT_ENA);
-      esp32_serialout(priv, UART_INT_ENA_OFFSET, regval);
+      putreg32(regval, UART_INT_ENA_REG(priv->config->id));
     }
 
   leave_critical_section(flags);
@@ -1065,9 +1160,7 @@ static void esp32_rxint(struct uart_dev_s *dev, bool enable)
 static bool esp32_rxavailable(struct uart_dev_s *dev)
 {
   struct esp32_dev_s *priv = (struct esp32_dev_s *)dev->priv;
-
-  return ((esp32_serialin(priv, UART_STATUS_OFFSET)
-          & UART_RXFIFO_CNT_M) > 0);
+  return esp32_get_rx_fifo_len(priv) > 0;
 }
 
 /****************************************************************************
@@ -1082,7 +1175,7 @@ static void esp32_send(struct uart_dev_s *dev, int ch)
 {
   struct esp32_dev_s *priv = (struct esp32_dev_s *)dev->priv;
 
-  esp32_serialout(priv, UART_FIFO_OFFSET, (uint32_t)ch);
+  putreg32((uint32_t)ch, AHB_UART_FIFO_REG(priv->config->id));
 }
 
 /****************************************************************************
@@ -1097,20 +1190,16 @@ static void esp32_txint(struct uart_dev_s *dev, bool enable)
 {
   struct esp32_dev_s *priv = (struct esp32_dev_s *)dev->priv;
   irqstate_t flags;
-  int regval;
 
   flags = enter_critical_section();
 
   if (enable)
     {
-      /* Set to receive an interrupt when the TX holding register register
-       * is empty
-       */
+      /* Set to receive an interrupt when the TX holding register is empty */
 
 #ifndef CONFIG_SUPPRESS_SERIAL_INTS
-      regval  = esp32_serialin(priv, UART_INT_ENA_OFFSET);
-      regval |= (UART_TX_DONE_INT_ENA | UART_TXFIFO_EMPTY_INT_ENA);
-      esp32_serialout(priv, UART_INT_ENA_OFFSET, regval);
+      modifyreg32(UART_INT_ENA_REG(priv->config->id),
+                  0, (UART_TX_DONE_INT_ENA | UART_TXFIFO_EMPTY_INT_ENA));
 
       /* Fake a TX interrupt here by just calling uart_xmitchars() with
        * interrupts disabled (note this may recurse).
@@ -1123,9 +1212,8 @@ static void esp32_txint(struct uart_dev_s *dev, bool enable)
     {
       /* Disable the TX interrupt */
 
-      regval  = esp32_serialin(priv, UART_INT_ENA_OFFSET);
-      regval &= ~(UART_TX_DONE_INT_ENA | UART_TXFIFO_EMPTY_INT_ENA);
-      esp32_serialout(priv, UART_INT_ENA_OFFSET, regval);
+      modifyreg32(UART_INT_ENA_REG(priv->config->id),
+                  (UART_TX_DONE_INT_ENA | UART_TXFIFO_EMPTY_INT_ENA), 0);
     }
 
   leave_critical_section(flags);
@@ -1144,10 +1232,17 @@ static bool esp32_txready(struct uart_dev_s *dev)
   uint32_t txcnt;
   struct esp32_dev_s *priv = (struct esp32_dev_s *)dev->priv;
 
-  txcnt = (esp32_serialin(priv, UART_STATUS_OFFSET) >> UART_TXFIFO_CNT_S) &
+  txcnt = (getreg32(UART_STATUS_REG(priv->config->id)) >> UART_TXFIFO_CNT_S) &
           UART_TXFIFO_CNT_V;
 
-  return txcnt < 0x7f;
+  if (txcnt < (UART_TX_FIFO_SIZE -1))
+    {
+      return true;
+    }
+  else
+    {
+      return false;
+    }
 }
 
 /****************************************************************************
@@ -1162,8 +1257,8 @@ static bool esp32_txempty(struct uart_dev_s *dev)
 {
   struct esp32_dev_s *priv = (struct esp32_dev_s *)dev->priv;
 
-  return ((esp32_serialin(priv, UART_STATUS_OFFSET) & UART_TXFIFO_CNT_M)
-          == 0);
+  return ((getreg32(UART_STATUS_REG(priv->config->id))
+          & UART_TXFIFO_CNT_M) == 0);
 }
 
 /****************************************************************************
@@ -1171,6 +1266,21 @@ static bool esp32_txempty(struct uart_dev_s *dev)
  ****************************************************************************/
 
 /****************************************************************************
+ * Name: esp32_lowsetup
+ *
+ * Description:
+ *   Performs the low level UART initialization early in debug so that the
+ *   serial console will be available during bootup.  This must be called
+ *   before up_serialinit.
+ *
+ ****************************************************************************/
+
+void esp32_lowsetup(void)
+{
+ 
+}
+
+/****************************************************************************
  * Name: xtensa_early_serial_initialize
  *
  * Description:
diff --git a/arch/xtensa/src/esp32/hardware/esp32_soc.h b/arch/xtensa/src/esp32/hardware/esp32_soc.h
index f208741..2d2b037 100644
--- a/arch/xtensa/src/esp32/hardware/esp32_soc.h
+++ b/arch/xtensa/src/esp32/hardware/esp32_soc.h
@@ -244,6 +244,15 @@
 #define DR_REG_PWM3_BASE                        0x3ff70000
 #define PERIPHS_SPI_ENCRYPT_BASEADDR            DR_REG_SPI_ENCRYPT_BASE
 
+/* Some AHB addresses can be used instead of DPORT addresses
+ * as a workaround for some HW bugs.
+ * This workaround is detailed at
+ * https://www.espressif.com/sites/default/files/documentation/
+ * eco_and_workarounds_for_bugs_in_esp32_en.pdf
+ */
+
+#define AHB_REG_UART_BASE   0x60000000
+
 /* Overall memory map */
 
 #define SOC_DROM_LOW            0x3f400000
diff --git a/arch/xtensa/src/esp32/hardware/esp32_uart.h b/arch/xtensa/src/esp32/hardware/esp32_uart.h
index 73cfd87..cba15cb 100644
--- a/arch/xtensa/src/esp32/hardware/esp32_uart.h
+++ b/arch/xtensa/src/esp32/hardware/esp32_uart.h
@@ -32,9 +32,11 @@
  ****************************************************************************/
 
 #define REG_UART_BASE(i)                 (DR_REG_UART_BASE + (i) * 0x10000 + (i > 1 ? 0xe000 : 0))
+#define AHB_FIFO_BASE(i)                 (AHB_REG_UART_BASE + (i) * 0x10000 + (i > 1 ? 0xe000 : 0))
 
 #define UART_FIFO_OFFSET                 0x00
-#define UART_FIFO_REG(i)                 (REG_UART_BASE(i) + UART_FIFO_OFFSET)
+#define AHB_UART_FIFO_REG(i)             (AHB_FIFO_BASE(i) + UART_FIFO_OFFSET)
+#define DR_UART_FIFO_REG(i)              (REG_UART_BASE(i) + UART_FIFO_OFFSET)
 
 /* UART_RXFIFO_RD_BYTE : RO ;bitpos:[7:0] ;default: 8'b0 ; */
 
@@ -1798,6 +1800,24 @@
 #define UART_MEM_RX_STATUS_V            0xFFFFFF
 #define UART_MEM_RX_STATUS_S            0
 
+/* UART_RD_ADDRESS : bitpos:[12:2] */
+
+/* Description: Read address of the UART RX FIFO. (a pointer) */
+
+#define UART_RD_ADDRESS                 0x000007FF
+#define UART_RD_ADDRESS_M               ((UART_RD_ADDRESS_V) << (UART_RD_ADDRESS_S))
+#define UART_RD_ADDRESS_V               0x7FF
+#define UART_RD_ADDRESS_S               2
+
+/* UART_WR_ADDRESS : bitpos:[23:13] */
+
+/* Description: Write address of the UART RX FIFO. (a pointer) */
+
+#define UART_WR_ADDRESS                 0x000007FF
+#define UART_WR_ADDRESS_M               ((UART_WR_ADDRESS_V) << (UART_WR_ADDRESS_S))
+#define UART_WR_ADDRESS_V               0x7FF
+#define UART_WR_ADDRESS_S               13
+
 #define UART_MEM_CNT_STATUS_OFFSET      0x64
 #define UART_MEM_CNT_STATUS_REG(i)      (REG_UART_BASE(i) + UART_MEM_CNT_STATUS_OFFSET)