diff --git a/components/esp_hw_support/clk_utils.c b/components/esp_hw_support/clk_utils.c index aa17d26ac64..f67d6b810ad 100644 --- a/components/esp_hw_support/clk_utils.c +++ b/components/esp_hw_support/clk_utils.c @@ -7,34 +7,38 @@ #include #include #include +#include #include "sdkconfig.h" #include "esp_check.h" #include "esp_log.h" -#include "soc/soc_caps.h" #include "soc/rtc.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) +#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 CONFIG_IDF_TARGET_ESP32S3 (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 CONFIG_IDF_TARGET_ESP32P4 - (void) target_cpu_src_freq; - /** - * Workaround for ESP32P4, - * f_cpu >= f_mspi +#elif CONFIG_IDF_TARGET_ESP32P4 && 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 (((target_cpu_freq) < CONFIG_ESPTOOLPY_FLASHFREQ_VAL) -#if CONFIG_SPIRAM - || ((target_cpu_freq) < CONFIG_SPIRAM_SPEED) -#endif - ) { + 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 @@ -50,17 +54,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()) { mspi_timing_change_speed_mode_cache_safe(false); } -#elif CONFIG_IDF_TARGET_ESP32P4 - (void) target_cpu_src_freq; - /** - * Workaround for ESP32P4, - * f_cpu >= f_mspi +#elif CONFIG_IDF_TARGET_ESP32P4 && 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 (((target_cpu_freq) >= CONFIG_ESPTOOLPY_FLASHFREQ_VAL) -#if CONFIG_SPIRAM - && ((target_cpu_freq) >= CONFIG_SPIRAM_SPEED) -#endif - ) { + if (!BELOW_FREQ_THRESHOLD(target_cpu_freq)) { mspi_timing_change_speed_mode_cache_safe(false); } #else diff --git a/components/esp_hw_support/include/esp_private/mspi_timing_tuning.h b/components/esp_hw_support/include/esp_private/mspi_timing_tuning.h index c1e999cc181..be59ef7dfb6 100644 --- a/components/esp_hw_support/include/esp_private/mspi_timing_tuning.h +++ b/components/esp_hw_support/include/esp_private/mspi_timing_tuning.h @@ -24,6 +24,12 @@ extern "C" { */ 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. * @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); - #ifdef __cplusplus } #endif diff --git a/components/esp_hw_support/mspi_timing_tuning.c b/components/esp_hw_support/mspi_timing_tuning.c index 946d78f6ec6..2bff3eea155 100644 --- a/components/esp_hw_support/mspi_timing_tuning.c +++ b/components/esp_hw_support/mspi_timing_tuning.c @@ -474,6 +474,11 @@ void mspi_timing_psram_tuning(void) /*------------------------------------------------------------------------------ * 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) { #if SOC_MEMSPI_FLASH_CLK_SRC_IS_INDEPENDENT @@ -497,14 +502,14 @@ void mspi_timing_enter_low_speed_mode(bool control_spi1) * 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 */ - mspi_timing_config_set_flash_clock(20, MSPI_TIMING_SPEED_MODE_LOW_PERF, control_spi1); - mspi_timing_config_set_psram_clock(20, MSPI_TIMING_SPEED_MODE_LOW_PERF, control_spi1); -#endif //#if SOC_SPI_MEM_SUPPORT_TIMING_TUNING - + uint32_t low_speed_freq_mhz = mspi_timing_get_psram_low_speed_freq_mhz(); + mspi_timing_config_set_flash_clock(low_speed_freq_mhz, MSPI_TIMING_SPEED_MODE_LOW_PERF, control_spi1); + 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 mspi_timing_flash_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 SOC_SPI_MEM_SUPPORT_TIMING_TUNING } /** diff --git a/components/spi_flash/esp_flash_api.c b/components/spi_flash/esp_flash_api.c index 69ba6f2b5d3..cd8572871a3 100644 --- a/components/spi_flash/esp_flash_api.c +++ b/components/spi_flash/esp_flash_api.c @@ -148,15 +148,6 @@ static 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"); -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 { esp_err_t (*start)(esp_flash_t *chip); esp_err_t (*end)(esp_flash_t *chip, esp_err_t err); @@ -164,7 +155,22 @@ 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); } rom_spiflash_api_func_t; -#if !CONFIG_SPI_FLASH_ROM_IMPL || ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV +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 +// API funcs case 1: Not using ROM - define our own pointer and all functions +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. DRAM_ATTR static rom_spiflash_api_func_t default_spiflash_rom_api = { .start = spiflash_start_default, @@ -174,17 +180,41 @@ DRAM_ATTR static rom_spiflash_api_func_t default_spiflash_rom_api = { }; DRAM_ATTR rom_spiflash_api_func_t *rom_spiflash_api_funcs = &default_spiflash_rom_api; -#else -extern rom_spiflash_api_func_t *esp_flash_api_funcs; -#define rom_spiflash_api_funcs esp_flash_api_funcs -#endif // !CONFIG_SPI_FLASH_ROM_IMPL || ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV + +#else // CONFIG_SPI_FLASH_ROM_IMPL +// Using ROM implementation + +# if ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV +// API funcs case 2: Using ROM APIs but patch flash_end_flush_cache function +// When ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV, the api_funcs provided by ROM does not have flash_end_flush_cache member. +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); +DRAM_ATTR static rom_spiflash_api_func_t esp_flash_api_funcs_patched; + +// Copy ROM structure to RAM and patch flash_end_flush_cache function +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.flash_end_flush_cache = flash_end_flush_cache; + esp_flash_api_funcs = &esp_flash_api_funcs_patched; +} + +# else +// API funcs case 3: Using All ROM APIs directly +void esp_flash_rom_api_funcs_init(void) +{ + // Do nothing +} + +# endif // ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV +#endif // !CONFIG_SPI_FLASH_ROM_IMPL /* Static function to notify OS of a new SPI flash operation. If returns an error result, caller must abort. If returns ESP_OK, caller must 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 static esp_err_t IRAM_ATTR spiflash_start_default(esp_flash_t *chip) { if (chip->os_func != NULL && chip->os_func->start != NULL) { @@ -224,7 +254,13 @@ static IRAM_ATTR esp_err_t check_chip_pointer_default(esp_flash_t **inout_chip) } return ESP_OK; } +#endif // !CONFIG_SPI_FLASH_ROM_IMPL +#if !CONFIG_SPI_FLASH_ROM_IMPL || ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV +/* ROM and patch information + * Latest: No change + * V1 (!ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV): Added to ROM + */ static IRAM_ATTR esp_err_t flash_end_flush_cache(esp_flash_t* chip, esp_err_t err, bool bus_acquired, uint32_t address, uint32_t length) { if (!bus_acquired) { @@ -731,7 +767,7 @@ esp_err_t IRAM_ATTR esp_flash_erase_region(esp_flash_t *chip, uint32_t start, ui if (len == 0) { return ESP_OK; } - if (len > chip->size - start) { + if (start > chip->size || len > chip->size - start) { return ESP_ERR_INVALID_ARG; } return rom_esp_flash_erase_region(chip, start, len); @@ -744,7 +780,7 @@ esp_err_t IRAM_ATTR esp_flash_erase_region(esp_flash_t *chip, uint32_t start, ui if (err != ESP_OK) { return err; } - if (len > chip->size - start) { + if (start > chip->size || len > chip->size - start) { return ESP_ERR_INVALID_ARG; } return rom_esp_flash_erase_region(chip, start, len); @@ -1501,7 +1537,7 @@ esp_err_t IRAM_ATTR esp_flash_write_encrypted(esp_flash_t *chip, uint32_t addres if (err != ESP_OK) { return err; } - if (length > chip->size - address) { + if (buffer == NULL || address > chip->size || length > chip->size - address) { return ESP_ERR_INVALID_ARG; } return rom_esp_flash_write_encrypted(chip, address, buffer, length); diff --git a/components/spi_flash/esp_flash_spi_init.c b/components/spi_flash/esp_flash_spi_init.c index 1e9eb050bca..41fccd92afe 100644 --- a/components/spi_flash/esp_flash_spi_init.c +++ b/components/spi_flash/esp_flash_spi_init.c @@ -396,6 +396,10 @@ esp_err_t esp_flash_init_default_chip(void) return err; } +#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: to account for chips which are slow to power on, maybe keep probing in a loop here err = esp_flash_init_main(&default_chip); diff --git a/components/spi_flash/include/esp_flash_internal.h b/components/spi_flash/include/esp_flash_internal.h index d07b3e22900..b3a87206bfb 100644 --- a/components/spi_flash/include/esp_flash_internal.h +++ b/components/spi_flash/include/esp_flash_internal.h @@ -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); +#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 } #endif