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 00ff9ef15cc583ce46bc5148b14c718cee880e9f
Author: Eren Terzioglu <[email protected]>
AuthorDate: Thu Jul 18 15:44:19 2024 +0200

    esp32[c3|c6|h2]: Add SPI slave DMA support
---
 arch/risc-v/src/common/espressif/esp_spi_slave.c | 238 ++++++++++++++++++++++-
 1 file changed, 237 insertions(+), 1 deletion(-)

diff --git a/arch/risc-v/src/common/espressif/esp_spi_slave.c 
b/arch/risc-v/src/common/espressif/esp_spi_slave.c
index 645993e090..a33057d5f5 100644
--- a/arch/risc-v/src/common/espressif/esp_spi_slave.c
+++ b/arch/risc-v/src/common/espressif/esp_spi_slave.c
@@ -51,6 +51,10 @@
 #include "hal/spi_slave_hal.h"
 #include "periph_ctrl.h"
 
+#ifdef CONFIG_ESPRESSIF_SPI2_DMA
+#include "esp_dma.h"
+#endif
+
 #include "riscv_internal.h"
 
 /****************************************************************************
@@ -59,6 +63,22 @@
 
 #define SPI_SLAVE_BUFSIZE (CONFIG_ESPRESSIF_SPI2_SLAVE_BUFSIZE)
 
+#ifdef CONFIG_ESPRESSIF_SPI2_DMA
+/* SPI DMA RX/TX number of descriptors */
+
+#if (SPI_SLAVE_BUFSIZE % ESPRESSIF_DMA_DATALEN_MAX) > 0
+#  define SPI_DMA_DESC_NUM (SPI_SLAVE_BUFSIZE / ESPRESSIF_DMA_DATALEN_MAX + 1)
+#else
+#  define SPI_DMA_DESC_NUM (SPI_SLAVE_BUFSIZE / ESPRESSIF_DMA_DATALEN_MAX)
+#endif
+
+#endif /* CONFIG_ESPRESSIF_SPI2_DMA */
+
+#if defined(CONFIG_ARCH_CHIP_ESP32C6) || defined(CONFIG_ARCH_CHIP_ESP32H2)
+#  define SPI2_INTR_SOURCE GSPI2_INTR_SOURCE
+#  define ESP_IRQ_SPI2     ESP_IRQ_GSPI2
+#endif
+
 /* Verify whether SPI has been assigned IOMUX pins.
  * Otherwise, SPI signals will be routed via GPIO Matrix.
  */
@@ -123,6 +143,9 @@ struct spislave_priv_s
   int refs;                     /* Reference count */
   int cpuint;                   /* SPI interrupt ID */
   enum spi_slave_mode_e mode;   /* Current SPI Slave hardware mode */
+#ifdef CONFIG_ESPRESSIF_SPI2_DMA
+  int32_t dma_channel;        /* Channel assigned by the GDMA driver */
+#endif
   uint8_t nbits;                /* Current configured bit width */
   uint32_t tx_length;           /* Location of next TX value */
 
@@ -151,6 +174,15 @@ struct spislave_priv_s
  * Private Function Prototypes
  ****************************************************************************/
 
+/* SPI Slave controller buffer operations */
+
+#ifndef CONFIG_ESPRESSIF_SPI2_DMA
+static inline void spislave_cpu_tx_fifo_reset(spi_dev_t *hw);
+#else
+static inline void spislave_dma_tx_fifo_reset(spi_dev_t *hw);
+static inline void spislave_dma_rx_fifo_reset(spi_dev_t *hw);
+#endif
+
 /* SPI Slave controller interrupt handlers */
 
 static int spislave_cs_interrupt(int irq, void *context, void *arg);
@@ -160,6 +192,12 @@ static int spislave_periph_interrupt(int irq, void 
*context, void *arg);
 
 static void spislave_evict_sent_data(struct spislave_priv_s *priv,
                                      uint32_t sent_bytes);
+#ifdef CONFIG_ESPRESSIF_SPI2_DMA
+static void spislave_setup_rx_dma(struct spislave_priv_s *priv);
+static void spislave_setup_tx_dma(struct spislave_priv_s *priv);
+static void spislave_prepare_next_tx(struct spislave_priv_s *priv);
+static void spislave_dma_init(struct spislave_priv_s *priv);
+#endif
 static void spislave_initialize(struct spi_slave_ctrlr_s *ctrlr);
 
 /* SPI Slave controller operations */
@@ -189,7 +227,7 @@ static const struct spislave_config_s esp_spi2slave_config =
   .mosi_pin     = CONFIG_ESPRESSIF_SPI2_MOSIPIN,
   .miso_pin     = CONFIG_ESPRESSIF_SPI2_MISOPIN,
   .clk_pin      = CONFIG_ESPRESSIF_SPI2_CLKPIN,
-  .periph       = ETS_SPI2_INTR_SOURCE,
+  .periph       = SPI2_INTR_SOURCE,
   .irq          = ESP_IRQ_SPI2,
   .cs_insig     = FSPICS0_IN_IDX,
   .cs_outsig    = FSPICS0_OUT_IDX,
@@ -221,6 +259,9 @@ static struct spislave_priv_s esp_spi2slave_priv =
   .config        = &esp_spi2slave_config,
   .refs          = 0,
   .cpuint        = -ENOMEM,
+#ifdef CONFIG_ESPRESSIF_SPI2_DMA
+  .dma_channel   = -ENOMEM,
+#endif
   .mode          = SPISLAVE_MODE0,
   .nbits         = 0,
   .tx_length     = 0,
@@ -247,6 +288,15 @@ static struct spislave_priv_s esp_spi2slave_priv =
 };
 #endif /* CONFIG_ESPRESSIF_SPI2 */
 
+#ifdef CONFIG_ESPRESSIF_SPI2_DMA
+
+/* SPI DMA RX/TX description */
+
+static struct esp_dmadesc_s dma_rxdesc[SPI_DMA_DESC_NUM];
+static struct esp_dmadesc_s dma_txdesc[SPI_DMA_DESC_NUM];
+
+#endif
+
 /****************************************************************************
  * Private Functions
  ****************************************************************************/
@@ -266,10 +316,56 @@ static struct spislave_priv_s esp_spi2slave_priv =
  *
  ****************************************************************************/
 
+#ifndef CONFIG_ESPRESSIF_SPI2_DMA
 static inline void spislave_cpu_tx_fifo_reset(spi_dev_t *hw)
 {
   spi_ll_cpu_tx_fifo_reset(hw);
 }
+#endif
+
+/****************************************************************************
+ * Name: spislave_dma_tx_fifo_reset
+ *
+ * Description:
+ *   Reset the DMA TX AFIFO, which is used to send data out in SPI Slave
+ *   DMA-controlled mode transfer.
+ *
+ * Input Parameters:
+ *   None.
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESPRESSIF_SPI2_DMA
+static inline void spislave_dma_tx_fifo_reset(spi_dev_t *hw)
+{
+  spi_ll_dma_tx_fifo_reset(hw);
+}
+#endif
+
+/****************************************************************************
+ * Name: spislave_dma_rx_fifo_reset
+ *
+ * Description:
+ *   Reset the RX AFIFO, which is used to receive data in SPI Slave mode
+ *   transfer.
+ *
+ * Input Parameters:
+ *   hw - Beginning address of the peripheral register
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESPRESSIF_SPI2_DMA
+static inline void spislave_dma_rx_fifo_reset(spi_dev_t *hw)
+{
+  spi_ll_dma_rx_fifo_reset(hw);
+}
+#endif
 
 /****************************************************************************
  * Name: spislave_cs_interrupt
@@ -335,6 +431,80 @@ static void spislave_evict_sent_data(struct 
spislave_priv_s *priv,
     }
 }
 
+/****************************************************************************
+ * Name: spislave_setup_rx_dma
+ *
+ * Description:
+ *   Configure the SPI Slave peripheral to perform the next RX data transfer
+ *   via DMA.
+ *
+ * Input Parameters:
+ *   priv - Private SPI Slave controller structure
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESPRESSIF_SPI2_DMA
+static void spislave_setup_rx_dma(struct spislave_priv_s *priv)
+{
+  uint32_t length = SPI_SLAVE_BUFSIZE - priv->rx_length;
+
+  esp_dma_setup(priv->dma_channel, false, dma_rxdesc, SPI_DMA_DESC_NUM,
+                priv->rx_buffer + priv->rx_length, length);
+
+  spi_ll_slave_reset(priv->ctx.hw);
+
+  /* Clear input FIFO full error */
+
+  spi_ll_infifo_full_clr(priv->ctx.hw);
+
+  /* Enable SPI DMA RX */
+
+  spi_ll_dma_rx_enable(priv->ctx.hw, true);
+
+  esp_dma_enable(priv->dma_channel, false);
+}
+#endif
+
+/****************************************************************************
+ * Name: spislave_setup_tx_dma
+ *
+ * Description:
+ *   Configure the SPI Slave peripheral to perform the next TX data transfer
+ *   via DMA.
+ *
+ * Input Parameters:
+ *   priv   - Private SPI Slave controller structure
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESPRESSIF_SPI2_DMA
+static void spislave_setup_tx_dma(struct spislave_priv_s *priv)
+{
+  esp_dma_setup(priv->dma_channel, true, dma_txdesc, SPI_DMA_DESC_NUM,
+                priv->tx_buffer, SPI_SLAVE_BUFSIZE);
+
+  spislave_dma_tx_fifo_reset(priv->ctx.hw);
+
+  spi_ll_slave_reset(priv->ctx.hw);
+
+  /* Clear output FIFO full error */
+
+  spi_ll_outfifo_empty_clr(priv->ctx.hw);
+
+  /* Enable SPI DMA TX */
+
+  spi_ll_dma_tx_enable(priv->ctx.hw, true);
+
+  esp_dma_enable(priv->dma_channel, true);
+}
+#endif
+
 /****************************************************************************
  * Name: spislave_prepare_next_tx
  *
@@ -354,14 +524,20 @@ static void spislave_prepare_next_tx(struct 
spislave_priv_s *priv)
 {
   if (priv->tx_length != 0)
     {
+#ifdef CONFIG_ESPRESSIF_SPI2_DMA
+      spislave_setup_tx_dma(priv);
+#else
       spi_slave_hal_prepare_data(&priv->ctx);
+#endif
       priv->is_tx_enabled = true;
     }
   else
     {
       spiwarn("TX buffer empty! Disabling TX for next transaction\n");
 
+#ifndef CONFIG_ESPRESSIF_SPI2_DMA
       spislave_cpu_tx_fifo_reset(priv->ctx.hw);
+#endif
 
       priv->is_tx_enabled = false;
     }
@@ -404,6 +580,13 @@ static int spislave_periph_interrupt(int irq, void 
*context, void *arg)
       priv->rx_length += transfer_size;
     }
 
+#ifdef CONFIG_ESPRESSIF_SPI2_DMA
+  if (priv->rx_length < SPI_SLAVE_BUFSIZE)
+    {
+      spislave_setup_rx_dma(priv);
+    }
+#endif
+
   /* TX process */
 
   if (transfer_size > 0 && priv->is_tx_enabled)
@@ -431,6 +614,40 @@ static int spislave_periph_interrupt(int irq, void 
*context, void *arg)
   return 0;
 }
 
+/****************************************************************************
+ * Name: spislave_dma_init
+ *
+ * Description:
+ *   Initialize SPI Slave connection to GDMA engine.
+ *
+ * Input Parameters:
+ *   priv - Private SPI Slave controller structure
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESPRESSIF_SPI2_DMA
+static void spislave_dma_init(struct spislave_priv_s *priv)
+{
+  /* Initialize GDMA controller */
+
+  esp_dma_init();
+
+  /* Request a GDMA channel for SPI peripheral */
+
+  priv->dma_channel = esp_dma_request(ESPRESSIF_DMA_PERIPH_M2M, 1, 1,
+                                      true);
+  if (priv->dma_channel < 0)
+    {
+      spierr("Failed to allocate GDMA channel\n");
+
+      DEBUGPANIC();
+    }
+}
+#endif
+
 /****************************************************************************
  * Name: spislave_initialize
  *
@@ -483,13 +700,25 @@ static void spislave_initialize(struct spi_slave_ctrlr_s 
*ctrlr)
   esp_gpio_matrix_in(config->clk_pin, config->clk_insig, 0);
 #endif
 
+#ifdef CONFIG_ESPRESSIF_SPI2_DMA
+  spislave_dma_init(priv);
+#endif
+
   esp_gpioirqenable(ESP_PIN2IRQ(config->cs_pin), RISING);
 
   priv->ctx.rx_lsbfirst = 0;
   priv->ctx.tx_lsbfirst = 0;
 
+#ifdef CONFIG_ESPRESSIF_SPI2_DMA
+  priv->ctx.dmadesc_n = priv->dma_channel;
+  priv->ctx.use_dma = 1;
+
+  priv->ctx.dmadesc_rx = (lldesc_t *)dma_rxdesc;
+  priv->ctx.dmadesc_tx = (lldesc_t *)dma_txdesc;
+#else
   priv->ctx.dmadesc_n = 0;
   priv->ctx.use_dma = 0;
+#endif
 }
 
 /****************************************************************************
@@ -606,6 +835,8 @@ static void spislave_unbind(struct spi_slave_ctrlr_s *ctrlr)
 
   /* Disable the trans_done interrupt */
 
+  spi_ll_disable_intr(priv->ctx.hw, SPI_LL_INTR_TRANS_DONE);
+
   periph_module_disable(priv->module);
 
   priv->dev = NULL;
@@ -922,6 +1153,11 @@ int esp_spislave_ctrlr_uninitialize(struct 
spi_slave_ctrlr_s *ctrlr)
   priv->cpuint = -ENOMEM;
 
   esp_gpioirqdisable(ESP_PIN2IRQ(priv->config->cs_pin));
+
+  /* Disable the trans_done interrupt */
+
+  spi_ll_disable_intr(priv->ctx.hw, SPI_LL_INTR_TRANS_DONE);
+
   periph_module_disable(priv->module);
 
   priv->cpuint = -ENOMEM;

Reply via email to