mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'bugfix/add_support_for_mspi_to_work_with_cpu_clock_switch' into 'master'
mspi: make cpu clock source switch safe Closes IDFCI-902 See merge request espressif/esp-idf!15557
This commit is contained in:
commit
390f71cbcb
@ -21,18 +21,7 @@
|
||||
#include "esp_attr.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
/**
|
||||
* TODO: IDF-3204
|
||||
* Temporarily solution. Depends on MSPI
|
||||
* Final solution: the rtc should not depend on MSPI. We should do rtc related before Flash init
|
||||
*/
|
||||
#include "esp_private/spi_flash_os.h"
|
||||
#include "esp32s3/rom/cache.h"
|
||||
#include "freertos/portmacro.h"
|
||||
portMUX_TYPE rtc_init_spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
|
||||
#endif
|
||||
|
||||
|
||||
#define RTC_CNTL_MEM_FORCE_NOISO (RTC_CNTL_SLOWMEM_FORCE_NOISO | RTC_CNTL_FASTMEM_FORCE_NOISO)
|
||||
@ -248,39 +237,23 @@ static void set_ocode_by_efuse(int calib_version)
|
||||
REGI2C_WRITE_MASK(I2C_ULP, I2C_ULP_IR_FORCE_CODE, 1);
|
||||
}
|
||||
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
//TODO: IDF-3204
|
||||
//Temporary solution, these 2 functions should be defined elsewhere, because similar operations are also needed elsewhere
|
||||
//Final solution: the rtc should not depend on MSPI. We should do rtc related before Flash init
|
||||
static void IRAM_ATTR enter_mspi_low_speed_mode_safe(void)
|
||||
{
|
||||
portENTER_CRITICAL(&rtc_init_spinlock);
|
||||
Cache_Freeze_ICache_Enable(1);
|
||||
Cache_Freeze_DCache_Enable(1);
|
||||
spi_timing_enter_mspi_low_speed_mode(false);
|
||||
Cache_Freeze_DCache_Disable();
|
||||
Cache_Freeze_ICache_Disable();
|
||||
portEXIT_CRITICAL(&rtc_init_spinlock);
|
||||
}
|
||||
|
||||
static void IRAM_ATTR enter_mspi_high_speed_mode_safe(void)
|
||||
{
|
||||
portENTER_CRITICAL(&rtc_init_spinlock);
|
||||
Cache_Freeze_ICache_Enable(1);
|
||||
Cache_Freeze_DCache_Enable(1);
|
||||
spi_timing_enter_mspi_high_speed_mode(false);
|
||||
Cache_Freeze_DCache_Disable();
|
||||
Cache_Freeze_ICache_Disable();
|
||||
portEXIT_CRITICAL(&rtc_init_spinlock);
|
||||
}
|
||||
#endif
|
||||
|
||||
//TODO: IDF-3204
|
||||
//This function will change the system clock source to XTAL. Under lower frequency (e.g. XTAL), MSPI timing tuning configures should be modified accordingly.
|
||||
static void IRAM_ATTR calibrate_ocode(void)
|
||||
/**
|
||||
* TODO: IDF-4141
|
||||
* 1. This function will change the system clock source to XTAL. Under lower frequency (e.g. XTAL), MSPI timing tuning configures should be modified accordingly.
|
||||
* 2. RTC related should be done before SPI0 initialisation
|
||||
*/
|
||||
static void calibrate_ocode(void)
|
||||
{
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
enter_mspi_low_speed_mode_safe();
|
||||
/**
|
||||
* Background:
|
||||
* 1. Following code will switch the system clock to XTAL first, to self-calibrate the OCode.
|
||||
* 2. For some of the MSPI high frequency setting (e.g. 80M DDR mode Flash or PSRAM), timing tuning is required.
|
||||
* Certain delay will be added to the MSPI RX direction.
|
||||
*
|
||||
* When CPU clock switches down, the delay should be cleared. Therefore here we call this function to remove the delays.
|
||||
*/
|
||||
spi_timing_change_speed_mode_cache_safe(true);
|
||||
#endif
|
||||
/*
|
||||
Bandgap output voltage is not precise when calibrate o-code by hardware sometimes, so need software o-code calibration (must turn off PLL).
|
||||
@ -330,6 +303,7 @@ static void IRAM_ATTR calibrate_ocode(void)
|
||||
}
|
||||
rtc_clk_cpu_freq_set_config(&old_config);
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
enter_mspi_high_speed_mode_safe();
|
||||
//System clock is switched back to PLL. Here we switch to the MSPI high speed mode, add the delays back
|
||||
spi_timing_change_speed_mode_cache_safe(false);
|
||||
#endif
|
||||
}
|
||||
|
@ -359,25 +359,20 @@ void spi_timing_config_psram_tune_dummy(uint8_t extra_dummy)
|
||||
|
||||
#endif //#if SPI_TIMING_FLASH_NEEDS_TUNING || SPI_TIMING_PSRAM_NEEDS_TUNING
|
||||
|
||||
static bool spi_timing_config_cs_setup_enable(void)
|
||||
|
||||
/*-------------------------------------------------------------------------------------------------
|
||||
* To let upper lay (spi_flash_timing_tuning.c) to know the necessary timing registers
|
||||
*-------------------------------------------------------------------------------------------------*/
|
||||
static bool s_get_cs_setup_enable(void)
|
||||
{
|
||||
return REG_GET_BIT(SPI_MEM_USER_REG(0), SPI_MEM_CS_SETUP);
|
||||
}
|
||||
|
||||
static bool spi_timing_config_cs_hold_enable(void)
|
||||
static bool s_get_cs_hold_enable(void)
|
||||
{
|
||||
return REG_GET_BIT(SPI_MEM_USER_REG(0), SPI_MEM_CS_HOLD);
|
||||
}
|
||||
|
||||
bool spi_timine_config_flash_is_tuned(void)
|
||||
{
|
||||
#if SPI_TIMING_FLASH_NEEDS_TUNING || SPI_TIMING_PSRAM_NEEDS_TUNING
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the SPI1 Flash CS timing setting. The setup time and hold time are both realistic cycles.
|
||||
* @note On ESP32-S3, SPI0/1 share the Flash CS timing registers. Therefore, we should not change these values.
|
||||
@ -392,12 +387,12 @@ void spi_timing_config_get_cs_timing(uint8_t *setup_time, uint32_t *hold_time)
|
||||
* The logic here is, if setup_en / hold_en is false, then we return the realistic cycle number,
|
||||
* which is 0. If true, then the realistic cycle number is (reg_value + 1)
|
||||
*/
|
||||
if (spi_timing_config_cs_setup_enable()) {
|
||||
if (s_get_cs_setup_enable()) {
|
||||
*setup_time += 1;
|
||||
} else {
|
||||
*setup_time = 0;
|
||||
}
|
||||
if (spi_timing_config_cs_hold_enable()) {
|
||||
if (s_get_cs_hold_enable()) {
|
||||
*hold_time += 1;
|
||||
} else {
|
||||
*hold_time = 0;
|
||||
|
@ -245,7 +245,7 @@ void spi_timing_config_psram_tune_dummy(uint8_t extra_dummy);
|
||||
|
||||
/**
|
||||
* SPI1 register info get APIs. These APIs inform `spi_flash_timing_tuning.c` (driver layer) of the SPI1 flash settings.
|
||||
* In this way, other components (e.g.: esp_flash driver) can get the info from it.
|
||||
* In this way, other components (e.g.: esp_flash driver) can get the info from it (`spi_flash_timing_tuning.c`).
|
||||
*/
|
||||
void spi_timing_config_get_cs_timing(uint8_t *setup_time, uint32_t *hold_time);
|
||||
uint32_t spi_timing_config_get_flash_clock_reg(void);
|
||||
|
@ -296,7 +296,7 @@ esp_err_t esp_flash_init_default_chip(void)
|
||||
|
||||
// For chips need time tuning, get value directely from system here.
|
||||
#if SOC_SPI_MEM_SUPPORT_TIME_TUNING
|
||||
if (spi_timine_config_flash_is_tuned()) {
|
||||
if (spi_timing_is_tuned()) {
|
||||
cfg.using_timing_tuning = 1;
|
||||
spi_timing_get_flash_timing_param(&cfg.timing_reg);
|
||||
}
|
||||
|
@ -45,17 +45,26 @@ extern "C" {
|
||||
esp_err_t spi_flash_init_chip_state(void);
|
||||
|
||||
/**
|
||||
* @brief Make MSPI work under 20Mhz
|
||||
* @brief Make MSPI work under 20Mhz, remove the timing tuning required delays.
|
||||
* @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
|
||||
*/
|
||||
void spi_timing_enter_mspi_low_speed_mode(bool control_spi1);
|
||||
|
||||
/**
|
||||
* @brief Make MSPI work under the frequency as users set
|
||||
* @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
|
||||
*/
|
||||
void spi_timing_enter_mspi_high_speed_mode(bool control_spi1);
|
||||
|
||||
/**
|
||||
* @brief Switch MSPI into low speed mode / high speed mode.
|
||||
* @note This API is cache safe, it will freeze both D$ and I$ and restore them after MSPI is switched
|
||||
* @note For some of the MSPI high frequency settings (e.g. 80M DDR mode Flash or PSRAM), timing tuning is required.
|
||||
* Certain delays will be added to the MSPI RX direction. When CPU clock switches from PLL to XTAL, should call
|
||||
* this API first to enter MSPI low speed mode to remove the delays, and vice versa.
|
||||
*/
|
||||
void spi_timing_change_speed_mode_cache_safe(bool switch_down);
|
||||
|
||||
/**
|
||||
* @brief Tune MSPI flash timing to make it work under high frequency
|
||||
*/
|
||||
@ -90,9 +99,9 @@ esp_err_t esp_flash_init_main(esp_flash_t *chip);
|
||||
void spi_timing_get_flash_timing_param(spi_flash_hal_timing_config_t *out_timing_config);
|
||||
|
||||
/**
|
||||
* @brief Judge if the flash in tuned
|
||||
* @brief Get the knowledge if the MSPI timing is tuned or not
|
||||
*/
|
||||
bool spi_timine_config_flash_is_tuned(void);
|
||||
bool spi_timing_is_tuned(void);
|
||||
|
||||
/**
|
||||
* @brief Set Flash chip specifically required MSPI register settings here
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "soc/soc.h"
|
||||
#if CONFIG_IDF_TARGET_ESP32S3
|
||||
#include "esp32s3/spi_timing_config.h"
|
||||
#include "esp32s3/rom/cache.h"
|
||||
#endif
|
||||
|
||||
#define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(*(arr)))
|
||||
@ -377,6 +378,7 @@ void spi_timing_psram_tuning(void)
|
||||
}
|
||||
#endif //SPI_TIMING_PSRAM_NEEDS_TUNING
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* APIs to make SPI0 (and SPI1) FLASH work for high/low freq
|
||||
*----------------------------------------------------------------------------*/
|
||||
@ -460,9 +462,33 @@ void spi_timing_enter_mspi_high_speed_mode(bool control_spi1)
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Should be only used by SPI1 Flash driver to know the necessary timing registers
|
||||
*/
|
||||
void spi_timing_change_speed_mode_cache_safe(bool switch_down)
|
||||
{
|
||||
Cache_Freeze_ICache_Enable(1);
|
||||
Cache_Freeze_DCache_Enable(1);
|
||||
if (switch_down) {
|
||||
//enter MSPI low speed mode, extra delays should be removed
|
||||
spi_timing_enter_mspi_low_speed_mode(false);
|
||||
} else {
|
||||
//enter MSPI high speed mode, extra delays should be considered
|
||||
spi_timing_enter_mspi_high_speed_mode(false);
|
||||
}
|
||||
Cache_Freeze_DCache_Disable();
|
||||
Cache_Freeze_ICache_Disable();
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* APIs to inform SPI1 Flash driver of necessary timing configurations
|
||||
*----------------------------------------------------------------------------*/
|
||||
bool spi_timing_is_tuned(void)
|
||||
{
|
||||
#if SPI_TIMING_FLASH_NEEDS_TUNING || SPI_TIMING_PSRAM_NEEDS_TUNING
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if SPI_TIMING_FLASH_NEEDS_TUNING || SPI_TIMING_PSRAM_NEEDS_TUNING
|
||||
void spi_timing_get_flash_timing_param(spi_flash_hal_timing_config_t *out_timing_config)
|
||||
{
|
||||
|
@ -17,7 +17,6 @@
|
||||
#include "esp32s3/rom/opi_flash.h"
|
||||
#endif
|
||||
|
||||
const static char *TAG = "SPI0";
|
||||
|
||||
//-----------------------------------------SPI0 PSRAM TEST-----------------------------------------------//
|
||||
#if CONFIG_SPIRAM
|
||||
@ -80,8 +79,7 @@ extern void spi_flash_enable_interrupts_caches_and_other_cpu(void);
|
||||
static DRAM_ATTR uint8_t rd_buf[SPI1_FLASH_TEST_LEN];
|
||||
static DRAM_ATTR uint8_t wr_buf[SPI1_FLASH_TEST_LEN];
|
||||
|
||||
|
||||
static IRAM_ATTR esp_err_t spi1_flash_test(void)
|
||||
static NOINLINE_ATTR IRAM_ATTR esp_err_t spi1_flash_test(void)
|
||||
{
|
||||
printf(DRAM_STR("----------SPI1 Flash Test----------\n"));
|
||||
|
||||
@ -124,7 +122,7 @@ static IRAM_ATTR esp_err_t spi1_flash_test(void)
|
||||
#define SPI0_FLASH_TEST_BUF {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, \
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F}
|
||||
|
||||
uint8_t flash_rd_buf[SPI0_FLASH_TEST_LEN] __attribute__((section (".flash.rodata"))) = SPI0_FLASH_TEST_BUF;
|
||||
static const uint8_t flash_rd_buf[SPI0_FLASH_TEST_LEN] = SPI0_FLASH_TEST_BUF;
|
||||
extern int _flash_rodata_start;
|
||||
extern int _rodata_reserved_end;
|
||||
|
||||
@ -133,7 +131,7 @@ static IRAM_ATTR esp_err_t spi0_flash_test(void)
|
||||
{
|
||||
printf("----------SPI0 Flash Test----------\n");
|
||||
//Check if the flash_rd_buf is in .rodata
|
||||
ESP_RETURN_ON_ERROR(((intptr_t)flash_rd_buf >= (intptr_t)_flash_rodata_start) && ((intptr_t)flash_rd_buf < (intptr_t)_rodata_reserved_end), TAG, "psram_rd_buf not in rodata");
|
||||
assert(((intptr_t)flash_rd_buf >= (intptr_t)&_flash_rodata_start) && ((intptr_t)flash_rd_buf < (intptr_t)&_rodata_reserved_end));
|
||||
|
||||
uint8_t cmp_buf[SPI0_FLASH_TEST_LEN] = SPI0_FLASH_TEST_BUF;
|
||||
|
||||
|
@ -0,0 +1,9 @@
|
||||
# Legacy, F4R4, Flash 120M SDR, PSRAM disable, compiler -Os and silent
|
||||
|
||||
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
|
||||
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
|
||||
|
||||
CONFIG_SPI_FLASH_USE_LEGACY_IMPL=y
|
||||
CONFIG_ESPTOOLPY_FLASHFREQ_120M=y
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
Loading…
x
Reference in New Issue
Block a user