esp32[c3|c6|h2]: Add SPI slave DMA support
This commit is contained in:
parent
f5b63cea18
commit
00ff9ef15c
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user