mspi: move timing tuning to esp_hw_support

pull/10546/head
Armando 2023-01-05 15:24:08 +08:00
rodzic c55d82d1fa
commit b46cfd15a2
15 zmienionych plików z 107 dodań i 81 usunięć

Wyświetl plik

@ -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

Wyświetl plik

@ -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

Wyświetl plik

@ -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)

Wyświetl plik

@ -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();

Wyświetl plik

@ -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

Wyświetl plik

@ -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
}

Wyświetl plik

@ -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.

Wyświetl plik

@ -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

Wyświetl plik

@ -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();

Wyświetl plik

@ -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()

Wyświetl plik

@ -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

Wyświetl plik

@ -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
*/

Wyświetl plik

@ -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)