This is an automated email from the ASF dual-hosted git repository.
xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new b24f931aca xtensa/esp32s3: Support 32MB SPI flash
b24f931aca is described below
commit b24f931acaf0d461b90148f086800347f9253ac1
Author: Dong Heng <[email protected]>
AuthorDate: Wed May 24 10:27:09 2023 +0800
xtensa/esp32s3: Support 32MB SPI flash
---
arch/xtensa/src/esp32s3/Kconfig | 22 +
arch/xtensa/src/esp32s3/esp32s3_spiflash.c | 547 +++++++++++++++++++++++--
arch/xtensa/src/esp32s3/hardware/esp32s3_soc.h | 35 ++
3 files changed, 581 insertions(+), 23 deletions(-)
diff --git a/arch/xtensa/src/esp32s3/Kconfig b/arch/xtensa/src/esp32s3/Kconfig
index 2a783c3ea7..ef788de47d 100644
--- a/arch/xtensa/src/esp32s3/Kconfig
+++ b/arch/xtensa/src/esp32s3/Kconfig
@@ -230,6 +230,11 @@ config ESP32S3_FLASH_16M
bool
default n
+config ESP32S3_FLASH_32M
+ bool
+ default n
+ select ESP32S3S_SPI_FLASH_USE_32BIT_ADDRESS
+
config ESP32S3_ESPTOOLPY_NO_STUB
bool "Disable download stub"
default n
@@ -1036,6 +1041,23 @@ choice ESP32S3_FLASH_SAMPLE_MODE
bool "STR Mode"
endchoice
+config ESP32S3_SPI_FLASH_DONT_USE_ROM_CODE
+ bool "Don't use SPI flash driver in ROM"
+ default n
+ help
+ Use source code for SPI flash driver instead of functions
+ in ROM.
+
+config ESP32S3S_SPI_FLASH_USE_32BIT_ADDRESS
+ bool "SPI flash uses 32-bit address"
+ default n
+ select ESP32S3_SPI_FLASH_DONT_USE_ROM_CODE
+ help
+ SPI flash driver in ROM only support 24-bit address access,
+ if select the option, it will force to use source code instead
+ of functions in ROM, so that SPI flash driver can access full
+ 32-bit address.
+
config ESP32S3_HAVE_OTA_PARTITION
bool
default n
diff --git a/arch/xtensa/src/esp32s3/esp32s3_spiflash.c
b/arch/xtensa/src/esp32s3/esp32s3_spiflash.c
index 99c47e2a61..bf4e468a31 100644
--- a/arch/xtensa/src/esp32s3/esp32s3_spiflash.c
+++ b/arch/xtensa/src/esp32s3/esp32s3_spiflash.c
@@ -29,16 +29,19 @@
#include <debug.h>
#include <string.h>
#include <sys/types.h>
+#include <sys/param.h>
#include <inttypes.h>
#include <errno.h>
#include <nuttx/arch.h>
#include <nuttx/init.h>
-#include "hardware/esp32s3_soc.h"
-
+#include "xtensa.h"
+#include "xtensa_attr.h"
+#include "hardware/esp32s3_spi_mem_reg.h"
+#include "rom/esp32s3_spiflash.h"
+#include "rom/esp32s3_opi_flash.h"
#include "esp32s3_irq.h"
-
#include "esp32s3_spiflash.h"
/****************************************************************************
@@ -71,6 +74,99 @@
#define MMU_BYTES2PAGES(_n) (((_n) + SPI_FLASH_MMU_PAGE_SIZE - 1) / \
SPI_FLASH_MMU_PAGE_SIZE)
+#ifdef CONFIG_ESP32S3_SPI_FLASH_DONT_USE_ROM_CODE
+
+/* SPI port number */
+
+# define SPI_PORT (1)
+
+/* SPI buffer size */
+
+# define SPI_BUFFER_WORDS (16)
+# define SPI_BUFFER_BYTES (SPI_BUFFER_WORDS * 4)
+
+/* SPI flash hardware definition */
+
+# define FLASH_SECTOR_SIZE (4096)
+
+/* SPI flash command */
+
+# define FLASH_CMD_WRDI ROM_FLASH_CMD_WRDI
+# define FLASH_CMD_WREN ROM_FLASH_CMD_WREN
+# define FLASH_CMD_RDSR ROM_FLASH_CMD_RDSR
+# define FLASH_CMD_SE4B ROM_FLASH_CMD_SE4B
+# define FLASH_CMD_SE ROM_FLASH_CMD_ERASE_SEC
+# define FLASH_CMD_PP4B ROM_FLASH_CMD_PP4B
+# define FLASH_CMD_PP 0x02
+# define FLASH_CMD_FSTRD4B ROM_FLASH_CMD_FSTRD4B
+# define FLASH_CMD_FSTRD 0x0B
+
+/* SPI flash SR1 bits */
+
+# define FLASH_SR1_BUSY ESP_ROM_SPIFLASH_BUSY_FLAG
+# define FLASH_SR1_WREN ESP_ROM_SPIFLASH_WRENABLE_FLAG
+
+/* SPI flash operation */
+
+# ifdef CONFIG_ESP32S3S_SPI_FLASH_USE_32BIT_ADDRESS
+# define ADDR_BITS(addr) (((addr) & 0xff000000) ? 32 : 24)
+# define READ_CMD(addr) (ADDR_BITS(addr) == 32 ? FLASH_CMD_FSTRD4B
: \
+ FLASH_CMD_FSTRD)
+# define WRITE_CMD(addr) (ADDR_BITS(addr) == 32 ? FLASH_CMD_PP4B : \
+ FLASH_CMD_PP)
+# define ERASE_CMD(addr) (ADDR_BITS(addr) == 32 ? FLASH_CMD_SE4B : \
+ FLASH_CMD_SE)
+# define READ_DUMMY(addr) (8)
+# else
+# define ADDR_BITS(addr) 24
+# define READ_CMD(addr) FLASH_CMD_FSTRD
+# define WRITE_CMD(addr) FLASH_CMD_PP
+# define ERASE_CMD(addr) FLASH_CMD_SE
+# define READ_DUMMY(addr) (8)
+# endif
+
+# define SEND_CMD8_TO_FLASH(cmd) \
+ esp32s3_spi_trans((cmd), 8, \
+ 0, 0, \
+ NULL, 0, \
+ NULL, 0, \
+ 0, \
+ false)
+
+# define READ_SR1_FROM_FLASH(cmd, status) \
+ esp32s3_spi_trans((cmd), 8, \
+ 0, 0, \
+ NULL, 0, \
+ (status), 1, \
+ 0, \
+ false)
+
+# define ERASE_FLASH_SECTOR(addr) \
+ esp32s3_spi_trans(ERASE_CMD(addr), 8, \
+ (addr), ADDR_BITS(addr), \
+ NULL, 0, \
+ NULL, 0, \
+ 0, \
+ true)
+
+# define WRITE_DATA_TO_FLASH(addr, buffer, size) \
+ esp32s3_spi_trans(WRITE_CMD(addr), 8, \
+ (addr), ADDR_BITS(addr), \
+ buffer, size, \
+ NULL, 0, \
+ 0, \
+ true)
+
+# define READ_DATA_FROM_FLASH(addr, buffer, size) \
+ esp32s3_spi_trans(READ_CMD(addr), 8, \
+ (addr), ADDR_BITS(addr), \
+ NULL, 0, \
+ buffer, size, \
+ READ_DUMMY(addr), \
+ false)
+
+#endif /* CONFIG_ESP32S3_SPI_FLASH_DONT_USE_ROM_CODE */
+
/****************************************************************************
* Private Types
****************************************************************************/
@@ -100,24 +196,6 @@ struct spiflash_map_req_s
uint32_t page_cnt;
};
-/* Structure holding SPI flash access critical sections management
- * functions.
- */
-
-struct spiflash_guard_funcs_s
-{
- void (*start)(void); /* critical section start function */
- void (*end)(void); /* critical section end function */
- void (*op_lock)(void); /* flash access API lock function */
- void (*op_unlock)(void); /* flash access API unlock function */
-
- /* checks flash write addresses */
-
- bool (*address_is_safe)(size_t addr, size_t size);
-
- void (*yield)(void); /* yield to the OS during flash erase */
-};
-
struct spiflash_cachestate_s
{
uint32_t value;
@@ -139,7 +217,6 @@ static void spiflash_end(void);
* Public Functions Declaration
****************************************************************************/
-extern void spi_flash_guard_set(const struct spiflash_guard_funcs_s *funcs);
extern uint32_t cache_suspend_icache(void);
extern uint32_t cache_suspend_dcache(void);
extern void cache_resume_icache(uint32_t val);
@@ -150,7 +227,7 @@ extern int cache_invalidate_addr(uint32_t addr, uint32_t
size);
* Private Data
****************************************************************************/
-static struct spiflash_guard_funcs_s g_spi_flash_guard_funcs =
+static struct spiflash_guard_funcs g_spi_flash_guard_funcs =
{
.start = spiflash_start,
.end = spiflash_end,
@@ -216,6 +293,258 @@ static IRAM_ATTR void spiflash_end(void)
leave_critical_section(g_state.flags);
}
+/****************************************************************************
+ * Name: esp32s3_spi_trans
+ *
+ * Description:
+ * Transmit given command, address and data.
+ *
+ * Input Parameters:
+ * command - command value
+ * command_bits - command bits
+ * address - address value
+ * address_bits - address bits
+ * tx_buffer - write buffer
+ * tx_bytes - write buffer size
+ * rx_buffer - read buffer
+ * rx_bytes - read buffer size
+ * dummy_bits - dummy bits
+ * is_program - true if operation is program or erase
+ *
+ * Returned Value:
+ * 0 if success or a negative value if fail.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32S3_SPI_FLASH_DONT_USE_ROM_CODE
+static IRAM_ATTR void esp32s3_spi_trans(uint32_t command,
+ uint32_t command_bits,
+ uint32_t address,
+ uint32_t address_bits,
+ uint32_t *tx_buffer,
+ uint32_t tx_bytes,
+ uint32_t *rx_buffer,
+ uint32_t rx_bytes,
+ uint32_t dummy_bits,
+ bool is_program)
+{
+ uint32_t regval;
+ uint32_t cmd_reg;
+ uint32_t user1_reg = getreg32(SPI_MEM_USER1_REG(SPI_PORT));
+ uint32_t user_reg = getreg32(SPI_MEM_USER_REG(SPI_PORT));
+
+ /* Initiliaze SPI user register */
+
+ user_reg &= ~(SPI_MEM_USR_ADDR_M | SPI_MEM_USR_DUMMY_M |
+ SPI_MEM_USR_MOSI_M | SPI_MEM_USR_MISO_M);
+ user_reg |= SPI_MEM_USR_COMMAND_M;
+
+ /* Wait until SPI is idle */
+
+ do
+ {
+ cmd_reg = getreg32(SPI_MEM_CMD_REG(SPI_PORT));
+ }
+ while ((cmd_reg & SPI_MEM_USR_M) != 0);
+
+ /* Set command bits and value, and command is always needed */
+
+ regval = getreg32(SPI_MEM_USER2_REG(SPI_PORT));
+ regval &= ~(SPI_MEM_USR_COMMAND_BITLEN_M | SPI_MEM_USR_COMMAND_VALUE_M);
+ regval |= ((command_bits - 1) << SPI_MEM_USR_COMMAND_BITLEN_S) |
+ (command << SPI_MEM_USR_COMMAND_VALUE_S);
+ putreg32(regval, SPI_MEM_USER2_REG(SPI_PORT));
+
+ /* Set address bits and value */
+
+ if (address_bits)
+ {
+ user1_reg &= ~SPI_MEM_USR_ADDR_BITLEN_M;
+ user1_reg |= (address_bits - 1) << SPI_MEM_USR_ADDR_BITLEN_S;
+
+ putreg32(address, SPI_MEM_ADDR_REG(SPI_PORT));
+
+ user_reg |= SPI_MEM_USR_ADDR_M;
+
+ regval = getreg32(SPI_MEM_CACHE_FCTRL_REG(SPI_PORT));
+ if (address_bits > 24)
+ {
+ regval |= SPI_MEM_CACHE_USR_CMD_4BYTE_M;
+ }
+ else
+ {
+ regval &= ~SPI_MEM_CACHE_USR_CMD_4BYTE_M;
+ }
+
+ putreg32(regval, SPI_MEM_CACHE_FCTRL_REG(SPI_PORT));
+ }
+
+ /* Set dummy */
+
+ if (dummy_bits)
+ {
+ user1_reg &= ~SPI_MEM_USR_DUMMY_CYCLELEN_M;
+ user1_reg |= (dummy_bits - 1) << SPI_MEM_USR_DUMMY_CYCLELEN_S;
+
+ user_reg |= SPI_MEM_USR_DUMMY_M;
+ }
+
+ /* Set TX data */
+
+ if (tx_bytes)
+ {
+ putreg32(tx_bytes * 8 - 1, SPI_MEM_MOSI_DLEN_REG(SPI_PORT));
+ for (uint32_t i = 0; i < tx_bytes; i += 4)
+ {
+ putreg32(tx_buffer[i / 4], SPI_MEM_W0_REG(SPI_PORT) + i);
+ }
+
+ user_reg |= SPI_MEM_USR_MOSI_M;
+ }
+
+ /* Set RX data */
+
+ if (rx_bytes)
+ {
+ putreg32(rx_bytes * 8 - 1, SPI_MEM_MISO_DLEN_REG(SPI_PORT));
+
+ user_reg |= SPI_MEM_USR_MISO_M;
+ }
+
+ putreg32(user_reg, SPI_MEM_USER_REG(SPI_PORT));
+ putreg32(user1_reg, SPI_MEM_USER1_REG(SPI_PORT));
+
+ /* Set I/O mode */
+
+ regval = getreg32(SPI_MEM_CTRL_REG(SPI_PORT));
+ regval &= ~(SPI_MEM_FREAD_QIO_M | SPI_MEM_FREAD_DIO_M |
+ SPI_MEM_FREAD_QUAD_M | SPI_MEM_FREAD_DUAL_M |
+ SPI_MEM_FCMD_OCT_M | SPI_MEM_FCMD_QUAD_M |
+ SPI_MEM_FCMD_DUAL_M | SPI_MEM_FADDR_OCT_M |
+ SPI_MEM_FDIN_OCT_M | SPI_MEM_FDOUT_OCT_M |
+ SPI_MEM_FDUMMY_OUT_M | SPI_MEM_RESANDRES_M |
+ SPI_MEM_WP_REG_M | SPI_MEM_WRSR_2B_M);
+ regval |= SPI_MEM_FASTRD_MODE_M;
+ putreg32(regval, SPI_MEM_CTRL_REG(SPI_PORT));
+
+ /* Set clock and delay */
+
+ regval = SPI_MEM_FLASH_PES_WAIT_EN_M |
+ SPI_MEM_FLASH_PER_WAIT_EN_M;
+ putreg32(regval, SPI_MEM_FLASH_SUS_CMD_REG(SPI_PORT));
+ putreg32(0, SPI_MEM_CLOCK_GATE_REG(SPI_PORT));
+
+ /* Set if this is program or erase operation */
+
+ if (is_program)
+ {
+ cmd_reg |= SPI_MEM_FLASH_PE_M;
+ }
+
+ /* Start transmision */
+
+ cmd_reg |= SPI_MEM_USR_M;
+ putreg32(cmd_reg, SPI_MEM_CMD_REG(SPI_PORT));
+
+ /* Wait until transmission is done */
+
+ while ((getreg32(SPI_MEM_CMD_REG(SPI_PORT)) & SPI_MEM_USR_M) != 0)
+ {
+ ;
+ }
+
+ /* Get read data */
+
+ if (rx_bytes)
+ {
+ for (uint32_t i = 0; i < rx_bytes; i += 4)
+ {
+ rx_buffer[i / 4] = getreg32(SPI_MEM_W0_REG(SPI_PORT) + i);
+ }
+ }
+}
+
+/****************************************************************************
+ * Name: wait_flash_idle
+ *
+ * Description:
+ * Wait until flash enters idle state
+ *
+ * Returned Value:
+ * None.
+ *
+ ****************************************************************************/
+
+static IRAM_ATTR void wait_flash_idle(void)
+{
+ uint32_t status;
+
+ do
+ {
+ READ_SR1_FROM_FLASH(FLASH_CMD_RDSR, &status);
+ if ((status & FLASH_SR1_BUSY) == 0)
+ {
+ break;
+ }
+ }
+ while (1);
+}
+
+/****************************************************************************
+ * Name: enable_flash_write
+ *
+ * Description:
+ * Enable Flash write mode
+ *
+ * Returned Value:
+ * None.
+ *
+ ****************************************************************************/
+
+static IRAM_ATTR void enable_flash_write(void)
+{
+ uint32_t status;
+
+ do
+ {
+ SEND_CMD8_TO_FLASH(FLASH_CMD_WREN);
+ READ_SR1_FROM_FLASH(FLASH_CMD_RDSR, &status);
+ if ((status & FLASH_SR1_WREN) != 0)
+ {
+ break;
+ }
+ }
+ while (1);
+}
+
+/****************************************************************************
+ * Name: disable_flash_write
+ *
+ * Description:
+ * Disable Flash write mode
+ *
+ * Returned Value:
+ * None.
+ *
+ ****************************************************************************/
+
+static IRAM_ATTR void disable_flash_write(void)
+{
+ uint32_t status;
+
+ do
+ {
+ SEND_CMD8_TO_FLASH(FLASH_CMD_WRDI);
+ READ_SR1_FROM_FLASH(FLASH_CMD_RDSR, &status);
+ if ((status & FLASH_SR1_WREN) == 0)
+ {
+ break;
+ }
+ }
+ while (1);
+}
+#endif /* CONFIG_ESP32S3_SPI_FLASH_DONT_USE_ROM_CODE */
+
/****************************************************************************
* Name: esp32s3_mmap
*
@@ -357,6 +686,178 @@ int spi_flash_read_encrypted(uint32_t addr, void *buffer,
uint32_t size)
return OK;
}
+/****************************************************************************
+ * Name: spi_flash_erase_sector
+ *
+ * Description:
+ * Erase the Flash sector.
+ *
+ * Parameters:
+ * sector - Sector number, the count starts at sector 0, 4KB per sector.
+ *
+ * Returned Values: esp_err_t
+ * Zero (OK) is returned or a negative error.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32S3_SPI_FLASH_DONT_USE_ROM_CODE
+IRAM_ATTR int spi_flash_erase_sector(uint32_t sector)
+{
+ int ret = OK;
+ uint32_t addr = sector * FLASH_SECTOR_SIZE;
+
+ spiflash_start();
+
+ wait_flash_idle();
+ enable_flash_write();
+
+ ERASE_FLASH_SECTOR(addr);
+
+ wait_flash_idle();
+ disable_flash_write();
+
+ spiflash_end();
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: spi_flash_erase_range
+ *
+ * Description:
+ * Erase a range of flash sectors
+ *
+ * Parameters:
+ * start_address - Address where erase operation has to start.
+ * Must be 4kB-aligned
+ * size - Size of erased range, in bytes. Must be divisible by
+ * 4kB.
+ *
+ * Returned Values:
+ * Zero (OK) is returned or a negative error.
+ *
+ ****************************************************************************/
+
+IRAM_ATTR int spi_flash_erase_range(uint32_t start_address, uint32_t size)
+{
+ int ret = OK;
+ uint32_t addr = start_address;
+
+ spiflash_start();
+
+ for (uint32_t i = 0; i < size; i += FLASH_SECTOR_SIZE)
+ {
+ wait_flash_idle();
+ enable_flash_write();
+
+ ERASE_FLASH_SECTOR(addr);
+ addr += FLASH_SECTOR_SIZE;
+ }
+
+ wait_flash_idle();
+ disable_flash_write();
+
+ spiflash_end();
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: spi_flash_write
+ *
+ * Description:
+ * Write data to Flash.
+ *
+ * Parameters:
+ * dest_addr - Destination address in Flash.
+ * src - Pointer to the source buffer.
+ * size - Length of data, in bytes.
+ *
+ * Returned Values:
+ * Zero (OK) is returned or a negative error.
+ *
+ ****************************************************************************/
+
+IRAM_ATTR int spi_flash_write(uint32_t dest_addr,
+ const void *buffer,
+ uint32_t size)
+{
+ int ret = OK;
+ const uint8_t *tx_buf = (const uint8_t *)buffer;
+ uint32_t tx_bytes = size;
+ uint32_t tx_addr = dest_addr;
+
+ spiflash_start();
+
+ for (int i = 0; i < size; i += SPI_BUFFER_BYTES)
+ {
+ uint32_t spi_buffer[SPI_BUFFER_WORDS];
+ uint32_t n = MIN(tx_bytes, SPI_BUFFER_BYTES);
+
+ memcpy(spi_buffer, tx_buf, n);
+
+ wait_flash_idle();
+ enable_flash_write();
+
+ WRITE_DATA_TO_FLASH(tx_addr, spi_buffer, n);
+
+ tx_bytes -= n;
+ tx_buf += n;
+ tx_addr += n;
+ }
+
+ wait_flash_idle();
+ disable_flash_write();
+
+ spiflash_end();
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: spi_flash_read
+ *
+ * Description:
+ * Read data from Flash.
+ *
+ * Parameters:
+ * src_addr - source address of the data in Flash.
+ * dest - pointer to the destination buffer
+ * size - length of data
+ *
+ * Returned Values:
+ * Zero (OK) is returned or a negative error.
+ *
+ ****************************************************************************/
+
+IRAM_ATTR int spi_flash_read(uint32_t src_addr, void *dest, uint32_t size)
+{
+ int ret = OK;
+ uint8_t *rx_buf = (uint8_t *)dest;
+ uint32_t rx_bytes = size;
+ uint32_t rx_addr = src_addr;
+
+ spiflash_start();
+
+ for (uint32_t i = 0; i < size; i += SPI_BUFFER_BYTES)
+ {
+ uint32_t spi_buffer[SPI_BUFFER_WORDS];
+ uint32_t n = MIN(rx_bytes, SPI_BUFFER_BYTES);
+
+ READ_DATA_FROM_FLASH(rx_addr, spi_buffer, n);
+
+ memcpy(rx_buf, spi_buffer, n);
+ rx_bytes -= n;
+ rx_buf += n;
+ rx_addr += n;
+ }
+
+ spiflash_end();
+
+ return ret;
+}
+#endif /* CONFIG_ESP32S3_SPI_FLASH_DONT_USE_ROM_CODE */
+
/****************************************************************************
* Name: esp32s3_spiflash_init
*
diff --git a/arch/xtensa/src/esp32s3/hardware/esp32s3_soc.h
b/arch/xtensa/src/esp32s3/hardware/esp32s3_soc.h
index 053c5a589e..c85d315d50 100644
--- a/arch/xtensa/src/esp32s3/hardware/esp32s3_soc.h
+++ b/arch/xtensa/src/esp32s3/hardware/esp32s3_soc.h
@@ -36,6 +36,41 @@
* Pre-processor Definitions
****************************************************************************/
+/* Register Bits */
+
+#define BIT31 0x80000000
+#define BIT30 0x40000000
+#define BIT29 0x20000000
+#define BIT28 0x10000000
+#define BIT27 0x08000000
+#define BIT26 0x04000000
+#define BIT25 0x02000000
+#define BIT24 0x01000000
+#define BIT23 0x00800000
+#define BIT22 0x00400000
+#define BIT21 0x00200000
+#define BIT20 0x00100000
+#define BIT19 0x00080000
+#define BIT18 0x00040000
+#define BIT17 0x00020000
+#define BIT16 0x00010000
+#define BIT15 0x00008000
+#define BIT14 0x00004000
+#define BIT13 0x00002000
+#define BIT12 0x00001000
+#define BIT11 0x00000800
+#define BIT10 0x00000400
+#define BIT9 0x00000200
+#define BIT8 0x00000100
+#define BIT7 0x00000080
+#define BIT6 0x00000040
+#define BIT5 0x00000020
+#define BIT4 0x00000010
+#define BIT3 0x00000008
+#define BIT2 0x00000004
+#define BIT1 0x00000002
+#define BIT0 0x00000001
+
#define PRO_CPU_NUM (0)
#define APP_CPU_NUM (1)