From 8f25329260c5b34f413d3ac331e3a8a54a7b20c6 Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Sat, 6 May 2023 15:20:48 +0800 Subject: [PATCH] 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 | 390 +++-- 6 files changed, 2132 insertions(+), 192 deletions(-) create mode 100644 arch/xtensa/src/esp32s3/esp32s3_qspi.c create mode 100644 arch/xtensa/src/esp32s3/esp32s3_qspi.h 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 +config ESP32S3_SPI2_IO2PIN + int "SPI2 IO2 Pin" + default 14 + range 0 48 + depends on ESP32S3_SPI_IO_QIO -if ESP32S3_SPI3 - -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 + +#ifdef CONFIG_ESP32S3_SPI + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#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 +#include + +/**************************************************************************** + * 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) -#else -# define SPI_DMA_DESC_NUM (SPI_SLAVE_BUFSIZE / ESP32S3_DMA_BUFLEN_MAX) -#endif +# 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 -#endif /* ESP32S3_SPI_DMA */ +# 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_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 */ @@ -1086,6 +1152,105 @@ void spislave_dma_init(struct spislave_priv_s *priv) } #endif +/**************************************************************************** + * Name: spislave_initializ_iomux + * + * Description: + * Initialize ESP32-S3 SPI Slave GPIO by IO MUX. + * + * Input Parameters: + * priv - Private SPI Slave controller structure + * + * Returned Value: + * None. + * + ****************************************************************************/ + +#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_configgpio(config->cs_pin, attr); + esp32s3_configgpio(config->clk_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); + +#ifdef CONFIG_ESP32S3_SPI_IO_QIO + attr |= OUTPUT; + + 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->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 + +/**************************************************************************** + * 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. + * + ****************************************************************************/ + +#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->cs_pin, attr); + esp32s3_gpio_matrix_in(config->cs_pin, config->cs_insig, 0); + + 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, 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); +# 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 * @@ -1102,54 +1267,19 @@ void spislave_dma_init(struct spislave_priv_s *priv) static void spislave_gpio_initialize(struct spislave_priv_s *priv) { - 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); - #if SPI_VIA_IOMUX != 0 - if (priv->config->id == 0) + if (priv->config->id == 2) { - esp32s3_configgpio(config->cs_pin, INPUT_FUNCTION_5 | PULLUP); - esp32s3_gpio_matrix_out(config->cs_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); - - 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->clk_pin, INPUT_FUNCTION_5 | PULLUP); - esp32s3_gpio_matrix_out(config->clk_pin, SIG_GPIO_OUT_IDX, 0, 0); + spislave_initializ_iomux(priv); } +# ifdef CONFIG_ESP32S3_SPI3 else { - esp32s3_configgpio(config->cs_pin, INPUT_FUNCTION_2 | PULLUP); - esp32s3_gpio_matrix_in(config->cs_pin, config->cs_insig, 0); - - esp32s3_configgpio(config->mosi_pin, INPUT_FUNCTION_2 | PULLUP); - esp32s3_gpio_matrix_in(config->mosi_pin, config->mosi_insig, 0); - - esp32s3_configgpio(config->miso_pin, OUTPUT_FUNCTION_2 | PULLUP); - 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); + spislave_initializ_iomatrix(priv); } +# endif #else - esp32s3_configgpio(config->cs_pin, INPUT_FUNCTION_2 | PULLUP); - esp32s3_gpio_matrix_in(config->cs_pin, config->cs_insig, 0); - - esp32s3_configgpio(config->mosi_pin, INPUT_FUNCTION_2 | PULLUP); - esp32s3_gpio_matrix_in(config->mosi_pin, config->mosi_insig, 0); - - esp32s3_configgpio(config->miso_pin, OUTPUT_FUNCTION_2 | PULLUP); - 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); + 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);