feat(mspi): supported flash 120MHz SDR timing tuning on ESP32P4

This commit is contained in:
Armando 2024-11-19 11:32:59 +08:00
parent 8eeb3e2055
commit 1eef2e8c19
21 changed files with 898 additions and 70 deletions

View File

@ -136,6 +136,9 @@ if(NOT non_os_build)
if(CONFIG_SOC_MEMSPI_TIMING_TUNING_BY_DQS)
list(APPEND srcs "mspi_timing_by_dqs.c")
endif()
if(CONFIG_SOC_MEMSPI_TIMING_TUNING_BY_FLASH_DELAY)
list(APPEND srcs "mspi_timing_by_flash_delay.c")
endif()
endif()
if(CONFIG_SOC_RTC_FAST_MEM_SUPPORTED AND CONFIG_ESP_ROM_SUPPORT_DEEP_SLEEP_WAKEUP_STUB)

View File

@ -42,6 +42,9 @@ entries:
mspi_timing_config (noflash)
if SOC_MEMSPI_TIMING_TUNING_BY_DQS = y:
mspi_timing_by_dqs (noflash)
if SOC_MEMSPI_TIMING_TUNING_BY_FLASH_DELAY = y:
mspi_timing_by_flash_delay (noflash)
if SOC_MEMSPI_TIMING_TUNING_BY_DQS = y || SOC_MEMSPI_TIMING_TUNING_BY_FLASH_DELAY = y:
mspi_timing_config (noflash)
if SOC_ADC_SHARED_POWER = y:
if ADC_ONESHOT_CTRL_FUNC_IN_IRAM = y:

View File

@ -223,15 +223,3 @@ void mspi_timing_psram_config_set_tuning_regs(bool control_both_mspi)
}
}
}
void mspi_timing_flash_config_set_tuning_regs(bool control_both_mspi)
{
//no need for now, may need set drvs
//keep for compatibility
}
void mspi_timing_flash_config_clear_tuning_regs(bool control_both_mspi)
{
//no need for now, may need clear drvs
//keep for compatibility
}

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -14,6 +14,7 @@
#include <stdint.h>
#include "soc/soc_caps.h"
#if SOC_MEMSPI_TIMING_TUNING_BY_DQS
#include "mspi_timing_types.h"
#include "mspi_timing_tuning_configs.h"
#include "hal/mspi_timing_tuning_ll.h"
#endif
@ -28,26 +29,6 @@ extern "C" {
#define IS_SDR (!IS_DDR)
/**
* Delayline
*/
typedef struct {
uint8_t data_delayline;
uint8_t dqs_delayline;
} __attribute__((packed)) delayline_config_t;
/**
* MSPI timing tuning configurations
*/
typedef struct {
mspi_ll_dqs_phase_t phase[MSPI_LL_DQS_PHASE_MAX];
delayline_config_t delayline_table[MSPI_TIMING_CONFIG_NUM_MAX];
union {
uint32_t available_config_num;
uint32_t available_phase_num;
};
} mspi_timing_config_t;
/*-------------------------------------------------------------------------------------------------
* Timing Required APIs
*-------------------------------------------------------------------------------------------------*/

View File

@ -0,0 +1,226 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @brief
*
* This file contains configuration APIs doing MSPI timing tuning by Flash delay
* This file will only be built when `SOC_MEMSPI_TIMING_TUNING_BY_FLASH_DELAY == 1`
*/
#include <stdint.h>
#include <string.h>
#include <sys/param.h>
#include "sdkconfig.h"
#include "esp_attr.h"
#include "esp_err.h"
#include "esp_types.h"
#include "esp_log.h"
#include "mspi_timing_by_flash_delay.h"
#include "mspi_timing_tuning_configs.h"
#include "esp_private/mspi_timing_config.h"
#include "hal/mspi_timing_tuning_ll.h"
#include "rom/spi_flash.h"
const static char *TAG = "Flash Delay";
void mspi_timing_flash_init(uint32_t flash_freq_mhz)
{
mspi_timing_config_set_flash_clock(flash_freq_mhz, MSPI_TIMING_SPEED_MODE_NORMAL_PERF, true);
//Power on HCLK
mspi_timinng_ll_enable_flash_timing_adjust_clk(MSPI_TIMING_LL_MSPI_ID_0);
ESP_EARLY_LOGD(TAG, "init rom dummy val: %d", g_rom_spiflash_dummy_len_plus[1]);
}
//-------------------------------------FLASH timing tuning register config-------------------------------------//
void mspi_timing_get_flash_tuning_configs(mspi_timing_config_t *config)
{
#if CONFIG_ESPTOOLPY_FLASHFREQ_120M
*config = MSPI_TIMING_FLASH_GET_TUNING_CONFIG(MSPI_TIMING_FLASH_CORE_CLOCK_MHZ, 120, STR_MODE);
#else
assert(false && "should never reach here");
#endif
}
static void s_set_flash_din_mode_num(uint8_t spi_num, uint8_t din_mode, uint8_t din_num)
{
mspi_timing_ll_set_flash_din_mode(spi_num, din_mode);
mspi_timing_ll_set_flash_din_num(spi_num, din_num);
}
static void s_set_flash_extra_dummy(uint8_t spi_num, uint8_t extra_dummy)
{
mspi_timing_ll_set_flash_extra_dummy(spi_num, extra_dummy);
}
void mspi_timing_config_flash_set_tuning_regs(const void *configs, uint8_t id)
{
const mspi_timing_tuning_param_t *params = &((mspi_timing_config_t *)configs)->tuning_config_table[id];
/**
* 1. SPI_MEM_DINx_MODE(1), SPI_MEM_DINx_NUM(1) are meaningless
* SPI0 and SPI1 share the SPI_MEM_DINx_MODE(0), SPI_MEM_DINx_NUM(0) for FLASH timing tuning
* 2. We use SPI1 to get the best Flash timing tuning (mode and num) config
*/
s_set_flash_din_mode_num(MSPI_TIMING_LL_MSPI_ID_0, params->spi_din_mode, params->spi_din_num);
s_set_flash_extra_dummy(MSPI_TIMING_LL_MSPI_ID_1, params->extra_dummy_len);
}
//-------------------------------------------FLASH Read/Write------------------------------------------//
void mspi_timing_config_flash_read_data(uint8_t *buf, uint32_t addr, uint32_t len)
{
#if CONFIG_ESPTOOLPY_FLASHMODE_QIO
g_rom_spiflash_dummy_len_plus[1] = 4;
#endif
esp_rom_spiflash_read(addr, (uint32_t *)buf, len);
int spi1_usr_dummy = 0;
int spi1_extra_dummy = 0;
int spi0_usr_dummy = 0;
int spi0_extra_dummy = 0;
mspi_timing_ll_get_flash_dummy(MSPI_TIMING_LL_MSPI_ID_0, &spi0_usr_dummy, &spi0_extra_dummy);
mspi_timing_ll_get_flash_dummy(MSPI_TIMING_LL_MSPI_ID_1, &spi1_usr_dummy, &spi1_extra_dummy);
ESP_EARLY_LOGD(TAG, "spi0_usr_dummy: %d, spi0_extra_dummy: %d, spi1_usr_dummy: %d, spi1_extra_dummy: %d", spi0_usr_dummy, spi0_extra_dummy, spi1_usr_dummy, spi1_extra_dummy);
}
/*-------------------------------------------------------------------------------------------------
* Best Timing Tuning Params Selection
*-------------------------------------------------------------------------------------------------*/
static uint32_t s_select_best_tuning_config_str(const mspi_timing_config_t *configs, uint32_t consecutive_length, uint32_t end)
{
//STR best point scheme
uint32_t best_point;
if (consecutive_length < 3) {
//tuning fails, select default point, and generate a warning
best_point = configs->flash_default_config_id;
ESP_EARLY_LOGW(TAG, "tuning fail, best point is fallen back to index %"PRIu32"", best_point);
} else {
best_point = end - consecutive_length / 2;
ESP_EARLY_LOGI(TAG, "tuning success, best point is index %"PRIu32"", best_point);
}
return best_point;
}
static uint32_t s_select_best_tuning_config(const mspi_timing_config_t *configs, uint32_t consecutive_length, uint32_t end, const uint8_t *reference_data, bool is_ddr, bool is_flash)
{
uint32_t best_point = 0;
if (is_ddr) {
assert(false);
} else {
best_point = s_select_best_tuning_config_str(configs, consecutive_length, end);
}
return best_point;
}
uint32_t mspi_timing_flash_select_best_tuning_config(const void *configs, uint32_t consecutive_length, uint32_t end, const uint8_t *reference_data, bool is_ddr)
{
const mspi_timing_config_t *timing_configs = (const mspi_timing_config_t *)configs;
uint32_t best_point = s_select_best_tuning_config(timing_configs, consecutive_length, end, reference_data, is_ddr, true);
ESP_EARLY_LOGI(TAG, "Flash timing tuning index: %"PRIu32"", best_point);
return best_point;
}
static mspi_timing_tuning_param_t s_flash_best_timing_tuning_config;
static mspi_timing_tuning_param_t s_psram_best_timing_tuning_config;
void mspi_timing_flash_set_best_tuning_config(const void *configs, uint8_t best_id)
{
s_flash_best_timing_tuning_config = ((const mspi_timing_config_t *)configs)->tuning_config_table[best_id];
}
void mspi_timing_psram_set_best_tuning_config(const void *configs, uint8_t best_id)
{
s_psram_best_timing_tuning_config = ((const mspi_timing_config_t *)configs)->tuning_config_table[best_id];
}
/*-------------------------------------------------------------------------------------------------
* Best Timing Tuning Params Clear / Set
*-------------------------------------------------------------------------------------------------*/
void mspi_timing_flash_config_clear_tuning_regs(bool control_both_mspi)
{
s_set_flash_din_mode_num(MSPI_TIMING_LL_MSPI_ID_0, 0, 0); //SPI0 and SPI1 share the registers for flash din mode and num setting, so we only set SPI0's reg
s_set_flash_extra_dummy(MSPI_TIMING_LL_MSPI_ID_0, 0);
//Won't touch SPI1 registers if not control_both_mspi
if (control_both_mspi) {
s_set_flash_extra_dummy(MSPI_TIMING_LL_MSPI_ID_1, 0);
}
}
void mspi_timing_flash_config_set_tuning_regs(bool control_both_mspi)
{
//SPI0 and SPI1 share the registers for flash din mode and num setting, so we only set SPI0's reg
s_set_flash_din_mode_num(MSPI_TIMING_LL_MSPI_ID_0, s_flash_best_timing_tuning_config.spi_din_mode, s_flash_best_timing_tuning_config.spi_din_num);
s_set_flash_extra_dummy(0, s_flash_best_timing_tuning_config.extra_dummy_len);
if (control_both_mspi) {
s_set_flash_extra_dummy(MSPI_TIMING_LL_MSPI_ID_1, s_flash_best_timing_tuning_config.extra_dummy_len);
} else {
//Won't touch SPI1 registers
}
#if CONFIG_ESPTOOLPY_FLASHMODE_QIO
mspi_timing_ll_set_flash_user_dummy(MSPI_TIMING_LL_MSPI_ID_0, 7);
#endif
int spi1_usr_dummy = 0;
int spi1_extra_dummy = 0;
int spi0_usr_dummy = 0;
int spi0_extra_dummy = 0;
mspi_timing_ll_get_flash_dummy(MSPI_TIMING_LL_MSPI_ID_0, &spi0_usr_dummy, &spi0_extra_dummy);
mspi_timing_ll_get_flash_dummy(MSPI_TIMING_LL_MSPI_ID_1, &spi1_usr_dummy, &spi1_extra_dummy);
ESP_EARLY_LOGD(TAG, "spi0_usr_dummy: %d, spi0_extra_dummy: %d, spi1_usr_dummy: %d, spi1_extra_dummy: %d", spi0_usr_dummy, spi0_extra_dummy, spi1_usr_dummy, spi1_extra_dummy);
}
/*-------------------------------------------------------------------------------------------------
* To let upper lay (spi_flash_timing_tuning.c) to know the necessary timing registers
*-------------------------------------------------------------------------------------------------*/
/**
* Get the SPI1 Flash CS timing setting. The setup time and hold time are both realistic cycles.
* @note On ESP32-P4, SPI0/1 share the Flash CS timing registers. Therefore, we should not change these values.
* @note This function inform `spi_flash_timing_tuning.c` (driver layer) of the cycle,
* and other component (esp_flash driver) should get these cycle and configure the registers accordingly.
*/
void mspi_timing_config_get_cs_timing(uint8_t *setup_time, uint32_t *hold_time)
{
*setup_time = mspi_timing_ll_get_cs_setup_val(MSPI_TIMING_LL_MSPI_ID_0);
*hold_time = mspi_timing_ll_get_cs_hold_val(MSPI_TIMING_LL_MSPI_ID_0);
/**
* 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 (mspi_timing_ll_is_cs_setup_enabled(MSPI_TIMING_LL_MSPI_ID_0)) {
*setup_time += 1;
} else {
*setup_time = 0;
}
if (mspi_timing_ll_is_cs_hold_enabled(MSPI_TIMING_LL_MSPI_ID_0)) {
*hold_time += 1;
} else {
*hold_time = 0;
}
}
/**
* Get the SPI1 Flash clock setting.
* @note Similarly, this function inform `spi_flash_timing_tuning.c` (driver layer) of the clock setting,
* and other component (esp_flash driver) should get these and configure the registers accordingly.
*/
uint32_t mspi_timing_config_get_flash_clock_reg(void)
{
return mspi_timing_ll_get_clock_reg(MSPI_TIMING_LL_MSPI_ID_1);
}
uint8_t mspi_timing_config_get_flash_extra_dummy(void)
{
//use hw extra dummy
return 0;
}

View File

@ -0,0 +1,145 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @brief
*
* This file contains configuration APIs doing MSPI timing tuning by MSPI delay
*/
#pragma once
#include <stdint.h>
#include "soc/soc_caps.h"
#if SOC_MEMSPI_TIMING_TUNING_BY_FLASH_DELAY
#include "mspi_timing_types.h"
#include "mspi_timing_tuning_configs.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
#if SOC_MEMSPI_TIMING_TUNING_BY_FLASH_DELAY
#define IS_DDR 1
#define IS_SDR (!IS_DDR)
/*-------------------------------------------------------------------------------------------------
* Timing Required APIs
*-------------------------------------------------------------------------------------------------*/
/**
* @brief Get Flash tuning all configurations
*
* @param[out] config Pointer to Flash tuning configurations
*/
void mspi_timing_get_flash_tuning_configs(mspi_timing_config_t *config);
/**
* @brief Init MSPI for Flash timing tuning
*
* @param[in] flash_freq_mhz Flash frequency in MHz
*/
void mspi_timing_flash_init(uint32_t flash_freq_mhz);
/**
* @brief Tune Flash timing registers for SPI1 accessing Flash
*
* @param[in] configs Timing configs
* @param[in] id Config ID
*/
void mspi_timing_config_flash_set_tuning_regs(const void *configs, uint8_t id);
/**
* @brief Configure Flash to read data via SPI1
*
* @param[out] buf buffer
* @param[in] addr address
* @param[in] len length
*/
void mspi_timing_config_flash_read_data(uint8_t *buf, uint32_t addr, uint32_t len);
/*-------------------------------------------------------------------------------------------------
* Best Timing Tuning Params Selection
*-------------------------------------------------------------------------------------------------*/
/**
* @brief Select Flash best tuning configuration
*
* @param[in] configs Timing tuning configuration table
* @param[in] consecutive_length Length of the consecutive successful sample results
* @param[in] end End of the consecutive successful sample results
* @param[in] reference_data Reference data
* @param[in] is_ddr DDR or SDR
*
* @return Best config ID
*/
uint32_t mspi_timing_flash_select_best_tuning_config(const void *configs, uint32_t consecutive_length, uint32_t end, const uint8_t *reference_data, bool is_ddr);
/**
* @brief Set best Flash tuning configs.
* After this, calling `mspi_timing_enter_high_speed_mode` will set these configs correctly
*
* @param[in] configs Timing tuning configs
* @param[in] best_id Best config ID
*/
void mspi_timing_flash_set_best_tuning_config(const void *configs, uint8_t best_id);
/*-------------------------------------------------------------------------------------------------
* Best Timing Tuning Params Clear / Set
*-------------------------------------------------------------------------------------------------*/
/**
* @brief Clear Flash timing tuning settings
*
* This is used when the system is going into low speed mode / MSPI doesn't need to be run in high speed
*
* @param[in] control_both_mspi Control SPI1 as well
*/
void mspi_timing_flash_config_clear_tuning_regs(bool control_both_mspi);
/**
* @brief Set Flash timing tuning settings
*
* This is used when the system is going to high speed mode / MSPI needs to be run in high speed
*
* @param[in] control_both_mspi Control SPI1 as well
*/
void mspi_timing_flash_config_set_tuning_regs(bool control_both_mspi);
/*-------------------------------------------------------------------------------------------------
* APIs for coordination with ESP Flash driver
*-------------------------------------------------------------------------------------------------*/
/**
* 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 (`spi_flash_timing_tuning.c`).
*/
/**
* @brief Get CS timing
*
* @param[out] setup_time Setup time
* @param[out] hold_time Hold time
*/
void mspi_timing_config_get_cs_timing(uint8_t *setup_time, uint32_t *hold_time);
/**
* @brief Get Flash clock reg val
*
* @return Flash clock reg val
*/
uint32_t mspi_timing_config_get_flash_clock_reg(void);
/**
* @brief Get Flash extra dummy len
*
* @return Flash extra dummy
*/
uint8_t mspi_timing_config_get_flash_extra_dummy(void);
#endif //#if SOC_MEMSPI_TIMING_TUNING_BY_FLASH_DELAY
#ifdef __cplusplus
}
#endif

View File

@ -97,7 +97,7 @@ void mspi_timing_flash_init(uint32_t flash_freq_mhz)
mspi_timing_config_set_flash_clock(flash_freq_mhz, MSPI_TIMING_SPEED_MODE_NORMAL_PERF, true);
//Power on HCLK
mspi_timinng_ll_enable_flash_hclk(0);
mspi_timinng_ll_enable_flash_timing_adjust_clk(0);
}
static void s_set_flash_din_mode_num(uint8_t spi_num, uint8_t din_mode, uint8_t din_num)
@ -227,7 +227,7 @@ void mspi_timing_psram_init(uint32_t psram_freq_mhz)
mspi_timing_config_set_flash_clock(psram_freq_mhz, MSPI_TIMING_SPEED_MODE_NORMAL_PERF, true);
//Power on HCLK
mspi_timinng_ll_enable_psram_hclk(0);
mspi_timinng_ll_enable_psram_timing_adjust_clk(0);
}
static void s_set_psram_din_mode_num(uint8_t spi_num, uint8_t din_mode, uint8_t din_num)

View File

@ -14,6 +14,7 @@
#include <stdint.h>
#include "soc/soc_caps.h"
#if SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY
#include "mspi_timing_types.h"
#include "mspi_timing_tuning_configs.h"
#endif
@ -26,25 +27,6 @@ extern "C" {
#define IS_DDR 1
#define IS_SDR (!IS_DDR)
/**
* MSPI timing tuning registers.
* Upper layer rely on these 3 registers to tune the timing.
*/
typedef struct {
uint8_t spi_din_mode; // input signal delay mode
uint8_t spi_din_num; // input signal delay number
uint8_t extra_dummy_len; // extra dummy length
} mspi_timing_tuning_param_t;
/**
* MSPI timing tuning configurations
*/
typedef struct {
mspi_timing_tuning_param_t tuning_config_table[MSPI_TIMING_CONFIG_NUM_MAX]; // Available timing tuning configs
uint32_t available_config_num; // Available timing tuning config numbers
uint32_t default_config_id; // If tuning fails, we use this one as default
} mspi_timing_config_t;
#if MSPI_TIMING_FLASH_NEEDS_TUNING || MSPI_TIMING_PSRAM_NEEDS_TUNING
/*-------------------------------------------------------------------------------------------------

View File

@ -20,7 +20,8 @@
#include "esp_private/mspi_timing_config.h"
#include "mspi_timing_by_mspi_delay.h"
#include "mspi_timing_by_dqs.h"
#if SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY || SOC_MEMSPI_TIMING_TUNING_BY_DQS
#include "mspi_timing_by_flash_delay.h"
#if SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY || SOC_MEMSPI_TIMING_TUNING_BY_DQS || SOC_MEMSPI_TIMING_TUNING_BY_FLASH_DELAY
#include "mspi_timing_tuning_configs.h"
#include "hal/mspi_timing_tuning_ll.h"
#endif
@ -343,7 +344,7 @@ void mspi_timing_flash_tuning(void)
*/
mspi_timing_enter_low_speed_mode(true);
#if SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY
#if SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY || SOC_MEMSPI_TIMING_TUNING_BY_FLASH_DELAY
mspi_tuning_cfg_drv_t drv = {
.flash_tuning_type = MSPI_TIMING_TUNING_MSPI_DIN_DUMMY,
.sweep_test_nums = 1,
@ -365,7 +366,7 @@ void mspi_timing_flash_tuning(void)
mspi_timing_config_t timing_configs = {0};
mspi_timing_get_flash_tuning_configs(&timing_configs);
#endif //SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY
#endif //SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY || SOC_MEMSPI_TIMING_TUNING_BY_FLASH_DELAY
s_do_tuning(reference_data, &timing_configs, true);

View File

@ -0,0 +1,85 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @brief
*
* This file contains types for MSPI timing tuning
*/
#pragma once
#include <stdint.h>
#include "soc/soc_caps.h"
#if SOC_MEMSPI_TIMING_TUNING_BY_DQS || SOC_MEMSPI_TIMING_TUNING_BY_FLASH_DELAY || SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY
#include "hal/mspi_timing_tuning_ll.h"
#include "mspi_timing_tuning_configs.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
#if SOC_MEMSPI_TIMING_TUNING_BY_DQS || SOC_MEMSPI_TIMING_TUNING_BY_FLASH_DELAY
/**
* Delayline
*/
typedef struct {
uint8_t data_delayline;
uint8_t dqs_delayline;
} __attribute__((packed)) delayline_config_t;
/**
* MSPI timing tuning registers.
*/
typedef struct {
uint8_t spi_din_mode; // input signal delay mode
uint8_t spi_din_num; // input signal delay number
uint8_t extra_dummy_len; // extra dummy length
} mspi_timing_tuning_param_t;
/**
* MSPI timing tuning configurations
*/
typedef struct {
//for psram
mspi_ll_dqs_phase_t phase[MSPI_LL_DQS_PHASE_MAX];
delayline_config_t delayline_table[MSPI_TIMING_CONFIG_NUM_MAX];
//for flash
mspi_timing_tuning_param_t tuning_config_table[MSPI_TIMING_CONFIG_NUM_MAX];
uint32_t flash_default_config_id;
//common
union {
uint32_t available_config_num;
uint32_t available_phase_num;
};
} mspi_timing_config_t;
#endif //#if SOC_MEMSPI_TIMING_TUNING_BY_DQS || SOC_MEMSPI_TIMING_TUNING_BY_FLASH_DELAY
#if SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY
/**
* MSPI timing tuning registers.
* Upper layer rely on these 3 registers to tune the timing.
*/
typedef struct {
uint8_t spi_din_mode; // input signal delay mode
uint8_t spi_din_num; // input signal delay number
uint8_t extra_dummy_len; // extra dummy length
} mspi_timing_tuning_param_t;
/**
* MSPI timing tuning configurations
*/
typedef struct {
mspi_timing_tuning_param_t tuning_config_table[MSPI_TIMING_CONFIG_NUM_MAX]; // Available timing tuning configs
uint32_t available_config_num; // Available timing tuning config numbers
uint32_t default_config_id; // If tuning fails, we use this one as default
} mspi_timing_config_t;
#endif
#ifdef __cplusplus
}
#endif

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -15,6 +15,8 @@
#include "esp_private/mspi_timing_config.h"
#include "mspi_timing_tuning_configs.h"
#include "hal/psram_ctrlr_ll.h"
#include "hal/mspi_timing_tuning_ll.h"
#include "soc/hp_sys_clkrst_struct.h"
const static char *TAG = "MSPI Timing";
@ -35,5 +37,24 @@ void mspi_timing_config_set_psram_clock(uint32_t psram_freq_mhz, mspi_timing_spe
void mspi_timing_config_set_flash_clock(uint32_t flash_freq_mhz, mspi_timing_speed_mode_t speed_mode, bool control_both_mspi)
{
//For compatibility
#if MSPI_TIMING_FLASH_NEEDS_TUNING
assert(HP_SYS_CLKRST.peri_clk_ctrl00.reg_flash_clk_src_sel == 1);
uint32_t core_clock_mhz = MSPI_TIMING_SPLL_FREQ_MHZ / MSPI_TIMING_LL_FLASH_CORE_CLK_DIV;
assert(core_clock_mhz == 120);
uint32_t freqdiv = core_clock_mhz / flash_freq_mhz;
PERIPH_RCC_ATOMIC() {
//core clock shared among SPI0 / SPI1
mspi_timing_ll_set_flash_core_clock(MSPI_TIMING_LL_MSPI_ID_0, core_clock_mhz);
}
mspi_timing_ll_set_flash_clock(MSPI_TIMING_LL_MSPI_ID_0, freqdiv);
if (control_both_mspi) {
mspi_timing_ll_set_flash_clock(MSPI_TIMING_LL_MSPI_ID_1, freqdiv);
}
mspi_timing_ll_mask_invalid_dqs(MSPI_TIMING_LL_MSPI_ID_0, true);
mspi_timing_ll_mask_invalid_dqs(MSPI_TIMING_LL_MSPI_ID_1, true);
#endif
}

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -7,10 +7,12 @@
#include "sdkconfig.h"
#define MSPI_TIMING_MSPI1_IS_INVOLVED CONFIG_ESPTOOLPY_FLASHFREQ_120M //This means esp flash driver needs to be notified
#define MSPI_TIMING_CONFIG_NUM_MAX 32 //This should be larger than the max available timing config num
#define MSPI_TIMING_TEST_DATA_LEN 128
#define MSPI_TIMING_PSRAM_TEST_DATA_ADDR 0x80
#define MSPI_TIMING_DELAYLINE_TEST_NUMS 100
#define MSPI_TIMING_FLASH_TEST_DATA_ADDR CONFIG_BOOTLOADER_OFFSET_IN_FLASH
#define MSPI_TIMING_CORE_CLOCK_DIV 1
#if CONFIG_SPIRAM_SPEED_250M
@ -22,5 +24,42 @@
#else
#define MSPI_TIMING_MPLL_FREQ_MHZ 400
#endif
#define MSPI_TIMING_SPLL_FREQ_MHZ 480
#define MSPI_TIMING_PSRAM_DTR_MODE CONFIG_SPIRAM_MODE_HEX
#define MSPI_TIMING_FLASH_STR_MODE 1
#if CONFIG_ESPTOOLPY_FLASHFREQ_20M
#define MSPI_TIMING_FLASH_MODULE_CLOCK 20
#elif CONFIG_ESPTOOLPY_FLASHFREQ_40M
#define MSPI_TIMING_FLASH_MODULE_CLOCK 40
#elif CONFIG_ESPTOOLPY_FLASHFREQ_80M
#define MSPI_TIMING_FLASH_MODULE_CLOCK 80
#else //CONFIG_ESPTOOLPY_FLASHFREQ_120M
#define MSPI_TIMING_FLASH_MODULE_CLOCK 120
#endif
#define MSPI_TIMING_FLASH_NEEDS_TUNING (MSPI_TIMING_FLASH_MODULE_CLOCK > 80)
#if MSPI_TIMING_FLASH_NEEDS_TUNING
#define MSPI_TIMING_FLASH_CORE_CLOCK_MHZ 120
#else
#define MSPI_TIMING_FLASH_CORE_CLOCK_MHZ 80
#endif
//------------------------------------------Helper Macros to get FLASH/PSRAM tuning configs-----------------------------------------------//
#define __GET_TUNING_CONFIG(type, core_clock, module_clock, mode) \
(mspi_timing_config_t) { .tuning_config_table = MSPI_TIMING_##type##_CONFIG_TABLE_CORE_CLK_##core_clock##M_MODULE_CLK_##module_clock##M_##mode, \
.available_config_num = MSPI_TIMING_##type##_CONFIG_NUM_CORE_CLK_##core_clock##M_MODULE_CLK_##module_clock##M_##mode, \
.flash_default_config_id = MSPI_TIMING_##type##_DEFAULT_CONFIG_ID_CORE_CLK_##core_clock##M_MODULE_CLK_##module_clock##M_##mode }
#define _GET_TUNING_CONFIG(type, core_clock, module_clock, mode) __GET_TUNING_CONFIG(type, core_clock, module_clock, mode)
#define MSPI_TIMING_FLASH_GET_TUNING_CONFIG(core_clock_mhz, module_clock_mhz, mode) _GET_TUNING_CONFIG(FLASH, core_clock_mhz, module_clock_mhz, mode)
/**
* Timing Tuning Parameters
*/
//FLASH: core clock 120M, module clock 120M, STR mode
#define MSPI_TIMING_FLASH_CONFIG_TABLE_CORE_CLK_120M_MODULE_CLK_120M_STR_MODE {{2, 0, 1}, {0, 0, 0}, {2, 2, 2}, {2, 1, 2}, {2, 0, 2}, {0, 0, 1}, {2, 2, 3}, {2, 1, 3}, {2, 0, 3}, {0, 0, 2}, {2, 2, 4}, {2, 1, 4}}
#define MSPI_TIMING_FLASH_CONFIG_NUM_CORE_CLK_120M_MODULE_CLK_120M_STR_MODE 12
#define MSPI_TIMING_FLASH_DEFAULT_CONFIG_ID_CORE_CLK_120M_MODULE_CLK_120M_STR_MODE 2

View File

@ -561,7 +561,7 @@ 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 SOC_MEMSPI_SRC_FREQ_120M
#if SOC_MEMSPI_SRC_FREQ_120M_SUPPORTED
// This function needs to be called when PLL is enabled. Needs to be called after spi_flash_init_chip_state in case
// some state of flash is modified.
mspi_timing_flash_tuning();

View File

@ -15,15 +15,33 @@
#include <stdint.h>
#include <stdbool.h>
#include "hal/assert.h"
#include "hal/misc.h"
#include "soc/soc.h"
#include "soc/iomux_mspi_pin_reg.h"
#include "soc/iomux_mspi_pin_struct.h"
#include "soc/hp_sys_clkrst_reg.h"
#include "soc/hp_sys_clkrst_struct.h"
#include "soc/spi_mem_c_reg.h"
#include "soc/spi1_mem_c_reg.h"
#ifdef __cplusplus
extern "C" {
#endif
#define MSPI_TIMING_LL_MSPI_ID_0 0
#define MSPI_TIMING_LL_MSPI_ID_1 1
#define MSPI_TIMING_LL_FLASH_CORE_CLK_DIV 4
#define MSPI_TIMING_LL_FLASH_OCT_MASK (SPI_MEM_C_FCMD_OCT | SPI_MEM_C_FADDR_OCT | SPI_MEM_C_FDIN_OCT | SPI_MEM_C_FDOUT_OCT)
#define MSPI_TIMING_LL_FLASH_QUAD_MASK (SPI_MEM_C_FASTRD_MODE | SPI_MEM_C_FREAD_DUAL | SPI_MEM_C_FREAD_DIO | SPI_MEM_C_FREAD_QUAD | SPI_MEM_C_FREAD_QIO)
#define MSPI_TIMING_LL_FLASH_QIO_MODE_MASK (SPI_MEM_C_FREAD_QIO | SPI_MEM_C_FASTRD_MODE)
#define MSPI_TIMING_LL_FLASH_QUAD_MODE_MASK (SPI_MEM_C_FREAD_QUAD | SPI_MEM_C_FASTRD_MODE)
#define MSPI_TIMING_LL_FLASH_DIO_MODE_MASK (SPI_MEM_C_FREAD_DIO | SPI_MEM_C_FASTRD_MODE)
#define MSPI_TIMING_LL_FLASH_DUAL_MODE_MASK (SPI_MEM_C_FREAD_DUAL | SPI_MEM_C_FASTRD_MODE)
#define MSPI_TIMING_LL_FLASH_FAST_MODE_MASK (SPI_MEM_C_FASTRD_MODE)
#define MSPI_TIMING_LL_FLASH_SLOW_MODE_MASK 0
/**
* MSPI DQS ID
*/
@ -72,6 +90,19 @@ typedef enum {
MSPI_LL_PIN_MAX,
} mspi_ll_pin_t;
/**
* MSPI flash mode
*/
typedef enum {
MSPI_TIMING_LL_FLASH_OPI_MODE = BIT(0),
MSPI_TIMING_LL_FLASH_QIO_MODE = BIT(1),
MSPI_TIMING_LL_FLASH_QUAD_MODE = BIT(2),
MSPI_TIMING_LL_FLASH_DIO_MODE = BIT(3),
MSPI_TIMING_LL_FLASH_DUAL_MODE = BIT(4),
MSPI_TIMING_LL_FLASH_FAST_MODE = BIT(5),
MSPI_TIMING_LL_FLASH_SLOW_MODE = BIT(6),
} mspi_timing_ll_flash_mode_t;
/**
* Reset the MSPI clock
*/
@ -86,6 +117,9 @@ static inline void _mspi_timing_ll_reset_mspi(void)
/// the critical section needs to declare the __DECLARE_RCC_RC_ATOMIC_ENV variable in advance
#define mspi_timing_ll_reset_mspi(...) (void)__DECLARE_RCC_RC_ATOMIC_ENV; _mspi_timing_ll_reset_mspi(__VA_ARGS__)
/*---------------------------------------------------------------
PSRAM tuning
---------------------------------------------------------------*/
/**
* Set all MSPI DQS phase
*
@ -200,6 +234,312 @@ static inline void mspi_timing_ll_pin_drv_set(uint8_t drv)
REG_SET_FIELD(IOMUX_MSPI_PIN_PSRAM_CS_PIN0_REG, IOMUX_MSPI_PIN_REG_PSRAM_CS_DRV, drv);
}
/*---------------------------------------------------------------
Flash tuning
---------------------------------------------------------------*/
/**
* Set MSPI Flash core clock
*
* @param spi_num SPI0 / SPI1
* @param core_clk_mhz core clock mhz
*/
__attribute__((always_inline))
static inline void _mspi_timing_ll_set_flash_core_clock(int spi_num, uint32_t core_clk_mhz)
{
(void)spi_num;
if (core_clk_mhz == 120) {
HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl00, reg_flash_core_clk_div_num, (MSPI_TIMING_LL_FLASH_CORE_CLK_DIV - 1));
HP_SYS_CLKRST.peri_clk_ctrl00.reg_flash_core_clk_en = 1;
} else {
//ESP32P4 flash timing tuning is based on SPLL==480MHz, flash_core_clock==120MHz. We add assertion here to ensure this
HAL_ASSERT(false);
}
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define mspi_timing_ll_set_flash_core_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; _mspi_timing_ll_set_flash_core_clock(__VA_ARGS__)
/**
* Set MSPI Flash clock
*
* @param spi_num SPI0 / SPI1
* @param freqdiv Divider value
*/
__attribute__((always_inline))
static inline void mspi_timing_ll_set_flash_clock(uint8_t spi_num, uint32_t freqdiv)
{
if (spi_num == MSPI_TIMING_LL_MSPI_ID_0) {
if (freqdiv == 1) {
WRITE_PERI_REG(SPI_MEM_C_CLOCK_REG, SPI_MEM_C_CLK_EQU_SYSCLK);
} else {
uint32_t freqbits = (((freqdiv - 1) << SPI_MEM_C_CLKCNT_N_S)) | (((freqdiv / 2 - 1) << SPI_MEM_C_CLKCNT_H_S)) | ((freqdiv - 1) << SPI_MEM_C_CLKCNT_L_S);
WRITE_PERI_REG(SPI_MEM_C_CLOCK_REG, freqbits);
}
} else if (spi_num == MSPI_TIMING_LL_MSPI_ID_1) {
if (freqdiv == 1) {
WRITE_PERI_REG(SPI1_MEM_C_CLOCK_REG, SPI1_MEM_C_CLK_EQU_SYSCLK);
} else {
uint32_t freqbits = (((freqdiv - 1) << SPI1_MEM_C_CLKCNT_N_S)) | (((freqdiv / 2 - 1) << SPI1_MEM_C_CLKCNT_H_S)) | ((freqdiv - 1) << SPI1_MEM_C_CLKCNT_L_S);
WRITE_PERI_REG(SPI1_MEM_C_CLOCK_REG, freqbits);
}
} else {
HAL_ASSERT(false);
}
}
/**
* Enable Flash timing adjust clock
*
* @param spi_num SPI0 / SPI1
*/
__attribute__((always_inline))
static inline void mspi_timinng_ll_enable_flash_timing_adjust_clk(uint8_t spi_num)
{
(void)spi_num;
REG_GET_BIT(SPI_MEM_C_TIMING_CALI_REG, SPI_MEM_C_TIMING_CLK_ENA);
}
/**
* Set MSPI Flash din mode
*
* @param spi_num SPI0 / SPI1
* @param din_mode Din mode value
*/
__attribute__((always_inline))
static inline void mspi_timing_ll_set_flash_din_mode(uint8_t spi_num, uint8_t din_mode)
{
(void)spi_num;
uint32_t reg_val = (REG_READ(SPI_MEM_C_DIN_MODE_REG) & (~(SPI_MEM_C_DIN0_MODE_M | SPI_MEM_C_DIN1_MODE_M | SPI_MEM_C_DIN2_MODE_M | SPI_MEM_C_DIN3_MODE_M | SPI_MEM_C_DIN4_MODE_M | SPI_MEM_C_DIN5_MODE_M | SPI_MEM_C_DIN6_MODE_M | SPI_MEM_C_DIN7_MODE_M | SPI_MEM_C_DINS_MODE_M)))
| (din_mode << SPI_MEM_C_DIN0_MODE_S) | (din_mode << SPI_MEM_C_DIN1_MODE_S) | (din_mode << SPI_MEM_C_DIN2_MODE_S) | (din_mode << SPI_MEM_C_DIN3_MODE_S)
| (din_mode << SPI_MEM_C_DIN4_MODE_S) | (din_mode << SPI_MEM_C_DIN5_MODE_S) | (din_mode << SPI_MEM_C_DIN6_MODE_S) | (din_mode << SPI_MEM_C_DIN7_MODE_S) | (din_mode << SPI_MEM_C_DINS_MODE_S);
REG_WRITE(SPI_MEM_C_DIN_MODE_REG, reg_val);
REG_SET_BIT(SPI_MEM_C_TIMING_CALI_REG, SPI_MEM_C_TIMING_CALI_UPDATE);
}
/**
* Set MSPI Flash din num
*
* @param spi_num SPI0 / SPI1
* @param din_num Din num value
*/
__attribute__((always_inline))
static inline void mspi_timing_ll_set_flash_din_num(uint8_t spi_num, uint8_t din_num)
{
(void)spi_num;
uint32_t reg_val = (REG_READ(SPI_MEM_C_DIN_NUM_REG) & (~(SPI_MEM_C_DIN0_NUM_M | SPI_MEM_C_DIN1_NUM_M | SPI_MEM_C_DIN2_NUM_M | SPI_MEM_C_DIN3_NUM_M | SPI_MEM_C_DIN4_NUM_M | SPI_MEM_C_DIN5_NUM_M | SPI_MEM_C_DIN6_NUM_M | SPI_MEM_C_DIN7_NUM_M | SPI_MEM_C_DINS_NUM_M)))
| (din_num << SPI_MEM_C_DIN0_NUM_S) | (din_num << SPI_MEM_C_DIN1_NUM_S) | (din_num << SPI_MEM_C_DIN2_NUM_S) | (din_num << SPI_MEM_C_DIN3_NUM_S)
| (din_num << SPI_MEM_C_DIN4_NUM_S) | (din_num << SPI_MEM_C_DIN5_NUM_S) | (din_num << SPI_MEM_C_DIN6_NUM_S) | (din_num << SPI_MEM_C_DIN7_NUM_S) | (din_num << SPI_MEM_C_DINS_NUM_S);
REG_WRITE(SPI_MEM_C_DIN_NUM_REG, reg_val);
REG_SET_BIT(SPI_MEM_C_TIMING_CALI_REG, SPI_MEM_C_TIMING_CALI_UPDATE);
}
/**
* Set MSPI Flash extra dummy
*
* @param spi_num SPI0 / SPI1
* @param extra_dummy Extra dummy
*/
__attribute__((always_inline))
static inline void mspi_timing_ll_set_flash_extra_dummy(uint8_t spi_num, uint8_t extra_dummy)
{
if (spi_num == MSPI_TIMING_LL_MSPI_ID_0) {
if (extra_dummy > 0) {
SET_PERI_REG_MASK(SPI_MEM_C_TIMING_CALI_REG, SPI_MEM_C_TIMING_CALI_M);
SET_PERI_REG_BITS(SPI_MEM_C_TIMING_CALI_REG, SPI_MEM_C_EXTRA_DUMMY_CYCLELEN_V, extra_dummy, SPI_MEM_C_EXTRA_DUMMY_CYCLELEN_S);
} else {
CLEAR_PERI_REG_MASK(SPI_MEM_C_TIMING_CALI_REG, SPI_MEM_C_TIMING_CALI_M);
SET_PERI_REG_BITS(SPI_MEM_C_TIMING_CALI_REG, SPI_MEM_C_EXTRA_DUMMY_CYCLELEN_V, 0, SPI_MEM_C_EXTRA_DUMMY_CYCLELEN_S);
}
REG_SET_BIT(SPI_MEM_C_TIMING_CALI_REG, SPI_MEM_C_TIMING_CALI_UPDATE);
} else if (spi_num == MSPI_TIMING_LL_MSPI_ID_1) {
if (extra_dummy > 0) {
SET_PERI_REG_MASK(SPI1_MEM_C_TIMING_CALI_REG, SPI1_MEM_C_TIMING_CALI);
SET_PERI_REG_BITS(SPI1_MEM_C_TIMING_CALI_REG, SPI1_MEM_C_EXTRA_DUMMY_CYCLELEN_V, extra_dummy, SPI1_MEM_C_EXTRA_DUMMY_CYCLELEN_S);
} else {
CLEAR_PERI_REG_MASK(SPI1_MEM_C_TIMING_CALI_REG, SPI1_MEM_C_TIMING_CALI);
SET_PERI_REG_BITS(SPI1_MEM_C_TIMING_CALI_REG, SPI1_MEM_C_EXTRA_DUMMY_CYCLELEN_V, 0, SPI1_MEM_C_EXTRA_DUMMY_CYCLELEN_S);
}
REG_SET_BIT(SPI_MEM_C_TIMING_CALI_REG, SPI_MEM_C_TIMING_CALI_UPDATE);
} else {
HAL_ASSERT(false);
}
}
/**
* Set MSPI Flash user dummy
*
* @param spi_num SPI0 / SPI1
* @param user_dummy user dummy
*/
__attribute__((always_inline))
static inline void mspi_timing_ll_set_flash_user_dummy(uint8_t spi_num, uint8_t user_dummy)
{
if (spi_num == MSPI_TIMING_LL_MSPI_ID_0) {
REG_SET_FIELD(SPI_MEM_C_USER1_REG, SPI_MEM_C_USR_DUMMY_CYCLELEN, user_dummy);
} else if (spi_num == MSPI_TIMING_LL_MSPI_ID_1) {
REG_SET_FIELD(SPI1_MEM_C_USER1_REG, SPI1_MEM_C_USR_DUMMY_CYCLELEN, user_dummy);
} else {
HAL_ASSERT(false);
}
}
/**
* Enable/Disable Flash variable dummy
*
* @param spi_num SPI0 / SPI1
* @param enable Enable / Disable
*/
__attribute__((always_inline))
static inline void mspi_timing_ll_enable_flash_variable_dummy(uint8_t spi_num, bool enable)
{
(void)spi_num;
REG_SET_FIELD(SPI1_MEM_C_DDR_REG, SPI1_MEM_C_FMEM_VAR_DUMMY, enable);
}
/**
* Mask invalid DQS
*
* @param spi_num SPI0 / SPI1
* @param enable Enable / Disable
*/
__attribute__((always_inline))
static inline void mspi_timing_ll_mask_invalid_dqs(uint8_t spi_num, bool enable)
{
if (spi_num == MSPI_TIMING_LL_MSPI_ID_0) {
REG_SET_FIELD(SPI_MEM_C_CTRL_REG, SPI_MEM_C_FDUMMY_RIN, enable);
} else if (spi_num == MSPI_TIMING_LL_MSPI_ID_1) {
REG_SET_FIELD(SPI1_MEM_C_CTRL_REG, SPI1_MEM_C_FDUMMY_RIN, enable);
} else {
HAL_ASSERT(false);
}
}
/**
* Get if cs setup is enabled or not
*
* @param spi_num SPI0 / SPI1
*
* @return
* true: enabled; false: disabled
*/
__attribute__((always_inline))
static inline bool mspi_timing_ll_is_cs_setup_enabled(uint8_t spi_num)
{
(void)spi_num;
return REG_GET_BIT(SPI_MEM_C_USER_REG, SPI_MEM_C_CS_SETUP);
}
/**
* Get cs setup val
*
* @param spi_num SPI0 / SPI1
*
* @return
* cs setup reg val
*/
static inline uint32_t mspi_timing_ll_get_cs_setup_val(uint8_t spi_num)
{
(void)spi_num;
return REG_GET_FIELD(SPI_MEM_C_CTRL2_REG, SPI_MEM_C_CS_SETUP_TIME);
}
/**
* Get if cs hold is enabled or not
*
* @param spi_num SPI0 / SPI1
*
* @return
* true: enabled; false: disabled
*/
__attribute__((always_inline))
static inline bool mspi_timing_ll_is_cs_hold_enabled(uint8_t spi_num)
{
(void)spi_num;
return REG_GET_FIELD(SPI_MEM_C_USER_REG, SPI_MEM_C_CS_HOLD);
}
/**
* Get cs hold val
*
* @param spi_num SPI0 / SPI1
*
* @return
* cs hold reg val
*/
static inline uint32_t mspi_timing_ll_get_cs_hold_val(uint8_t spi_num)
{
(void)spi_num;
return REG_GET_FIELD(SPI_MEM_C_CTRL2_REG, SPI_MEM_C_CS_HOLD_TIME);
}
/**
* Get clock reg val
*
* @param spi_num SPI0 / SPI1
*
* @return
* clock reg val
*/
__attribute__((always_inline))
static inline uint32_t mspi_timing_ll_get_clock_reg(uint8_t spi_num)
{
(void)spi_num;
return READ_PERI_REG(SPI1_MEM_C_CLOCK_REG);
}
/**
* Get MSPI Flash mode
*
* @param spi_num SPI0 / SPI1
*
* @return Flash mode
*/
__attribute__((always_inline))
static inline mspi_timing_ll_flash_mode_t mspi_timing_ll_get_flash_mode(uint8_t spi_num)
{
uint32_t ctrl_reg = READ_PERI_REG(SPI_MEM_C_CTRL_REG);
if (ctrl_reg & MSPI_TIMING_LL_FLASH_OCT_MASK) {
return MSPI_TIMING_LL_FLASH_OPI_MODE;
}
switch (ctrl_reg & MSPI_TIMING_LL_FLASH_QUAD_MASK) {
case MSPI_TIMING_LL_FLASH_QIO_MODE_MASK:
return MSPI_TIMING_LL_FLASH_QIO_MODE;
case MSPI_TIMING_LL_FLASH_QUAD_MODE_MASK:
return MSPI_TIMING_LL_FLASH_QUAD_MODE;
case MSPI_TIMING_LL_FLASH_DIO_MODE_MASK:
return MSPI_TIMING_LL_FLASH_DIO_MODE;
case MSPI_TIMING_LL_FLASH_DUAL_MODE_MASK:
return MSPI_TIMING_LL_FLASH_DUAL_MODE;
case MSPI_TIMING_LL_FLASH_FAST_MODE_MASK:
return MSPI_TIMING_LL_FLASH_FAST_MODE;
case MSPI_TIMING_LL_FLASH_SLOW_MODE_MASK:
return MSPI_TIMING_LL_FLASH_SLOW_MODE;
default:
HAL_ASSERT(false);
return (mspi_timing_ll_flash_mode_t)0;
}
}
/**
* Get MSPI flash dummy info
*/
__attribute__((always_inline))
static inline void mspi_timing_ll_get_flash_dummy(uint8_t spi_num, int *usr_dummy, int *extra_dummy)
{
if (spi_num == MSPI_TIMING_LL_MSPI_ID_0) {
*usr_dummy = REG_GET_FIELD(SPI_MEM_C_USER1_REG, SPI_MEM_C_USR_DUMMY_CYCLELEN);
*extra_dummy = REG_GET_FIELD(SPI_MEM_C_TIMING_CALI_REG, SPI_MEM_C_EXTRA_DUMMY_CYCLELEN);
} else if (spi_num == MSPI_TIMING_LL_MSPI_ID_1) {
*usr_dummy = REG_GET_FIELD(SPI1_MEM_C_USER1_REG, SPI1_MEM_C_USR_DUMMY_CYCLELEN);
*extra_dummy = REG_GET_FIELD(SPI1_MEM_C_TIMING_CALI_REG, SPI1_MEM_C_EXTRA_DUMMY_CYCLELEN);
} else {
HAL_ASSERT(false);
}
}
#ifdef __cplusplus
}
#endif

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -101,23 +101,23 @@ static inline void mspi_timing_ll_set_psram_clock_pin_drive(uint8_t spi_num, uin
}
/**
* Enable Flash HCLK
* Enable Flash timing adjust clock
*
* @param spi_num SPI0 / SPI1
*/
__attribute__((always_inline))
static inline void mspi_timinng_ll_enable_flash_hclk(uint8_t spi_num)
static inline void mspi_timinng_ll_enable_flash_timing_adjust_clk(uint8_t spi_num)
{
REG_SET_BIT(SPI_MEM_TIMING_CALI_REG(spi_num), SPI_MEM_TIMING_CLK_ENA);
}
/**
* Enable PSRAM HCLK
* Enable PSRAM timing adjust clock
*
* @param spi_num SPI0 / SPI1
*/
__attribute__((always_inline))
static inline void mspi_timinng_ll_enable_psram_hclk(uint8_t spi_num)
static inline void mspi_timinng_ll_enable_psram_timing_adjust_clk(uint8_t spi_num)
{
REG_SET_BIT(SPI_MEM_SPI_SMEM_TIMING_CALI_REG(spi_num), SPI_MEM_SPI_SMEM_TIMING_CLK_ENA);
}

View File

@ -1559,6 +1559,10 @@ config SOC_MEMSPI_TIMING_TUNING_BY_DQS
bool
default y
config SOC_MEMSPI_TIMING_TUNING_BY_FLASH_DELAY
bool
default y
config SOC_SPI_MEM_SUPPORT_CACHE_32BIT_ADDR_MAP
bool
default y
@ -1579,6 +1583,10 @@ config SOC_MEMSPI_SRC_FREQ_20M_SUPPORTED
bool
default y
config SOC_MEMSPI_SRC_FREQ_120M_SUPPORTED
bool
default y
config SOC_MEMSPI_FLASH_PSRAM_INDEPENDENT
bool
default y

View File

@ -580,6 +580,7 @@
// #define SOC_SPI_MEM_SUPPORT_WRAP (1) // IDFCI-2073 The feature cannot be treated as supported on P4
#define SOC_SPI_MEM_SUPPORT_TIMING_TUNING (1)
#define SOC_MEMSPI_TIMING_TUNING_BY_DQS (1)
#define SOC_MEMSPI_TIMING_TUNING_BY_FLASH_DELAY (1)
#define SOC_SPI_MEM_SUPPORT_CACHE_32BIT_ADDR_MAP (1)
#define SOC_SPI_PERIPH_SUPPORT_CONTROL_DUMMY_OUT (1)
@ -587,6 +588,7 @@
#define SOC_MEMSPI_SRC_FREQ_80M_SUPPORTED 1
#define SOC_MEMSPI_SRC_FREQ_40M_SUPPORTED 1
#define SOC_MEMSPI_SRC_FREQ_20M_SUPPORTED 1
#define SOC_MEMSPI_SRC_FREQ_120M_SUPPORTED 1
#define SOC_MEMSPI_FLASH_PSRAM_INDEPENDENT 1

View File

@ -919,7 +919,7 @@ config SOC_SPI_SCT_CONF_BITLEN_MAX
hex
default 0x3FFFA
config SOC_MEMSPI_SRC_FREQ_120M
config SOC_MEMSPI_SRC_FREQ_120M_SUPPORTED
bool
default y

View File

@ -360,7 +360,7 @@
#define SOC_SPI_SCT_BUFFER_NUM_MAX (1 + SOC_SPI_SCT_REG_NUM) //1-word-bitmap + 14-word-regs
#define SOC_SPI_SCT_CONF_BITLEN_MAX 0x3FFFA //18 bits wide reg
#define SOC_MEMSPI_SRC_FREQ_120M 1
#define SOC_MEMSPI_SRC_FREQ_120M_SUPPORTED 1
#define SOC_MEMSPI_SRC_FREQ_80M_SUPPORTED 1
#define SOC_MEMSPI_SRC_FREQ_40M_SUPPORTED 1
#define SOC_MEMSPI_SRC_FREQ_20M_SUPPORTED 1

View File

@ -36,7 +36,7 @@ menu "Main Flash configuration"
choice SPI_FLASH_HPM
prompt "High Performance Mode (READ DOCS FIRST, > 80MHz)"
# Currently, only esp32s3 allows high performance mode.
depends on IDF_TARGET_ESP32S3 && !ESPTOOLPY_OCT_FLASH
depends on (IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32P4) && !ESPTOOLPY_OCT_FLASH
default SPI_FLASH_HPM_AUTO
help
Whether the High Performance Mode of Flash is enabled. As an optional feature, user needs to manually
@ -56,7 +56,7 @@ menu "Main Flash configuration"
config SPI_FLASH_HPM_ON
bool
# For ESP32-S3, it's enabled by default. For later chips it should be disabled by default
default y if IDF_TARGET_ESP32S3 && ((SPI_FLASH_HPM_ENA || SPI_FLASH_HPM_AUTO)) || \
default y if (IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32P4) && ((SPI_FLASH_HPM_ENA || SPI_FLASH_HPM_AUTO)) || \
(!IDF_TARGET_ESP32S3 && SPI_FLASH_HPM_ENA)
help
This option is invisible, and will be selected automatically

View File

@ -2,6 +2,10 @@ choice ESPTOOLPY_FLASHFREQ
prompt "Flash SPI speed"
default ESPTOOLPY_FLASHFREQ_40M if ESP32P4_REV_MIN_0
default ESPTOOLPY_FLASHFREQ_80M
config ESPTOOLPY_FLASHFREQ_120M
bool "120 MHz"
depends on IDF_EXPERIMENTAL_FEATURES
depends on !ESP32P4_REV_MIN_0
config ESPTOOLPY_FLASHFREQ_80M
bool "80 MHz"
depends on !ESP32P4_REV_MIN_0