mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
mspi: move timing tuning to esp_hw_support
This commit is contained in:
parent
c55d82d1fa
commit
b46cfd15a2
@ -74,6 +74,11 @@ if(NOT BOOTLOADER_BUILD)
|
||||
if(CONFIG_SOC_MODEM_CLOCK_IS_INDEPENDENT)
|
||||
list(APPEND srcs "modem_clock.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SOC_MEMSPI_SRC_FREQ_120M)
|
||||
list(APPEND srcs "mspi_timing_tuning.c" "port/${target}/mspi_timing_config.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_IDF_TARGET_ESP32H2)
|
||||
list(REMOVE_ITEM srcs
|
||||
"adc_share_hw_ctrl.c" # TODO: IDF-6215
|
||||
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* This file is for MSPI timinig tuning private APIs
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @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 mspi_timing_enter_low_speed_mode(bool control_spi1);
|
||||
|
||||
/**
|
||||
* @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 mspi_timing_enter_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 mspi_timing_change_speed_mode_cache_safe(bool switch_down);
|
||||
|
||||
/**
|
||||
* @brief Tune MSPI flash timing to make it work under high frequency
|
||||
*/
|
||||
void mspi_timing_flash_tuning(void);
|
||||
|
||||
/**
|
||||
* @brief Tune MSPI psram timing to make it work under high frequency
|
||||
*/
|
||||
void mspi_timing_psram_tuning(void);
|
||||
|
||||
/**
|
||||
* @brief Set MSPI pin default pin drive
|
||||
*/
|
||||
void mspi_timing_set_pin_drive_strength(void);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -32,3 +32,6 @@ entries:
|
||||
gdma: gdma_reset (noflash)
|
||||
if SOC_SYSTIMER_SUPPORTED = y:
|
||||
systimer (noflash)
|
||||
if SOC_MEMSPI_SRC_FREQ_120M = y:
|
||||
mspi_timing_tuning (noflash)
|
||||
mspi_timing_config (noflash)
|
||||
|
@ -13,10 +13,11 @@
|
||||
#include "esp_log.h"
|
||||
#include "soc/spi_mem_reg.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "esp_private/spi_flash_os.h"
|
||||
#include "esp_private/mspi_timing_tuning.h"
|
||||
#include "soc/soc.h"
|
||||
#include "hal/spi_flash_hal.h"
|
||||
#if CONFIG_IDF_TARGET_ESP32S3
|
||||
#include "esp32s3/spi_timing_config.h"
|
||||
#include "port/esp32s3/mspi_timing_config.h"
|
||||
#include "esp32s3/rom/cache.h"
|
||||
#endif
|
||||
|
||||
@ -31,7 +32,7 @@ static spi_timing_tuning_param_t s_psram_best_timing_tuning_config;
|
||||
/*------------------------------------------------------------------------------
|
||||
* Common settings
|
||||
*----------------------------------------------------------------------------*/
|
||||
void spi_timing_set_pin_drive_strength(void)
|
||||
void mspi_timing_set_pin_drive_strength(void)
|
||||
{
|
||||
//For now, set them all to 3. Need to check after QVL test results are out. TODO: IDF-3663
|
||||
//Set default clk
|
||||
@ -297,13 +298,13 @@ static void get_flash_tuning_configs(spi_timing_config_t *config)
|
||||
#undef FLASH_MODE
|
||||
}
|
||||
|
||||
void spi_timing_flash_tuning(void)
|
||||
void mspi_timing_flash_tuning(void)
|
||||
{
|
||||
/**
|
||||
* set SPI01 related regs to 20mhz configuration, to get reference data from FLASH
|
||||
* see detailed comments in this function (`spi_timing_enter_mspi_low_speed_mode`)
|
||||
* see detailed comments in this function (`mspi_timing_enter_low_speed_mode`)
|
||||
*/
|
||||
spi_timing_enter_mspi_low_speed_mode(true);
|
||||
mspi_timing_enter_low_speed_mode(true);
|
||||
|
||||
//Disable the variable dummy mode when doing timing tuning
|
||||
CLEAR_PERI_REG_MASK(SPI_MEM_DDR_REG(1), SPI_MEM_SPI_FMEM_VAR_DUMMY); //GD flash will read error in variable mode with 20MHz
|
||||
@ -314,10 +315,10 @@ void spi_timing_flash_tuning(void)
|
||||
get_flash_tuning_configs(&timing_configs);
|
||||
|
||||
do_tuning(reference_data, &timing_configs, true);
|
||||
spi_timing_enter_mspi_high_speed_mode(true);
|
||||
mspi_timing_enter_high_speed_mode(true);
|
||||
}
|
||||
#else
|
||||
void spi_timing_flash_tuning(void)
|
||||
void mspi_timing_flash_tuning(void)
|
||||
{
|
||||
//Empty function for compatibility, therefore upper layer won't need to know that FLASH in which operation mode and frequency config needs to be tuned
|
||||
}
|
||||
@ -347,13 +348,13 @@ static void get_psram_tuning_configs(spi_timing_config_t *config)
|
||||
#undef PSRAM_MODE
|
||||
}
|
||||
|
||||
void spi_timing_psram_tuning(void)
|
||||
void mspi_timing_psram_tuning(void)
|
||||
{
|
||||
/**
|
||||
* set SPI01 related regs to 20mhz configuration, to write reference data to PSRAM
|
||||
* see detailed comments in this function (`spi_timing_enter_mspi_low_speed_mode`)
|
||||
* see detailed comments in this function (`mspi_timing_enter_low_speed_mode`)
|
||||
*/
|
||||
spi_timing_enter_mspi_low_speed_mode(true);
|
||||
mspi_timing_enter_low_speed_mode(true);
|
||||
|
||||
// write data into psram, used to do timing tuning test.
|
||||
uint8_t reference_data[SPI_TIMING_TEST_DATA_LEN];
|
||||
@ -368,11 +369,11 @@ void spi_timing_psram_tuning(void)
|
||||
CLEAR_PERI_REG_MASK(SPI_MEM_DDR_REG(1), SPI_MEM_SPI_FMEM_VAR_DUMMY);
|
||||
//Get required config, and set them to PSRAM related registers
|
||||
do_tuning(reference_data, &timing_configs, false);
|
||||
spi_timing_enter_mspi_high_speed_mode(true);
|
||||
mspi_timing_enter_high_speed_mode(true);
|
||||
}
|
||||
|
||||
#else
|
||||
void spi_timing_psram_tuning(void)
|
||||
void mspi_timing_psram_tuning(void)
|
||||
{
|
||||
//Empty function for compatibility, therefore upper layer won't need to know that FLASH in which operation mode and frequency config needs to be tuned
|
||||
}
|
||||
@ -398,7 +399,7 @@ static void clear_timing_tuning_regs(bool control_spi1)
|
||||
}
|
||||
#endif //#if SPI_TIMING_FLASH_NEEDS_TUNING || SPI_TIMING_PSRAM_NEEDS_TUNING
|
||||
|
||||
void spi_timing_enter_mspi_low_speed_mode(bool control_spi1)
|
||||
void mspi_timing_enter_low_speed_mode(bool control_spi1)
|
||||
{
|
||||
/**
|
||||
* Here we are going to slow the SPI1 frequency to 20Mhz, so we need to set SPI1 din_num and din_mode regs.
|
||||
@ -445,9 +446,9 @@ static void set_timing_tuning_regs_as_required(bool control_spi1)
|
||||
* according to the configuration got from timing tuning function (`calculate_best_flash_tuning_config`).
|
||||
* iF control_spi1 == 1, will also update SPI1 timing registers. Should only be set to 1 when do tuning.
|
||||
*
|
||||
* This function should always be called after `spi_timing_flash_tuning` or `calculate_best_flash_tuning_config`
|
||||
* This function should always be called after `mspi_timing_flash_tuning` or `calculate_best_flash_tuning_config`
|
||||
*/
|
||||
void spi_timing_enter_mspi_high_speed_mode(bool control_spi1)
|
||||
void mspi_timing_enter_high_speed_mode(bool control_spi1)
|
||||
{
|
||||
spi_timing_config_core_clock_t core_clock = get_mspi_core_clock();
|
||||
uint32_t flash_div = get_flash_clock_divider();
|
||||
@ -468,16 +469,16 @@ void spi_timing_enter_mspi_high_speed_mode(bool control_spi1)
|
||||
#endif
|
||||
}
|
||||
|
||||
void spi_timing_change_speed_mode_cache_safe(bool switch_down)
|
||||
void mspi_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);
|
||||
mspi_timing_enter_low_speed_mode(false);
|
||||
} else {
|
||||
//enter MSPI high speed mode, extra delays should be considered
|
||||
spi_timing_enter_mspi_high_speed_mode(false);
|
||||
mspi_timing_enter_high_speed_mode(false);
|
||||
}
|
||||
Cache_Freeze_DCache_Disable();
|
||||
Cache_Freeze_ICache_Disable();
|
@ -12,8 +12,7 @@
|
||||
#include "esp_types.h"
|
||||
#include "esp_log.h"
|
||||
#include "soc/spi_mem_reg.h"
|
||||
#include "spi_timing_config.h"
|
||||
#include "esp_private/spi_flash_os.h"
|
||||
#include "mspi_timing_config.h"
|
||||
#include "bootloader_flash.h"
|
||||
|
||||
#define OPI_PSRAM_SYNC_READ 0x0000
|
@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/param.h>
|
||||
#include "soc/soc.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
@ -21,7 +22,7 @@
|
||||
#include "esp_hw_log.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_private/spi_flash_os.h"
|
||||
#include "esp_private/mspi_timing_tuning.h"
|
||||
#include "hal/efuse_hal.h"
|
||||
#include "hal/efuse_ll.h"
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
@ -260,7 +261,7 @@ static void calibrate_ocode(void)
|
||||
*
|
||||
* 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);
|
||||
mspi_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).
|
||||
@ -309,7 +310,7 @@ static void calibrate_ocode(void)
|
||||
rtc_clk_cpu_freq_set_config(&old_config);
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
//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);
|
||||
mspi_timing_change_speed_mode_cache_safe(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "soc/syscon_reg.h"
|
||||
#include "esp_private/spi_flash_os.h"
|
||||
#include "esp_private/mspi_timing_tuning.h"
|
||||
|
||||
#define OPI_PSRAM_SYNC_READ 0x0000
|
||||
#define OPI_PSRAM_SYNC_WRITE 0x8080
|
||||
@ -295,7 +296,7 @@ esp_err_t esp_psram_impl_enable(psram_vaddr_mode_t vaddrmode)
|
||||
s_configure_psram_ecc();
|
||||
|
||||
//enter MSPI slow mode to init PSRAM device registers
|
||||
spi_timing_enter_mspi_low_speed_mode(true);
|
||||
mspi_timing_enter_low_speed_mode(true);
|
||||
|
||||
//set to variable dummy mode
|
||||
SET_PERI_REG_MASK(SPI_MEM_DDR_REG(1), SPI_MEM_SPI_FMEM_VAR_DUMMY);
|
||||
@ -322,9 +323,9 @@ esp_err_t esp_psram_impl_enable(psram_vaddr_mode_t vaddrmode)
|
||||
mode_reg.mr2.density == 0x7 ? PSRAM_SIZE_32MB : 0;
|
||||
|
||||
//Do PSRAM timing tuning, we use SPI1 to do the tuning, and set the SPI0 PSRAM timing related registers accordingly
|
||||
spi_timing_psram_tuning();
|
||||
mspi_timing_psram_tuning();
|
||||
//Back to the high speed mode. Flash/PSRAM clocks are set to the clock that user selected. SPI0/1 registers are all set correctly
|
||||
spi_timing_enter_mspi_high_speed_mode(true);
|
||||
mspi_timing_enter_high_speed_mode(true);
|
||||
|
||||
/**
|
||||
* Tuning may change SPI1 regs, whereas legacy spi_flash APIs rely on these regs.
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "esp_rom_efuse.h"
|
||||
#include "hal/gpio_hal.h"
|
||||
#include "esp_private/spi_flash_os.h"
|
||||
#include "esp_private/mspi_timing_tuning.h"
|
||||
|
||||
static const char* TAG = "quad_psram";
|
||||
|
||||
@ -303,7 +304,7 @@ esp_err_t esp_psram_impl_enable(psram_vaddr_mode_t vaddrmode) //psram init
|
||||
psram_set_cs_timing();
|
||||
|
||||
//enter MSPI slow mode to init PSRAM device registers
|
||||
spi_timing_enter_mspi_low_speed_mode(true);
|
||||
mspi_timing_enter_low_speed_mode(true);
|
||||
|
||||
//We use SPI1 to init PSRAM
|
||||
psram_disable_qio_mode(SPI1_NUM);
|
||||
@ -335,12 +336,12 @@ esp_err_t esp_psram_impl_enable(psram_vaddr_mode_t vaddrmode) //psram init
|
||||
psram_enable_qio_mode(SPI1_NUM);
|
||||
|
||||
//Do PSRAM timing tuning, we use SPI1 to do the tuning, and set the SPI0 PSRAM timing related registers accordingly
|
||||
spi_timing_psram_tuning();
|
||||
mspi_timing_psram_tuning();
|
||||
|
||||
//Configure SPI0 PSRAM related SPI Phases
|
||||
config_psram_spi_phases();
|
||||
//Back to the high speed mode. Flash/PSRAM clocks are set to the clock that user selected. SPI0/1 registers are all set correctly
|
||||
spi_timing_enter_mspi_high_speed_mode(true);
|
||||
mspi_timing_enter_high_speed_mode(true);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -364,7 +365,7 @@ static void config_psram_spi_phases(void)
|
||||
//Dummy
|
||||
/**
|
||||
* We set the PSRAM chip required dummy here. If timing tuning is needed,
|
||||
* the dummy length will be updated in `spi_timing_enter_mspi_high_speed_mode()`
|
||||
* the dummy length will be updated in `mspi_timing_enter_high_speed_mode()`
|
||||
*/
|
||||
SET_PERI_REG_MASK(SPI_MEM_CACHE_SCTRL_REG(0), SPI_MEM_USR_RD_SRAM_DUMMY_M); //enable cache read dummy
|
||||
SET_PERI_REG_BITS(SPI_MEM_CACHE_SCTRL_REG(0), SPI_MEM_SRAM_RDUMMY_CYCLELEN_V, (PSRAM_FAST_READ_QUAD_DUMMY - 1), SPI_MEM_SRAM_RDUMMY_CYCLELEN_S); //dummy
|
||||
|
@ -74,6 +74,7 @@
|
||||
#endif
|
||||
|
||||
#include "esp_private/spi_flash_os.h"
|
||||
#include "esp_private/mspi_timing_tuning.h"
|
||||
#include "bootloader_flash_config.h"
|
||||
#include "bootloader_flash.h"
|
||||
#include "esp_private/crosscore_int.h"
|
||||
@ -386,9 +387,8 @@ void IRAM_ATTR call_start_cpu0(void)
|
||||
* In this stage, we re-configure the Flash (and MSPI) to required configuration
|
||||
*/
|
||||
spi_flash_init_chip_state();
|
||||
#if CONFIG_IDF_TARGET_ESP32S3
|
||||
//On other chips, this feature is not provided by HW, or hasn't been tested yet.
|
||||
spi_timing_flash_tuning();
|
||||
#if SOC_MEMSPI_SRC_FREQ_120M
|
||||
mspi_timing_flash_tuning();
|
||||
#endif
|
||||
|
||||
bootloader_init_mem();
|
||||
|
@ -22,8 +22,6 @@ else()
|
||||
|
||||
if(CONFIG_IDF_TARGET_ESP32S3)
|
||||
list(APPEND srcs
|
||||
"esp32s3/spi_timing_config.c"
|
||||
"spi_flash_timing_tuning.c"
|
||||
"spi_flash_hpm_enable.c")
|
||||
endif()
|
||||
|
||||
|
@ -45,6 +45,7 @@
|
||||
#endif
|
||||
#include "esp_rom_spiflash.h"
|
||||
#include "esp_flash_partitions.h"
|
||||
#include "esp_private/mspi_timing_tuning.h"
|
||||
#include "esp_private/cache_utils.h"
|
||||
#include "esp_flash.h"
|
||||
#include "esp_attr.h"
|
||||
@ -163,8 +164,7 @@ void IRAM_ATTR esp_mspi_pin_init(void)
|
||||
|
||||
if (octal_mspi_required) {
|
||||
esp_rom_opiflash_pin_config();
|
||||
extern void spi_timing_set_pin_drive_strength(void);
|
||||
spi_timing_set_pin_drive_strength();
|
||||
mspi_timing_set_pin_drive_strength();
|
||||
}
|
||||
//Set F4R4 board pin drive strength. TODO: IDF-3663
|
||||
#endif
|
||||
|
@ -7,16 +7,6 @@
|
||||
/**
|
||||
* System level MSPI APIs (private)
|
||||
*/
|
||||
/**
|
||||
* Currently the MSPI timing tuning related APIs are designed to be private.
|
||||
* Because:
|
||||
* 1. now we don't split SPI0 and SPI1, we don't have a component for SPI0, including PSRAM, Cache, etc..
|
||||
* 2. SPI0 and SPI1 are strongly coupling.
|
||||
*
|
||||
* In the future, we may consider creating a component for SPI0, and spi_flash component will only work on SPI1 (and it
|
||||
* can rely on SPI0). Therefore, we can put these APIs there.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
@ -58,37 +48,6 @@ typedef enum {
|
||||
*/
|
||||
esp_err_t spi_flash_init_chip_state(void);
|
||||
|
||||
/**
|
||||
* @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, 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
|
||||
*/
|
||||
void spi_timing_flash_tuning(void);
|
||||
|
||||
/**
|
||||
* @brief Tune MSPI psram timing to make it work under high frequency
|
||||
*/
|
||||
void spi_timing_psram_tuning(void);
|
||||
|
||||
/**
|
||||
* @brief To initislize the MSPI pins
|
||||
*/
|
||||
|
@ -12,8 +12,6 @@ entries:
|
||||
flash_brownout_hook (noflash)
|
||||
|
||||
if IDF_TARGET_ESP32S3 = y:
|
||||
spi_flash_timing_tuning (noflash)
|
||||
spi_timing_config (noflash)
|
||||
spi_flash_chip_mxic_opi (noflash)
|
||||
spi_flash_hpm_enable (noflash)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user