refactor(spi_flash): move os layer to esp_mspi and chip configs to spi_flash

Also fixes the implicit dependency on esp_partition.
This commit is contained in:
armando
2026-06-02 11:12:03 +08:00
committed by Armando (Dou Yiwen)
parent c565262ded
commit 6e3abd12a1
197 changed files with 1227 additions and 1139 deletions

View File

@@ -3,33 +3,19 @@ idf_build_get_property(non_os_build NON_OS_BUILD)
if(${target} STREQUAL "linux")
idf_component_register(SRCS "linux/spi_flash_linux.c"
"linux/cache_utils.c"
"linux/flash_mmap.c"
"spi_flash_blockdev.c"
INCLUDE_DIRS include
REQUIRES esp_hal_mspi esp_blockdev)
REQUIRES esp_hal_mspi esp_blockdev
PRIV_REQUIRES esp_mspi)
return()
endif()
if(non_os_build OR CONFIG_APP_BUILD_TYPE_PURE_RAM_APP)
set(srcs "spi_flash_wrap.c")
set(srcs "")
set(priv_requires bootloader_support soc esp_hal_gpio)
else()
set(srcs "flash_brownout_hook.c")
if(CONFIG_SOC_SPI_MEM_SUPPORT_FLASH_OPI_MODE)
list(APPEND srcs "${target}/spi_flash_oct_flash_init.c")
endif()
if(CONFIG_SPI_FLASH_HPM_ON)
list(APPEND srcs
"spi_flash_hpm_enable.c")
endif()
if(CONFIG_ESP_SLEEP_SET_FLASH_DPD)
list(APPEND srcs
"spi_flash_dpd_enable.c")
endif()
set(srcs "")
# New implementation after IDF v4.0
list(APPEND srcs
@@ -46,13 +32,7 @@ else()
"spi_flash_blockdev.c")
set(cache_srcs
"cache_utils.c"
"flash_mmap.c"
"flash_ops.c"
"spi_flash_wrap.c"
)
list(APPEND cache_srcs
"esp_flash_api.c"
"esp_flash_spi_init.c"
"spi_flash_os_func_app.c"
@@ -67,7 +47,7 @@ else()
endif()
idf_component_register(SRCS "${srcs}"
REQUIRES hal esp_hal_mspi esp_blockdev
REQUIRES hal esp_hal_mspi esp_mspi esp_blockdev
PRIV_REQUIRES "${priv_requires}"
INCLUDE_DIRS include
LDFRAGMENTS linker.lf)

View File

@@ -1,193 +1,112 @@
menu "Main Flash configuration"
menu "Optional and Experimental SPI Flash Features (READ DOCS FIRST)"
depends on !APP_BUILD_TYPE_PURE_RAM_APP
menu "SPI Flash behavior when brownout"
comment "Features here require specific hardware (READ DOCS FIRST!)"
config SPI_FLASH_BROWNOUT_RESET_XMC
bool "Enable sending reset when brownout for XMC flash chips"
default y
select SPI_FLASH_BROWNOUT_RESET
help
When this option is selected, the patch will be enabled for XMC.
Follow the recommended flow by XMC for better stability.
config SPI_FLASH_AUTO_SUSPEND
bool "Auto suspend long erase/write operations (READ DOCS FIRST)"
default n
depends on SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND && !SPI_FLASH_ROM_IMPL
help
This option is disabled by default because it is supported only
for specific flash chips and for specific Espressif chips.
To evaluate if you can use this feature refer to
`Optional Features for Flash` > `Auto Suspend & Resume` of the `ESP-IDF Programming Guide`.
DO NOT DISABLE UNLESS YOU KNOW WHAT YOU ARE DOING.
CAUTION: If you want to OTA to an app with this feature turned on, please make
sure the bootloader has the support for it. (later than IDF v4.3)
config SPI_FLASH_BROWNOUT_RESET
bool
default y
select ESP_BROWNOUT_USE_INTR
help
When brownout happens during flash erase/write operations,
send reset command to stop the flash operations to improve stability.
If you are using an official Espressif module, please contact Espressif Business support
to check if the module has the flash that support this feature installed.
Also refer to `Concurrency Constraints for Flash on SPI1` > `Flash Auto Suspend Feature`
before enabling this option.
endmenu
config SPI_FLASH_SUSPEND_TSUS_VAL_US
int "SPI flash tSUS value (refer to chapter AC CHARACTERISTICS)"
default 50
range 20 100
help
This config is used for setting Tsus parameter. Tsus means CS# high to next command after
suspend. You can refer to the chapter of AC CHARACTERISTICS of flash datasheet.
menu "Optional and Experimental Features (READ DOCS FIRST)"
config SPI_FLASH_SUSPEND_TRS_VAL_US
int "SPI flash tRS value (refer to chapter AC CHARACTERISTICS)"
default 50
range 20 200
depends on SOC_SPI_MEM_SUPPORT_TSUS_TRES_SEPERATE_CTR && (!ESP32P4_SELECTS_REV_LESS_V3)
help
This config is used for setting Trs parameter. Trs means CS Latency Between Resume And Next Suspend.
You can refer to the chapter of AC CHARACTERISTICS of flash datasheet.
For high-performance scenarios, some flash chips allow this set value to be smaller than the
given value in the datasheet without causing errors in the flash state machine.
When you have any related needs, please contact espressif business team.
comment "Features here require specific hardware (READ DOCS FIRST!)"
config SPI_FLASH_FORCE_ENABLE_XMC_C_SUSPEND
bool "Enable XMC-C series flash chip suspend feature anyway"
default n
help
XMC-C series is regarded as not qualified for the Suspend feature, since its specification
has a tRS >= 1ms restriction. We strongly do not suggest using it for the Suspend feature.
However, if your product in field has enabled this feature, you may still enable this
config option to keep the legacy behavior.
config SPI_FLASH_UNDER_HIGH_FREQ
bool
default y if ESPTOOLPY_FLASHFREQ_120M
help
This is a helper config for HPM. Invisible for users.
For new users, DO NOT enable this config.
choice SPI_FLASH_HPM
prompt "High Performance Mode (READ DOCS FIRST, > 80MHz)"
depends on SOC_SPI_MEM_FLASH_SUPPORT_HPM && !ESPTOOLPY_OCT_FLASH
default SPI_FLASH_HPM_AUTO
help
Whether the High Performance Mode of Flash is enabled. As an optional feature, user needs to manually
enable this option as a confirmation. To be back-compatible with earlier IDF version, this option is
automatically enabled with warning when Flash running > 80Mhz.
config SPI_FLASH_FORCE_ENABLE_C6_H2_SUSPEND
bool "Enable chip suspend feature on c6 or h2 anyway (DO NOT ENABLE FOR NEW USERS OR APPLICATIONS)"
default n
help
Flash suspend has a defect on ESP32C6 until v0.2 and ESP32H2 until v1.2. If you already use suspend
feature for mass production, you can enable this for bypassing check after knowing the risk.
But if you are new users, or developing new applications, or producing a new batch,
please DO NOT enable this config option.
config SPI_FLASH_HPM_ENA
# Not using name of SPI_FLASH_HPM_ENABLE because it was used as an invisible option and we don't want
# to inherit the value of that one
bool "Enable"
config SPI_FLASH_HPM_AUTO
bool "Auto (Not recommended)"
config SPI_FLASH_HPM_DIS
bool "Disabled"
endchoice
For more information, please refer to errata or connect to Espressif business support team.
config SPI_FLASH_HPM_ON
bool
# For ESP32-S3, it's enabled by default. For later chips it should be disabled by default
default y if (IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32P4) && ((SPI_FLASH_HPM_ENA || SPI_FLASH_HPM_AUTO)) || \
(!IDF_TARGET_ESP32S3 && SPI_FLASH_HPM_ENA)
help
This option is invisible, and will be selected automatically
when ``ESPTOOLPY_FLASHFREQ_120M`` is selected.
config SPI_FLASH_SOFTWARE_RESUME
bool "Resume flash program/erase form suspend state by software control"
default n
depends on SPI_FLASH_AUTO_SUSPEND && FREERTOS_UNICORE && IDF_EXPERIMENTAL_FEATURES
help
Enable this config will disable auto-resume from hardware. Thus the software will resume the chip
after any higher priority task/interrupt which suspend the chip. The benefit is that the suspend-resume
will not disturb the higher priority task and interrupt.
choice SPI_FLASH_HPM_DC
prompt "Support HPM using DC (READ DOCS FIRST)"
depends on SPI_FLASH_HPM_ON
default SPI_FLASH_HPM_DC_AUTO
help
This feature needs your bootloader to be compiled DC-aware (BOOTLOADER_FLASH_DC_AWARE=y). Otherwise the
chip will not be able to boot after a reset.
This currently is only valid on single core chip.
config SPI_FLASH_HPM_DC_AUTO
bool "Auto (Enable when bootloader support enabled (BOOTLOADER_FLASH_DC_AWARE))"
config SPI_FLASH_HPM_DC_DISABLE
bool "Disable (READ DOCS FIRST)"
endchoice
config SPI_FLASH_DISABLE_SCHEDULER_IN_SUSPEND
bool "Disable task scheduler when suspend is enabled when SPI1 operation is ongoing"
default n
# Only valid on single core because no protection is supported on multi core
depends on SPI_FLASH_AUTO_SUSPEND && FREERTOS_UNICORE
help
Disable freertos task scheduler when CONFIG_SPI_FLASH_AUTO_SUSPEND is enabled.
Thus only interrupt can trigger a suspend. When SPI_FLASH_AUTO_SUSPEND is enabled,
default behavior is not disable the task scheduler, so both interrupt and high priority
task can suspend the erase/program operation. When this option is enabled, task
scheduler is disabled, only interrupt can suspend erase/program operation.
config SPI_FLASH_HPM_DC_ON
bool
default y if SPI_FLASH_HPM_DC_AUTO && BOOTLOADER_FLASH_DC_AWARE
help
This is a helper config for HPM. Whether HPM-DC is enabled is also determined by bootloader.
Invisible for users.
config SPI_FLASH_AUTO_CHECK_SUSPEND_STATUS
bool "Check flash status automatically after flash suspend"
default n
depends on SPI_FLASH_AUTO_SUSPEND
help
Majority flash supports to use flash register to judge if flash suspend status is
done or not. So enable this config, the behavior would use flash register WIP bit to judge
whether suspend is valid instead of waiting for a specific long time, which can save a
lot of time and benefit for performance improvement.
config SPI_FLASH_AUTO_SUSPEND
bool "Auto suspend long erase/write operations (READ DOCS FIRST)"
default n
depends on SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND && !SPI_FLASH_ROM_IMPL
help
This option is disabled by default because it is supported only
for specific flash chips and for specific Espressif chips.
To evaluate if you can use this feature refer to
`Optional Features for Flash` > `Auto Suspend & Resume` of the `ESP-IDF Programming Guide`.
config SPI_FLASH_PLACE_FUNCTIONS_IN_IRAM
bool "Place spi_flash operation functions into IRAM" if SPI_FLASH_AUTO_SUSPEND
default y
help
When disabled, certain functions in `spi_flash` component will be placed into Flash memory
instead of IRAM. Disabling this option will save almost 10KB of IRAM depending on which
functions are used.
CAUTION: If you want to OTA to an app with this feature turned on, please make
sure the bootloader has the support for it. (later than IDF v4.3)
When enabled, these functions will be placed in internal RAM, with better performance.
If you are using an official Espressif module, please contact Espressif Business support
to check if the module has the flash that support this feature installed.
Also refer to `Concurrency Constraints for Flash on SPI1` > `Flash Auto Suspend Feature`
before enabling this option.
config SPI_FLASH_SUSPEND_TSUS_VAL_US
int "SPI flash tSUS value (refer to chapter AC CHARACTERISTICS)"
default 50
range 20 100
help
This config is used for setting Tsus parameter. Tsus means CS# high to next command after
suspend. You can refer to the chapter of AC CHARACTERISTICS of flash datasheet.
config SPI_FLASH_SUSPEND_TRS_VAL_US
int "SPI flash tRS value (refer to chapter AC CHARACTERISTICS)"
default 50
range 20 200
depends on SOC_SPI_MEM_SUPPORT_TSUS_TRES_SEPERATE_CTR && (!ESP32P4_SELECTS_REV_LESS_V3)
help
This config is used for setting Trs parameter. Trs means CS Latency Between Resume And Next Suspend.
You can refer to the chapter of AC CHARACTERISTICS of flash datasheet.
For high-performance scenarios, some flash chips allow this set value to be smaller than the
given value in the datasheet without causing errors in the flash state machine.
When you have any related needs, please contact espressif business team.
config SPI_FLASH_FORCE_ENABLE_XMC_C_SUSPEND
bool "Enable XMC-C series flash chip suspend feature anyway"
default n
help
XMC-C series is regarded as not qualified for the Suspend feature, since its specification
has a tRS >= 1ms restriction. We strongly do not suggest using it for the Suspend feature.
However, if your product in field has enabled this feature, you may still enable this
config option to keep the legacy behavior.
For new users, DO NOT enable this config.
config SPI_FLASH_FORCE_ENABLE_C6_H2_SUSPEND
bool "Enable chip suspend feature on c6 or h2 anyway (DO NOT ENABLE FOR NEW USERS OR APPLICATIONS)"
default n
help
Flash suspend has a defect on ESP32C6 until v0.2 and ESP32H2 until v1.2. If you already use suspend
feature for mass production, you can enable this for bypassing check after knowing the risk.
But if you are new users, or developing new applications, or producing a new batch,
please DO NOT enable this config option.
For more information, please refer to errata or connect to Espressif business support team.
config SPI_FLASH_SOFTWARE_RESUME
bool "Resume flash program/erase form suspend state by software control"
default n
depends on SPI_FLASH_AUTO_SUSPEND && FREERTOS_UNICORE && IDF_EXPERIMENTAL_FEATURES
help
Enable this config will disable auto-resume from hardware. Thus the software will resume the chip
after any higher priority task/interrupt which suspend the chip. The benefit is that the suspend-resume
will not disturb the higher priority task and interrupt.
This currently is only valid on single core chip.
config SPI_FLASH_DISABLE_SCHEDULER_IN_SUSPEND
bool "Disable task scheduler when suspend is enabled when SPI1 operation is ongoing"
default n
# Only valid on single core because no protection is supported on multi core
depends on SPI_FLASH_AUTO_SUSPEND && FREERTOS_UNICORE
help
Disable freertos task scheduler when CONFIG_SPI_FLASH_AUTO_SUSPEND is enabled.
Thus only interrupt can trigger a suspend. When SPI_FLASH_AUTO_SUSPEND is enabled,
default behavior is not disable the task scheduler, so both interrupt and high priority
task can suspend the erase/program operation. When this option is enabled, task
scheduler is disabled, only interrupt can suspend erase/program operation.
config SPI_FLASH_AUTO_CHECK_SUSPEND_STATUS
bool "Check flash status automatically after flash suspend"
default n
depends on SPI_FLASH_AUTO_SUSPEND
help
Majority flash supports to use flash register to judge if flash suspend status is
done or not. So enable this config, the behavior would use flash register WIP bit to judge
whether suspend is valid instead of waiting for a specific long time, which can save a
lot of time and benefit for performance improvement.
config SPI_FLASH_PLACE_FUNCTIONS_IN_IRAM
bool "Place spi_flash operation functions into IRAM" if SPI_FLASH_AUTO_SUSPEND
default y
help
When disabled, certain functions in `spi_flash` component will be placed into Flash memory
instead of IRAM. Disabling this option will save almost 10KB of IRAM depending on which
functions are used.
When enabled, these functions will be placed in internal RAM, with better performance.
For more information please refer to programming guide.
endmenu
For more information please refer to programming guide.
endmenu
menu "SPI Flash driver"

View File

@@ -1 +0,0 @@
See the spi_flash.rst in the programming guide folder for more details.

View File

@@ -1,928 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "rom/cache.h"
#if CONFIG_IDF_TARGET_ESP32
#include "soc/dport_reg.h"
#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C6
#include "soc/extmem_reg.h"
#endif
#include "soc/ext_mem_defs.h"
#include "esp_rom_spiflash.h"
#include "hal/cache_hal.h"
#include "hal/cache_ll.h"
#include <soc/soc.h>
#include "sdkconfig.h"
#ifndef CONFIG_FREERTOS_UNICORE
#include "esp_private/esp_ipc.h"
#endif
#include "esp_attr.h"
#include "esp_cpu.h"
#include "esp_memory_utils.h"
#include "esp_intr_alloc.h"
#include "esp_private/esp_cache_private.h"
#include "esp_private/cache_utils.h"
#include "esp_private/spi_flash_os.h"
#include "esp_private/freertos_idf_additions_priv.h"
#include "esp_log.h"
ESP_LOG_ATTR_TAG(TAG, "cache");
// Used only on ROM impl. in idf, this param unused, cache status hold by hal
static uint32_t s_flash_op_cache_state[2];
#ifndef CONFIG_FREERTOS_UNICORE
static SemaphoreHandle_t s_flash_op_mutex;
static volatile bool s_flash_op_can_start = false;
static volatile bool s_flash_op_complete = false;
#ifndef NDEBUG
static volatile int s_flash_op_cpu = -1;
#endif
void spi_flash_init_lock(void)
{
s_flash_op_mutex = xSemaphoreCreateRecursiveMutex();
assert(s_flash_op_mutex != NULL);
}
void spi_flash_op_lock(void)
{
xSemaphoreTakeRecursive(s_flash_op_mutex, portMAX_DELAY);
}
void spi_flash_op_unlock(void)
{
xSemaphoreGiveRecursive(s_flash_op_mutex);
}
/*
If you're going to modify this, keep in mind that while the flash caches of the pro and app
cpu are separate, the psram cache is *not*. If one of the CPUs returns from a flash routine
with its cache enabled but the other CPUs cache is not enabled yet, you will have problems
when accessing psram from the former CPU.
*/
void IRAM_ATTR spi_flash_op_block_func(void *arg)
{
// Disable scheduler on this CPU
#if ( ( CONFIG_FREERTOS_SMP ) && ( !CONFIG_FREERTOS_UNICORE ) )
/*
Note: FreeRTOS SMP has changed the behavior of scheduler suspension. But the vTaskPreemptionDisable() function should
achieve the same affect as before (i.e., prevent the current task from being preempted).
*/
vTaskPreemptionDisable(NULL);
#else
vTaskSuspendAll();
#endif // #if ( ( CONFIG_FREERTOS_SMP ) && ( !CONFIG_FREERTOS_UNICORE ) )
// Restore interrupts that aren't located in IRAM
esp_intr_noniram_disable();
uint32_t cpuid = (uint32_t) arg;
#if SOC_BRANCH_PREDICTOR_SUPPORTED
/* The branch predictor issues speculative cache requests while this core
* spins in IRAM. The flash-op core is about to suspend the (shared) cache,
* so speculative fetches into flash would raise a cache access-fail on
* this core. */
esp_cpu_branch_prediction_disable();
#endif
// s_flash_op_complete flag is cleared on *this* CPU, otherwise the other
// CPU may reset the flag back to false before IPC task has a chance to check it
// (if it is preempted by an ISR taking non-trivial amount of time)
s_flash_op_complete = false;
s_flash_op_can_start = true;
while (!s_flash_op_complete) {
// busy loop here and wait for the other CPU to finish flash operation
}
// Flash operation is complete, re-enable cache
spi_flash_restore_cache(cpuid, s_flash_op_cache_state[cpuid]);
#if SOC_BRANCH_PREDICTOR_SUPPORTED
esp_cpu_branch_prediction_enable();
#endif
// Restore interrupts that aren't located in IRAM
esp_intr_noniram_enable();
#if ( ( CONFIG_FREERTOS_SMP ) && ( !CONFIG_FREERTOS_UNICORE ) )
//Note: Scheduler suspension behavior changed in FreeRTOS SMP
vTaskPreemptionEnable(NULL);
#else
// Re-enable scheduler
xTaskResumeAll();
#endif // #if ( ( CONFIG_FREERTOS_SMP ) && ( !CONFIG_FREERTOS_UNICORE ) )
}
void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu(void)
{
#if CONFIG_FREERTOS_TASK_CREATE_ALLOW_EXT_MEM
assert(esp_task_stack_is_sane_cache_disabled());
#endif
spi_flash_op_lock();
int cpuid = xPortGetCoreID();
uint32_t other_cpuid = (cpuid == 0) ? 1 : 0;
#ifndef NDEBUG
// For sanity check later: record the CPU which has started doing flash operation
assert(s_flash_op_cpu == -1);
s_flash_op_cpu = cpuid;
#endif
if (xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED) {
// Scheduler hasn't been started yet, it means that spi_flash API is being
// called from the 2nd stage bootloader or from user_start_cpu0, i.e. from
// PRO CPU. APP CPU is either in reset or spinning inside user_start_cpu1,
// which is in IRAM. So it is safe to disable cache for the other_cpuid after
// esp_intr_noniram_disable.
assert(other_cpuid == 1);
} else {
bool ipc_call_was_send_to_other_cpu;
do {
#if ( ( CONFIG_FREERTOS_SMP ) && ( !CONFIG_FREERTOS_UNICORE ) )
//Note: Scheduler suspension behavior changed in FreeRTOS SMP
vTaskPreemptionDisable(NULL);
#else
// Disable scheduler on the current CPU
vTaskSuspendAll();
#endif
cpuid = xPortGetCoreID();
other_cpuid = (cpuid == 0) ? 1 : 0;
#ifndef NDEBUG
s_flash_op_cpu = cpuid;
#endif
s_flash_op_can_start = false;
ipc_call_was_send_to_other_cpu = esp_ipc_call_nonblocking(other_cpuid, &spi_flash_op_block_func, (void *) other_cpuid) == ESP_OK;
if (!ipc_call_was_send_to_other_cpu) {
// IPC call was not send to other cpu because another nonblocking API is running now.
// Enable the Scheduler again will not help the IPC to speed it up
// but there is a benefit to schedule to a higher priority task before the nonblocking running IPC call is done.
#if ( ( CONFIG_FREERTOS_SMP ) && ( !CONFIG_FREERTOS_UNICORE ) )
//Note: Scheduler suspension behavior changed in FreeRTOS SMP
vTaskPreemptionEnable(NULL);
#else
xTaskResumeAll();
#endif
}
} while (!ipc_call_was_send_to_other_cpu);
while (!s_flash_op_can_start) {
// Busy loop and wait for spi_flash_op_block_func to disable cache
// on the other CPU
}
}
// Kill interrupts that aren't located in IRAM
esp_intr_noniram_disable();
#if SOC_BRANCH_PREDICTOR_SUPPORTED
esp_cpu_branch_prediction_disable();
#endif
// This CPU executes this routine, with non-IRAM interrupts and the scheduler
// disabled. The other CPU is spinning in the spi_flash_op_block_func task, also
// with non-iram interrupts and the scheduler disabled. None of these CPUs will
// touch external RAM or flash this way, so we can safely disable caches.
spi_flash_disable_cache(cpuid, &s_flash_op_cache_state[cpuid]);
#if SOC_IDCACHE_PER_CORE
//only needed if cache(s) is per core
spi_flash_disable_cache(other_cpuid, &s_flash_op_cache_state[other_cpuid]);
#endif
}
void IRAM_ATTR spi_flash_enable_interrupts_caches_and_other_cpu(void)
{
const int cpuid = xPortGetCoreID();
#ifndef NDEBUG
// Sanity check: flash operation ends on the same CPU as it has started
assert(cpuid == s_flash_op_cpu);
// More sanity check: if scheduler isn't started, only CPU0 can call this.
assert(!(xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED && cpuid != 0));
s_flash_op_cpu = -1;
#endif
// Re-enable cache. After this, cache (flash and external RAM) should work again.
spi_flash_restore_cache(cpuid, s_flash_op_cache_state[cpuid]);
#if SOC_IDCACHE_PER_CORE
//only needed if cache(s) is per core
const uint32_t other_cpuid = (cpuid == 0) ? 1 : 0;
spi_flash_restore_cache(other_cpuid, s_flash_op_cache_state[other_cpuid]);
#endif
if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) {
// Signal to spi_flash_op_block_task that flash operation is complete
s_flash_op_complete = true;
}
#if SOC_BRANCH_PREDICTOR_SUPPORTED
esp_cpu_branch_prediction_enable();
#endif
// Re-enable non-iram interrupts
esp_intr_noniram_enable();
// Resume tasks on the current CPU, if the scheduler has started.
// NOTE: enabling non-IRAM interrupts has to happen before this,
// because once the scheduler has started, due to preemption the
// current task can end up being moved to the other CPU.
// But esp_intr_noniram_enable has to be called on the same CPU which
// called esp_intr_noniram_disable
if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) {
#if ( ( CONFIG_FREERTOS_SMP ) && ( !CONFIG_FREERTOS_UNICORE ) )
//Note: Scheduler suspension behavior changed in FreeRTOS SMP
vTaskPreemptionEnable(NULL);
#else
xTaskResumeAll();
#endif // #if ( ( CONFIG_FREERTOS_SMP ) && ( !CONFIG_FREERTOS_UNICORE ) )
}
// Release API lock
spi_flash_op_unlock();
}
void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu_no_os(void)
{
const uint32_t cpuid = xPortGetCoreID();
const uint32_t other_cpuid = (cpuid == 0) ? 1 : 0;
#if SOC_BRANCH_PREDICTOR_SUPPORTED
/* Disable BP before the first disable_cache(): on shared-cache chips that
* call suspends external memory for all cores, so speculative fetches must
* already be stopped. */
esp_cpu_branch_prediction_disable();
#endif
// do not care about other CPU, it was halted upon entering panic handler
spi_flash_disable_cache(other_cpuid, &s_flash_op_cache_state[other_cpuid]);
// Kill interrupts that aren't located in IRAM
esp_intr_noniram_disable();
// Disable cache on this CPU as well
spi_flash_disable_cache(cpuid, &s_flash_op_cache_state[cpuid]);
}
void IRAM_ATTR spi_flash_enable_interrupts_caches_no_os(void)
{
const uint32_t cpuid = xPortGetCoreID();
// Re-enable cache on this CPU
spi_flash_restore_cache(cpuid, s_flash_op_cache_state[cpuid]);
#if SOC_BRANCH_PREDICTOR_SUPPORTED
esp_cpu_branch_prediction_enable();
#endif
// Re-enable non-iram interrupts
esp_intr_noniram_enable();
}
#else // CONFIG_FREERTOS_UNICORE
void spi_flash_init_lock(void)
{
}
void spi_flash_op_lock(void)
{
#if ( ( CONFIG_FREERTOS_SMP ) && ( !CONFIG_FREERTOS_UNICORE ) )
if (xTaskGetSchedulerState() == taskSCHEDULER_RUNNING) {
//Note: Scheduler suspension behavior changed in FreeRTOS SMP
vTaskPreemptionDisable(NULL);
}
#else
vTaskSuspendAll();
#endif // #if ( ( CONFIG_FREERTOS_SMP ) && ( !CONFIG_FREERTOS_UNICORE ) )
}
void spi_flash_op_unlock(void)
{
#if ( ( CONFIG_FREERTOS_SMP ) && ( !CONFIG_FREERTOS_UNICORE ) )
if (xTaskGetSchedulerState() == taskSCHEDULER_RUNNING) {
//Note: Scheduler suspension behavior changed in FreeRTOS SMP
vTaskPreemptionEnable(NULL);
}
#else
xTaskResumeAll();
#endif // #if ( ( CONFIG_FREERTOS_SMP ) && ( !CONFIG_FREERTOS_UNICORE ) )
}
void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu(void)
{
spi_flash_op_lock();
esp_intr_noniram_disable();
#if SOC_BRANCH_PREDICTOR_SUPPORTED
esp_cpu_branch_prediction_disable();
#endif
spi_flash_disable_cache(0, &s_flash_op_cache_state[0]);
}
void IRAM_ATTR spi_flash_enable_interrupts_caches_and_other_cpu(void)
{
spi_flash_restore_cache(0, s_flash_op_cache_state[0]);
#if SOC_BRANCH_PREDICTOR_SUPPORTED
esp_cpu_branch_prediction_enable();
#endif
esp_intr_noniram_enable();
spi_flash_op_unlock();
}
void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu_no_os(void)
{
// Kill interrupts that aren't located in IRAM
esp_intr_noniram_disable();
#if SOC_BRANCH_PREDICTOR_SUPPORTED
esp_cpu_branch_prediction_disable();
#endif
// Disable cache on this CPU as well
spi_flash_disable_cache(0, &s_flash_op_cache_state[0]);
}
void IRAM_ATTR spi_flash_enable_interrupts_caches_no_os(void)
{
// Re-enable cache on this CPU
spi_flash_restore_cache(0, s_flash_op_cache_state[0]);
#if SOC_BRANCH_PREDICTOR_SUPPORTED
esp_cpu_branch_prediction_enable();
#endif
// Re-enable non-iram interrupts
esp_intr_noniram_enable();
}
#endif // CONFIG_FREERTOS_UNICORE
void IRAM_ATTR spi_flash_enable_cache(uint32_t cpuid)
{
#if CONFIG_IDF_TARGET_ESP32
uint32_t cache_value = cache_ll_l1_get_enabled_bus(cpuid);
// Re-enable cache on this CPU
spi_flash_restore_cache(cpuid, cache_value);
#else
spi_flash_restore_cache(0, 0); // TODO cache_value should be non-zero
#endif
}
#if !CONFIG_SPI_FLASH_ROM_IMPL
void IRAM_ATTR spi_flash_disable_cache(uint32_t cpuid, uint32_t *saved_state)
{
esp_cache_suspend_ext_mem_cache();
}
void IRAM_ATTR spi_flash_restore_cache(uint32_t cpuid, uint32_t saved_state)
{
esp_cache_resume_ext_mem_cache();
}
bool IRAM_ATTR spi_flash_cache_enabled(void)
{
return cache_hal_is_cache_enabled(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
}
#endif
#if CONFIG_IDF_TARGET_ESP32S2
IRAM_ATTR void esp_config_instruction_cache_mode(void)
{
cache_size_t cache_size;
cache_ways_t cache_ways;
cache_line_size_t cache_line_size;
#if CONFIG_ESP32S2_INSTRUCTION_CACHE_8KB
Cache_Allocate_SRAM(CACHE_MEMORY_ICACHE_LOW, CACHE_MEMORY_INVALID, CACHE_MEMORY_INVALID, CACHE_MEMORY_INVALID);
cache_size = CACHE_SIZE_8KB;
#else
Cache_Allocate_SRAM(CACHE_MEMORY_ICACHE_LOW, CACHE_MEMORY_ICACHE_HIGH, CACHE_MEMORY_INVALID, CACHE_MEMORY_INVALID);
cache_size = CACHE_SIZE_16KB;
#endif
cache_ways = CACHE_4WAYS_ASSOC;
#if CONFIG_ESP32S2_INSTRUCTION_CACHE_LINE_16B
cache_line_size = CACHE_LINE_SIZE_16B;
#else
cache_line_size = CACHE_LINE_SIZE_32B;
#endif
ESP_EARLY_LOGI(TAG, "Instruction cache \t: size %dKB, %dWays, cache line size %dByte", cache_size == CACHE_SIZE_8KB ? 8 : 16, 4, cache_line_size == CACHE_LINE_SIZE_16B ? 16 : 32);
Cache_Suspend_ICache();
Cache_Set_ICache_Mode(cache_size, cache_ways, cache_line_size);
Cache_Invalidate_ICache_All();
Cache_Resume_ICache(0);
}
IRAM_ATTR void esp_config_data_cache_mode(void)
{
#define CACHE_SIZE_0KB 99 //If Cache set to 0 KB, cache is bypassed, the cache size doesn't take into effect. Set this macro to a unique value for log
cache_size_t cache_size;
cache_ways_t cache_ways;
cache_line_size_t cache_line_size;
#if CONFIG_ESP32S2_INSTRUCTION_CACHE_8KB
#if CONFIG_ESP32S2_DATA_CACHE_0KB
Cache_Allocate_SRAM(CACHE_MEMORY_ICACHE_LOW, CACHE_MEMORY_INVALID, CACHE_MEMORY_INVALID, CACHE_MEMORY_INVALID);
cache_size = CACHE_SIZE_0KB;
#elif CONFIG_ESP32S2_DATA_CACHE_8KB
Cache_Allocate_SRAM(CACHE_MEMORY_ICACHE_LOW, CACHE_MEMORY_DCACHE_LOW, CACHE_MEMORY_INVALID, CACHE_MEMORY_INVALID);
cache_size = CACHE_SIZE_8KB;
#else
Cache_Allocate_SRAM(CACHE_MEMORY_ICACHE_LOW, CACHE_MEMORY_DCACHE_LOW, CACHE_MEMORY_DCACHE_HIGH, CACHE_MEMORY_INVALID);
cache_size = CACHE_SIZE_16KB;
#endif
#else
#if CONFIG_ESP32S2_DATA_CACHE_0KB
Cache_Allocate_SRAM(CACHE_MEMORY_ICACHE_LOW, CACHE_MEMORY_ICACHE_HIGH, CACHE_MEMORY_INVALID, CACHE_MEMORY_INVALID);
cache_size = CACHE_SIZE_0KB;
#elif CONFIG_ESP32S2_DATA_CACHE_8KB
Cache_Allocate_SRAM(CACHE_MEMORY_ICACHE_LOW, CACHE_MEMORY_ICACHE_HIGH, CACHE_MEMORY_DCACHE_LOW, CACHE_MEMORY_INVALID);
cache_size = CACHE_SIZE_8KB;
#else
Cache_Allocate_SRAM(CACHE_MEMORY_ICACHE_LOW, CACHE_MEMORY_ICACHE_HIGH, CACHE_MEMORY_DCACHE_LOW, CACHE_MEMORY_DCACHE_HIGH);
cache_size = CACHE_SIZE_16KB;
#endif
#endif
cache_ways = CACHE_4WAYS_ASSOC;
#if CONFIG_ESP32S2_DATA_CACHE_LINE_16B
cache_line_size = CACHE_LINE_SIZE_16B;
#else
cache_line_size = CACHE_LINE_SIZE_32B;
#endif
ESP_EARLY_LOGI(TAG, "Data cache \t\t: size %dKB, %dWays, cache line size %dByte", (cache_size == CACHE_SIZE_0KB) ? 0 : ((cache_size == CACHE_SIZE_8KB) ? 8 : 16), 4, cache_line_size == CACHE_LINE_SIZE_16B ? 16 : 32);
Cache_Set_DCache_Mode(cache_size, cache_ways, cache_line_size);
Cache_Invalidate_DCache_All();
}
static IRAM_ATTR void esp_enable_cache_flash_wrap(bool icache, bool dcache)
{
uint32_t i_autoload, d_autoload;
if (icache) {
i_autoload = Cache_Suspend_ICache();
}
if (dcache) {
d_autoload = Cache_Suspend_DCache();
}
REG_SET_BIT(EXTMEM_PRO_CACHE_WRAP_AROUND_CTRL_REG, EXTMEM_PRO_CACHE_FLASH_WRAP_AROUND);
if (icache) {
Cache_Resume_ICache(i_autoload);
}
if (dcache) {
Cache_Resume_DCache(d_autoload);
}
}
#if (CONFIG_IDF_TARGET_ESP32S2 && CONFIG_SPIRAM)
static IRAM_ATTR void esp_enable_cache_spiram_wrap(bool icache, bool dcache)
{
uint32_t i_autoload, d_autoload;
if (icache) {
i_autoload = Cache_Suspend_ICache();
}
if (dcache) {
d_autoload = Cache_Suspend_DCache();
}
REG_SET_BIT(EXTMEM_PRO_CACHE_WRAP_AROUND_CTRL_REG, EXTMEM_PRO_CACHE_SRAM_RD_WRAP_AROUND);
if (icache) {
Cache_Resume_ICache(i_autoload);
}
if (dcache) {
Cache_Resume_DCache(d_autoload);
}
}
#endif
esp_err_t esp_enable_cache_wrap(bool icache_wrap_enable, bool dcache_wrap_enable)
{
int icache_wrap_size = 0, dcache_wrap_size = 0;
int flash_wrap_sizes[2] = {-1, -1}, spiram_wrap_sizes[2] = {-1, -1};
int flash_wrap_size = 0, spiram_wrap_size = 0;
int flash_count = 0, spiram_count = 0;
int i;
bool flash_spiram_wrap_together, flash_support_wrap = true, spiram_support_wrap = true;
uint32_t drom0_in_icache = 1;//always 1 in esp32s2
#if CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32P4 || CONFIG_IDF_TARGET_ESP32C61 //TODO: IDF-4307
drom0_in_icache = 0;
#endif
if (icache_wrap_enable) {
#if CONFIG_ESP32S2_INSTRUCTION_CACHE_LINE_16B || CONFIG_ESP32S3_INSTRUCTION_CACHE_LINE_16B
icache_wrap_size = FLASH_WRAP_SIZE_16B;
#else
icache_wrap_size = FLASH_WRAP_SIZE_32B;
#endif
}
if (dcache_wrap_enable) {
#if CONFIG_ESP32S2_DATA_CACHE_LINE_16B || CONFIG_ESP32S3_DATA_CACHE_LINE_16B
dcache_wrap_size = FLASH_WRAP_SIZE_16B;
#else
dcache_wrap_size = FLASH_WRAP_SIZE_32B;
#endif
}
uint32_t instruction_use_spiram = 0;
uint32_t rodata_use_spiram = 0;
#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS
extern uint32_t esp_spiram_instruction_access_enabled(void);
instruction_use_spiram = esp_spiram_instruction_access_enabled();
#endif
#if CONFIG_SPIRAM_RODATA
extern uint32_t esp_spiram_rodata_access_enabled(void);
rodata_use_spiram = esp_spiram_rodata_access_enabled();
#endif
if (instruction_use_spiram) {
spiram_wrap_sizes[0] = icache_wrap_size;
} else {
flash_wrap_sizes[0] = icache_wrap_size;
}
if (rodata_use_spiram) {
if (drom0_in_icache) {
spiram_wrap_sizes[0] = icache_wrap_size;
} else {
spiram_wrap_sizes[1] = dcache_wrap_size;
flash_wrap_sizes[1] = dcache_wrap_size;
}
} else {
if (drom0_in_icache) {
flash_wrap_sizes[0] = icache_wrap_size;
} else {
flash_wrap_sizes[1] = dcache_wrap_size;
}
}
#if (CONFIG_IDF_TARGET_ESP32S2 && CONFIG_SPIRAM)
spiram_wrap_sizes[1] = dcache_wrap_size;
#endif
for (i = 0; i < 2; i++) {
if (flash_wrap_sizes[i] != -1) {
flash_count++;
flash_wrap_size = flash_wrap_sizes[i];
}
}
for (i = 0; i < 2; i++) {
if (spiram_wrap_sizes[i] != -1) {
spiram_count++;
spiram_wrap_size = spiram_wrap_sizes[i];
}
}
if (flash_count + spiram_count <= 2) {
flash_spiram_wrap_together = false;
} else {
flash_spiram_wrap_together = true;
}
ESP_EARLY_LOGI(TAG, "flash_count=%d, size=%d, spiram_count=%d, size=%d,together=%d", flash_count, flash_wrap_size, spiram_count, spiram_wrap_size, flash_spiram_wrap_together);
if (flash_count > 1 && flash_wrap_sizes[0] != flash_wrap_sizes[1]) {
ESP_EARLY_LOGW(TAG, "Flash wrap with different length %d and %d, abort wrap.", flash_wrap_sizes[0], flash_wrap_sizes[1]);
if (spiram_wrap_size == 0) {
return ESP_FAIL;
}
if (flash_spiram_wrap_together) {
ESP_EARLY_LOGE(TAG, "Abort spiram wrap because flash wrap length not fixed.");
return ESP_FAIL;
}
}
if (spiram_count > 1 && spiram_wrap_sizes[0] != spiram_wrap_sizes[1]) {
ESP_EARLY_LOGW(TAG, "SPIRAM wrap with different length %d and %d, abort wrap.", spiram_wrap_sizes[0], spiram_wrap_sizes[1]);
if (flash_wrap_size == 0) {
return ESP_FAIL;
}
if (flash_spiram_wrap_together) {
ESP_EARLY_LOGW(TAG, "Abort flash wrap because spiram wrap length not fixed.");
return ESP_FAIL;
}
}
if (flash_spiram_wrap_together && flash_wrap_size != spiram_wrap_size) {
ESP_EARLY_LOGW(TAG, "SPIRAM has different wrap length with flash, %d and %d, abort wrap.", spiram_wrap_size, flash_wrap_size);
return ESP_FAIL;
}
#ifdef CONFIG_ESPTOOLPY_FLASHMODE_QIO
flash_support_wrap = true;
spi_flash_wrap_probe();
if (!spi_flash_support_wrap_size(flash_wrap_size)) {
flash_support_wrap = false;
ESP_EARLY_LOGW(TAG, "Flash do not support wrap size %d.", flash_wrap_size);
}
#else
ESP_EARLY_LOGW(TAG, "Flash is not in QIO mode, do not support wrap.");
#endif
#if (CONFIG_IDF_TARGET_ESP32S2 && CONFIG_SPIRAM)
extern bool psram_support_wrap_size(uint32_t wrap_size);
if (!psram_support_wrap_size(spiram_wrap_size)) {
spiram_support_wrap = false;
ESP_EARLY_LOGW(TAG, "SPIRAM do not support wrap size %d.", spiram_wrap_size);
}
#endif
if (flash_spiram_wrap_together && !(flash_support_wrap && spiram_support_wrap)) {
ESP_EARLY_LOGW(TAG, "Flash and SPIRAM should support wrap together.");
return ESP_FAIL;
}
if (flash_support_wrap && flash_wrap_size > 0) {
ESP_EARLY_LOGI(TAG, "Flash wrap enabled, size = %d.", flash_wrap_size);
spi_flash_wrap_enable(flash_wrap_size);
esp_enable_cache_flash_wrap((flash_wrap_sizes[0] > 0), (flash_wrap_sizes[1] > 0));
}
#if (CONFIG_IDF_TARGET_ESP32S2 && CONFIG_SPIRAM)
extern esp_err_t psram_enable_wrap(uint32_t wrap_size);
if (spiram_support_wrap && spiram_wrap_size > 0) {
ESP_EARLY_LOGI(TAG, "SPIRAM wrap enabled, size = %d.", spiram_wrap_size);
psram_enable_wrap(spiram_wrap_size);
esp_enable_cache_spiram_wrap((spiram_wrap_sizes[0] > 0), (spiram_wrap_sizes[1] > 0));
}
#endif
return ESP_OK;
}
#endif
#if CONFIG_IDF_TARGET_ESP32S3
IRAM_ATTR void esp_config_instruction_cache_mode(void)
{
cache_size_t cache_size;
cache_ways_t cache_ways;
cache_line_size_t cache_line_size;
#if CONFIG_ESP32S3_INSTRUCTION_CACHE_16KB
Cache_Occupy_ICache_MEMORY(CACHE_MEMORY_IBANK0, CACHE_MEMORY_INVALID);
cache_size = CACHE_SIZE_HALF;
#else
Cache_Occupy_ICache_MEMORY(CACHE_MEMORY_IBANK0, CACHE_MEMORY_IBANK1);
cache_size = CACHE_SIZE_FULL;
#endif
#if CONFIG_ESP32S3_INSTRUCTION_CACHE_4WAYS
cache_ways = CACHE_4WAYS_ASSOC;
#else
cache_ways = CACHE_8WAYS_ASSOC;
#endif
#if CONFIG_ESP32S3_INSTRUCTION_CACHE_LINE_16B
cache_line_size = CACHE_LINE_SIZE_16B;
#elif CONFIG_ESP32S3_INSTRUCTION_CACHE_LINE_32B
cache_line_size = CACHE_LINE_SIZE_32B;
#else
cache_line_size = CACHE_LINE_SIZE_64B;
#endif
ESP_EARLY_LOGI(TAG, "Instruction cache: size %dKB, %dWays, cache line size %dByte", cache_size == CACHE_SIZE_HALF ? 16 : 32, cache_ways == CACHE_4WAYS_ASSOC ? 4 : 8, cache_line_size == CACHE_LINE_SIZE_16B ? 16 : (cache_line_size == CACHE_LINE_SIZE_32B ? 32 : 64));
Cache_Set_ICache_Mode(cache_size, cache_ways, cache_line_size);
Cache_Invalidate_ICache_All();
extern void Cache_Enable_ICache(uint32_t autoload);
Cache_Enable_ICache(0);
}
IRAM_ATTR void esp_config_data_cache_mode(void)
{
cache_size_t cache_size;
cache_ways_t cache_ways;
cache_line_size_t cache_line_size;
#if CONFIG_ESP32S3_DATA_CACHE_32KB
Cache_Occupy_DCache_MEMORY(CACHE_MEMORY_DBANK1, CACHE_MEMORY_INVALID);
cache_size = CACHE_SIZE_HALF;
#else
Cache_Occupy_DCache_MEMORY(CACHE_MEMORY_DBANK0, CACHE_MEMORY_DBANK1);
cache_size = CACHE_SIZE_FULL;
#endif
#if CONFIG_ESP32S3_DATA_CACHE_4WAYS
cache_ways = CACHE_4WAYS_ASSOC;
#else
cache_ways = CACHE_8WAYS_ASSOC;
#endif
#if CONFIG_ESP32S3_DATA_CACHE_LINE_16B
cache_line_size = CACHE_LINE_SIZE_16B;
#elif CONFIG_ESP32S3_DATA_CACHE_LINE_32B
cache_line_size = CACHE_LINE_SIZE_32B;
#else
cache_line_size = CACHE_LINE_SIZE_64B;
#endif
// ESP_EARLY_LOGI(TAG, "Data cache: size %dKB, %dWays, cache line size %dByte", cache_size == CACHE_SIZE_HALF ? 32 : 64, cache_ways == CACHE_4WAYS_ASSOC ? 4 : 8, cache_line_size == CACHE_LINE_SIZE_16B ? 16 : (cache_line_size == CACHE_LINE_SIZE_32B ? 32 : 64));
Cache_Set_DCache_Mode(cache_size, cache_ways, cache_line_size);
Cache_Invalidate_DCache_All();
}
static IRAM_ATTR void esp_enable_cache_flash_wrap(bool icache, bool dcache)
{
uint32_t i_autoload, d_autoload;
if (icache) {
i_autoload = Cache_Suspend_ICache();
}
if (dcache) {
d_autoload = Cache_Suspend_DCache();
}
REG_SET_BIT(EXTMEM_CACHE_WRAP_AROUND_CTRL_REG, EXTMEM_CACHE_FLASH_WRAP_AROUND);
if (icache) {
Cache_Resume_ICache(i_autoload);
}
if (dcache) {
Cache_Resume_DCache(d_autoload);
}
}
#if (CONFIG_IDF_TARGET_ESP32S3 && CONFIG_SPIRAM)
static IRAM_ATTR void esp_enable_cache_spiram_wrap(bool icache, bool dcache)
{
uint32_t i_autoload, d_autoload;
if (icache) {
i_autoload = Cache_Suspend_ICache();
}
if (dcache) {
d_autoload = Cache_Suspend_DCache();
}
REG_SET_BIT(EXTMEM_CACHE_WRAP_AROUND_CTRL_REG, EXTMEM_CACHE_SRAM_RD_WRAP_AROUND);
if (icache) {
Cache_Resume_ICache(i_autoload);
}
if (dcache) {
Cache_Resume_DCache(d_autoload);
}
}
#endif
esp_err_t esp_enable_cache_wrap(bool icache_wrap_enable, bool dcache_wrap_enable)
{
int icache_wrap_size = 0, dcache_wrap_size = 0;
int flash_wrap_sizes[2] = {-1, -1}, spiram_wrap_sizes[2] = {-1, -1};
int flash_wrap_size = 0, spiram_wrap_size = 0;
int flash_count = 0, spiram_count = 0;
int i;
bool flash_spiram_wrap_together, flash_support_wrap = false, spiram_support_wrap = true;
uint32_t drom0_in_icache = 0;//always 0 in chip7.2.4
if (icache_wrap_enable) {
#if CONFIG_ESP32S3_INSTRUCTION_CACHE_LINE_16B
icache_wrap_size = FLASH_WRAP_SIZE_16B;
#elif CONFIG_ESP32S3_INSTRUCTION_CACHE_LINE_32B
icache_wrap_size = FLASH_WRAP_SIZE_32B;
#else
icache_wrap_size = FLASH_WRAP_SIZE_64B;
#endif
}
if (dcache_wrap_enable) {
#if CONFIG_ESP32S3_DATA_CACHE_LINE_16B
dcache_wrap_size = FLASH_WRAP_SIZE_16B;
#elif CONFIG_ESP32S3_DATA_CACHE_LINE_32B
dcache_wrap_size = FLASH_WRAP_SIZE_32B;
#else
dcache_wrap_size = FLASH_WRAP_SIZE_64B;
#endif
}
uint32_t instruction_use_spiram = 0;
uint32_t rodata_use_spiram = 0;
#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS
extern uint32_t esp_spiram_instruction_access_enabled(void);
instruction_use_spiram = esp_spiram_instruction_access_enabled();
#endif
#if CONFIG_SPIRAM_RODATA
extern uint32_t esp_spiram_rodata_access_enabled(void);
rodata_use_spiram = esp_spiram_rodata_access_enabled();
#endif
if (instruction_use_spiram) {
spiram_wrap_sizes[0] = icache_wrap_size;
} else {
flash_wrap_sizes[0] = icache_wrap_size;
}
if (rodata_use_spiram) {
if (drom0_in_icache) {
spiram_wrap_sizes[0] = icache_wrap_size;
} else {
spiram_wrap_sizes[1] = dcache_wrap_size;
}
} else {
if (drom0_in_icache) {
flash_wrap_sizes[0] = icache_wrap_size;
} else {
flash_wrap_sizes[1] = dcache_wrap_size;
}
}
#if (CONFIG_IDF_TARGET_ESP32S3 && CONFIG_SPIRAM)
spiram_wrap_sizes[1] = dcache_wrap_size;
#endif
for (i = 0; i < 2; i++) {
if (flash_wrap_sizes[i] != -1) {
flash_count++;
flash_wrap_size = flash_wrap_sizes[i];
}
}
for (i = 0; i < 2; i++) {
if (spiram_wrap_sizes[i] != -1) {
spiram_count++;
spiram_wrap_size = spiram_wrap_sizes[i];
}
}
if (flash_count + spiram_count <= 2) {
flash_spiram_wrap_together = false;
} else {
flash_spiram_wrap_together = true;
}
if (flash_count > 1 && flash_wrap_sizes[0] != flash_wrap_sizes[1]) {
ESP_EARLY_LOGW(TAG, "Flash wrap with different length %d and %d, abort wrap.", flash_wrap_sizes[0], flash_wrap_sizes[1]);
if (spiram_wrap_size == 0) {
return ESP_FAIL;
}
if (flash_spiram_wrap_together) {
ESP_EARLY_LOGE(TAG, "Abort spiram wrap because flash wrap length not fixed.");
return ESP_FAIL;
}
}
if (spiram_count > 1 && spiram_wrap_sizes[0] != spiram_wrap_sizes[1]) {
ESP_EARLY_LOGW(TAG, "SPIRAM wrap with different length %d and %d, abort wrap.", spiram_wrap_sizes[0], spiram_wrap_sizes[1]);
if (flash_wrap_size == 0) {
return ESP_FAIL;
}
if (flash_spiram_wrap_together) {
ESP_EARLY_LOGW(TAG, "Abort flash wrap because spiram wrap length not fixed.");
return ESP_FAIL;
}
}
if (flash_spiram_wrap_together && flash_wrap_size != spiram_wrap_size) {
ESP_EARLY_LOGW(TAG, "SPIRAM has different wrap length with flash, %d and %d, abort wrap.", spiram_wrap_size, flash_wrap_size);
return ESP_FAIL;
}
#ifdef CONFIG_ESPTOOLPY_FLASHMODE_QIO
flash_support_wrap = true;
spi_flash_wrap_probe();
if (!spi_flash_support_wrap_size(flash_wrap_size)) {
flash_support_wrap = false;
ESP_EARLY_LOGW(TAG, "Flash do not support wrap size %d.", flash_wrap_size);
}
#else
ESP_EARLY_LOGW(TAG, "Flash is not in QIO mode, do not support wrap.");
#endif
#if (CONFIG_IDF_TARGET_ESP32S3 && CONFIG_SPIRAM)
extern bool psram_support_wrap_size(uint32_t wrap_size);
if (!psram_support_wrap_size(spiram_wrap_size)) {
spiram_support_wrap = false;
ESP_EARLY_LOGW(TAG, "SPIRAM do not support wrap size %d.", spiram_wrap_size);
}
#endif
if (flash_spiram_wrap_together && !(flash_support_wrap && spiram_support_wrap)) {
ESP_EARLY_LOGW(TAG, "Flash and SPIRAM should support wrap together.");
return ESP_FAIL;
}
if (flash_support_wrap && flash_wrap_size > 0) {
ESP_EARLY_LOGI(TAG, "Flash wrap enabled, size = %d.", flash_wrap_size);
spi_flash_wrap_enable(flash_wrap_size);
esp_enable_cache_flash_wrap((flash_wrap_sizes[0] > 0), (flash_wrap_sizes[1] > 0));
}
#if (CONFIG_IDF_TARGET_ESP32S3 && CONFIG_SPIRAM)
extern esp_err_t psram_enable_wrap(uint32_t wrap_size);
if (spiram_support_wrap && spiram_wrap_size > 0) {
ESP_EARLY_LOGI(TAG, "SPIRAM wrap enabled, size = %d.", spiram_wrap_size);
psram_enable_wrap(spiram_wrap_size);
esp_enable_cache_spiram_wrap((spiram_wrap_sizes[0] > 0), (spiram_wrap_sizes[1] > 0));
}
#endif
return ESP_OK;
}
#endif
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C2
static IRAM_ATTR void esp_enable_cache_flash_wrap(bool icache)
{
uint32_t i_autoload;
if (icache) {
i_autoload = Cache_Suspend_ICache();
}
REG_SET_BIT(EXTMEM_CACHE_WRAP_AROUND_CTRL_REG, EXTMEM_CACHE_FLASH_WRAP_AROUND);
if (icache) {
Cache_Resume_ICache(i_autoload);
}
}
esp_err_t esp_enable_cache_wrap(bool icache_wrap_enable)
{
int flash_wrap_size = 0;
bool flash_support_wrap = false;
if (icache_wrap_enable) {
flash_wrap_size = 32;
}
#ifdef CONFIG_ESPTOOLPY_FLASHMODE_QIO
flash_support_wrap = true;
spi_flash_wrap_probe();
if (!spi_flash_support_wrap_size(flash_wrap_size)) {
flash_support_wrap = false;
ESP_EARLY_LOGW(TAG, "Flash do not support wrap size %d.", flash_wrap_size);
}
#else
ESP_EARLY_LOGW(TAG, "Flash is not in QIO mode, do not support wrap.");
#endif // CONFIG_ESPTOOLPY_FLASHMODE_QIO
if (flash_support_wrap && flash_wrap_size > 0) {
ESP_EARLY_LOGI(TAG, "Flash wrap enabled, size = %d.", flash_wrap_size);
spi_flash_wrap_enable(flash_wrap_size);
esp_enable_cache_flash_wrap((flash_wrap_size > 0));
}
return ESP_OK;
}
#endif // CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C2

View File

@@ -1,185 +0,0 @@
/*
* SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include "esp_flash_chips/spi_flash_defs.h"
//MXIC OPI mode needs two bytes of command - 2nd byte is the inversion of the command (1st) byte. S3 HW send LSB first
#define MXIC_CMD16(cmd8) ( (uint8_t)(cmd8) | ((uint8_t)(~(cmd8)) << 8) )
#define OPI_CMD_FORMAT_MXIC_STR() { \
.rdid = { \
.mode = ESP_ROM_SPIFLASH_OPI_STR_MODE, \
.cmd_bit_len = 16, \
.cmd = MXIC_CMD16(CMD_RDID), \
.addr = 0, \
.addr_bit_len = 4*8, \
.dummy_bit_len = 4, \
.data_bit_len = 4 * 8, \
.cs_sel = 0x1, \
.is_pe = 0, \
}, \
.rdsr = { \
.mode = ESP_ROM_SPIFLASH_OPI_STR_MODE, \
.cmd_bit_len = 16, \
.cmd = MXIC_CMD16(CMD_RDSR), \
.addr = 0, \
.addr_bit_len = 4*8, \
.dummy_bit_len = 4, \
.data_bit_len = 1 * 8, \
.cs_sel = 0x1, \
.is_pe = 0, \
}, \
.wren = { \
.mode = ESP_ROM_SPIFLASH_OPI_STR_MODE, \
.cmd_bit_len = 16, \
.cmd = MXIC_CMD16(CMD_WREN), \
.addr = 0, \
.addr_bit_len = 0, \
.dummy_bit_len = 0, \
.data_bit_len = 0, \
.cs_sel = 0x1, \
.is_pe = 0, \
}, \
.se = { \
.mode = ESP_ROM_SPIFLASH_OPI_STR_MODE, \
.cmd_bit_len = 16, \
.cmd = MXIC_CMD16(CMD_SECTOR_ERASE_4B), \
.addr = 0, \
.addr_bit_len = 32, \
.dummy_bit_len = 0, \
.data_bit_len = 0, \
.cs_sel = 0x1, \
.is_pe = 1, \
}, \
.be64k = { \
.mode = ESP_ROM_SPIFLASH_OPI_STR_MODE, \
.cmd_bit_len = 16, \
.cmd = MXIC_CMD16(CMD_LARGE_BLOCK_ERASE_4B), \
.addr = 0, \
.addr_bit_len = 32, \
.dummy_bit_len = 0, \
.data_bit_len = 0, \
.cs_sel = 0x1, \
.is_pe = 1, \
}, \
.read = { \
.mode = ESP_ROM_SPIFLASH_OPI_STR_MODE, \
.cmd_bit_len = 16, \
.cmd = MXIC_CMD16(CMD_8READ), \
.addr = 0, \
.addr_bit_len = 32, \
.dummy_bit_len = 20, \
.data_bit_len = 0, \
.cs_sel = 0x1, \
.is_pe = 0, \
}, \
.pp = { \
.mode = ESP_ROM_SPIFLASH_OPI_STR_MODE, \
.cmd_bit_len = 16, \
.cmd = MXIC_CMD16(CMD_PROGRAM_PAGE_4B), \
.addr = 0, \
.addr_bit_len = 32, \
.dummy_bit_len = 0, \
.data_bit_len = 0, \
.cs_sel = 0x1, \
.is_pe = 1, \
}, \
.cache_rd_cmd = { \
.addr_bit_len = 32, \
.dummy_bit_len = 20, \
.cmd = MXIC_CMD16(CMD_8READ), \
.cmd_bit_len = 16, \
.var_dummy_en = 1, \
} \
}
#define OPI_CMD_FORMAT_MXIC_DTR() { \
.rdid = { \
.mode = ESP_ROM_SPIFLASH_OPI_DTR_MODE, \
.cmd_bit_len = 16, \
.cmd = MXIC_CMD16(CMD_RDID), \
.addr = 0, \
.addr_bit_len = 4*8, \
.dummy_bit_len = 4*2, \
.data_bit_len = 4 * 8, \
.cs_sel = 0x1, \
.is_pe = 0, \
}, \
.rdsr = { \
.mode = ESP_ROM_SPIFLASH_OPI_DTR_MODE, \
.cmd_bit_len = 16, \
.cmd = MXIC_CMD16(CMD_RDSR), \
.addr = 0, \
.addr_bit_len = 4*8, \
.dummy_bit_len = 4*2, \
.data_bit_len = 2 * 8, \
.cs_sel = 0x1, \
.is_pe = 0, \
}, \
.wren = { \
.mode = ESP_ROM_SPIFLASH_OPI_DTR_MODE, \
.cmd_bit_len = 16, \
.cmd = MXIC_CMD16(CMD_WREN), \
.addr = 0, \
.addr_bit_len = 0, \
.dummy_bit_len = 0, \
.data_bit_len = 0, \
.cs_sel = 0x1, \
.is_pe = 0, \
}, \
.se = { \
.mode = ESP_ROM_SPIFLASH_OPI_DTR_MODE, \
.cmd_bit_len = 16, \
.cmd = MXIC_CMD16(CMD_SECTOR_ERASE_4B), \
.addr = 0, \
.addr_bit_len = 32, \
.dummy_bit_len = 0, \
.data_bit_len = 0, \
.cs_sel = 0x1, \
.is_pe = 1, \
}, \
.be64k = { \
.mode = ESP_ROM_SPIFLASH_OPI_DTR_MODE, \
.cmd_bit_len = 16, \
.cmd = MXIC_CMD16(CMD_LARGE_BLOCK_ERASE_4B), \
.addr = 0, \
.addr_bit_len = 32, \
.dummy_bit_len = 0, \
.data_bit_len = 0, \
.cs_sel = 0x1, \
.is_pe = 1, \
}, \
.read = { \
.mode = ESP_ROM_SPIFLASH_OPI_DTR_MODE, \
.cmd_bit_len = 16, \
.cmd = MXIC_CMD16(CMD_8DTRD), \
.addr = 0, \
.addr_bit_len = 32, \
.dummy_bit_len = 20*2, \
.data_bit_len = 0, \
.cs_sel = 0x1, \
.is_pe = 0, \
}, \
.pp = { \
.mode = ESP_ROM_SPIFLASH_OPI_DTR_MODE, \
.cmd_bit_len = 16, \
.cmd = MXIC_CMD16(CMD_PROGRAM_PAGE_4B), \
.addr = 0, \
.addr_bit_len = 32, \
.dummy_bit_len = 0, \
.data_bit_len = 0, \
.cs_sel = 0x1, \
.is_pe = 1, \
}, \
.cache_rd_cmd = { \
.addr_bit_len = 32, \
.dummy_bit_len = 20*2, \
.cmd = MXIC_CMD16(CMD_8DTRD), \
.cmd_bit_len = 16, \
.var_dummy_en = 1, \
} \
}

View File

@@ -1,36 +0,0 @@
/*
* SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* System level OPI Flash APIs (private)
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "sdkconfig.h"
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Register ROM functions and init flash device registers to make use of octal flash
*
* @param chip_id Full device ID read via RDID command
*/
esp_err_t esp_opiflash_init(uint32_t chip_id);
/**
* @brief Set Octal Flash chip specifically required MSPI register settings here
*/
void esp_opiflash_set_required_regs(void);
#ifdef __cplusplus
}
#endif

View File

@@ -1,306 +0,0 @@
/*
* SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "sdkconfig.h"
#include "esp_log.h"
#include "esp_err.h"
#include "esp32s3/rom/spi_flash.h"
#include "esp32s3/rom/opi_flash.h"
#include "esp_private/spi_flash_os.h"
#include "opi_flash_private.h"
#include "soc/spi_mem_reg.h"
#include "soc/io_mux_reg.h"
#include "opi_flash_cmd_format_mxic.h"
#define SPI_FLASH_SPI_CMD_WRCR2 0x72
#define SPI_FLASH_SPI_CMD_RDSR 0x05
#define SPI_FLASH_SPI_CMD_RDCR 0x15
#define SPI_FLASH_SPI_CMD_WRSRCR 0x01
#define SPI_FLASH_SPI_CMD_RDSFDP 0x5A
/**
* Supported Flash chip vendor id
*/
#define ESP_FLASH_CHIP_MXIC_OCT 0xC2
const static char *TAG = "Octal Flash";
// default value is rom_default_spiflash_legacy_flash_func
extern const spiflash_legacy_funcs_t *rom_spiflash_legacy_funcs;
static uint32_t s_chip_id;
static void s_register_rom_function(void)
{
static spiflash_legacy_funcs_t rom_func =
{
.read_sub_len = 32,
.write_sub_len = 32,
.unlock = esp_rom_opiflash_wait_idle,
.erase_block = esp_rom_opiflash_erase_block_64k,
.erase_sector = esp_rom_opiflash_erase_sector,
.read = esp_rom_opiflash_read,
.write = esp_rom_opiflash_write,
.wait_idle = esp_rom_opiflash_wait_idle,
.wren = esp_rom_opiflash_wren,
.erase_area = esp_rom_opiflash_erase_area,
};
rom_spiflash_legacy_funcs = &rom_func;
}
#if CONFIG_SPI_FLASH_SUPPORT_MXIC_OPI_CHIP
/*----------------------------------------------------------------------------------------------------
MXIC Specific Functions
-----------------------------------------------------------------------------------------------------*/
static esp_err_t s_probe_mxic_chip(uint32_t chip_id, uint8_t *out_vendor_id)
{
if (chip_id >> 16 != ESP_FLASH_CHIP_MXIC_OCT) {
return ESP_ERR_NOT_FOUND;
}
if (((chip_id >> 8) & 0xf0) != 0x80) {
// We now suppose that middle id of opi flash is 0x8*.
ESP_EARLY_LOGE(TAG, "Detected MXIC Flash, but memory type is not Octal");
return ESP_ERR_NOT_FOUND;
}
*out_vendor_id = ESP_FLASH_CHIP_MXIC_OCT;
return ESP_OK;
}
#if CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_DTR
static bool s_mxic_dtr_need_swap(void)
{
// This function is used for judging the data bytes whether need swap.
// For some of opi flash chips, the data bytes are ordered by D1-D0-D3-D2. This kinds of order needs swap.
// On the contrary, some opi flash chips order the data like D0-D1-D2-D3. This kinds of order doesn't need swap.
// Note: this function must be called when flash works under single line mode.
// 1. Send 0x5A to read SFDP regs for getting the first address of JEDEC Flash Parameter table.
// 2. Add offset with first address to get the order in 8D-8D-8D mode.
// 3. Judge whether the BIT(7) is 1, 1 stands for need swap, vice versa.
uint8_t JEDEC_first_address = 0;
uint8_t byte_order_val = 0;
uint8_t dummy = 8;
uint8_t cmd_len = 8;
uint8_t addr_len = 24;
uint8_t miso_bit_len = 8;
esp_rom_opiflash_exec_cmd(1, ESP_ROM_SPIFLASH_FASTRD_MODE,
SPI_FLASH_SPI_CMD_RDSFDP, cmd_len,
0x0C, addr_len,
dummy,
NULL, 0,
(uint8_t*)&JEDEC_first_address, miso_bit_len,
ESP_ROM_OPIFLASH_SEL_CS0,
false);
esp_rom_opiflash_exec_cmd(1, ESP_ROM_SPIFLASH_FASTRD_MODE,
SPI_FLASH_SPI_CMD_RDSFDP, cmd_len,
(JEDEC_first_address + 0x47), addr_len,
dummy,
NULL, 0,
(uint8_t*)&byte_order_val, miso_bit_len,
ESP_ROM_OPIFLASH_SEL_CS0,
false);
return ((byte_order_val & 0x80) == 0x80) ? true : false;
}
#endif // CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_DTR
// 0x00: SPI; 0x01: STR OPI; 0x02: DTR OPI
static void s_set_flash_dtr_str_opi_mode(int spi_num, uint8_t val)
{
uint8_t cmd_len = 8;
int addr_bit_len = 32;
int dummy = 0;
int data_bit_len = 8;
esp_rom_spiflash_write_enable(&g_rom_flashchip);
//SPI command, WRCR2
esp_rom_opiflash_exec_cmd(spi_num, ESP_ROM_SPIFLASH_FASTRD_MODE,
SPI_FLASH_SPI_CMD_WRCR2, cmd_len,
0, addr_bit_len,
dummy,
(uint8_t *)&val, data_bit_len,
NULL, 0,
ESP_ROM_OPIFLASH_SEL_CS0,
false);
}
//To set the output driver strength
static void s_set_flash_ouput_driver_strength(int spi_num, uint8_t strength)
{
uint16_t reg_val = 0;
uint8_t sr_reg_val = 0;
uint8_t cr_reg_val = 0;
uint8_t cmd_len = 8;
uint32_t addr = 0;
int addr_bit_len = 0;
int dummy = 0;
int data_bit_len = 8;
//Read
//SPI command, RDSR
esp_rom_opiflash_exec_cmd(spi_num, ESP_ROM_SPIFLASH_FASTRD_MODE,
SPI_FLASH_SPI_CMD_RDSR, cmd_len,
addr, addr_bit_len,
dummy,
NULL, 0,
(uint8_t*)&sr_reg_val, data_bit_len,
ESP_ROM_OPIFLASH_SEL_CS0,
false);
//SPI command, RDCR
esp_rom_opiflash_exec_cmd(spi_num, ESP_ROM_SPIFLASH_FASTRD_MODE,
SPI_FLASH_SPI_CMD_RDCR, cmd_len,
addr, addr_bit_len,
dummy,
NULL, 0,
(uint8_t*)&cr_reg_val, data_bit_len,
ESP_ROM_OPIFLASH_SEL_CS0,
false);
//Modify
reg_val = (((cr_reg_val & 0xf8) | strength) << 8) | sr_reg_val;
//Write
//SPI command, WRSR/WRCR
data_bit_len = 16;
esp_rom_spiflash_write_enable(&g_rom_flashchip);
esp_rom_opiflash_exec_cmd(spi_num, ESP_ROM_SPIFLASH_FASTRD_MODE,
SPI_FLASH_SPI_CMD_WRSRCR, cmd_len,
addr, addr_bit_len,
dummy,
(uint8_t*)&reg_val, data_bit_len,
NULL, 0,
ESP_ROM_OPIFLASH_SEL_CS0,
false);
}
static void s_set_pin_drive_capability(uint8_t drv)
{
//flash clock
REG_SET_FIELD(SPI_MEM_DATE_REG(0), SPI_MEM_SPI_FMEM_SPICLK_FUN_DRV, 3);
//cs0
PIN_SET_DRV(IO_MUX_GPIO29_REG, 3);
}
static void s_flash_init_mxic(esp_rom_spiflash_read_mode_t mode)
{
#if CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_STR
static const esp_rom_opiflash_def_t opiflash_cmd_def_mxic = OPI_CMD_FORMAT_MXIC_STR();
#elif CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_DTR
static const esp_rom_opiflash_def_t opiflash_cmd_def_mxic = OPI_CMD_FORMAT_MXIC_DTR();
#endif
esp_rom_opiflash_legacy_driver_init(&opiflash_cmd_def_mxic);
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
// increase flash output driver strength
s_set_flash_ouput_driver_strength(1, 7);
// STR/DTR specific setting
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
#if CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_STR
s_set_pin_drive_capability(3);
s_set_flash_dtr_str_opi_mode(1, 0x1);
esp_rom_spiflash_cache_mode_config(mode, &rom_opiflash_cmd_def->cache_rd_cmd);
esp_rom_spi_set_dtr_swap_mode(0, false, false);
esp_rom_spi_set_dtr_swap_mode(1, false, false);
#else //CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_DTR
s_set_pin_drive_capability(3);
bool need_swap = s_mxic_dtr_need_swap();
s_set_flash_dtr_str_opi_mode(1, 0x2);
esp_rom_spiflash_cache_mode_config(mode, &rom_opiflash_cmd_def->cache_rd_cmd);
esp_rom_spi_set_dtr_swap_mode(0, need_swap, need_swap);
esp_rom_spi_set_dtr_swap_mode(1, need_swap, need_swap);
#endif
esp_rom_opiflash_wait_idle();
}
#endif // #if CONFIG_SPI_FLASH_SUPPORT_MXIC_OPI_CHIP
#if CONFIG_SPI_FLASH_SUPPORT_MXIC_OPI_CHIP
static void s_mxic_set_required_regs(uint32_t chip_id)
{
bool is_swap = false;
#if CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_DTR
is_swap = true;
#else
//STR mode does not need to enable ddr_swap registers
#endif
esp_rom_spi_set_dtr_swap_mode(0, is_swap, is_swap);
esp_rom_spi_set_dtr_swap_mode(1, is_swap, is_swap);
}
#endif
/*----------------------------------------------------------------------------------------------------
General Functions
-----------------------------------------------------------------------------------------------------*/
typedef struct opi_flash_func_t {
esp_err_t (*probe)(uint32_t flash_id, uint8_t *out_vendor_id); //Function pointer for detecting Flash chip vendor
void (*init)(esp_rom_spiflash_read_mode_t mode); //Function pointer for initialising certain Flash chips
void (*regs_set)(uint32_t flash_id); //Function pointer for setting required registers, decided by certain flash chips.
} opi_flash_func_t;
#if CONFIG_SPI_FLASH_SUPPORT_MXIC_OPI_CHIP
static const opi_flash_func_t opi_flash_func_mxic = {
.probe = &s_probe_mxic_chip,
.init = &s_flash_init_mxic,
.regs_set = &s_mxic_set_required_regs,
};
#endif
static const opi_flash_func_t *registered_chip_funcs[] = {
#if CONFIG_SPI_FLASH_SUPPORT_MXIC_OPI_CHIP
&opi_flash_func_mxic,
#endif
NULL,
};
//To check which Flash chip is used
static const opi_flash_func_t **s_chip_func = NULL;
esp_err_t esp_opiflash_init(uint32_t chip_id)
{
esp_err_t ret = ESP_FAIL;
esp_rom_spiflash_read_mode_t mode;
#if CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_STR
mode = ESP_ROM_SPIFLASH_OPI_STR_MODE;
#elif CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_DTR
mode = ESP_ROM_SPIFLASH_OPI_DTR_MODE;
#else
mode = ESP_ROM_SPIFLASH_FASTRD_MODE;
#endif
const opi_flash_func_t **chip_func = &registered_chip_funcs[0];
uint8_t vendor_id = 0;
while (*chip_func) {
ret = (*chip_func)->probe(chip_id, &vendor_id);
if (ret == ESP_OK) {
// Detect this is the supported chip type
s_chip_id = chip_id;
(*chip_func)->init(mode);
s_register_rom_function();
break;
}
chip_func++;
}
s_chip_func = chip_func;
if (ret != ESP_OK) {
ESP_EARLY_LOGE(TAG, "No detected Flash chip, please check the menuconfig to see if the chip is supported");
abort();
}
return ESP_OK;
}
/**
* Add Flash chip specifically required MSPI register settings here
*/
void esp_opiflash_set_required_regs(void)
{
(*s_chip_func)->regs_set(s_chip_id);
}

View File

@@ -24,8 +24,9 @@
#include "esp_flash_chips/spi_flash_chip_driver.h"
#include "esp_private/memspi_host_driver.h"
#include "esp_private/esp_flash_internal.h"
#include "esp_flash_chips/spi_flash_defs.h"
#include "spi_flash_defs.h"
#include "spi_flash_mmap.h"
#include "esp_flash.h"
#if CONFIG_IDF_TARGET_ESP32S2
#include "esp_crypto_lock.h" // for locking flash encryption peripheral

View File

@@ -21,7 +21,6 @@
#include "esp_private/startup_internal.h"
#include "esp_spi_flash_counters.h"
#include "esp_rom_spiflash.h"
#include "bootloader_flash.h"
#include "esp_check.h"
#include "esp_private/esp_clk_tree_common.h"
#include "esp_clk_tree.h"
@@ -33,6 +32,7 @@
#include "esp_flash.h"
#include "esp_flash_spi_init.h"
#include "esp_flash_chips/spi_flash_chip_driver.h"
#include "esp_flash_chips/esp_flash_types.h"
#include "esp_private/memspi_host_driver.h"
#include "esp_private/esp_flash_internal.h"
#include "esp_private/spi_flash_os.h"
@@ -472,7 +472,7 @@ static DRAM_ATTR esp_flash_t default_chip = {
static void s_esp_flash_choose_correct_mode(memspi_host_config_t *cfg)
{
static const char *mode = FLASH_MODE_STRING;
if (bootloader_flash_is_octal_mode_enabled()) {
if (spi_flash_is_octal_mode_enabled()) {
#if !CONFIG_ESPTOOLPY_FLASHMODE_OPI
ESP_EARLY_LOGW(TAG, "Octal flash chip is using but %s mode is selected, will automatically switch to Octal mode", mode);
cfg->octal_mode_en = 1;
@@ -663,6 +663,7 @@ ESP_SYSTEM_INIT_FN(init_flash, CORE, BIT(0), 130)
esp_mspi_register_isr(NULL);
#endif
//else register flash standalone ISR to deal with CPU / API flash access
return ESP_OK;
}
#endif // !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP

View File

@@ -1,39 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <stdbool.h>
#include "esp_attr.h"
#include "sdkconfig.h"
#include "esp_rom_spiflash.h"
#if CONFIG_SPI_FLASH_BROWNOUT_RESET
static bool flash_brownout_needs_reset = false;
static bool flash_erasing = false;
// This function could be called in startup
void spi_flash_needs_reset_check(void)
{
// Currently only XMC is suggested to reset when brownout
#if CONFIG_SPI_FLASH_BROWNOUT_RESET_XMC
if ((g_rom_flashchip.device_id >> 16) == 0x20) {
flash_brownout_needs_reset = true;
}
#endif
}
void spi_flash_set_erasing_flag(bool status)
{
flash_erasing = status;
}
bool spi_flash_brownout_need_reset(void)
{
return (flash_brownout_needs_reset && flash_erasing);
}
#endif //CONFIG_SPI_FLASH_BROWNOUT_RESET

View File

@@ -1,325 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <sys/param.h> // For MIN/MAX(a, b)
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/semphr.h>
#include <soc/soc.h>
#include <soc/soc_memory_layout.h>
#include "soc/io_mux_reg.h"
#include "soc/spi_pins.h"
#include "sdkconfig.h"
#include "esp_attr.h"
#include "esp_cpu.h"
#include "spi_flash_mmap.h"
#include "esp_log.h"
#include "esp_private/system_internal.h"
#include "esp_private/spi_flash_os.h"
#include "esp_private/esp_clk.h"
#include "esp_private/esp_gpio_reserve.h"
#if CONFIG_IDF_TARGET_ESP32
#include "esp32/rom/cache.h"
#include "esp32/rom/spi_flash.h"
#elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/rom/cache.h"
#elif CONFIG_IDF_TARGET_ESP32S3
#include "soc/spi_mem_reg.h"
#include "esp32s3/rom/opi_flash.h"
#include "esp32s3/rom/cache.h"
#include "esp32s3/opi_flash_private.h"
#elif CONFIG_IDF_TARGET_ESP32C3
#include "esp32c3/rom/cache.h"
#elif CONFIG_IDF_TARGET_ESP32C2
#include "esp32c2/rom/cache.h"
#elif CONFIG_IDF_TARGET_ESP32C6
#include "esp32c6/rom/cache.h"
#elif CONFIG_IDF_TARGET_ESP32C61
#include "esp32c61/rom/cache.h"
#endif
#include "esp_rom_spiflash.h"
#include "esp_flash_partitions.h"
#include "esp_private/mspi_timing_tuning.h"
#include "esp_private/cache_utils.h"
#include "esp_flash.h"
#include "esp_attr.h"
#include "bootloader_flash.h"
#include "bootloader_flash_config.h"
#include "esp_compiler.h"
#include "esp_rom_efuse.h"
#include "esp_rom_caps.h"
#include "soc/chip_revision.h"
#include "hal/efuse_hal.h"
#if CONFIG_SPIRAM
#include "esp_private/esp_psram_io.h"
#endif
#if SOC_MEMSPI_CLOCK_IS_INDEPENDENT
#include "hal/cache_hal.h"
#endif
/* bytes erased by SPIEraseBlock() ROM function */
#define BLOCK_ERASE_SIZE 65536
/* Limit number of bytes written/read in a single SPI operation,
as these operations disable all higher priority tasks from running.
*/
#ifdef CONFIG_SPI_FLASH_WRITE_CHUNK_SIZE
#define MAX_WRITE_CHUNK CONFIG_SPI_FLASH_WRITE_CHUNK_SIZE
#else
#define MAX_WRITE_CHUNK 8192
#endif // CONFIG_SPI_FLASH_WRITE_CHUNK_SIZE
#define MAX_READ_CHUNK 16384
static const char *TAG __attribute__((unused)) = "spi_flash";
const DRAM_ATTR spi_flash_guard_funcs_t g_flash_guard_default_ops = {
.start = spi_flash_disable_interrupts_caches_and_other_cpu,
.end = spi_flash_enable_interrupts_caches_and_other_cpu,
};
const DRAM_ATTR spi_flash_guard_funcs_t g_flash_guard_no_os_ops = {
.start = spi_flash_disable_interrupts_caches_and_other_cpu_no_os,
.end = spi_flash_enable_interrupts_caches_no_os,
};
static const spi_flash_guard_funcs_t *s_flash_guard_ops;
void IRAM_ATTR spi_flash_guard_set(const spi_flash_guard_funcs_t *funcs)
{
s_flash_guard_ops = funcs;
}
const spi_flash_guard_funcs_t *IRAM_ATTR spi_flash_guard_get(void)
{
return s_flash_guard_ops;
}
#ifdef CONFIG_SPI_FLASH_DANGEROUS_WRITE_ABORTS
#define UNSAFE_WRITE_ADDRESS abort()
#else
#define UNSAFE_WRITE_ADDRESS return false
#endif
static __attribute__((unused)) bool is_safe_write_address(size_t addr, size_t size)
{
if (!esp_partition_main_flash_region_safe(addr, size)) {
UNSAFE_WRITE_ADDRESS;
}
return true;
}
#if CONFIG_SPI_FLASH_ROM_IMPL
#include "esp_heap_caps.h"
void IRAM_ATTR *spi_flash_malloc_internal(size_t size)
{
return heap_caps_malloc(size, MALLOC_CAP_8BIT|MALLOC_CAP_INTERNAL);
}
void IRAM_ATTR spi_flash_rom_impl_init(void)
{
spi_flash_guard_set(&g_flash_guard_default_ops);
#if ESP_ROM_HAS_SPI_FLASH_MMAP
/* These two functions are in ROM only */
extern void spi_flash_mmap_os_func_set(void *(*func1)(size_t size), void (*func2)(void *p));
spi_flash_mmap_os_func_set(spi_flash_malloc_internal, heap_caps_free);
extern esp_err_t spi_flash_mmap_page_num_init(uint32_t page_num);
spi_flash_mmap_page_num_init(128);
#endif // ESP_ROM_HAS_SPI_FLASH_MMAP
}
#endif
void IRAM_ATTR esp_mspi_pin_init(void)
{
#if SOC_SPI_MEM_SUPPORT_FLASH_OPI_MODE
bool octal_mspi_required = bootloader_flash_is_octal_mode_enabled();
#if CONFIG_SPIRAM_MODE_OCT
octal_mspi_required |= true;
#endif
if (octal_mspi_required) {
esp_rom_opiflash_pin_config();
mspi_timing_set_pin_drive_strength();
}
//Set F4R4 board pin drive strength. TODO: IDF-3663
#endif
}
void esp_mspi_pin_reserve(void)
{
uint64_t reserve_pin_mask = 0;
uint8_t mspi_io;
for (esp_mspi_io_t i = 0; i < ESP_MSPI_IO_MAX; i++) {
#if SOC_SPI_MEM_SUPPORT_FLASH_OPI_MODE
if (!bootloader_flash_is_octal_mode_enabled()
&& i >= ESP_MSPI_IO_DQS && i <= ESP_MSPI_IO_D7) {
continue;
}
#endif
mspi_io = esp_mspi_get_io(i);
if (mspi_io < 64) { // 'reserve_pin_mask' have 64 bits length
reserve_pin_mask |= BIT64(mspi_io);
}
}
esp_gpio_reserve(reserve_pin_mask);
}
esp_err_t IRAM_ATTR spi_flash_init_chip_state(void)
{
#if SOC_SPI_MEM_SUPPORT_FLASH_OPI_MODE
if (bootloader_flash_is_octal_mode_enabled()) {
return esp_opiflash_init(rom_spiflash_legacy_data->chip.device_id);
}
#endif
#if CONFIG_SPI_FLASH_HPM_ON
return spi_flash_enable_high_performance_mode();
#endif // CONFIG_SPI_FLASH_HPM_ON
return ESP_OK;
}
void IRAM_ATTR spi_flash_set_rom_required_regs(void)
{
#if SOC_SPI_MEM_SUPPORT_FLASH_OPI_MODE
if (bootloader_flash_is_octal_mode_enabled()) {
//Disable the variable dummy mode when doing timing tuning
CLEAR_PERI_REG_MASK(SPI_MEM_DDR_REG(1), SPI_MEM_SPI_FMEM_VAR_DUMMY);
/**
* STR /DTR mode setting is done every time when `esp_rom_opiflash_exec_cmd` is called
*
* Add any registers that are not set in ROM SPI flash functions here in the future
*/
}
#endif
}
#if CONFIG_IDF_TARGET_ESP32S3 && CONFIG_SPIRAM_MODE_OCT
// This function will only be called when Octal PSRAM enabled.
void IRAM_ATTR spi_flash_set_vendor_required_regs(void)
{
if (bootloader_flash_is_octal_mode_enabled()) {
esp_opiflash_set_required_regs();
SET_PERI_REG_BITS(SPI_MEM_CACHE_FCTRL_REG(1), SPI_MEM_CACHE_USR_CMD_4BYTE_V, 1, SPI_MEM_CACHE_USR_CMD_4BYTE_S);
} else {
//Flash chip requires MSPI specifically, call this function to set them
// Set back MSPI registers after Octal PSRAM initialization.
SET_PERI_REG_BITS(SPI_MEM_CACHE_FCTRL_REG(1), SPI_MEM_CACHE_USR_CMD_4BYTE_V, 0, SPI_MEM_CACHE_USR_CMD_4BYTE_S);
}
}
#endif
static const uint8_t s_mspi_io_num_default[] = {
MSPI_IOMUX_PIN_NUM_CLK,
MSPI_IOMUX_PIN_NUM_MISO,
MSPI_IOMUX_PIN_NUM_MOSI,
MSPI_IOMUX_PIN_NUM_CS0,
MSPI_IOMUX_PIN_NUM_HD,
MSPI_IOMUX_PIN_NUM_WP,
#if SOC_SPI_MEM_SUPPORT_FLASH_OPI_MODE
MSPI_IOMUX_PIN_NUM_DQS,
MSPI_IOMUX_PIN_NUM_D4,
MSPI_IOMUX_PIN_NUM_D5,
MSPI_IOMUX_PIN_NUM_D6,
MSPI_IOMUX_PIN_NUM_D7
#endif // SOC_SPI_MEM_SUPPORT_FLASH_OPI_MODE
};
uint8_t esp_mspi_get_io(esp_mspi_io_t io)
{
#if CONFIG_SPIRAM
if (io == ESP_MSPI_IO_CS1) {
return esp_psram_io_get_cs_io();
}
#endif
assert(io >= ESP_MSPI_IO_CLK);
#if SOC_SPI_MEM_SUPPORT_FLASH_OPI_MODE
assert(io <= ESP_MSPI_IO_D7);
#else
assert(io <= ESP_MSPI_IO_WP);
#endif
#if SOC_SPI_MEM_SUPPORT_CONFIG_GPIO_BY_EFUSE
uint8_t mspi_io = 0;
uint32_t spiconfig = 0;
if (io == ESP_MSPI_IO_WP) {
/**
* wp pad is a bit special:
* 1. since 32's efuse does not have enough bits for wp pad, so wp pad config put in flash bin header
* 2. rom code take 0x3f as invalid wp pad num, but take 0 as other invalid mspi pads num
*/
#if CONFIG_IDF_TARGET_ESP32
return bootloader_flash_get_wp_pin();
#else
spiconfig = esp_rom_efuse_get_flash_wp_gpio();
return (spiconfig == 0x3f) ? s_mspi_io_num_default[io] : spiconfig & 0x3f;
#endif
}
#if SOC_SPI_MEM_SUPPORT_FLASH_OPI_MODE
spiconfig = (io < ESP_MSPI_IO_WP) ? esp_rom_efuse_get_flash_gpio_info() : esp_rom_efuse_get_opiconfig();
#else
spiconfig = esp_rom_efuse_get_flash_gpio_info();
#endif // SOC_SPI_MEM_SUPPORT_FLASH_OPI_MODE
if (spiconfig == ESP_ROM_EFUSE_FLASH_DEFAULT_SPI) {
mspi_io = s_mspi_io_num_default[io];
} else if (io < ESP_MSPI_IO_WP) {
/**
* [0 : 5] -- CLK
* [6 :11] -- Q(D1)
* [12:17] -- D(D0)
* [18:23] -- CS
* [24:29] -- HD(D3)
*/
mspi_io = (spiconfig >> io * 6) & 0x3f;
}
#if SOC_SPI_MEM_SUPPORT_FLASH_OPI_MODE
else {
/**
* [0 : 5] -- DQS
* [6 :11] -- D4
* [12:17] -- D5
* [18:23] -- D6
* [24:29] -- D7
*/
mspi_io = (spiconfig >> (io - ESP_MSPI_IO_DQS) * 6) & 0x3f;
}
#endif // SOC_SPI_MEM_SUPPORT_FLASH_OPI_MODE
return mspi_io;
#else // SOC_SPI_MEM_SUPPORT_CONFIG_GPIO_BY_EFUSE
return s_mspi_io_num_default[io];
#endif // SOC_SPI_MEM_SUPPORT_CONFIG_GPIO_BY_EFUSE
}
#if !CONFIG_IDF_TARGET_ESP32P4 || !CONFIG_APP_BUILD_TYPE_RAM // IDF-10019
esp_err_t IRAM_ATTR esp_mspi_32bit_address_flash_feature_check(void)
{
#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
ESP_EARLY_LOGE(TAG, "32bit address (flash over 16MB) has high risk on this chip");
return ESP_ERR_NOT_SUPPORTED;
#elif CONFIG_IDF_TARGET_ESP32P4
// IDF-10019
unsigned chip_version = efuse_hal_chip_revision();
if (unlikely(!ESP_CHIP_REV_ABOVE(chip_version, 1))) {
ESP_EARLY_LOGE(TAG, "32bit address (flash over 16MB) has high risk on ESP32P4 v0.0");
return ESP_ERR_NOT_SUPPORTED;
}
#endif
return ESP_OK;
}
#endif // !CONFIG_IDF_TARGET_ESP32P4 || !CONFIG_APP_BUILD_TYPE_RAM

View File

@@ -87,7 +87,7 @@ struct esp_flash_t {
spi_flash_host_inst_t* host; ///< Pointer to hardware-specific "host_driver" structure. Must be initialized before used.
const spi_flash_chip_t *chip_drv; ///< Pointer to chip-model-specific "adapter" structure. If NULL, will be detected during initialisation.
const esp_flash_os_functions_t *os_func; ///< Pointer to os-specific hook structure. Call ``esp_flash_init_os_functions()`` to setup this field, after the host is properly initialized.
const esp_flash_os_functions_t *os_func; ///< Pointer to os-specific hook structure.
void *os_func_data; ///< Pointer to argument for os-specific hooks. Left NULL and will be initialized with ``os_func``.
esp_flash_io_mode_t read_mode; ///< Configured SPI flash read mode. Set before ``esp_flash_init`` is called.

View File

@@ -1,87 +1,9 @@
/*
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "soc/soc_caps.h"
#pragma once
/* SPI commands (actual on-wire commands not SPI controller bitmasks)
Suitable for use with spi_flash_hal_common_command static function.
*/
#define CMD_RDID 0x9F
#define CMD_RDUID 0x4B /* Read the flash unique ID*/
#define CMD_WRSR 0x01
#define SR_WIP (1<<0) /* Status register write-in-progress bit */
#define SR_WREN (1<<1) /* Status register write enable bit */
#define CMD_WRSR2 0x31 /* Not all SPI flash uses this command */
#define CMD_WREN 0x06
#define CMD_WRDI 0x04
#define CMD_RDSR 0x05
#define CMD_RDSR2 0x35 /* Not all SPI flash uses this command */
#define CMD_RDSCUR 0x2B /* MXIC-specific, read security register */
#define CMD_8READ 0xEC /* MXIC-specific, 8 I/O read */
#define CMD_8DTRD 0xEE /* MXIC-specific, 8 I/O DTR read */
#define CMD_RDFR 0x48 /* ISSI-specific, read function register */
#define CMD_FASTRD_QIO 0xEB
#define CMD_FASTRD_QIO_4B 0xEC
#define CMD_FASTRD_QUAD 0x6B
#define CMD_FASTRD_QUAD_4B 0x6C
#define CMD_FASTRD_DIO 0xBB
#define CMD_FASTRD_DIO_4B 0xBC
#define CMD_FASTRD_DUAL 0x3B
#define CMD_FASTRD_DUAL_4B 0x3C
#define CMD_FASTRD 0x0B
#define CMD_FASTRD_4B 0x0C
#define CMD_READ 0x03 /* Speed limited */
#define CMD_READ_4B 0x13 /* Speed limited */
#define CMD_CHIP_ERASE 0xC7
#define CMD_SECTOR_ERASE 0x20
#define CMD_SECTOR_ERASE_4B 0x21
#define CMD_LARGE_BLOCK_ERASE 0xD8 /* 64KB block erase command */
#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_HPMEN 0xA3 /* Enable High Performance mode on flash */
#define CMD_WRAP 0x77
#define CMD_BURST_RD 0xC0 /* wrap(0x77) and burst read are functionally same. But commands and formats is different */
#define CMD_RST_EN 0x66
#define CMD_RST_DEV 0x99
#define CMD_RDSFDP 0x5A /* Read the SFDP of the flash */
#define SPI_FLASH_DIO_DUMMY_BITLEN 4
#define SPI_FLASH_QIO_DUMMY_BITLEN 6
#define SPI_FLASH_DIO_ADDR_BITLEN 24
#define SPI_FLASH_QIO_ADDR_BITLEN 24
#define SPI_FLASH_QOUT_ADDR_BITLEN 24
#define SPI_FLASH_QOUT_DUMMY_BITLEN 8
#define SPI_FLASH_DOUT_ADDR_BITLEN 24
#define SPI_FLASH_DOUT_DUMMY_BITLEN 8
#define SPI_FLASH_FASTRD_ADDR_BITLEN 24
#define SPI_FLASH_FASTRD_DUMMY_BITLEN 8
#define SPI_FLASH_SLOWRD_ADDR_BITLEN 24
#define SPI_FLASH_SLOWRD_DUMMY_BITLEN 0
#define SPI_FLASH_OPISTR_ADDR_BITLEN 32
#define SPI_FLASH_OPISTR_DUMMY_BITLEN 20
#define SPI_FLASH_OPIDTR_ADDR_BITLEN 32
#define SPI_FLASH_OPIDTR_DUMMY_BITLEN 40
#define SPI_FLASH_QIO_HPM_DUMMY_BITLEN 10
#define SPI_FLASH_DIO_HPM_DUMMY_BITLEN 8
// Flash vendors.
#define SPI_FLASH_GD 0xC8
#define SPI_FLASH_ISSI 0x9D
#define SPI_FLASH_MXIC 0xC2
#define SPI_FLASH_XMC_1 0x20
#define SPI_FLASH_XMC_2 0x46
#define SPI_FLASH_WINBOND 0xEF
#define SPI_FLASH_TH 0xCD
#define SPI_FLASH_BY 0x68
#include <spi_flash_defs.h>

View File

@@ -1,105 +0,0 @@
/*
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include "sdkconfig.h"
#include "esp_err.h"
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Structure for flash dummy bits.
* For some flash chips, dummy bits are configurable under different conditions.
*/
typedef struct {
uint8_t dio_dummy;
uint8_t dout_dummy;
uint8_t qio_dummy;
uint8_t qout_dummy;
uint8_t fastrd_dummy;
} spi_flash_hpm_dummy_conf_t;
typedef enum {
SPI_FLASH_HPM_CMD_NEEDED, // Means that in the certain condition, flash needs to enter the high performance mode by command.
SPI_FLASH_HPM_DUMMY_NEEDED, // Means that in the certain condition, flash needs to enter the high performance mode by adjusting dummy.
SPI_FLASH_HPM_WRITE_SR_NEEDED, // Means that in the certain condition, flash needs to enter the high performance mode by writing status register.
SPI_FLASH_HPM_UNNEEDED, // Means that flash doesn't need to enter the high performance mode.
SPI_FLASH_HPM_BEYOND_LIMIT, // Means that flash has no capability to meet that condition.
} spi_flash_requirement_t;
typedef void (*spi_flash_hpm_enable_fn_t)(void);
typedef esp_err_t (*spi_flash_hpf_check_fn_t)(void);
typedef void (*spi_flash_get_chip_dummy_fn_t)(spi_flash_hpm_dummy_conf_t *dummy_conf);
typedef esp_err_t (*spi_flash_hpm_probe_fn_t)(uint32_t flash_id);
typedef spi_flash_requirement_t (*spi_flash_hpm_chip_requirement_check_t)(uint32_t flash_id, uint32_t freq_mhz, int voltage_mv, int temperature);
typedef struct __attribute__((packed))
{
const char *method; /* Flash HPM method */
spi_flash_hpm_probe_fn_t probe;
spi_flash_hpm_chip_requirement_check_t chip_hpm_requirement_check;
spi_flash_hpm_enable_fn_t flash_hpm_enable;
spi_flash_hpf_check_fn_t flash_hpf_check;
spi_flash_get_chip_dummy_fn_t flash_get_dummy;
} spi_flash_hpm_info_t;
/**
* @brief Enum for user to select valid wrap size.
*/
typedef enum {
FLASH_WRAP_SIZE_8B = 8,
FLASH_WRAP_SIZE_16B = 16,
FLASH_WRAP_SIZE_32B = 32,
FLASH_WRAP_SIZE_64B = 64,
} spi_flash_wrap_size_t;
/**
* @brief Probe flash wrap method
*
* @param flash_id Flash chip ID
*
* @return ESP_OK: If succeed
*/
typedef esp_err_t (*spi_flash_wrap_probe_fn_t)(uint32_t flash_id);
/**
* @brief Set flash wrap
*
* @param wrap_size: wrap_size
*
* @return ESP_OK: If succeed
*/
typedef esp_err_t (*spi_flash_wrap_set_fn_t)(spi_flash_wrap_size_t wrap_size);
/**
* @brief Clear flash wrap.
*
* @return ESP_OK: If succeed
*/
typedef esp_err_t (*spi_flash_wrap_clr_fn_t)(void);
typedef struct __attribute__((packed))
{
const char *method;
spi_flash_wrap_probe_fn_t probe;
spi_flash_wrap_set_fn_t chip_wrap_set;
spi_flash_wrap_clr_fn_t chip_wrap_clr;
} spi_flash_wrap_info_t;
/**
* Array of known flash chips and method to enable flash high performance mode.
*
* Users can override this array.
*/
extern const spi_flash_hpm_info_t __attribute__((weak)) spi_flash_hpm_enable_list[];
#ifdef __cplusplus
}
#endif

View File

@@ -30,6 +30,8 @@ enum {
};
//The ROM code has already taken 1 and 2, to avoid possible conflicts, start from 3.
#define ESP_ERR_FLASH_OP_FAIL (ESP_ERR_FLASH_BASE+1) ///< aligned with rom
#define ESP_ERR_FLASH_OP_TIMEOUT (ESP_ERR_FLASH_BASE+2) ///< aligned with rom
#define ESP_ERR_FLASH_NOT_INITIALISED (ESP_ERR_FLASH_BASE+3) ///< esp_flash_chip_t structure not correctly initialised by esp_flash_init().
#define ESP_ERR_FLASH_UNSUPPORTED_HOST (ESP_ERR_FLASH_BASE+4) ///< Requested operation isn't supported via this host SPI bus (chip->spi field).
#define ESP_ERR_FLASH_UNSUPPORTED_CHIP (ESP_ERR_FLASH_BASE+5) ///< Requested operation isn't supported by this model of SPI flash chip.

View File

@@ -1,124 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "sdkconfig.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* This header file contains declarations of cache manipulation functions
* used both in flash_ops.c and flash_mmap.c.
*
* These functions are considered internal and are not designed to be called from applications.
*/
// Init mutex protecting access to spi_flash_* APIs
void spi_flash_init_lock(void);
// Take mutex protecting access to spi_flash_* APIs
void spi_flash_op_lock(void);
// Release said mutex
void spi_flash_op_unlock(void);
// Suspend the scheduler on both CPUs, disable cache.
// Contrary to its name this doesn't do anything with interrupts, yet.
// Interrupt disabling capability will be added once we implement
// interrupt allocation API.
void spi_flash_disable_interrupts_caches_and_other_cpu(void);
// Enable cache, enable interrupts (to be added in future), resume scheduler
void spi_flash_enable_interrupts_caches_and_other_cpu(void);
// Disables non-IRAM interrupt handlers on current CPU and caches on both CPUs.
// This function is implied to be called when other CPU is not running or running code from IRAM.
void spi_flash_disable_interrupts_caches_and_other_cpu_no_os(void);
// Enable cache, enable interrupts on current CPU.
// This function is implied to be called when other CPU is not running or running code from IRAM.
void spi_flash_enable_interrupts_caches_no_os(void);
// Mark the pages containing a flash region as having been
// erased or written to. This means the flash cache needs
// to be evicted before these pages can be flash_mmap()ed again,
// as they may contain stale data
//
// Only call this while holding spi_flash_op_lock()
// Returns true if cache was flushed, false otherwise
bool spi_flash_check_and_flush_cache(size_t start_addr, size_t length);
//config cache mode
#if !CONFIG_IDF_TARGET_ESP32
//config instrcutin cache size and cache block size by menuconfig
void esp_config_instruction_cache_mode(void);
//config data cache size and cache block size by menuconfig
void esp_config_data_cache_mode(void);
#endif
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C2
/**
* @brief enable cache wrap mode for i/d shared cache
* @param icache_wrap_enable enable cache wrap mode for i/d shared cache
* @return ESP_OK on success, ESP_FAIL otherwise
*/
esp_err_t esp_enable_cache_wrap(bool icache_wrap_enable);
#elif CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32S2
/**
* @brief enable cache wrap mode for instruction cache and data cache
* @param icache_wrap_enable enable cache wrap mode for i cache
* @param dcache_wrap_enable enable cache wrap mode for d cache
* @return ESP_OK on success, ESP_FAIL otherwise
*/
esp_err_t esp_enable_cache_wrap(bool icache_wrap_enable, bool dcache_wrap_enable);
#endif
/** @brief Check at runtime if flash cache is enabled on both CPUs
*
* @return true if both CPUs have flash cache enabled, false otherwise.
*/
bool spi_flash_cache_enabled(void);
/**
* @brief Re-enable cache for the core defined as cpuid parameter.
*
* @param cpuid the core number to enable instruction cache for
*/
void spi_flash_enable_cache(uint32_t cpuid);
/**
* @brief Suspend the Cache access to external memory.
*
* @note Callers must disable branch prediction around this window when
* SOC_BRANCH_PREDICTOR_SUPPORTED, otherwise speculative fetches can
* raise cache access-fail errors while the cache is suspended.
*
* @param cpuid the core number to enable the cache for, meaning less on shared cache.
* @param saved_state Cache status hold by hal (Used only on ROM impl. in idf, this param unused)
*/
void spi_flash_disable_cache(uint32_t cpuid, uint32_t *saved_state);
/**
* @brief Resume the Cache access to external memory.
*
* @note Callers that disabled branch prediction for the suspend window must
* re-enable it after this call when SOC_BRANCH_PREDICTOR_SUPPORTED.
*
* @param cpuid the core number to enable the cache for, meaning less on shared cache.
* @param saved_state Cache status hold by hal (Used only on ROM impl. in idf, this param unused)
*/
void spi_flash_restore_cache(uint32_t cpuid, uint32_t saved_state);
#ifdef __cplusplus
}
#endif

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -20,19 +20,44 @@
extern "C" {
#endif
//-----------------------------ESP FLASH UTILITIES-------------------------------------//
/**
* @brief Initialize main flash
* @note Only call this function to initialize the main flash (flash chip on SPI1 CS0).
*
* @param chip Pointer to main SPI flash(SPI1 CS0) chip to use.
* @return ESP_OK on success, or a flash error code if initialisation fails.
*/
esp_err_t esp_flash_init_main(esp_flash_t *chip);
/** @brief Initialise the default SPI flash chip
/**
* @brief Initialize the bus lock on the SPI1 bus. Should be called if drivers (including esp_flash)
* wants to use SPI1 bus.
*
* @note When using legacy spi flash API, the bus lock will not be available on SPI1 bus.
*
* @return esp_err_t always ESP_OK.
*/
esp_err_t esp_flash_app_init_os_functions(void);
#if CONFIG_SPI_FLASH_ROM_IMPL
/**
* @brief Initialize ROM API functions structure
*
* This function initializes the ROM API functions structure, either by pointing
* to a custom structure or by patching the ROM structure in RAM.
*/
void esp_flash_rom_api_funcs_init(void);
#endif // CONFIG_SPI_FLASH_ROM_IMPL
//-----------------------------ESP FLASH OS LAYER-------------------------------------//
/**
* @brief Initialise the default SPI flash chip
*
* Called by OS startup code. You do not need to call this in your own applications.
*/
esp_err_t esp_flash_init_default_chip(void);
/**
* @brief Initialize main flash
* @param chip Pointer to main SPI flash(SPI1 CS0) chip to use..
*/
esp_err_t esp_flash_init_main(esp_flash_t *chip);
/**
* Enable OS-level SPI flash protections in IDF
*
@@ -76,16 +101,6 @@ esp_err_t esp_flash_init_os_functions(esp_flash_t *chip, int host_id, spi_bus_lo
*/
esp_err_t esp_flash_deinit_os_functions(esp_flash_t* chip, spi_bus_lock_dev_handle_t* out_dev_handle);
/**
* @brief Initialize the bus lock on the SPI1 bus. Should be called if drivers (including esp_flash)
* wants to use SPI1 bus.
*
* @note When using legacy spi flash API, the bus lock will not be available on SPI1 bus.
*
* @return esp_err_t always ESP_OK.
*/
esp_err_t esp_flash_app_init_os_functions(void);
/**
* Initialize OS-level functions for the main flash chip.
*
@@ -126,15 +141,45 @@ esp_err_t esp_flash_app_disable_os_functions(esp_flash_t* chip);
*/
esp_err_t esp_flash_set_dangerous_write_protection(esp_flash_t *chip, const bool protect);
#if CONFIG_SPI_FLASH_ROM_IMPL
/**
* @brief Initialize ROM API functions structure
*
* This function initializes the ROM API functions structure, either by pointing
* to a custom structure or by patching the ROM structure in RAM.
* @brief Partition operations
*/
void esp_flash_rom_api_funcs_init(void);
#endif // CONFIG_SPI_FLASH_ROM_IMPL
typedef struct esp_flash_partition_ops_s {
/**
* @brief Check if the main flash region is safe to write/erase.
*
* @param[in] start_addr Start address of the region
* @param[in] size Size of the region
* @return true if the region is safe to write/erase, false otherwise
*/
bool (*check_main_flash_region_safe)(size_t start_addr, size_t size);
/**
* @brief Check if a region is writable
*
* @param[in] start_addr Start address of the region
* @param[in] size Size of the region
* @return true if the region is writable/eraseable, false otherwise
*/
bool (*check_region_writable)(size_t start_addr, size_t size);
} esp_flash_partition_ops_t;
/**
* @brief Register a callback to determine whether a flash region is safe to write/erase.
*
* This allows upper-layer components (e.g. esp_partition) to inject partition-aware
* write protection logic without creating a circular dependency.
*
* The main flash chip must always register valid ops. For external flash chips
* calling this is optional; if not called, partition protection stays disabled
* (the default set by the OS-functions constructor).
*
* @param chip Pointer to the flash chip. Must not be NULL.
* @param ops Partition operations. Must not be NULL and both callbacks must be set.
* @return ESP_OK on success, ESP_ERR_INVALID_ARG if chip or ops is invalid,
* ESP_ERR_INVALID_STATE if the flash OS functions are not initialized.
*/
esp_err_t esp_flash_register_partition_ops(esp_flash_t *chip, esp_flash_partition_ops_t *ops);
#ifdef __cplusplus
}

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -7,7 +7,6 @@
#pragma once
#include "sdkconfig.h"
#include "esp_flash.h"
#include "esp_attr.h"
#ifdef __cplusplus

View File

@@ -1,299 +0,0 @@
/*
* SPDX-FileCopyrightText: 2019-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* System level MSPI APIs (private)
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "sdkconfig.h"
#include "esp_rom_spiflash.h"
#include "esp_err.h"
#include "soc/soc_caps.h"
#include "soc/clk_tree_defs.h"
#include "hal/spi_flash_hal.h"
#include "esp_flash.h"
#include "esp_flash_chips/esp_flash_types.h"
#include "esp_flash_chips/spi_flash_override.h"
#ifdef __cplusplus
extern "C" {
#endif
// Type of MSPI IO
typedef enum {
ESP_MSPI_IO_CLK = 0,
ESP_MSPI_IO_Q,
ESP_MSPI_IO_D,
ESP_MSPI_IO_CS0, /* cs for spi flash */
ESP_MSPI_IO_HD,
ESP_MSPI_IO_WP,
#if SOC_SPI_MEM_SUPPORT_FLASH_OPI_MODE
ESP_MSPI_IO_DQS,
ESP_MSPI_IO_D4,
ESP_MSPI_IO_D5,
ESP_MSPI_IO_D6,
ESP_MSPI_IO_D7,
#endif // SOC_SPI_MEM_SUPPORT_FLASH_OPI_MODE
#if CONFIG_SPIRAM
ESP_MSPI_IO_CS1, /* cs for spi ram */
#endif
ESP_MSPI_IO_MAX, /* Maximum IO MSPI occupied */
} esp_mspi_io_t;
/**
* @brief To setup Flash chip
*/
esp_err_t spi_flash_init_chip_state(void);
/**
* @brief To initislize the MSPI pins
*/
void esp_mspi_pin_init(void);
/**
* @brief Reserve MSPI IOs
*/
void esp_mspi_pin_reserve(void);
/**
* @brief Get the number of the GPIO corresponding to the given MSPI io
*
* @param[in] io MSPI io
*
* @return MSPI IO number
*/
uint8_t esp_mspi_get_io(esp_mspi_io_t io);
/**
* @brief Set SPI1 registers to make ROM functions work
* @note This function is used for setting SPI1 registers to the state that ROM SPI functions work
*/
void spi_flash_set_rom_required_regs(void);
/**
* @brief Should be only used by SPI1 Flash driver to know the necessary timing registers
* @param out_timing_config Pointer to timing_tuning parameters.
*/
void spi_timing_get_flash_timing_param(spi_flash_hal_timing_config_t *out_timing_config);
/**
* @brief Get the knowledge if the Flash timing is tuned or not
*/
bool spi_flash_timing_is_tuned(void);
/**
* @brief Set Flash chip specifically required MSPI register settings here
*/
void spi_flash_set_vendor_required_regs(void);
/**
* @brief Judge whether need to reset flash when brownout.
* Set` flash_brownout_needs_reset` inside the function if really need reset.
*/
void spi_flash_needs_reset_check(void);
/**
* @brief Set flag to reset flash. set when erase chip or program chip
*
* @param bool status. True if flash is eraing. False if flash is not erasing.
*
* @return None.
*/
void spi_flash_set_erasing_flag(bool status);
/**
* @brief Judge whether need to reset flash when brownout.
*
* @return true if need reset, otherwise false.
*/
bool spi_flash_brownout_need_reset(void);
/**
* @brief Check whether esp-chip supports 32bit address properly
*
* @return ESP_OK for supported, ESP_ERR_NOT_SUPPORTED for not supported
*/
esp_err_t esp_mspi_32bit_address_flash_feature_check(void);
#if CONFIG_SPI_FLASH_HPM_ON
/**
* @brief Enable SPI flash high performance mode.
*
* @note 1. When `CONFIG_SPI_FLASH_HPM_ON` is True, caller can always call this function without taking whether the used
* frequency falls into the HPM range into consideration.
* 2. However, caller shouldn't attempt to call this function on Octal flash. `CONFIG_SPI_FLASH_HPM_ON` may be
* True when `CONFIG_ESPTOOLPY_FLASH_MODE_AUTO_DETECT && !CONFIG_ESPTOOLPY_OCT_FLASH`
*
* @return ESP_OK if success.
*/
esp_err_t spi_flash_enable_high_performance_mode(void);
/**
* @brief Get the flash dummy through this function
* This can be used when one flash has several dummy configurations to enable the high performance mode.
* @note Don't forget to subtract one when assign to the register of mspi e.g. if the value you get is 4, (4-1=3) should be assigned to the register.
*
* @return Pointer to spi_flash_hpm_dummy_conf_t.
*/
const spi_flash_hpm_dummy_conf_t *spi_flash_hpm_get_dummy(void);
/**
* @brief Used to judge whether flash works under HPM mode with dummy adjustment.
*
* @return true Yes, and work under HPM with adjusting dummy. Otherwise, false.
*/
bool spi_flash_hpm_dummy_adjust(void);
#endif //CONFIG_SPI_FLASH_HPM_ON
#if CONFIG_ESP_SLEEP_SET_FLASH_DPD
/**
* @brief Get the duration of entering deep power-down mode.
*
* @return Entering deep power-down mode time(tDp), in microseconds.
*/
uint32_t spi_flash_dpd_get_enter_duration(void);
/**
* @brief Get the duration of exiting deep power-down mode.
*
* @return Exiting deep power-down mode time(tRES1), in microseconds.
*/
uint32_t spi_flash_dpd_get_exit_duration(void);
/**
* @brief Enable or disable SPI flash deep power-down mode.
*
* @param enable True to enter deep power-down mode, false to exit.
* @param wait_delay If true, wait tDP (enter) or tRES1 (exit) after the command.
* If false, skip the delay; the caller must ensure timing is met elsewhere
*
* @note If using self-provided flash (not the chips factory-default flash), consult its datasheet to use this API safely.
*
* @return ESP_OK if success.
*/
esp_err_t spi_flash_enable_deep_power_down_mode(bool enable, bool wait_delay);
#endif
#if SOC_SPI_MEM_SUPPORT_WRAP
/**
* @brief set wrap size of flash
*
* @param wrap_size: wrap mode support disable, 16 32, 64 byte
*
* @return esp_err_t : ESP_OK for successful.
*
*/
esp_err_t spi_flash_wrap_enable(spi_flash_wrap_size_t wrap_size);
/**
* @brief Probe flash wrap method
*
* @return esp_err_t: ESP_OK for success
*/
esp_err_t spi_flash_wrap_probe(void);
/**
* @brief disable cache wrap
*/
esp_err_t spi_flash_wrap_disable(void);
/**
* @brief Check whether flash and esp chip supports wrap mode.
*
* @param wrap_size wrap size.
* @return true: wrap support, otherwise, false.
*/
bool spi_flash_support_wrap_size(uint32_t wrap_size);
#endif //SOC_SPI_MEM_SUPPORT_WRAP
/**
* @brief SPI flash critical section enter function.
*
*/
typedef void (*spi_flash_guard_start_func_t)(void);
/**
* @brief SPI flash critical section exit function.
*/
typedef void (*spi_flash_guard_end_func_t)(void);
/**
* Structure holding SPI flash access critical sections management functions.
*
* Flash API uses two types of flash access management functions:
* 1) Functions which prepare/restore flash cache and interrupts before calling
* appropriate ROM functions (SPIWrite, SPIRead and SPIEraseBlock):
* - 'start' function should disables flash cache and non-IRAM interrupts and
* is invoked before the call to one of ROM function above.
* - 'end' function should restore state of flash cache and non-IRAM interrupts and
* is invoked after the call to one of ROM function above.
* These two functions are not recursive.
*
* Different versions of the guarding functions should be used depending on the context of
* execution (with or without functional OS). In normal conditions when flash API is called
* from task the functions use OS primitives. When there is no OS at all or when
* it is not guaranteed that OS is functional (accessing flash from exception handler) these
* functions cannot use OS primitives or even does not need them (multithreaded access is not possible).
*
* @note Structure and corresponding guard functions should not reside in flash.
* For example structure can be placed in DRAM and functions in IRAM sections.
*/
typedef struct {
spi_flash_guard_start_func_t start; /**< critical section start function. */
spi_flash_guard_end_func_t end; /**< critical section end function. */
} spi_flash_guard_funcs_t;
/**
* @brief Sets guard functions to access flash.
*
* @note Pointed structure and corresponding guard functions should not reside in flash.
* For example structure can be placed in DRAM and functions in IRAM sections.
*
* @param funcs pointer to structure holding flash access guard functions.
*/
void spi_flash_guard_set(const spi_flash_guard_funcs_t* funcs);
/**
* @brief Get the guard functions used for flash access
*
* @return The guard functions that were set via spi_flash_guard_set(). These functions
* can be called if implementing custom low-level SPI flash operations.
*/
const spi_flash_guard_funcs_t *spi_flash_guard_get(void);
/**
* @brief Default OS-aware flash access guard functions
*/
extern const spi_flash_guard_funcs_t g_flash_guard_default_ops;
/**
* @brief Non-OS flash access guard functions
*
* @note This version of flash guard functions is to be used when no OS is present or from panic handler.
* It does not use any OS primitives and IPC and implies that only calling CPU is active.
*/
extern const spi_flash_guard_funcs_t g_flash_guard_no_os_ops;
/**
* @brief This function is used to re-initialize the flash mmap when using ROM flash
* implementations.
*
* @note Only called in startup. User should not call this function.
*/
void spi_flash_rom_impl_init(void);
#ifdef __cplusplus
}
#endif

View File

@@ -21,14 +21,12 @@
#include "esp_attr.h"
#include "sdkconfig.h"
#include "esp_spi_flash_counters.h"
#include "hal/esp_flash_err.h"
#ifdef __cplusplus
extern "C" {
#endif
#define ESP_ERR_FLASH_OP_FAIL (ESP_ERR_FLASH_BASE + 1)
#define ESP_ERR_FLASH_OP_TIMEOUT (ESP_ERR_FLASH_BASE + 2)
#define SPI_FLASH_SEC_SIZE 4096 /**< SPI Flash sector size */
#define SPI_FLASH_MMU_PAGE_SIZE CONFIG_MMU_PAGE_SIZE /**< Flash cache MMU mapping page size */
@@ -166,7 +164,6 @@ void spi_flash_mmap_dump(void);
*/
uint32_t spi_flash_mmap_get_free_pages(spi_flash_mmap_memory_t memory);
#define SPI_FLASH_CACHE2PHYS_FAIL UINT32_MAX /*<! Result from spi_flash_cache2phys() if flash cache address is invalid */
/**

View File

@@ -2,10 +2,7 @@
archive: libspi_flash.a
entries:
if APP_BUILD_TYPE_PURE_RAM_APP = n:
flash_brownout_hook (noflash)
if SPI_FLASH_PLACE_FUNCTIONS_IN_IRAM = y:
spi_flash_wrap (noflash)
spi_flash_chip_generic (noflash)
spi_flash_chip_issi (noflash)
spi_flash_chip_mxic (noflash)
@@ -40,9 +37,6 @@ entries:
if IDF_TARGET_ESP32S3 = y:
spi_flash_chip_mxic_opi (noflash)
if ESPTOOLPY_OCT_FLASH = y || ESPTOOLPY_FLASH_MODE_AUTO_DETECT = y:
spi_flash_oct_flash_init (noflash)
if SPI_FLASH_VERIFY_WRITE = y:
esp_flash_api: s_verify_write (noflash)
@@ -75,17 +69,6 @@ entries:
if SPI_FLASH_WARN_SETTING_ZERO_TO_ONE = y:
esp_flash_api: s_check_setting_zero_to_one (noflash)
if SPI_FLASH_HPM_ON = y:
spi_flash_hpm_enable (noflash)
if ESP_SLEEP_SET_FLASH_DPD = y:
spi_flash_dpd_enable (noflash)
if SOC_GPIO_NEED_SOFT_ISOLATE_DURING_PD = y:
flash_ops: esp_mspi_get_io (noflash)
flash_ops: s_mspi_io_num_default (noflash)
[mapping:spi_flash_hal]
archive: libesp_hal_mspi.a
entries:

View File

@@ -1,12 +0,0 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdbool.h>
bool spi_flash_cache_enabled(void)
{
return true;
}

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/

View File

@@ -11,8 +11,7 @@
#include "esp_memory_utils.h"
#include "hal/mspi_ll.h"
#include "esp_flash_err.h"
#include "esp_flash_partitions.h"
#include "esp_flash_chips/spi_flash_defs.h"
#include "spi_flash_defs.h"
#include "esp_private/cache_utils.h"
#include "esp_private/memspi_host_driver.h"

View File

@@ -1,7 +0,0 @@
# sdkconfig replacement configurations for deprecated options formatted as
# CONFIG_DEPRECATED_OPTION CONFIG_NEW_OPTION
CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS CONFIG_SPI_FLASH_DANGEROUS_WRITE
CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ABORTS CONFIG_SPI_FLASH_DANGEROUS_WRITE_ABORTS
CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_FAILS CONFIG_SPI_FLASH_DANGEROUS_WRITE_FAILS
CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ALLOWED CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*

View File

@@ -5,7 +5,7 @@
*/
#include <stdlib.h>
#include "esp_flash_chips/spi_flash_defs.h"
#include "spi_flash_defs.h"
#include "esp_flash_chips/spi_flash_chip_generic.h"
#include "esp_flash_chips/spi_flash_chip_gd.h"

View File

@@ -8,7 +8,7 @@
#include "sdkconfig.h"
#include "esp_log.h"
#include "esp_flash_chips/spi_flash_defs.h"
#include "spi_flash_defs.h"
#include "esp_flash_chips/spi_flash_chip_driver.h"
#include "esp_flash_chips/spi_flash_chip_generic.h"
#include "esp_flash_chips/spi_flash_chip_issi.h"

View File

@@ -10,7 +10,7 @@
#include "esp_log.h"
#include "sdkconfig.h"
#include "esp_flash_chips/spi_flash_defs.h"
#include "spi_flash_defs.h"
#include "esp_flash_chips/spi_flash_chip_generic.h"
#include "esp_flash_chips/spi_flash_chip_gd.h"

View File

@@ -12,7 +12,7 @@
#include "esp_rom_caps.h"
#include "hal/spi_flash_encrypt_hal.h"
#include "esp_flash_chips/spi_flash_defs.h"
#include "spi_flash_defs.h"
#include "esp_flash_chips/spi_flash_chip_generic.h"
#include "esp_private/spi_flash_os.h"

View File

@@ -5,7 +5,7 @@
*/
#include <stdlib.h>
#include "esp_flash_chips/spi_flash_defs.h"
#include "spi_flash_defs.h"
#include "esp_flash_chips/spi_flash_chip_generic.h"
#include "esp_flash_chips/spi_flash_chip_issi.h"

View File

@@ -8,7 +8,7 @@
#include "esp_log.h"
#include "hal/spi_flash_hal.h"
#include "esp_flash_chips/spi_flash_defs.h"
#include "spi_flash_defs.h"
#include "esp_flash_chips/spi_flash_chip_generic.h"
/* Driver for MXIC flash chip */

View File

@@ -10,7 +10,7 @@
#include <sys/param.h> // For MIN/MAX
#include "hal/spi_flash_hal.h"
#include "esp_flash_chips/spi_flash_defs.h"
#include "spi_flash_defs.h"
#include "esp_flash_chips/spi_flash_chip_generic.h"
#define CMD_OPI_FLASH_MXIC(cmd) ((((~(cmd) & 0xff) << 8)) | ((cmd) & 0xff))

View File

@@ -5,7 +5,7 @@
*/
#include <stdlib.h>
#include "esp_flash_chips/spi_flash_defs.h"
#include "spi_flash_defs.h"
#include "esp_flash_chips/spi_flash_chip_generic.h"
esp_err_t spi_flash_chip_th_probe(esp_flash_t *chip, uint32_t flash_id)

View File

@@ -9,7 +9,7 @@
#include <sys/param.h> // For MIN/MAX
#include "esp_log.h"
#include "esp_flash_chips/spi_flash_defs.h"
#include "spi_flash_defs.h"
#include "esp_flash_chips/spi_flash_chip_generic.h"

View File

@@ -1,91 +0,0 @@
/*
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include "sdkconfig.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_attr.h"
#include "hal/spi_flash_hal.h"
#include "esp_flash_chips/spi_flash_chip_generic.h"
/*******************************************************************************
* Flash deep power-down mode.
* DPD: Deep power-down mode.
* TDP: CS high to deep power-down mode duration.
* TRES1: CS high to standby mode without ID read duration.
*
* Different flash chips might have different deep power-down strategy.
* 1. Most flash chips send B9H to enter DPD and send ABH to exist DPD.
* 2. Some flash chips send ABH followed by 3-dummy bytes to get device ID.
* 3. Some flash chips send B9H to enter PD(power-down) → send 79H to enter UDPD(ultra-deep power-down mode); send FFH to exit UDPD → send ABH to exit PD (ABH).
* 4. Some flash chips do nothing.
******************************************************************************/
__attribute__((unused)) const static char *DPD_TAG = "flash DPD";
#ifdef CONFIG_ESP_SLEEP_SPI_FLASH_ENTER_DPD_MODE_DELAY
#define SPI_FLASH_TDP_SAFE_VAL_US CONFIG_ESP_SLEEP_SPI_FLASH_ENTER_DPD_MODE_DELAY
#else
#define SPI_FLASH_TDP_SAFE_VAL_US (25)
#endif
#ifdef CONFIG_ESP_SLEEP_SPI_FLASH_EXIT_DPD_MODE_DELAY
#define SPI_FLASH_TRES1_SAFE_VAL_US CONFIG_ESP_SLEEP_SPI_FLASH_EXIT_DPD_MODE_DELAY
#else
#define SPI_FLASH_TRES1_SAFE_VAL_US (40)
#endif
/*
* Note: This file should only be compiled when DPD_ON, which is only available when (!APP_BUILD_TYPE_PURE_RAM_APP && !ESP_SLEEP_POWER_DOWN_FLASH).
* However when DPD_ON, there are still some cases this file is not actually used:
* TODO: PM-623
*/
uint32_t spi_flash_dpd_get_enter_duration(void)
{
#ifndef CONFIG_ESP_SLEEP_SPI_FLASH_ENTER_DPD_MODE_DELAY
ESP_EARLY_LOGW(DPD_TAG, "No DPD enter delay value defined. Using default safe delay value. Verify with your flash datasheet.");
#endif
return SPI_FLASH_TDP_SAFE_VAL_US;
}
uint32_t spi_flash_dpd_get_exit_duration(void)
{
#ifndef CONFIG_ESP_SLEEP_SPI_FLASH_EXIT_DPD_MODE_DELAY
ESP_EARLY_LOGW(DPD_TAG, "No DPD exit delay value defined. Using default safe delay value. Verify with your flash datasheet.");
#endif
return SPI_FLASH_TRES1_SAFE_VAL_US;
}
static esp_err_t spi_flash_enter_dpd(bool wait_delay)
{
esp_err_t ret = spi_flash_hal_enter_dpd_mode(esp_flash_default_chip->host);
if (wait_delay) {
esp_rom_delay_us(spi_flash_dpd_get_enter_duration());
}
return ret;
}
static esp_err_t spi_flash_exit_dpd(bool wait_delay)
{
esp_err_t ret = spi_flash_hal_exit_dpd_mode(esp_flash_default_chip->host);
if (wait_delay) {
esp_rom_delay_us(spi_flash_dpd_get_exit_duration());
}
return ret;
}
esp_err_t spi_flash_enable_deep_power_down_mode(bool enable, bool wait_delay)
{
if (enable) {
return spi_flash_enter_dpd(wait_delay);
}
return spi_flash_exit_dpd(wait_delay);
}

View File

@@ -1,516 +0,0 @@
/*
* SPDX-FileCopyrightText: 2020-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include "sdkconfig.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_rom_sys.h"
#include "esp_rom_spiflash.h"
#include "esp_flash_chips/spi_flash_defs.h"
#include "esp_flash_chips/spi_flash_override.h"
// TODO: These dependencies will be removed after remove bootloader_flash to G0.IDF-4609
#include "bootloader_flash_override.h"
#include "bootloader_flash_priv.h"
/*******************************************************************************
* Flash high speed performance mode.
* HPM: High performance mode.
* HPF: High performance flag.
*
* Different flash chips might have different high performance strategy.
* 1. Some flash chips send A3H to enable the HPM.
* 2. Some flash chips write HPF bit in status register.
* 3. Some flash chips adjust dummy cycles.
* 4. Some flash chips do nothing.
******************************************************************************/
/*
* Note: This file should only be compiled when HPM_ON, which is only available when !CONFIG_ESPTOOLPY_OCT_FLASH.
* However when HPM_ON, there are still some cases this file is not actually used:
*
* - !CONFIG_SPI_FLASH_UNDER_HIGH_FREQ:
* It mean that the flash not running under frequency requires HPM. spi_flash_enable_high_performance_mode() still
* called because caller shouldn't take care of the frequency.
*
* - bootloader_flash_is_octal_mode_enabled() == true:
* This is possible when `CONFIG_ESPTOOLPY_FLASH_MODE_AUTO_DETECT` selected
*
* Octal Flash for now all support 120M. No need to enable HPM. The file is compiled, but will not actually run
* into spi_flash_enable_high_performance_mode().
*/
void spi_flash_hpm_get_dummy_generic(spi_flash_hpm_dummy_conf_t *dummy_conf);
#if CONFIG_SPI_FLASH_UNDER_HIGH_FREQ
#if CONFIG_SPI_FLASH_HPM_AUTO
// This only happens on S3, where HPM_AUTO leads to HPM_ON
#warning High Performance Mode (QSPI Flash > 80MHz) is optional feature that depends on flash model. Read Docs First!
#endif
const static char *HPM_TAG = "flash HPM";
// TODO: This function will be changed after remove bootloader_flash to G0.IDF-4609
extern uint32_t bootloader_flash_execute_command_common(
uint8_t command,
uint32_t addr_len, uint32_t address,
uint8_t dummy_len,
uint8_t mosi_len, uint32_t mosi_data,
uint8_t miso_len);
extern uint32_t IRAM_ATTR bootloader_flash_read_sfdp(uint32_t sfdp_addr, unsigned int miso_byte_num);
//-----------------For flash chips which enter HPM via command-----------------------//
/**
* @brief Probe the chip whether use command to enable HPM mode. Take GD as an example:
* Some GD send 0xA3 command to enable HPM mode of the flash.
*/
static esp_err_t spi_flash_hpm_probe_chip_with_cmd(uint32_t flash_id)
{
esp_err_t ret = ESP_OK;
uint32_t gd_sfdp;
switch (flash_id) {
/* The flash listed here should enter the HPM with command 0xA3 */
case 0xC84016:
case 0xC84017:
// Read BYTE4 in SFDP, 0 means C series, 6 means E series
gd_sfdp = bootloader_flash_read_sfdp(0x4, 1);
if (gd_sfdp == 0x0) {
break;
} else {
ret = ESP_ERR_NOT_FOUND;
break;
}
default:
ret = ESP_ERR_NOT_FOUND;
break;
}
return ret;
}
static spi_flash_requirement_t spi_flash_hpm_chip_hpm_requirement_check_with_cmd(uint32_t flash_id, uint32_t freq_mhz, int voltage_mv, int temperautre)
{
// voltage and temperature are not been used now, to be completed in the future.
(void)voltage_mv;
(void)temperautre;
spi_flash_requirement_t chip_cap = SPI_FLASH_HPM_UNNEEDED;
if (freq_mhz > 80) {
chip_cap = SPI_FLASH_HPM_CMD_NEEDED;
}
ESP_EARLY_LOGD(HPM_TAG, "HPM with command, status is %d", chip_cap);
return chip_cap;
}
/**
* @brief Send HPMEN command (A3H)
*/
static void spi_flash_enable_high_performance_send_cmd(void)
{
uint32_t dummy = 24;
bootloader_flash_execute_command_common(CMD_HPMEN, 0, 0, dummy, 0, 0, 0);
// Delay for T(HPM) referring to datasheet.
esp_rom_delay_us(20);
}
/**
* @brief Check whether flash HPM has been enabled. According to flash datasheets, majorities of
* HPF bit are at bit-5, sr-3. But some are not. Therefore, this function is only used for those
* HPF bit is at bit-5, sr-3.
*/
static esp_err_t spi_flash_high_performance_check_hpf_bit_5(void)
{
if((bootloader_read_status_8b_rdsr3() & (1 << 4)) == 0) {
return ESP_FAIL;
}
return ESP_OK;
}
//-----------------For flash chips which enter HPM via adjust dummy-----------------------//
#if CONFIG_SPI_FLASH_HPM_DC_ON
/**
* @brief Probe the chip whether adjust dummy to enable HPM mode. Take XMC as an example:
* Adjust dummy bits to enable HPM mode of the flash. If XMC works under 80MHz, the dummy bits
* might be 6, but when works under 120MHz, the dummy bits might be 10.
*/
static esp_err_t spi_flash_hpm_probe_chip_with_dummy(uint32_t flash_id)
{
esp_err_t ret = ESP_OK;
uint32_t gd_sfdp;
switch (flash_id) {
/* The flash listed here should enter the HPM by adjusting dummy cycles */
// XMC chips.
case 0x204017:
case 0x204018:
case 0x464016:
case 0x464017:
case 0x464018:
break;
// GD chips.
case 0xC84017:
case 0xC84018:
// Read BYTE4 in SFDP, 0 means C series, 6 means E series
gd_sfdp = bootloader_flash_read_sfdp(0x4, 1);
if (gd_sfdp == 0x6) {
break;
} else {
ret = ESP_ERR_NOT_FOUND;
break;
}
default:
ret = ESP_ERR_NOT_FOUND;
break;
}
return ret;
}
static spi_flash_requirement_t spi_flash_hpm_chip_hpm_requirement_check_with_dummy(uint32_t flash_id, uint32_t freq_mhz, int voltage_mv, int temperautre)
{
// voltage and temperature are not been used now, to be completed in the future.
(void)voltage_mv;
(void)temperautre;
spi_flash_requirement_t chip_cap = SPI_FLASH_HPM_UNNEEDED;
if (freq_mhz >= 104) {
chip_cap = SPI_FLASH_HPM_DUMMY_NEEDED;
}
ESP_EARLY_LOGD(HPM_TAG, "HPM with dummy, status is %d", chip_cap);
return chip_cap;
}
/**
* @brief Adjust dummy cycles. This function modifies the Dummy Cycle Bits in SR3.
* Usually, the bits are at bit-0, bit-1, sr-3 and set DC[1:0]=[1,1].
*
* @note Don't forget to adjust dummy configurations for MSPI, you can get the
* correct dummy from interface `spi_flash_hpm_get_dummy`.
*/
static void spi_flash_turn_high_performance_reconfig_dummy(void)
{
uint8_t old_status_3 = bootloader_read_status_8b_rdsr3();
uint8_t new_status = (old_status_3 | 0x03);
bootloader_execute_flash_command(CMD_WRENVSR, 0, 0, 0);
bootloader_write_status_8b_wrsr3(new_status);
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
}
/**
* @brief Check whether HPM has been enabled. This function checks the DC bits
*/
static esp_err_t spi_flash_high_performance_check_dummy_sr(void)
{
if((bootloader_read_status_8b_rdsr3() & 0x03) == 0) {
return ESP_FAIL;
}
return ESP_OK;
}
static void spi_flash_hpm_get_dummy_xmc(spi_flash_hpm_dummy_conf_t *dummy_conf)
{
dummy_conf->dio_dummy = SPI_FLASH_DIO_HPM_DUMMY_BITLEN;
dummy_conf->dout_dummy = SPI_FLASH_DOUT_DUMMY_BITLEN;
dummy_conf->qio_dummy = SPI_FLASH_QIO_HPM_DUMMY_BITLEN;
dummy_conf->qout_dummy = SPI_FLASH_QOUT_DUMMY_BITLEN;
dummy_conf->fastrd_dummy = SPI_FLASH_FASTRD_DUMMY_BITLEN;
}
/**
* @brief Probe the chip whether adjust dummy (bit3,4) to enable HPM mode. Take XMC as an example:
* Adjust dummy bits to enable HPM mode of the flash. If XMC works under 80MHz, the dummy bits
* might be 6, but when works under 120MHz, the dummy bits might be 10.
*/
static esp_err_t spi_flash_hpm_probe_chip_with_dummy_bit3_4(uint32_t flash_id)
{
esp_err_t ret = ESP_OK;
switch (flash_id) {
/* The flash listed here should enter the HPM by adjusting dummy cycles */
// XMC chips.
case 0x204019:
case 0x204020:
break;
default:
ret = ESP_ERR_NOT_FOUND;
break;
}
return ret;
}
static spi_flash_requirement_t spi_flash_hpm_chip_hpm_requirement_check_with_dummy_bit3_4(uint32_t flash_id, uint32_t freq_mhz, int voltage_mv, int temperautre)
{
// voltage and temperature are not been used now, to be completed in the future.
(void)voltage_mv;
(void)temperautre;
spi_flash_requirement_t chip_cap = SPI_FLASH_HPM_UNNEEDED;
if (freq_mhz >= 104) {
chip_cap = SPI_FLASH_HPM_DUMMY_NEEDED;
}
ESP_EARLY_LOGD(HPM_TAG, "HPM with dummy bit3,4, status is %d", chip_cap);
return chip_cap;
}
/**
* @brief Adjust dummy cycles. This function modifies the Dummy Cycle Bits in SR3.
* Usually, the bits are at bit-0, bit-1, sr-3 and set DC[1:0]=[1,1].
*
* @note Don't forget to adjust dummy configurations for MSPI, you can get the
* correct dummy from interface `spi_flash_hpm_get_dummy`.
*/
static void spi_flash_turn_high_performance_dummy_bit3_4(void)
{
uint8_t old_status_3 = bootloader_read_status_8b_rdsr3();
uint8_t new_status = (old_status_3 | 0x18);
bootloader_execute_flash_command(CMD_WRENVSR, 0, 0, 0);
bootloader_write_status_8b_wrsr3(new_status);
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
}
/**
* @brief Check whether HPM has been enabled. This function checks the DC bits
*/
static esp_err_t spi_flash_high_performance_check_dummy_bit3_4(void)
{
if((bootloader_read_status_8b_rdsr3() & 0x18) == 0) {
return ESP_FAIL;
}
return ESP_OK;
}
#elif !CONFIG_SPI_FLASH_HPM_DC_DISABLE
//This is because bootloader doesn't support this
#warning HPM-DC, which helps to run some flash > 80MHz by adjusting dummy cycles, is no longer enabled by default.
#warning To enable this feature, your bootloader needs to have the support for it (by explicitly selecting BOOTLOADER_FLASH_DC_AWARE).
#warning If your bootloader does not support it, select SPI_FLASH_HPM_DC_DISABLE to suppress the warning. READ DOCS FIRST!
#endif //CONFIG_SPI_FLASH_HPM_DC_ON
//-----------------For flash chips which enter HPM via write status register-----------------------//
/**
* @brief Probe the chip whether to write status register to enable HPM mode. Take ZB as an example:
* Write status register bits to enable HPM mode of the flash. If ZB works under 80MHz, the register value
* would be 0, but when works under 120MHz, the register value would be 1.
*/
static esp_err_t spi_flash_hpm_probe_chip_with_write_hpf_bit_5(uint32_t flash_id)
{
esp_err_t ret = ESP_OK;
switch (flash_id) {
/* The flash listed here should enter the HPM by adjusting dummy cycles */
// ZB chips.
case 0x5E4016:
break;
default:
ret = ESP_ERR_NOT_FOUND;
break;
}
return ret;
}
static spi_flash_requirement_t spi_flash_hpm_chip_hpm_requirement_check_with_write_hpf_bit_5(uint32_t flash_id, uint32_t freq_mhz, int voltage_mv, int temperautre)
{
// voltage and temperature are not been used now, to be completed in the future.
(void)voltage_mv;
(void)temperautre;
spi_flash_requirement_t chip_cap = SPI_FLASH_HPM_UNNEEDED;
if (freq_mhz >= 104) {
chip_cap = SPI_FLASH_HPM_WRITE_SR_NEEDED;
}
ESP_EARLY_LOGD(HPM_TAG, "HPM with dummy, status is %d", chip_cap);
return chip_cap;
}
/**
* @brief Write bit 5 in status 3
*/
static void spi_flash_turn_high_performance_write_hpf_bit_5(void)
{
uint8_t old_status_3 = bootloader_read_status_8b_rdsr3();
uint8_t new_status = (old_status_3 | 0x10);
bootloader_execute_flash_command(CMD_WRENVSR, 0, 0, 0);
bootloader_write_status_8b_wrsr3(new_status);
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
}
//-----------------For flash chips which enter HPM with doing nothing-----------------------//
/**
* @brief Probe the chip whether to write status register to enable HPM mode. Take a GD chip as an example:
* This chip (GD25LQ255E) supports maximum frequency to 133MHz by default. So, we don't need to do any extra
* thing.
*/
static esp_err_t spi_flash_hpm_probe_chip_with_doing_nothing(uint32_t flash_id)
{
esp_err_t ret = ESP_OK;
switch (flash_id) {
/* The flash listed here should enter the HPM by doing nothing */
// GD25LQ255E.
case 0xC86019:
break;
case 0xEF4017:
break;
default:
ret = ESP_ERR_NOT_FOUND;
break;
}
return ret;
}
static spi_flash_requirement_t spi_flash_hpm_chip_hpm_requirement_check_with_doing_nothing(uint32_t flash_id, uint32_t freq_mhz, int voltage_mv, int temperautre)
{
// voltage and temperature are not been used now, to be completed in the future.
(void)voltage_mv;
(void)temperautre;
spi_flash_requirement_t chip_cap = SPI_FLASH_HPM_UNNEEDED;
ESP_EARLY_LOGD(HPM_TAG, "HPM by default, chip caps is %d", chip_cap);
return chip_cap;
}
const spi_flash_hpm_info_t __attribute__((weak)) spi_flash_hpm_enable_list[] = {
/* vendor, chip_id, freq_threshold, temperature threshold, operation for setting high performance, reading HPF status, get dummy */
{ "command", spi_flash_hpm_probe_chip_with_cmd, spi_flash_hpm_chip_hpm_requirement_check_with_cmd, spi_flash_enable_high_performance_send_cmd, spi_flash_high_performance_check_hpf_bit_5, spi_flash_hpm_get_dummy_generic },
#if CONFIG_SPI_FLASH_HPM_DC_ON
{ "dummy sr3-bit01", spi_flash_hpm_probe_chip_with_dummy, spi_flash_hpm_chip_hpm_requirement_check_with_dummy, spi_flash_turn_high_performance_reconfig_dummy, spi_flash_high_performance_check_dummy_sr, spi_flash_hpm_get_dummy_xmc},
{ "dummy sr3-bit3_4", spi_flash_hpm_probe_chip_with_dummy_bit3_4, spi_flash_hpm_chip_hpm_requirement_check_with_dummy_bit3_4, spi_flash_turn_high_performance_dummy_bit3_4, spi_flash_high_performance_check_dummy_bit3_4, spi_flash_hpm_get_dummy_xmc},
#endif //CONFIG_SPI_FLASH_HPM_DC_ON
{ "write sr3-bit5", spi_flash_hpm_probe_chip_with_write_hpf_bit_5, spi_flash_hpm_chip_hpm_requirement_check_with_write_hpf_bit_5, spi_flash_turn_high_performance_write_hpf_bit_5, spi_flash_high_performance_check_hpf_bit_5, spi_flash_hpm_get_dummy_generic},
{ "noting-to-do", spi_flash_hpm_probe_chip_with_doing_nothing, spi_flash_hpm_chip_hpm_requirement_check_with_doing_nothing, NULL, NULL, spi_flash_hpm_get_dummy_generic},
// default: do nothing, but keep the dummy get function. The first item with NULL as its probe will be the fallback.
{ "NULL", NULL, NULL, NULL, NULL, spi_flash_hpm_get_dummy_generic},
};
static const spi_flash_hpm_info_t *chip_hpm = NULL;
#if CONFIG_SPI_FLASH_HPM_DC_ON
static bool s_hpm_dummy_changed = false;
static spi_flash_hpm_dummy_conf_t s_dummy_conf;
const spi_flash_hpm_dummy_conf_t *spi_flash_hpm_get_dummy(void)
{
chip_hpm->flash_get_dummy(&s_dummy_conf);
return &s_dummy_conf;
}
bool spi_flash_hpm_dummy_adjust(void)
{
return s_hpm_dummy_changed;
}
#endif //CONFIG_SPI_FLASH_HPM_DC_ON
#if CONFIG_ESPTOOLPY_FLASHFREQ_120M
#define FLASH_FREQUENCY 120
#endif
esp_err_t spi_flash_enable_high_performance_mode(void)
{
uint32_t flash_chip_id = g_rom_flashchip.device_id;
uint32_t flash_freq = FLASH_FREQUENCY;
spi_flash_requirement_t hpm_requirement_check;
// voltage and temperature has not been implemented, just leave an interface here. Complete in the future.
int voltage = 0;
int temperature = 0;
#if CONFIG_SPI_FLASH_HPM_AUTO
ESP_EARLY_LOGW(HPM_TAG, "HPM mode is optional feature that depends on flash model. Read Docs First!");
#endif
#if CONFIG_SPI_FLASH_HPM_DC_DISABLE
// case 1: force disabled
ESP_EARLY_LOGI(HPM_TAG, "w/o HPM-DC support");
#elif CONFIG_SPI_FLASH_HPM_DC_ON
// case 2: auto, and actually enabled
ESP_EARLY_LOGI(HPM_TAG, "with HPM-DC support");
#else
// case 3: auto, but disabled (not supported by bootloader)
ESP_EARLY_LOGW(HPM_TAG, "HPM mode with DC adjustment is disabled. Some flash models may not be supported. Read Docs First!");
#endif
const spi_flash_hpm_info_t *chip = spi_flash_hpm_enable_list;
esp_err_t ret = ESP_OK;
while (chip->probe) {
ret = chip->probe(flash_chip_id);
if (ret == ESP_OK) {
break;
}
chip++;
}
chip_hpm = chip;
/* When > 80 MHz, flash chips usually need special HPM support to run normally. The support is chip-specific. When
* the chip is not in the known flash list, nothing will be done and there will be an warning.
* When <= 80 MHz, it's assumed that all flash chips can run without chip-specific HPM support. This function will not be called and there will be no warning.
*/
if (ret != ESP_OK) {
ESP_EARLY_LOGW(HPM_TAG, "High performance mode of this flash model hasn't been supported.");
return ret;
}
hpm_requirement_check = chip_hpm->chip_hpm_requirement_check(flash_chip_id, flash_freq, voltage, temperature);
if ((hpm_requirement_check == SPI_FLASH_HPM_CMD_NEEDED) || (hpm_requirement_check == SPI_FLASH_HPM_DUMMY_NEEDED) || (hpm_requirement_check == SPI_FLASH_HPM_WRITE_SR_NEEDED)) {
ESP_EARLY_LOGI(HPM_TAG, "Enabling flash high speed mode by %s", chip_hpm->method);
chip_hpm->flash_hpm_enable();
ESP_EARLY_LOGD(HPM_TAG, "Checking whether HPM has been executed");
if (chip_hpm->flash_hpf_check() != ESP_OK) {
ESP_EARLY_LOGE(HPM_TAG, "Flash high performance mode hasn't been executed successfully");
return ESP_FAIL;
}
#if CONFIG_SPI_FLASH_HPM_DC_ON
s_hpm_dummy_changed = (hpm_requirement_check == SPI_FLASH_HPM_DUMMY_NEEDED) ? true : false;
#else
assert(hpm_requirement_check != SPI_FLASH_HPM_DUMMY_NEEDED);
#endif
} else if (hpm_requirement_check == SPI_FLASH_HPM_BEYOND_LIMIT) {
ESP_EARLY_LOGE(HPM_TAG, "Flash does not have the ability to raise to that frequency");
return ESP_FAIL;
}
return ESP_OK;
}
#else
//!CONFIG_SPI_FLASH_UNDER_HIGH_FREQ
static spi_flash_hpm_dummy_conf_t s_dummy_conf;
esp_err_t spi_flash_enable_high_performance_mode(void)
{
return ESP_OK;
}
const spi_flash_hpm_dummy_conf_t *spi_flash_hpm_get_dummy(void)
{
spi_flash_hpm_get_dummy_generic(&s_dummy_conf);
return &s_dummy_conf;
}
bool spi_flash_hpm_dummy_adjust(void)
{
return false;
}
#endif //CONFIG_SPI_FLASH_UNDER_HIGH_FREQ
//-----------------------generic functions-------------------------------------//
/**
* @brief Default dummy for almost all flash chips. If your flash doesn't need to reconfigure dummy,
* just call this function.
*/
void __attribute__((weak)) spi_flash_hpm_get_dummy_generic(spi_flash_hpm_dummy_conf_t *dummy_conf)
{
dummy_conf->dio_dummy = SPI_FLASH_DIO_DUMMY_BITLEN;
dummy_conf->dout_dummy = SPI_FLASH_DOUT_DUMMY_BITLEN;
dummy_conf->qio_dummy = SPI_FLASH_QIO_DUMMY_BITLEN;
dummy_conf->qout_dummy = SPI_FLASH_QOUT_DUMMY_BITLEN;
dummy_conf->fastrd_dummy = SPI_FLASH_FASTRD_DUMMY_BITLEN;
}

View File

@@ -4,6 +4,7 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include <assert.h>
#include <stdarg.h>
#include <sys/lock.h>
#include <sys/param.h> //For max/min
@@ -19,9 +20,9 @@
#include "esp_flash.h"
#include "esp_flash_chips/esp_flash_types.h"
#include "esp_flash_partitions.h"
#include "esp_private/spi_flash_os.h"
#include "esp_private/esp_flash_internal.h"
#include "esp_private/cache_utils.h"
#include "esp_private/flash_mmap.h"
#include "esp_private/spi_share_hw_ctrl.h"
@@ -61,7 +62,10 @@ typedef struct {
spi_bus_lock_dev_handle_t dev_lock;
uint32_t no_protect : 1; //to decide whether to check protected region (for the main chip) or not.
uint32_t current_op_type : 3; //Whether the mmap lock is already taken, only for SPI1.
uint32_t reserved : 28;
uint32_t require_partition_protection : 1; // Only the main flash must have partition-aware protection callbacks.
uint32_t reserved : 27;
bool (*check_main_flash_region_safe)(size_t start_addr, size_t size); ///< Callback to check if the main flash region is safe to write/erase. Registered by upper layer (e.g. esp_partition).
bool (*check_region_writable)(size_t start_addr, size_t size); ///< Callback to check if a region is writable/eraseable. Registered by upper layer (e.g. esp_partition).
uint32_t acquired_since_us; // Time since last explicit yield()
uint32_t released_since_us; // Time since last end() (implicit yield)
uint32_t start_flags; // Flags passed to start() function, used to determine if freq_limit was called
@@ -384,11 +388,24 @@ static void release_buffer_malloc(void* arg, void *temp_buf)
static esp_err_t main_flash_region_protected(void* arg, size_t start_addr, size_t size)
{
if (!esp_partition_is_flash_region_writable(start_addr, size)) {
app_func_arg_t *func_arg = (app_func_arg_t *)arg;
if (!func_arg->require_partition_protection) {
/**
* - Main flash always register partition protection callbacks.
* - External flash chips on SPI1 may omit them
* - because they are not governed by the main flash partition table
* This case just return OK
*/
return ESP_OK;
}
assert(func_arg->check_region_writable != NULL);
assert(func_arg->check_main_flash_region_safe != NULL);
if (!func_arg->check_region_writable(start_addr, size)) {
return ESP_ERR_NOT_ALLOWED;
}
#if !CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED
if (((app_func_arg_t*)arg)->no_protect || esp_partition_main_flash_region_safe(start_addr, size)) {
if (func_arg->no_protect ||
func_arg->check_main_flash_region_safe(start_addr, size)) {
//ESP_OK = 0, also means protected==0
return ESP_OK;
} else {
@@ -474,13 +491,15 @@ esp_err_t esp_flash_init_os_functions(esp_flash_t *chip, int host_id, spi_bus_lo
chip->os_func = &esp_flash_spi23_default_os_functions;
break;
default:
free(chip->os_func_data);
chip->os_func_data = NULL;
return ESP_ERR_INVALID_ARG;
break;
}
*(app_func_arg_t*) chip->os_func_data = (app_func_arg_t) {
.dev_lock = dev_handle,
.no_protect = true, // This is OK because this code path isn't used for the main flash chip which requires `no_protect = false`
.require_partition_protection = false,
};
return ESP_OK;
@@ -537,12 +556,32 @@ esp_err_t esp_flash_app_enable_os_functions(esp_flash_t* chip)
main_flash_arg = (app_func_arg_t) {
.dev_lock = g_spi_lock_main_flash_dev,
.no_protect = false, // Required for the main flash chip
.require_partition_protection = true,
};
chip->os_func = &esp_flash_spi1_default_os_functions;
chip->os_func_data = &main_flash_arg;
return ESP_OK;
}
esp_err_t esp_flash_register_partition_ops(esp_flash_t *chip, esp_flash_partition_ops_t *ops)
{
// Error checks first
if (chip == NULL || ops == NULL ||
ops->check_region_writable == NULL || ops->check_main_flash_region_safe == NULL) {
return ESP_ERR_INVALID_ARG;
}
// os functions (and thus os_func_data) must be initialized before registering ops
if (chip->os_func_data == NULL) {
return ESP_ERR_INVALID_STATE;
}
app_func_arg_t *func_arg = (app_func_arg_t *)chip->os_func_data;
func_arg->check_region_writable = ops->check_region_writable;
func_arg->check_main_flash_region_safe = ops->check_main_flash_region_safe;
func_arg->require_partition_protection = true;
return ESP_OK;
}
esp_err_t esp_flash_set_dangerous_write_protection(esp_flash_t *chip, const bool protect)
{
#if !CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -16,6 +16,7 @@
#include "esp_flash.h"
#include "esp_flash_chips/esp_flash_types.h"
#include "esp_private/esp_flash_internal.h"
static IRAM_ATTR esp_err_t start(void *arg, uint32_t flags)
{

View File

@@ -1,175 +0,0 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <stdbool.h>
#include "sdkconfig.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_rom_sys.h"
#include "esp_rom_spiflash.h"
#include "rom/spi_flash.h"
#include "esp_flash_chips/spi_flash_defs.h"
#include "esp_flash_chips/spi_flash_override.h"
#include "esp_private/spi_flash_os.h"
// TODO: These dependencies will be removed after remove bootloader_flash to G0.IDF-4609
#include "bootloader_flash_override.h"
#include "bootloader_flash_priv.h"
/***********************************************************************************
* Flash wrap feature (also called burst read on some flash chips)
*
* Different flash chips enter wrap (burst read) mode in different strategies.
* 1. Command 0xC0 + 8 Bytes.
* 2. Command 0x77 + 24 dummy + 8 Bytes.
**********************************************************************************/
#if SOC_SPI_MEM_SUPPORT_WRAP
const static char *FLASH_WRAP_TAG = "flash wrap";
// TODO: This function will be changed after remove bootloader_flash to G0.IDF-4609
extern uint32_t bootloader_flash_execute_command_common(
uint8_t command,
uint32_t addr_len, uint32_t address,
uint8_t dummy_len,
uint8_t mosi_len, uint32_t mosi_data,
uint8_t miso_len);
esp_err_t spi_flash_wrap_probe_c0(uint32_t flash_id)
{
esp_err_t ret = ESP_OK;
switch (flash_id) {
/* The flash listed here should enter the wrap with command 0xC0 */
case 0xC22018:
break;
default:
ret = ESP_ERR_NOT_FOUND;
break;
}
return ret;
}
/**
* @brief Burst read with command 0xC0 + 8 Bytes
*
* |------------|-----------------------------|
* | data | wrap depth |
* | 00h | 8 |
* | 01h | 16 |
* | 02h | 32 |
* | 03h | 64 |
* |------------|-----------------------------|
*/
esp_err_t spi_flash_wrap_enable_c0(spi_flash_wrap_size_t wrap_size)
{
uint8_t wrap_code = (uint8_t) (__builtin_ctz(wrap_size) - 3);
bootloader_flash_execute_command_common(CMD_BURST_RD, 0, 0, 0, 8, wrap_code, 0);
return ESP_OK;
}
/**
* @brief Burst read with command 0x77 + 24 Dummy + 8 Bytes
*
* |-------------------|-----------------------------|
* | data(W6,W5) | wrap depth |
* | 00h | 8 |
* | 01h | 16 |
* | 02h | 32 |
* | 03h | 64 |
* |-------------------|-----------------------------|
*/
esp_err_t spi_flash_wrap_enable_77(spi_flash_wrap_size_t wrap_size)
{
uint8_t wrap_code = (uint8_t) (((__builtin_ctz(wrap_size) - 3) * 2) << 4);
// According to the special format, we need enable QIO_FWRITE for command 77h and clear it after this command is done.
REG_SET_BIT(PERIPHS_SPI_FLASH_USRREG, SPI_MEM_FWRITE_QIO);
bootloader_flash_execute_command_common(CMD_WRAP, 0, 0, 6, 8, wrap_code, 0);
REG_CLR_BIT(PERIPHS_SPI_FLASH_USRREG, SPI_MEM_FWRITE_QIO);
return ESP_OK;
}
/**
* @brief Burst read is cleared by setting 0x1xh,
* so we set 0x10 to disable this feature.
*/
esp_err_t spi_flash_wrap_clear_c0(void)
{
bootloader_flash_execute_command_common(CMD_BURST_RD, 0, 0, 0, 8, 0x10, 0);
return ESP_OK;
}
/**
* @brief Burst read is cleared by setting W4 bit 1,
* so we set 0x10 to disable this feature.
*/
esp_err_t spi_flash_wrap_clear_77(void)
{
// According to the special format, we need enable QIO_FWRITE for command 77h and clear it after this command is done.
REG_SET_BIT(PERIPHS_SPI_FLASH_USRREG, SPI_MEM_FWRITE_QIO);
bootloader_flash_execute_command_common(CMD_WRAP, 0, 0, 6, 8, 0x10, 0);
REG_CLR_BIT(PERIPHS_SPI_FLASH_USRREG, SPI_MEM_FWRITE_QIO);
return ESP_OK;
}
const spi_flash_wrap_info_t __attribute__((weak)) spi_flash_wrap_list[] = {
/* method probe chip wrap set chip wrap clear */
{"C0H+8B", spi_flash_wrap_probe_c0, spi_flash_wrap_enable_c0, spi_flash_wrap_clear_c0},
{"default", NULL, spi_flash_wrap_enable_77, spi_flash_wrap_clear_77},
};
static const spi_flash_wrap_info_t *chip_wrap = NULL;
esp_err_t spi_flash_wrap_probe(void)
{
uint32_t flash_chip_id = g_rom_flashchip.device_id;
const spi_flash_wrap_info_t *chip = spi_flash_wrap_list;
esp_err_t ret = ESP_OK;
while (chip->probe) {
ret = chip->probe(flash_chip_id);
if (ret == ESP_OK) {
break;
}
chip++;
}
chip_wrap = chip;
return ret;
}
esp_err_t spi_flash_wrap_enable(spi_flash_wrap_size_t wrap_size)
{
return chip_wrap->chip_wrap_set(wrap_size);
}
esp_err_t spi_flash_wrap_disable(void)
{
return chip_wrap->chip_wrap_clr();
}
bool spi_flash_support_wrap_size(uint32_t wrap_size)
{
// Only QIO mode supports wrap.
if (!REG_GET_BIT(PERIPHS_SPI_FLASH_CTRL, SPI_MEM_FREAD_QIO)) {
ESP_EARLY_LOGE(FLASH_WRAP_TAG, "flash wrap is only supported in QIO mode");
abort();
}
// Only following size can be wrapped.
switch (wrap_size) {
case 0:
case 8:
case 16:
case 32:
case 64:
return true;
default:
return false;
}
}
#endif // SOC_SPI_MEM_SUPPORT_WRAP

View File

@@ -4,9 +4,9 @@ components/spi_flash/test_apps/esp_flash:
depends_filepatterns:
- components/bootloader_support/bootloader_flash/**/*
depends_components:
- *common_components
- esp_mm
- esp_psram
- esp_mspi
- spi_flash
- esp_driver_gpio
- esp_driver_spi
@@ -19,14 +19,14 @@ components/spi_flash/test_apps/esp_flash_blockdev:
temporary: false
reason: should be sufficient to test on one Xtensa and one RISC-V target
depends_components:
- *common_components
- esp_mspi
- spi_flash
components/spi_flash/test_apps/esp_flash_freq_limit:
enable:
- if: IDF_TARGET == "esp32c5"
depends_components:
- *common_components
- esp_mspi
- spi_flash
- esp_pm
- esp_driver_gptimer
@@ -34,7 +34,7 @@ components/spi_flash/test_apps/esp_flash_freq_limit:
components/spi_flash/test_apps/esp_flash_stress:
depends_components:
- *common_components
- esp_mspi
- esp_mm
- spi_flash
- esp_hal_mspi
@@ -51,14 +51,14 @@ components/spi_flash/test_apps/flash_encryption:
reason: No runners # IDF-5634
depends_components:
- *common_components
- esp_mspi
- esp_mm
- spi_flash
- esp_hal_mspi
components/spi_flash/test_apps/flash_mmap:
depends_components:
- *common_components
- esp_mspi
- esp_mm
- spi_flash
- esp_hal_mspi
@@ -82,7 +82,7 @@ components/spi_flash/test_apps/flash_suspend:
temporary: true
reason: lack of runners, or we don't trust generic runner must support suspend
depends_components:
- *common_components
- esp_mspi
- spi_flash
- esp_driver_gptimer
- esp_hal_mspi
@@ -94,7 +94,7 @@ components/spi_flash/test_apps/mspi_test:
depends_filepatterns:
- components/bootloader_support/bootloader_flash/**/*
depends_components:
- *common_components
- esp_mspi
- esp_mm
- esp_psram
- spi_flash
@@ -102,8 +102,3 @@ components/spi_flash/test_apps/mspi_test:
- esp_driver_spi
- esptool_py # Some flash related kconfigs are listed here.
- esp_hal_mspi
components/spi_flash/test_apps/no_flash_delay:
disable:
- if: IDF_TARGET not in ["esp32c3"]
reason: Testing on a single target is sufficient

View File

@@ -22,7 +22,7 @@ const esp_partition_t *get_test_flash_partition(void)
{
/* This finds "flash_test" partition defined in custom partitions.csv */
const esp_partition_t *result = esp_partition_find_first(ESP_PARTITION_TYPE_DATA,
ESP_PARTITION_SUBTYPE_ANY, "flash_test");
ESP_PARTITION_SUBTYPE_ANY, "flash_test");
assert(result != NULL); /* means partition table set wrong */
return result;
}
@@ -101,7 +101,8 @@ err:
return ret;
}
const esp_partition_t * spi_flash_suspend_test_find_last_partition(void) {
const esp_partition_t * spi_flash_suspend_test_find_last_partition(void)
{
const esp_partition_t *last_partition = NULL;
esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_ANY, ESP_PARTITION_SUBTYPE_ANY, NULL);

View File

@@ -30,13 +30,11 @@ void app_main(void)
// | `---..-' || | --' | |` | |\ '-' |.-' `)| | | |
// `------'`-----' `--' `--' `--' `--`--'`----' `--' `--'
printf(",------. ,---. ,------. ,------.,--. ,--. \n");
printf("| .---'' .-' | .--. ' | .---'| | ,--,--. ,---. | ,---. \n");
printf("| `--, `. `-. | '--' | | `--, | |' ,-. |( .-' | .-. | \n");
printf("| `---..-' || | --' | |` | |\\ '-' |.-' `)| | | | \n");
printf("`------'`-----' `--' `--' `--' `--`--'`----' `--' `--' \n");
unity_run_menu();
}

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
@@ -120,7 +120,6 @@ typedef void (*flash_test_func_t)(const esp_partition_t *part);
LOG_ERASE(bus, erase_2, chip); \
} while (0)
#if defined(CONFIG_SPIRAM)
//SPI1 CS1 occupied by PSRAM
#define BYPASS_MULTIPLE_CHIP 1
@@ -182,77 +181,77 @@ static const char TAG[] = "test_esp_flash";
#if CONFIG_IDF_TARGET_ESP32
flashtest_config_t config_list[] = {
FLASHTEST_CONFIG_COMMON,
/* current runner doesn't have a flash on SPI2_HOST */
// {
// .io_mode = TEST_SPI_READ_MODE,
// .freq_mhz = TEST_SPI_SPEED,
// .host_id = SPI2_HOST,
// .cs_id = 0,
// // uses GPIO matrix on esp32s2 regardless if FORCE_GPIO_MATRIX
// .cs_io_num = SPI2_PIN_NUM_CS,
// .input_delay_ns = 20,
// },
{
.io_mode = TEST_SPI_READ_MODE,
.freq_mhz = TEST_SPI_SPEED,
.host_id = SPI3_HOST,
.cs_id = 0,
.cs_io_num = SPI3_PIN_NUM_CS,
.input_delay_ns = 0,
},
};
FLASHTEST_CONFIG_COMMON,
/* current runner doesn't have a flash on SPI2_HOST */
// {
// .io_mode = TEST_SPI_READ_MODE,
// .freq_mhz = TEST_SPI_SPEED,
// .host_id = SPI2_HOST,
// .cs_id = 0,
// // uses GPIO matrix on esp32s2 regardless if FORCE_GPIO_MATRIX
// .cs_io_num = SPI2_PIN_NUM_CS,
// .input_delay_ns = 20,
// },
{
.io_mode = TEST_SPI_READ_MODE,
.freq_mhz = TEST_SPI_SPEED,
.host_id = SPI3_HOST,
.cs_id = 0,
.cs_io_num = SPI3_PIN_NUM_CS,
.input_delay_ns = 0,
},
};
#elif CONFIG_IDF_TARGET_ESP32S2
flashtest_config_t config_list[] = {
FLASHTEST_CONFIG_COMMON,
{
.io_mode = TEST_SPI_READ_MODE,
.freq_mhz = TEST_SPI_SPEED,
.host_id = SPI2_HOST,
.cs_id = 0,
.cs_io_num = SPI2_PIN_NUM_CS,
.input_delay_ns = 0,
},
{
.io_mode = TEST_SPI_READ_MODE,
.freq_mhz = TEST_SPI_SPEED,
.host_id = SPI3_HOST,
.cs_id = 0,
// uses GPIO matrix on esp32s2 regardless of FORCE_GPIO_MATRIX
.cs_io_num = SPI2_PIN_NUM_CS,
.input_delay_ns = 0,
},
};
FLASHTEST_CONFIG_COMMON,
{
.io_mode = TEST_SPI_READ_MODE,
.freq_mhz = TEST_SPI_SPEED,
.host_id = SPI2_HOST,
.cs_id = 0,
.cs_io_num = SPI2_PIN_NUM_CS,
.input_delay_ns = 0,
},
{
.io_mode = TEST_SPI_READ_MODE,
.freq_mhz = TEST_SPI_SPEED,
.host_id = SPI3_HOST,
.cs_id = 0,
// uses GPIO matrix on esp32s2 regardless of FORCE_GPIO_MATRIX
.cs_io_num = SPI2_PIN_NUM_CS,
.input_delay_ns = 0,
},
};
#elif CONFIG_IDF_TARGET_ESP32S3
flashtest_config_t config_list[] = {
/* No SPI1 CS1 flash on esp32S3 test */
{
/* no need to init */
.host_id = -1,
},
{
.io_mode = TEST_SPI_READ_MODE,
.freq_mhz = TEST_SPI_SPEED,
.host_id = SPI2_HOST,
.cs_id = 0,
.cs_io_num = SPI2_PIN_NUM_CS,
.input_delay_ns = 0,
},
};
/* No SPI1 CS1 flash on esp32S3 test */
{
/* no need to init */
.host_id = -1,
},
{
.io_mode = TEST_SPI_READ_MODE,
.freq_mhz = TEST_SPI_SPEED,
.host_id = SPI2_HOST,
.cs_id = 0,
.cs_io_num = SPI2_PIN_NUM_CS,
.input_delay_ns = 0,
},
};
#else
flashtest_config_t config_list[] = {
/* No SPI1 CS1 flash on esp32c3 test */
{
/* no need to init */
.host_id = -1,
},
{
.io_mode = TEST_SPI_READ_MODE,
.freq_mhz = TEST_SPI_SPEED,
.host_id = SPI2_HOST,
.cs_id = 0,
.cs_io_num = SPI2_PIN_NUM_CS,
.input_delay_ns = 0,
},
};
/* No SPI1 CS1 flash on esp32c3 test */
{
/* no need to init */
.host_id = -1,
},
{
.io_mode = TEST_SPI_READ_MODE,
.freq_mhz = TEST_SPI_SPEED,
.host_id = SPI2_HOST,
.cs_id = 0,
.cs_io_num = SPI2_PIN_NUM_CS,
.input_delay_ns = 0,
},
};
#endif

View File

@@ -12,7 +12,9 @@
#include <unity.h>
#include "esp_flash.h"
#include "esp_flash_chips/esp_flash_types.h" // For esp_flash_t structure definition
#include "esp_private/spi_common_internal.h"
#include "esp_private/spi_flash_os.h"
#include "esp_flash_spi_init.h"
#include "esp_private/memspi_host_driver.h"
#include <esp_attr.h>
@@ -31,7 +33,6 @@
#include "esp_rom_sys.h"
#include "esp_timer.h"
#include "test_esp_flash_def.h"
#include "esp_private/spi_flash_os.h"
#include "ccomp_timer.h"
static uint8_t sector_buf[4096];
@@ -229,7 +230,7 @@ static void flash_test_func(flash_test_func_t func, int test_num)
{
esp_log_level_set("gpio", ESP_LOG_NONE);
for (int i = 0; i < test_num; i++) {
ESP_LOGI(TAG, "Testing config %u/%u", i+1, test_num);
ESP_LOGI(TAG, "Testing config %u/%u", i + 1, test_num);
flash_test_core(func, &config_list[i]);
}
ESP_LOGI(TAG, "Completed %u configs", test_num);
@@ -264,7 +265,7 @@ static uint32_t erase_test_region(const esp_partition_t *part, int num_sectors)
bzero(sector_buf, sizeof(sector_buf));
printf("Erase @ 0x%lx...\n", offs);
TEST_ASSERT_EQUAL_HEX32(ESP_OK, esp_flash_erase_region(chip, offs, num_sectors * 4096) );
TEST_ASSERT_EQUAL_HEX32(ESP_OK, esp_flash_erase_region(chip, offs, num_sectors * 4096));
printf("Verify erased...\n");
for (int i = 0; i < num_sectors; i++) {
@@ -291,12 +292,12 @@ void test_simple_read_write(const esp_partition_t* part)
}
printf("Write %p...\n", (void *)offs);
TEST_ASSERT_EQUAL(ESP_OK, esp_flash_write(chip, sector_buf, offs, sizeof(sector_buf)) );
TEST_ASSERT_EQUAL(ESP_OK, esp_flash_write(chip, sector_buf, offs, sizeof(sector_buf)));
bzero(sector_buf, sizeof(sector_buf));
printf("Read back...\n");
TEST_ASSERT_EQUAL(ESP_OK, esp_flash_read(chip, sector_buf, offs, sizeof(sector_buf)) );
TEST_ASSERT_EQUAL(ESP_OK, esp_flash_read(chip, sector_buf, offs, sizeof(sector_buf)));
printf("Buffer starts 0x%02x 0x%02x 0x%02x 0x%02x\n", sector_buf[0], sector_buf[1], sector_buf[2], sector_buf[3]);
@@ -317,13 +318,13 @@ void test_unaligned_read_write(const esp_partition_t* part)
const char *msg = "i am a message";
TEST_ASSERT(strlen(msg) + 1 % 4 != 0);
TEST_ASSERT_EQUAL(ESP_OK, esp_flash_write(chip, msg, offs + 1, strlen(msg) + 1) );
TEST_ASSERT_EQUAL(ESP_OK, esp_flash_write(chip, msg, offs + 1, strlen(msg) + 1));
char buf[strlen(msg) + 1];
memset(buf, 0xEE, sizeof(buf));
TEST_ASSERT_EQUAL(ESP_OK, esp_flash_read(chip, buf, offs + 1, strlen(msg) + 1) );
TEST_ASSERT_EQUAL(ESP_OK, esp_flash_read(chip, buf, offs + 1, strlen(msg) + 1));
TEST_ASSERT_EQUAL_STRING_LEN(msg, buf, strlen(msg));
TEST_ASSERT(memcmp(buf, msg, strlen(msg) + 1) == 0);
}
@@ -340,14 +341,14 @@ void test_single_read_write(const esp_partition_t* part)
srand(seed);
for (unsigned v = 0; v < 512; v++) {
uint32_t data = rand();
TEST_ASSERT_EQUAL_HEX(ESP_OK, esp_flash_write(chip, &data, offs + v, 1) );
TEST_ASSERT_EQUAL_HEX(ESP_OK, esp_flash_write(chip, &data, offs + v, 1));
}
srand(seed);
for (unsigned v = 0; v < 512; v++) {
uint8_t readback;
uint32_t data = rand();
TEST_ASSERT_EQUAL_HEX(ESP_OK, esp_flash_read(chip, &readback, offs + v, 1) );
TEST_ASSERT_EQUAL_HEX(ESP_OK, esp_flash_read(chip, &readback, offs + v, 1));
TEST_ASSERT_EQUAL_HEX8(data, readback);
}
}
@@ -355,7 +356,6 @@ void test_single_read_write(const esp_partition_t* part)
TEST_CASE_FLASH("SPI flash single byte reads/writes", test_single_read_write);
TEST_CASE_MULTI_FLASH("SPI flash single byte reads/writes", test_single_read_write);
/* this test is notable because it generates a lot of unaligned reads/writes,
and also reads/writes across both a sector boundary & many page boundaries.
*/
@@ -370,14 +370,14 @@ void test_three_byte_read_write(const esp_partition_t* part)
srand(seed);
for (uint32_t v = 0; v < 86; v++) {
uint32_t data = rand();
TEST_ASSERT_EQUAL(ESP_OK, esp_flash_write(chip, &data, offs + 3 * v, 3) );
TEST_ASSERT_EQUAL(ESP_OK, esp_flash_write(chip, &data, offs + 3 * v, 3));
}
srand(seed);
for (uint32_t v = 0; v < 1; v++) {
uint32_t readback;
uint32_t data = rand();
TEST_ASSERT_EQUAL(ESP_OK, esp_flash_read(chip, &readback, offs + 3 * v, 3) );
TEST_ASSERT_EQUAL(ESP_OK, esp_flash_read(chip, &readback, offs + 3 * v, 3));
TEST_ASSERT_EQUAL_HEX32(data & 0xFFFFFF, readback & 0xFFFFFF);
}
}
@@ -478,7 +478,7 @@ void test_flash_wrap(const esp_partition_t* part)
wrap_buf[i] = rand();
}
printf("Write %p...\n", (void *)offs);
TEST_ASSERT_EQUAL(ESP_OK, esp_flash_write(chip, wrap_buf, offs + 3, sizeof(wrap_buf)) );
TEST_ASSERT_EQUAL(ESP_OK, esp_flash_write(chip, wrap_buf, offs + 3, sizeof(wrap_buf)));
bzero(wrap_buf, sizeof(wrap_buf));
@@ -542,7 +542,7 @@ static bool is_mxic_chip(esp_flash_t* chip)
uint32_t flash_id;
esp_err_t ret = esp_flash_read_chip_id(chip, &flash_id);
TEST_ESP_OK(ret);
return (spi_flash_chip_mxic_probe(chip, flash_id)==ESP_OK);
return (spi_flash_chip_mxic_probe(chip, flash_id) == ESP_OK);
}
IRAM_ATTR NOINLINE_ATTR static void test_toggle_qe(const esp_partition_t* part)
@@ -562,7 +562,7 @@ IRAM_ATTR NOINLINE_ATTR static void test_toggle_qe(const esp_partition_t* part)
for (int i = 0; i < 4; i ++) {
esp_rom_printf(DRAM_STR("write qe: %" PRIu32 "->%" PRIu32 "\n"), qe, !qe);
qe = !qe;
chip->read_mode = qe? SPI_FLASH_QOUT: SPI_FLASH_SLOWRD;
chip->read_mode = qe ? SPI_FLASH_QOUT : SPI_FLASH_SLOWRD;
ret = esp_flash_set_io_mode(chip, qe);
if (allow_failure && !qe && ret == ESP_ERR_FLASH_NO_RESPONSE) {
//allows clear qe failure for Winbond chips
@@ -609,7 +609,7 @@ void test_permutations_part(const flashtest_config_t* config, esp_partition_t* p
{
int clock_index = 0;
if (config->host_id != -1) {
while (clock_index < sizeof(flash_frequency_table)/sizeof(uint8_t)) {
while (clock_index < sizeof(flash_frequency_table) / sizeof(uint8_t)) {
uint8_t speed = flash_frequency_table[clock_index];
//test io_mode in the inner loop to test QE set/clear function, since
//the io mode will switch frequently.
@@ -686,16 +686,20 @@ void test_permutations_chip(const flashtest_config_t* config)
}
for (int i = 0; i < 2; i++) {
if (part[i].size == 0) continue;
if (part[i].size == 0) {
continue;
}
write_large_buffer(&part[i], source_buf, length);
}
teardown_test_chip(chip);
for (int i = 0; i < 2; i++) {
if (part[i].size == 0) continue;
if (part[i].size == 0) {
continue;
}
part[i].flash_chip = (esp_flash_t*)-1;
part[i].flash_chip = (esp_flash_t*) -1;
ESP_LOGI(TAG, "Testing address 0x%08lX...", part[i].address);
test_permutations_part(config, &part[i], source_buf, length);
}
@@ -717,7 +721,6 @@ TEST_CASE("SPI flash test reading with all speed/mode permutations, 3 chips", "[
}
#endif
static void test_write_large_const_buffer(const esp_partition_t* part)
{
test_write_large_buffer(part, large_const_buffer, sizeof(large_const_buffer));
@@ -744,10 +747,10 @@ static void write_large_buffer(const esp_partition_t *part, const uint8_t *sourc
esp_flash_t* chip = part->flash_chip;
printf("Writing chip %p %p, %u bytes from source %p\n", chip, (void*)part->address, length, source);
ESP_ERROR_CHECK( esp_flash_erase_region(chip, part->address, (length + part->erase_size) & ~(part->erase_size - 1)) );
ESP_ERROR_CHECK(esp_flash_erase_region(chip, part->address, (length + part->erase_size) & ~(part->erase_size - 1)));
// note writing to unaligned address
ESP_ERROR_CHECK( esp_flash_write(chip, source, part->address + 1, length) );
ESP_ERROR_CHECK(esp_flash_write(chip, source, part->address + 1, length));
}
static void read_and_check(const esp_partition_t *part, const uint8_t *source, size_t length)
@@ -756,18 +759,18 @@ static void read_and_check(const esp_partition_t *part, const uint8_t *source, s
printf("Checking chip %p 0x%08lX, %u bytes\n", chip, part->address, length);
uint8_t *buf = malloc(length);
TEST_ASSERT_NOT_NULL(buf);
ESP_ERROR_CHECK( esp_flash_read(chip, buf, part->address + 1, length) );
ESP_ERROR_CHECK(esp_flash_read(chip, buf, part->address + 1, length));
TEST_ASSERT_EQUAL_HEX8_ARRAY(source, buf, length);
free(buf);
// check nothing was written at beginning or end
uint8_t ends[8];
ESP_ERROR_CHECK( esp_flash_read(chip, ends, part->address, sizeof(ends)) );
ESP_ERROR_CHECK(esp_flash_read(chip, ends, part->address, sizeof(ends)));
TEST_ASSERT_EQUAL_HEX8(0xFF, ends[0]);
TEST_ASSERT_EQUAL_HEX8(source[0], ends[1]);
ESP_ERROR_CHECK( esp_flash_read(chip, ends, part->address + length, sizeof(ends)) );
ESP_ERROR_CHECK(esp_flash_read(chip, ends, part->address + length, sizeof(ends)));
TEST_ASSERT_EQUAL_HEX8(source[length - 1], ends[0]);
TEST_ASSERT_EQUAL_HEX8(0xFF, ends[1]);
@@ -793,20 +796,20 @@ static void test_write_over_boundary(const esp_partition_t* part)
const uint32_t SECTOR_SIZE = 4096;
uint8_t buf[0];
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_erase_region(chip, 0, flash_size+SECTOR_SIZE));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_erase_region(chip, 0, flash_size + SECTOR_SIZE));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_erase_region(chip, SECTOR_SIZE, flash_size));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_erase_region(chip, flash_size/2, flash_size/2 + SECTOR_SIZE));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_erase_region(chip, flash_size/2 + SECTOR_SIZE, flash_size/2));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_erase_region(chip, flash_size / 2, flash_size / 2 + SECTOR_SIZE));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_erase_region(chip, flash_size / 2 + SECTOR_SIZE, flash_size / 2));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_erase_region(chip, flash_size - SECTOR_SIZE, 2 * SECTOR_SIZE));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_erase_region(chip, 2 * SECTOR_SIZE, flash_size - SECTOR_SIZE));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_erase_region(chip, flash_size - SECTOR_SIZE, flash_size - SECTOR_SIZE));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_erase_region(chip, flash_size - SECTOR_SIZE, UINT32_MAX - SECTOR_SIZE + 1));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_erase_region(chip, UINT32_MAX - SECTOR_SIZE + 1, flash_size - SECTOR_SIZE));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_write(chip, buf, 0, flash_size+SECTOR_SIZE));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_write(chip, buf, 0, flash_size + SECTOR_SIZE));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_write(chip, buf, SECTOR_SIZE, flash_size));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_write(chip, buf, flash_size/2, flash_size/2 + SECTOR_SIZE));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_write(chip, buf, flash_size/2 + SECTOR_SIZE, flash_size/2));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_write(chip, buf, flash_size / 2, flash_size / 2 + SECTOR_SIZE));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_write(chip, buf, flash_size / 2 + SECTOR_SIZE, flash_size / 2));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_write(chip, buf, flash_size - SECTOR_SIZE, 2 * SECTOR_SIZE));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_write(chip, buf, 2 * SECTOR_SIZE, flash_size - SECTOR_SIZE));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_write(chip, buf, flash_size - SECTOR_SIZE, flash_size - SECTOR_SIZE));
@@ -836,7 +839,7 @@ static uint32_t time_measure_end(time_meas_ctx_t* ctx)
uint32_t c_time_us = ccomp_timer_stop();
uint32_t time_us = esp_timer_get_time() - ctx->us_start;
ESP_LOGI(TAG, "%s: compensated: %.2lf kB/s, typical: %.2lf kB/s", ctx->name, ctx->len / (c_time_us / 1000.), ctx->len / (time_us/1000.));
ESP_LOGI(TAG, "%s: compensated: %.2lf kB/s, typical: %.2lf kB/s", ctx->name, ctx->len / (c_time_us / 1000.), ctx->len / (time_us / 1000.));
return ctx->len * 1000 / (c_time_us / 1000);
}
@@ -902,8 +905,7 @@ static uint32_t measure_read(const char* name, const esp_partition_t* part, uint
static const char* get_chip_vendor(uint32_t id)
{
switch (id)
{
switch (id) {
case 0x20:
return "XMC";
break;
@@ -967,7 +969,7 @@ static void test_flash_read_write_performance(const esp_partition_t *part)
LOG_PERFORMANCE(EXT_, chip_name);
} else if (cs_id == 0) {
// Main flash
LOG_PERFORMANCE(,chip_name);
LOG_PERFORMANCE(, chip_name);
} else {
// Other cs pins on SPI1
LOG_PERFORMANCE(SPI1_, chip_name);
@@ -978,7 +980,10 @@ static void test_flash_read_write_performance(const esp_partition_t *part)
#if !BYPASS_MULTIPLE_CHIP
//To make performance data stable, needs to run on special runner
TEST_CASE("Test esp_flash read/write performance", "[esp_flash][test_env=UT_T1_ESP_FLASH]") {flash_test_func(test_flash_read_write_performance, 1);}
TEST_CASE("Test esp_flash read/write performance", "[esp_flash][test_env=UT_T1_ESP_FLASH]")
{
flash_test_func(test_flash_read_write_performance, 1);
}
#endif
TEST_CASE_MULTI_FLASH("Test esp_flash read/write performance", test_flash_read_write_performance);
@@ -992,12 +997,12 @@ TEST_CASE_MULTI_FLASH("Test esp_flash read/write performance", test_flash_read_w
static void s_test_compare_flash_contents_small_reads(esp_flash_t *chip, const uint8_t *buffer, size_t offs, size_t len)
{
const size_t INTERNAL_BUF_SZ = 1024; // Should fit in internal RAM
uint8_t *ibuf = heap_caps_malloc(INTERNAL_BUF_SZ, MALLOC_CAP_8BIT|MALLOC_CAP_INTERNAL);
uint8_t *ibuf = heap_caps_malloc(INTERNAL_BUF_SZ, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
TEST_ASSERT_NOT_NULL(ibuf);
for (int i = 0; i < len; i += INTERNAL_BUF_SZ) {
size_t to_read = MIN(INTERNAL_BUF_SZ, len - i);
ESP_ERROR_CHECK( esp_flash_read(chip, ibuf, offs + i, to_read) );
ESP_ERROR_CHECK(esp_flash_read(chip, ibuf, offs + i, to_read));
TEST_ASSERT_EQUAL_HEX8_ARRAY(buffer + i, ibuf, to_read);
}
@@ -1010,10 +1015,10 @@ static void test_flash_read_large_psram_buffer(const esp_partition_t *part)
const size_t BUF_SZ = 256 * 1024; // Too large for internal RAM
const size_t TEST_OFFS = 0x1000; // Can be any offset, really
uint8_t *buf = heap_caps_malloc(BUF_SZ, MALLOC_CAP_8BIT|MALLOC_CAP_SPIRAM);
uint8_t *buf = heap_caps_malloc(BUF_SZ, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM);
TEST_ASSERT_NOT_NULL(buf);
ESP_ERROR_CHECK( esp_flash_read(chip, buf, TEST_OFFS, BUF_SZ) );
ESP_ERROR_CHECK(esp_flash_read(chip, buf, TEST_OFFS, BUF_SZ));
// Read back the same into smaller internal memory buffer and check it all matches
s_test_compare_flash_contents_small_reads(chip, buf, TEST_OFFS, BUF_SZ);
@@ -1023,7 +1028,6 @@ static void test_flash_read_large_psram_buffer(const esp_partition_t *part)
TEST_CASE_FLASH("esp_flash_read large PSRAM buffer", test_flash_read_large_psram_buffer);
/* similar to above test, but perform it under memory pressure */
static void test_flash_read_large_psram_buffer_low_internal_mem(const esp_partition_t *part)
{
@@ -1033,14 +1037,14 @@ static void test_flash_read_large_psram_buffer_low_internal_mem(const esp_partit
const size_t TEST_OFFS = 0x8000;
/* Exhaust the available free internal memory */
test_utils_exhaust_memory_rec erec = test_utils_exhaust_memory(MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT, REMAINING_INTERNAL);
test_utils_exhaust_memory_rec erec = test_utils_exhaust_memory(MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT, REMAINING_INTERNAL);
uint8_t *buf = heap_caps_malloc(BUF_SZ, MALLOC_CAP_8BIT|MALLOC_CAP_SPIRAM);
uint8_t *buf = heap_caps_malloc(BUF_SZ, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM);
TEST_ASSERT_NOT_NULL(buf);
/* Calling esp_flash_read() here will need to allocate a small internal buffer,
so check it works. */
ESP_ERROR_CHECK( esp_flash_read(chip, buf, TEST_OFFS, BUF_SZ) );
ESP_ERROR_CHECK(esp_flash_read(chip, buf, TEST_OFFS, BUF_SZ));
test_utils_free_exhausted_memory(erec);
@@ -1053,7 +1057,6 @@ static void test_flash_read_large_psram_buffer_low_internal_mem(const esp_partit
TEST_CASE_FLASH("esp_flash_read large PSRAM buffer low memory", test_flash_read_large_psram_buffer_low_internal_mem);
#endif
#if CONFIG_SPI_FLASH_ENABLE_COUNTERS
#define TEST_CNT_RW_TIMES 4
#define TEST_CNT_RW_LEN 64
@@ -1066,7 +1069,7 @@ void test_flash_counter(const esp_partition_t* part)
static uint8_t write_buf[TEST_CNT_RW_LEN * TEST_CNT_RW_TIMES];
static uint8_t read_buf[TEST_CNT_RW_LEN * TEST_CNT_RW_TIMES];
for(int i = 0;i < TEST_CNT_RW_LEN * TEST_CNT_RW_TIMES; i ++){
for (int i = 0; i < TEST_CNT_RW_LEN * TEST_CNT_RW_TIMES; i ++) {
write_buf[i] = i;
}
@@ -1086,15 +1089,15 @@ void test_flash_counter(const esp_partition_t* part)
TEST_ASSERT_EQUAL_UINT32(TEST_CNT_ERASE_LEN, flash_counter.erase.bytes);
int count;
for(count = 0; count < TEST_CNT_RW_TIMES; count ++) {
for (count = 0; count < TEST_CNT_RW_TIMES; count ++) {
// check counter on write option
TEST_ASSERT_EQUAL(ESP_OK, esp_flash_write(chip, write_buf + TEST_CNT_RW_LEN * count, offs + TEST_CNT_RW_LEN * count, TEST_CNT_RW_LEN) );
TEST_ASSERT_EQUAL(ESP_OK, esp_flash_write(chip, write_buf + TEST_CNT_RW_LEN * count, offs + TEST_CNT_RW_LEN * count, TEST_CNT_RW_LEN));
flash_counter = *esp_flash_get_counters();
TEST_ASSERT_EQUAL_UINT32((count + 1), flash_counter.write.count);
TEST_ASSERT_EQUAL_UINT32((count + 1) * TEST_CNT_RW_LEN, flash_counter.write.bytes);
// check counter on read option
TEST_ASSERT_EQUAL(ESP_OK, esp_flash_read(chip, read_buf + TEST_CNT_RW_LEN * count, offs + TEST_CNT_RW_LEN * count, TEST_CNT_RW_LEN) );
TEST_ASSERT_EQUAL(ESP_OK, esp_flash_read(chip, read_buf + TEST_CNT_RW_LEN * count, offs + TEST_CNT_RW_LEN * count, TEST_CNT_RW_LEN));
flash_counter = *esp_flash_get_counters();
TEST_ASSERT_EQUAL_UINT32((count + 1), flash_counter.read.count);
TEST_ASSERT_EQUAL_UINT32((count + 1) * TEST_CNT_RW_LEN, flash_counter.read.bytes);
@@ -1114,8 +1117,8 @@ void test_flash_counter(const esp_partition_t* part)
TEST_ASSERT_EACH_EQUAL_HEX8(0, &flash_counter, sizeof(esp_flash_counters_t));
#if SOC_FLASH_ENC_SUPPORTED
TEST_ASSERT_EQUAL(ESP_OK, esp_flash_write_encrypted(chip, offs, write_buf, TEST_CNT_RW_LEN) );
TEST_ASSERT_EQUAL(ESP_OK, esp_flash_read_encrypted(chip, offs, read_buf, TEST_CNT_RW_LEN) );
TEST_ASSERT_EQUAL(ESP_OK, esp_flash_write_encrypted(chip, offs, write_buf, TEST_CNT_RW_LEN));
TEST_ASSERT_EQUAL(ESP_OK, esp_flash_read_encrypted(chip, offs, read_buf, TEST_CNT_RW_LEN));
printf("\ntest for encrypted write/read\n");
esp_flash_dump_counters(stdout);
@@ -1137,7 +1140,7 @@ TEST_CASE_FLASH("SPI flash counter test", test_flash_counter);
#if CONFIG_SPI_FLASH_DANGEROUS_WRITE_FAILS
TEST_CASE("test writes to dangerous regions like bootloader", "[esp_flash]")
{
TEST_ASSERT_EQUAL_HEX(ESP_ERR_INVALID_ARG, esp_flash_erase_region(NULL, CONFIG_BOOTLOADER_OFFSET_IN_FLASH, 4*4096));
TEST_ASSERT_EQUAL_HEX(ESP_ERR_INVALID_ARG, esp_flash_erase_region(NULL, CONFIG_BOOTLOADER_OFFSET_IN_FLASH, 4 * 4096));
TEST_ASSERT_EQUAL_HEX(ESP_ERR_INVALID_ARG, esp_flash_erase_region(NULL, CONFIG_PARTITION_TABLE_OFFSET, 4096));
char buffer[32] = {0xa5};
// Encrypted writes to bootloader region not allowed

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
@@ -10,7 +10,6 @@
#include <freertos/semphr.h>
#include "unity.h"
#include "spi_flash_mmap.h"
#include "esp_attr.h"
#include "esp_intr_alloc.h"
#include "ccomp_timer.h"
@@ -20,6 +19,8 @@
#include "esp_timer.h"
#include "esp_partition.h"
#include "bootloader_flash.h" //for bootloader_flash_xmc_startup
#include "esp_flash.h"
#include "spi_flash_mmap.h"
#include "test_utils.h"
#include "sdkconfig.h"
@@ -96,11 +97,11 @@ TEST_CASE("flash write and erase work both on PRO CPU and on APP CPU", "[spi_fla
SemaphoreHandle_t done = xSemaphoreCreateCounting(4, 0);
struct flash_test_ctx ctx[] = {
{ .offset = 0x10 + 6, .done = done },
{ .offset = 0x10 + 7, .done = done },
{ .offset = 0x10 + 8, .done = done },
{ .offset = 0x10 + 6, .done = done },
{ .offset = 0x10 + 7, .done = done },
{ .offset = 0x10 + 8, .done = done },
#ifndef CONFIG_FREERTOS_UNICORE
{ .offset = 0x10 + 9, .done = done }
{ .offset = 0x10 + 9, .done = done }
#endif
};
@@ -111,7 +112,7 @@ TEST_CASE("flash write and erase work both on PRO CPU and on APP CPU", "[spi_fla
xTaskCreatePinnedToCore(flash_test_task, "t3", 2048, &ctx[3], 3, NULL, 1);
#endif
const size_t task_count = sizeof(ctx)/sizeof(ctx[0]);
const size_t task_count = sizeof(ctx) / sizeof(ctx[0]);
for (int i = 0; i < task_count; ++i) {
xSemaphoreTake(done, portMAX_DELAY);
}

View File

@@ -903,7 +903,6 @@ static void cleanup_interrupt_timer(void)
}
}
/**
* Helper function: Test interrupt during encrypt with PM configuration
* Common test logic for both PM enabled and disabled scenarios
@@ -1247,5 +1246,4 @@ TEST_CASE("Frequency limit: APB lock released in ISR", "[esp_flash_freq_limit]")
}
#endif // CONFIG_PM_ENABLE
#endif // CONFIG_IDF_TARGET_ESP32C5

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -127,7 +127,7 @@ TEST_CASE("Flash UniCore: Test ESP Flash API Concurrency [Stress]", "[esp_flash]
xTaskCreatePinnedToCore(&s_test_flash_ops_task, flash_task_name, 4096, (void *)(&ctx), 5, NULL, 0);
}
while(1);
while (1);
}
#if !CONFIG_FREERTOS_UNICORE
@@ -167,7 +167,6 @@ TEST_CASE("Flash DualCore: Test ESP Flash API Concurrency", "[esp_flash]")
vSemaphoreDelete(s_test_concurrency_smphr);
}
/**
* esp_flash APIs concurrency pressure test
* This test is for manually test
@@ -195,6 +194,6 @@ TEST_CASE("Flash DualCore: Test ESP Flash API Concurrency [Stress]", "[esp_flash
xTaskCreatePinnedToCore(&s_test_flash_ops_task, flash_task_name, 4096, (void *)(&ctx), 5, NULL, 1);
}
while(1);
while (1);
}
#endif //#if !CONFIG_FREERTOS_UNICORE

View File

@@ -2,5 +2,6 @@ set(srcs "test_app_main.c"
"test_flash_encryption.c")
idf_component_register(SRCS ${srcs}
PRIV_REQUIRES unity spi_flash bootloader_support esp_partition test_utils test_flash_utils
PRIV_REQUIRES unity spi_flash bootloader_support esp_partition test_utils
test_flash_utils
WHOLE_ARCHIVE)

View File

@@ -25,7 +25,7 @@ static void check_leak(size_t before_free, size_t after_free, const char *type)
void setUp(void)
{
// Calling esp_partition_find_first ensures that the paritions have been loaded
// Calling esp_partition_find_first ensures that the partitions have been loaded
// and subsequent calls to esp_partition_find_first from the tests would not
// load partitions which otherwise gets considered as a memory leak.
esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, NULL);

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
@@ -50,7 +50,7 @@ static void setup_tests(void)
static void verify_erased_flash(size_t offset, size_t length)
{
uint8_t *readback = (uint8_t *)heap_caps_malloc(SPI_FLASH_SEC_SIZE, MALLOC_CAP_32BIT | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
printf("verify erased 0x%" PRIx32 " - 0x%" PRIx32 "\n", (uint32_t) offset, (uint32_t) (offset + length));
printf("verify erased 0x%" PRIx32 " - 0x%" PRIx32 "\n", (uint32_t) offset, (uint32_t)(offset + length));
TEST_ASSERT_EQUAL_HEX(ESP_OK,
esp_flash_read(NULL, readback, offset, length));
for (int i = 0; i < length; i++) {
@@ -64,19 +64,19 @@ TEST_CASE("test 16 byte encrypted writes", "[flash_encryption]")
setup_tests();
TEST_ASSERT_EQUAL_HEX(ESP_OK,
esp_flash_erase_region(NULL, start, SPI_FLASH_SEC_SIZE));
esp_flash_erase_region(NULL, start, SPI_FLASH_SEC_SIZE));
uint8_t fortyeight_bytes[0x30]; // 0, 1, 2, 3, 4... 47
for(int i = 0; i < sizeof(fortyeight_bytes); i++) {
for (int i = 0; i < sizeof(fortyeight_bytes); i++) {
fortyeight_bytes[i] = i;
}
/* Verify unaligned start or length fails */
TEST_ASSERT_EQUAL_HEX(ESP_ERR_INVALID_ARG,
esp_flash_write_encrypted(NULL, start + 1, fortyeight_bytes, 32));
esp_flash_write_encrypted(NULL, start + 1, fortyeight_bytes, 32));
TEST_ASSERT_EQUAL_HEX(ESP_ERR_INVALID_SIZE,
esp_flash_write_encrypted(NULL, start, fortyeight_bytes, 15));
esp_flash_write_encrypted(NULL, start, fortyeight_bytes, 15));
/* ensure nothing happened to the flash yet */
verify_erased_flash(start, 0x20);
@@ -87,8 +87,8 @@ TEST_CASE("test 16 byte encrypted writes", "[flash_encryption]")
/* Slip in an unaligned esp_flash_read_encrypted() test */
uint8_t buf[0x10];
esp_flash_read_encrypted(NULL, start+0x10, buf, 0x10);
TEST_ASSERT_EQUAL_HEX8_ARRAY(fortyeight_bytes+0x10, buf, 16);
esp_flash_read_encrypted(NULL, start + 0x10, buf, 0x10);
TEST_ASSERT_EQUAL_HEX8_ARRAY(fortyeight_bytes + 0x10, buf, 16);
/* Write 16 bytes unaligned */
test_encrypted_write(start + 0x30, fortyeight_bytes, 0x10);
@@ -124,7 +124,7 @@ TEST_CASE("test read & write random encrypted data", "[flash_encryption]")
{
const int MAX_LEN = 192;
//buffer to hold the read data
WORD_ALIGNED_ATTR uint8_t buffer_to_write[MAX_LEN+4];
WORD_ALIGNED_ATTR uint8_t buffer_to_write[MAX_LEN + 4];
//test with unaligned buffer
uint8_t* data_buf = &buffer_to_write[3];
@@ -145,7 +145,7 @@ TEST_CASE("test read & write random encrypted data", "[flash_encryption]")
do {
//the encrypted write only works at 16-byte boundary
int skip = (rand() % 4) * 16;
int len = ((rand() % (MAX_LEN/16)) + 1) * 16;
int len = ((rand() % (MAX_LEN / 16)) + 1) * 16;
for (int i = 0; i < MAX_LEN; i++) {
data_buf[i] = rand();
@@ -159,7 +159,7 @@ TEST_CASE("test read & write random encrypted data", "[flash_encryption]")
len = SPI_FLASH_SEC_SIZE - offset;
}
printf("write %d bytes to 0x%08" PRIx32 "...\n", len, (uint32_t) (start + offset));
printf("write %d bytes to 0x%08" PRIx32 "...\n", len, (uint32_t)(start + offset));
err = esp_flash_write_encrypted(NULL, start + offset, data_buf, len);
TEST_ESP_OK(err);
@@ -169,7 +169,7 @@ TEST_CASE("test read & write random encrypted data", "[flash_encryption]")
offset = 0;
do {
int len = ((rand() % (MAX_LEN/16)) + 1) * 16;
int len = ((rand() % (MAX_LEN / 16)) + 1) * 16;
if (offset + len > SPI_FLASH_SEC_SIZE) {
len = SPI_FLASH_SEC_SIZE - offset;
}
@@ -177,7 +177,7 @@ TEST_CASE("test read & write random encrypted data", "[flash_encryption]")
err = esp_flash_read_encrypted(NULL, start + offset, data_buf, len);
TEST_ESP_OK(err);
printf("compare %d bytes at 0x%08" PRIx32 "...\n", len, (uint32_t) (start + offset));
printf("compare %d bytes at 0x%08" PRIx32 "...\n", len, (uint32_t)(start + offset));
TEST_ASSERT_EQUAL_HEX8_ARRAY(cmp_buf + offset, data_buf, len);
offset += len;
@@ -208,19 +208,19 @@ TEST_CASE("test 16 byte encrypted writes (esp_flash)", "[flash_encryption]")
setup_tests();
TEST_ASSERT_EQUAL_HEX(ESP_OK,
esp_flash_erase_region(NULL, start, SPI_FLASH_SEC_SIZE));
esp_flash_erase_region(NULL, start, SPI_FLASH_SEC_SIZE));
uint8_t fortyeight_bytes[0x30]; // 0, 1, 2, 3, 4... 47
for(int i = 0; i < sizeof(fortyeight_bytes); i++) {
for (int i = 0; i < sizeof(fortyeight_bytes); i++) {
fortyeight_bytes[i] = i;
}
/* Verify unaligned start or length fails */
TEST_ASSERT_EQUAL_HEX(ESP_ERR_INVALID_ARG,
esp_flash_write_encrypted(NULL, start+1, fortyeight_bytes, 32));
esp_flash_write_encrypted(NULL, start + 1, fortyeight_bytes, 32));
TEST_ASSERT_EQUAL_HEX(ESP_ERR_INVALID_SIZE,
esp_flash_write_encrypted(NULL, start, fortyeight_bytes, 15));
esp_flash_write_encrypted(NULL, start, fortyeight_bytes, 15));
/* ensure nothing happened to the flash yet */
verify_erased_flash(start, 0x20);
@@ -231,8 +231,8 @@ TEST_CASE("test 16 byte encrypted writes (esp_flash)", "[flash_encryption]")
/* Slip in an unaligned esp_flash_read_encrypted() test */
uint8_t buf[0x10];
esp_flash_read_encrypted(NULL, start+0x10, buf, 0x10);
TEST_ASSERT_EQUAL_HEX8_ARRAY(fortyeight_bytes+0x10, buf, 16);
esp_flash_read_encrypted(NULL, start + 0x10, buf, 0x10);
TEST_ASSERT_EQUAL_HEX8_ARRAY(fortyeight_bytes + 0x10, buf, 16);
/* Write 16 bytes unaligned */
test_encrypted_write_new_impl(start + 0x30, fortyeight_bytes, 0x10);
@@ -392,7 +392,7 @@ TEST_CASE("test read & write encrypted data with large buffer(n*64+32+16)", "[fl
TEST_ESP_OK(ccomp_timer_start());
TEST_ESP_OK(esp_flash_write_encrypted(NULL, start, large_const_buffer, sizeof(large_const_buffer)));
int64_t write_time = ccomp_timer_stop();
IDF_LOG_PERFORMANCE(TAG, "Writing speed: %.2f us/KB", (double)(write_time/sizeof(large_const_buffer))*1024);
IDF_LOG_PERFORMANCE(TAG, "Writing speed: %.2f us/KB", (double)(write_time / sizeof(large_const_buffer)) * 1024);
uint8_t *buf = (uint8_t*)heap_caps_malloc(sizeof(large_const_buffer), MALLOC_CAP_8BIT);
@@ -412,7 +412,7 @@ TEST_CASE("test read & write encrypted data with large buffer(n*64+32+16)", "[fl
TEST_ESP_OK(ccomp_timer_start());
TEST_ESP_OK(esp_flash_write_encrypted(NULL, start, large_const_buffer, sizeof(large_const_buffer)));
write_time = ccomp_timer_stop();
IDF_LOG_PERFORMANCE(TAG, "Writing speed: %.2f us/KB", (double)(write_time/sizeof(large_const_buffer))*1024);
IDF_LOG_PERFORMANCE(TAG, "Writing speed: %.2f us/KB", (double)(write_time / sizeof(large_const_buffer)) * 1024);
buf = (uint8_t*)heap_caps_malloc(sizeof(large_const_buffer), MALLOC_CAP_8BIT);
@@ -446,7 +446,7 @@ TEST_CASE("test read & write encrypted data with large buffer in ram", "[flash_e
TEST_ESP_OK(ccomp_timer_start());
TEST_ESP_OK(esp_flash_write_encrypted(NULL, start, large_const_buffer_dram, sizeof(large_const_buffer_dram)));
int64_t write_time = ccomp_timer_stop();
IDF_LOG_PERFORMANCE(TAG, "Writing speed: %.2f us/KB", (double)(write_time/sizeof(large_const_buffer_dram))*1024);
IDF_LOG_PERFORMANCE(TAG, "Writing speed: %.2f us/KB", (double)(write_time / sizeof(large_const_buffer_dram)) * 1024);
uint8_t *buf = (uint8_t*)heap_caps_malloc(sizeof(large_const_buffer_dram), MALLOC_CAP_32BIT | MALLOC_CAP_8BIT);
TEST_ESP_OK(esp_flash_read_encrypted(NULL, start, buf, sizeof(large_const_buffer_dram)));
@@ -457,7 +457,7 @@ TEST_CASE("test read & write encrypted data with large buffer in ram", "[flash_e
#if CONFIG_SPI_FLASH_DANGEROUS_WRITE_FAILS
TEST_CASE("test encrypted writes to dangerous regions like bootloader", "[flash_encryption]")
{
TEST_ASSERT_EQUAL_HEX(ESP_ERR_INVALID_ARG, esp_flash_erase_region(NULL, CONFIG_BOOTLOADER_OFFSET_IN_FLASH, 4*4096));
TEST_ASSERT_EQUAL_HEX(ESP_ERR_INVALID_ARG, esp_flash_erase_region(NULL, CONFIG_BOOTLOADER_OFFSET_IN_FLASH, 4 * 4096));
TEST_ASSERT_EQUAL_HEX(ESP_ERR_INVALID_ARG, esp_flash_erase_region(NULL, CONFIG_PARTITION_TABLE_OFFSET, 4096));
char buffer[32] = {0xa5};
// Encrypted writes to bootloader region not allowed
@@ -475,20 +475,20 @@ TEST_CASE("Test flash encrypted write over boundary", "[flash_encryption]")
const uint32_t SECTOR_SIZE = 4096;
uint8_t buf[0];
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_erase_region(chip, 0, flash_size+SECTOR_SIZE));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_erase_region(chip, 0, flash_size + SECTOR_SIZE));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_erase_region(chip, SECTOR_SIZE, flash_size));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_erase_region(chip, flash_size/2, flash_size/2 + SECTOR_SIZE));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_erase_region(chip, flash_size/2 + SECTOR_SIZE, flash_size/2));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_erase_region(chip, flash_size / 2, flash_size / 2 + SECTOR_SIZE));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_erase_region(chip, flash_size / 2 + SECTOR_SIZE, flash_size / 2));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_erase_region(chip, flash_size - SECTOR_SIZE, 2 * SECTOR_SIZE));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_erase_region(chip, 2 * SECTOR_SIZE, flash_size - SECTOR_SIZE));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_erase_region(chip, flash_size - SECTOR_SIZE, flash_size - SECTOR_SIZE));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_erase_region(chip, flash_size - SECTOR_SIZE, UINT32_MAX - SECTOR_SIZE + 1));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_erase_region(chip, UINT32_MAX - SECTOR_SIZE + 1, flash_size - SECTOR_SIZE));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_write_encrypted(chip, 0, buf, flash_size+SECTOR_SIZE));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_write_encrypted(chip, 0, buf, flash_size + SECTOR_SIZE));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_write_encrypted(chip, SECTOR_SIZE, buf, flash_size));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_write_encrypted(chip, flash_size/2, buf, flash_size/2 + SECTOR_SIZE));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_write_encrypted(chip, flash_size/2 + SECTOR_SIZE, buf, flash_size/2));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_write_encrypted(chip, flash_size / 2, buf, flash_size / 2 + SECTOR_SIZE));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_write_encrypted(chip, flash_size / 2 + SECTOR_SIZE, buf, flash_size / 2));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_write_encrypted(chip, flash_size - SECTOR_SIZE, buf, 2 * SECTOR_SIZE));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_write_encrypted(chip, 2 * SECTOR_SIZE, buf, flash_size - SECTOR_SIZE));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_write_encrypted(chip, flash_size - SECTOR_SIZE, buf, flash_size - SECTOR_SIZE));

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
@@ -14,7 +14,6 @@
static size_t before_free_8bit;
static size_t before_free_32bit;
void setUp(void)
{
before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
@@ -41,7 +40,6 @@ void app_main(void)
*/
printf("______ _ ___ _____ _ _ ___ ______ ___ ___ ______\n");
printf("| ___| | / _ \\ / ___| | | | | \\/ || \\/ | / _ \\ | ___ \\\n");
printf("| |_ | | / /_\\ \\\\ `--.| |_| | | . . || . . |/ /_\\ \\| |_/ /\n");

View File

@@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
# SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
import pytest
from pytest_embedded import Dut

View File

@@ -14,7 +14,6 @@
static size_t before_free_8bit;
static size_t before_free_32bit;
void setUp(void)
{
before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);

View File

@@ -47,7 +47,6 @@ DRAM_ATTR static uint32_t s_isr_interval_t2;
DRAM_ATTR static uint32_t s_isr_interval_time;
DRAM_ATTR static uint32_t times = 0;
static NOINLINE_ATTR void func_in_flash(void)
{
/**
@@ -66,7 +65,7 @@ static NOINLINE_ATTR void func_in_flash(void)
static bool IRAM_ATTR gptimer_alarm_suspend_cb(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_ctx)
{
s_isr_t1 = esp_cpu_get_cycle_count();
if (s_isr_interval_t1 != 0 ) {
if (s_isr_interval_t1 != 0) {
s_isr_interval_t2 = esp_cpu_get_cycle_count();
s_isr_interval_time += (s_isr_interval_t2 - s_isr_interval_t1);
}

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2010-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2010-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -22,8 +22,8 @@
static const uint8_t large_const_buffer[16400] = {
203, // first byte
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,
21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
[50 ... 99] = 2,
[1600 ... 2000] = 3,
[8000 ... 9000] = 77,
@@ -37,7 +37,7 @@ const esp_partition_t *get_test_data_partition(void)
{
/* This finds "flash_test" partition defined in partition_table_unit_test_app.csv */
const esp_partition_t *result = esp_partition_find_first(ESP_PARTITION_TYPE_DATA,
ESP_PARTITION_SUBTYPE_ANY, "flash_test");
ESP_PARTITION_SUBTYPE_ANY, "flash_test");
TEST_ASSERT_NOT_NULL(result); /* means partition table set wrong */
return result;
}
@@ -68,12 +68,12 @@ static void test_write_large_buffer(const uint8_t *source, size_t length)
uint8_t *buf = malloc(length);
TEST_ASSERT_NOT_NULL(buf);
TEST_ESP_OK( esp_flash_erase_region(NULL, part->address, (length + part->erase_size) & ~(part->erase_size-1)) );
TEST_ESP_OK(esp_flash_erase_region(NULL, part->address, (length + part->erase_size) & ~(part->erase_size - 1)));
// note writing to unaligned address
TEST_ESP_OK( esp_flash_write(NULL, source, part->address + 1, length) );
TEST_ESP_OK(esp_flash_write(NULL, source, part->address + 1, length));
TEST_ESP_OK( esp_flash_read(NULL, buf, part->address + 1, length) );
TEST_ESP_OK(esp_flash_read(NULL, buf, part->address + 1, length));
TEST_ASSERT_EQUAL_HEX8_ARRAY(source, buf, length);
@@ -82,12 +82,12 @@ static void test_write_large_buffer(const uint8_t *source, size_t length)
// check nothing was written at beginning or end
uint8_t ends[8];
TEST_ESP_OK( esp_flash_read(NULL, ends, part->address, sizeof(ends)) );
TEST_ESP_OK(esp_flash_read(NULL, ends, part->address, sizeof(ends)));
TEST_ASSERT_EQUAL_HEX8(0xFF, ends[0]);
TEST_ASSERT_EQUAL_HEX8(source[0] , ends[1]);
TEST_ASSERT_EQUAL_HEX8(source[0], ends[1]);
TEST_ESP_OK( esp_flash_read(NULL, ends, part->address + length, sizeof(ends)) );
TEST_ASSERT_EQUAL_HEX8(source[length-1], ends[0]);
TEST_ESP_OK(esp_flash_read(NULL, ends, part->address + length, sizeof(ends)));
TEST_ASSERT_EQUAL_HEX8(source[length - 1], ends[0]);
TEST_ASSERT_EQUAL_HEX8(0xFF, ends[1]);
TEST_ASSERT_EQUAL_HEX8(0xFF, ends[2]);
TEST_ASSERT_EQUAL_HEX8(0xFF, ends[3]);

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2010-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2010-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -50,7 +50,7 @@ static void setup_tests(void)
static void fill(char *dest, int32_t start, int32_t len)
{
for (int32_t i = 0; i < len; i++) {
*(dest + i) = (char) (start + i);
*(dest + i) = (char)(start + i);
}
}
@@ -330,8 +330,7 @@ TEST_CASE("esp_flash_write can write from external RAM buffer", "[spi_flash]")
TEST_ASSERT_NOT_NULL(buf_ext);
srand(0);
for (size_t i = 0; i < SPI_FLASH_SEC_SIZE / sizeof(uint32_t); i++)
{
for (size_t i = 0; i < SPI_FLASH_SEC_SIZE / sizeof(uint32_t); i++) {
uint32_t val = rand();
buf_ext[i] = val;
}

View File

@@ -1,10 +0,0 @@
# The following lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.22)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
idf_build_set_property(MINIMAL_BUILD ON)
project(test_build)

View File

@@ -1,6 +0,0 @@
| Supported Targets | ESP32-C3 |
| ----------------- | -------- |
This project tests building with the no_flash_delay configuration.
This project uses MINIMAL_BUILD=y to reduce build time and dependencies.

View File

@@ -1,2 +0,0 @@
idf_component_register(SRCS "test_main.c"
INCLUDE_DIRS ".")

View File

@@ -1,8 +0,0 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
void app_main(void)
{
}

View File

@@ -1 +0,0 @@
CONFIG_SPI_FLASH_YIELD_DURING_ERASE=n

View File

@@ -1,10 +0,0 @@
# The following lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.22)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
idf_build_set_property(MINIMAL_BUILD ON)
project(test_build)

View File

@@ -1,6 +0,0 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | ESP32-S31 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- | -------- | --------- |
This project tests building with the spi_flash_opts configuration.
This project uses MINIMAL_BUILD=y to reduce build time and dependencies.

View File

@@ -1,2 +0,0 @@
idf_component_register(SRCS "test_main.c"
INCLUDE_DIRS ".")

View File

@@ -1,8 +0,0 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
void app_main(void)
{
}

View File

@@ -1 +0,0 @@
CONFIG_SPI_FLASH_SIZE_OVERRIDE=y