mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
mspi: make cpu clock source switch safe
For some of the MSPI high frequency setting (e.g. 80M DDR mode Flash or PSRAM), timing tuning is required. Certain delays will be added to the MSPI RX direction. When system clock switches down, the delays should be cleared. When system clock switches up, the delays should be restored.
This commit is contained in:
parent
7c3a37977f
commit
c331c85318
@ -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