Files
esp-idf/components/esp_hw_support/clk_utils.c
T
Xiao Xufeng 230ee88d99 feat(spi_flash): implement dynamic CPU frequency switching workaround for encrypted writes
This commit implements a workaround that allows ESP32-C5 to run at 240MHz CPU frequency
normally, while automatically reducing CPU frequency during encrypted flash writes to
ensure correct operation. The frequency limit is chip revision dependent:
- v1.2 and above: limited to 160MHz during encrypted writes
- v1.0 and below: limited to 80MHz during encrypted writes

Key implementation details:
- Frequency limiting is triggered automatically when esp_flash_write_encrypted() is called
- Uses start() flags (ESP_FLASH_START_FLAG_LIMIT_CPU_FREQ) to integrate with OS layer
- Works with both PM enabled and disabled configurations
- Frequency is automatically restored after encrypted write completes
- For ESP32-C5 with 120MHz flash, Flash clock and timing registers are adjusted when
  CPU frequency is reduced to 80MHz
- SPI1 timing registers are configured during frequency switching since encrypted writes
  use SPI1 and must work correctly at reduced CPU frequencies

Code improvements:
- Use SOC_MSPI_FREQ_AXI_CONSTRAINED capability macro instead of hardcoded chip checks
- Control workaround via Kconfig (CONFIG_PM_WORKAROUND_FREQ_LIMIT_ENABLED) instead of
  hardcoded macros
- Add comprehensive test cases covering various PM configurations and edge cases

This workaround enables ESP32-C5 applications to benefit from 240MHz CPU performance
while maintaining reliable encrypted flash write functionality.
2025-12-16 17:42:44 +08:00

76 lines
2.8 KiB
C

/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <sys/param.h>
#include <inttypes.h>
#include <string.h>
#include <assert.h>
#include "sdkconfig.h"
#include "esp_check.h"
#include "esp_log.h"
#include "soc/soc_caps.h"
#include "soc/rtc.h"
#include "hal/mspi_ll.h"
#include "hal/clk_tree_ll.h"
#include "esp_private/mspi_timing_tuning.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)
#elif CONFIG_IDF_TARGET_ESP32S31
#define BELOW_FREQ_THRESHOLD(freq) ((freq) * 4 < CONFIG_SPIRAM_SPEED * 3)
#endif
#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)
{
#if MSPI_TIMING_LL_FLASH_CPU_CLK_SRC_BINDED
(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()) {
mspi_timing_change_speed_mode_cache_safe(true);
}
#elif SOC_SPI_MEM_PSRAM_FREQ_AXI_CONSTRAINED && CONFIG_SPIRAM
/* 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.
*/
if (BELOW_FREQ_THRESHOLD(target_cpu_freq)) {
// Before switching to low speed mode, verify CPU frequency meets the constraint
assert(target_cpu_freq >= mspi_timing_get_psram_low_speed_freq_mhz());
mspi_timing_change_speed_mode_cache_safe(true);
}
#else
(void) target_cpu_src_freq;
(void) target_cpu_freq;
#endif
}
void esp_clk_utils_mspi_speed_mode_sync_after_cpu_freq_switching(uint32_t target_cpu_src_freq, uint32_t target_cpu_freq)
{
#if MSPI_TIMING_LL_FLASH_CPU_CLK_SRC_BINDED
(void) target_cpu_freq;
if (target_cpu_src_freq > clk_ll_xtal_load_freq_mhz()) {
mspi_timing_change_speed_mode_cache_safe(false);
}
#elif SOC_SPI_MEM_PSRAM_FREQ_AXI_CONSTRAINED && CONFIG_SPIRAM
/* 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.
*/
if (!BELOW_FREQ_THRESHOLD(target_cpu_freq)) {
mspi_timing_change_speed_mode_cache_safe(false);
}
#else
(void) target_cpu_src_freq;
(void) target_cpu_freq;
#endif
}
#endif