mirror of
https://github.com/espressif/esp-idf
synced 2025-03-09 09:09:10 -04:00
feat(mspi): supported flash 120MHz SDR timing tuning on ESP32P4
This commit is contained in:
parent
8eeb3e2055
commit
1eef2e8c19
@ -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)
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
*-------------------------------------------------------------------------------------------------*/
|
||||
|
226
components/esp_hw_support/mspi_timing_by_flash_delay.c
Normal file
226
components/esp_hw_support/mspi_timing_by_flash_delay.c
Normal 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;
|
||||
}
|
145
components/esp_hw_support/mspi_timing_by_flash_delay.h
Normal file
145
components/esp_hw_support/mspi_timing_by_flash_delay.h
Normal 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
|
@ -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)
|
||||
|
@ -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
|
||||
/*-------------------------------------------------------------------------------------------------
|
||||
|
@ -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);
|
||||
|
||||
|
85
components/esp_hw_support/mspi_timing_types.h
Normal file
85
components/esp_hw_support/mspi_timing_types.h
Normal 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
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user