Merge branch 'feature/support_flash_sus_res_c3' into 'master'

spi_flash: Add flash auto-suspend auto-resume mode on esp32c3

Closes IDF-2591

See merge request espressif/esp-idf!11888
This commit is contained in:
Michael (XIAO Xufeng) 2021-01-25 17:41:32 +08:00
commit 7a20ea5f0e
37 changed files with 952 additions and 75 deletions

View File

@ -38,6 +38,7 @@
#define CMD_RDSR2 0x35 /* Not all SPI flash uses this command */
#define CMD_OTPEN 0x3A /* Enable OTP mode, not all SPI flash uses this command */
#define CMD_WRAP 0x77 /* Set burst with wrap command */
#define CMD_RESUME 0x7A /* Resume command to clear flash suspend bit */
/* Provide a Flash API for bootloader_support code,

View File

@ -193,6 +193,12 @@ static void IRAM_ATTR bootloader_init_flash_configure(void)
bootloader_flash_cs_timing_config();
}
static void bootloader_spi_flash_resume(void)
{
bootloader_execute_flash_command(CMD_RESUME, 0, 0, 0);
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
}
static esp_err_t bootloader_init_spi_flash(void)
{
bootloader_init_flash_configure();
@ -204,6 +210,7 @@ static esp_err_t bootloader_init_spi_flash(void)
}
#endif
bootloader_spi_flash_resume();
esp_rom_spiflash_unlock();
#if CONFIG_ESPTOOLPY_FLASHMODE_QIO || CONFIG_ESPTOOLPY_FLASHMODE_QOUT

View File

@ -105,6 +105,147 @@ static inline void spimem_flash_ll_erase_block(spi_mem_dev_t *dev)
dev->cmd.flash_be = 1;
}
/**
* Suspend erase/program operation.
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void spimem_flash_ll_suspend(spi_mem_dev_t *dev)
{
dev->flash_sus_ctrl.flash_pes = 1;
}
/**
* Resume suspended erase/program operation.
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void spimem_flash_ll_resume(spi_mem_dev_t *dev)
{
dev->flash_sus_ctrl.flash_per = 1;
}
/**
* Initialize auto suspend mode, and esp32c3 doesn't support disable auto-suspend.
*
* @param dev Beginning address of the peripheral registers.
* @param auto_sus Enable/disable Flash Auto-Suspend.
*/
static inline void spimem_flash_ll_auto_suspend_init(spi_mem_dev_t *dev, bool auto_sus)
{
dev->flash_sus_ctrl.flash_pes_en = auto_sus;
}
/**
* Initialize auto resume mode
*
* @param dev Beginning address of the peripheral registers.
* @param auto_res Enable/Disable Flash Auto-Resume.
*
*/
static inline void spimem_flash_ll_auto_resume_init(spi_mem_dev_t *dev, bool auto_res)
{
dev->flash_sus_ctrl.pes_per_en = auto_res;
}
/**
* Setup the flash suspend command, may vary from chips to chips.
*
* @param dev Beginning address of the peripheral registers.
* @param sus_cmd Flash suspend command.
*
*/
static inline void spimem_flash_ll_suspend_cmd_setup(spi_mem_dev_t *dev, uint32_t sus_cmd)
{
dev->flash_sus_cmd.flash_pes_command = sus_cmd;
}
/**
* Setup the flash resume command, may vary from chips to chips.
*
* @param dev Beginning address of the peripheral registers.
* @param res_cmd Flash resume command.
*
*/
static inline void spimem_flash_ll_resume_cmd_setup(spi_mem_dev_t *dev, uint32_t res_cmd)
{
dev->flash_sus_cmd.flash_per_command = res_cmd;
}
/**
* Setup the flash read suspend status command, may vary from chips to chips.
*
* @param dev Beginning address of the peripheral registers.
* @param pesr_cmd Flash read suspend status command.
*
*/
static inline void spimem_flash_ll_rd_sus_cmd_setup(spi_mem_dev_t *dev, uint32_t pesr_cmd)
{
dev->flash_sus_cmd.wait_pesr_command = pesr_cmd;
}
/**
* Setup to check SUS/SUS1/SUS2 to ensure the suspend status of flashs.
*
* @param dev Beginning address of the peripheral registers.
* @param sus_check_sus_en 1: enable, 0: disable.
*
*/
static inline void spimem_flash_ll_sus_check_sus_setup(spi_mem_dev_t *dev, bool sus_check_sus_en)
{
dev->flash_sus_ctrl.sus_timeout_cnt = 5;
dev->flash_sus_ctrl.pes_end_en = sus_check_sus_en;
}
/**
* Setup to check SUS/SUS1/SUS2 to ensure the resume status of flashs.
*
* @param dev Beginning address of the peripheral registers.
* @param sus_check_sus_en 1: enable, 0: disable.
*
*/
static inline void spimem_flash_ll_res_check_sus_setup(spi_mem_dev_t *dev, bool res_check_sus_en)
{
dev->flash_sus_ctrl.sus_timeout_cnt = 5;
dev->flash_sus_ctrl.per_end_en = res_check_sus_en;
}
/**
* Set 8 bit command to read suspend status
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void spimem_flash_ll_set_read_sus_status(spi_mem_dev_t *dev, uint32_t sus_conf)
{
dev->flash_sus_ctrl.frd_sus_2b = 0;
dev->flash_sus_ctrl.pesr_end_msk = sus_conf;
}
/**
* Initialize auto wait idle mode
*
* @param dev Beginning address of the peripheral registers.
* @param auto_waiti Enable/disable auto wait-idle function
*/
static inline void spimem_flash_ll_auto_wait_idle_init(spi_mem_dev_t *dev, bool auto_waiti)
{
dev->flash_waiti_ctrl.waiti_cmd = 0x05;
dev->flash_sus_ctrl.flash_per_wait_en = auto_waiti;
dev->flash_sus_ctrl.flash_pes_wait_en = auto_waiti;
}
/**
* Return the suspend status of erase or program operations.
*
* @param dev Beginning address of the peripheral registers.
*
* @return true if suspended, otherwise false.
*/
static inline bool spimem_flash_ll_sus_status(spi_mem_dev_t *dev)
{
return dev->sus_status.flash_sus;
}
/**
* Enable/disable write protection for the flash chip.
*

View File

@ -105,6 +105,143 @@ static inline void spimem_flash_ll_erase_block(spi_mem_dev_t *dev)
dev->cmd.flash_be = 1;
}
/**
* Suspend erase/program operation.
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void spimem_flash_ll_suspend(spi_mem_dev_t *dev)
{
dev->flash_sus_cmd.flash_pes = 1;
}
/**
* Resume suspended erase/program operation.
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void spimem_flash_ll_resume(spi_mem_dev_t *dev)
{
dev->flash_sus_cmd.flash_per = 1;
}
/**
* Initialize auto suspend mode
*
* @param dev Beginning address of the peripheral registers.
* @param auto_sus Enable/disable Flash Auto-Suspend.
*/
static inline void spimem_flash_ll_auto_suspend_init(spi_mem_dev_t *dev, bool auto_sus)
{
dev->flash_sus_ctrl.flash_pes_en = auto_sus;
}
/**
* Initialize auto resume mode
*
* @param dev Beginning address of the peripheral registers.
* @param auto_res Enable/Disable Flash Auto-Resume.
*
*/
static inline void spimem_flash_ll_auto_resume_init(spi_mem_dev_t *dev, bool auto_res)
{
dev->misc.auto_per = 0; // Must disable Hardware Auto-Resume (should not be enabled, ESP32-S2 has bugs).
}
/**
* Set 8 bit command to read suspend status
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void spimem_flash_ll_set_read_sus_status(spi_mem_dev_t *dev, uint32_t sus_mask)
{
abort();// Not supported on esp32s2
}
/**
* Setup the flash suspend command, may vary from chips to chips.
*
* @param dev Beginning address of the peripheral registers.
* @param sus_cmd Flash suspend command.
*
*/
static inline void spimem_flash_ll_suspend_cmd_setup(spi_mem_dev_t *dev, uint32_t sus_cmd)
{
dev->flash_sus_ctrl.flash_pes_command = sus_cmd;
}
/**
* Setup the flash resume command, may vary from chips to chips.
*
* @param dev Beginning address of the peripheral registers.
* @param res_cmd Flash resume command.
*
*/
static inline void spimem_flash_ll_resume_cmd_setup(spi_mem_dev_t *dev, uint32_t res_cmd)
{
dev->flash_sus_ctrl.flash_per_command = res_cmd;
}
/**
* Setup the flash read suspend status command, may vary from chips to chips.
*
* @param dev Beginning address of the peripheral registers.
* @param pesr_cmd Flash read suspend status command.
*
*/
static inline void spimem_flash_ll_rd_sus_cmd_setup(spi_mem_dev_t *dev, uint32_t pesr_cmd)
{
abort();// Not supported on esp32s2
}
/**
* Setup to check SUS/SUS1/SUS2 to ensure the suspend status of flashs.
*
* @param dev Beginning address of the peripheral registers.
* @param sus_check_sus_en 1: enable, 0: disable.
*
*/
static inline void spimem_flash_ll_sus_check_sus_setup(spi_mem_dev_t *dev, bool sus_check_sus_en)
{
abort();// Not supported on esp32s2
}
/**
* Setup to check SUS/SUS1/SUS2 to ensure the resume status of flashs.
*
* @param dev Beginning address of the peripheral registers.
* @param sus_check_sus_en 1: enable, 0: disable.
*
*/
static inline void spimem_flash_ll_res_check_sus_setup(spi_mem_dev_t *dev, bool res_check_sus_en)
{
abort();// Not supported on esp32s2
}
/**
* Initialize auto wait idle mode
*
* @param dev Beginning address of the peripheral registers.
* @param auto_waiti Enable/disable auto wait-idle function
*/
static inline void spimem_flash_ll_auto_wait_idle_init(spi_mem_dev_t *dev, bool auto_waiti)
{
dev->flash_waiti_ctrl.waiti_cmd = 0x05; // Set the command to send, to fetch flash status reg value.
dev->flash_waiti_ctrl.waiti_en = auto_waiti; // enable auto wait-idle function.
}
/**
* Return the suspend status of erase or program operations.
*
* @param dev Beginning address of the peripheral registers.
*
* @return true if suspended, otherwise false.
*/
static inline bool spimem_flash_ll_sus_status(spi_mem_dev_t *dev)
{
return dev->sus_status.flash_sus;
}
/**
* Enable/disable write protection for the flash chip.
*

View File

@ -105,6 +105,144 @@ static inline void spimem_flash_ll_erase_block(spi_mem_dev_t *dev)
dev->cmd.flash_be = 1;
}
/**
* Suspend erase/program operation.
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void spimem_flash_ll_suspend(spi_mem_dev_t *dev)
{
dev->flash_sus_cmd.flash_pes = 1;
}
/**
* Resume suspended erase/program operation.
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void spimem_flash_ll_resume(spi_mem_dev_t *dev)
{
dev->flash_sus_cmd.flash_per = 1;
}
/**
* Initialize auto wait idle mode
*
* @param dev Beginning address of the peripheral registers.
* @param auto_sus Enable/disable Flash Auto-Suspend.
*/
static inline void spimem_flash_ll_auto_suspend_init(spi_mem_dev_t *dev, bool auto_sus)
{
dev->user.usr_dummy_idle = 1;// MUST SET 1, to avoid missing Resume
dev->flash_sus_ctrl.flash_pes_en = auto_sus; // enable Flash Auto-Suspend.
}
/**
* Initialize auto resume mode
*
* @param dev Beginning address of the peripheral registers.
* @param auto_res Enable/Disable Flash Auto-Resume.
*
*/
static inline void spimem_flash_ll_auto_resume_init(spi_mem_dev_t *dev, bool auto_res)
{
dev->misc.auto_per = auto_res;
}
/**
* Setup the flash suspend command, may vary from chips to chips.
*
* @param dev Beginning address of the peripheral registers.
* @param sus_cmd Flash suspend command.
*
*/
static inline void spimem_flash_ll_suspend_cmd_setup(spi_mem_dev_t *dev, uint32_t sus_cmd)
{
dev->flash_sus_ctrl.flash_pes_command = sus_cmd;
}
/**
* Setup the flash resume command, may vary from chips to chips.
*
* @param dev Beginning address of the peripheral registers.
* @param res_cmd Flash resume command.
*
*/
static inline void spimem_flash_ll_resume_cmd_setup(spi_mem_dev_t *dev, uint32_t res_cmd)
{
dev->flash_sus_ctrl.flash_per_command = res_cmd;
}
/**
* Setup the flash read suspend status command, may vary from chips to chips.
*
* @param dev Beginning address of the peripheral registers.
* @param pesr_cmd Flash read suspend status command.
*
*/
static inline void spimem_flash_ll_rd_sus_cmd_setup(spi_mem_dev_t *dev, uint32_t pesr_cmd)
{
abort(); //Not support on esp32s3
}
/**
* Setup to check SUS/SUS1/SUS2 to ensure the suspend status of flashs.
*
* @param dev Beginning address of the peripheral registers.
* @param sus_check_sus_en 1: enable, 0: disable.
*
*/
static inline void spimem_flash_ll_sus_check_sus_setup(spi_mem_dev_t *dev, bool sus_check_sus_en)
{
abort(); //Not support on esp32s3
}
/**
* Setup to check SUS/SUS1/SUS2 to ensure the resume status of flashs.
*
* @param dev Beginning address of the peripheral registers.
* @param sus_check_sus_en 1: enable, 0: disable.
*
*/
static inline void spimem_flash_ll_res_check_sus_setup(spi_mem_dev_t *dev, bool res_check_sus_en)
{
abort(); //Not support ont esp32s3
}
/**
* Set 8 bit command to read suspend status
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void spimem_flash_ll_set_read_sus_status(spi_mem_dev_t *dev, uint32_t sus_mask)
{
abort();// Not supported on esp32s3
}
/**
* Initialize auto wait idle mode
*
* @param dev Beginning address of the peripheral registers.
* @param auto_waiti Enable/disable auto wait-idle function
*/
static inline void spimem_flash_ll_auto_wait_idle_init(spi_mem_dev_t *dev, bool auto_waiti)
{
dev->flash_waiti_ctrl.waiti_cmd = 0x05; // Set the command to send, to fetch flash status reg value.
dev->flash_waiti_ctrl.waiti_en = auto_waiti; // enable auto wait-idle function.
}
/**
* Return the suspend status of erase or program operations.
*
* @param dev Beginning address of the peripheral registers.
*
* @return true if suspended, otherwise false.
*/
static inline bool spimem_flash_ll_sus_status(spi_mem_dev_t *dev)
{
return dev->sus_status.flash_sus;
}
/**
* Enable/disable write protection for the flash chip.
*

View File

@ -48,18 +48,22 @@ typedef struct {
};
spi_flash_ll_clock_reg_t clock_conf; ///< Pre-calculated clock configuration value
esp_flash_io_mode_t base_io_mode; ///< Default IO mode mask for common commands
uint32_t reserved_config[1]; ///< The ROM has reserved some memory for configurations with one set of driver code. (e.g. QPI mode, 64-bit address mode, etc.)
uint32_t flags; ///< Flags for configurations with one set of driver code. (e.g. QPI mode, auto-suspend mode, 64-bit address mode, etc.)
#define SPI_FLASH_HOST_CONTEXT_FLAG_AUTO_SUSPEND BIT(0) ///< When the auto-suspend is setup in configuration.
#define SPI_FLASH_HOST_CONTEXT_FLAG_AUTO_RESUME BIT(1) ///< Setup auto-resume feature.
spi_flash_sus_cmd_conf sus_cfg; ///< To store suspend command/mask information.
} spi_flash_hal_context_t;
_Static_assert(sizeof(spi_flash_hal_context_t) == 28, "size of spi_flash_hal_context_t incorrect. Please check data compatibility with the ROM");
_Static_assert(sizeof(spi_flash_hal_context_t) == 36, "size of spi_flash_hal_context_t incorrect. Please check data compatibility with the ROM");
/// Configuration structure for the SPI driver.
typedef struct {
spi_host_device_t host_id; ///< SPI peripheral ID.
int cs_num; ///< Which cs pin is used, 0-(SOC_SPI_PERIPH_CS_NUM-1).
bool iomux; ///< Whether the IOMUX is used, used for timing compensation.
int input_delay_ns; ///< Input delay on the MISO pin after the launch clock used for timing compensation.
int input_delay_ns; ///< Input delay on the MISO pin after the launch clock, used for timing compensation.
esp_flash_speed_t speed;///< SPI flash clock speed to work at.
uint32_t cs_hold; ///< CS hold time config used by the host
bool auto_sus_en; ///< Auto suspend feature enable bit 1: enable, 0: disable.
} spi_flash_hal_config_t;
/**
@ -160,9 +164,9 @@ esp_err_t spi_flash_hal_set_write_protect(spi_flash_host_inst_t *host, bool wp);
*
* @param host The driver context.
*
* @return ture if idle, otherwise false.
* @return 0:busy, 1:idle, 2:suspended.
*/
bool spi_flash_hal_host_idle(spi_flash_host_inst_t *host);
uint32_t spi_flash_hal_check_status(spi_flash_host_inst_t *host);
/**
* @brief Configure the SPI host hardware registers for the specified io mode.
@ -226,3 +230,29 @@ bool spi_flash_hal_supports_direct_write(spi_flash_host_inst_t *host, const void
* @return True if the buffer can be used to receive data, otherwise false.
*/
bool spi_flash_hal_supports_direct_read(spi_flash_host_inst_t *host, const void *p);
/**
* @brief Resume flash chip status from suspend.
*
* @param host The driver context.
*
*/
void spi_flash_hal_resume(spi_flash_host_inst_t *host);
/**
* @brief Set the flash into suspend status manually.
*
* @param host The driver context.
*
*/
void spi_flash_hal_suspend(spi_flash_host_inst_t *host);
/**
* To setup for reading flash suspend status register
*
* @param host The driver context.
* @param sus_conf Flash chip suspend feature configuration, mainly for command config, may vary from chip to chip.
*
* @return Always ESP_OK
*/
esp_err_t spi_flash_hal_setup_read_suspend(spi_flash_host_inst_t *host, const spi_flash_sus_cmd_conf *sus_conf);

View File

@ -75,6 +75,17 @@ typedef enum {
SPI_FLASH_READ_MODE_MAX, ///< The fastest io mode supported by the host is ``ESP_FLASH_READ_MODE_MAX-1``.
} esp_flash_io_mode_t;
/// Configuration structure for the flash chip suspend feature.
typedef struct {
uint32_t sus_mask; ///< SUS/SUS1/SUS2 bit in flash register.
struct {
uint32_t cmd_rdsr :8; ///< Read flash status register(2) command.
uint32_t sus_cmd :8; ///< Flash suspend command.
uint32_t res_cmd :8; ///< Flash resume command.
uint32_t reserved :8; ///< Reserved, set to 0.
};
} spi_flash_sus_cmd_conf;
///Slowest io mode supported by ESP32, currently SlowRd
#define SPI_FLASH_READ_MODE_MIN SPI_FLASH_SLOWRD
@ -159,9 +170,9 @@ struct spi_flash_host_driver_s {
*/
int (*read_data_slicer)(spi_flash_host_inst_t *host, uint32_t address, uint32_t len, uint32_t *align_addr, uint32_t page_size);
/**
* Check whether the host is idle to perform new operations.
* Check the host status, 0:busy, 1:idle, 2:suspended.
*/
bool (*host_idle)(spi_flash_host_inst_t *host);
uint32_t (*host_status)(spi_flash_host_inst_t *host);
/**
* Configure the host to work at different read mode. Responsible to compensate the timing and set IO mode.
*/
@ -177,6 +188,21 @@ struct spi_flash_host_driver_s {
* modified, the cache needs to be flushed. Left NULL if not supported.
*/
esp_err_t (*flush_cache)(spi_flash_host_inst_t* host, uint32_t addr, uint32_t size);
/**
* Resume flash from suspend manually
*/
void (*resume)(spi_flash_host_inst_t *host);
/**
* Set flash in suspend status manually
*/
void (*suspend)(spi_flash_host_inst_t *host);
/**
* Suspend feature setup for setting cmd and status register mask.
*/
esp_err_t (*sus_setup)(spi_flash_host_inst_t *host, const spi_flash_sus_cmd_conf *sus_conf);
};
#ifdef __cplusplus

View File

@ -91,6 +91,10 @@ esp_err_t spi_flash_hal_init(spi_flash_hal_context_t *data_out, const spi_flash_
.clock_conf = clock_cfg->clock_reg_val,
.cs_hold = cfg->cs_hold,
};
if (cfg->auto_sus_en) {
data_out->flags |= SPI_FLASH_HOST_CONTEXT_FLAG_AUTO_SUSPEND;
data_out->flags |= SPI_FLASH_HOST_CONTEXT_FLAG_AUTO_RESUME;
}
ESP_EARLY_LOGD(TAG, "extra_dummy: %d", data_out->extra_dummy);
return ESP_OK;

View File

@ -50,6 +50,20 @@ esp_err_t spi_flash_hal_device_config(spi_flash_host_inst_t *host)
spi_flash_ll_set_clock(dev, &ctx->clock_conf);
int cs_hold = ctx->cs_hold;
spi_flash_ll_set_hold(dev, cs_hold);
#ifndef GPSPI_BUILD
#if SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND
if ((ctx->flags & SPI_FLASH_HOST_CONTEXT_FLAG_AUTO_SUSPEND) != 0) {
spi_flash_hal_setup_auto_suspend_mode(host);
} else {
spi_flash_hal_disable_auto_suspend_mode(host);
}
if ((ctx->flags & SPI_FLASH_HOST_CONTEXT_FLAG_AUTO_RESUME) != 0) {
spi_flash_hal_setup_auto_resume_mode(host);
} else {
spi_flash_hal_disable_auto_resume_mode(host);
}
#endif //SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND
#endif //GPSPI_BUILD
return ESP_OK;
}
@ -78,7 +92,7 @@ esp_err_t spi_flash_hal_configure_host_io_mode(
return ESP_ERR_NOT_SUPPORTED;
}
#if CONFIG_SPI_FLASH_ROM_IMPL
#if CONFIG_SPI_FLASH_ROM_IMPL && CONFIG_IDF_TARGET_ESP32S3
/*
* In S3 ROM, extra bits than 24-bit are used to indicate requirements of M7-M0:
* - 24: normal transactions

View File

@ -36,7 +36,7 @@ bool spi_flash_hal_gpspi_supports_direct_read(spi_flash_host_inst_t *host, const
return true;
}
bool spi_flash_hal_gpspi_host_idle(spi_flash_host_inst_t *host)
uint32_t spi_flash_hal_gpspi_check_status(spi_flash_host_inst_t *host)
{
spi_dev_t *dev = get_spi_dev(host);
return spi_flash_ll_host_idle(dev);

View File

@ -13,30 +13,33 @@
// limitations under the License.
#include "sdkconfig.h"
#include "hal/spi_flash_hal.h"
#if SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND
void spi_flash_hal_setup_auto_suspend_mode(spi_flash_host_inst_t *host);
void spi_flash_hal_disable_auto_resume_mode(spi_flash_host_inst_t *host);
void spi_flash_hal_disable_auto_suspend_mode(spi_flash_host_inst_t *host);
void spi_flash_hal_setup_auto_resume_mode(spi_flash_host_inst_t *host);
#endif //SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND
#include "spi_flash_hal_common.inc"
#ifndef CONFIG_SPI_FLASH_ROM_IMPL
// HAL for
// - MEMSPI
// - SPI1~3 on ESP32
// - SPI1~3 on ESP32/S2/S3/C3
// The common part is in spi_flash_hal_common.inc
// HAL for
// - MEMSPI
// - SPI1~3 on ESP32
// The common part is in spi_flash_hal_common.inc
// HAL for
// - MEMSPI
// - SPI1~3 on ESP32
// The common part is in spi_flash_hal_common.inc
#include "spi_flash_hal_common.inc"
void spi_flash_hal_erase_chip(spi_flash_host_inst_t *host)
{
spi_dev_t *dev = get_spi_dev(host);
spi_flash_ll_erase_chip(dev);
#if SOC_SPI_MEM_SUPPORT_AUTO_WAIT_IDLE
if((((spi_flash_hal_context_t*)host)->flags & SPI_FLASH_HOST_CONTEXT_FLAG_AUTO_SUSPEND) == 0) {
host->driver->poll_cmd_done(host);
}
#else
host->driver->poll_cmd_done(host);
#endif
}
// Only support 24bit address
@ -46,7 +49,14 @@ void spi_flash_hal_erase_sector(spi_flash_host_inst_t *host, uint32_t start_addr
spi_flash_ll_set_addr_bitlen(dev, 24);
spi_flash_ll_set_address(dev, start_address & ADDRESS_MASK_24BIT);
spi_flash_ll_erase_sector(dev);
#if SOC_SPI_MEM_SUPPORT_AUTO_WAIT_IDLE
if((((spi_flash_hal_context_t*)host)->flags & SPI_FLASH_HOST_CONTEXT_FLAG_AUTO_SUSPEND) == 0) {
host->driver->poll_cmd_done(host);
}
#else
host->driver->poll_cmd_done(host);
#endif
}
// Only support 24bit address
@ -56,7 +66,13 @@ void spi_flash_hal_erase_block(spi_flash_host_inst_t *host, uint32_t start_addre
spi_flash_ll_set_addr_bitlen(dev, 24);
spi_flash_ll_set_address(dev, start_address & ADDRESS_MASK_24BIT);
spi_flash_ll_erase_block(dev);
#if SOC_SPI_MEM_SUPPORT_AUTO_WAIT_IDLE
if((((spi_flash_hal_context_t*)host)->flags & SPI_FLASH_HOST_CONTEXT_FLAG_AUTO_SUSPEND) == 0) {
host->driver->poll_cmd_done(host);
}
#else
host->driver->poll_cmd_done(host);
#endif
}
// Only support 24bit address
@ -77,22 +93,97 @@ esp_err_t spi_flash_hal_set_write_protect(spi_flash_host_inst_t *host, bool wp)
return ESP_OK;
}
bool spi_flash_hal_host_idle(spi_flash_host_inst_t *host)
#endif // !CONFIG_SPI_FLASH_ROM_IMPL
uint32_t spi_flash_hal_check_status(spi_flash_host_inst_t *host)
{
spi_dev_t *dev = get_spi_dev(host);
bool idle = spi_flash_ll_host_idle(dev);
uint32_t status = spi_flash_ll_host_idle(dev);
#if SOC_SPI_MEM_SUPPORT_AUTO_WAIT_IDLE
uint32_t sus_status = spimem_flash_ll_sus_status((spi_mem_dev_t*)dev) << 1;
#else
uint32_t sus_status = 0;
#endif
// Not clear if this is necessary, or only necessary if
// chip->spi == SPI1. But probably doesn't hurt...
if ((void*) dev == spi_flash_ll_get_hw(SPI_HOST)) {
#if CONFIG_IDF_TARGET_ESP32
idle &= spi_flash_ll_host_idle(&SPI0);
#else
idle &= spi_flash_ll_host_idle(&SPIMEM0);
status &= spi_flash_ll_host_idle(&SPI0);
#endif
}
return idle;
//status and sus_status should be mutual exclusion
return (status | sus_status);
}
#endif // !CONFIG_SPI_FLASH_ROM_IMPL
esp_err_t spi_flash_hal_setup_read_suspend(spi_flash_host_inst_t *host, const spi_flash_sus_cmd_conf *sus_conf)
{
#if SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND
spi_mem_dev_t *dev = (spi_mem_dev_t *)spi_flash_ll_get_hw(SPI_HOST);
spi_flash_hal_context_t* ctx = (spi_flash_hal_context_t*)host;
memcpy(&(ctx->sus_cfg), sus_conf, sizeof(spi_flash_sus_cmd_conf));
spimem_flash_ll_set_read_sus_status(dev, sus_conf->sus_mask);
spimem_flash_ll_suspend_cmd_setup(dev, sus_conf->sus_cmd);
spimem_flash_ll_resume_cmd_setup(dev, sus_conf->res_cmd);
spimem_flash_ll_rd_sus_cmd_setup(dev, sus_conf->cmd_rdsr);
#endif // SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND
return ESP_OK;
}
#if SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND
void spi_flash_hal_setup_auto_suspend_mode(spi_flash_host_inst_t *host)
{
spi_mem_dev_t *dev = (spi_mem_dev_t*)spi_flash_ll_get_hw(SPI_HOST);
spimem_flash_ll_auto_wait_idle_init(dev, true);
spimem_flash_ll_auto_suspend_init(dev, true);
#if SOC_SPI_MEM_SUPPORT_CHECK_SUS
spimem_flash_ll_sus_check_sus_setup(dev, true);
#endif
}
void spi_flash_hal_setup_auto_resume_mode(spi_flash_host_inst_t *host)
{
spi_mem_dev_t *dev = (spi_mem_dev_t*)spi_flash_ll_get_hw(SPI_HOST);
spimem_flash_ll_auto_resume_init(dev, true);
#if SOC_SPI_MEM_SUPPORT_CHECK_SUS
spimem_flash_ll_res_check_sus_setup(dev, true);
#endif
}
void spi_flash_hal_disable_auto_suspend_mode(spi_flash_host_inst_t *host)
{
spi_mem_dev_t *dev = (spi_mem_dev_t *)spi_flash_ll_get_hw(SPI_HOST);
spimem_flash_ll_auto_wait_idle_init(dev, false);
spimem_flash_ll_auto_suspend_init(dev, false);
#if SOC_SPI_MEM_SUPPORT_CHECK_SUS
spimem_flash_ll_sus_check_sus_setup(dev, false);
#endif
}
void spi_flash_hal_disable_auto_resume_mode(spi_flash_host_inst_t *host)
{
spi_mem_dev_t *dev = (spi_mem_dev_t*)spi_flash_ll_get_hw(SPI_HOST);
spimem_flash_ll_auto_resume_init(dev, false);
#if SOC_SPI_MEM_SUPPORT_CHECK_SUS
spimem_flash_ll_res_check_sus_setup(dev, false);
#endif
}
#endif // SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND
void spi_flash_hal_resume(spi_flash_host_inst_t *host)
{
#if SOC_SPI_MEM_SUPPORT_SW_SUSPEND
spimem_flash_ll_resume((spi_mem_dev_t*)(((spi_flash_hal_context_t *)host)->spi));
#else
abort();
#endif
}
void spi_flash_hal_suspend(spi_flash_host_inst_t *host)
{
#if SOC_SPI_MEM_SUPPORT_SW_SUSPEND
spimem_flash_ll_suspend((spi_mem_dev_t *)(((spi_flash_hal_context_t *)host)->spi));
#else
abort();
#endif
}

View File

@ -123,6 +123,13 @@
/*-------------------------- COEXISTENCE HARDWARE PTI CAPS -------------------------------*/
#define SOC_COEX_HW_PTI (1)
/*-------------------------- SPI MEM CAPS ---------------------------------------*/
#define SOC_SPI_MEM_SUPPORT_AUTO_WAIT_IDLE (1)
#define SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND (1)
#define SOC_SPI_MEM_SUPPORT_AUTO_RESUME (1)
#define SOC_SPI_MEM_SUPPORT_IDLE_INTR (1)
#define SOC_SPI_MEM_SUPPORT_SW_SUSPEND (1)
#define SOC_SPI_MEM_SUPPORT_CHECK_SUS (1)
/*-------------------------- Power Management CAPS ----------------------------*/
#define SOC_PM_SUPPORT_WIFI_WAKEUP (1)

View File

@ -297,6 +297,10 @@
/*-------------------------- WI-FI HARDWARE TSF CAPS -------------------------------*/
#define SOC_WIFI_HW_TSF (1)
/*-------------------------- SPI MEM CAPS ---------------------------------------*/
#define SOC_SPI_MEM_SUPPORT_AUTO_WAIT_IDLE (1)
#define SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND (1)
#define SOC_SPI_MEM_SUPPORT_SW_SUSPEND (1)
/*-------------------------- Power Management CAPS ---------------------------*/
#define SOC_PM_SUPPORT_EXT_WAKEUP (1)

View File

@ -266,7 +266,7 @@ typedef volatile struct spi_mem_dev_s {
};
uint32_t val;
} fsm;
uint32_t data_buf[18]; /*data buffer*/
uint32_t data_buf[16]; /*data buffer*/
union {
struct {
uint32_t waiti_en: 1; /*auto-waiting flash idle operation when program flash or erase flash. 1: enable 0: disable.*/
@ -699,6 +699,7 @@ typedef volatile struct spi_mem_dev_s {
uint32_t val;
} date;
} spi_mem_dev_t;
_Static_assert(sizeof(spi_mem_dev_t) == 0x400, "invalid spi_mem_dev_t size");
extern spi_mem_dev_t SPIMEM0;
extern spi_mem_dev_t SPIMEM1;
#ifdef __cplusplus

View File

@ -167,5 +167,11 @@
/*-------------------------- WI-FI HARDWARE TSF CAPS -------------------------------*/
#define SOC_WIFI_HW_TSF (1)
/*-------------------------- SPI MEM CAPS ---------------------------------------*/
#define SOC_SPI_MEM_SUPPORT_AUTO_WAIT_IDLE (1)
#define SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND (1)
#define SOC_SPI_MEM_SUPPORT_AUTO_RESUME (1)
#define SOC_SPI_MEM_SUPPORT_SW_SUSPEND (1)
/*-------------------------- COEXISTENCE HARDWARE PTI CAPS -------------------------------*/
#define SOC_COEX_HW_PTI (1)

View File

@ -85,6 +85,7 @@ else()
"spi_flash_chip_mxic.c"
"spi_flash_chip_gd.c"
"spi_flash_chip_winbond.c"
"spi_flash_chip_boya.c"
"memspi_host_driver.c")
list(APPEND cache_srcs

View File

@ -137,12 +137,23 @@ menu "SPI Flash driver"
then it will yield CPUs after finishing a current command.
config SPI_FLASH_ERASE_YIELD_TICKS
int "CPU release time (tick)"
int "CPU release time (tick) for an erase operation"
depends on SPI_FLASH_YIELD_DURING_ERASE
default 1
help
Defines how many ticks will be before returning to continue a erasing.
config SPI_FLASH_AUTO_SUSPEND
bool "Auto suspend long erase/write operations"
default n
depends on IDF_TARGET_ESP32C3 && !SPI_FLASH_USE_LEGACY_IMPL && !SPI_FLASH_ROM_IMPL
help
This is made default n, because this needs bootloader support.
This feature needs special bootloader support.
If you want to OTA to a image with this feature
(e.g. turn on this config option for OTA image), please make
sure the bootloader has the support for it. (above IDF v4.3)
config SPI_FLASH_WRITE_CHUNK_SIZE
int "Flash write chunk size"
default 8192
@ -208,6 +219,15 @@ menu "SPI Flash driver"
given by ``chip_drv`` member of the chip struct. This adds support for variant
chips, however will extend detecting time.
config SPI_FLASH_SUPPORT_BOYA_CHIP
bool "BOYA"
depends on !IDF_TARGET_ESP32
default y
help
Enable this to support auto detection of BOYA chips if chip vendor not directly
given by ``chip_drv`` member of the chip struct. This adds support for variant
chips, however will extend detecting time.
endmenu #auto detect flash chips
endmenu

View File

@ -22,6 +22,7 @@
#include "esp_log.h"
#include "sdkconfig.h"
#include "esp_flash_internal.h"
#include "spi_flash_defs.h"
static const char TAG[] = "spi_flash";
@ -832,6 +833,12 @@ IRAM_ATTR esp_err_t esp_flash_set_io_mode(esp_flash_t* chip, bool qe)
}
#endif //CONFIG_SPI_FLASH_ROM_IMPL
//init suspend mode cmd, uses internal.
esp_err_t esp_flash_suspend_cmd_init(esp_flash_t* chip)
{
return chip->chip_drv->sus_setup(chip);
}
#ifndef CONFIG_SPI_FLASH_USE_LEGACY_IMPL
esp_err_t esp_flash_app_disable_protect(bool disable)
{

View File

@ -23,6 +23,7 @@
#include "esp_heap_caps.h"
#include "hal/spi_types.h"
#include "driver/spi_common_internal.h"
#include "hal/spi_flash_hal.h"
#include "esp_flash_internal.h"
#include "esp_rom_gpio.h"
#if CONFIG_IDF_TARGET_ESP32
@ -89,6 +90,7 @@ __attribute__((unused)) static const char TAG[] = "spi_flash";
}
#elif CONFIG_IDF_TARGET_ESP32C3
#include "esp32c3/rom/efuse.h"
#if !CONFIG_SPI_FLASH_AUTO_SUSPEND
#define ESP_FLASH_HOST_CONFIG_DEFAULT() (memspi_host_config_t){ \
.host_id = SPI_HOST,\
.speed = DEFAULT_FLASH_SPEED, \
@ -96,6 +98,16 @@ __attribute__((unused)) static const char TAG[] = "spi_flash";
.iomux = true, \
.input_delay_ns = 0,\
}
#else
#define ESP_FLASH_HOST_CONFIG_DEFAULT() (memspi_host_config_t){ \
.host_id = SPI_HOST,\
.speed = DEFAULT_FLASH_SPEED, \
.cs_num = 0, \
.iomux = true, \
.input_delay_ns = 0,\
.auto_sus_en = true,\
}
#endif //!CONFIG_SPI_FLASH_AUTO_SUSPEND
#endif
@ -239,6 +251,7 @@ static DRAM_ATTR esp_flash_t default_chip = {
.os_func = &esp_flash_noos_functions,
};
extern esp_err_t esp_flash_suspend_cmd_init(esp_flash_t* chip);
esp_err_t esp_flash_init_default_chip(void)
{
const esp_rom_spiflash_chip_t *legacy_chip = &g_rom_flashchip;
@ -272,6 +285,12 @@ esp_err_t esp_flash_init_default_chip(void)
default_chip.size = legacy_chip->chip_size;
esp_flash_default_chip = &default_chip;
#ifdef CONFIG_SPI_FLASH_AUTO_SUSPEND
err = esp_flash_suspend_cmd_init(&default_chip);
if (err != ESP_OK) {
return err;
}
#endif
return ESP_OK;
}

View File

@ -31,10 +31,13 @@
.write_data_slicer = memspi_host_write_data_slicer, \
.read = spi_flash_hal_read, \
.read_data_slicer = memspi_host_read_data_slicer, \
.host_idle = spi_flash_hal_host_idle, \
.host_status = spi_flash_hal_check_status, \
.configure_host_io_mode = spi_flash_hal_configure_host_io_mode, \
.poll_cmd_done = spi_flash_hal_poll_cmd_done, \
.flush_cache = memspi_host_flush_cache, \
.resume = spi_flash_hal_resume, \
.suspend = spi_flash_hal_suspend,\
.sus_setup = spi_flash_hal_setup_read_suspend,\
}
/// configuration for the memspi host

View File

@ -0,0 +1,21 @@
// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD
//
// Licensed 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.
#pragma once
#include <stdint.h>
#include "esp_flash.h"
#include "spi_flash_chip_driver.h"
extern const spi_flash_chip_t esp_flash_chip_boya;

View File

@ -186,6 +186,8 @@ struct spi_flash_chip_t {
/** Yield to other tasks. Called during erase operations. */
esp_err_t (*yield)(esp_flash_t *chip, uint32_t wip);
/** Setup flash suspend configuration. */
esp_err_t (*sus_setup)(esp_flash_t *chip);
};
/* Pointer to an array of pointers to all known drivers for flash chips. This array is used

View File

@ -255,24 +255,6 @@ extern const spi_flash_chip_t esp_flash_chip_generic;
* Utilities
*******************************************************************************/
/**
* @brief Wait for the SPI host hardware state machine to be idle.
*
* This isn't a flash chip_drv operation, but it's called by
* spi_flash_chip_generic_wait_idle() and may be useful when implementing
* alternative drivers.
*
* timeout_us will be decremented if the function needs to wait until the host hardware is idle.
*
* @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted.
*
* @return
* - ESP_OK if success
* - ESP_ERR_TIMEOUT if not idle before timeout
* - or other error passed from the ``set_write_protect`` or ``common_command`` function of host driver
*/
esp_err_t spi_flash_generic_wait_host_idle(esp_flash_t *chip, uint32_t *timeout_us);
/// Function pointer type for reading status register with QE bit.
typedef esp_err_t (*esp_flash_rdsr_func_t)(esp_flash_t* chip, uint32_t* out_sr);
@ -394,5 +376,13 @@ esp_err_t spi_flash_chip_generic_config_host_io_mode(esp_flash_t *chip, bool add
*/
esp_err_t spi_flash_chip_generic_yield(esp_flash_t* chip, uint32_t wip);
/**
* @brief Setup for flash suspend command configuration.
*
* @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted.
* @return ESP_OK
*/
esp_err_t spi_flash_chip_generic_suspend_cmd_conf(esp_flash_t *chip);
/// Default timeout configuration used by most chips
const flash_chip_op_timeout_t spi_flash_chip_generic_timeout;

View File

@ -8,3 +8,6 @@ entries:
spi_flash_chip_gd (noflash)
spi_flash_chip_winbond (noflash)
memspi_host_driver (noflash)
if IDF_TARGET_ESP32 = n:
spi_flash_chip_boya (noflash)

View File

@ -37,7 +37,7 @@ esp_err_t spi_flash_hal_gpspi_configure_host_io_mode(
esp_flash_io_mode_t io_mode);
extern esp_err_t spi_flash_hal_gpspi_common_command(spi_flash_host_inst_t *host, spi_flash_trans_t *trans);
extern esp_err_t spi_flash_hal_gpspi_read(spi_flash_host_inst_t *host, void *buffer, uint32_t address, uint32_t read_len);
extern bool spi_flash_hal_gpspi_host_idle(spi_flash_host_inst_t *host);
extern uint32_t spi_flash_hal_gpspi_check_status(spi_flash_host_inst_t *host);
extern bool spi_flash_hal_gpspi_supports_direct_write(spi_flash_host_inst_t *host, const void *p);
extern bool spi_flash_hal_gpspi_supports_direct_read(spi_flash_host_inst_t *host, const void *p);
@ -57,10 +57,12 @@ static const spi_flash_host_driver_t esp_flash_gpspi_host = {
.write_data_slicer = memspi_host_write_data_slicer,
.read = spi_flash_hal_gpspi_read,
.read_data_slicer = memspi_host_read_data_slicer,
.host_idle = spi_flash_hal_gpspi_host_idle,
.host_status = spi_flash_hal_gpspi_check_status,
.configure_host_io_mode = spi_flash_hal_gpspi_configure_host_io_mode,
.poll_cmd_done = spi_flash_hal_gpspi_poll_cmd_done,
.flush_cache = NULL,
.resume = spi_flash_hal_resume,
.suspend = spi_flash_hal_suspend,
};
#endif

View File

@ -26,6 +26,8 @@
#define CMD_WRDI 0x04
#define CMD_RDSR 0x05
#define CMD_RDSR2 0x35 /* Not all SPI flash uses this command */
#define CMD_RDSCUR 0x2B /* on specific(MXIC) board, read security register */
#define CMD_RDFR 0x48 /* on specific(ISSI) board, read function register */
#define CMD_FASTRD_QIO 0xEB
#define CMD_FASTRD_QIO_4B 0xEC
@ -47,6 +49,8 @@
#define CMD_LARGE_BLOCK_ERASE_4B 0xDC /* 64KB block erase command */
#define CMD_PROGRAM_PAGE 0x02
#define CMD_PROGRAM_PAGE_4B 0x12
#define CMD_SUSPEND 0x75
#define CMD_RESUME 0x7A
#define CMD_RST_EN 0x66
#define CMD_RST_DEV 0x99

View File

@ -121,9 +121,9 @@ struct spi_flash_host_driver_s {
*/
int (*read_data_slicer)(spi_flash_host_inst_t *host, uint32_t address, uint32_t len, uint32_t *align_addr, uint32_t page_size);
/**
* Check whether the host is idle to perform new operations.
* Check the host status, 0:busy, 1:idle, 2:suspended.
*/
bool (*host_idle)(spi_flash_host_inst_t *host);
uint32_t (*host_status)(spi_flash_host_inst_t *host);
/**
* Configure the host to work at different read mode. Responsible to compensate the timing and set IO mode.
*/
@ -139,6 +139,21 @@ struct spi_flash_host_driver_s {
* modified, the cache needs to be flushed. Left NULL if not supported.
*/
esp_err_t (*flush_cache)(spi_flash_host_inst_t* host, uint32_t addr, uint32_t size);
/**
* Resume flash from suspend manually
*/
void (*resume)(spi_flash_host_inst_t *host);
/**
* Set flash in suspend status manually
*/
void (*suspend)(spi_flash_host_inst_t *host);
/**
* Suspend feature setup for setting cmd and status register mask.
*/
esp_err_t (*sus_setup)(spi_flash_host_inst_t *host, const spi_flash_sus_cmd_conf *sus_conf);
};
///Slowest io mode supported by ESP32, currently SlowRd
#define SPI_FLASH_READ_MODE_MIN SPI_FLASH_SLOWRD

View File

@ -0,0 +1,80 @@
// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD
//
// Licensed 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.
#include <stdlib.h>
#include "spi_flash_chip_generic.h"
#include "spi_flash_chip_gd.h"
#include "spi_flash_defs.h"
/* Driver for BOYA flash chip */
esp_err_t spi_flash_chip_gd_suspend_cmd_conf(esp_flash_t *chip);
// Use the same implementation as GD chips
#define spi_flash_chip_boya_suspend_cmd_conf spi_flash_chip_gd_suspend_cmd_conf
esp_err_t spi_flash_chip_boya_probe(esp_flash_t *chip, uint32_t flash_id)
{
/* Check manufacturer and product IDs match our desired masks */
const uint8_t MFG_ID = 0x68;
if (flash_id >> 16 != MFG_ID) {
return ESP_ERR_NOT_FOUND;
}
const uint16_t FLASH_ID_MASK = 0xFF00;
const uint16_t FLASH_ID_VALUE = 0x4000;
if ((flash_id & FLASH_ID_MASK) != FLASH_ID_VALUE) {
return ESP_ERR_NOT_FOUND;
}
return ESP_OK;
}
static const char chip_name[] = "boya";
// The BOYA chip can use the functions for generic chips except from set read mode and probe,
// So we only replace these two functions.
const spi_flash_chip_t esp_flash_chip_boya = {
.name = chip_name,
.timeout = &spi_flash_chip_generic_timeout,
.probe = spi_flash_chip_boya_probe,
.reset = spi_flash_chip_generic_reset,
.detect_size = spi_flash_chip_generic_detect_size,
.erase_chip = spi_flash_chip_generic_erase_chip,
.erase_sector = spi_flash_chip_generic_erase_sector,
.erase_block = spi_flash_chip_generic_erase_block,
.sector_size = 4 * 1024,
.block_erase_size = 64 * 1024,
.get_chip_write_protect = spi_flash_chip_generic_get_write_protect,
.set_chip_write_protect = spi_flash_chip_generic_set_write_protect,
.num_protectable_regions = 0,
.protectable_regions = NULL,
.get_protected_regions = NULL,
.set_protected_regions = NULL,
.read = spi_flash_chip_generic_read,
.write = spi_flash_chip_generic_write,
.program_page = spi_flash_chip_generic_page_program,
.page_size = 256,
.write_encrypted = spi_flash_chip_generic_write_encrypted,
.wait_idle = spi_flash_chip_generic_wait_idle,
.set_io_mode = spi_flash_chip_generic_set_io_mode,
.get_io_mode = spi_flash_chip_generic_get_io_mode,
.read_reg = spi_flash_chip_generic_read_reg,
.yield = spi_flash_chip_generic_yield,
.sus_setup = spi_flash_chip_boya_suspend_cmd_conf,
};

View File

@ -19,6 +19,7 @@
#include "spi_flash_chip_mxic.h"
#include "spi_flash_chip_gd.h"
#include "spi_flash_chip_winbond.h"
#include "spi_flash_chip_boya.h"
#include "sdkconfig.h"
/*
@ -42,6 +43,9 @@ static const spi_flash_chip_t *default_registered_chips[] = {
#endif
#ifdef CONFIG_SPI_FLASH_SUPPORT_WINBOND_CHIP
&esp_flash_chip_winbond,
#endif
#ifdef CONFIG_SPI_FLASH_SUPPORT_BOYA_CHIP
&esp_flash_chip_boya,
#endif
// Default chip drivers that will accept all chip ID.
// FM, Winbond and XMC chips are supposed to be supported by this chip driver.

View File

@ -75,6 +75,18 @@ esp_err_t spi_flash_chip_gd_get_io_mode(esp_flash_t *chip, esp_flash_io_mode_t*
}
#endif //CONFIG_SPI_FLASH_ROM_IMPL
esp_err_t spi_flash_chip_gd_suspend_cmd_conf(esp_flash_t *chip)
{
spi_flash_sus_cmd_conf sus_conf = {
.sus_mask = 0x84,
.cmd_rdsr = CMD_RDSR2,
.sus_cmd = CMD_SUSPEND,
.res_cmd = CMD_RESUME,
};
return chip->host->driver->sus_setup(chip->host, &sus_conf);
}
static const char chip_name[] = "gd";
// The issi chip can use the functions for generic chips except from set read mode and probe,
@ -111,4 +123,5 @@ const spi_flash_chip_t esp_flash_chip_gd = {
.read_reg = spi_flash_chip_generic_read_reg,
.yield = spi_flash_chip_generic_yield,
.sus_setup = spi_flash_chip_gd_suspend_cmd_conf,
};

View File

@ -301,22 +301,6 @@ esp_err_t spi_flash_chip_generic_get_write_protect(esp_flash_t *chip, bool *out_
return err;
}
esp_err_t spi_flash_generic_wait_host_idle(esp_flash_t *chip, uint32_t *timeout_us)
{
while (!chip->host->driver->host_idle(chip->host) && *timeout_us > 0) {
#if HOST_DELAY_INTERVAL_US > 0
if (*timeout_us > 1) {
int delay = MIN(HOST_DELAY_INTERVAL_US, *timeout_us);
chip->os_func->delay_us(chip->os_func_data, delay);
*timeout_us -= delay;
} else {
return ESP_ERR_TIMEOUT;
}
#endif
}
return ESP_OK;
}
esp_err_t spi_flash_chip_generic_read_reg(esp_flash_t* chip, spi_flash_register_t reg_id, uint32_t* out_reg)
{
return chip->host->driver->read_status(chip->host, (uint8_t*)out_reg);
@ -357,14 +341,19 @@ esp_err_t spi_flash_chip_generic_wait_idle(esp_flash_t *chip, uint32_t timeout_u
uint8_t status = 0;
const int interval = CHIP_WAIT_IDLE_INTERVAL_US;
while (timeout_us > 0) {
while (!chip->host->driver->host_status(chip->host) && timeout_us > 0) {
esp_err_t err = spi_flash_generic_wait_host_idle(chip, & timeout_us);
if (err != ESP_OK) {
return err;
#if HOST_DELAY_INTERVAL_US > 0
if (timeout_us > 1) {
int delay = MIN(HOST_DELAY_INTERVAL_US, timeout_us);
chip->os_func->delay_us(chip->os_func_data, delay);
timeout_us -= delay;
}
#endif
}
uint32_t read;
err = chip->chip_drv->read_reg(chip, SPI_FLASH_REG_STATUS, &read);
esp_err_t err = chip->chip_drv->read_reg(chip, SPI_FLASH_REG_STATUS, &read);
if (err != ESP_OK) {
return err;
}
@ -511,6 +500,7 @@ const spi_flash_chip_t esp_flash_chip_generic = {
.read_reg = spi_flash_chip_generic_read_reg,
.yield = spi_flash_chip_generic_yield,
.sus_setup = spi_flash_chip_generic_suspend_cmd_conf,
};
#ifndef CONFIG_SPI_FLASH_ROM_IMPL
@ -652,3 +642,15 @@ esp_err_t spi_flash_common_set_io_mode(esp_flash_t *chip, esp_flash_wrsr_func_t
}
#endif // !CONFIG_SPI_FLASH_ROM_IMPL
esp_err_t spi_flash_chip_generic_suspend_cmd_conf(esp_flash_t *chip)
{
spi_flash_sus_cmd_conf sus_conf = {
.sus_mask = 0x80,
.cmd_rdsr = CMD_RDSR2,
.sus_cmd = CMD_SUSPEND,
.res_cmd = CMD_RESUME,
};
return chip->host->driver->sus_setup(chip->host, &sus_conf);
}

View File

@ -58,6 +58,17 @@ esp_err_t spi_flash_chip_issi_get_io_mode(esp_flash_t *chip, esp_flash_io_mode_t
return ret;
}
esp_err_t spi_flash_chip_issi_suspend_cmd_conf(esp_flash_t *chip)
{
spi_flash_sus_cmd_conf sus_conf = {
.sus_mask = 0x06,
.cmd_rdsr = CMD_RDFR,
.sus_cmd = CMD_SUSPEND,
.res_cmd = CMD_RESUME,
};
return chip->host->driver->sus_setup(chip->host, &sus_conf);
}
static const char chip_name[] = "issi";
@ -95,4 +106,5 @@ const spi_flash_chip_t esp_flash_chip_issi = {
.read_reg = spi_flash_chip_generic_read_reg,
.yield = spi_flash_chip_generic_yield,
.sus_setup = spi_flash_chip_issi_suspend_cmd_conf,
};

View File

@ -39,6 +39,18 @@ esp_err_t spi_flash_chip_issi_get_io_mode(esp_flash_t *chip, esp_flash_io_mode_t
static const char chip_name[] = "mxic";
esp_err_t spi_flash_chip_mxic_suspend_cmd_conf(esp_flash_t *chip)
{
spi_flash_sus_cmd_conf sus_conf = {
.sus_mask = 0x06,
.cmd_rdsr = CMD_RDSCUR,
.sus_cmd = CMD_SUSPEND,
.res_cmd = CMD_RESUME,
};
return chip->host->driver->sus_setup(chip->host, &sus_conf);
}
// The mxic chip can use the functions for generic chips except from set read mode and probe,
// So we only replace these two functions.
const spi_flash_chip_t esp_flash_chip_mxic = {
@ -73,4 +85,5 @@ const spi_flash_chip_t esp_flash_chip_mxic = {
.read_reg = spi_flash_chip_mxic_read_reg,
.yield = spi_flash_chip_generic_yield,
.sus_setup = spi_flash_chip_mxic_suspend_cmd_conf,
};

View File

@ -176,6 +176,7 @@ const spi_flash_chip_t esp_flash_chip_winbond = {
.read_reg = spi_flash_chip_generic_read_reg,
.yield = spi_flash_chip_generic_yield,
.sus_setup = spi_flash_chip_generic_suspend_cmd_conf,
};

View File

@ -67,12 +67,16 @@ static inline IRAM_ATTR bool on_spi1_check_yield(spi1_app_func_arg_t* ctx);
IRAM_ATTR static void cache_enable(void* arg)
{
#ifndef CONFIG_SPI_FLASH_AUTO_SUSPEND
g_flash_guard_default_ops.end();
#endif
}
IRAM_ATTR static void cache_disable(void* arg)
{
#ifndef CONFIG_SPI_FLASH_AUTO_SUSPEND
g_flash_guard_default_ops.start();
#endif
}
static IRAM_ATTR esp_err_t spi_start(void *arg)

View File

@ -24,6 +24,14 @@
#include "esp_rom_sys.h"
#include "esp_timer.h"
#if CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/rom/cache.h"
#elif CONFIG_IDF_TARGET_ESP32S3
#include "esp32s3/rom/cache.h"
#elif CONFIG_IDF_TARGET_ESP32C3
#include "esp32c3/rom/cache.h"
#endif
#define FUNC_SPI 1
static uint8_t sector_buf[4096];
@ -606,6 +614,51 @@ void test_erase_large_region(const esp_partition_t *part)
FLASH_TEST_CASE("SPI flash erase large region", test_erase_large_region);
FLASH_TEST_CASE_3("SPI flash erase large region", test_erase_large_region);
#if CONFIG_SPI_FLASH_AUTO_SUSPEND
void esp_test_for_suspend(void)
{
/*clear content in cache*/
#if !CONFIG_IDF_TARGET_ESP32C3
Cache_Invalidate_DCache_All();
#endif
Cache_Invalidate_ICache_All();
ESP_LOGI(TAG, "suspend test begins:");
printf("run into test suspend function\n");
printf("print something when flash is erasing:\n");
printf("aaaaa bbbbb zzzzz fffff qqqqq ccccc\n");
}
void task_erase_large_region(void *arg)
{
esp_partition_t *part = (esp_partition_t *)arg;
test_erase_large_region(part);
vTaskDelete(NULL);
}
void task_request_suspend(void *arg)
{
vTaskDelay(2);
ESP_LOGI(TAG, "flash go into suspend");
esp_test_for_suspend();
vTaskDelete(NULL);
}
void task_delay(void *arg)
{
esp_rom_delay_us(2000000);
vTaskDelete(NULL);
}
static void test_flash_suspend_resume(const esp_partition_t* part)
{
xTaskCreatePinnedToCore(task_request_suspend, "suspend", 2048, (void *)"test_for_suspend", UNITY_FREERTOS_PRIORITY + 3, NULL, 0);
xTaskCreatePinnedToCore(task_erase_large_region, "test", 2048, (void *)part, UNITY_FREERTOS_PRIORITY + 2, NULL, 0);
xTaskCreatePinnedToCore(task_delay, "task_delay", 1024, (void *)"task_delay", UNITY_FREERTOS_PRIORITY + 1, NULL, 0);
}
FLASH_TEST_CASE("SPI flash suspend and resume test", test_flash_suspend_resume);
#endif //CONFIG_SPI_FLASH_AUTO_SUSPEND
static void test_write_protection(const esp_partition_t* part)
{
esp_flash_t* chip = part->flash_chip;

View File

@ -42,6 +42,7 @@ components/spi_flash/include/spi_flash_chip_issi.h
components/spi_flash/include/spi_flash_chip_mxic.h
components/spi_flash/include/spi_flash_chip_gd.h
components/spi_flash/include/spi_flash_chip_winbond.h
components/spi_flash/include/spi_flash_chip_boya.h
components/spi_flash/include/memspi_host_driver.h
components/spi_flash/include/spi_flash_chip_driver.h
components/spi_flash/include/spi_flash_chip_generic.h