mirror of
https://github.com/espressif/esp-idf.git
synced 2026-09-22 13:01:16 +03:00
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:
committed by
Armando (Dou Yiwen)
parent
c565262ded
commit
6e3abd12a1
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
See the spi_flash.rst in the programming guide folder for more details.
|
||||
@@ -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
|
||||
@@ -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, \
|
||||
} \
|
||||
}
|
||||
@@ -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
|
||||
@@ -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*)®_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 = ®istered_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);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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.
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 chip’s 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
|
||||
@@ -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 */
|
||||
|
||||
/**
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -30,13 +30,11 @@ void app_main(void)
|
||||
// | `---..-' || | --' | |` | |\ '-' |.-' `)| | | |
|
||||
// `------'`-----' `--' `--' `--' `--`--'`----' `--' `--'
|
||||
|
||||
|
||||
printf(",------. ,---. ,------. ,------.,--. ,--. \n");
|
||||
printf("| .---'' .-' | .--. ' | .---'| | ,--,--. ,---. | ,---. \n");
|
||||
printf("| `--, `. `-. | '--' | | `--, | |' ,-. |( .-' | .-. | \n");
|
||||
printf("| `---..-' || | --' | |` | |\\ '-' |.-' `)| | | | \n");
|
||||
printf("`------'`-----' `--' `--' `--' `--`--'`----' `--' `--' \n");
|
||||
|
||||
|
||||
unity_run_menu();
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
@@ -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.
|
||||
@@ -1,2 +0,0 @@
|
||||
idf_component_register(SRCS "test_main.c"
|
||||
INCLUDE_DIRS ".")
|
||||
@@ -1,8 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
void app_main(void)
|
||||
{
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
CONFIG_SPI_FLASH_YIELD_DURING_ERASE=n
|
||||
@@ -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)
|
||||
@@ -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.
|
||||
@@ -1,2 +0,0 @@
|
||||
idf_component_register(SRCS "test_main.c"
|
||||
INCLUDE_DIRS ".")
|
||||
@@ -1,8 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
void app_main(void)
|
||||
{
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
CONFIG_SPI_FLASH_SIZE_OVERRIDE=y
|
||||
Reference in New Issue
Block a user