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;
