You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by ac...@apache.org on 2023/06/16 19:07:11 UTC
[nuttx] branch master updated: xtensa/esp32s3: SPI support quad I/O mode
This is an automated email from the ASF dual-hosted git repository.
acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new 8f25329260 xtensa/esp32s3: SPI support quad I/O mode
8f25329260 is described below
commit 8f25329260c5b34f413d3ac331e3a8a54a7b20c6
Author: Dong Heng <do...@espressif.com>
AuthorDate: Sat May 6 15:20:48 2023 +0800
xtensa/esp32s3: SPI support quad I/O mode
---
arch/xtensa/src/esp32s3/Kconfig | 80 +-
arch/xtensa/src/esp32s3/Make.defs | 13 +-
arch/xtensa/src/esp32s3/esp32s3_qspi.c | 1610 +++++++++++++++++++++++++++
arch/xtensa/src/esp32s3/esp32s3_qspi.h | 126 +++
arch/xtensa/src/esp32s3/esp32s3_spi.c | 105 +-
arch/xtensa/src/esp32s3/esp32s3_spi_slave.c | 380 +++++--
6 files changed, 2127 insertions(+), 187 deletions(-)
diff --git a/arch/xtensa/src/esp32s3/Kconfig b/arch/xtensa/src/esp32s3/Kconfig
index 9f3b569616..d9424a85d8 100644
--- a/arch/xtensa/src/esp32s3/Kconfig
+++ b/arch/xtensa/src/esp32s3/Kconfig
@@ -594,9 +594,22 @@ config ESP32S3_RTCIO_IRQ
menu "SPI configuration"
depends on ESP32S3_SPI
+choice
+ prompt "SPI I/O Mode"
+ default ESP32S3_SPI_IO_SPI
+
+config ESP32S3_SPI_IO_SPI
+ bool "SPI (4-line)"
+
+config ESP32S3_SPI_IO_QIO
+ bool "QIO (6-line)"
+
+endchoice # SPI I/O Mode
+
config ESP32S3_SPI_SWCS
bool "SPI software CS"
default n
+ depends on ESP32S3_SPI_IO_SPI
---help---
Use SPI software CS.
@@ -607,36 +620,34 @@ config ESP32S3_SPI_UDCS
---help---
Use user-defined CS.
-config ESP32S3_SPI_SLAVE_BUFSIZE
- int "SPI slave buffer size"
- default 2048
- depends on SPI_SLAVE
-
-if ESP32S3_SPI2
-
-config ESP32S3_SPI2_DMA
- bool "SPI2 use GDMA"
+config ESP32S3_SPI_DMA
+ bool "SPI use GDMA"
default n
- depends on ESP32S3_DMA
+ select ESP32S3_DMA
---help---
Enable support for transfers using the GDMA engine.
-config ESP32S3_SPI2_DMADESC_NUM
- int "SPI2 Master GDMA maximum number of descriptors"
- default 2
- depends on ESP32S3_SPI2_DMA
+config ESP32S3_SPI_DMA_BUFSIZE
+ int "SPI Master GDMA buffer size"
+ default 2048
+ depends on ESP32S3_SPI_DMA
---help---
- Configure the maximum number of out-link/in-link descriptors to
- be chained for a GDMA transfer.
+ This is used to calculate and allocate DMA description buffer,
+ not really allocate TX/RX buffer.
-config ESP32S3_SPI2_DMATHRESHOLD
- int "SPI2 Master GDMA threshold"
+config ESP32S3_SPI_DMATHRESHOLD
+ int "SPI Master GDMA threshold"
default 64
- depends on ESP32S3_SPI2_DMA
+ depends on ESP32S3_SPI_DMA && ESP32S3_SPI_IO_SPI
---help---
When SPI GDMA is enabled, GDMA transfers whose size are below the
defined threshold will be performed by polling logic.
+config ESP32S3_SPI_SLAVE_BUFSIZE
+ int "SPI Slave buffer size"
+ default 2048
+ depends on SPI_SLAVE
+
config ESP32S3_SPI2_CSPIN
int "SPI2 CS Pin"
default 10
@@ -657,16 +668,17 @@ config ESP32S3_SPI2_MISOPIN
default 13
range 0 48
-endif # ESP32S3_SPI2
-
-if ESP32S3_SPI3
+config ESP32S3_SPI2_IO2PIN
+ int "SPI2 IO2 Pin"
+ default 14
+ range 0 48
+ depends on ESP32S3_SPI_IO_QIO
-config ESP32S3_SPI3_DMA
- bool "SPI3 use GDMA"
- default n
- depends on ESP32S3_DMA
- ---help---
- Enable support for transfers using the GDMA engine.
+config ESP32S3_SPI2_IO3PIN
+ int "SPI2 IO3 Pin"
+ default 9
+ range 0 48
+ depends on ESP32S3_SPI_IO_QIO
config ESP32S3_SPI3_CSPIN
int "SPI3 CS Pin"
@@ -688,7 +700,17 @@ config ESP32S3_SPI3_MISOPIN
default 2
range 0 48
-endif # ESP32S3_SPI3
+config ESP32S3_SPI3_IO2PIN
+ int "SPI3 IO2 Pin"
+ default 3
+ range 0 48
+ depends on ESP32S3_SPI_IO_QIO
+
+config ESP32S3_SPI3_IO3PIN
+ int "SPI3 IO3 Pin"
+ default 4
+ range 0 48
+ depends on ESP32S3_SPI_IO_QIO
endmenu # SPI configuration
diff --git a/arch/xtensa/src/esp32s3/Make.defs b/arch/xtensa/src/esp32s3/Make.defs
index 65a6a301de..9aee50cb9e 100644
--- a/arch/xtensa/src/esp32s3/Make.defs
+++ b/arch/xtensa/src/esp32s3/Make.defs
@@ -106,10 +106,15 @@ CHIP_CSRCS += esp32s3_i2c.c
endif
ifeq ($(CONFIG_ESP32S3_SPI),y)
-CHIP_CSRCS += esp32s3_spi.c
-ifeq ($(CONFIG_SPI_SLAVE),y)
-CHIP_CSRCS += esp32s3_spi_slave.c
-endif
+ ifeq ($(CONFIG_ESP32S3_SPI_IO_SPI),y)
+ CHIP_CSRCS += esp32s3_spi.c
+ else
+ CHIP_CSRCS += esp32s3_qspi.c
+ endif
+
+ ifeq ($(CONFIG_SPI_SLAVE),y)
+ CHIP_CSRCS += esp32s3_spi_slave.c
+ endif
endif
ifeq ($(CONFIG_ESP32S3_SPIFLASH),y)
diff --git a/arch/xtensa/src/esp32s3/esp32s3_qspi.c b/arch/xtensa/src/esp32s3/esp32s3_qspi.c
new file mode 100644
index 0000000000..9ac7f1b655
--- /dev/null
+++ b/arch/xtensa/src/esp32s3/esp32s3_qspi.c
@@ -0,0 +1,1610 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32s3/esp32s3_qspi.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#ifdef CONFIG_ESP32S3_SPI
+
+#include <assert.h>
+#include <debug.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/clock.h>
+#include <nuttx/mutex.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/spi/qspi.h>
+
+#include <arch/board/board.h>
+
+#include "xtensa.h"
+#include "hardware/esp32s3_gpio_sigmap.h"
+#include "hardware/esp32s3_pinmap.h"
+#include "hardware/esp32s3_spi.h"
+#include "hardware/esp32s3_soc.h"
+#include "hardware/esp32s3_system.h"
+
+#include "esp32s3_irq.h"
+#include "esp32s3_gpio.h"
+#include "esp32s3_qspi.h"
+
+#ifdef CONFIG_ESP32S3_SPI_DMA
+#include "esp32s3_dma.h"
+#endif
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32S3_SPI_DMA
+
+/* QSPI maximum DMA buffer size in bytes */
+
+#define QSPI_DMA_BUFSIZE CONFIG_ESP32S3_SPI_DMA_BUFSIZE
+
+/* QSPI DMA RX/TX number of descriptors */
+
+# if (QSPI_DMA_BUFSIZE % ESP32S3_DMA_BUFLEN_MAX) > 0
+# define QSPI_DMA_DESC_NUM (QSPI_DMA_BUFSIZE / ESP32S3_DMA_BUFLEN_MAX + 1)
+# else
+# define QSPI_DMA_DESC_NUM (QSPI_DMA_BUFSIZE / ESP32S3_DMA_BUFLEN_MAX)
+# endif
+
+/* QSPI DMA reset before exchange */
+
+# define QSPI_DMA_RESET_MASK (SPI_DMA_AFIFO_RST_M | SPI_RX_AFIFO_RST_M)
+
+#endif /* CONFIG_ESP32S3_SPI_DMA */
+
+/* QSPI default frequency (limited by clock divider) */
+
+#define QSPI_DEFAULT_FREQ (400000)
+
+/* QSPI default width */
+
+#define QSPI_DEFAULT_WIDTH (8)
+
+/* QSPI default mode */
+
+#define QSPI_DEFAULT_MODE (QSPIDEV_MODE0)
+
+/* QSPI maximum non-DMA buffer size in bytes */
+
+#define QSPI_CMD_BUFSIZE (64)
+
+/* Verify whether QSPI has been assigned IOMUX pins.
+ * Otherwise, QSPI signals will be routed via GPIO Matrix.
+ */
+
+#ifdef CONFIG_ESP32S3_SPI2
+
+/* In quad QSPI mode, data IO map is:
+ * MOSI -> IO0
+ * MISO -> IO1
+ * WP -> IO2
+ * Hold -> IO3
+ */
+
+# define QSPI_IS_CS_IOMUX (CONFIG_ESP32S3_SPI2_CSPIN == SPI2_IOMUX_CSPIN)
+# define QSPI_IS_CLK_IOMUX (CONFIG_ESP32S3_SPI2_CLKPIN == SPI2_IOMUX_CLKPIN)
+# define QSPI_IS_MOSI_IOMUX (CONFIG_ESP32S3_SPI2_MOSIPIN == SPI2_IOMUX_MOSIPIN)
+# define QSPI_IS_MISO_IOMUX (CONFIG_ESP32S3_SPI2_MISOPIN == SPI2_IOMUX_MISOPIN)
+# define QSPI_IS_IO2_IOMUX (CONFIG_ESP32S3_SPI2_IO2PIN == SPI2_IOMUX_WPPIN)
+# define QSPI_IS_IO3_IOMUX (CONFIG_ESP32S3_SPI2_IO3PIN == SPI2_IOMUX_HDPIN)
+
+# define QSPI_VIA_IOMUX ((QSPI_IS_CS_IOMUX) && \
+ (QSPI_IS_CLK_IOMUX) && \
+ (QSPI_IS_MOSI_IOMUX) && \
+ (QSPI_IS_MISO_IOMUX) && \
+ (QSPI_IS_IO2_IOMUX) && \
+ (QSPI_IS_IO3_IOMUX))
+#else
+# define QSPI_VIA_IOMUX 0
+#endif
+
+/* Check if 16-bit command or 8 bit command and return its bits */
+
+#define QSPI_CMD_BITS(cmd) ((cmd) & 0xff00 ? 16 : 8)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* QSPI Device hardware configuration */
+
+struct esp32s3_qspi_config_s
+{
+ uint8_t id; /* ESP32-S3 QSPI device ID: SPIx {2,3} */
+
+ uint8_t cs_pin; /* GPIO configuration for CS */
+ uint8_t mosi_pin; /* GPIO configuration for MOSI */
+ uint8_t miso_pin; /* GPIO configuration for MISO */
+ uint8_t clk_pin; /* GPIO configuration for CLK */
+ uint8_t io2_pin; /* GPIO configuration for IO2 */
+ uint8_t io3_pin; /* GPIO configuration for IO3 */
+
+ int8_t periph; /* Peripheral ID */
+ uint8_t irq; /* Interrupt ID */
+
+ uint32_t clk_bit; /* Clock enable bit */
+ uint32_t rst_bit; /* QSPI reset bit */
+
+#ifdef CONFIG_ESP32S3_SPI_DMA
+
+ /* Peripheral for which the DMA channel request */
+
+ enum esp32s3_dma_periph_e dma_periph;
+ uint32_t dma_clk_bit; /* DMA clock enable bit */
+ uint32_t dma_rst_bit; /* DMA reset bit */
+#endif
+
+ uint32_t cs_insig; /* QSPI CS input signal index */
+ uint32_t cs_outsig; /* QSPI CS output signal index */
+ uint32_t mosi_insig; /* QSPI MOSI input signal index */
+ uint32_t mosi_outsig; /* QSPI MOSI output signal index */
+ uint32_t miso_insig; /* QSPI MISO input signal index */
+ uint32_t miso_outsig; /* QSPI MISO output signal index */
+ uint32_t clk_insig; /* QSPI CLK input signal index */
+ uint32_t clk_outsig; /* QSPI CLK output signal index */
+ uint32_t io2_insig; /* QSPI IO2 input signal index */
+ uint32_t io2_outsig; /* QSPI IO2 output signal index */
+ uint32_t io3_insig; /* QSPI IO3 input signal index */
+ uint32_t io3_outsig; /* QSPI IO3 output signal index */
+};
+
+struct esp32s3_qspi_priv_s
+{
+ /* Externally visible part of the (Q)QSPI interface */
+
+ struct qspi_dev_s spi_dev;
+
+ /* Port configuration */
+
+ const struct esp32s3_qspi_config_s *config;
+
+ int refs; /* Reference count */
+ mutex_t lock; /* Held while chip is selected for mutual exclusion */
+
+#ifdef CONFIG_ESP32S3_SPI_DMA
+ sem_t sem_isr; /* Interrupt wait semaphore */
+
+ int cpu; /* CPU ID */
+ int cpuint; /* QSPI interrupt ID */
+
+ int32_t dma_channel; /* Channel assigned by the GDMA driver */
+
+ /* DMA description */
+
+ struct esp32s3_dmadesc_s *dma_desc;
+#endif
+
+ uint32_t frequency; /* Requested clock frequency */
+ uint32_t actual; /* Actual clock frequency */
+ enum qspi_mode_e mode; /* Actual QSPI hardware mode */
+ uint8_t nbits; /* Actual QSPI send/receive bits once transmission */
+
+ uint8_t dummies; /* Number of dummy cycles of command transfer */
+ uint8_t addr_lines; /* Number of address transmiting I/O pins */
+ uint8_t data_lines; /* Number of data transmiting I/O pins */
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int esp32s3_qspi_lock(struct qspi_dev_s *dev, bool lock);
+static uint32_t esp32s3_qspi_setfrequency(struct qspi_dev_s *dev,
+ uint32_t frequency);
+static void esp32s3_qspi_setmode(struct qspi_dev_s *dev,
+ enum qspi_mode_e mode);
+static void esp32s3_qspi_setbits(struct qspi_dev_s *dev, int nbits);
+static int esp32s3_qspi_command(struct qspi_dev_s *dev,
+ struct qspi_cmdinfo_s *cmdinfo);
+static int esp32s3_qspi_memory(struct qspi_dev_s *dev,
+ struct qspi_meminfo_s *meminfo);
+static void *esp32s3_qspi_alloc(struct qspi_dev_s *dev, size_t buflen);
+static void esp32s3_qspi_free(struct qspi_dev_s *dev, void *buffer);
+
+#ifdef CONFIG_ESP32S3_SPI_DMA
+static int esp32s3_qspi_interrupt(int irq, void *context, void *arg);
+static int esp32s3_qspi_wait_sem(struct esp32s3_qspi_priv_s *priv);
+static void esp32s3_qspi_init_dma(struct esp32s3_qspi_priv_s *priv);
+#endif
+static void esp32s3_qspi_init(struct esp32s3_qspi_priv_s *priv);
+static void esp32s3_qspi_deinit(struct esp32s3_qspi_priv_s *priv);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32S3_SPI2
+static const struct esp32s3_qspi_config_s esp32s3_spi2_config =
+{
+ .id = 2,
+
+ .cs_pin = CONFIG_ESP32S3_SPI2_CSPIN,
+ .mosi_pin = CONFIG_ESP32S3_SPI2_MOSIPIN,
+ .miso_pin = CONFIG_ESP32S3_SPI2_MISOPIN,
+ .clk_pin = CONFIG_ESP32S3_SPI2_CLKPIN,
+ .io2_pin = CONFIG_ESP32S3_SPI2_IO2PIN,
+ .io3_pin = CONFIG_ESP32S3_SPI2_IO3PIN,
+
+ .periph = ESP32S3_PERIPH_SPI2,
+ .irq = ESP32S3_IRQ_SPI2,
+
+ .clk_bit = SYSTEM_SPI2_CLK_EN,
+ .rst_bit = SYSTEM_SPI2_RST,
+
+#ifdef CONFIG_ESP32S3_SPI_DMA
+ .dma_periph = ESP32S3_DMA_PERIPH_SPI2,
+ .dma_clk_bit = SYSTEM_SPI2_DMA_CLK_EN,
+ .dma_rst_bit = SYSTEM_SPI2_DMA_RST,
+#endif
+
+ .cs_insig = FSPICS0_IN_IDX,
+ .cs_outsig = FSPICS0_OUT_IDX,
+ .mosi_insig = FSPID_IN_IDX,
+ .mosi_outsig = FSPID_OUT_IDX,
+ .miso_insig = FSPIQ_IN_IDX,
+ .miso_outsig = FSPIQ_OUT_IDX,
+ .clk_insig = FSPICLK_IN_IDX,
+ .clk_outsig = FSPICLK_OUT_IDX,
+ .io2_insig = FSPIWP_IN_IDX,
+ .io2_outsig = FSPIWP_OUT_IDX,
+ .io3_insig = FSPIHD_IN_IDX,
+ .io3_outsig = FSPIHD_OUT_IDX,
+};
+
+static const struct qspi_ops_s esp32s3_spi2_ops =
+{
+ .lock = esp32s3_qspi_lock,
+ .setfrequency = esp32s3_qspi_setfrequency,
+ .setmode = esp32s3_qspi_setmode,
+ .setbits = esp32s3_qspi_setbits,
+ .command = esp32s3_qspi_command,
+ .memory = esp32s3_qspi_memory,
+ .alloc = esp32s3_qspi_alloc,
+ .free = esp32s3_qspi_free,
+};
+
+# ifdef CONFIG_ESP32S3_SPI_DMA
+
+/* QSPI 2 DMA RX/TX description */
+
+static struct esp32s3_dmadesc_s esp32s3_spi2_dma_desc[QSPI_DMA_DESC_NUM];
+# endif
+
+static struct esp32s3_qspi_priv_s esp32s3_spi2_priv =
+{
+ .spi_dev =
+ {
+ .ops = &esp32s3_spi2_ops
+ },
+
+ .config = &esp32s3_spi2_config,
+
+ .refs = 0,
+ .lock = NXMUTEX_INITIALIZER,
+
+#ifdef CONFIG_ESP32S3_SPI_DMA
+ .sem_isr = SEM_INITIALIZER(0),
+
+ .cpu = 0,
+ .cpuint = -ENOMEM,
+
+ .dma_channel = -1,
+ .dma_desc = esp32s3_spi2_dma_desc,
+#endif
+
+ .frequency = 0,
+ .actual = 0,
+ .mode = QSPIDEV_MODE0,
+ .nbits = 0,
+
+ .dummies = 0,
+ .addr_lines = 4,
+ .data_lines = 4,
+};
+#endif /* CONFIG_ESP32S3_SPI2 */
+
+#ifdef CONFIG_ESP32S3_SPI3
+static const struct esp32s3_qspi_config_s esp32s3_spi3_config =
+{
+ .id = 3,
+
+ .cs_pin = CONFIG_ESP32S3_SPI3_CSPIN,
+ .mosi_pin = CONFIG_ESP32S3_SPI3_MOSIPIN,
+ .miso_pin = CONFIG_ESP32S3_SPI3_MISOPIN,
+ .clk_pin = CONFIG_ESP32S3_SPI3_CLKPIN,
+ .io2_pin = CONFIG_ESP32S3_SPI3_IO2PIN,
+ .io3_pin = CONFIG_ESP32S3_SPI3_IO3PIN,
+
+ .periph = ESP32S3_PERIPH_SPI3,
+ .irq = ESP32S3_IRQ_SPI3,
+
+ .clk_bit = SYSTEM_SPI3_CLK_EN,
+ .rst_bit = SYSTEM_SPI3_RST,
+
+#ifdef CONFIG_ESP32S3_SPI_DMA
+ .dma_periph = ESP32S3_DMA_PERIPH_SPI3,
+ .dma_clk_bit = SYSTEM_SPI3_DMA_CLK_EN,
+ .dma_rst_bit = SYSTEM_SPI3_DMA_RST,
+#endif
+
+ .cs_insig = SPI3_CS0_IN_IDX,
+ .cs_outsig = SPI3_CS0_OUT_IDX,
+ .mosi_insig = SPI3_D_IN_IDX,
+ .mosi_outsig = SPI3_D_OUT_IDX,
+ .miso_insig = SPI3_Q_IN_IDX,
+ .miso_outsig = SPI3_Q_OUT_IDX,
+ .clk_insig = SPI3_CLK_IN_IDX,
+ .clk_outsig = SPI3_CLK_OUT_IDX,
+ .io2_insig = SPI3_WP_IN_IDX,
+ .io2_outsig = SPI3_WP_OUT_IDX,
+ .io3_insig = SPI3_HD_IN_IDX,
+ .io3_outsig = SPI3_HD_OUT_IDX,
+};
+
+static const struct qspi_ops_s esp32s3_spi3_ops =
+{
+ .lock = esp32s3_qspi_lock,
+ .setfrequency = esp32s3_qspi_setfrequency,
+ .setmode = esp32s3_qspi_setmode,
+ .setbits = esp32s3_qspi_setbits,
+ .command = esp32s3_qspi_command,
+ .memory = esp32s3_qspi_memory,
+ .alloc = esp32s3_qspi_alloc,
+ .free = esp32s3_qspi_free,
+};
+
+# ifdef CONFIG_ESP32S3_SPI_DMA
+
+/* QSPI 3 DMA description */
+
+static struct esp32s3_dmadesc_s esp32s3_spi3_dma_desc[QSPI_DMA_DESC_NUM];
+# endif
+
+static struct esp32s3_qspi_priv_s esp32s3_spi3_priv =
+{
+ .spi_dev =
+ {
+ .ops = &esp32s3_spi3_ops
+ },
+
+ .config = &esp32s3_spi3_config,
+
+ .refs = 0,
+ .lock = NXMUTEX_INITIALIZER,
+
+#ifdef CONFIG_ESP32S3_SPI_DMA
+ .sem_isr = SEM_INITIALIZER(0),
+
+ .cpu = 0,
+ .cpuint = -ENOMEM,
+
+ .dma_channel = -1,
+ .dma_desc = esp32s3_spi3_dma_desc,
+#endif
+
+ .frequency = 0,
+ .actual = 0,
+ .mode = QSPIDEV_MODE0,
+ .nbits = 0,
+
+ .dummies = 0,
+ .addr_lines = 4,
+ .data_lines = 4,
+};
+#endif /* CONFIG_ESP32S3_SPI3 */
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp32s3_qspi_lock
+ *
+ * Description:
+ * Lock or unlock the QSPI device.
+ *
+ * Input Parameters:
+ * dev - Device-specific state data
+ * lock - true: Lock QSPI bus, false: unlock QSPI bus
+ *
+ * Returned Value:
+ * The result of lock or unlock the QSPI device.
+ *
+ ****************************************************************************/
+
+static int esp32s3_qspi_lock(struct qspi_dev_s *dev, bool lock)
+{
+ int ret;
+ struct esp32s3_qspi_priv_s *priv = (struct esp32s3_qspi_priv_s *)dev;
+
+ if (lock)
+ {
+ ret = nxmutex_lock(&priv->lock);
+ }
+ else
+ {
+ ret = nxmutex_unlock(&priv->lock);
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: esp32s3_qspi_setfrequency
+ *
+ * Description:
+ * Set the QSPI frequency.
+ *
+ * Input Parameters:
+ * dev - Device-specific state data
+ * frequency - The requested QSPI frequency
+ *
+ * Returned Value:
+ * Returns the current selected frequency.
+ *
+ ****************************************************************************/
+
+static uint32_t esp32s3_qspi_setfrequency(struct qspi_dev_s *dev,
+ uint32_t frequency)
+{
+ uint32_t regval;
+ struct esp32s3_qspi_priv_s *priv = (struct esp32s3_qspi_priv_s *)dev;
+ const uint32_t duty_cycle = 128;
+
+ if (priv->frequency == frequency)
+ {
+ /* Requested frequency is the same as the current frequency. */
+
+ return priv->actual;
+ }
+
+ /* In HW, n, h and l fields range from 1 to 64, pre ranges from 1 to 8K.
+ * The value written to register is one lower than the used value.
+ */
+
+ if (frequency > ((APB_CLK_FREQ / 4) * 3))
+ {
+ /* Using APB frequency directly will give us the best result here. */
+
+ regval = SPI_CLK_EQU_SYSCLK_M;
+ priv->actual = APB_CLK_FREQ;
+ }
+ else
+ {
+ /* For best duty cycle resolution, we want n to be as close to 32 as
+ * possible, but we also need a pre/n combo that gets us as close as
+ * possible to the intended frequency. To do this, we bruteforce n and
+ * calculate the best pre to go along with that. If there's a choice
+ * between pre/n combos that give the same result, use the one with the
+ * higher n.
+ */
+
+ int32_t pre;
+ int32_t n;
+ int32_t h;
+ int32_t l;
+ int32_t bestn = -1;
+ int32_t bestpre = -1;
+ int32_t besterr = 0;
+ int32_t errval;
+
+ /* Start at n = 2. We need to be able to set h/l so we have at least
+ * one high and one low pulse.
+ */
+
+ for (n = 2; n <= 64; n++)
+ {
+ /* Effectively, this does:
+ * pre = round((APB_CLK_FREQ / n) / frequency)
+ */
+
+ pre = ((APB_CLK_FREQ / n) + (frequency / 2)) / frequency;
+
+ if (pre <= 0)
+ {
+ pre = 1;
+ }
+
+ if (pre > 16)
+ {
+ pre = 16;
+ }
+
+ errval = abs(APB_CLK_FREQ / (pre * n) - frequency);
+ if (bestn == -1 || errval <= besterr)
+ {
+ besterr = errval;
+ bestn = n;
+ bestpre = pre;
+ }
+ }
+
+ n = bestn;
+ pre = bestpre;
+ l = n;
+
+ /* Effectively, this does:
+ * h = round((duty_cycle * n) / 256)
+ */
+
+ h = (duty_cycle * n + 127) / 256;
+ if (h <= 0)
+ {
+ h = 1;
+ }
+
+ regval = ((l - 1) << SPI_CLKCNT_L_S) |
+ ((h - 1) << SPI_CLKCNT_H_S) |
+ ((n - 1) << SPI_CLKCNT_N_S) |
+ ((pre - 1) << SPI_CLKDIV_PRE_S);
+
+ priv->actual = APB_CLK_FREQ / (n * pre);
+ }
+
+ priv->frequency = frequency;
+
+ putreg32(regval, SPI_CLOCK_REG(priv->config->id));
+
+ spiinfo("frequency=%" PRIu32 ", actual=%" PRIu32 "\n",
+ priv->frequency, priv->actual);
+
+ return priv->actual;
+}
+
+/****************************************************************************
+ * Name: esp32s3_qspi_setmode
+ *
+ * Description:
+ * Set the QSPI mode.
+ *
+ * Input Parameters:
+ * dev - Device-specific state data
+ * mode - The requested QSPI mode
+ *
+ * Returned Value:
+ * None.
+ *
+ ****************************************************************************/
+
+static void esp32s3_qspi_setmode(struct qspi_dev_s *dev,
+ enum qspi_mode_e mode)
+{
+ uint32_t regval;
+ struct esp32s3_qspi_priv_s *priv = (struct esp32s3_qspi_priv_s *)dev;
+ uint8_t id = priv->config->id;
+
+ spiinfo("mode=%d\n", mode);
+
+ /* Has the mode changed? */
+
+ if (mode != priv->mode)
+ {
+ uint32_t ck_idle_edge;
+ uint32_t ck_out_edge;
+
+ switch (mode)
+ {
+ case QSPIDEV_MODE0: /* CPOL=0; CPHA=0 */
+ ck_idle_edge = 0;
+ ck_out_edge = 0;
+ break;
+
+ case QSPIDEV_MODE1: /* CPOL=0; CPHA=1 */
+ ck_idle_edge = 0;
+ ck_out_edge = 1;
+ break;
+
+ case QSPIDEV_MODE2: /* CPOL=1; CPHA=0 */
+ ck_idle_edge = 1;
+ ck_out_edge = 1;
+ break;
+
+ case QSPIDEV_MODE3: /* CPOL=1; CPHA=1 */
+ ck_idle_edge = 1;
+ ck_out_edge = 0;
+ break;
+
+ default:
+ spierr("Invalid mode: %d\n", mode);
+ DEBUGPANIC();
+ return;
+ }
+
+ regval = getreg32(SPI_MISC_REG(id));
+ regval &= SPI_CK_IDLE_EDGE_M;
+ regval |= ck_idle_edge << SPI_CK_IDLE_EDGE_S;
+ putreg32(regval, SPI_MISC_REG(id));
+
+ regval = getreg32(SPI_USER_REG(id));
+ regval &= SPI_CK_OUT_EDGE_M;
+ regval |= ck_out_edge << SPI_CK_OUT_EDGE_S;
+ putreg32(regval, SPI_USER_REG(id));
+
+ priv->mode = mode;
+ }
+}
+
+/****************************************************************************
+ * Name: esp32s3_qspi_setbits
+ *
+ * Description:
+ * Set the number of bits per word.
+ *
+ * Input Parameters:
+ * dev - Device-specific state data
+ * nbits - The number of bits in an QSPI word.
+ *
+ * Returned Value:
+ * None.
+ *
+ ****************************************************************************/
+
+static void esp32s3_qspi_setbits(struct qspi_dev_s *dev, int nbits)
+{
+ struct esp32s3_qspi_priv_s *priv = (struct esp32s3_qspi_priv_s *)dev;
+
+ spiinfo("nbits=%d\n", nbits);
+
+ priv->nbits = nbits;
+}
+
+/****************************************************************************
+ * Name: esp32s3_qspi_command
+ *
+ * Description:
+ * Perform one QSPI data transfer
+ *
+ * Input Parameters:
+ * dev - Device-specific state data
+ * cmdinfo - Describes the command transfer to be performed.
+ *
+ * Returned Value:
+ * Zero (OK) on SUCCESS, a negated errno on value of failure
+ *
+ ****************************************************************************/
+
+static int esp32s3_qspi_command(struct qspi_dev_s *dev,
+ struct qspi_cmdinfo_s *cmdinfo)
+{
+ uint32_t regval;
+ uint8_t *data;
+ struct esp32s3_qspi_priv_s *priv = (struct esp32s3_qspi_priv_s *)dev;
+ uint8_t id = priv->config->id;
+ uint32_t user1_reg = getreg32(SPI_USER1_REG(id));
+ uint32_t user_reg = getreg32(SPI_USER_REG(id));
+
+ if (QSPICMD_ISWRITE(cmdinfo->flags) || QSPICMD_ISREAD(cmdinfo->flags))
+ {
+ if (cmdinfo->buflen > QSPI_CMD_BUFSIZE)
+ {
+ return -EINVAL;
+ }
+ else
+ {
+ putreg32(cmdinfo->buflen * 8 - 1, SPI_MS_DLEN_REG(id));
+ }
+ }
+
+ /* Initiliaze QSPI user register */
+
+ user_reg &= ~(SPI_USR_ADDR_M |
+ SPI_USR_MOSI_M |
+ SPI_USR_MISO_M |
+ SPI_USR_DUMMY_M |
+ SPI_FWRITE_DUAL_M |
+ SPI_FWRITE_OCT_M |
+ SPI_FWRITE_QUAD_M);
+ user_reg |= SPI_USR_COMMAND_M;
+
+ /* Set command bits and value, and command is always needed */
+
+ regval = getreg32(SPI_USER2_REG(id));
+ regval &= ~(SPI_USR_COMMAND_BITLEN_M |
+ SPI_USR_COMMAND_VALUE_M |
+ SPI_MST_REMPTY_ERR_END_EN_M);
+ regval |= ((QSPI_CMD_BITS(cmdinfo->cmd) - 1) << SPI_USR_COMMAND_BITLEN_S) |
+ (cmdinfo->cmd << SPI_USR_COMMAND_VALUE_S);
+ putreg32(regval, SPI_USER2_REG(id));
+
+ /* Set address bits and value */
+
+ if (QSPICMD_ISADDRESS(cmdinfo->flags))
+ {
+ user1_reg &= ~SPI_USR_ADDR_BITLEN_M;
+ user1_reg |= (cmdinfo->addrlen * 8 - 1) << SPI_USR_ADDR_BITLEN_S;
+
+ user_reg |= SPI_USR_ADDR_M;
+
+ putreg32(cmdinfo->addr, SPI_ADDR_REG(id));
+ }
+
+ /* Set dummy */
+
+ if (priv->dummies)
+ {
+ user1_reg &= ~SPI_USR_DUMMY_CYCLELEN_M;
+ user1_reg |= (priv->dummies - 1) << SPI_USR_DUMMY_CYCLELEN_S;
+
+ user_reg |= SPI_USR_DUMMY_M;
+ }
+
+ /* Set TX data */
+
+ if (QSPICMD_ISWRITE(cmdinfo->flags))
+ {
+ data = (uint8_t *)cmdinfo->buffer;
+
+ for (int i = 0; i < cmdinfo->buflen; i += 4)
+ {
+ memcpy(®val, data + i, 4);
+ putreg32(regval, SPI_W0_REG(id) + i);
+ }
+
+ user_reg |= SPI_USR_MOSI_M;
+
+ if (priv->data_lines == 2)
+ {
+ user_reg |= SPI_FWRITE_DUAL_M;
+ }
+ else if (priv->data_lines == 4)
+ {
+ user_reg |= SPI_FWRITE_QUAD_M;
+ }
+ }
+ else if (QSPICMD_ISREAD(cmdinfo->flags))
+ {
+ user_reg |= SPI_USR_MISO_M;
+ }
+
+ putreg32(user_reg, SPI_USER_REG(id));
+ putreg32(user1_reg, SPI_USER1_REG(id));
+
+ /* Set command and address I/O mode */
+
+ regval = getreg32(SPI_CTRL_REG(id));
+ regval &= ~(SPI_FCMD_OCT_M | SPI_FADDR_OCT_M | SPI_FREAD_OCT_M |
+ SPI_FCMD_DUAL_M | SPI_FADDR_DUAL_M | SPI_FREAD_DUAL_M |
+ SPI_FCMD_QUAD_M | SPI_FADDR_QUAD_M | SPI_FREAD_QUAD_M);
+ if (QSPICMD_ISIDUAL(cmdinfo->flags))
+ {
+ regval |= SPI_FCMD_DUAL_M;
+ }
+ else if (QSPICMD_ISIQUAD(cmdinfo->flags))
+ {
+ regval |= SPI_FCMD_QUAD_M;
+ }
+
+ if (priv->addr_lines == 2)
+ {
+ regval |= SPI_FADDR_DUAL_M;
+ }
+ else if (priv->addr_lines == 4)
+ {
+ regval |= SPI_FADDR_QUAD_M;
+ }
+
+ if (QSPICMD_ISREAD(cmdinfo->flags))
+ {
+ if (priv->data_lines == 2)
+ {
+ regval |= SPI_FREAD_DUAL_M;
+ }
+ else if (priv->data_lines == 4)
+ {
+ regval |= SPI_FREAD_QUAD_M;
+ }
+ }
+
+ putreg32(regval, SPI_CTRL_REG(id));
+
+ /* Update QSPI master registers value */
+
+ regval = getreg32(SPI_CMD_REG(id));
+ regval |= SPI_UPDATE_M;
+ putreg32(regval, SPI_CMD_REG(id));
+
+ while ((getreg32(SPI_CMD_REG(id)) & SPI_UPDATE_M) != 0)
+ {
+ ;
+ }
+
+ /* Start transmision */
+
+ regval = getreg32(SPI_CMD_REG(id));
+ regval |= SPI_USR_M;
+ putreg32(regval, SPI_CMD_REG(id));
+
+ /* Wait until transmission is done */
+
+ while ((getreg32(SPI_CMD_REG(id)) & SPI_USR_M) != 0)
+ {
+ ;
+ }
+
+ if (QSPICMD_ISREAD(cmdinfo->flags))
+ {
+ data = (uint8_t *)cmdinfo->buffer;
+
+ for (int i = 0; i < cmdinfo->buflen; i += 4)
+ {
+ regval = getreg32(SPI_W0_REG(id) + i);
+ memcpy(data + i, ®val, MIN(4, cmdinfo->buflen - i));
+ }
+ }
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: esp32s3_qspi_memory
+ *
+ * Description:
+ * Perform one QSPI memory transfer
+ *
+ * Input Parameters:
+ * dev - Device-specific state data
+ * meminfo - Describes the memory transfer to be performed.
+ *
+ * Returned Value:
+ * Zero (OK) on SUCCESS, a negated errno on value of failure
+ *
+ ****************************************************************************/
+
+static int esp32s3_qspi_memory(struct qspi_dev_s *dev,
+ struct qspi_meminfo_s *meminfo)
+{
+#ifdef CONFIG_ESP32S3_SPI_DMA
+ uint32_t regval;
+ struct esp32s3_qspi_priv_s *priv = (struct esp32s3_qspi_priv_s *)dev;
+ uint8_t id = priv->config->id;
+ uint32_t user1_reg = getreg32(SPI_USER1_REG(id));
+ uint32_t user_reg = getreg32(SPI_USER_REG(id));
+
+ if (QSPIMEM_ISWRITE(meminfo->flags) || QSPIMEM_ISREAD(meminfo->flags))
+ {
+ if (meminfo->buflen > QSPI_DMA_BUFSIZE)
+ {
+ return -EINVAL;
+ }
+ else
+ {
+ putreg32(meminfo->buflen * 8 - 1, SPI_MS_DLEN_REG(id));
+ }
+ }
+
+ /* Reset SPI DMA FIFO */
+
+ regval = getreg32(SPI_DMA_CONF_REG(id));
+ regval |= QSPI_DMA_RESET_MASK;
+ putreg32(regval, SPI_DMA_CONF_REG(id));
+
+ regval &= ~QSPI_DMA_RESET_MASK;
+ putreg32(regval, SPI_DMA_CONF_REG(id));
+
+ /* Initiliaze QSPI user register */
+
+ user_reg &= ~(SPI_USR_MOSI_M |
+ SPI_USR_MISO_M |
+ SPI_USR_DUMMY_M |
+ SPI_FWRITE_DUAL_M |
+ SPI_FWRITE_OCT_M |
+ SPI_FWRITE_QUAD_M);
+ user_reg |= SPI_USR_COMMAND_M | SPI_USR_ADDR_M;
+
+ /* Set command bits and value, and command is always needed */
+
+ regval = getreg32(SPI_USER2_REG(id));
+ regval &= ~(SPI_USR_COMMAND_BITLEN_M |
+ SPI_USR_COMMAND_VALUE_M |
+ SPI_MST_REMPTY_ERR_END_EN_M);
+ regval |= ((QSPI_CMD_BITS(meminfo->cmd) - 1) << SPI_USR_COMMAND_BITLEN_S) |
+ (meminfo->cmd << SPI_USR_COMMAND_VALUE_S);
+ putreg32(regval, SPI_USER2_REG(id));
+
+ /* Set address bits and value */
+
+ user1_reg &= ~SPI_USR_ADDR_BITLEN_M;
+ user1_reg |= (meminfo->addrlen * 8 - 1) << SPI_USR_ADDR_BITLEN_S;
+
+ putreg32(meminfo->addr, SPI_ADDR_REG(id));
+
+ /* Set dummy */
+
+ if (meminfo->dummies)
+ {
+ user1_reg &= ~SPI_USR_DUMMY_CYCLELEN_M;
+ user1_reg |= (meminfo->dummies - 1) << SPI_USR_DUMMY_CYCLELEN_S;
+
+ user_reg |= SPI_USR_DUMMY_M;
+ }
+
+ /* Enable SPI DMA TX */
+
+ if (QSPIMEM_ISWRITE(meminfo->flags))
+ {
+ regval = getreg32(SPI_DMA_CONF_REG(id));
+ regval |= SPI_DMA_TX_ENA_M;
+ putreg32(regval, SPI_DMA_CONF_REG(id));
+
+ user_reg |= SPI_USR_MOSI_M;
+
+ if (priv->data_lines == 2)
+ {
+ user_reg |= SPI_FWRITE_DUAL_M;
+ }
+ else if (priv->data_lines == 4)
+ {
+ user_reg |= SPI_FWRITE_QUAD_M;
+ }
+
+ esp32s3_dma_setup(priv->dma_channel,
+ true,
+ priv->dma_desc,
+ QSPI_DMA_DESC_NUM,
+ (uint8_t *)meminfo->buffer,
+ meminfo->buflen);
+ esp32s3_dma_enable(priv->dma_channel, true);
+ }
+ else if (QSPIMEM_ISREAD(meminfo->flags))
+ {
+ regval = getreg32(SPI_DMA_CONF_REG(id));
+ regval |= SPI_DMA_RX_ENA_M;
+ putreg32(regval, SPI_DMA_CONF_REG(id));
+
+ user_reg |= SPI_USR_MISO_M;
+
+ esp32s3_dma_setup(priv->dma_channel,
+ false,
+ priv->dma_desc,
+ QSPI_DMA_DESC_NUM,
+ (uint8_t *)meminfo->buffer,
+ meminfo->buflen);
+ esp32s3_dma_enable(priv->dma_channel, false);
+ }
+
+ putreg32(user_reg, SPI_USER_REG(id));
+ putreg32(user1_reg, SPI_USER1_REG(id));
+
+ /* Set command and address I/O mode */
+
+ regval = getreg32(SPI_CTRL_REG(id));
+ regval &= ~(SPI_FCMD_OCT_M | SPI_FADDR_OCT_M | SPI_FREAD_OCT_M |
+ SPI_FCMD_DUAL_M | SPI_FADDR_DUAL_M | SPI_FREAD_DUAL_M |
+ SPI_FCMD_QUAD_M | SPI_FADDR_QUAD_M | SPI_FREAD_QUAD_M);
+ if (QSPIMEM_ISIDUAL(meminfo->flags))
+ {
+ regval |= SPI_FCMD_DUAL_M;
+ }
+ else if (QSPIMEM_ISIQUAD(meminfo->flags))
+ {
+ regval |= SPI_FCMD_QUAD_M;
+ }
+
+ if (priv->addr_lines == 2)
+ {
+ regval |= SPI_FADDR_DUAL_M;
+ }
+ else if (priv->addr_lines == 4)
+ {
+ regval |= SPI_FADDR_QUAD_M;
+ }
+
+ if (QSPIMEM_ISREAD(meminfo->flags))
+ {
+ if (priv->data_lines == 2)
+ {
+ regval |= SPI_FREAD_DUAL_M;
+ }
+ else if (priv->data_lines == 4)
+ {
+ regval |= SPI_FREAD_QUAD_M;
+ }
+ }
+
+ putreg32(regval, SPI_CTRL_REG(id));
+
+ /* Set interrupt */
+
+ putreg32(SPI_TRANS_DONE_INT_CLR_M, SPI_DMA_INT_CLR_REG(id));
+ putreg32(SPI_TRANS_DONE_INT_ENA_M, SPI_DMA_INT_ENA_REG(id));
+
+ /* Update QSPI master registers value */
+
+ regval = getreg32(SPI_CMD_REG(id));
+ regval |= SPI_UPDATE_M;
+ putreg32(regval, SPI_CMD_REG(id));
+
+ while ((getreg32(SPI_CMD_REG(id)) & SPI_UPDATE_M) != 0)
+ {
+ ;
+ }
+
+ /* Start transmision */
+
+ regval = getreg32(SPI_CMD_REG(id));
+ regval |= SPI_USR_M;
+ putreg32(regval, SPI_CMD_REG(id));
+
+ /* Wait for transmision done */
+
+ esp32s3_qspi_wait_sem(priv);
+
+ /* Reset interrupt */
+
+ putreg32(0, SPI_DMA_INT_ENA_REG(id));
+
+ return 0;
+#else
+ return -1;
+#endif
+}
+
+/****************************************************************************
+ * Name: esp32s3_qspi_alloc
+ *
+ * Description:
+ * Allocate a buffer suitable for DMA data transfer
+ *
+ * Input Parameters:
+ * dev - Device-specific state data
+ * buflen - Buffer length to allocate in bytes
+ *
+ * Returned Value:
+ * Address of the allocated memory on success; NULL is returned on any
+ * failure.
+ *
+ ****************************************************************************/
+
+static void *esp32s3_qspi_alloc(struct qspi_dev_s *dev, size_t buflen)
+{
+#ifdef CONFIG_ESP32S3_SPI_DMA
+ return kmm_malloc(ALIGN_UP(buflen, 4));
+#else
+ return NULL;
+#endif
+}
+
+/****************************************************************************
+ * Name: esp32s3_qspi_free
+ *
+ * Description:
+ * Free memory returned by QSPI_ALLOC
+ *
+ * Input Parameters:
+ * dev - Device-specific state data
+ * buffer - Buffer previously allocated via QSPI_ALLOC
+ *
+ * Returned Value:
+ * None.
+ *
+ ****************************************************************************/
+
+static void esp32s3_qspi_free(struct qspi_dev_s *dev, void *buffer)
+{
+#ifdef CONFIG_ESP32S3_SPI_DMA
+ if (buffer)
+ {
+ kmm_free(buffer);
+ }
+#endif
+}
+
+/****************************************************************************
+ * Name: esp32s3_qspi_wait_sem
+ *
+ * Description:
+ * Wait for a transfer to complete.
+ *
+ * Input Parameters:
+ * priv - QSPI private state data
+ *
+ * Returned Value:
+ * None.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32S3_SPI_DMA
+static int esp32s3_qspi_wait_sem(struct esp32s3_qspi_priv_s *priv)
+{
+ return nxsem_tickwait_uninterruptible(&priv->sem_isr, SEC2TICK(10));
+}
+#endif
+
+/****************************************************************************
+ * Name: esp32s3_qspi_init_dma
+ *
+ * Description:
+ * Initialize ESP32-S3 QSPI connection to GDMA engine.
+ *
+ * Input Parameters:
+ * priv - QSPI private state data
+ *
+ * Returned Value:
+ * None.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32S3_SPI_DMA
+void esp32s3_qspi_init_dma(struct esp32s3_qspi_priv_s *priv)
+{
+ const struct esp32s3_qspi_config_s *config = priv->config;
+
+ /* Enable GDMA clock for the QSPI peripheral */
+
+ modifyreg32(SYSTEM_PERIP_CLK_EN0_REG, 0, config->dma_clk_bit);
+
+ /* Reset GDMA for the QSPI peripheral */
+
+ modifyreg32(SYSTEM_PERIP_RST_EN0_REG, config->dma_rst_bit, 0);
+
+ /* Initialize GDMA controller */
+
+ esp32s3_dma_init();
+
+ /* Request a GDMA channel for QSPI peripheral */
+
+ priv->dma_channel = esp32s3_dma_request(config->dma_periph, 1, 1, true);
+ if (priv->dma_channel < 0)
+ {
+ spierr("Failed to allocate GDMA channel\n");
+
+ DEBUGPANIC();
+ }
+
+ /* Disable segment transaction mode for QSPI Master */
+
+ putreg32((SPI_SLV_RX_SEG_TRANS_CLR_EN_M | SPI_SLV_TX_SEG_TRANS_CLR_EN_M),
+ SPI_DMA_CONF_REG(config->id));
+}
+#endif
+
+/****************************************************************************
+ * Name: esp32s3_qspi_init_iomux
+ *
+ * Description:
+ * Initialize ESP32-S3 QSPI GPIO by IO MUX.
+ *
+ * Input Parameters:
+ * priv - QSPI private state data
+ *
+ * Returned Value:
+ * None.
+ *
+ ****************************************************************************/
+
+#if QSPI_VIA_IOMUX != 0
+static void esp32s3_qspi_init_iomux(struct esp32s3_qspi_priv_s *priv)
+{
+ uint32_t attr = OUTPUT_FUNCTION_5;
+ const struct esp32s3_qspi_config_s *config = priv->config;
+
+ esp32s3_configgpio(config->cs_pin, attr);
+ esp32s3_configgpio(config->clk_pin, attr);
+
+ attr |= INPUT;
+
+ esp32s3_configgpio(config->mosi_pin, attr);
+ esp32s3_configgpio(config->miso_pin, attr);
+ esp32s3_configgpio(config->io2_pin, attr);
+ esp32s3_configgpio(config->io3_pin, attr);
+
+ esp32s3_gpio_matrix_out(config->cs_pin, SIG_GPIO_OUT_IDX, 0, 0);
+ esp32s3_gpio_matrix_out(config->clk_pin, SIG_GPIO_OUT_IDX, 0, 0);
+ esp32s3_gpio_matrix_out(config->mosi_pin, SIG_GPIO_OUT_IDX, 0, 0);
+ esp32s3_gpio_matrix_out(config->miso_pin, SIG_GPIO_OUT_IDX, 0, 0);
+ esp32s3_gpio_matrix_out(config->io2_pin, SIG_GPIO_OUT_IDX, 0, 0);
+ esp32s3_gpio_matrix_out(config->io3_pin, SIG_GPIO_OUT_IDX, 0, 0);
+}
+#endif
+
+/****************************************************************************
+ * Name: esp32s3_qspi_init_iomatrix
+ *
+ * Description:
+ * Initialize ESP32-S3 QSPI GPIO by IO matrix.
+ *
+ * Input Parameters:
+ * priv - QSPI private state data
+ *
+ * Returned Value:
+ * None.
+ *
+ ****************************************************************************/
+
+#if QSPI_VIA_IOMUX == 0 || defined(CONFIG_ESP32S3_SPI3)
+static void esp32s3_qspi_init_iomatrix(struct esp32s3_qspi_priv_s *priv)
+{
+ uint32_t attr = OUTPUT;
+ const struct esp32s3_qspi_config_s *config = priv->config;
+
+ esp32s3_configgpio(config->cs_pin, OUTPUT);
+ esp32s3_gpio_matrix_out(config->cs_pin, config->cs_outsig, 0, 0);
+
+ esp32s3_configgpio(config->clk_pin, OUTPUT);
+ esp32s3_gpio_matrix_out(config->clk_pin, config->clk_outsig, 0, 0);
+
+ attr |= INPUT;
+
+ esp32s3_configgpio(config->mosi_pin, attr);
+ esp32s3_gpio_matrix_in(config->mosi_pin, config->mosi_insig, 0);
+ esp32s3_gpio_matrix_out(config->mosi_pin, config->mosi_outsig, 0, 0);
+
+ esp32s3_configgpio(config->miso_pin, attr);
+ esp32s3_gpio_matrix_in(config->miso_pin, config->miso_insig, 0);
+ esp32s3_gpio_matrix_out(config->miso_pin, config->miso_outsig, 0, 0);
+
+ esp32s3_configgpio(config->io2_pin, attr);
+ esp32s3_gpio_matrix_in(config->io2_pin, config->io2_insig, 0);
+ esp32s3_gpio_matrix_out(config->io2_pin, config->io2_outsig, 0, 0);
+
+ esp32s3_configgpio(config->io3_pin, attr);
+ esp32s3_gpio_matrix_in(config->io3_pin, config->io3_insig, 0);
+ esp32s3_gpio_matrix_out(config->io3_pin, config->io3_outsig, 0, 0);
+}
+#endif
+
+/****************************************************************************
+ * Name: esp32s3_qspi_init_gpio
+ *
+ * Description:
+ * Initialize ESP32-S3 QSPI GPIO
+ *
+ * Input Parameters:
+ * priv - QSPI private state data
+ *
+ * Returned Value:
+ * None.
+ *
+ ****************************************************************************/
+
+static void esp32s3_qspi_init_gpio(struct esp32s3_qspi_priv_s *priv)
+{
+ /* SPI3 doesn't have IOMUX */
+
+#if QSPI_VIA_IOMUX != 0
+ if (priv->config->id == 2)
+ {
+ esp32s3_qspi_init_iomux(priv);
+ }
+#ifdef CONFIG_ESP32S3_SPI3
+ else
+ {
+ esp32s3_qspi_init_iomatrix(priv);
+ }
+#endif
+#else
+ esp32s3_qspi_init_iomatrix(priv);
+#endif
+}
+
+/****************************************************************************
+ * Name: esp32s3_qspi_init
+ *
+ * Description:
+ * Initialize ESP32-S3 QSPI hardware interface.
+ *
+ * Input Parameters:
+ * priv - QSPI private state data
+ *
+ * Returned Value:
+ * None.
+ *
+ ****************************************************************************/
+
+static void esp32s3_qspi_init(struct esp32s3_qspi_priv_s *priv)
+{
+ const struct esp32s3_qspi_config_s *config = priv->config;
+ uint8_t id = config->id;
+
+ esp32s3_qspi_init_gpio(priv);
+
+ modifyreg32(SYSTEM_PERIP_CLK_EN0_REG, 0, config->clk_bit);
+ modifyreg32(SYSTEM_PERIP_RST_EN0_REG, config->rst_bit, 0);
+
+ putreg32(SPI_USR_MOSI_M | SPI_CS_HOLD_M, SPI_USER_REG(id));
+
+ putreg32(0, SPI_USER1_REG(id));
+ putreg32(0, SPI_SLAVE_REG(id));
+ putreg32(SPI_CS1_DIS_M | SPI_CS2_DIS_M, SPI_MISC_REG(id));
+
+ putreg32(SPI_CLK_EN_M | SPI_MST_CLK_ACTIVE_M | SPI_MST_CLK_SEL_M,
+ SPI_CLK_GATE_REG(id));
+
+ putreg32(0, SPI_CTRL_REG(id));
+
+#ifdef CONFIG_ESP32S3_SPI_DMA
+ esp32s3_qspi_init_dma(priv);
+#endif
+
+ esp32s3_qspi_setfrequency(&priv->spi_dev, QSPI_DEFAULT_FREQ);
+ esp32s3_qspi_setbits(&priv->spi_dev, QSPI_DEFAULT_WIDTH);
+ esp32s3_qspi_setmode(&priv->spi_dev, QSPI_DEFAULT_MODE);
+}
+
+/****************************************************************************
+ * Name: esp32s3_qspi_deinit
+ *
+ * Description:
+ * Deinitialize ESP32-S3 QSPI hardware interface.
+ *
+ * Input Parameters:
+ * priv - QSPI private state data
+ *
+ * Returned Value:
+ * None.
+ *
+ ****************************************************************************/
+
+static void esp32s3_qspi_deinit(struct esp32s3_qspi_priv_s *priv)
+{
+ const struct esp32s3_qspi_config_s *config = priv->config;
+
+#ifdef CONFIG_ESP32S3_SPI_DMA
+ modifyreg32(SYSTEM_PERIP_RST_EN0_REG, 0, config->dma_rst_bit);
+ modifyreg32(SYSTEM_PERIP_CLK_EN0_REG, config->dma_clk_bit, 0);
+#endif
+
+ modifyreg32(SYSTEM_PERIP_RST_EN0_REG, 0, config->rst_bit);
+ modifyreg32(SYSTEM_PERIP_CLK_EN0_REG, config->clk_bit, 0);
+
+ priv->frequency = 0;
+ priv->actual = 0;
+ priv->mode = QSPIDEV_MODE0;
+ priv->nbits = 0;
+ priv->dummies = 0;
+ priv->addr_lines = 4;
+ priv->data_lines = 4;
+}
+
+/****************************************************************************
+ * Name: esp32s3_qspi_interrupt
+ *
+ * Description:
+ * Common QSPI DMA interrupt handler.
+ *
+ * Input Parameters:
+ * irq - Number of the IRQ that generated the interrupt
+ * context - Interrupt register state save info
+ * arg - QSPI controller private data
+ *
+ * Returned Value:
+ * Standard interrupt return value.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32S3_SPI_DMA
+static int esp32s3_qspi_interrupt(int irq, void *context, void *arg)
+{
+ struct esp32s3_qspi_priv_s *priv = (struct esp32s3_qspi_priv_s *)arg;
+
+ /* Write 1 to clear interrupt bit */
+
+ putreg32(SPI_TRANS_DONE_INT_CLR_M, SPI_DMA_INT_CLR_REG(priv->config->id));
+
+ nxsem_post(&priv->sem_isr);
+
+ return 0;
+}
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp32s3_qspibus_set_attr
+ *
+ * Description:
+ * Set attribution of QSPI bus transfer.
+ *
+ * Input Parameters:
+ * dev - Device-specific state data
+ * dummies - Number of dummy cycles, this only works in command
+ * transfer, not works in memory transfer
+ * addr_lines - Number of address transmiting I/O pins
+ * data_lines - Number of data transmiting I/O pins
+ *
+ * Returned Value:
+ * Zero (OK) is returned on success. Otherwise -1 (ERROR).
+ *
+ ****************************************************************************/
+
+int esp32s3_qspibus_set_attr(struct qspi_dev_s *dev,
+ uint8_t dummies,
+ uint8_t addr_lines,
+ uint8_t data_lines)
+{
+ struct esp32s3_qspi_priv_s *priv = (struct esp32s3_qspi_priv_s *)dev;
+
+ DEBUGASSERT(dev);
+
+ if (priv->refs == 0)
+ {
+ return ERROR;
+ }
+
+ if ((addr_lines != 1) &&
+ (addr_lines != 2) &&
+ (addr_lines != 4))
+ {
+ return ERROR;
+ }
+
+ if ((data_lines != 1) &&
+ (data_lines != 2) &&
+ (data_lines != 4))
+ {
+ return ERROR;
+ }
+
+ priv->dummies = dummies;
+ priv->addr_lines = addr_lines;
+ priv->data_lines = data_lines;
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: esp32s3_qspibus_initialize
+ *
+ * Description:
+ * Initialize the selected QSPI bus.
+ *
+ * Input Parameters:
+ * port - Port number (for hardware that has multiple QSPI interfaces)
+ *
+ * Returned Value:
+ * Valid QSPI device structure reference on success; NULL on failure.
+ *
+ ****************************************************************************/
+
+struct qspi_dev_s *esp32s3_qspibus_initialize(int port)
+{
+ struct qspi_dev_s *spi_dev;
+ struct esp32s3_qspi_priv_s *priv;
+
+ switch (port)
+ {
+#ifdef CONFIG_ESP32S3_SPI2
+ case ESP32S3_SPI2:
+ priv = &esp32s3_spi2_priv;
+ break;
+#endif
+#ifdef CONFIG_ESP32S3_SPI3
+ case ESP32S3_SPI3:
+ priv = &esp32s3_spi3_priv;
+ break;
+#endif
+ default:
+ return NULL;
+ }
+
+ spi_dev = (struct qspi_dev_s *)priv;
+
+ nxmutex_lock(&priv->lock);
+ if (priv->refs != 0)
+ {
+ priv->refs++;
+ nxmutex_unlock(&priv->lock);
+ return spi_dev;
+ }
+
+#ifdef CONFIG_ESP32S3_SPI_DMA
+
+ /* Set up to receive peripheral interrupts on the current CPU */
+
+ priv->cpu = up_cpu_index();
+ priv->cpuint = esp32s3_setup_irq(priv->cpu, priv->config->periph,
+ ESP32S3_INT_PRIO_DEF,
+ ESP32S3_CPUINT_LEVEL);
+ if (priv->cpuint < 0)
+ {
+ /* Failed to allocate a CPU interrupt of this type. */
+
+ nxmutex_unlock(&priv->lock);
+ return NULL;
+ }
+
+ /* Attach and enable the IRQ */
+
+ if (irq_attach(priv->config->irq, esp32s3_qspi_interrupt, priv) != OK)
+ {
+ /* Failed to attach IRQ, so CPU interrupt must be freed. */
+
+ esp32s3_teardown_irq(priv->cpu, priv->config->periph, priv->cpuint);
+ priv->cpuint = -ENOMEM;
+ nxmutex_unlock(&priv->lock);
+
+ return NULL;
+ }
+
+ /* Enable the CPU interrupt that is linked to the QSPI device. */
+
+ up_enable_irq(priv->config->irq);
+#endif
+
+ esp32s3_qspi_init(priv);
+ priv->refs++;
+ nxmutex_unlock(&priv->lock);
+ return spi_dev;
+}
+
+/****************************************************************************
+ * Name: esp32s3_qspibus_uninitialize
+ *
+ * Description:
+ * Uninitialize an QSPI bus.
+ *
+ * Input Parameters:
+ * dev - Device-specific state data
+ *
+ * Returned Value:
+ * Zero (OK) is returned on success. Otherwise -1 (ERROR).
+ *
+ ****************************************************************************/
+
+int esp32s3_qspibus_uninitialize(struct qspi_dev_s *dev)
+{
+ struct esp32s3_qspi_priv_s *priv = (struct esp32s3_qspi_priv_s *)dev;
+
+ DEBUGASSERT(dev);
+
+ if (priv->refs == 0)
+ {
+ return ERROR;
+ }
+
+ nxmutex_lock(&priv->lock);
+ if (--priv->refs != 0)
+ {
+ nxmutex_unlock(&priv->lock);
+ return OK;
+ }
+
+#ifdef CONFIG_ESP32S3_SPI_DMA
+ up_disable_irq(priv->config->irq);
+ esp32s3_teardown_irq(priv->cpu, priv->config->periph, priv->cpuint);
+ irq_detach(priv->config->irq);
+
+ priv->cpuint = -ENOMEM;
+#endif
+
+ esp32s3_qspi_deinit(priv);
+ nxmutex_unlock(&priv->lock);
+
+ return OK;
+}
+
+#endif /* CONFIG_ESP32S3_SPI */
diff --git a/arch/xtensa/src/esp32s3/esp32s3_qspi.h b/arch/xtensa/src/esp32s3/esp32s3_qspi.h
new file mode 100644
index 0000000000..fd60fa66f0
--- /dev/null
+++ b/arch/xtensa/src/esp32s3/esp32s3_qspi.h
@@ -0,0 +1,126 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32s3/esp32s3_qspi.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#ifndef __ARCH_XTENSA_SRC_ESP32S3_ESP32S3_QSPI_H
+#define __ARCH_XTENSA_SRC_ESP32S3_ESP32S3_QSPI_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/spi/qspi.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32S3_SPI
+
+#ifdef CONFIG_ESP32S3_SPI2
+# define ESP32S3_SPI2 2
+#endif
+
+#ifdef CONFIG_ESP32S3_SPI3
+# define ESP32S3_SPI3 3
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+#ifndef __ASSEMBLY__
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Name: esp32s3_qspibus_set_attr
+ *
+ * Description:
+ * Set attribution of QSPI bus transfer.
+ *
+ * Input Parameters:
+ * dev - Device-specific state data
+ * dummies - Number of dummy cycles, this only works in command
+ * transfer, not works in memory transfer
+ * addr_lines - Number of address transmiting I/O pins
+ * data_lines - Number of data transmiting I/O pins
+ *
+ * Returned Value:
+ * Zero (OK) is returned on success. Otherwise -1 (ERROR).
+ *
+ ****************************************************************************/
+
+int esp32s3_qspibus_set_attr(struct qspi_dev_s *dev,
+ uint8_t dummies,
+ uint8_t addr_lines,
+ uint8_t data_lines);
+
+/****************************************************************************
+ * Name: esp32s3_qspibus_initialize
+ *
+ * Description:
+ * Initialize the selected QSPI bus.
+ *
+ * Input Parameters:
+ * port - Port number (for hardware that has multiple QSPI interfaces)
+ *
+ * Returned Value:
+ * Valid QSPI device structure reference on success; NULL on failure
+ *
+ ****************************************************************************/
+
+struct qspi_dev_s *esp32s3_qspibus_initialize(int port);
+
+/****************************************************************************
+ * Name: esp32s3_qspibus_uninitialize
+ *
+ * Description:
+ * Uninitialize an QSPI bus.
+ *
+ * Input Parameters:
+ * dev - Device-specific state data
+ *
+ * Returned Value:
+ * Zero (OK) is returned on success. Otherwise -1 (ERROR).
+ *
+ ****************************************************************************/
+
+int esp32s3_qspibus_uninitialize(struct qspi_dev_s *dev);
+
+#ifdef __cplusplus
+}
+#endif
+#undef EXTERN
+
+#endif /* __ASSEMBLY__ */
+#endif /* CONFIG_ESP32S3_SPI */
+#endif /* __ARCH_XTENSA_SRC_ESP32S3_ESP32S3_QSPI_H */
diff --git a/arch/xtensa/src/esp32s3/esp32s3_spi.c b/arch/xtensa/src/esp32s3/esp32s3_spi.c
index 9cb529f684..b7f048599d 100644
--- a/arch/xtensa/src/esp32s3/esp32s3_spi.c
+++ b/arch/xtensa/src/esp32s3/esp32s3_spi.c
@@ -48,7 +48,7 @@
#include "esp32s3_irq.h"
#include "esp32s3_gpio.h"
-#ifdef CONFIG_ESP32S3_SPI2_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
#include "esp32s3_dma.h"
#endif
@@ -71,11 +71,15 @@
# define SPI_HAVE_SWCS 0
#endif
-#ifdef CONFIG_ESP32S3_SPI2_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
-/* SPI DMA RX/TX number of descriptors */
+/* QSPI DMA RX/TX number of descriptors */
-#define SPI_DMA_DESC_NUM (CONFIG_ESP32S3_SPI2_DMADESC_NUM)
+# if (CONFIG_ESP32S3_SPI_DMA_BUFSIZE % ESP32S3_DMA_BUFLEN_MAX) > 0
+# define SPI_DMA_DESC_NUM (CONFIG_ESP32S3_SPI_DMA_BUFSIZE / ESP32S3_DMA_BUFLEN_MAX + 1)
+# else
+# define SPI_DMA_DESC_NUM (CONFIG_ESP32S3_SPI_DMA_BUFSIZE / ESP32S3_DMA_BUFLEN_MAX)
+# endif
/* SPI DMA reset before exchange */
@@ -123,13 +127,13 @@ struct esp32s3_spi_config_s
uint8_t mosi_pin; /* GPIO configuration for MOSI */
uint8_t miso_pin; /* GPIO configuration for MISO */
uint8_t clk_pin; /* GPIO configuration for CLK */
-#ifdef CONFIG_ESP32S3_SPI2_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
uint8_t periph; /* Peripheral ID */
uint8_t irq; /* Interrupt ID */
#endif
uint32_t clk_bit; /* Clock enable bit */
uint32_t rst_bit; /* SPI reset bit */
-#ifdef CONFIG_ESP32S3_SPI2_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
uint32_t dma_clk_bit; /* DMA clock enable bit */
uint32_t dma_rst_bit; /* DMA reset bit */
#endif
@@ -154,11 +158,16 @@ struct esp32s3_spi_priv_s
const struct esp32s3_spi_config_s *config;
int refs; /* Reference count */
mutex_t lock; /* Held while chip is selected for mutual exclusion */
-#ifdef CONFIG_ESP32S3_SPI2_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
sem_t sem_isr; /* Interrupt wait semaphore */
int cpu; /* CPU ID */
int cpuint; /* SPI interrupt ID */
int32_t dma_channel; /* Channel assigned by the GDMA driver */
+
+ /* DMA RX/TX description */
+
+ struct esp32s3_dmadesc_s *dma_rxdesc;
+ struct esp32s3_dmadesc_s *dma_txdesc;
#endif
uint32_t frequency; /* Requested clock frequency */
uint32_t actual; /* Actual clock frequency */
@@ -188,7 +197,7 @@ static uint32_t esp32s3_spi_send(struct spi_dev_s *dev, uint32_t wd);
static void esp32s3_spi_exchange(struct spi_dev_s *dev,
const void *txbuffer,
void *rxbuffer, size_t nwords);
-#ifdef CONFIG_ESP32S3_SPI2_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
static int esp32s3_spi_interrupt(int irq, void *context, void *arg);
static int esp32s3_spi_sem_waitdone(struct esp32s3_spi_priv_s *priv);
static void esp32s3_spi_dma_exchange(struct esp32s3_spi_priv_s *priv,
@@ -212,7 +221,7 @@ static void esp32s3_spi_recvblock(struct spi_dev_s *dev,
#ifdef CONFIG_SPI_TRIGGER
static int esp32s3_spi_trigger(struct spi_dev_s *dev);
#endif
-#ifdef CONFIG_ESP32S3_SPI2_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
static void esp32s3_spi_dma_init(struct spi_dev_s *dev);
#endif
static void esp32s3_spi_init(struct spi_dev_s *dev);
@@ -233,13 +242,13 @@ static const struct esp32s3_spi_config_s esp32s3_spi2_config =
.mosi_pin = CONFIG_ESP32S3_SPI2_MOSIPIN,
.miso_pin = CONFIG_ESP32S3_SPI2_MISOPIN,
.clk_pin = CONFIG_ESP32S3_SPI2_CLKPIN,
-#ifdef CONFIG_ESP32S3_SPI2_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
.periph = ESP32S3_PERIPH_SPI2,
.irq = ESP32S3_IRQ_SPI2,
#endif
.clk_bit = SYSTEM_SPI2_CLK_EN,
.rst_bit = SYSTEM_SPI2_RST,
-#ifdef CONFIG_ESP32S3_SPI2_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
.dma_clk_bit = SYSTEM_SPI2_DMA_CLK_EN,
.dma_rst_bit = SYSTEM_SPI2_DMA_RST,
#endif
@@ -284,6 +293,15 @@ static const struct spi_ops_s esp32s3_spi2_ops =
.registercallback = NULL,
};
+#ifdef CONFIG_ESP32S3_SPI_DMA
+
+/* SPI DMA RX/TX description */
+
+static struct esp32s3_dmadesc_s esp32s3_spi2_dma_txdesc[SPI_DMA_DESC_NUM];
+static struct esp32s3_dmadesc_s esp32s3_spi2_dma_rxdesc[SPI_DMA_DESC_NUM];
+
+#endif
+
static struct esp32s3_spi_priv_s esp32s3_spi2_priv =
{
.spi_dev =
@@ -293,10 +311,12 @@ static struct esp32s3_spi_priv_s esp32s3_spi2_priv =
.config = &esp32s3_spi2_config,
.refs = 0,
.lock = NXMUTEX_INITIALIZER,
-#ifdef CONFIG_ESP32S3_SPI2_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
.sem_isr = SEM_INITIALIZER(0),
.cpuint = -ENOMEM,
.dma_channel = -1,
+ .dma_rxdesc = esp32s3_spi2_dma_rxdesc,
+ .dma_txdesc = esp32s3_spi2_dma_txdesc,
#endif
.frequency = 0,
.actual = 0,
@@ -316,8 +336,16 @@ static const struct esp32s3_spi_config_s esp32s3_spi3_config =
.mosi_pin = CONFIG_ESP32S3_SPI3_MOSIPIN,
.miso_pin = CONFIG_ESP32S3_SPI3_MISOPIN,
.clk_pin = CONFIG_ESP32S3_SPI3_CLKPIN,
+#ifdef CONFIG_ESP32S3_SPI_DMA
+ .periph = ESP32S3_PERIPH_SPI3,
+ .irq = ESP32S3_IRQ_SPI3,
+#endif
.clk_bit = SYSTEM_SPI3_CLK_EN,
.rst_bit = SYSTEM_SPI3_RST,
+#ifdef CONFIG_ESP32S3_SPI_DMA
+ .dma_clk_bit = SYSTEM_SPI3_DMA_CLK_EN,
+ .dma_rst_bit = SYSTEM_SPI3_DMA_RST,
+#endif
.cs_insig = FSPICS0_IN_IDX,
.cs_outsig = FSPICS0_OUT_IDX,
.mosi_insig = FSPID_IN_IDX,
@@ -359,6 +387,15 @@ static const struct spi_ops_s esp32s3_spi3_ops =
.registercallback = NULL,
};
+#ifdef CONFIG_ESP32S3_SPI_DMA
+
+/* SPI DMA RX/TX description */
+
+static struct esp32s3_dmadesc_s esp32s3_spi3_dma_txdesc[SPI_DMA_DESC_NUM];
+static struct esp32s3_dmadesc_s esp32s3_spi3_dma_rxdesc[SPI_DMA_DESC_NUM];
+
+#endif
+
static struct esp32s3_spi_priv_s esp32s3_spi3_priv =
{
.spi_dev =
@@ -368,6 +405,13 @@ static struct esp32s3_spi_priv_s esp32s3_spi3_priv =
.config = &esp32s3_spi3_config,
.refs = 0,
.lock = NXMUTEX_INITIALIZER,
+#ifdef CONFIG_ESP32S3_SPI_DMA
+ .sem_isr = SEM_INITIALIZER(0),
+ .cpuint = -ENOMEM,
+ .dma_channel = -1,
+ .dma_rxdesc = esp32s3_spi3_dma_rxdesc,
+ .dma_txdesc = esp32s3_spi3_dma_txdesc,
+#endif
.frequency = 0,
.actual = 0,
.mode = 0,
@@ -375,15 +419,6 @@ static struct esp32s3_spi_priv_s esp32s3_spi3_priv =
};
#endif /* CONFIG_ESP32S3_SPI3 */
-#ifdef CONFIG_ESP32S3_SPI2_DMA
-
-/* SPI DMA RX/TX description */
-
-static struct esp32s3_dmadesc_s dma_rxdesc[SPI_DMA_DESC_NUM];
-static struct esp32s3_dmadesc_s dma_txdesc[SPI_DMA_DESC_NUM];
-
-#endif
-
/****************************************************************************
* Private Functions
****************************************************************************/
@@ -515,7 +550,7 @@ static int esp32s3_spi_lock(struct spi_dev_s *dev, bool lock)
*
****************************************************************************/
-#ifdef CONFIG_ESP32S3_SPI2_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
static int esp32s3_spi_sem_waitdone(struct esp32s3_spi_priv_s *priv)
{
return nxsem_tickwait_uninterruptible(&priv->sem_isr, SEC2TICK(10));
@@ -824,7 +859,7 @@ static int esp32s3_spi_hwfeatures(struct spi_dev_s *dev,
*
****************************************************************************/
-#ifdef CONFIG_ESP32S3_SPI2_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
static void esp32s3_spi_dma_exchange(struct esp32s3_spi_priv_s *priv,
const void *txbuffer,
void *rxbuffer,
@@ -869,8 +904,8 @@ static void esp32s3_spi_dma_exchange(struct esp32s3_spi_priv_s *priv,
esp32s3_spi_set_regbits(SPI_DMA_CONF_REG(priv->config->id),
SPI_DMA_TX_ENA_M);
- n = esp32s3_dma_setup(channel, true, dma_txdesc, SPI_DMA_DESC_NUM,
- tp, bytes);
+ n = esp32s3_dma_setup(channel, true, priv->dma_txdesc,
+ SPI_DMA_DESC_NUM, tp, bytes);
esp32s3_dma_enable(channel, true);
putreg32((n * 8 - 1), SPI_MS_DLEN_REG(priv->config->id));
@@ -886,8 +921,8 @@ static void esp32s3_spi_dma_exchange(struct esp32s3_spi_priv_s *priv,
esp32s3_spi_set_regbits(SPI_DMA_CONF_REG(priv->config->id),
SPI_DMA_RX_ENA_M);
- esp32s3_dma_setup(channel, false, dma_rxdesc, SPI_DMA_DESC_NUM,
- rp, bytes);
+ esp32s3_dma_setup(channel, false, priv->dma_rxdesc,
+ SPI_DMA_DESC_NUM, rp, bytes);
esp32s3_dma_enable(channel, false);
esp32s3_spi_set_regbits(SPI_USER_REG(priv->config->id),
@@ -1158,8 +1193,8 @@ static void esp32s3_spi_exchange(struct spi_dev_s *dev,
{
struct esp32s3_spi_priv_s *priv = (struct esp32s3_spi_priv_s *)dev;
-#ifdef CONFIG_ESP32S3_SPI2_DMA
- size_t thld = CONFIG_ESP32S3_SPI2_DMATHRESHOLD;
+#ifdef CONFIG_ESP32S3_SPI_DMA
+ size_t thld = CONFIG_ESP32S3_SPI_DMATHRESHOLD;
if (nwords > thld)
{
@@ -1270,7 +1305,7 @@ static int esp32s3_spi_trigger(struct spi_dev_s *dev)
*
****************************************************************************/
-#ifdef CONFIG_ESP32S3_SPI2_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
void esp32s3_spi_dma_init(struct spi_dev_s *dev)
{
struct esp32s3_spi_priv_s *priv = (struct esp32s3_spi_priv_s *)dev;
@@ -1389,7 +1424,7 @@ static void esp32s3_spi_init(struct spi_dev_s *dev)
putreg32(VALUE_MASK(0, SPI_CS_HOLD_TIME),
SPI_USER1_REG(priv->config->id));
-#ifdef CONFIG_ESP32S3_SPI2_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
esp32s3_spi_dma_init(dev);
#endif
@@ -1416,7 +1451,7 @@ static void esp32s3_spi_deinit(struct spi_dev_s *dev)
{
struct esp32s3_spi_priv_s *priv = (struct esp32s3_spi_priv_s *)dev;
-#ifdef CONFIG_ESP32S3_SPI2_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
modifyreg32(SYSTEM_PERIP_CLK_EN0_REG, priv->config->dma_clk_bit, 0);
#endif
@@ -1445,7 +1480,7 @@ static void esp32s3_spi_deinit(struct spi_dev_s *dev)
*
****************************************************************************/
-#ifdef CONFIG_ESP32S3_SPI2_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
static int esp32s3_spi_interrupt(int irq, void *context, void *arg)
{
struct esp32s3_spi_priv_s *priv = (struct esp32s3_spi_priv_s *)arg;
@@ -1505,7 +1540,7 @@ struct spi_dev_s *esp32s3_spibus_initialize(int port)
return spi_dev;
}
-#ifdef CONFIG_ESP32S3_SPI2_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
/* If a CPU Interrupt was previously allocated, then deallocate it */
if (priv->cpuint != -ENOMEM)
@@ -1591,7 +1626,7 @@ int esp32s3_spibus_uninitialize(struct spi_dev_s *dev)
return OK;
}
-#ifdef CONFIG_ESP32S3_SPI2_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
up_disable_irq(priv->config->irq);
esp32s3_teardown_irq(priv->cpu, priv->config->periph, priv->cpuint);
irq_detach(priv->config->irq);
diff --git a/arch/xtensa/src/esp32s3/esp32s3_spi_slave.c b/arch/xtensa/src/esp32s3/esp32s3_spi_slave.c
index 9b8edf2678..27ba2257f4 100644
--- a/arch/xtensa/src/esp32s3/esp32s3_spi_slave.c
+++ b/arch/xtensa/src/esp32s3/esp32s3_spi_slave.c
@@ -48,7 +48,7 @@
#include "esp32s3_irq.h"
#include "esp32s3_gpio.h"
-#if defined(CONFIG_ESP32S3_SPI2_DMA) || defined(CONFIG_ESP32S3_SPI3_DMA)
+#ifdef CONFIG_ESP32S3_SPI_DMA
#include "esp32s3_dma.h"
#endif
@@ -65,20 +65,27 @@
#define SPI_SLAVE_BUFSIZE (CONFIG_ESP32S3_SPI_SLAVE_BUFSIZE)
-#if defined(CONFIG_ESP32S3_SPI2_DMA) || defined(CONFIG_ESP32S3_SPI3_DMA)
-# define ESP32S3_SPI_DMA
-#endif
-
-#ifdef ESP32S3_SPI_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
/* SPI DMA RX/TX number of descriptors */
-#if (SPI_SLAVE_BUFSIZE % ESP32S3_DMA_BUFLEN_MAX) > 0
-# define SPI_DMA_DESC_NUM (SPI_SLAVE_BUFSIZE / ESP32S3_DMA_BUFLEN_MAX + 1)
+# if (SPI_SLAVE_BUFSIZE % ESP32S3_DMA_BUFLEN_MAX) > 0
+# define SPI_DMA_DESC_NUM (SPI_SLAVE_BUFSIZE / ESP32S3_DMA_BUFLEN_MAX + 1)
+# else
+# define SPI_DMA_DESC_NUM (SPI_SLAVE_BUFSIZE / ESP32S3_DMA_BUFLEN_MAX)
+# endif
+
+# define SPI_SLV_INT_EN (SPI_SLV_WR_DMA_DONE_INT_ENA_M | SPI_SLV_RD_DMA_DONE_INT_ENA_M)
+# define SPI_SLV_INT_RX SPI_SLV_WR_DMA_DONE_INT_ST_M
+# define SPI_SLV_INT_CLR_RX SPI_SLV_WR_DMA_DONE_INT_CLR_M
+# define SPI_SLV_INT_TX SPI_SLV_RD_DMA_DONE_INT_ST_M
+# define SPI_SLV_INT_CLR_TX SPI_SLV_RD_DMA_DONE_INT_CLR_M
#else
-# define SPI_DMA_DESC_NUM (SPI_SLAVE_BUFSIZE / ESP32S3_DMA_BUFLEN_MAX)
-#endif
-
-#endif /* ESP32S3_SPI_DMA */
+# define SPI_SLV_INT_EN (SPI_SLV_WR_BUF_DONE_INT_ENA_M | SPI_SLV_RD_BUF_DONE_INT_ENA_M)
+# define SPI_SLV_INT_RX SPI_SLV_WR_BUF_DONE_INT_ST_M
+# define SPI_SLV_INT_CLR_RX SPI_SLV_WR_BUF_DONE_INT_CLR_M
+# define SPI_SLV_INT_TX SPI_SLV_RD_BUF_DONE_INT_ST_M
+# define SPI_SLV_INT_CLR_TX SPI_SLV_RD_BUF_DONE_INT_CLR_M
+#endif /* CONFIG_ESP32S3_SPI_DMA */
/* Verify whether SPI has been assigned IOMUX pins.
* Otherwise, SPI signals will be routed via GPIO Matrix.
@@ -90,10 +97,29 @@
# define SPI_IS_MOSI_IOMUX (CONFIG_ESP32S3_SPI2_MOSIPIN == SPI2_IOMUX_MOSIPIN)
# define SPI_IS_MISO_IOMUX (CONFIG_ESP32S3_SPI2_MISOPIN == SPI2_IOMUX_MISOPIN)
-# define SPI_VIA_IOMUX ((SPI_IS_CS_IOMUX) && \
- (SPI_IS_CLK_IOMUX) && \
- (SPI_IS_MOSI_IOMUX) && \
- (SPI_IS_MISO_IOMUX))
+/* In quad SPI mode, flash's IO map is:
+ * MOSI -> IO0
+ * MISO -> IO1
+ * WP -> IO2
+ * Hold -> IO3
+ */
+
+# ifdef CONFIG_ESP32S3_SPI_IO_QIO
+# define SPI_IS_IO2_IOMUX (CONFIG_ESP32S3_SPI2_IO2PIN == SPI2_IOMUX_WPPIN)
+# define SPI_IS_IO3_IOMUX (CONFIG_ESP32S3_SPI2_IO3PIN == SPI2_IOMUX_HDPIN)
+
+# define SPI_VIA_IOMUX ((SPI_IS_CS_IOMUX) && \
+ (SPI_IS_CLK_IOMUX) && \
+ (SPI_IS_MOSI_IOMUX) && \
+ (SPI_IS_MISO_IOMUX) && \
+ (SPI_IS_IO2_IOMUX) && \
+ (SPI_IS_IO3_IOMUX))
+# else
+# define SPI_VIA_IOMUX ((SPI_IS_CS_IOMUX) && \
+ (SPI_IS_CLK_IOMUX) && \
+ (SPI_IS_MOSI_IOMUX) && \
+ (SPI_IS_MISO_IOMUX))
+# endif
#else
# define SPI_VIA_IOMUX 0
#endif
@@ -136,12 +162,15 @@ struct spislave_config_s
uint8_t mosi_pin; /* GPIO configuration for MOSI */
uint8_t miso_pin; /* GPIO configuration for MISO */
uint8_t clk_pin; /* GPIO configuration for CLK */
+#ifdef CONFIG_ESP32S3_SPI_IO_QIO
+ uint8_t io2_pin; /* GPIO configuration for IO2 */
+ uint8_t io3_pin; /* GPIO configuration for IO3 */
+#endif
uint8_t periph; /* Peripheral ID */
uint8_t irq; /* Interrupt ID */
uint32_t clk_bit; /* Clock enable bit */
uint32_t rst_bit; /* SPI reset bit */
-#ifdef ESP32S3_SPI_DMA
- bool dma_used; /* Enable DMA channel */
+#ifdef CONFIG_ESP32S3_SPI_DMA
uint32_t dma_clk_bit; /* DMA clock enable bit */
uint32_t dma_rst_bit; /* DMA reset bit */
uint8_t dma_periph; /* DMA peripheral */
@@ -154,6 +183,12 @@ struct spislave_config_s
uint32_t miso_outsig; /* SPI MISO output signal index */
uint32_t clk_insig; /* SPI CLK input signal index */
uint32_t clk_outsig; /* SPI CLK output signal index */
+#ifdef CONFIG_ESP32S3_SPI_IO_QIO
+ uint32_t io2_insig;
+ uint32_t io2_outsig;
+ uint32_t io3_insig;
+ uint32_t io3_outsig;
+#endif
};
struct spislave_priv_s
@@ -172,7 +207,7 @@ struct spislave_priv_s
int refs; /* Reference count */
int cpu; /* CPU ID */
int cpuint; /* SPI interrupt ID */
-#ifdef ESP32S3_SPI_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
int32_t dma_channel; /* Channel assigned by the GDMA driver */
/* DMA RX/TX description */
@@ -224,7 +259,7 @@ static void spislave_store_result(struct spislave_priv_s *priv,
uint32_t recv_bytes);
static void spislave_evict_sent_data(struct spislave_priv_s *priv,
uint32_t sent_bytes);
-#ifdef ESP32S3_SPI_DMA
+#ifdef CONFIG_ESP32S3_SPI_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_rx(struct spislave_priv_s *priv);
@@ -265,12 +300,15 @@ static const struct spislave_config_s esp32s3_spi2slave_config =
.mosi_pin = CONFIG_ESP32S3_SPI2_MOSIPIN,
.miso_pin = CONFIG_ESP32S3_SPI2_MISOPIN,
.clk_pin = CONFIG_ESP32S3_SPI2_CLKPIN,
+#ifdef CONFIG_ESP32S3_SPI_IO_QIO
+ .io2_pin = CONFIG_ESP32S3_SPI2_IO2PIN,
+ .io3_pin = CONFIG_ESP32S3_SPI2_IO3PIN,
+#endif
.periph = ESP32S3_PERIPH_SPI2,
.irq = ESP32S3_IRQ_SPI2,
.clk_bit = SYSTEM_SPI2_CLK_EN,
.rst_bit = SYSTEM_SPI2_RST,
-#ifdef CONFIG_ESP32S3_SPI2_DMA
- .dma_used = true,
+#ifdef CONFIG_ESP32S3_SPI_DMA
.dma_clk_bit = SYSTEM_SPI2_DMA_CLK_EN,
.dma_rst_bit = SYSTEM_SPI2_DMA_RST,
.dma_periph = ESP32S3_DMA_PERIPH_SPI2,
@@ -282,7 +320,13 @@ static const struct spislave_config_s esp32s3_spi2slave_config =
.miso_insig = FSPIQ_IN_IDX,
.miso_outsig = FSPIQ_OUT_IDX,
.clk_insig = FSPICLK_IN_IDX,
- .clk_outsig = FSPICLK_OUT_IDX
+ .clk_outsig = FSPICLK_OUT_IDX,
+#ifdef CONFIG_ESP32S3_SPI_IO_QIO
+ .io2_insig = FSPIWP_IN_IDX,
+ .io2_outsig = FSPIWP_OUT_IDX,
+ .io3_insig = FSPIHD_IN_IDX,
+ .io3_outsig = FSPIHD_OUT_IDX,
+#endif
};
static const struct spi_slave_ctrlrops_s esp32s3_spi2slave_ops =
@@ -295,7 +339,7 @@ static const struct spi_slave_ctrlrops_s esp32s3_spi2slave_ops =
.qpoll = spislave_qpoll
};
-#ifdef CONFIG_ESP32S3_SPI2_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
/* SPI DMA RX/TX description buffer */
@@ -314,7 +358,7 @@ static struct spislave_priv_s esp32s3_spi2slave_priv =
.refs = 0,
.cpu = -1,
.cpuint = -ENOMEM,
-#ifdef CONFIG_ESP32S3_SPI2_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
.dma_channel = -ENOMEM,
.dma_rxdesc = esp32s3_spi2_dma_rxdesc,
.dma_txdesc = esp32s3_spi2_dma_txdesc,
@@ -347,12 +391,15 @@ static const struct spislave_config_s esp32s3_spi3slave_config =
.mosi_pin = CONFIG_ESP32S3_SPI3_MOSIPIN,
.miso_pin = CONFIG_ESP32S3_SPI3_MISOPIN,
.clk_pin = CONFIG_ESP32S3_SPI3_CLKPIN,
+#ifdef CONFIG_ESP32S3_SPI_IO_QIO
+ .io2_pin = CONFIG_ESP32S3_SPI3_IO2PIN,
+ .io3_pin = CONFIG_ESP32S3_SPI3_IO3PIN,
+#endif
.periph = ESP32S3_PERIPH_SPI3,
.irq = ESP32S3_IRQ_SPI3,
.clk_bit = SYSTEM_SPI3_CLK_EN,
.rst_bit = SYSTEM_SPI3_RST,
-#ifdef CONFIG_ESP32S3_SPI3_DMA
- .dma_used = true,
+#ifdef CONFIG_ESP32S3_SPI_DMA
.dma_clk_bit = SYSTEM_SPI3_DMA_CLK_EN,
.dma_rst_bit = SYSTEM_SPI3_DMA_RST,
.dma_periph = ESP32S3_DMA_PERIPH_SPI3,
@@ -364,7 +411,13 @@ static const struct spislave_config_s esp32s3_spi3slave_config =
.miso_insig = SPI3_Q_IN_IDX,
.miso_outsig = SPI3_Q_OUT_IDX,
.clk_insig = SPI3_CLK_IN_IDX,
- .clk_outsig = SPI3_CLK_OUT_IDX
+ .clk_outsig = SPI3_CLK_OUT_IDX,
+#ifdef CONFIG_ESP32S3_SPI_IO_QIO
+ .io2_insig = SPI3_WP_IN_IDX,
+ .io2_outsig = SPI3_WP_OUT_IDX,
+ .io3_insig = SPI3_HD_IN_IDX,
+ .io3_outsig = SPI3_HD_OUT_IDX,
+#endif
};
static const struct spi_slave_ctrlrops_s esp32s3_spi3slave_ops =
@@ -377,7 +430,7 @@ static const struct spi_slave_ctrlrops_s esp32s3_spi3slave_ops =
.qpoll = spislave_qpoll
};
-#ifdef CONFIG_ESP32S3_SPI3_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
/* SPI DMA RX/TX description buffer */
@@ -396,7 +449,7 @@ static struct spislave_priv_s esp32s3_spi3slave_priv =
.refs = 0,
.cpu = -1,
.cpuint = -ENOMEM,
-#ifdef CONFIG_ESP32S3_SPI3_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
.dma_channel = -ENOMEM,
.dma_rxdesc = esp32s3_spi3_dma_rxdesc,
.dma_txdesc = esp32s3_spi3_dma_txdesc,
@@ -479,7 +532,7 @@ static inline void spislave_cpu_tx_fifo_reset(struct spislave_priv_s *priv)
*
****************************************************************************/
-#ifdef ESP32S3_SPI_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
static inline void spislave_dma_tx_fifo_reset(struct spislave_priv_s *priv)
{
setbits(SPI_DMA_AFIFO_RST_M, SPI_DMA_CONF_REG(priv->config->id));
@@ -502,7 +555,7 @@ static inline void spislave_dma_tx_fifo_reset(struct spislave_priv_s *priv)
*
****************************************************************************/
-#ifdef ESP32S3_SPI_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
static inline void spislave_dma_rx_fifo_reset(struct spislave_priv_s *priv)
{
setbits(SPI_RX_AFIFO_RST_M, SPI_DMA_CONF_REG(priv->config->id));
@@ -678,7 +731,7 @@ static void spislave_store_result(struct spislave_priv_s *priv,
bytes_to_copy = remaining_space;
}
-#ifdef ESP32S3_SPI_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
if (bytes_to_copy)
{
if ((priv->rx_dma_offset != priv->rx_length))
@@ -739,7 +792,7 @@ static void spislave_store_result(struct spislave_priv_s *priv,
*
****************************************************************************/
-#ifdef ESP32S3_SPI_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
static void spislave_prepare_next_rx(struct spislave_priv_s *priv)
{
if (priv->rx_length < SPI_SLAVE_BUFSIZE)
@@ -797,7 +850,7 @@ static void spislave_evict_sent_data(struct spislave_priv_s *priv,
*
****************************************************************************/
-#ifndef ESP32S3_SPI_DMA
+#ifndef CONFIG_ESP32S3_SPI_DMA
static void spislave_write_tx_buffer(struct spislave_priv_s *priv)
{
/* Initialize data_buf_reg with the address of the first data buffer
@@ -842,7 +895,7 @@ static void spislave_write_tx_buffer(struct spislave_priv_s *priv)
*
****************************************************************************/
-#ifdef ESP32S3_SPI_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
static void spislave_setup_rx_dma(struct spislave_priv_s *priv)
{
uint32_t length = SPI_SLAVE_BUFSIZE - priv->rx_length;
@@ -888,7 +941,7 @@ static void spislave_setup_rx_dma(struct spislave_priv_s *priv)
*
****************************************************************************/
-#ifdef ESP32S3_SPI_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
static void spislave_setup_tx_dma(struct spislave_priv_s *priv)
{
esp32s3_dma_setup(priv->dma_channel,
@@ -934,11 +987,8 @@ static void spislave_prepare_next_tx(struct spislave_priv_s *priv)
{
if (priv->tx_length != 0)
{
-#ifdef ESP32S3_SPI_DMA
- if (priv->config->dma_used)
- {
- spislave_setup_tx_dma(priv);
- }
+#ifdef CONFIG_ESP32S3_SPI_DMA
+ spislave_setup_tx_dma(priv);
#else
spislave_peripheral_reset(priv);
@@ -953,14 +1003,7 @@ static void spislave_prepare_next_tx(struct spislave_priv_s *priv)
{
spiwarn("TX buffer empty! Disabling TX for next transaction\n");
-#ifdef ESP32S3_SPI_DMA
- if (!priv->config->dma_used)
- {
- spislave_cpu_tx_fifo_reset(priv);
- }
-#else
spislave_cpu_tx_fifo_reset(priv);
-#endif
priv->is_tx_enabled = false;
}
@@ -986,10 +1029,16 @@ static void spislave_prepare_next_tx(struct spislave_priv_s *priv)
static int spislave_periph_interrupt(int irq, void *context, void *arg)
{
struct spislave_priv_s *priv = (struct spislave_priv_s *)arg;
-
uint32_t regval = getreg32(SPI_SLAVE1_REG(priv->config->id));
uint32_t transfer_size = REG_MASK(regval, SPI_SLV_DATA_BITLEN) / 8;
+#ifdef CONFIG_ESP32S3_SPI_IO_QIO
+ uint32_t int_clear = 0;
+ uint32_t int_status = getreg32(SPI_DMA_INT_ST_REG(priv->config->id));
+#else
+ uint32_t int_clear = SPI_TRANS_DONE_INT_CLR_M;
+#endif
+
if (!priv->is_processing)
{
SPIS_DEV_SELECT(priv->dev, true);
@@ -998,26 +1047,41 @@ static int spislave_periph_interrupt(int irq, void *context, void *arg)
/* RX process */
- if (transfer_size > 0)
+#ifdef CONFIG_ESP32S3_SPI_IO_QIO
+ if (int_status & SPI_SLV_INT_RX)
{
- spislave_store_result(priv, transfer_size);
- }
+#endif
+ if (transfer_size > 0)
+ {
+ spislave_store_result(priv, transfer_size);
+ }
-#ifdef ESP32S3_SPI_DMA
- if (priv->config->dma_used)
- {
+#ifdef CONFIG_ESP32S3_SPI_DMA
spislave_prepare_next_rx(priv);
+#endif
+
+#ifdef CONFIG_ESP32S3_SPI_IO_QIO
+ int_clear |= SPI_SLV_INT_CLR_RX;
}
#endif
/* TX process */
- if (priv->is_tx_enabled && transfer_size > 0)
+#ifdef CONFIG_ESP32S3_SPI_IO_QIO
+ if (int_status & SPI_SLV_INT_TX)
{
- spislave_evict_sent_data(priv, transfer_size);
- }
+#endif
+ if (priv->is_tx_enabled && transfer_size > 0)
+ {
+ spislave_evict_sent_data(priv, transfer_size);
+ }
- spislave_prepare_next_tx(priv);
+ spislave_prepare_next_tx(priv);
+
+#ifdef CONFIG_ESP32S3_SPI_IO_QIO
+ int_clear |= SPI_SLV_INT_CLR_TX;
+ }
+#endif
if (priv->is_processing && esp32s3_gpioread(priv->config->cs_pin))
{
@@ -1027,11 +1091,13 @@ static int spislave_periph_interrupt(int irq, void *context, void *arg)
/* Clear the trans_done interrupt flag */
- setbits(SPI_TRANS_DONE_INT_CLR_M, SPI_DMA_INT_CLR_REG(priv->config->id));
+ setbits(int_clear, SPI_DMA_INT_CLR_REG(priv->config->id));
/* Trigger the start of user-defined transaction */
+#ifndef CONFIG_ESP32S3_SPI_IO_QIO
setbits(SPI_USR_M, SPI_CMD_REG(priv->config->id));
+#endif
return 0;
}
@@ -1050,7 +1116,7 @@ static int spislave_periph_interrupt(int irq, void *context, void *arg)
*
****************************************************************************/
-#ifdef ESP32S3_SPI_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
void spislave_dma_init(struct spislave_priv_s *priv)
{
/* Enable GDMA clock for the SPI peripheral */
@@ -1087,10 +1153,10 @@ void spislave_dma_init(struct spislave_priv_s *priv)
#endif
/****************************************************************************
- * Name: spislave_gpio_initialize
+ * Name: spislave_initializ_iomux
*
* Description:
- * Initialize ESP32-S3 SPI Slave GPIO
+ * Initialize ESP32-S3 SPI Slave GPIO by IO MUX.
*
* Input Parameters:
* priv - Private SPI Slave controller structure
@@ -1100,56 +1166,120 @@ void spislave_dma_init(struct spislave_priv_s *priv)
*
****************************************************************************/
-static void spislave_gpio_initialize(struct spislave_priv_s *priv)
+#if SPI_VIA_IOMUX != 0
+static void spislave_initializ_iomux(struct spislave_priv_s *priv)
{
+ uint32_t attr = INPUT_FUNCTION_5 | DRIVE_0;
const struct spislave_config_s *config = priv->config;
- esp32s3_gpiowrite(config->cs_pin, 1);
- esp32s3_gpiowrite(config->mosi_pin, 1);
- esp32s3_gpiowrite(config->miso_pin, 1);
- esp32s3_gpiowrite(config->clk_pin, 1);
+ esp32s3_configgpio(config->cs_pin, attr);
+ esp32s3_configgpio(config->clk_pin, attr);
-#if SPI_VIA_IOMUX != 0
- if (priv->config->id == 0)
- {
- esp32s3_configgpio(config->cs_pin, INPUT_FUNCTION_5 | PULLUP);
- esp32s3_gpio_matrix_out(config->cs_pin, SIG_GPIO_OUT_IDX, 0, 0);
+ esp32s3_gpio_matrix_out(config->cs_pin, SIG_GPIO_OUT_IDX, 0, 0);
+ esp32s3_gpio_matrix_out(config->clk_pin, SIG_GPIO_OUT_IDX, 0, 0);
+ esp32s3_gpio_matrix_out(config->mosi_pin, SIG_GPIO_OUT_IDX, 0, 0);
+ esp32s3_gpio_matrix_out(config->miso_pin, SIG_GPIO_OUT_IDX, 0, 0);
- esp32s3_configgpio(config->mosi_pin, INPUT_FUNCTION_5 | PULLUP);
- esp32s3_gpio_matrix_out(config->mosi_pin, SIG_GPIO_OUT_IDX, 0, 0);
+#ifdef CONFIG_ESP32S3_SPI_IO_QIO
+ attr |= OUTPUT;
- esp32s3_configgpio(config->miso_pin, OUTPUT_FUNCTION_5 | PULLUP);
- esp32s3_gpio_matrix_out(config->miso_pin, SIG_GPIO_OUT_IDX, 0, 0);
+ esp32s3_configgpio(config->mosi_pin, attr);
+ esp32s3_configgpio(config->miso_pin, attr);
+ esp32s3_configgpio(config->io2_pin, attr);
+ esp32s3_configgpio(config->io3_pin, attr);
- esp32s3_configgpio(config->clk_pin, INPUT_FUNCTION_5 | PULLUP);
- esp32s3_gpio_matrix_out(config->clk_pin, SIG_GPIO_OUT_IDX, 0, 0);
- }
- else
- {
- esp32s3_configgpio(config->cs_pin, INPUT_FUNCTION_2 | PULLUP);
- esp32s3_gpio_matrix_in(config->cs_pin, config->cs_insig, 0);
+ esp32s3_gpio_matrix_out(config->io2_pin, SIG_GPIO_OUT_IDX, 0, 0);
+ esp32s3_gpio_matrix_out(config->io3_pin, SIG_GPIO_OUT_IDX, 0, 0);
+#else
+ esp32s3_configgpio(config->mosi_pin, attr);
+ esp32s3_configgpio(config->miso_pin, OUTPUT_FUNCTION_5);
+#endif
+}
+#endif
- esp32s3_configgpio(config->mosi_pin, INPUT_FUNCTION_2 | PULLUP);
- esp32s3_gpio_matrix_in(config->mosi_pin, config->mosi_insig, 0);
+/****************************************************************************
+ * Name: spislave_initializ_iomatrix
+ *
+ * Description:
+ * Initialize ESP32-S3 SPI Slave GPIO by IO matrix.
+ *
+ * Input Parameters:
+ * priv - Private SPI Slave controller structure
+ *
+ * Returned Value:
+ * None.
+ *
+ ****************************************************************************/
- esp32s3_configgpio(config->miso_pin, OUTPUT_FUNCTION_2 | PULLUP);
- esp32s3_gpio_matrix_out(config->miso_pin, config->miso_outsig, 0, 0);
+#if SPI_VIA_IOMUX == 0 || defined(CONFIG_ESP32S3_SPI3)
+static void spislave_initializ_iomatrix(struct spislave_priv_s *priv)
+{
+ uint32_t attr = INPUT | DRIVE_0;
+ const struct spislave_config_s *config = priv->config;
- esp32s3_configgpio(config->clk_pin, INPUT_FUNCTION_2 | PULLUP);
- esp32s3_gpio_matrix_in(config->clk_pin, config->clk_insig, 0);
- }
-#else
- esp32s3_configgpio(config->cs_pin, INPUT_FUNCTION_2 | PULLUP);
+ esp32s3_configgpio(config->cs_pin, attr);
esp32s3_gpio_matrix_in(config->cs_pin, config->cs_insig, 0);
- esp32s3_configgpio(config->mosi_pin, INPUT_FUNCTION_2 | PULLUP);
+ esp32s3_configgpio(config->clk_pin, attr);
+ esp32s3_gpio_matrix_in(config->clk_pin, config->clk_insig, 0);
+
+# ifdef CONFIG_ESP32S3_SPI_IO_QIO
+ attr |= OUTPUT;
+
+ esp32s3_configgpio(config->mosi_pin, attr);
esp32s3_gpio_matrix_in(config->mosi_pin, config->mosi_insig, 0);
+ esp32s3_gpio_matrix_out(config->mosi_pin, config->mosi_outsig, 0, 0);
- esp32s3_configgpio(config->miso_pin, OUTPUT_FUNCTION_2 | PULLUP);
+ esp32s3_configgpio(config->miso_pin, attr);
+ esp32s3_gpio_matrix_in(config->miso_pin, config->miso_insig, 0);
esp32s3_gpio_matrix_out(config->miso_pin, config->miso_outsig, 0, 0);
- esp32s3_configgpio(config->clk_pin, INPUT_FUNCTION_2 | PULLUP);
- esp32s3_gpio_matrix_in(config->clk_pin, config->clk_insig, 0);
+ esp32s3_configgpio(config->io2_pin, attr);
+ esp32s3_gpio_matrix_in(config->io2_pin, config->io2_insig, 0);
+ esp32s3_gpio_matrix_out(config->io2_pin, config->io2_outsig, 0, 0);
+
+ esp32s3_configgpio(config->io3_pin, attr);
+ esp32s3_gpio_matrix_in(config->io3_pin, config->io3_insig, 0);
+ esp32s3_gpio_matrix_out(config->io3_pin, config->io3_outsig, 0, 0);
+# else
+ esp32s3_configgpio(config->mosi_pin, attr);
+ esp32s3_gpio_matrix_in(config->mosi_pin, config->mosi_insig, 0);
+
+ esp32s3_configgpio(config->miso_pin, OUTPUT);
+ esp32s3_gpio_matrix_out(config->miso_pin, config->miso_outsig, 0, 0);
+# endif
+}
+#endif
+
+/****************************************************************************
+ * Name: spislave_gpio_initialize
+ *
+ * Description:
+ * Initialize ESP32-S3 SPI Slave GPIO
+ *
+ * Input Parameters:
+ * priv - Private SPI Slave controller structure
+ *
+ * Returned Value:
+ * None.
+ *
+ ****************************************************************************/
+
+static void spislave_gpio_initialize(struct spislave_priv_s *priv)
+{
+#if SPI_VIA_IOMUX != 0
+ if (priv->config->id == 2)
+ {
+ spislave_initializ_iomux(priv);
+ }
+# ifdef CONFIG_ESP32S3_SPI3
+ else
+ {
+ spislave_initializ_iomatrix(priv);
+ }
+# endif
+#else
+ spislave_initializ_iomatrix(priv);
#endif
}
@@ -1169,6 +1299,7 @@ static void spislave_gpio_initialize(struct spislave_priv_s *priv)
static void spislave_initialize(struct spi_slave_ctrlr_s *ctrlr)
{
+ uint32_t regval;
struct spislave_priv_s *priv = (struct spislave_priv_s *)ctrlr;
const struct spislave_config_s *config = priv->config;
@@ -1183,11 +1314,23 @@ static void spislave_initialize(struct spi_slave_ctrlr_s *ctrlr)
putreg32(0, SPI_CLOCK_REG(priv->config->id));
- putreg32(SPI_DOUTDIN_M, SPI_USER_REG(priv->config->id));
+#ifdef CONFIG_ESP32S3_SPI_IO_QIO
+ regval = 0;
+#else
+ regval = SPI_DOUTDIN_M;
+#endif
+ putreg32(regval, SPI_USER_REG(priv->config->id));
putreg32(0, SPI_CTRL_REG(priv->config->id));
- putreg32(SPI_SLAVE_MODE_M, SPI_SLAVE_REG(priv->config->id));
+ regval = SPI_SLAVE_MODE_M;
+#ifdef CONFIG_ESP32S3_SPI_DMA
+ regval |= SPI_SLV_WRDMA_BITLEN_EN_M | SPI_SLV_RDDMA_BITLEN_EN_M;
+#else
+ regval |= SPI_SLV_WRBUF_BITLEN_EN_M | SPI_SLV_RDBUF_BITLEN_EN_M;
+#endif
+
+ putreg32(regval, SPI_SLAVE_REG(priv->config->id));
spislave_peripheral_reset(priv);
@@ -1200,11 +1343,8 @@ static void spislave_initialize(struct spi_slave_ctrlr_s *ctrlr)
resetbits(SPI_INT_MASK, SPI_DMA_INT_ENA_REG(priv->config->id));
-#ifdef ESP32S3_SPI_DMA
- if (priv->config->dma_used)
- {
- spislave_dma_init(priv);
- }
+#ifdef CONFIG_ESP32S3_SPI_DMA
+ spislave_dma_init(priv);
#endif
esp32s3_gpioirqenable(ESP32S3_PIN2IRQ(config->cs_pin), GPIO_INTR_POSEDGE);
@@ -1216,8 +1356,13 @@ static void spislave_initialize(struct spi_slave_ctrlr_s *ctrlr)
* queued.
*/
- setbits(SPI_TRANS_DONE_INT_RAW_M, SPI_DMA_INT_RAW_REG(priv->config->id));
- setbits(SPI_TRANS_DONE_INT_ENA_M, SPI_DMA_INT_ENA_REG(priv->config->id));
+#ifdef CONFIG_ESP32S3_SPI_IO_QIO
+ regval = SPI_SLV_INT_EN;
+#else
+ regval = SPI_TRANS_DONE_INT_ENA_M;
+#endif
+ setbits(regval, SPI_DMA_INT_RAW_REG(priv->config->id));
+ setbits(regval, SPI_DMA_INT_ENA_REG(priv->config->id));
}
/****************************************************************************
@@ -1244,12 +1389,8 @@ static void spislave_deinitialize(struct spi_slave_ctrlr_s *ctrlr)
resetbits(SPI_TRANS_DONE_INT_ENA_M, SPI_DMA_INT_ENA_REG(priv->config->id));
-#ifdef ESP32S3_SPI_DMA
- if (priv->config->dma_used)
- {
- resetbits(priv->config->dma_clk_bit, SYSTEM_PERIP_CLK_EN0_REG);
- }
-
+#ifdef CONFIG_ESP32S3_SPI_DMA
+ resetbits(priv->config->dma_clk_bit, SYSTEM_PERIP_CLK_EN0_REG);
priv->rx_dma_offset = 0;
#endif
@@ -1315,7 +1456,7 @@ static void spislave_bind(struct spi_slave_ctrlr_s *ctrlr,
SPIS_DEV_CMDDATA(dev, false);
-#ifdef ESP32S3_SPI_DMA
+#ifdef CONFIG_ESP32S3_SPI_DMA
priv->rx_dma_offset = 0;
#endif
@@ -1337,6 +1478,10 @@ static void spislave_bind(struct spi_slave_ctrlr_s *ctrlr,
priv->tx_length += num_bytes;
}
+#ifdef CONFIG_ESP32S3_SPI_DMA
+ spislave_prepare_next_rx(priv);
+#endif
+
/* Enable the CPU interrupt that is linked to the SPI Slave controller */
up_enable_irq(priv->config->irq);
@@ -1380,11 +1525,8 @@ static void spislave_unbind(struct spi_slave_ctrlr_s *ctrlr)
resetbits(SPI_TRANS_DONE_INT_ENA_M, SPI_DMA_INT_ENA_REG(priv->config->id));
-#ifdef ESP32S3_SPI_DMA
- if (priv->config->dma_used)
- {
- resetbits(priv->config->dma_clk_bit, SYSTEM_PERIP_CLK_EN0_REG);
- }
+#ifdef CONFIG_ESP32S3_SPI_DMA
+ resetbits(priv->config->dma_clk_bit, SYSTEM_PERIP_CLK_EN0_REG);
#endif
resetbits(priv->config->clk_bit, SYSTEM_PERIP_CLK_EN0_REG);