mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-02 11:10:54 +03:00
Merge branch 'bugfix/esp32c5_encrypted_flash_write_v6.0' into 'release/v6.0'
fix(spi_flash): Add CPU frequency switching during flash encrypted write (v6.0) See merge request espressif/esp-idf!44304
This commit is contained in:
@@ -7,6 +7,7 @@
|
|||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
#include "sdkconfig.h"
|
#include "sdkconfig.h"
|
||||||
#include "esp_check.h"
|
#include "esp_check.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
@@ -17,25 +18,31 @@
|
|||||||
#include "esp_private/mspi_timing_tuning.h"
|
#include "esp_private/mspi_timing_tuning.h"
|
||||||
#include "esp_private/esp_clk_utils.h"
|
#include "esp_private/esp_clk_utils.h"
|
||||||
|
|
||||||
|
// Not directly divide to avoid truncation issue
|
||||||
|
// DIG-498
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32P4
|
||||||
|
#define BELOW_FREQ_THRESHOLD(freq) ((freq) < CONFIG_SPIRAM_SPEED)
|
||||||
|
#elif CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C61 || CONFIG_IDF_TARGET_ESP32H4
|
||||||
|
#define BELOW_FREQ_THRESHOLD(freq) ((freq) * 8 < CONFIG_SPIRAM_SPEED)
|
||||||
|
#endif
|
||||||
|
|
||||||
#if !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
|
#if !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
|
||||||
void esp_clk_utils_mspi_speed_mode_sync_before_cpu_freq_switching(uint32_t target_cpu_src_freq, uint32_t target_cpu_freq)
|
void esp_clk_utils_mspi_speed_mode_sync_before_cpu_freq_switching(uint32_t target_cpu_src_freq, uint32_t target_cpu_freq)
|
||||||
{
|
{
|
||||||
#if MSPI_TIMING_LL_FLASH_CPU_CLK_SRC_BINDED
|
#if MSPI_TIMING_LL_FLASH_CPU_CLK_SRC_BINDED
|
||||||
(void) target_cpu_freq;
|
(void) target_cpu_freq;
|
||||||
|
/* For ESP32S3, the clock source of MSPI is same as the CPU. When CPU use XTAL as clock source, we need to sync the
|
||||||
|
* MSPI speed mode. */
|
||||||
if (target_cpu_src_freq <= clk_ll_xtal_load_freq_mhz()) {
|
if (target_cpu_src_freq <= clk_ll_xtal_load_freq_mhz()) {
|
||||||
mspi_timing_change_speed_mode_cache_safe(true);
|
mspi_timing_change_speed_mode_cache_safe(true);
|
||||||
}
|
}
|
||||||
#elif CONFIG_IDF_TARGET_ESP32P4
|
#elif SOC_SPI_MEM_PSRAM_FREQ_AXI_CONSTRAINED && CONFIG_SPIRAM
|
||||||
(void) target_cpu_src_freq;
|
/* On chips with AXI bus, currently there is a restriction that AXI frequency (usually equals to a portion of CPU
|
||||||
/**
|
* frequency) needs to be greater than or equal to MSPI PSRAM frequency to avoid writing MSPI FIFO overflow.
|
||||||
* Workaround for ESP32P4,
|
|
||||||
* f_cpu >= f_mspi
|
|
||||||
*/
|
*/
|
||||||
if (((target_cpu_freq) < CONFIG_ESPTOOLPY_FLASHFREQ_VAL)
|
if (BELOW_FREQ_THRESHOLD(target_cpu_freq)) {
|
||||||
#if CONFIG_SPIRAM
|
// Before switching to low speed mode, verify CPU frequency meets the constraint
|
||||||
|| ((target_cpu_freq) < CONFIG_SPIRAM_SPEED)
|
assert(target_cpu_freq >= mspi_timing_get_psram_low_speed_freq_mhz());
|
||||||
#endif
|
|
||||||
) {
|
|
||||||
mspi_timing_change_speed_mode_cache_safe(true);
|
mspi_timing_change_speed_mode_cache_safe(true);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
@@ -51,17 +58,11 @@ void esp_clk_utils_mspi_speed_mode_sync_after_cpu_freq_switching(uint32_t target
|
|||||||
if (target_cpu_src_freq > clk_ll_xtal_load_freq_mhz()) {
|
if (target_cpu_src_freq > clk_ll_xtal_load_freq_mhz()) {
|
||||||
mspi_timing_change_speed_mode_cache_safe(false);
|
mspi_timing_change_speed_mode_cache_safe(false);
|
||||||
}
|
}
|
||||||
#elif CONFIG_IDF_TARGET_ESP32P4
|
#elif SOC_SPI_MEM_PSRAM_FREQ_AXI_CONSTRAINED && CONFIG_SPIRAM
|
||||||
(void) target_cpu_src_freq;
|
/* On chips with AXI bus, currently there is a restriction that AXI frequency (usually equals to a portion of CPU
|
||||||
/**
|
* frequency) needs to be greater than or equal to MSPI PSRAM frequency to avoid writing MSPI FIFO overflow.
|
||||||
* Workaround for ESP32P4,
|
|
||||||
* f_cpu >= f_mspi
|
|
||||||
*/
|
*/
|
||||||
if (((target_cpu_freq) >= CONFIG_ESPTOOLPY_FLASHFREQ_VAL)
|
if (!BELOW_FREQ_THRESHOLD(target_cpu_freq)) {
|
||||||
#if CONFIG_SPIRAM
|
|
||||||
&& ((target_cpu_freq) >= CONFIG_SPIRAM_SPEED)
|
|
||||||
#endif
|
|
||||||
) {
|
|
||||||
mspi_timing_change_speed_mode_cache_safe(false);
|
mspi_timing_change_speed_mode_cache_safe(false);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
|||||||
+6
-1
@@ -24,6 +24,12 @@ extern "C" {
|
|||||||
*/
|
*/
|
||||||
void mspi_timing_enter_low_speed_mode(bool control_spi1);
|
void mspi_timing_enter_low_speed_mode(bool control_spi1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get PSRAM frequency in low speed mode (MHz)
|
||||||
|
* @return PSRAM frequency in MHz when in low speed mode
|
||||||
|
*/
|
||||||
|
uint32_t mspi_timing_get_psram_low_speed_freq_mhz(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Make MSPI work under the frequency as users set, may add certain delays to MSPI RX direction to meet timing requirements.
|
* @brief Make MSPI work under the frequency as users set, may add certain delays to MSPI RX direction to meet timing requirements.
|
||||||
* @param control_spi1 Select whether to control SPI1. For tuning, we need to use SPI1. After tuning (during startup stage), let the flash driver to control SPI1
|
* @param control_spi1 Select whether to control SPI1. For tuning, we need to use SPI1. After tuning (during startup stage), let the flash driver to control SPI1
|
||||||
@@ -54,7 +60,6 @@ void mspi_timing_psram_tuning(void);
|
|||||||
*/
|
*/
|
||||||
void mspi_timing_set_pin_drive_strength(void);
|
void mspi_timing_set_pin_drive_strength(void);
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -481,6 +481,11 @@ void mspi_timing_psram_tuning(void)
|
|||||||
/*------------------------------------------------------------------------------
|
/*------------------------------------------------------------------------------
|
||||||
* APIs to make SPI0 (and SPI1) FLASH work for high/low freq
|
* APIs to make SPI0 (and SPI1) FLASH work for high/low freq
|
||||||
*----------------------------------------------------------------------------*/
|
*----------------------------------------------------------------------------*/
|
||||||
|
uint32_t mspi_timing_get_psram_low_speed_freq_mhz(void)
|
||||||
|
{
|
||||||
|
return 20;
|
||||||
|
}
|
||||||
|
|
||||||
void mspi_timing_enter_low_speed_mode(bool control_spi1)
|
void mspi_timing_enter_low_speed_mode(bool control_spi1)
|
||||||
{
|
{
|
||||||
#if MSPI_TIMING_LL_FLASH_CLK_SRC_CHANGEABLE
|
#if MSPI_TIMING_LL_FLASH_CLK_SRC_CHANGEABLE
|
||||||
@@ -500,14 +505,14 @@ void mspi_timing_enter_low_speed_mode(bool control_spi1)
|
|||||||
* Should be extended to other no-timing-tuning chips if needed. e.g.:
|
* Should be extended to other no-timing-tuning chips if needed. e.g.:
|
||||||
* we still need to turn down Flash / PSRAM clock speed at a certain period of time
|
* we still need to turn down Flash / PSRAM clock speed at a certain period of time
|
||||||
*/
|
*/
|
||||||
mspi_timing_config_set_flash_clock(20, MSPI_TIMING_SPEED_MODE_LOW_PERF, control_spi1);
|
uint32_t low_speed_freq_mhz = mspi_timing_get_psram_low_speed_freq_mhz();
|
||||||
mspi_timing_config_set_psram_clock(20, MSPI_TIMING_SPEED_MODE_LOW_PERF, control_spi1);
|
mspi_timing_config_set_flash_clock(low_speed_freq_mhz, MSPI_TIMING_SPEED_MODE_LOW_PERF, control_spi1);
|
||||||
#endif //#if SOC_SPI_MEM_SUPPORT_TIMING_TUNING
|
mspi_timing_config_set_psram_clock(low_speed_freq_mhz, MSPI_TIMING_SPEED_MODE_LOW_PERF, control_spi1);
|
||||||
|
|
||||||
#if MSPI_TIMING_FLASH_NEEDS_TUNING || MSPI_TIMING_PSRAM_NEEDS_TUNING
|
#if MSPI_TIMING_FLASH_NEEDS_TUNING || MSPI_TIMING_PSRAM_NEEDS_TUNING
|
||||||
mspi_timing_flash_config_clear_tuning_regs(control_spi1);
|
mspi_timing_flash_config_clear_tuning_regs(control_spi1);
|
||||||
mspi_timing_psram_config_clear_tuning_regs(control_spi1);
|
mspi_timing_psram_config_clear_tuning_regs(control_spi1);
|
||||||
#endif //#if MSPI_TIMING_FLASH_NEEDS_TUNING || MSPI_TIMING_PSRAM_NEEDS_TUNING
|
#endif //#if MSPI_TIMING_FLASH_NEEDS_TUNING || MSPI_TIMING_PSRAM_NEEDS_TUNING
|
||||||
|
#endif //#if SOC_SPI_MEM_SUPPORT_TIMING_TUNING
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -568,10 +573,24 @@ void mspi_timing_change_speed_mode_cache_safe(bool switch_down)
|
|||||||
|
|
||||||
if (switch_down) {
|
if (switch_down) {
|
||||||
//enter MSPI low speed mode, extra delays should be removed
|
//enter MSPI low speed mode, extra delays should be removed
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32C5
|
||||||
|
// ESP32-C5 needs to perform encrypted flash writes even when CPU frequency is reduced.
|
||||||
|
// Since encrypted writes use SPI1, we need to configure SPI1 timing registers as well
|
||||||
|
// during runtime frequency switching to ensure proper operation.
|
||||||
|
mspi_timing_enter_low_speed_mode(true);
|
||||||
|
#else
|
||||||
mspi_timing_enter_low_speed_mode(false);
|
mspi_timing_enter_low_speed_mode(false);
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
//enter MSPI high speed mode, extra delays should be considered
|
//enter MSPI high speed mode, extra delays should be considered
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32C5
|
||||||
|
// ESP32-C5 needs to perform encrypted flash writes even when CPU frequency is reduced.
|
||||||
|
// Since encrypted writes use SPI1, we need to configure SPI1 timing registers as well
|
||||||
|
// during runtime frequency switching to ensure proper operation.
|
||||||
|
mspi_timing_enter_high_speed_mode(true);
|
||||||
|
#else
|
||||||
mspi_timing_enter_high_speed_mode(false);
|
mspi_timing_enter_high_speed_mode(false);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SOC_CACHE_FREEZE_SUPPORTED
|
#if SOC_CACHE_FREEZE_SUPPORTED
|
||||||
|
|||||||
@@ -1,10 +1,21 @@
|
|||||||
idf_build_get_property(target IDF_TARGET)
|
idf_build_get_property(target IDF_TARGET)
|
||||||
|
set(priv_requires esp_system esp_driver_gpio esp_timer)
|
||||||
|
|
||||||
if(${target} STREQUAL "linux")
|
if(${target} STREQUAL "linux")
|
||||||
return() # This component is not supported by the POSIX/Linux simulator
|
return() # This component is not supported by the POSIX/Linux simulator
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
idf_component_register(SRCS "pm_locks.c" "pm_trace.c" "pm_impl.c"
|
set(srcs "pm_locks.c" "pm_trace.c" "pm_impl.c")
|
||||||
|
if(CONFIG_PM_WORKAROUND_FREQ_LIMIT_ENABLED)
|
||||||
|
list(APPEND srcs "pm_c5_flash_freq_limit.c")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(${target} STREQUAL "esp32c5")
|
||||||
|
# pm_c5_flash_freq_limit.c needs spi_flash header when CONFIG_PM_WORKAROUND_FREQ_LIMIT_ENABLED is enabled
|
||||||
|
list(APPEND priv_requires spi_flash)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
idf_component_register(SRCS ${srcs}
|
||||||
INCLUDE_DIRS include
|
INCLUDE_DIRS include
|
||||||
PRIV_REQUIRES esp_system esp_driver_gpio esp_timer
|
PRIV_REQUIRES "${priv_requires}"
|
||||||
LDFRAGMENTS linker.lf)
|
LDFRAGMENTS linker.lf)
|
||||||
|
|||||||
@@ -239,4 +239,12 @@ menu "Power Management"
|
|||||||
NOTE: Enabling these callbacks may change sleep duration calculations based on time spent in callback and
|
NOTE: Enabling these callbacks may change sleep duration calculations based on time spent in callback and
|
||||||
hence it is highly recommended to keep them as short as possible
|
hence it is highly recommended to keep them as short as possible
|
||||||
|
|
||||||
|
config PM_WORKAROUND_FREQ_LIMIT_ENABLED
|
||||||
|
bool
|
||||||
|
default y if SPI_FLASH_FREQ_LIMIT_C5_240MHZ
|
||||||
|
help
|
||||||
|
Workaround for frequency limit during encrypted flash writes.
|
||||||
|
Only enabled when SPI_FLASH_FREQ_LIMIT_C5_240MHZ is enabled.
|
||||||
|
This is an internal configuration, automatically set based on SPI Flash configuration.
|
||||||
|
|
||||||
endmenu # "Power Management"
|
endmenu # "Power Management"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2016-2023 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2016-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@@ -15,7 +15,6 @@
|
|||||||
|
|
||||||
#include "soc/rtc.h"
|
#include "soc/rtc.h"
|
||||||
#include "esp_pm.h"
|
#include "esp_pm.h"
|
||||||
#include "esp_timer.h"
|
|
||||||
#include "sdkconfig.h"
|
#include "sdkconfig.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
@@ -26,11 +25,11 @@ extern "C" {
|
|||||||
* This is an enum of possible power modes supported by the implementation
|
* This is an enum of possible power modes supported by the implementation
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
PM_MODE_LIGHT_SLEEP,//!< Light sleep
|
PM_MODE_LIGHT_SLEEP, //!< Light sleep
|
||||||
PM_MODE_APB_MIN, //!< Idle (no CPU frequency or APB frequency locks)
|
PM_MODE_APB_MIN, //!< Idle (no CPU frequency or APB frequency locks)
|
||||||
PM_MODE_APB_MAX, //!< Maximum APB frequency mode
|
PM_MODE_APB_MAX, //!< Maximum APB frequency mode
|
||||||
PM_MODE_CPU_MAX, //!< Maximum CPU frequency mode
|
PM_MODE_CPU_MAX, //!< Maximum CPU frequency mode
|
||||||
PM_MODE_COUNT //!< Number of items
|
PM_MODE_COUNT //!< Number of items
|
||||||
} pm_mode_t;
|
} pm_mode_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -141,8 +140,18 @@ esp_err_t esp_pm_register_skip_light_sleep_callback(skip_light_sleep_cb_t cb);
|
|||||||
*/
|
*/
|
||||||
esp_err_t esp_pm_unregister_skip_light_sleep_callback(skip_light_sleep_cb_t cb);
|
esp_err_t esp_pm_unregister_skip_light_sleep_callback(skip_light_sleep_cb_t cb);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize flash frequency limit
|
||||||
|
*
|
||||||
|
* This function initializes the flash frequency limit.
|
||||||
|
* @note This function is only available when CONFIG_PM_WORKAROUND_FREQ_LIMIT_ENABLED is enabled.
|
||||||
|
*/
|
||||||
|
void esp_pm_flash_freq_limit_init(void);
|
||||||
|
|
||||||
#ifdef CONFIG_PM_PROFILING
|
#ifdef CONFIG_PM_PROFILING
|
||||||
#define WITH_PROFILING
|
#define WITH_PROFILING
|
||||||
|
#include "esp_timer.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef WITH_PROFILING
|
#ifdef WITH_PROFILING
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2016-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "sdkconfig.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CONFIG_PM_WORKAROUND_FREQ_LIMIT_ENABLED
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize and pre-calculate forced CPU_MAX frequency configuration (private function for spi_flash)
|
||||||
|
*
|
||||||
|
* This function pre-calculates and stores the forced CPU_MAX frequency configuration
|
||||||
|
* based on the given frequency limit. The configuration is computed once during
|
||||||
|
* initialization and reused during runtime for better performance.
|
||||||
|
*
|
||||||
|
* @param limit_freq_mhz Frequency limit in MHz
|
||||||
|
* @note This is a private function, only for use by spi_flash component.
|
||||||
|
* @note Must be called during initialization before esp_pm_impl_cpu_max_freq_force().
|
||||||
|
* @note This function is only available when CONFIG_PM_WORKAROUND_FREQ_LIMIT_ENABLED is enabled and CONFIG_PM_ENABLE is enabled.
|
||||||
|
*/
|
||||||
|
void esp_pm_impl_cpu_max_freq_force_init(uint32_t limit_freq_mhz);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Force CPU_MAX frequency to pre-configured limit (private function for spi_flash)
|
||||||
|
*
|
||||||
|
* This function activates the pre-configured forced CPU_MAX frequency limit.
|
||||||
|
* When forced, all reads of CPU_MAX frequency will use the pre-configured value
|
||||||
|
* instead of the configured value.
|
||||||
|
*
|
||||||
|
* @note This is a private function, only for use by spi_flash component.
|
||||||
|
* @note The forced frequency configuration must be pre-calculated during initialization.
|
||||||
|
* @note This function is only available when CONFIG_PM_WORKAROUND_FREQ_LIMIT_ENABLED is enabled and CONFIG_PM_ENABLE is enabled.
|
||||||
|
*/
|
||||||
|
void esp_pm_impl_cpu_max_freq_force(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Unforce CPU_MAX frequency (private function for spi_flash)
|
||||||
|
*
|
||||||
|
* This function removes the forced CPU_MAX frequency, allowing the configured
|
||||||
|
* value to be used again.
|
||||||
|
* @note This is a private function, only for use by spi_flash component.
|
||||||
|
* @note This function is only available when CONFIG_PM_WORKAROUND_FREQ_LIMIT_ENABLED is enabled and CONFIG_PM_ENABLE is enabled.
|
||||||
|
*/
|
||||||
|
void esp_pm_impl_cpu_max_freq_unforce(void);
|
||||||
|
|
||||||
|
#endif // CONFIG_PM_WORKAROUND_FREQ_LIMIT_ENABLED
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,168 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
//This file implements esp_flash_freq_limit_cb and esp_flash_freq_unlimit_cb callbacks to limit and unlimit CPU
|
||||||
|
//frequency when encrypted flash writes are performed.
|
||||||
|
|
||||||
|
#include "sdkconfig.h"
|
||||||
|
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "esp_attr.h"
|
||||||
|
#include "esp_rom_sys.h"
|
||||||
|
#include "soc/chip_revision.h"
|
||||||
|
#include "soc/rtc.h"
|
||||||
|
#include "hal/efuse_hal.h"
|
||||||
|
|
||||||
|
#include "esp_private/pm_impl_freq_limit.h"
|
||||||
|
#include "esp_private/spi_flash_freq_limit_cbs.h"
|
||||||
|
#include "esp_private/esp_clk_utils.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the frequency limit for flash encryption lock based on chip revision
|
||||||
|
*
|
||||||
|
* @return uint32_t Frequency limit (MHz)
|
||||||
|
*
|
||||||
|
* Logic:
|
||||||
|
* - v1.2+: limit to 160MHz
|
||||||
|
* - v1.0: limit to 80MHz
|
||||||
|
*/
|
||||||
|
static uint32_t IRAM_ATTR get_encrypt_lock_freq_limit(void)
|
||||||
|
{
|
||||||
|
unsigned int chip_revision = efuse_hal_chip_revision();
|
||||||
|
if (ESP_CHIP_REV_ABOVE(chip_revision, 102)) {
|
||||||
|
return 160;
|
||||||
|
} else {
|
||||||
|
return 80;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void esp_pm_flash_freq_limit_init(void)
|
||||||
|
{
|
||||||
|
uint32_t limit_freq_mhz = get_encrypt_lock_freq_limit();
|
||||||
|
ESP_EARLY_LOGW("spi_flash", "CPU frequency is set to 240MHz. esp_flash_write_encrypted() will automatically limit CPU frequency to %dMHz during execution.", limit_freq_mhz);
|
||||||
|
#ifdef CONFIG_PM_ENABLE
|
||||||
|
/* Pre-calculate and store forced frequency configuration during initialization.
|
||||||
|
* This is done here to avoid runtime calculation overhead in lock/unlock functions.
|
||||||
|
*/
|
||||||
|
esp_pm_impl_cpu_max_freq_force_init(limit_freq_mhz);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !CONFIG_PM_ENABLE
|
||||||
|
/* Saved original frequency for !PM_ENABLE case (0 means no change was made) */
|
||||||
|
static uint32_t s_saved_freq_mhz = 0;
|
||||||
|
|
||||||
|
// Switch CPU frequency with all necessary synchronization (for !PM_ENABLE case)
|
||||||
|
// Similar to do_switch() but without PM-specific state management
|
||||||
|
static void IRAM_ATTR esp_pm_impl_switch_cpu_freq(const rtc_cpu_freq_config_t *old_config, const rtc_cpu_freq_config_t *new_config)
|
||||||
|
{
|
||||||
|
if (new_config->freq_mhz != old_config->freq_mhz) {
|
||||||
|
//No need to run on_freq_update for ccount, since that's not supported on C5.
|
||||||
|
#if !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
|
||||||
|
/* Synchronize MSPI speed mode before CPU frequency switching */
|
||||||
|
esp_clk_utils_mspi_speed_mode_sync_before_cpu_freq_switching(new_config->source_freq_mhz, new_config->freq_mhz);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//Not taking s_time_update_lock since C5 have fixed divider for systimer
|
||||||
|
rtc_clk_cpu_freq_set_config_fast(new_config);
|
||||||
|
|
||||||
|
#if !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
|
||||||
|
/* Synchronize MSPI speed mode after CPU frequency switching */
|
||||||
|
esp_clk_utils_mspi_speed_mode_sync_after_cpu_freq_switching(new_config->source_freq_mhz, new_config->freq_mhz);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Limit CPU frequency to target frequency (for !PM_ENABLE case only)
|
||||||
|
*
|
||||||
|
* This function automatically reads the current CPU frequency, saves it,
|
||||||
|
* and switches to the target frequency if current frequency is higher.
|
||||||
|
* The original frequency can be restored by calling unlimit_cpu_freq().
|
||||||
|
*
|
||||||
|
* @param target_freq_mhz Target frequency limit in MHz
|
||||||
|
* @note limit->unlimit cannot be nested, and this function must not be called concurrently
|
||||||
|
* @note This is a private function, only for use by spi_flash component.
|
||||||
|
* @note This function is only available when CONFIG_PM_WORKAROUND_FREQ_LIMIT_ENABLED is enabled and CONFIG_PM_ENABLE is not set.
|
||||||
|
*/
|
||||||
|
static void IRAM_ATTR limit_cpu_freq(uint32_t target_freq_mhz)
|
||||||
|
{
|
||||||
|
/* PM not enabled, directly switch frequency and save original frequency */
|
||||||
|
rtc_cpu_freq_config_t old_config, new_config;
|
||||||
|
rtc_clk_cpu_freq_get_config(&old_config);
|
||||||
|
|
||||||
|
if (old_config.freq_mhz > target_freq_mhz) {
|
||||||
|
s_saved_freq_mhz = old_config.freq_mhz;
|
||||||
|
if (rtc_clk_cpu_freq_mhz_to_config(target_freq_mhz, &new_config)) {
|
||||||
|
/* Use PM implementation function to switch frequency with all necessary synchronization */
|
||||||
|
esp_pm_impl_switch_cpu_freq(&old_config, &new_config);
|
||||||
|
const unsigned wait_clock_stable_us = 10;
|
||||||
|
esp_rom_delay_us(wait_clock_stable_us);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
s_saved_freq_mhz = 0; /* No change needed */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Unlimit CPU frequency, restoring to original frequency (for !PM_ENABLE case only)
|
||||||
|
*
|
||||||
|
* This function restores the CPU frequency to the value saved by
|
||||||
|
* limit_cpu_freq(). If no frequency change was made, this function
|
||||||
|
* does nothing.
|
||||||
|
*
|
||||||
|
* @note limit->unlimit cannot be nested, and this function must not be called concurrently
|
||||||
|
* @note This is a private function, only for use by spi_flash component.
|
||||||
|
* @note This function is only available when CONFIG_PM_WORKAROUND_FREQ_LIMIT_ENABLED is enabled and CONFIG_PM_ENABLE is not set.
|
||||||
|
*/
|
||||||
|
static void IRAM_ATTR unlimit_cpu_freq(void)
|
||||||
|
{
|
||||||
|
/* PM not enabled, restore to original frequency */
|
||||||
|
if (s_saved_freq_mhz > 0) {
|
||||||
|
rtc_cpu_freq_config_t old_config, new_config;
|
||||||
|
rtc_clk_cpu_freq_get_config(&old_config);
|
||||||
|
if (rtc_clk_cpu_freq_mhz_to_config(s_saved_freq_mhz, &new_config)) {
|
||||||
|
/* Use PM implementation function to switch frequency with all necessary synchronization */
|
||||||
|
esp_pm_impl_switch_cpu_freq(&old_config, &new_config);
|
||||||
|
const unsigned wait_clock_stable_us = 10;
|
||||||
|
esp_rom_delay_us(wait_clock_stable_us);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* If s_saved_freq_mhz == 0, no change was made, so no need to restore */
|
||||||
|
s_saved_freq_mhz = 0;
|
||||||
|
}
|
||||||
|
#endif // !CONFIG_PM_ENABLE
|
||||||
|
|
||||||
|
void IRAM_ATTR esp_flash_freq_limit_cb(void)
|
||||||
|
{
|
||||||
|
/* Limit the frequency */
|
||||||
|
#ifdef CONFIG_PM_ENABLE
|
||||||
|
/* PM enabled, use force mechanism */
|
||||||
|
esp_pm_impl_cpu_max_freq_force();
|
||||||
|
#else
|
||||||
|
/* PM not enabled, use limit mechanism */
|
||||||
|
uint32_t limit_freq_mhz = get_encrypt_lock_freq_limit();
|
||||||
|
/* Call PM implementation function to limit CPU frequency.
|
||||||
|
* This function automatically reads current frequency, saves it, and switches to target frequency.
|
||||||
|
*/
|
||||||
|
limit_cpu_freq(limit_freq_mhz);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void IRAM_ATTR esp_flash_freq_unlimit_cb(void)
|
||||||
|
{
|
||||||
|
/* Restore the frequency */
|
||||||
|
#ifdef CONFIG_PM_ENABLE
|
||||||
|
/* PM enabled, use unforce mechanism */
|
||||||
|
esp_pm_impl_cpu_max_freq_unforce();
|
||||||
|
#else
|
||||||
|
/* PM not enabled, use unlimit mechanism */
|
||||||
|
/* Call PM implementation function to unlimit CPU frequency.
|
||||||
|
* This function restores the original frequency saved by limit_cpu_freq().
|
||||||
|
*/
|
||||||
|
unlimit_cpu_freq();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <sys/lock.h>
|
#include <sys/lock.h>
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
#include "sdkconfig.h"
|
#include "sdkconfig.h"
|
||||||
#include "esp_attr.h"
|
#include "esp_attr.h"
|
||||||
@@ -33,6 +34,7 @@
|
|||||||
|
|
||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/task.h"
|
#include "freertos/task.h"
|
||||||
|
#include "freertos/portmacro.h"
|
||||||
#if CONFIG_FREERTOS_SYSTICK_USES_CCOUNT
|
#if CONFIG_FREERTOS_SYSTICK_USES_CCOUNT
|
||||||
#include "xtensa_timer.h"
|
#include "xtensa_timer.h"
|
||||||
#include "xtensa/core-macros.h"
|
#include "xtensa/core-macros.h"
|
||||||
@@ -41,6 +43,7 @@
|
|||||||
#include "esp_private/pm_impl.h"
|
#include "esp_private/pm_impl.h"
|
||||||
#include "esp_private/pm_trace.h"
|
#include "esp_private/pm_trace.h"
|
||||||
#include "esp_private/esp_timer_private.h"
|
#include "esp_private/esp_timer_private.h"
|
||||||
|
#include "esp_timer.h"
|
||||||
#include "esp_private/esp_clk.h"
|
#include "esp_private/esp_clk.h"
|
||||||
#include "esp_private/esp_clk_tree_common.h"
|
#include "esp_private/esp_clk_tree_common.h"
|
||||||
#include "esp_private/sleep_cpu.h"
|
#include "esp_private/sleep_cpu.h"
|
||||||
@@ -50,7 +53,7 @@
|
|||||||
#include "esp_private/esp_clk_utils.h"
|
#include "esp_private/esp_clk_utils.h"
|
||||||
#include "esp_sleep.h"
|
#include "esp_sleep.h"
|
||||||
#include "esp_memory_utils.h"
|
#include "esp_memory_utils.h"
|
||||||
|
#include "esp_rom_sys.h"
|
||||||
|
|
||||||
#if SOC_PERIPH_CLK_CTRL_SHARED
|
#if SOC_PERIPH_CLK_CTRL_SHARED
|
||||||
#define HP_UART_SRC_CLK_ATOMIC() PERIPH_RCC_ATOMIC()
|
#define HP_UART_SRC_CLK_ATOMIC() PERIPH_RCC_ATOMIC()
|
||||||
@@ -167,6 +170,16 @@ static esp_pm_lock_handle_t s_rtos_lock_handle[CONFIG_FREERTOS_NUMBER_OF_CORES];
|
|||||||
*/
|
*/
|
||||||
static rtc_cpu_freq_config_t s_cpu_freq_by_mode[PM_MODE_COUNT];
|
static rtc_cpu_freq_config_t s_cpu_freq_by_mode[PM_MODE_COUNT];
|
||||||
|
|
||||||
|
#if CONFIG_PM_WORKAROUND_FREQ_LIMIT_ENABLED
|
||||||
|
/* Forced CPU_MAX frequency configuration.
|
||||||
|
* s_cpu_max_freq_forced indicates whether CPU_MAX frequency is forced.
|
||||||
|
* s_cpu_max_freq_force_config stores the forced frequency configuration.
|
||||||
|
* Protected by s_switch_lock, same as s_cpu_freq_by_mode.
|
||||||
|
*/
|
||||||
|
static bool s_cpu_max_freq_forced = false;
|
||||||
|
static rtc_cpu_freq_config_t s_cpu_max_freq_force_config;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Whether automatic light sleep is enabled */
|
/* Whether automatic light sleep is enabled */
|
||||||
static bool s_light_sleep_en = false;
|
static bool s_light_sleep_en = false;
|
||||||
|
|
||||||
@@ -392,6 +405,32 @@ static esp_err_t esp_pm_sleep_configure(const esp_pm_config_t *config)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get frequency configuration for a given mode, considering forced frequency
|
||||||
|
*
|
||||||
|
* This function returns a pointer to the frequency configuration for the given mode.
|
||||||
|
* For PM_MODE_CPU_MAX, if s_cpu_max_freq_forced is true, it returns
|
||||||
|
* a pointer to s_cpu_max_freq_force_config. Otherwise, it returns a pointer to
|
||||||
|
* s_cpu_freq_by_mode[mode].
|
||||||
|
*
|
||||||
|
* @param mode Power mode to get configuration for
|
||||||
|
* @note Must be called with s_switch_lock held
|
||||||
|
* @note Must be in IRAM when called from ISR context (e.g., do_switch)
|
||||||
|
* @return rtc_cpu_freq_config_t* Pointer to frequency configuration for the given mode
|
||||||
|
*/
|
||||||
|
static inline IRAM_ATTR rtc_cpu_freq_config_t *get_cpu_freq_config_by_mode(pm_mode_t mode)
|
||||||
|
{
|
||||||
|
#if CONFIG_PM_WORKAROUND_FREQ_LIMIT_ENABLED
|
||||||
|
if (mode == PM_MODE_CPU_MAX && s_cpu_max_freq_forced) {
|
||||||
|
return &s_cpu_max_freq_force_config;
|
||||||
|
} else {
|
||||||
|
return &s_cpu_freq_by_mode[mode];
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
return &s_cpu_freq_by_mode[mode];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
esp_err_t esp_pm_configure(const void* vconfig)
|
esp_err_t esp_pm_configure(const void* vconfig)
|
||||||
{
|
{
|
||||||
#ifndef CONFIG_PM_ENABLE
|
#ifndef CONFIG_PM_ENABLE
|
||||||
@@ -641,18 +680,19 @@ static void IRAM_ATTR do_switch(pm_mode_t new_mode)
|
|||||||
s_is_switching = true;
|
s_is_switching = true;
|
||||||
bool config_changed = s_config_changed;
|
bool config_changed = s_config_changed;
|
||||||
s_config_changed = false;
|
s_config_changed = false;
|
||||||
portENTER_CRITICAL_ISR(&s_cpu_freq_switch_lock[core_id]);
|
|
||||||
portEXIT_CRITICAL_ISR(&s_switch_lock);
|
|
||||||
|
|
||||||
rtc_cpu_freq_config_t new_config = s_cpu_freq_by_mode[new_mode];
|
rtc_cpu_freq_config_t new_config = *get_cpu_freq_config_by_mode(new_mode);
|
||||||
rtc_cpu_freq_config_t old_config;
|
rtc_cpu_freq_config_t old_config;
|
||||||
|
|
||||||
if (!config_changed) {
|
if (!config_changed) {
|
||||||
old_config = s_cpu_freq_by_mode[s_mode];
|
old_config = *get_cpu_freq_config_by_mode(s_mode);
|
||||||
} else {
|
} else {
|
||||||
rtc_clk_cpu_freq_get_config(&old_config);
|
rtc_clk_cpu_freq_get_config(&old_config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
portENTER_CRITICAL_ISR(&s_cpu_freq_switch_lock[core_id]);
|
||||||
|
portEXIT_CRITICAL_ISR(&s_switch_lock);
|
||||||
|
|
||||||
if (new_config.freq_mhz != old_config.freq_mhz) {
|
if (new_config.freq_mhz != old_config.freq_mhz) {
|
||||||
uint32_t old_ticks_per_us = old_config.freq_mhz;
|
uint32_t old_ticks_per_us = old_config.freq_mhz;
|
||||||
uint32_t new_ticks_per_us = new_config.freq_mhz;
|
uint32_t new_ticks_per_us = new_config.freq_mhz;
|
||||||
@@ -865,6 +905,7 @@ void vApplicationSleep( TickType_t xExpectedIdleTime )
|
|||||||
void esp_pm_impl_dump_stats(FILE* out)
|
void esp_pm_impl_dump_stats(FILE* out)
|
||||||
{
|
{
|
||||||
pm_time_t time_in_mode[PM_MODE_COUNT];
|
pm_time_t time_in_mode[PM_MODE_COUNT];
|
||||||
|
uint32_t freq_mhz_by_mode[PM_MODE_COUNT];
|
||||||
|
|
||||||
portENTER_CRITICAL_ISR(&s_switch_lock);
|
portENTER_CRITICAL_ISR(&s_switch_lock);
|
||||||
memcpy(time_in_mode, s_time_in_mode, sizeof(time_in_mode));
|
memcpy(time_in_mode, s_time_in_mode, sizeof(time_in_mode));
|
||||||
@@ -874,6 +915,10 @@ void esp_pm_impl_dump_stats(FILE* out)
|
|||||||
bool light_sleep_en = s_light_sleep_en;
|
bool light_sleep_en = s_light_sleep_en;
|
||||||
uint32_t light_sleep_counts = s_light_sleep_counts;
|
uint32_t light_sleep_counts = s_light_sleep_counts;
|
||||||
uint32_t light_sleep_reject_counts = s_light_sleep_reject_counts;
|
uint32_t light_sleep_reject_counts = s_light_sleep_reject_counts;
|
||||||
|
// Read all frequency configs while holding s_switch_lock
|
||||||
|
for (int i = 0; i < PM_MODE_COUNT; ++i) {
|
||||||
|
freq_mhz_by_mode[i] = get_cpu_freq_config_by_mode(i)->freq_mhz;
|
||||||
|
}
|
||||||
portEXIT_CRITICAL_ISR(&s_switch_lock);
|
portEXIT_CRITICAL_ISR(&s_switch_lock);
|
||||||
|
|
||||||
time_in_mode[cur_mode] += now - last_mode_change_time;
|
time_in_mode[cur_mode] += now - last_mode_change_time;
|
||||||
@@ -887,7 +932,7 @@ void esp_pm_impl_dump_stats(FILE* out)
|
|||||||
}
|
}
|
||||||
fprintf(out, "%-8s %-3"PRIu32"M%-7s %-10lld %-2d%%\n",
|
fprintf(out, "%-8s %-3"PRIu32"M%-7s %-10lld %-2d%%\n",
|
||||||
s_mode_names[i],
|
s_mode_names[i],
|
||||||
s_cpu_freq_by_mode[i].freq_mhz,
|
freq_mhz_by_mode[i],
|
||||||
"", //Empty space to align columns
|
"", //Empty space to align columns
|
||||||
time_in_mode[i],
|
time_in_mode[i],
|
||||||
(int) (time_in_mode[i] * 100 / now));
|
(int) (time_in_mode[i] * 100 / now));
|
||||||
@@ -904,7 +949,7 @@ int esp_pm_impl_get_cpu_freq(pm_mode_t mode)
|
|||||||
int freq_mhz;
|
int freq_mhz;
|
||||||
if (mode >= PM_MODE_LIGHT_SLEEP && mode < PM_MODE_COUNT) {
|
if (mode >= PM_MODE_LIGHT_SLEEP && mode < PM_MODE_COUNT) {
|
||||||
portENTER_CRITICAL(&s_switch_lock);
|
portENTER_CRITICAL(&s_switch_lock);
|
||||||
freq_mhz = s_cpu_freq_by_mode[mode].freq_mhz;
|
freq_mhz = get_cpu_freq_config_by_mode(mode)->freq_mhz;
|
||||||
portEXIT_CRITICAL(&s_switch_lock);
|
portEXIT_CRITICAL(&s_switch_lock);
|
||||||
} else {
|
} else {
|
||||||
abort();
|
abort();
|
||||||
@@ -1050,3 +1095,42 @@ void esp_pm_impl_waiti(void)
|
|||||||
esp_cpu_wait_for_intr();
|
esp_cpu_wait_for_intr();
|
||||||
#endif // CONFIG_FREERTOS_USE_TICKLESS_IDLE
|
#endif // CONFIG_FREERTOS_USE_TICKLESS_IDLE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if CONFIG_PM_WORKAROUND_FREQ_LIMIT_ENABLED && CONFIG_PM_ENABLE
|
||||||
|
void esp_pm_impl_cpu_max_freq_force_init(uint32_t limit_freq_mhz)
|
||||||
|
{
|
||||||
|
// Pre-calculate frequency config (done outside critical section)
|
||||||
|
rtc_cpu_freq_config_t force_config;
|
||||||
|
bool res = rtc_clk_cpu_freq_mhz_to_config(limit_freq_mhz, &force_config);
|
||||||
|
assert(res && "Failed to convert forced CPU_MAX frequency to config");
|
||||||
|
|
||||||
|
// Store the pre-calculated config in critical section
|
||||||
|
portENTER_CRITICAL(&s_switch_lock);
|
||||||
|
s_cpu_max_freq_force_config = force_config;
|
||||||
|
portEXIT_CRITICAL(&s_switch_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IRAM_ATTR esp_pm_impl_cpu_max_freq_force(void)
|
||||||
|
{
|
||||||
|
portENTER_CRITICAL_SAFE(&s_switch_lock);
|
||||||
|
// Activate pre-configured forced frequency (no calculation needed at runtime)
|
||||||
|
s_cpu_max_freq_forced = true;
|
||||||
|
s_config_changed = true;
|
||||||
|
portEXIT_CRITICAL_SAFE(&s_switch_lock);
|
||||||
|
do_switch(PM_MODE_CPU_MAX);
|
||||||
|
const unsigned wait_clock_stable_us = 10;
|
||||||
|
esp_rom_delay_us(wait_clock_stable_us);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IRAM_ATTR esp_pm_impl_cpu_max_freq_unforce(void)
|
||||||
|
{
|
||||||
|
portENTER_CRITICAL_SAFE(&s_switch_lock);
|
||||||
|
s_cpu_max_freq_forced = false;
|
||||||
|
s_config_changed = true;
|
||||||
|
portEXIT_CRITICAL_SAFE(&s_switch_lock);
|
||||||
|
do_switch(PM_MODE_CPU_MAX);
|
||||||
|
const unsigned wait_clock_stable_us = 10;
|
||||||
|
esp_rom_delay_us(wait_clock_stable_us);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // CONFIG_PM_WORKAROUND_FREQ_LIMIT_ENABLED && CONFIG_PM_ENABLE
|
||||||
|
|||||||
@@ -55,16 +55,6 @@ static void esp_key_mgr_init(void)
|
|||||||
|
|
||||||
ESP_SYSTEM_INIT_FN(esp_security_init, SECONDARY, BIT(0), 103)
|
ESP_SYSTEM_INIT_FN(esp_security_init, SECONDARY, BIT(0), 103)
|
||||||
{
|
{
|
||||||
#if CONFIG_IDF_TARGET_ESP32C5
|
|
||||||
// Check for unsupported configuration: flash encryption with CPU frequency > 160MHz
|
|
||||||
// Manual encrypted flash writes are not stable at higher CPU clock.
|
|
||||||
// Please refer to the ESP32-C5 SoC Errata document for more details.
|
|
||||||
if (efuse_hal_flash_encryption_enabled() && CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ > 160) {
|
|
||||||
ESP_EARLY_LOGE(TAG, "Flash encryption with CPU frequency > 160MHz is not supported. Please reconfigure the CPU frequency.");
|
|
||||||
return ESP_ERR_NOT_SUPPORTED;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
esp_crypto_clk_init();
|
esp_crypto_clk_init();
|
||||||
|
|
||||||
#if SOC_KEY_MANAGER_SUPPORT_KEY_DEPLOYMENT
|
#if SOC_KEY_MANAGER_SUPPORT_KEY_DEPLOYMENT
|
||||||
|
|||||||
@@ -1,12 +1,9 @@
|
|||||||
choice ESP_DEFAULT_CPU_FREQ_MHZ
|
choice ESP_DEFAULT_CPU_FREQ_MHZ
|
||||||
prompt "CPU frequency"
|
prompt "CPU frequency"
|
||||||
default ESP_DEFAULT_CPU_FREQ_MHZ_40 if IDF_ENV_FPGA
|
default ESP_DEFAULT_CPU_FREQ_MHZ_40 if IDF_ENV_FPGA
|
||||||
default ESP_DEFAULT_CPU_FREQ_MHZ_160 if SECURE_FLASH_ENC_ENABLED
|
|
||||||
default ESP_DEFAULT_CPU_FREQ_MHZ_240
|
default ESP_DEFAULT_CPU_FREQ_MHZ_240
|
||||||
help
|
help
|
||||||
CPU frequency to be set on application startup. For flash encryption enabled case,
|
CPU frequency to be set on application startup.
|
||||||
the default CPU frequency is 160MHz as the encrypted flash writes are not stable at
|
|
||||||
higher CPU clock. Please see SoC Errata document for details.
|
|
||||||
|
|
||||||
config ESP_DEFAULT_CPU_FREQ_MHZ_40
|
config ESP_DEFAULT_CPU_FREQ_MHZ_40
|
||||||
bool "40 MHz"
|
bool "40 MHz"
|
||||||
@@ -16,10 +13,14 @@ choice ESP_DEFAULT_CPU_FREQ_MHZ
|
|||||||
config ESP_DEFAULT_CPU_FREQ_MHZ_160
|
config ESP_DEFAULT_CPU_FREQ_MHZ_160
|
||||||
bool "160 MHz"
|
bool "160 MHz"
|
||||||
config ESP_DEFAULT_CPU_FREQ_MHZ_240
|
config ESP_DEFAULT_CPU_FREQ_MHZ_240
|
||||||
# Encrypted flash writes aren't supported at 240 MHz.
|
|
||||||
# Please see SoC Errata document for details.
|
|
||||||
depends on !SECURE_FLASH_ENC_ENABLED
|
|
||||||
bool "240 MHz"
|
bool "240 MHz"
|
||||||
|
help
|
||||||
|
When 240MHz is selected, esp_flash_write_encrypted() will automatically limit CPU frequency during
|
||||||
|
execution:
|
||||||
|
- v1.2 and above chips: limited to 160MHz
|
||||||
|
- v1.0 and below chips: limited to 80MHz
|
||||||
|
When 160MHz or lower is selected, no frequency limiting occurs during encrypted writes. Please refer to
|
||||||
|
the ESP32-C5 SoC Errata document for more details.
|
||||||
endchoice
|
endchoice
|
||||||
|
|
||||||
config ESP_DEFAULT_CPU_FREQ_MHZ
|
config ESP_DEFAULT_CPU_FREQ_MHZ
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
#include "private/esp_coexist_internal.h"
|
#include "private/esp_coexist_internal.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if CONFIG_PM_ENABLE
|
#if CONFIG_PM_ENABLE || CONFIG_PM_WORKAROUND_FREQ_LIMIT_ENABLED
|
||||||
#include "esp_pm.h"
|
#include "esp_pm.h"
|
||||||
#include "esp_private/pm_impl.h"
|
#include "esp_private/pm_impl.h"
|
||||||
#endif
|
#endif
|
||||||
@@ -120,6 +120,9 @@ ESP_SYSTEM_INIT_FN(init_flash, CORE, BIT(0), 130)
|
|||||||
#endif // CONFIG_SPI_FLASH_BROWNOUT_RESET
|
#endif // CONFIG_SPI_FLASH_BROWNOUT_RESET
|
||||||
// The log library will call the registered callback function to check if the cache is disabled.
|
// The log library will call the registered callback function to check if the cache is disabled.
|
||||||
esp_log_util_set_cache_enabled_cb(spi_flash_cache_enabled);
|
esp_log_util_set_cache_enabled_cb(spi_flash_cache_enabled);
|
||||||
|
#if CONFIG_PM_WORKAROUND_FREQ_LIMIT_ENABLED
|
||||||
|
esp_pm_flash_freq_limit_init();
|
||||||
|
#endif // CONFIG_PM_WORKAROUND_FREQ_LIMIT_ENABLED
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
#endif // !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
|
#endif // !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
|
||||||
|
|||||||
@@ -1083,6 +1083,10 @@ config SOC_SPI_MEM_SUPPORT_TSUS_TRES_SEPERATE_CTR
|
|||||||
bool
|
bool
|
||||||
default y
|
default y
|
||||||
|
|
||||||
|
config SOC_SPI_MEM_PSRAM_FREQ_AXI_CONSTRAINED
|
||||||
|
bool
|
||||||
|
default y
|
||||||
|
|
||||||
config SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY
|
config SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY
|
||||||
bool
|
bool
|
||||||
default y
|
default y
|
||||||
|
|||||||
@@ -443,6 +443,7 @@
|
|||||||
#define SOC_SPI_MEM_SUPPORT_CACHE_32BIT_ADDR_MAP (1)
|
#define SOC_SPI_MEM_SUPPORT_CACHE_32BIT_ADDR_MAP (1)
|
||||||
#define SOC_SPI_MEM_SUPPORT_TIMING_TUNING (1)
|
#define SOC_SPI_MEM_SUPPORT_TIMING_TUNING (1)
|
||||||
#define SOC_SPI_MEM_SUPPORT_TSUS_TRES_SEPERATE_CTR (1)
|
#define SOC_SPI_MEM_SUPPORT_TSUS_TRES_SEPERATE_CTR (1)
|
||||||
|
#define SOC_SPI_MEM_PSRAM_FREQ_AXI_CONSTRAINED (1)
|
||||||
#define SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY (1)
|
#define SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY (1)
|
||||||
|
|
||||||
#define SOC_MEMSPI_SRC_FREQ_120M_SUPPORTED 1
|
#define SOC_MEMSPI_SRC_FREQ_120M_SUPPORTED 1
|
||||||
|
|||||||
@@ -815,6 +815,10 @@ config SOC_SPI_MEM_SUPPORT_TSUS_TRES_SEPERATE_CTR
|
|||||||
bool
|
bool
|
||||||
default y
|
default y
|
||||||
|
|
||||||
|
config SOC_SPI_MEM_PSRAM_FREQ_AXI_CONSTRAINED
|
||||||
|
bool
|
||||||
|
default y
|
||||||
|
|
||||||
config SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY
|
config SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY
|
||||||
bool
|
bool
|
||||||
default y
|
default y
|
||||||
|
|||||||
@@ -341,6 +341,7 @@
|
|||||||
#define SOC_SPI_MEM_SUPPORT_WRAP (1)
|
#define SOC_SPI_MEM_SUPPORT_WRAP (1)
|
||||||
#define SOC_SPI_MEM_SUPPORT_TIMING_TUNING (1)
|
#define SOC_SPI_MEM_SUPPORT_TIMING_TUNING (1)
|
||||||
#define SOC_SPI_MEM_SUPPORT_TSUS_TRES_SEPERATE_CTR (1)
|
#define SOC_SPI_MEM_SUPPORT_TSUS_TRES_SEPERATE_CTR (1)
|
||||||
|
#define SOC_SPI_MEM_PSRAM_FREQ_AXI_CONSTRAINED (1)
|
||||||
#define SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY (1)
|
#define SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY (1)
|
||||||
|
|
||||||
#define SOC_MEMSPI_SRC_FREQ_80M_SUPPORTED 1
|
#define SOC_MEMSPI_SRC_FREQ_80M_SUPPORTED 1
|
||||||
|
|||||||
@@ -675,6 +675,10 @@ config SOC_SPI_MEM_SUPPORT_WRAP
|
|||||||
bool
|
bool
|
||||||
default y
|
default y
|
||||||
|
|
||||||
|
config SOC_SPI_MEM_PSRAM_FREQ_AXI_CONSTRAINED
|
||||||
|
bool
|
||||||
|
default y
|
||||||
|
|
||||||
config SOC_SYSTIMER_COUNTER_NUM
|
config SOC_SYSTIMER_COUNTER_NUM
|
||||||
int
|
int
|
||||||
default 2
|
default 2
|
||||||
|
|||||||
@@ -384,6 +384,7 @@
|
|||||||
#define SOC_SPI_MEM_SUPPORT_SW_SUSPEND (1)
|
#define SOC_SPI_MEM_SUPPORT_SW_SUSPEND (1)
|
||||||
#define SOC_SPI_MEM_SUPPORT_CHECK_SUS (1)
|
#define SOC_SPI_MEM_SUPPORT_CHECK_SUS (1)
|
||||||
#define SOC_SPI_MEM_SUPPORT_WRAP (1)
|
#define SOC_SPI_MEM_SUPPORT_WRAP (1)
|
||||||
|
#define SOC_SPI_MEM_PSRAM_FREQ_AXI_CONSTRAINED (1)
|
||||||
|
|
||||||
/*-------------------------- SYSTIMER CAPS ----------------------------------*/
|
/*-------------------------- SYSTIMER CAPS ----------------------------------*/
|
||||||
#define SOC_SYSTIMER_COUNTER_NUM 2 // Number of counter units
|
#define SOC_SYSTIMER_COUNTER_NUM 2 // Number of counter units
|
||||||
|
|||||||
@@ -1435,6 +1435,10 @@ config SOC_SPI_MEM_SUPPORT_CACHE_32BIT_ADDR_MAP
|
|||||||
bool
|
bool
|
||||||
default y
|
default y
|
||||||
|
|
||||||
|
config SOC_SPI_MEM_PSRAM_FREQ_AXI_CONSTRAINED
|
||||||
|
bool
|
||||||
|
default y
|
||||||
|
|
||||||
config SOC_SPI_MEM_SUPPORT_TSUS_TRES_SEPERATE_CTR
|
config SOC_SPI_MEM_SUPPORT_TSUS_TRES_SEPERATE_CTR
|
||||||
bool
|
bool
|
||||||
default y
|
default y
|
||||||
|
|||||||
@@ -554,6 +554,7 @@
|
|||||||
#define SOC_MEMSPI_TIMING_TUNING_BY_DQS (1)
|
#define SOC_MEMSPI_TIMING_TUNING_BY_DQS (1)
|
||||||
#define SOC_MEMSPI_TIMING_TUNING_BY_FLASH_DELAY (1)
|
#define SOC_MEMSPI_TIMING_TUNING_BY_FLASH_DELAY (1)
|
||||||
#define SOC_SPI_MEM_SUPPORT_CACHE_32BIT_ADDR_MAP (1)
|
#define SOC_SPI_MEM_SUPPORT_CACHE_32BIT_ADDR_MAP (1)
|
||||||
|
#define SOC_SPI_MEM_PSRAM_FREQ_AXI_CONSTRAINED (1)
|
||||||
#define SOC_SPI_MEM_SUPPORT_TSUS_TRES_SEPERATE_CTR (1)
|
#define SOC_SPI_MEM_SUPPORT_TSUS_TRES_SEPERATE_CTR (1)
|
||||||
|
|
||||||
#define SOC_SPI_PERIPH_SUPPORT_CONTROL_DUMMY_OUT (1)
|
#define SOC_SPI_PERIPH_SUPPORT_CONTROL_DUMMY_OUT (1)
|
||||||
|
|||||||
@@ -458,4 +458,11 @@ menu "SPI Flash driver"
|
|||||||
application is not using flash encryption feature and is in need of some additional
|
application is not using flash encryption feature and is in need of some additional
|
||||||
memory from IRAM region (~1KB) then this config can be disabled.
|
memory from IRAM region (~1KB) then this config can be disabled.
|
||||||
|
|
||||||
|
config SPI_FLASH_FREQ_LIMIT_C5_240MHZ
|
||||||
|
bool
|
||||||
|
default y if IDF_TARGET_ESP32C5 && ESP_DEFAULT_CPU_FREQ_MHZ_240
|
||||||
|
help
|
||||||
|
Enable frequency limit workaround for encrypted flash writes on ESP32-C5 at 240MHz default CPU frequency.
|
||||||
|
This is an internal configuration, automatically set based on target chip and CPU frequency.
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|||||||
@@ -135,15 +135,6 @@ static ESP_LOG_ATTR const char io_mode_str[][IO_STR_LEN] = {
|
|||||||
|
|
||||||
_Static_assert(sizeof(io_mode_str)/IO_STR_LEN == SPI_FLASH_READ_MODE_MAX, "the io_mode_str should be consistent with the esp_flash_io_mode_t defined in spi_flash_types.h");
|
_Static_assert(sizeof(io_mode_str)/IO_STR_LEN == SPI_FLASH_READ_MODE_MAX, "the io_mode_str should be consistent with the esp_flash_io_mode_t defined in spi_flash_types.h");
|
||||||
|
|
||||||
esp_err_t esp_flash_read_chip_id(esp_flash_t* chip, uint32_t* flash_id);
|
|
||||||
|
|
||||||
#if !CONFIG_SPI_FLASH_ROM_IMPL || ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV
|
|
||||||
static esp_err_t spiflash_start_default(esp_flash_t *chip);
|
|
||||||
static esp_err_t spiflash_end_default(esp_flash_t *chip, esp_err_t err);
|
|
||||||
static esp_err_t check_chip_pointer_default(esp_flash_t **inout_chip);
|
|
||||||
static esp_err_t flash_end_flush_cache(esp_flash_t* chip, esp_err_t err, bool bus_acquired, uint32_t address, uint32_t length);
|
|
||||||
#endif // !CONFIG_SPI_FLASH_ROM_IMPL || ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
esp_err_t (*start)(esp_flash_t *chip);
|
esp_err_t (*start)(esp_flash_t *chip);
|
||||||
esp_err_t (*end)(esp_flash_t *chip, esp_err_t err);
|
esp_err_t (*end)(esp_flash_t *chip, esp_err_t err);
|
||||||
@@ -151,19 +142,70 @@ typedef struct {
|
|||||||
esp_err_t (*flash_end_flush_cache)(esp_flash_t* chip, esp_err_t err, bool bus_acquired, uint32_t address, uint32_t length);
|
esp_err_t (*flash_end_flush_cache)(esp_flash_t* chip, esp_err_t err, bool bus_acquired, uint32_t address, uint32_t length);
|
||||||
} rom_spiflash_api_func_t;
|
} rom_spiflash_api_func_t;
|
||||||
|
|
||||||
|
|
||||||
|
esp_err_t esp_flash_read_chip_id(esp_flash_t* chip, uint32_t* flash_id);
|
||||||
|
|
||||||
|
#if CONFIG_SPI_FLASH_ROM_IMPL
|
||||||
|
extern rom_spiflash_api_func_t *esp_flash_api_funcs;
|
||||||
|
#define rom_spiflash_api_funcs esp_flash_api_funcs
|
||||||
|
#else
|
||||||
|
#define rom_spiflash_api_funcs esp_flash_api_funcs_patched_ptr
|
||||||
|
#endif
|
||||||
|
|
||||||
#if !CONFIG_SPI_FLASH_ROM_IMPL || ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV
|
#if !CONFIG_SPI_FLASH_ROM_IMPL || ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV
|
||||||
|
// API funcs case 1 & 2
|
||||||
|
static esp_err_t spiflash_start_default(esp_flash_t *chip);
|
||||||
|
static esp_err_t spiflash_end_default(esp_flash_t *chip, esp_err_t err);
|
||||||
|
static esp_err_t check_chip_pointer_default(esp_flash_t **inout_chip);
|
||||||
|
static esp_err_t flash_end_flush_cache(esp_flash_t* chip, esp_err_t err, bool bus_acquired, uint32_t address, uint32_t length);
|
||||||
|
|
||||||
// These functions can be placed in the ROM. For now we use the code in IDF.
|
// These functions can be placed in the ROM. For now we use the code in IDF.
|
||||||
DRAM_ATTR static rom_spiflash_api_func_t default_spiflash_rom_api = {
|
DRAM_ATTR static rom_spiflash_api_func_t esp_flash_api_funcs_patched = {
|
||||||
.start = spiflash_start_default,
|
.start = spiflash_start_default,
|
||||||
.end = spiflash_end_default,
|
.end = spiflash_end_default,
|
||||||
.chip_check = check_chip_pointer_default,
|
.chip_check = check_chip_pointer_default,
|
||||||
.flash_end_flush_cache = flash_end_flush_cache,
|
.flash_end_flush_cache = flash_end_flush_cache,
|
||||||
};
|
};
|
||||||
|
|
||||||
DRAM_ATTR rom_spiflash_api_func_t *rom_spiflash_api_funcs = &default_spiflash_rom_api;
|
# if !CONFIG_SPI_FLASH_ROM_IMPL
|
||||||
#else
|
// API funcs case 1: Not using ROM - define our own pointer and all functions
|
||||||
extern rom_spiflash_api_func_t *esp_flash_api_funcs;
|
DRAM_ATTR static rom_spiflash_api_func_t *esp_flash_api_funcs_patched_ptr = &esp_flash_api_funcs_patched;
|
||||||
#define rom_spiflash_api_funcs esp_flash_api_funcs
|
|
||||||
|
# else // CONFIG_SPI_FLASH_ROM_IMPL
|
||||||
|
// API funcs case 2: Using ROM APIs but patch all api_funcs by updating esp_flash_api_funcs from ROM
|
||||||
|
void esp_flash_rom_api_funcs_init(void)
|
||||||
|
{
|
||||||
|
// Point esp_flash_api_funcs to our default structure
|
||||||
|
esp_flash_api_funcs = &esp_flash_api_funcs_patched;
|
||||||
|
}
|
||||||
|
|
||||||
|
# endif // CONFIG_SPI_FLASH_ROM_IMPL
|
||||||
|
|
||||||
|
#else // CONFIG_SPI_FLASH_ROM_IMPL && !ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV
|
||||||
|
// Using ROM implementation
|
||||||
|
|
||||||
|
# if CONFIG_SPI_FLASH_FREQ_LIMIT_C5_240MHZ
|
||||||
|
// API funcs case 3: Using ROM APIs but patch start function to support flags parameter
|
||||||
|
static esp_err_t spiflash_start_default(esp_flash_t *chip);
|
||||||
|
DRAM_ATTR static rom_spiflash_api_func_t esp_flash_api_funcs_patched;
|
||||||
|
|
||||||
|
// Copy ROM structure to RAM and patch start function to support flags
|
||||||
|
void esp_flash_rom_api_funcs_init(void)
|
||||||
|
{
|
||||||
|
rom_spiflash_api_func_t *rom_ptr = esp_flash_api_funcs;
|
||||||
|
memcpy(&esp_flash_api_funcs_patched, rom_ptr, sizeof(rom_spiflash_api_func_t));
|
||||||
|
esp_flash_api_funcs_patched.start = spiflash_start_default;
|
||||||
|
esp_flash_api_funcs = &esp_flash_api_funcs_patched;
|
||||||
|
}
|
||||||
|
|
||||||
|
# else
|
||||||
|
// API funcs case 4: Using All ROM APIs directly
|
||||||
|
void esp_flash_rom_api_funcs_init(void)
|
||||||
|
{
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
# endif // CONFIG_SPI_FLASH_FREQ_LIMIT_C5_240MHZ
|
||||||
#endif // !CONFIG_SPI_FLASH_ROM_IMPL || ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV
|
#endif // !CONFIG_SPI_FLASH_ROM_IMPL || ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV
|
||||||
|
|
||||||
/* Static function to notify OS of a new SPI flash operation.
|
/* Static function to notify OS of a new SPI flash operation.
|
||||||
@@ -171,11 +213,13 @@ extern rom_spiflash_api_func_t *esp_flash_api_funcs;
|
|||||||
If returns an error result, caller must abort. If returns ESP_OK, caller must
|
If returns an error result, caller must abort. If returns ESP_OK, caller must
|
||||||
call rom_spiflash_api_funcs->end() before returning.
|
call rom_spiflash_api_funcs->end() before returning.
|
||||||
*/
|
*/
|
||||||
#if !CONFIG_SPI_FLASH_ROM_IMPL || ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV
|
#if !CONFIG_SPI_FLASH_ROM_IMPL || ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV || CONFIG_SPI_FLASH_FREQ_LIMIT_C5_240MHZ
|
||||||
static esp_err_t spiflash_start_default(esp_flash_t *chip)
|
//Avoid constprop issue that place this function into flash.
|
||||||
|
__attribute__((optimize("O0"))) //IDF-14941
|
||||||
|
static esp_err_t spiflash_start_core(esp_flash_t *chip, uint32_t flags)
|
||||||
{
|
{
|
||||||
if (chip->os_func != NULL && chip->os_func->start != NULL) {
|
if (chip->os_func != NULL && chip->os_func->start != NULL) {
|
||||||
esp_err_t err = chip->os_func->start(chip->os_func_data);
|
esp_err_t err = chip->os_func->start(chip->os_func_data, flags);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@@ -184,6 +228,13 @@ static esp_err_t spiflash_start_default(esp_flash_t *chip)
|
|||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static esp_err_t spiflash_start_default(esp_flash_t *chip)
|
||||||
|
{
|
||||||
|
return spiflash_start_core(chip, 0);
|
||||||
|
}
|
||||||
|
#endif //!CONFIG_SPI_FLASH_ROM_IMPL || ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV || CONFIG_SPI_FLASH_FREQ_LIMIT_C5_240MHZ
|
||||||
|
|
||||||
|
#if !CONFIG_SPI_FLASH_ROM_IMPL || ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV
|
||||||
/* Static function to notify OS that SPI flash operation is complete.
|
/* Static function to notify OS that SPI flash operation is complete.
|
||||||
*/
|
*/
|
||||||
static esp_err_t spiflash_end_default(esp_flash_t *chip, esp_err_t err)
|
static esp_err_t spiflash_end_default(esp_flash_t *chip, esp_err_t err)
|
||||||
@@ -1235,13 +1286,20 @@ esp_err_t esp_flash_set_io_mode(esp_flash_t* chip, bool qe)
|
|||||||
}
|
}
|
||||||
#endif //CONFIG_SPI_FLASH_ROM_IMPL
|
#endif //CONFIG_SPI_FLASH_ROM_IMPL
|
||||||
|
|
||||||
#if !(CONFIG_SPI_FLASH_ROM_IMPL && !ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV)
|
#if !(CONFIG_SPI_FLASH_ROM_IMPL && !ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV) || CONFIG_SPI_FLASH_FREQ_LIMIT_C5_240MHZ
|
||||||
// use `esp_flash_write_encrypted` ROM version on chips later than C3 and S3
|
// use `esp_flash_write_encrypted` ROM version on chips later than C3, S3
|
||||||
FORCE_INLINE_ATTR esp_err_t s_encryption_write_lock(esp_flash_t *chip) {
|
// For ESP32-C5, use IDF implementation when CPU frequency is 240MHz (calling start() with arg is required)
|
||||||
|
FORCE_INLINE_ATTR esp_err_t s_encryption_write_lock(esp_flash_t *chip)
|
||||||
|
{
|
||||||
#if CONFIG_IDF_TARGET_ESP32S2
|
#if CONFIG_IDF_TARGET_ESP32S2
|
||||||
esp_crypto_dma_lock_acquire();
|
esp_crypto_dma_lock_acquire();
|
||||||
#endif //CONFIG_IDF_TARGET_ESP32S2
|
#endif //CONFIG_IDF_TARGET_ESP32S2
|
||||||
|
#if CONFIG_SPI_FLASH_FREQ_LIMIT_C5_240MHZ
|
||||||
|
// Use start_core with LIMIT_CPU_FREQ flag to trigger freq_limit_lock in OS layer
|
||||||
|
return spiflash_start_core(chip, ESP_FLASH_START_FLAG_LIMIT_CPU_FREQ);
|
||||||
|
#else
|
||||||
return rom_spiflash_api_funcs->start(chip);
|
return rom_spiflash_api_funcs->start(chip);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
FORCE_INLINE_ATTR esp_err_t s_encryption_write_unlock(esp_flash_t *chip) {
|
FORCE_INLINE_ATTR esp_err_t s_encryption_write_unlock(esp_flash_t *chip) {
|
||||||
@@ -1493,7 +1551,7 @@ esp_err_t IRAM_ATTR esp_flash_write_encrypted(esp_flash_t *chip, uint32_t addres
|
|||||||
}
|
}
|
||||||
return rom_esp_flash_write_encrypted(chip, address, buffer, length);
|
return rom_esp_flash_write_encrypted(chip, address, buffer, length);
|
||||||
}
|
}
|
||||||
#endif // !(CONFIG_SPI_FLASH_ROM_IMPL && !ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV)
|
#endif // !(CONFIG_SPI_FLASH_ROM_IMPL && !ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV) || CONFIG_SPI_FLASH_FREQ_LIMIT_C5_240MHZ
|
||||||
|
|
||||||
//init suspend mode cmd, uses internal.
|
//init suspend mode cmd, uses internal.
|
||||||
esp_err_t esp_flash_suspend_cmd_init(esp_flash_t* chip)
|
esp_err_t esp_flash_suspend_cmd_init(esp_flash_t* chip)
|
||||||
|
|||||||
@@ -145,6 +145,19 @@ esp_flash_t *esp_flash_default_chip = NULL;
|
|||||||
#endif //!CONFIG_SPI_FLASH_AUTO_SUSPEND
|
#endif //!CONFIG_SPI_FLASH_AUTO_SUSPEND
|
||||||
#endif // Other target
|
#endif // Other target
|
||||||
|
|
||||||
|
// Dynamic flash configuration is only needed when:
|
||||||
|
// 1. Frequency limit workaround is enabled (CONFIG_SPI_FLASH_FREQ_LIMIT_C5_240MHZ)
|
||||||
|
// 2. Flash frequency requires timing tuning (80MHz or 120MHz, i.e., > 40MHz)
|
||||||
|
// 3. CPU frequency reduction will trigger MSPI timing tuning to enter low speed mode
|
||||||
|
// This happens when: SOC_SPI_MEM_PSRAM_FREQ_AXI_CONSTRAINED && CONFIG_SPIRAM &&
|
||||||
|
// (target_cpu_freq < CONFIG_SPIRAM_SPEED)
|
||||||
|
// Note: The runtime check for CPU freq < PSRAM speed is done in clk_utils.c,
|
||||||
|
// which calls mspi_timing_change_speed_mode_cache_safe(true) to enter low speed mode.
|
||||||
|
// For ESP32-C5, if PSRAM is enabled and CPU freq < PSRAM speed, timing tuning will be disabled.
|
||||||
|
#define C5_NEEDS_DYNAMIC_CONFIG (CONFIG_SPI_FLASH_FREQ_LIMIT_C5_240MHZ && CONFIG_SPIRAM && \
|
||||||
|
(CONFIG_ESPTOOLPY_FLASHFREQ_80M || CONFIG_ESPTOOLPY_FLASHFREQ_120M))
|
||||||
|
|
||||||
|
|
||||||
static IRAM_ATTR NOINLINE_ATTR void cs_initialize(esp_flash_t *chip, const esp_flash_spi_device_config_t *config, bool cs_use_iomux, int cs_id)
|
static IRAM_ATTR NOINLINE_ATTR void cs_initialize(esp_flash_t *chip, const esp_flash_spi_device_config_t *config, bool cs_use_iomux, int cs_id)
|
||||||
{
|
{
|
||||||
//Not using spicommon_cs_initialize since we don't want to put the whole
|
//Not using spicommon_cs_initialize since we don't want to put the whole
|
||||||
@@ -160,7 +173,7 @@ static IRAM_ATTR NOINLINE_ATTR void cs_initialize(esp_flash_t *chip, const esp_f
|
|||||||
|
|
||||||
//To avoid the panic caused by flash data line conflicts during cs line
|
//To avoid the panic caused by flash data line conflicts during cs line
|
||||||
//initialization, disable the cache temporarily
|
//initialization, disable the cache temporarily
|
||||||
chip->os_func->start(chip->os_func_data);
|
chip->os_func->start(chip->os_func_data, 0);
|
||||||
gpio_hal_input_enable(&gpio_hal, cs_io_num);
|
gpio_hal_input_enable(&gpio_hal, cs_io_num);
|
||||||
if (cs_use_iomux) {
|
if (cs_use_iomux) {
|
||||||
gpio_hal_func_sel(&gpio_hal, cs_io_num, spics_func);
|
gpio_hal_func_sel(&gpio_hal, cs_io_num, spics_func);
|
||||||
@@ -554,6 +567,16 @@ esp_err_t esp_flash_init_default_chip(void)
|
|||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
#if C5_NEEDS_DYNAMIC_CONFIG
|
||||||
|
err = memspi_host_init_c5_dynamic_config(&esp_flash_default_host);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CONFIG_SPI_FLASH_ROM_IMPL
|
||||||
|
esp_flash_rom_api_funcs_init();
|
||||||
|
#endif // CONFIG_SPI_FLASH_ROM_IMPL
|
||||||
|
|
||||||
// ROM TODO: account for non-standard default pins in efuse
|
// ROM TODO: account for non-standard default pins in efuse
|
||||||
// ROM TODO: to account for chips which are slow to power on, maybe keep probing in a loop here
|
// ROM TODO: to account for chips which are slow to power on, maybe keep probing in a loop here
|
||||||
@@ -615,6 +638,7 @@ esp_err_t esp_flash_app_init(void)
|
|||||||
|
|
||||||
spi_flash_init_lock();
|
spi_flash_init_lock();
|
||||||
spi_flash_guard_set(&g_flash_guard_default_ops);
|
spi_flash_guard_set(&g_flash_guard_default_ops);
|
||||||
|
|
||||||
#if CONFIG_SPI_FLASH_ENABLE_COUNTERS
|
#if CONFIG_SPI_FLASH_ENABLE_COUNTERS
|
||||||
esp_flash_reset_counters();
|
esp_flash_reset_counters();
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -38,11 +38,17 @@ typedef struct {
|
|||||||
* risk.
|
* risk.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
/**
|
||||||
|
* Flags for start function
|
||||||
|
*/
|
||||||
|
/** Limit CPU frequency during flash operations (ESP32-C5 only, 240MHz).
|
||||||
|
*/
|
||||||
|
#define ESP_FLASH_START_FLAG_LIMIT_CPU_FREQ BIT(0)
|
||||||
/**
|
/**
|
||||||
* Called before commencing any flash operation. Does not need to be
|
* Called before commencing any flash operation. Does not need to be
|
||||||
* recursive (ie is called at most once for each call to 'end').
|
* recursive (ie is called at most once for each call to 'end').
|
||||||
*/
|
*/
|
||||||
esp_err_t (*start)(void *arg);
|
esp_err_t (*start)(void *arg, uint32_t flags);
|
||||||
|
|
||||||
/** Called after completing any flash operation. */
|
/** Called after completing any flash operation. */
|
||||||
esp_err_t (*end)(void *arg);
|
esp_err_t (*end)(void *arg);
|
||||||
|
|||||||
@@ -117,6 +117,16 @@ 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);
|
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.
|
||||||
|
*/
|
||||||
|
void esp_flash_rom_api_funcs_init(void);
|
||||||
|
#endif // CONFIG_SPI_FLASH_ROM_IMPL
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "sdkconfig.h"
|
||||||
|
#include "esp_flash.h"
|
||||||
|
#include "esp_attr.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CONFIG_SPI_FLASH_FREQ_LIMIT_C5_240MHZ
|
||||||
|
/**
|
||||||
|
* @brief Callback to limit CPU frequency for flash encryption writes (ESP32-C5 only, 240MHz)
|
||||||
|
*
|
||||||
|
* This function limits CPU frequency to <= 160MHz during encrypted flash writes.
|
||||||
|
* It should be called before starting an encrypted flash write operation.
|
||||||
|
*
|
||||||
|
* @note This is an internal function, not exposed to users.
|
||||||
|
* @note This function is placed in IRAM (implementation uses IRAM_ATTR).
|
||||||
|
* @note This function is called from spi_flash_os_func_app.c::spi1_start() after cache
|
||||||
|
* and scheduler locks are acquired. As a result, there is no concurrency concern
|
||||||
|
* and no need for internal locking or reference counting.
|
||||||
|
*/
|
||||||
|
void esp_flash_freq_limit_cb(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Callback to unlimit CPU frequency after flash encryption writes (ESP32-C5 only, 240MHz)
|
||||||
|
*
|
||||||
|
* This function restores the CPU frequency after an encrypted flash write operation.
|
||||||
|
* It should be called after completing an encrypted flash write operation.
|
||||||
|
*
|
||||||
|
* @note This is an internal function, not exposed to users.
|
||||||
|
* @note This function is placed in IRAM (implementation uses IRAM_ATTR).
|
||||||
|
* @note This function is called from spi_flash_os_func_app.c::spi1_end() before cache
|
||||||
|
* and scheduler locks are released. As a result, there is no concurrency concern
|
||||||
|
* and no need for internal locking or reference counting.
|
||||||
|
*/
|
||||||
|
void esp_flash_freq_unlimit_cb(void);
|
||||||
|
#endif // CONFIG_SPI_FLASH_FREQ_LIMIT_C5_240MHZ
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -48,6 +48,17 @@ typedef spi_flash_hal_context_t memspi_host_inst_t;
|
|||||||
*/
|
*/
|
||||||
esp_err_t memspi_host_init_pointers(memspi_host_inst_t *host, const memspi_host_config_t *cfg);
|
esp_err_t memspi_host_init_pointers(memspi_host_inst_t *host, const memspi_host_config_t *cfg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the memory SPI host for ESP32-C5 dynamic configuration.
|
||||||
|
*
|
||||||
|
* @param host Pointer to the host structure.
|
||||||
|
*
|
||||||
|
* @note This function is available only when CONFIG_SPI_FLASH_FREQ_LIMIT_C5_240MHZ is defined.
|
||||||
|
* @note This function can only be called once at startup, after memspi_host_init_pointers() is called.
|
||||||
|
* @return always return ESP_OK
|
||||||
|
*/
|
||||||
|
esp_err_t memspi_host_init_c5_dynamic_config(memspi_host_inst_t *host);
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* NOTICE
|
* NOTICE
|
||||||
* Rest part of this file are part of the HAL layer
|
* Rest part of this file are part of the HAL layer
|
||||||
@@ -161,7 +172,7 @@ int memspi_host_read_data_slicer(spi_flash_host_inst_t *host, uint32_t address,
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Slicer for write data used in non-encrypted regions. This slicer limit the length to the
|
* @brief Slicer for write data used in non-encrypted regions. This slicer limit the length to the
|
||||||
* maximum size the host supports, and truncate if the write data lie accross the page boundary
|
* maximum size the host supports, and truncate if the write data lie across the page boundary
|
||||||
* (256 bytes)
|
* (256 bytes)
|
||||||
*
|
*
|
||||||
* @param address Flash address to write
|
* @param address Flash address to write
|
||||||
|
|||||||
@@ -45,12 +45,15 @@ entries:
|
|||||||
if SPI_FLASH_VERIFY_WRITE = y:
|
if SPI_FLASH_VERIFY_WRITE = y:
|
||||||
esp_flash_api: s_verify_write (noflash)
|
esp_flash_api: s_verify_write (noflash)
|
||||||
|
|
||||||
if SPI_FLASH_ROM_IMPL = n || ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV = y:
|
if SPI_FLASH_ROM_IMPL = n || ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV = y || SPI_FLASH_FREQ_LIMIT_C5_240MHZ = y:
|
||||||
esp_flash_api: spiflash_start_default (noflash)
|
esp_flash_api: spiflash_start_default (noflash)
|
||||||
|
esp_flash_api: spiflash_start_core (noflash)
|
||||||
|
esp_flash_api: esp_flash_write_encrypted (noflash)
|
||||||
|
|
||||||
|
if SPI_FLASH_ROM_IMPL = n || ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV = y:
|
||||||
esp_flash_api: spiflash_end_default (noflash)
|
esp_flash_api: spiflash_end_default (noflash)
|
||||||
esp_flash_api: check_chip_pointer_default (noflash)
|
esp_flash_api: check_chip_pointer_default (noflash)
|
||||||
esp_flash_api: flash_end_flush_cache (noflash)
|
esp_flash_api: flash_end_flush_cache (noflash)
|
||||||
esp_flash_api: esp_flash_write_encrypted (noflash)
|
|
||||||
|
|
||||||
if SPI_FLASH_ROM_IMPL = n:
|
if SPI_FLASH_ROM_IMPL = n:
|
||||||
esp_flash_api: esp_flash_get_size (noflash)
|
esp_flash_api: esp_flash_get_size (noflash)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "sdkconfig.h"
|
||||||
#include "soc/soc_caps.h"
|
#include "soc/soc_caps.h"
|
||||||
#include "spi_flash_defs.h"
|
#include "spi_flash_defs.h"
|
||||||
#include "memspi_host_driver.h"
|
#include "memspi_host_driver.h"
|
||||||
@@ -12,12 +13,13 @@
|
|||||||
#include "esp_private/cache_utils.h"
|
#include "esp_private/cache_utils.h"
|
||||||
#include "esp_flash_partitions.h"
|
#include "esp_flash_partitions.h"
|
||||||
#include "esp_memory_utils.h"
|
#include "esp_memory_utils.h"
|
||||||
|
#include "hal/mspi_ll.h"
|
||||||
|
|
||||||
|
|
||||||
#define SPI_FLASH_HAL_MAX_WRITE_BYTES 64
|
#define SPI_FLASH_HAL_MAX_WRITE_BYTES 64
|
||||||
#define SPI_FLASH_HAL_MAX_READ_BYTES 64
|
#define SPI_FLASH_HAL_MAX_READ_BYTES 64
|
||||||
|
|
||||||
DRAM_ATTR static const spi_flash_host_driver_t esp_flash_default_host = ESP_FLASH_DEFAULT_HOST_DRIVER();
|
DRAM_ATTR static spi_flash_host_driver_t esp_flash_default_host = ESP_FLASH_DEFAULT_HOST_DRIVER();
|
||||||
|
|
||||||
#if SOC_MEMSPI_IS_INDEPENDENT
|
#if SOC_MEMSPI_IS_INDEPENDENT
|
||||||
extern void spi_flash_hal_gpspi_poll_cmd_done(spi_flash_host_inst_t *host);
|
extern void spi_flash_hal_gpspi_poll_cmd_done(spi_flash_host_inst_t *host);
|
||||||
@@ -71,9 +73,9 @@ esp_err_t memspi_host_init_pointers(memspi_host_inst_t *host, const memspi_host_
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if SOC_MEMSPI_IS_INDEPENDENT
|
#if SOC_MEMSPI_IS_INDEPENDENT
|
||||||
if (cfg->host_id == SPI1_HOST)
|
if (cfg->host_id == SPI1_HOST) {
|
||||||
host->inst.driver = &esp_flash_default_host;
|
host->inst.driver = &esp_flash_default_host;
|
||||||
else {
|
} else {
|
||||||
host->inst.driver = &esp_flash_gpspi_host;
|
host->inst.driver = &esp_flash_gpspi_host;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
@@ -253,3 +255,52 @@ int memspi_host_read_data_slicer(spi_flash_host_inst_t *host, uint32_t address,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endif // CONFIG_SPI_FLASH_ROM_IMPL
|
#endif // CONFIG_SPI_FLASH_ROM_IMPL
|
||||||
|
|
||||||
|
#if CONFIG_SPI_FLASH_FREQ_LIMIT_C5_240MHZ
|
||||||
|
// Dynamic flash configuration based on timing tuning state:
|
||||||
|
// 1. The timing tuning system automatically sets core clock and timing parameters (including din_mode/num, etc.).
|
||||||
|
// It also generates configurations such as clock configuration and dummy configuration for driver use.
|
||||||
|
// Without calling this function, the driver gets these configurations during initialization and uses them forever.
|
||||||
|
// The timing tuning provides clock configuration (frequency division) and dummy count.
|
||||||
|
// 2. When dynamic configuration is needed, call this function. The function supports two states:
|
||||||
|
// - Timing tuned state (high speed): Restore the values generated by the timing tuning system to the driver,
|
||||||
|
// as if there was no frequency reduction.
|
||||||
|
// - Without timing tuning state (low speed): Set configuration to maximum frequency (40 MHz on C5), dummy=0.
|
||||||
|
static uint32_t s_high_speed_clock_reg;
|
||||||
|
static uint32_t s_high_speed_extra_dummy;
|
||||||
|
|
||||||
|
ESP_STATIC_ASSERT(MSPI_TIMING_LL_CORE_CLOCK_MHZ_DEFAULT == 80);
|
||||||
|
#define LOW_SPEED_DIV (MSPI_TIMING_LL_CORE_CLOCK_MHZ_DEFAULT/40)
|
||||||
|
static esp_err_t spi_flash_hal_device_config_c5(spi_flash_host_inst_t *host)
|
||||||
|
{
|
||||||
|
spi_flash_hal_context_t* ctx = (spi_flash_hal_context_t*)host;
|
||||||
|
|
||||||
|
// Note: SPI0 and SPI1 have separate TIMING_CALI_REG registers, but SPI0's register reflects the timing tuning state
|
||||||
|
// since SPI0 and SPI1 share din_mode/din_num registers and timing tuning is configured on SPI0
|
||||||
|
uint32_t timing_cali_reg = REG_READ(SPI_MEM_TIMING_CALI_REG(MSPI_TIMING_LL_MSPI_ID_0));
|
||||||
|
bool is_low_speed = !(timing_cali_reg & SPI_MEM_TIMING_CALI_M);
|
||||||
|
|
||||||
|
if (is_low_speed) {
|
||||||
|
// Low speed mode: Set to safe division, dummy=0
|
||||||
|
uint32_t low_speed_clock_reg = mspi_timing_ll_calculate_clock_reg(LOW_SPEED_DIV);
|
||||||
|
ctx->clock_conf.spimem = low_speed_clock_reg;
|
||||||
|
ctx->extra_dummy = 0;
|
||||||
|
} else {
|
||||||
|
// High speed mode: Restore timing tuning values
|
||||||
|
ctx->clock_conf.spimem = s_high_speed_clock_reg;
|
||||||
|
ctx->extra_dummy = s_high_speed_extra_dummy;
|
||||||
|
}
|
||||||
|
return spi_flash_hal_device_config(host);
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t memspi_host_init_c5_dynamic_config(memspi_host_inst_t *host)
|
||||||
|
{
|
||||||
|
assert(s_high_speed_clock_reg == 0 && s_high_speed_extra_dummy == 0);
|
||||||
|
|
||||||
|
spi_flash_hal_context_t* ctx = (spi_flash_hal_context_t*)host;
|
||||||
|
s_high_speed_clock_reg = ctx->clock_conf.spimem;
|
||||||
|
s_high_speed_extra_dummy = ctx->extra_dummy;
|
||||||
|
esp_flash_default_host.dev_config = spi_flash_hal_device_config_c5;
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -20,9 +20,12 @@
|
|||||||
#include "esp_rom_sys.h"
|
#include "esp_rom_sys.h"
|
||||||
#include "esp_private/spi_flash_os.h"
|
#include "esp_private/spi_flash_os.h"
|
||||||
#include "esp_private/cache_utils.h"
|
#include "esp_private/cache_utils.h"
|
||||||
|
|
||||||
#include "esp_private/spi_share_hw_ctrl.h"
|
#include "esp_private/spi_share_hw_ctrl.h"
|
||||||
|
|
||||||
|
// For C5 encrypted write workaround
|
||||||
|
// Functions are only available when CONFIG_SPI_FLASH_FREQ_LIMIT_C5_240MHZ is true
|
||||||
|
#include "esp_private/spi_flash_freq_limit_cbs.h"
|
||||||
|
|
||||||
#define SPI_FLASH_CACHE_NO_DISABLE (CONFIG_SPI_FLASH_AUTO_SUSPEND || (CONFIG_SPIRAM_FETCH_INSTRUCTIONS && CONFIG_SPIRAM_RODATA) || CONFIG_APP_BUILD_TYPE_RAM)
|
#define SPI_FLASH_CACHE_NO_DISABLE (CONFIG_SPI_FLASH_AUTO_SUSPEND || (CONFIG_SPIRAM_FETCH_INSTRUCTIONS && CONFIG_SPIRAM_RODATA) || CONFIG_APP_BUILD_TYPE_RAM)
|
||||||
static const char TAG[] = "spi_flash";
|
static const char TAG[] = "spi_flash";
|
||||||
|
|
||||||
@@ -53,6 +56,7 @@ typedef struct {
|
|||||||
bool no_protect; //to decide whether to check protected region (for the main chip) or not.
|
bool no_protect; //to decide whether to check protected region (for the main chip) or not.
|
||||||
uint32_t acquired_since_us; // Time since last explicit yield()
|
uint32_t acquired_since_us; // Time since last explicit yield()
|
||||||
uint32_t released_since_us; // Time since last end() (implicit 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
|
||||||
} app_func_arg_t;
|
} app_func_arg_t;
|
||||||
|
|
||||||
static inline void on_spi_released(app_func_arg_t* ctx);
|
static inline void on_spi_released(app_func_arg_t* ctx);
|
||||||
@@ -90,21 +94,27 @@ static IRAM_ATTR esp_err_t release_spi_bus_lock(void *arg)
|
|||||||
return spi_bus_lock_acquire_end(((app_func_arg_t *)arg)->dev_lock);
|
return spi_bus_lock_acquire_end(((app_func_arg_t *)arg)->dev_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static esp_err_t spi23_start(void *arg){
|
static esp_err_t spi23_start(void *arg, uint32_t flags)
|
||||||
|
{
|
||||||
|
(void)flags;
|
||||||
esp_err_t ret = acquire_spi_bus_lock(arg);
|
esp_err_t ret = acquire_spi_bus_lock(arg);
|
||||||
on_spi_acquired((app_func_arg_t*)arg);
|
on_spi_acquired((app_func_arg_t*)arg);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static esp_err_t spi23_end(void *arg){
|
static esp_err_t spi23_end(void *arg)
|
||||||
|
{
|
||||||
esp_err_t ret = release_spi_bus_lock(arg);
|
esp_err_t ret = release_spi_bus_lock(arg);
|
||||||
on_spi_released((app_func_arg_t*)arg);
|
on_spi_released((app_func_arg_t*)arg);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static IRAM_ATTR esp_err_t spi1_start(void *arg)
|
static IRAM_ATTR esp_err_t spi1_start(void *arg, uint32_t flags)
|
||||||
{
|
{
|
||||||
esp_err_t ret = ESP_OK;
|
esp_err_t ret = ESP_OK;
|
||||||
|
app_func_arg_t* ctx = (app_func_arg_t*)arg;
|
||||||
|
ctx->start_flags = flags;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* There are three ways for ESP Flash API lock:
|
* There are three ways for ESP Flash API lock:
|
||||||
* 1. spi bus lock, this is used when SPI1 is shared with GPSPI Master Driver
|
* 1. spi bus lock, this is used when SPI1 is shared with GPSPI Master Driver
|
||||||
@@ -136,13 +146,28 @@ static IRAM_ATTR esp_err_t spi1_start(void *arg)
|
|||||||
}
|
}
|
||||||
#endif // CONFIG_SPI_FLASH_DISABLE_SCHEDULER_IN_SUSPEND
|
#endif // CONFIG_SPI_FLASH_DISABLE_SCHEDULER_IN_SUSPEND
|
||||||
|
|
||||||
on_spi_acquired((app_func_arg_t*)arg);
|
#if CONFIG_SPI_FLASH_FREQ_LIMIT_C5_240MHZ
|
||||||
|
if (flags & ESP_FLASH_START_FLAG_LIMIT_CPU_FREQ) {
|
||||||
|
esp_flash_freq_limit_cb();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
on_spi_acquired(ctx);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static IRAM_ATTR esp_err_t spi1_end(void *arg)
|
static IRAM_ATTR esp_err_t spi1_end(void *arg)
|
||||||
{
|
{
|
||||||
esp_err_t ret = ESP_OK;
|
esp_err_t ret = ESP_OK;
|
||||||
|
app_func_arg_t* ctx = (app_func_arg_t*)arg;
|
||||||
|
|
||||||
|
// Call freq_limit_unlock if needed, before releasing the lock
|
||||||
|
#if CONFIG_SPI_FLASH_FREQ_LIMIT_C5_240MHZ
|
||||||
|
uint32_t flags = ctx->start_flags;
|
||||||
|
if (flags & ESP_FLASH_START_FLAG_LIMIT_CPU_FREQ) {
|
||||||
|
esp_flash_freq_unlimit_cb();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* There are three ways for ESP Flash API lock, see `spi1_start`
|
* There are three ways for ESP Flash API lock, see `spi1_start`
|
||||||
@@ -166,7 +191,7 @@ static IRAM_ATTR esp_err_t spi1_end(void *arg)
|
|||||||
}
|
}
|
||||||
#endif // CONFIG_SPI_FLASH_DISABLE_SCHEDULER_IN_SUSPEND
|
#endif // CONFIG_SPI_FLASH_DISABLE_SCHEDULER_IN_SUSPEND
|
||||||
|
|
||||||
on_spi_released((app_func_arg_t*)arg);
|
on_spi_released(ctx);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
#include "hal/cache_ll.h"
|
#include "hal/cache_ll.h"
|
||||||
#include "soc/soc_caps.h"
|
#include "soc/soc_caps.h"
|
||||||
|
|
||||||
static IRAM_ATTR esp_err_t start(void *arg)
|
static IRAM_ATTR esp_err_t start(void *arg, uint32_t flags)
|
||||||
{
|
{
|
||||||
#if SOC_BRANCH_PREDICTOR_SUPPORTED
|
#if SOC_BRANCH_PREDICTOR_SUPPORTED
|
||||||
//branch predictor will start cache request as well
|
//branch predictor will start cache request as well
|
||||||
|
|||||||
@@ -24,6 +24,15 @@ components/spi_flash/test_apps/esp_flash_blockdev:
|
|||||||
depends_components:
|
depends_components:
|
||||||
- spi_flash
|
- spi_flash
|
||||||
|
|
||||||
|
components/spi_flash/test_apps/esp_flash_freq_limit:
|
||||||
|
enable:
|
||||||
|
- if: IDF_TARGET == "esp32c5"
|
||||||
|
depends_components:
|
||||||
|
- spi_flash
|
||||||
|
- esp_pm
|
||||||
|
- esp_driver_gptimer
|
||||||
|
- esp_hw_support
|
||||||
|
|
||||||
components/spi_flash/test_apps/esp_flash_stress:
|
components/spi_flash/test_apps/esp_flash_stress:
|
||||||
disable:
|
disable:
|
||||||
- if: IDF_TARGET == "esp32h4"
|
- if: IDF_TARGET == "esp32h4"
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
# This is the project CMakeLists.txt file for the test subproject
|
||||||
|
cmake_minimum_required(VERSION 3.22)
|
||||||
|
|
||||||
|
set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/test_apps/components")
|
||||||
|
|
||||||
|
# "Trim" the build. Include the minimal set of components, main, and anything it depends on. We also depend on
|
||||||
|
# esptool_py as we set CONFIG_ESPTOOLPY_... options.
|
||||||
|
set(COMPONENTS main esptool_py)
|
||||||
|
|
||||||
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||||
|
|
||||||
|
project(test_esp_flash_freq_limit)
|
||||||
|
|
||||||
|
message(STATUS "Checking memspi registers are not read-write by half-word")
|
||||||
|
include($ENV{IDF_PATH}/tools/ci/check_register_rw_half_word.cmake)
|
||||||
|
check_register_rw_half_word(SOC_MODULES "spi_mem*" "spi1_mem*"
|
||||||
|
HAL_MODULES "spimem_flash")
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
| Supported Targets | ESP32-C5 |
|
||||||
|
| ----------------- | -------- |
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
set(srcs "test_app_main.c"
|
||||||
|
"test_esp_flash_freq_limit.c")
|
||||||
|
|
||||||
|
# In order for the cases defined by `TEST_CASE` to be linked into the final elf,
|
||||||
|
# the component can be registered as WHOLE_ARCHIVE
|
||||||
|
idf_component_register(SRCS ${srcs}
|
||||||
|
PRIV_REQUIRES unity test_utils spi_flash esp_pm bootloader_support freertos esp_timer
|
||||||
|
esp_driver_gptimer esp_hw_support esp_psram
|
||||||
|
WHOLE_ARCHIVE)
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "unity.h"
|
||||||
|
#include "unity_test_utils.h"
|
||||||
|
|
||||||
|
#define TEST_MEMORY_LEAK_THRESHOLD (700)
|
||||||
|
|
||||||
|
void setUp(void)
|
||||||
|
{
|
||||||
|
unity_utils_record_free_mem();
|
||||||
|
}
|
||||||
|
|
||||||
|
void tearDown(void)
|
||||||
|
{
|
||||||
|
unity_utils_evaluate_leaks_direct(TEST_MEMORY_LEAK_THRESHOLD);
|
||||||
|
}
|
||||||
|
|
||||||
|
void app_main(void)
|
||||||
|
{
|
||||||
|
unity_run_menu();
|
||||||
|
}
|
||||||
+1250
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,5 @@
|
|||||||
|
# Name, Type, SubType, Offset, Size, Flags
|
||||||
|
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
|
||||||
|
nvs, data, nvs, 0x9000, 0x6000,
|
||||||
|
factory, 0, 0, 0x10000, 1M
|
||||||
|
flash_test, data, fat, , 700K
|
||||||
|
@@ -0,0 +1,23 @@
|
|||||||
|
# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
import pytest
|
||||||
|
from pytest_embedded import Dut
|
||||||
|
from pytest_embedded_idf.utils import idf_parametrize
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.generic
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
'config',
|
||||||
|
[
|
||||||
|
'pm_disabled_240mhz',
|
||||||
|
'pm_disabled_160mhz',
|
||||||
|
'pm_enabled_240mhz',
|
||||||
|
'pm_enabled_160mhz',
|
||||||
|
'pm_disabled_240mhz_xip_psram',
|
||||||
|
'pm_enabled_240mhz_xip_psram',
|
||||||
|
],
|
||||||
|
indirect=True,
|
||||||
|
)
|
||||||
|
@idf_parametrize('target', ['esp32c5'], indirect=['target'])
|
||||||
|
def test_esp_flash_freq_limit(dut: Dut) -> None:
|
||||||
|
dut.run_all_single_board_cases(group='esp_flash_freq_limit', timeout=10)
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
CONFIG_PM_ENABLE=n
|
||||||
|
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_160=y
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
CONFIG_PM_ENABLE=n
|
||||||
|
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
CONFIG_PM_ENABLE=n
|
||||||
|
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y
|
||||||
|
CONFIG_ESPTOOLPY_FLASHFREQ_120M=y
|
||||||
|
CONFIG_SPIRAM=y
|
||||||
|
CONFIG_SPIRAM_BOOT_HW_INIT=y
|
||||||
|
CONFIG_SPIRAM_BOOT_INIT=y
|
||||||
|
CONFIG_SPIRAM_XIP_FROM_PSRAM=y
|
||||||
|
CONFIG_SPIRAM_SPEED_120M=y
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
CONFIG_FREERTOS_USE_TICKLESS_IDLE=y
|
||||||
|
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
|
||||||
|
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
|
||||||
|
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
|
||||||
|
CONFIG_PM_ENABLE=y
|
||||||
|
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_160=y
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
CONFIG_FREERTOS_USE_TICKLESS_IDLE=y
|
||||||
|
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
|
||||||
|
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
|
||||||
|
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
|
||||||
|
CONFIG_PM_ENABLE=y
|
||||||
|
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y
|
||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
CONFIG_FREERTOS_USE_TICKLESS_IDLE=y
|
||||||
|
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
|
||||||
|
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
|
||||||
|
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
|
||||||
|
CONFIG_PM_ENABLE=y
|
||||||
|
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y
|
||||||
|
CONFIG_ESPTOOLPY_FLASHFREQ_120M=y
|
||||||
|
CONFIG_SPIRAM=y
|
||||||
|
CONFIG_SPIRAM_BOOT_HW_INIT=y
|
||||||
|
CONFIG_SPIRAM_BOOT_INIT=y
|
||||||
|
CONFIG_SPIRAM_XIP_FROM_PSRAM=y
|
||||||
|
CONFIG_SPIRAM_SPEED_120M=y
|
||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
CONFIG_FREERTOS_USE_TICKLESS_IDLE=y
|
||||||
|
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
|
||||||
|
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
|
||||||
|
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
|
||||||
|
CONFIG_PM_ENABLE=y
|
||||||
|
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y
|
||||||
|
CONFIG_ESPTOOLPY_FLASHFREQ_120M=y
|
||||||
|
CONFIG_SPIRAM=y
|
||||||
|
CONFIG_SPIRAM_BOOT_HW_INIT=y
|
||||||
|
CONFIG_SPIRAM_BOOT_INIT=y
|
||||||
|
CONFIG_SPIRAM_XIP_FROM_PSRAM=y
|
||||||
|
CONFIG_SPIRAM_SPEED_120M=y
|
||||||
|
CONFIG_SPI_FLASH_ROM_IMPL=y
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||||
|
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
||||||
@@ -303,6 +303,7 @@ SPI Flash Driver
|
|||||||
- Deprecated API ``spi_flash_dump_counters`` has been removed. Please use :cpp:func:`esp_flash_dump_counters` instead.
|
- Deprecated API ``spi_flash_dump_counters`` has been removed. Please use :cpp:func:`esp_flash_dump_counters` instead.
|
||||||
- Deprecated API ``spi_flash_get_counters`` has been removed. Please use :cpp:func:`esp_flash_get_counters` instead.
|
- Deprecated API ``spi_flash_get_counters`` has been removed. Please use :cpp:func:`esp_flash_get_counters` instead.
|
||||||
- Deprecated API ``spi_flash_reset_counters`` has been removed. Please use :cpp:func:`esp_flash_reset_counters` instead.
|
- Deprecated API ``spi_flash_reset_counters`` has been removed. Please use :cpp:func:`esp_flash_reset_counters` instead.
|
||||||
|
- New argument ``flags`` is added to ``esp_flash_os_functions_t::start``. Caller and implementer should handle this argument properly.
|
||||||
- Kconfig option ``CONFIG_SPI_FLASH_ROM_DRIVER_PATCH`` has been removed. Considering that this option is unlikely to be widely used by users and may cause serious issues if misused, it has been decided to remove it.
|
- Kconfig option ``CONFIG_SPI_FLASH_ROM_DRIVER_PATCH`` has been removed. Considering that this option is unlikely to be widely used by users and may cause serious issues if misused, it has been decided to remove it.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|||||||
@@ -303,6 +303,7 @@ SPI flash 驱动
|
|||||||
- 已弃用的 API ``spi_flash_dump_counters`` 已被移除。请改用 :cpp:func:`esp_flash_dump_counters`。
|
- 已弃用的 API ``spi_flash_dump_counters`` 已被移除。请改用 :cpp:func:`esp_flash_dump_counters`。
|
||||||
- 已弃用的 API ``spi_flash_get_counters`` 已被移除。请改用 :cpp:func:`esp_flash_get_counters`。
|
- 已弃用的 API ``spi_flash_get_counters`` 已被移除。请改用 :cpp:func:`esp_flash_get_counters`。
|
||||||
- 已弃用的 API ``spi_flash_reset_counters`` 已被移除。请改用 :cpp:func:`esp_flash_reset_counters`。
|
- 已弃用的 API ``spi_flash_reset_counters`` 已被移除。请改用 :cpp:func:`esp_flash_reset_counters`。
|
||||||
|
- ``esp_flash_os_functions_t::start`` 新增了一个参数 ``flags``。调用者和实现者应正确处理此参数。
|
||||||
- Kconfig 选项 ``CONFIG_SPI_FLASH_ROM_DRIVER_PATCH`` 已被移除,考虑到这个选项不会被广泛被用户使用,且有因误用而导致出现严重的问题,遂决定移除。
|
- Kconfig 选项 ``CONFIG_SPI_FLASH_ROM_DRIVER_PATCH`` 已被移除,考虑到这个选项不会被广泛被用户使用,且有因误用而导致出现严重的问题,遂决定移除。
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|||||||
Reference in New Issue
Block a user