xtensa/esp32s3: Support 32MB SPI flash

This commit is contained in:
Dong Heng 2023-05-24 10:27:09 +08:00 committed by Xiang Xiao
parent 69081a72d7
commit b24f931aca
3 changed files with 581 additions and 23 deletions

View File

@ -230,6 +230,11 @@ config ESP32S3_FLASH_16M
bool bool
default n default n
config ESP32S3_FLASH_32M
bool
default n
select ESP32S3S_SPI_FLASH_USE_32BIT_ADDRESS
config ESP32S3_ESPTOOLPY_NO_STUB config ESP32S3_ESPTOOLPY_NO_STUB
bool "Disable download stub" bool "Disable download stub"
default n default n
@ -1036,6 +1041,23 @@ choice ESP32S3_FLASH_SAMPLE_MODE
bool "STR Mode" bool "STR Mode"
endchoice 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 config ESP32S3_HAVE_OTA_PARTITION
bool bool
default n default n

View File

@ -29,16 +29,19 @@
#include <debug.h> #include <debug.h>
#include <string.h> #include <string.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/param.h>
#include <inttypes.h> #include <inttypes.h>
#include <errno.h> #include <errno.h>
#include <nuttx/arch.h> #include <nuttx/arch.h>
#include <nuttx/init.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_irq.h"
#include "esp32s3_spiflash.h" #include "esp32s3_spiflash.h"
/**************************************************************************** /****************************************************************************
@ -71,6 +74,99 @@
#define MMU_BYTES2PAGES(_n) (((_n) + SPI_FLASH_MMU_PAGE_SIZE - 1) / \ #define MMU_BYTES2PAGES(_n) (((_n) + SPI_FLASH_MMU_PAGE_SIZE - 1) / \
SPI_FLASH_MMU_PAGE_SIZE) 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 * Private Types
****************************************************************************/ ****************************************************************************/
@ -100,24 +196,6 @@ struct spiflash_map_req_s
uint32_t page_cnt; 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 struct spiflash_cachestate_s
{ {
uint32_t value; uint32_t value;
@ -139,7 +217,6 @@ static void spiflash_end(void);
* Public Functions Declaration * 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_icache(void);
extern uint32_t cache_suspend_dcache(void); extern uint32_t cache_suspend_dcache(void);
extern void cache_resume_icache(uint32_t val); 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 * 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, .start = spiflash_start,
.end = spiflash_end, .end = spiflash_end,
@ -216,6 +293,258 @@ static IRAM_ATTR void spiflash_end(void)
leave_critical_section(g_state.flags); 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 * Name: esp32s3_mmap
* *
@ -357,6 +686,178 @@ int spi_flash_read_encrypted(uint32_t addr, void *buffer, uint32_t size)
return OK; 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 * Name: esp32s3_spiflash_init
* *

View File

@ -36,6 +36,41 @@
* Pre-processor Definitions * 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 PRO_CPU_NUM (0)
#define APP_CPU_NUM (1) #define APP_CPU_NUM (1)