mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-02 11:10:54 +03:00
Merge branch 'refactor/flash_refactor' into 'master'
spi_flash: split driver and os driver into `spi_flash` and `esp_mspi` components Closes IDF-15210 See merge request espressif/esp-idf!45409
This commit is contained in:
@@ -14,10 +14,6 @@ endif()
|
||||
|
||||
set(public_include_dirs "include" "include/soc"
|
||||
"ldo/include" "debug_probe/include" "etm/include"
|
||||
"mspi/mspi_timing_tuning/include" "mspi/mspi_timing_tuning/tuning_scheme_impl/include"
|
||||
"mspi/mspi_intr/include"
|
||||
"mspi/esp_mspi_align/include"
|
||||
"mspi/mspi_mem_barrier/include"
|
||||
"power_supply/include" "modem/include")
|
||||
|
||||
if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/include/soc/${target}")
|
||||
@@ -44,7 +40,7 @@ endif()
|
||||
|
||||
set(requires esp_hal_gpio esp_hal_usb esp_hal_pmu esp_hal_regi2c esp_hal_uart esp_hal_debug_assist)
|
||||
set(priv_requires efuse # only esp_hw_support/adc_share_hw_ctrl.c requires efuse component
|
||||
spi_flash
|
||||
esp_mspi
|
||||
bootloader_support
|
||||
esp_hal_wdt
|
||||
esp_hal_rtc_timer
|
||||
@@ -55,9 +51,6 @@ set(priv_requires efuse # only esp_hw_support/adc_share_hw_ctrl.
|
||||
)
|
||||
|
||||
set(srcs "cpu.c" "port/${IDF_TARGET}/esp_cpu_intr.c" "esp_memory_utils.c" "port/${IDF_TARGET}/cpu_region_protect.c")
|
||||
if(NOT BOOTLOADER_BUILD)
|
||||
list(APPEND srcs "mspi/esp_mspi_align/esp_mspi_align.c")
|
||||
endif()
|
||||
if(NOT non_os_build)
|
||||
list(APPEND srcs "esp_clk.c"
|
||||
"clk_ctrl_os.c"
|
||||
@@ -76,8 +69,7 @@ if(NOT non_os_build)
|
||||
"port/${target}/esp_clk_tree.c"
|
||||
"spi_bus_lock.c"
|
||||
"heap_align_hw.c"
|
||||
"clk_utils.c"
|
||||
"mspi/mspi_mem_barrier/mspi_mem_barrier.c")
|
||||
"clk_utils.c")
|
||||
if(CONFIG_SOC_USB_OTG_SUPPORTED)
|
||||
list(APPEND srcs "usb_phy/usb_phy.c")
|
||||
endif()
|
||||
@@ -156,27 +148,6 @@ if(NOT non_os_build)
|
||||
"port/regdma_link.c")
|
||||
endif()
|
||||
|
||||
if(NOT CONFIG_APP_BUILD_TYPE_PURE_RAM_APP)
|
||||
list(APPEND srcs "mspi/mspi_timing_tuning/mspi_timing_tuning.c")
|
||||
if(CONFIG_SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY AND NOT CONFIG_IDF_TARGET_ESP32S3)
|
||||
set(mspi_delay_file
|
||||
"${CMAKE_CURRENT_LIST_DIR}/mspi/mspi_timing_tuning/tuning_scheme_impl/mspi_timing_by_mspi_delay.c"
|
||||
)
|
||||
if(EXISTS "${mspi_delay_file}")
|
||||
list(APPEND srcs "mspi/mspi_timing_tuning/tuning_scheme_impl/mspi_timing_by_mspi_delay.c")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(CONFIG_SOC_MEMSPI_TIMING_TUNING_BY_DQS)
|
||||
list(APPEND srcs "mspi/mspi_timing_tuning/tuning_scheme_impl/mspi_timing_by_dqs.c")
|
||||
endif()
|
||||
if(CONFIG_SOC_MEMSPI_TIMING_TUNING_BY_FLASH_DELAY)
|
||||
list(APPEND srcs "mspi/mspi_timing_tuning/tuning_scheme_impl/mspi_timing_by_flash_delay.c")
|
||||
endif()
|
||||
|
||||
list(APPEND srcs "mspi/mspi_intr/mspi_intr.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SOC_RTC_FAST_MEM_SUPPORTED AND CONFIG_ESP_ROM_SUPPORT_DEEP_SLEEP_WAKEUP_STUB)
|
||||
list(APPEND srcs "sleep_wake_stub.c")
|
||||
endif()
|
||||
@@ -196,18 +167,6 @@ if(NOT non_os_build)
|
||||
else()
|
||||
if(ESP_TEE_BUILD)
|
||||
list(APPEND srcs "esp_clk.c" "hw_random.c")
|
||||
if(CONFIG_SECURE_TEE_EXT_FLASH_MEMPROT_SPI1)
|
||||
list(APPEND srcs "mspi/mspi_timing_tuning/mspi_timing_tuning.c")
|
||||
if(CONFIG_SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY)
|
||||
list(APPEND srcs "mspi/mspi_timing_tuning/tuning_scheme_impl/mspi_timing_by_mspi_delay.c")
|
||||
endif()
|
||||
if(CONFIG_SOC_MEMSPI_TIMING_TUNING_BY_DQS)
|
||||
list(APPEND srcs "mspi/mspi_timing_tuning/tuning_scheme_impl/mspi_timing_by_dqs.c")
|
||||
endif()
|
||||
if(CONFIG_SOC_MEMSPI_TIMING_TUNING_BY_FLASH_DELAY)
|
||||
list(APPEND srcs "mspi/mspi_timing_tuning/tuning_scheme_impl/mspi_timing_by_flash_delay.c")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Requires "_esp_error_check_failed()" function
|
||||
@@ -224,15 +183,12 @@ idf_component_register(SRCS ${srcs}
|
||||
PRIV_INCLUDE_DIRS port/include include/esp_private
|
||||
REQUIRES ${requires}
|
||||
PRIV_REQUIRES "${priv_requires}"
|
||||
LDFRAGMENTS linker.lf ldo/linker.lf mspi/linker.lf)
|
||||
LDFRAGMENTS linker.lf ldo/linker.lf)
|
||||
|
||||
idf_define_esp_err_codes(HEADERS include/esp_memprot_err.h)
|
||||
|
||||
idf_build_get_property(target IDF_TARGET)
|
||||
add_subdirectory(port/${target})
|
||||
if(CONFIG_SOC_SPI_MEM_SUPPORT_TIMING_TUNING)
|
||||
add_subdirectory(mspi/mspi_timing_tuning/port/${target})
|
||||
endif()
|
||||
add_subdirectory(lowpower)
|
||||
add_subdirectory(modem)
|
||||
|
||||
|
||||
@@ -86,7 +86,7 @@ This document describes the implementation differences of MSPI interrupt handlin
|
||||
|
||||
| File | Description |
|
||||
|------|-------------|
|
||||
| `components/esp_hw_support/mspi/mspi_intr/mspi_intr.c` | Shared MSPI interrupt management |
|
||||
| `components/esp_mspi/mspi_intr/mspi_intr.c` | Shared MSPI interrupt management |
|
||||
| `components/esp_psram/system_layer/esp_psram_mspi.c` | PSRAM specific interrupt handling |
|
||||
|
||||
---
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/param.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_memory_utils.h"
|
||||
#include "esp_private/esp_mspi_align.h"
|
||||
#if CONFIG_SPIRAM
|
||||
#include "esp_psram.h"
|
||||
#endif /* CONFIG_SPIRAM */
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
#define MSPI_FLASH_ENC_ALIGNMENT SOC_MEMSPI_ENCRYPTION_ALIGNMENT
|
||||
#define MSPI_PSRAM_ECC_ALIGNMENT SOC_MEMSPI_ENCRYPTION_ALIGNMENT
|
||||
|
||||
size_t esp_mspi_get_alignment(const void *ptr)
|
||||
{
|
||||
size_t alignment = 1;
|
||||
bool generic_query = ptr == NULL;
|
||||
bool __attribute__((unused)) is_psram = esp_ptr_external_ram(ptr);
|
||||
bool is_drom = esp_ptr_in_drom(ptr);
|
||||
bool is_psram_enc = false;
|
||||
|
||||
#if CONFIG_SPIRAM
|
||||
is_psram_enc = is_psram && !esp_psram_ptr_is_no_enc(ptr);
|
||||
#endif /* CONFIG_SPIRAM */
|
||||
|
||||
if ((generic_query || is_drom || is_psram_enc) && esp_efuse_is_flash_encryption_enabled()) {
|
||||
alignment = MAX(alignment, MSPI_FLASH_ENC_ALIGNMENT);
|
||||
}
|
||||
|
||||
#if CONFIG_SPIRAM_ECC_ENABLE
|
||||
if (generic_query || is_psram) {
|
||||
alignment = MAX(alignment, MSPI_PSRAM_ECC_ALIGNMENT);
|
||||
}
|
||||
#endif
|
||||
|
||||
return alignment;
|
||||
}
|
||||
|
||||
bool esp_mspi_buffer_alignment_satisfied(const void *ptr, size_t size)
|
||||
{
|
||||
// Zero-length is not a valid MSPI transfer, so it never satisfies the check.
|
||||
if (ptr == NULL || size == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t alignment = esp_mspi_get_alignment(ptr);
|
||||
if (alignment <= 1) {
|
||||
return true;
|
||||
}
|
||||
uintptr_t addr = (uintptr_t)ptr;
|
||||
return ((addr & (alignment - 1)) == 0) && ((size & (alignment - 1)) == 0);
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Get MSPI alignment requirement for an address
|
||||
*
|
||||
* The address is used so future targets can apply different alignment rules to
|
||||
* different MSPI-backed regions. Pass NULL when only the generic external-memory
|
||||
* requirement is needed and no concrete address is available yet.
|
||||
*
|
||||
* @param ptr Buffer pointer in the region to be accessed, or NULL for generic query
|
||||
* @return Required alignment in bytes, or 1 when no extra MSPI alignment is needed
|
||||
*/
|
||||
size_t esp_mspi_get_alignment(const void *ptr);
|
||||
|
||||
/**
|
||||
* @brief Check whether a buffer satisfies MSPI strict alignment requirements
|
||||
*
|
||||
* Returns false when @p ptr is NULL or @p size is 0 (not a valid transfer).
|
||||
* When strict alignment is not required, returns true for any non-empty buffer.
|
||||
* When required, both @p ptr and @p size must be aligned to the rule returned by
|
||||
* @ref esp_mspi_get_alignment for that address.
|
||||
*
|
||||
* @param ptr Buffer pointer
|
||||
* @param size Transfer size in bytes
|
||||
* @return true if alignment requirements are satisfied
|
||||
*/
|
||||
bool esp_mspi_buffer_alignment_satisfied(const void *ptr, size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,22 +0,0 @@
|
||||
[mapping:esp_mspi_align]
|
||||
archive: libesp_hw_support.a
|
||||
entries:
|
||||
if APP_BUILD_TYPE_PURE_RAM_APP = n:
|
||||
esp_mspi_align:esp_mspi_get_alignment (noflash)
|
||||
esp_mspi_align:esp_mspi_buffer_alignment_satisfied (noflash)
|
||||
|
||||
[mapping:mspi_timing_tuning_driver]
|
||||
archive: libesp_hw_support.a
|
||||
entries:
|
||||
|
||||
if APP_BUILD_TYPE_PURE_RAM_APP = n:
|
||||
mspi_timing_tuning (noflash)
|
||||
if SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY = y:
|
||||
mspi_timing_by_mspi_delay (noflash)
|
||||
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)
|
||||
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "esp_err.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief MSPI ISR
|
||||
*/
|
||||
typedef struct mspi_isr_s {
|
||||
/**
|
||||
* @brief MSPI PSRAM ISR
|
||||
*
|
||||
* @param[in] arg Argument to the ISR
|
||||
* @param[in] intr_events Interrupt events
|
||||
*/
|
||||
void (*psram_isr)(void *arg, uint32_t intr_events);
|
||||
|
||||
/**
|
||||
* @brief MSPI Flash ISR
|
||||
*
|
||||
* @param[in] arg Argument to the ISR
|
||||
* @param[in] intr_events Interrupt events
|
||||
*/
|
||||
void (*flash_isr)(void *arg, uint32_t intr_events);
|
||||
} mspi_isr_t;
|
||||
|
||||
/**
|
||||
* @brief Register MSPI interrupt
|
||||
* @note ISR dispatcher will decide if abort, dispatched ISRs should not abort
|
||||
*
|
||||
* This ISR mainly:
|
||||
* - Report MSPI bus errors, e.g. fifo overflow, underflow.
|
||||
* - ECC error, which will be useful for a Nand flash replacement mechanism.
|
||||
* - etc.
|
||||
*
|
||||
* @return ESP_OK on success, otherwise an error code
|
||||
*/
|
||||
esp_err_t esp_mspi_register_isr(mspi_isr_t *isr);
|
||||
|
||||
/**
|
||||
* @brief Unregister MSPI interrupt
|
||||
*
|
||||
* @return ESP_OK on success, otherwise an error code
|
||||
*/
|
||||
esp_err_t esp_mspi_unregister_isr(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,140 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <sys/param.h>
|
||||
#include <inttypes.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "hal/mspi_ll.h"
|
||||
#include "hal/mspi_periph.h"
|
||||
#include "esp_private/startup_internal.h"
|
||||
#include "esp_private/mspi_intr.h"
|
||||
|
||||
#if MSPI_LL_INTR_EVENT_SUPPORTED && MSPI_LL_INTR_SHARED
|
||||
|
||||
#if CONFIG_ESP_PANIC_HANDLER_IRAM
|
||||
#define MSPI_ISR_ATTR IRAM_ATTR
|
||||
#define MSPI_ISR_FLAGS ESP_INTR_FLAG_IRAM
|
||||
#else
|
||||
#define MSPI_ISR_ATTR
|
||||
#define MSPI_ISR_FLAGS 0
|
||||
#endif
|
||||
|
||||
ESP_LOG_ATTR_TAG_DRAM(TAG, "mspi_intr");
|
||||
static intr_handle_t s_intr_handle = NULL;
|
||||
static volatile mspi_isr_t s_isr = {
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static void MSPI_ISR_ATTR mspi_isr_handler(void *arg)
|
||||
{
|
||||
uint32_t intr_events = mspi_ll_get_intr_raw(MSPI_TIMING_LL_MSPI_ID_0);
|
||||
mspi_ll_clear_intr(MSPI_TIMING_LL_MSPI_ID_0, intr_events);
|
||||
|
||||
ESP_DRAM_LOGE(TAG, "MSPI error");
|
||||
ESP_DRAM_LOGD(TAG, "intr_events: 0x%" PRIx32, intr_events);
|
||||
|
||||
bool is_ecc_error = false;
|
||||
|
||||
#if MSPI_LL_ECC_INT_SUPPORTED
|
||||
if (intr_events & MSPI_LL_EVENT_ECC_ERR) {
|
||||
ESP_DRAM_LOGE(TAG, "ecc error");
|
||||
is_ecc_error = true;
|
||||
}
|
||||
#endif
|
||||
#if MSPI_LL_PMS_INT_SUPPORTED
|
||||
if (intr_events & MSPI_LL_EVENT_PMS_REJECT) {
|
||||
ESP_DRAM_LOGE(TAG, "pms reject");
|
||||
}
|
||||
#endif
|
||||
#if MSPI_LL_ADDR_INT_SUPPORTED
|
||||
if (intr_events & MSPI_LL_EVENT_AXI_RADDR_ERR) {
|
||||
ESP_DRAM_LOGE(TAG, "read address invalid or misaligned");
|
||||
}
|
||||
if (intr_events & MSPI_LL_EVENT_AXI_WADDR_ERR) {
|
||||
ESP_DRAM_LOGE(TAG, "write addr error");
|
||||
}
|
||||
if (intr_events & MSPI_LL_EVENT_AXI_WR_FLASH_ERR) {
|
||||
ESP_DRAM_LOGE(TAG, "write flash error");
|
||||
}
|
||||
#endif
|
||||
#if MSPI_LL_THRESH_INT_SUPPORTED
|
||||
if (intr_events & MSPI_LL_EVENT_RX_TRANS_OVF) {
|
||||
ESP_DRAM_LOGE(TAG, "rx trans overflow");
|
||||
}
|
||||
if (intr_events & MSPI_LL_EVENT_TX_TRANS_UDF) {
|
||||
ESP_DRAM_LOGE(TAG, "tx trans underflow");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (s_isr.psram_isr) {
|
||||
s_isr.psram_isr(arg, intr_events);
|
||||
}
|
||||
|
||||
if (s_isr.flash_isr) {
|
||||
s_isr.flash_isr(arg, intr_events);
|
||||
}
|
||||
|
||||
// For ecc error, will handle in the flash/psram isr
|
||||
if (!is_ecc_error) {
|
||||
abort();
|
||||
}
|
||||
|
||||
//no yield for now
|
||||
}
|
||||
|
||||
esp_err_t esp_mspi_register_isr(mspi_isr_t *isr)
|
||||
{
|
||||
esp_err_t ret = ESP_FAIL;
|
||||
|
||||
if (isr && isr->psram_isr) {
|
||||
s_isr.psram_isr = isr->psram_isr;
|
||||
}
|
||||
|
||||
if (isr && isr->flash_isr) {
|
||||
s_isr.flash_isr = isr->flash_isr;
|
||||
}
|
||||
|
||||
if (!s_intr_handle) {
|
||||
ret = esp_intr_alloc(mspi_hw_info.instances[MSPI_TIMING_LL_MSPI_ID_0].irq,
|
||||
MSPI_ISR_FLAGS,
|
||||
mspi_isr_handler,
|
||||
NULL,
|
||||
&s_intr_handle);
|
||||
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to allocate MSPI flash interrupt");
|
||||
|
||||
mspi_ll_clear_intr(MSPI_TIMING_LL_MSPI_ID_0, MSPI_LL_EVENT_MASK);
|
||||
mspi_ll_enable_intr(MSPI_TIMING_LL_MSPI_ID_0, MSPI_LL_EVENT_MASK, true);
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_mspi_unregister_isr(void)
|
||||
{
|
||||
esp_err_t ret = ESP_FAIL;
|
||||
|
||||
if (s_intr_handle == NULL) {
|
||||
ESP_EARLY_LOGE(TAG, "MSPI interrupt not registered");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
ret = esp_intr_free(s_intr_handle);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to free MSPI interrupt");
|
||||
|
||||
s_isr.psram_isr = NULL;
|
||||
s_isr.flash_isr = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif //#if MSPI_LL_INTR_EVENT_SUPPORTED && MSPI_LL_INTR_SHARED
|
||||
-37
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_err.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Initialize the MSPI memory barrier workaround
|
||||
*
|
||||
* On targets affected by the MSPI memory barrier hardware issue, this allocates the
|
||||
* dummy cacheline used by @ref esp_psram_mspi_mb to force a cache writeback/fence. On
|
||||
* other targets this is a no-op.
|
||||
*
|
||||
* @return ESP_OK on success, otherwise an error code
|
||||
*/
|
||||
esp_err_t esp_psram_mspi_mb_init(void);
|
||||
|
||||
/**
|
||||
* @brief MSPI memory barrier
|
||||
*
|
||||
* Some targets need this workaround after a DMA transfer into PSRAM to make sure the
|
||||
* data is visible to the CPU. This is a no-op on targets that don't need the workaround.
|
||||
*/
|
||||
void esp_psram_mspi_mb(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_cache.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_private/mspi_mem_barrier.h"
|
||||
|
||||
#define MSPI_MEM_BARRIER_WORKAROUND ((CONFIG_IDF_TARGET_ESP32C5 && CONFIG_ESP32C5_REV_MIN_FULL < 102) || (CONFIG_IDF_TARGET_ESP32C61 && CONFIG_ESP32C61_REV_MIN_FULL < 101))
|
||||
|
||||
__attribute__((unused)) ESP_LOG_ATTR_TAG_DRAM(TAG, "mspi_mem_barrier");
|
||||
|
||||
#if MSPI_MEM_BARRIER_WORKAROUND
|
||||
static void *s_psram_mb_dummy_cacheline; //dummy cacheline for cache memory barrier
|
||||
#endif
|
||||
|
||||
esp_err_t esp_psram_mspi_mb_init(void)
|
||||
{
|
||||
#if MSPI_MEM_BARRIER_WORKAROUND
|
||||
s_psram_mb_dummy_cacheline = heap_caps_calloc(1, CONFIG_CACHE_L1_CACHE_LINE_SIZE, MALLOC_CAP_SPIRAM | MALLOC_CAP_CACHE_ALIGNED);
|
||||
if (!s_psram_mb_dummy_cacheline) {
|
||||
ESP_EARLY_LOGE(TAG, "Failed to allocate dummy cacheline for PSRAM memory barrier!");
|
||||
}
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void IRAM_ATTR esp_psram_mspi_mb(void)
|
||||
{
|
||||
#if MSPI_MEM_BARRIER_WORKAROUND
|
||||
if (s_psram_mb_dummy_cacheline) {
|
||||
uint32_t *p = (uint32_t *)s_psram_mb_dummy_cacheline;
|
||||
*p = (*p + 1) % UINT32_MAX;
|
||||
__attribute__((unused)) esp_err_t ret = ESP_FAIL;
|
||||
ret = esp_cache_msync(s_psram_mb_dummy_cacheline, sizeof(uint32_t), ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED); //malloc is aligned, no need to writeback all
|
||||
assert(ret == ESP_OK);
|
||||
asm volatile("fence");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
-40
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "esp_private/mspi_timing_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------------------------------
|
||||
* Generic Config APIs
|
||||
*-------------------------------------------------------------------------------------------------*/
|
||||
/**
|
||||
* @brief Set Flash module clock
|
||||
*
|
||||
* @param flash_freq_mhz Flash clock frequency in MHz
|
||||
* @param speed_mode Speed mode
|
||||
* @param control_both_mspi Control SPI1 as well
|
||||
*/
|
||||
void mspi_timing_config_set_flash_clock(uint32_t flash_freq_mhz, mspi_timing_speed_mode_t speed_mode, bool control_both_mspi);
|
||||
|
||||
/**
|
||||
* @brief Set PSRAM module clock
|
||||
*
|
||||
* @param psram_freq_mhz PSRAM clock frequency in MHz
|
||||
* @param speed_mode Speed mode
|
||||
* @param control_both_mspi Not used, for compatibility
|
||||
*/
|
||||
void mspi_timing_config_set_psram_clock(uint32_t psram_freq_mhz, mspi_timing_speed_mode_t speed_mode, bool control_both_mspi);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
-80
@@ -1,80 +0,0 @@
|
||||
/*
|
||||
* 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 Get PSRAM frequency in low speed mode (MHz)
|
||||
* @return PSRAM frequency in MHz when in low speed mode
|
||||
*/
|
||||
uint32_t mspi_timing_get_psram_low_speed_freq_mhz(void);
|
||||
|
||||
/**
|
||||
* @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 to low speed while suspending external memory cache to avoid in-flight cache line fills across the
|
||||
* clock change.
|
||||
*
|
||||
* @note Early init only. Not safe for general runtime use: does not coordinate with other cores or freeze cache.
|
||||
*/
|
||||
void mspi_timing_enter_low_speed_early(void);
|
||||
|
||||
/**
|
||||
* @brief Switch MSPI to high speed while suspending external memory cache.
|
||||
*
|
||||
* @note Same usage constraints as @ref mspi_timing_enter_low_speed_early.
|
||||
*/
|
||||
void mspi_timing_enter_high_speed_early(void);
|
||||
|
||||
/**
|
||||
* @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
|
||||
-30
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* This file is for MSPI timinig tuning private APIs
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief MSPI Timing speed mode
|
||||
*/
|
||||
typedef enum {
|
||||
MSPI_TIMING_SPEED_MODE_LOW_PERF, /*!< Low performance speed mode, this mode is safe for all the scenarios,
|
||||
unless the MSPI attached devices (Flash, PSRAM) are powered down.
|
||||
As a tradeoff, the performance of the MSPI (devices) are switched to a very low speed */
|
||||
MSPI_TIMING_SPEED_MODE_NORMAL_PERF, /*!< Normal performance speed mode, MSPI speed is the same as you configured in menuconfig */
|
||||
} mspi_timing_speed_mode_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,739 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_types.h"
|
||||
#include "esp_log.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "soc/soc.h"
|
||||
#include "hal/spi_flash_hal.h"
|
||||
#include "hal/mspi_ll.h"
|
||||
#if !ESP_TEE_BUILD
|
||||
#include "esp_private/esp_cache_private.h"
|
||||
#include "hal/cache_ll.h"
|
||||
#else
|
||||
#include "hal/cache_ll.h"
|
||||
#include "hal/cache_hal.h"
|
||||
#endif
|
||||
#include "esp_private/cache_utils.h"
|
||||
#include "esp_cpu.h"
|
||||
#include "esp_private/mspi_timing_tuning.h"
|
||||
#include "esp_private/mspi_timing_config.h"
|
||||
#include "esp_private/mspi_timing_by_mspi_delay.h"
|
||||
#include "esp_private/mspi_timing_by_dqs.h"
|
||||
#include "esp_private/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"
|
||||
#endif
|
||||
#if SOC_MEMSPI_CLK_SRC_IS_INDEPENDENT
|
||||
#include "hal/spimem_flash_ll.h"
|
||||
#endif
|
||||
|
||||
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
|
||||
#include "esp_ipc_isr.h"
|
||||
#endif
|
||||
|
||||
#if CONFIG_ESPTOOLPY_FLASHFREQ_120M
|
||||
#define FLASH_FREQUENCY_MHZ 120
|
||||
#elif CONFIG_ESPTOOLPY_FLASHFREQ_80M
|
||||
#define FLASH_FREQUENCY_MHZ 80
|
||||
#elif CONFIG_ESPTOOLPY_FLASHFREQ_64M
|
||||
#define FLASH_FREQUENCY_MHZ 64
|
||||
#elif CONFIG_ESPTOOLPY_FLASHFREQ_60M
|
||||
#define FLASH_FREQUENCY_MHZ 60
|
||||
#elif CONFIG_ESPTOOLPY_FLASHFREQ_48M
|
||||
#define FLASH_FREQUENCY_MHZ 48
|
||||
#elif CONFIG_ESPTOOLPY_FLASHFREQ_40M
|
||||
#define FLASH_FREQUENCY_MHZ 40
|
||||
#elif CONFIG_ESPTOOLPY_FLASHFREQ_32M
|
||||
#define FLASH_FREQUENCY_MHZ 32
|
||||
#elif CONFIG_ESPTOOLPY_FLASHFREQ_30M
|
||||
#define FLASH_FREQUENCY_MHZ 30
|
||||
#elif CONFIG_ESPTOOLPY_FLASHFREQ_26M
|
||||
#define FLASH_FREQUENCY_MHZ 26
|
||||
#elif CONFIG_ESPTOOLPY_FLASHFREQ_24M
|
||||
#define FLASH_FREQUENCY_MHZ 24
|
||||
#elif CONFIG_ESPTOOLPY_FLASHFREQ_20M
|
||||
#define FLASH_FREQUENCY_MHZ 20
|
||||
#elif CONFIG_ESPTOOLPY_FLASHFREQ_16M
|
||||
#define FLASH_FREQUENCY_MHZ 16
|
||||
#elif CONFIG_ESPTOOLPY_FLASHFREQ_15M
|
||||
#define FLASH_FREQUENCY_MHZ 15
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief MSPI timing tuning type
|
||||
*/
|
||||
typedef enum {
|
||||
MSPI_TIMING_TUNING_MSPI_DIN_DUMMY, //tune by mspi din and dummy
|
||||
MSPI_TIMING_TUNING_MSPI_DQS_PHASE, //tune by mspi dqs phase
|
||||
MSPI_TIMING_TUNING_MSPI_DELAYLINE, //tune by mspi delayline
|
||||
} mspi_timing_tuning_t;
|
||||
|
||||
typedef struct mspi_tuning_cfg_drv_s mspi_tuning_cfg_drv_t;
|
||||
__attribute__((unused)) const static char *TAG = "MSPI Timing";
|
||||
|
||||
struct mspi_tuning_cfg_drv_s {
|
||||
|
||||
/**
|
||||
* @brief Flash tuning scheme type
|
||||
*/
|
||||
mspi_timing_tuning_t flash_tuning_type;
|
||||
|
||||
/**
|
||||
* @brief How many test times during sweep
|
||||
*/
|
||||
uint32_t sweep_test_nums;
|
||||
|
||||
/**
|
||||
* @brief Init MSPI for Flash timing tuning
|
||||
*
|
||||
* @param[in] flash_freq_mhz Flash frequency in MHz
|
||||
*/
|
||||
void (*flash_init_mspi)(uint32_t flash_freq_mhz);
|
||||
|
||||
/**
|
||||
* @brief Configure MSPI for Flash timing tuning
|
||||
*
|
||||
* @param[in] configs Timing tuning configs
|
||||
* @param[in] id Config ID
|
||||
*/
|
||||
void (*flash_tune_mspi)(const void *configs, uint8_t id);
|
||||
|
||||
/**
|
||||
* @brief Flash read
|
||||
*
|
||||
* @param[in] buf Read buffer
|
||||
* @param[in] addr Read address
|
||||
* @param[in] len Read length
|
||||
*/
|
||||
void (*flash_read)(uint8_t *buf, uint32_t addr, uint32_t len);
|
||||
|
||||
/**
|
||||
* @brief Select best tuning configs for Flash
|
||||
*
|
||||
* @param[in] configs Timing tuning configurations
|
||||
* @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 (*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 (*flash_set_best_tuning_config)(const void *configs, uint8_t best_id);
|
||||
|
||||
/**
|
||||
* @brief PSRAM tuning scheme type
|
||||
*/
|
||||
mspi_timing_tuning_t psram_tuning_type;
|
||||
|
||||
/**
|
||||
* @brief Init MSPI for PSRAM timing tuning
|
||||
*
|
||||
* @param[in] flash_freq_mhz PSRAM frequency in MHz
|
||||
*/
|
||||
void (*psram_init_mspi)(uint32_t psram_freq_mhz);
|
||||
|
||||
/**
|
||||
* @brief Configure MSPI for PSRAM timing tuning
|
||||
*
|
||||
* @param[in] configs Timing tuning configs
|
||||
* @param[in] id Config ID
|
||||
*/
|
||||
void (*psram_tune_mspi)(const void *configs, uint8_t id);
|
||||
|
||||
/**
|
||||
* @brief PSRAM read
|
||||
*
|
||||
* @param[in] buf Read buffer
|
||||
* @param[in] addr Read address
|
||||
* @param[in] len Read length
|
||||
*/
|
||||
void (*psram_read)(uint8_t *buf, uint32_t addr, uint32_t len);
|
||||
|
||||
/**
|
||||
* @brief Select best tuning configs for PSRAM
|
||||
*
|
||||
* @param[in] configs Timing tuning configurations
|
||||
* @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 (*psram_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 PSRAM tuning configs.
|
||||
* After this, calling `mspi_timing_enter_high_speed_mode` will set these configs correctly
|
||||
*
|
||||
* @param[in] configs Timing tuning config
|
||||
* @param[in] best_id Best config ID
|
||||
*/
|
||||
void (*psram_set_best_tuning_config)(const void *configs, uint8_t best_id);
|
||||
};
|
||||
|
||||
static mspi_tuning_cfg_drv_t s_tuning_cfg_drv = {};
|
||||
|
||||
void s_register_config_driver(mspi_tuning_cfg_drv_t *cfg_drv, bool is_flash)
|
||||
{
|
||||
if (is_flash) {
|
||||
s_tuning_cfg_drv.flash_tuning_type = cfg_drv->flash_tuning_type;
|
||||
s_tuning_cfg_drv.flash_init_mspi = cfg_drv->flash_init_mspi;
|
||||
s_tuning_cfg_drv.flash_tune_mspi = cfg_drv->flash_tune_mspi;
|
||||
s_tuning_cfg_drv.flash_read = cfg_drv->flash_read;
|
||||
s_tuning_cfg_drv.flash_select_best_tuning_config = cfg_drv->flash_select_best_tuning_config;
|
||||
s_tuning_cfg_drv.flash_set_best_tuning_config = cfg_drv->flash_set_best_tuning_config;
|
||||
} else {
|
||||
s_tuning_cfg_drv.psram_tuning_type = cfg_drv->psram_tuning_type;
|
||||
s_tuning_cfg_drv.psram_init_mspi = cfg_drv->psram_init_mspi;
|
||||
s_tuning_cfg_drv.psram_tune_mspi = cfg_drv->psram_tune_mspi;
|
||||
s_tuning_cfg_drv.psram_read = cfg_drv->psram_read;
|
||||
s_tuning_cfg_drv.psram_select_best_tuning_config = cfg_drv->psram_select_best_tuning_config;
|
||||
s_tuning_cfg_drv.psram_set_best_tuning_config = cfg_drv->psram_set_best_tuning_config;
|
||||
}
|
||||
s_tuning_cfg_drv.sweep_test_nums = cfg_drv->sweep_test_nums;
|
||||
}
|
||||
|
||||
#if MSPI_TIMING_FLASH_NEEDS_TUNING || MSPI_TIMING_PSRAM_NEEDS_TUNING
|
||||
/**
|
||||
* We use different MSPI timing tuning config to read data to see if current MSPI sampling is successful.
|
||||
* The sampling result will be stored in an array. In this array, successful item will be 1, failed item will be 0.
|
||||
*/
|
||||
static void s_sweep_for_success_sample_points(uint8_t *reference_data, void *config, bool is_flash, uint32_t *out_array)
|
||||
{
|
||||
const mspi_timing_config_t *timing_config = (const mspi_timing_config_t *)config;
|
||||
uint32_t config_idx = 0;
|
||||
uint8_t read_data[MSPI_TIMING_TEST_DATA_LEN] = {0};
|
||||
|
||||
for (config_idx = 0; config_idx < timing_config->available_config_num; config_idx++) {
|
||||
out_array[config_idx] = 0;
|
||||
for (int i = 0; i < s_tuning_cfg_drv.sweep_test_nums; i++) {
|
||||
memset(read_data, 0, MSPI_TIMING_TEST_DATA_LEN);
|
||||
#if MSPI_TIMING_FLASH_NEEDS_TUNING
|
||||
if (is_flash) {
|
||||
s_tuning_cfg_drv.flash_tune_mspi(timing_config, config_idx);
|
||||
s_tuning_cfg_drv.flash_read(read_data, MSPI_TIMING_FLASH_TEST_DATA_ADDR, sizeof(read_data));
|
||||
}
|
||||
#endif
|
||||
#if MSPI_TIMING_PSRAM_NEEDS_TUNING
|
||||
if (!is_flash) {
|
||||
s_tuning_cfg_drv.psram_tune_mspi(timing_config, config_idx);
|
||||
s_tuning_cfg_drv.psram_read(read_data, MSPI_TIMING_PSRAM_TEST_DATA_ADDR, MSPI_TIMING_TEST_DATA_LEN);
|
||||
}
|
||||
#endif
|
||||
if (memcmp(reference_data, read_data, sizeof(read_data)) == 0) {
|
||||
out_array[config_idx] += 1;
|
||||
ESP_DRAM_LOGV(TAG, "config_idx: %d, good", config_idx);
|
||||
} else {
|
||||
ESP_DRAM_LOGV(TAG, "config_idx: %d, bad", config_idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ESP_DRAM_LOGD(TAG, "test nums: %" PRIu32 ", test result: [id][good/bad][good_times]:", s_tuning_cfg_drv.sweep_test_nums);
|
||||
for (config_idx = 0; config_idx < timing_config->available_config_num; config_idx++) {
|
||||
ESP_DRAM_LOGD(TAG, "[%"PRIu32"][%s][%" PRIu32 "] ", config_idx, out_array[config_idx] == s_tuning_cfg_drv.sweep_test_nums ? "good" : "bad", out_array[config_idx]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find consecutive successful sampling points.
|
||||
* e.g. array: {1, 1, 0, 0, 1, 1, 1, 0}
|
||||
* out_length: 3
|
||||
* outout_end_index: 6
|
||||
*/
|
||||
static void s_find_max_consecutive_success_points(uint32_t *array, uint32_t size, uint32_t *out_length, uint32_t *out_end_index)
|
||||
{
|
||||
uint32_t max = 0;
|
||||
uint32_t match_num = 0;
|
||||
uint32_t i = 0;
|
||||
uint32_t end = 0;
|
||||
|
||||
while (i < size) {
|
||||
if (array[i] == s_tuning_cfg_drv.sweep_test_nums) {
|
||||
match_num++;
|
||||
} else {
|
||||
if (match_num > max) {
|
||||
max = match_num;
|
||||
end = i - 1;
|
||||
}
|
||||
match_num = 0;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
/**
|
||||
* this is to deal with the case when the last points are consecutive 1, e.g.
|
||||
* {1, 0, 0, 1, 1, 1, 1, 1, 1}
|
||||
*/
|
||||
if (match_num > max) {
|
||||
max = match_num;
|
||||
end = i - 1;
|
||||
}
|
||||
|
||||
*out_length = max;
|
||||
*out_end_index = end;
|
||||
}
|
||||
|
||||
static void s_select_best_tuning_config(mspi_timing_config_t *config, uint32_t consecutive_length, uint32_t end, const uint8_t *reference_data, bool is_flash)
|
||||
{
|
||||
const mspi_timing_config_t *timing_config = (const mspi_timing_config_t *)config;
|
||||
uint32_t best_point = 0;
|
||||
if (is_flash) {
|
||||
#if MSPI_TIMING_FLASH_DTR_MODE
|
||||
best_point = s_tuning_cfg_drv.flash_select_best_tuning_config(timing_config, consecutive_length, end, reference_data, IS_DDR);
|
||||
#elif MSPI_TIMING_FLASH_STR_MODE
|
||||
best_point = s_tuning_cfg_drv.flash_select_best_tuning_config(timing_config, consecutive_length, end, NULL, IS_SDR);
|
||||
#endif
|
||||
s_tuning_cfg_drv.flash_set_best_tuning_config(timing_config, best_point);
|
||||
} else {
|
||||
#if MSPI_TIMING_PSRAM_DTR_MODE
|
||||
best_point = s_tuning_cfg_drv.psram_select_best_tuning_config(timing_config, consecutive_length, end, reference_data, IS_DDR);
|
||||
#if CONFIG_SPIRAM_TIMING_TUNING_POINT_VIA_TEMPERATURE_SENSOR
|
||||
mspi_timing_setting_temperature_adjustment_best_point(best_point);
|
||||
#endif
|
||||
#elif MSPI_TIMING_PSRAM_STR_MODE
|
||||
best_point = s_tuning_cfg_drv.psram_select_best_tuning_config(timing_config, consecutive_length, end, NULL, IS_SDR);
|
||||
#endif
|
||||
s_tuning_cfg_drv.psram_set_best_tuning_config(timing_config, best_point);
|
||||
}
|
||||
}
|
||||
|
||||
static void s_do_tuning(uint8_t *reference_data, mspi_timing_config_t *config, bool is_flash)
|
||||
{
|
||||
/**
|
||||
* We use MSPI to tune the timing:
|
||||
* 1. Get all MSPI sampling results.
|
||||
* 2. Find the longest consecutive successful sampling points from the result above.
|
||||
* 3. The middle one will be the best sampling point.
|
||||
*/
|
||||
uint32_t consecutive_length = 0;
|
||||
uint32_t last_success_point = 0;
|
||||
uint32_t sample_result[MSPI_TIMING_CONFIG_NUM_MAX] = {0};
|
||||
|
||||
#if MSPI_TIMING_FLASH_NEEDS_TUNING
|
||||
if (is_flash) {
|
||||
s_tuning_cfg_drv.flash_init_mspi(FLASH_FREQUENCY_MHZ);
|
||||
}
|
||||
#endif
|
||||
#if MSPI_TIMING_PSRAM_NEEDS_TUNING
|
||||
if (!is_flash) {
|
||||
s_tuning_cfg_drv.psram_init_mspi(CONFIG_SPIRAM_SPEED);
|
||||
}
|
||||
#endif
|
||||
|
||||
s_sweep_for_success_sample_points(reference_data, config, is_flash, sample_result);
|
||||
s_find_max_consecutive_success_points(sample_result, config->available_config_num, &consecutive_length, &last_success_point);
|
||||
s_select_best_tuning_config(config, consecutive_length, last_success_point, reference_data, is_flash);
|
||||
}
|
||||
#endif //#if MSPI_TIMING_FLASH_NEEDS_TUNING || MSPI_TIMING_PSRAM_NEEDS_TUNING
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* FLASH Timing Tuning
|
||||
*----------------------------------------------------------------------------*/
|
||||
#if MSPI_TIMING_FLASH_NEEDS_TUNING
|
||||
void mspi_timing_flash_tuning(void)
|
||||
{
|
||||
/**
|
||||
* set MSPI related regs to 20mhz configuration, to get reference data from FLASH
|
||||
* see detailed comments in this function (`mspi_timing_enter_low_speed_early`)
|
||||
*/
|
||||
ESP_EARLY_LOGI(TAG, "Enter flash timing tuning");
|
||||
mspi_timing_enter_low_speed_early();
|
||||
|
||||
#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,
|
||||
.flash_init_mspi = mspi_timing_flash_init,
|
||||
.flash_tune_mspi = mspi_timing_config_flash_set_tuning_regs,
|
||||
.flash_read = mspi_timing_config_flash_read_data,
|
||||
.flash_select_best_tuning_config = mspi_timing_flash_select_best_tuning_config,
|
||||
.flash_set_best_tuning_config = mspi_timing_flash_set_best_tuning_config,
|
||||
};
|
||||
bool is_flash = true;
|
||||
s_register_config_driver(&drv, is_flash);
|
||||
|
||||
//Disable the variable dummy mode when doing timing tuning
|
||||
mspi_timing_ll_enable_flash_variable_dummy(1, false); //GD flash will read error in variable mode with 20MHz
|
||||
|
||||
uint8_t reference_data[MSPI_TIMING_TEST_DATA_LEN] = {0};
|
||||
s_tuning_cfg_drv.flash_read(reference_data, MSPI_TIMING_FLASH_TEST_DATA_ADDR, sizeof(reference_data));
|
||||
|
||||
mspi_timing_config_t timing_configs = {0};
|
||||
mspi_timing_get_flash_tuning_configs(&timing_configs);
|
||||
|
||||
#endif //SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY || SOC_MEMSPI_TIMING_TUNING_BY_FLASH_DELAY
|
||||
|
||||
s_do_tuning(reference_data, &timing_configs, true);
|
||||
|
||||
mspi_timing_enter_high_speed_early();
|
||||
}
|
||||
#else
|
||||
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
|
||||
}
|
||||
#endif //MSPI_TIMING_FLASH_NEEDS_TUNING
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* PSRAM Timing Tuning
|
||||
*----------------------------------------------------------------------------*/
|
||||
#if MSPI_TIMING_PSRAM_NEEDS_TUNING
|
||||
void mspi_timing_psram_tuning(void)
|
||||
{
|
||||
/**
|
||||
* set MSPI related regs to 20mhz configuration, to write reference data to PSRAM
|
||||
* see detailed comments in this function (`mspi_timing_enter_low_speed_early`)
|
||||
*/
|
||||
ESP_EARLY_LOGI(TAG, "Enter psram timing tuning");
|
||||
mspi_timing_enter_low_speed_early();
|
||||
|
||||
// write data into psram, used to do timing tuning test.
|
||||
uint8_t reference_data[MSPI_TIMING_TEST_DATA_LEN];
|
||||
mspi_timing_config_psram_prepare_reference_data(reference_data, MSPI_TIMING_TEST_DATA_LEN);
|
||||
mspi_timing_config_psram_write_data(reference_data, MSPI_TIMING_PSRAM_TEST_DATA_ADDR, MSPI_TIMING_TEST_DATA_LEN);
|
||||
|
||||
#if SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY
|
||||
mspi_tuning_cfg_drv_t drv = {
|
||||
.psram_tuning_type = MSPI_TIMING_TUNING_MSPI_DIN_DUMMY,
|
||||
.sweep_test_nums = 1,
|
||||
.psram_init_mspi = mspi_timing_psram_init,
|
||||
.psram_tune_mspi = mspi_timing_config_psram_set_tuning_regs,
|
||||
.psram_read = mspi_timing_config_psram_read_data,
|
||||
.psram_select_best_tuning_config = mspi_timing_psram_select_best_tuning_config,
|
||||
.psram_set_best_tuning_config = mspi_timing_psram_set_best_tuning_config,
|
||||
};
|
||||
bool is_flash = false;
|
||||
s_register_config_driver(&drv, is_flash);
|
||||
|
||||
mspi_timing_config_t timing_configs = {};
|
||||
mspi_timing_get_psram_tuning_configs(&timing_configs);
|
||||
|
||||
//Disable the variable dummy mode when doing timing tuning
|
||||
mspi_timing_ll_enable_flash_variable_dummy(1, false);
|
||||
|
||||
//Get required config, and set them to PSRAM related registers
|
||||
s_do_tuning(reference_data, &timing_configs, false);
|
||||
#endif //#if SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY
|
||||
|
||||
#if SOC_MEMSPI_TIMING_TUNING_BY_DQS
|
||||
bool is_flash = false;
|
||||
mspi_timing_config_t timing_configs = {};
|
||||
|
||||
//Phase
|
||||
mspi_tuning_cfg_drv_t drv = {
|
||||
.psram_tuning_type = MSPI_TIMING_TUNING_MSPI_DQS_PHASE,
|
||||
.sweep_test_nums = 1,
|
||||
.psram_init_mspi = mspi_timing_psram_init,
|
||||
.psram_tune_mspi = mspi_timing_config_psram_set_tuning_phase,
|
||||
.psram_read = mspi_timing_config_psram_read_data,
|
||||
.psram_select_best_tuning_config = mspi_timing_psram_select_best_tuning_phase,
|
||||
.psram_set_best_tuning_config = mspi_timing_psram_set_best_tuning_phase,
|
||||
};
|
||||
s_register_config_driver(&drv, is_flash);
|
||||
mspi_timing_get_psram_tuning_phases(&timing_configs);
|
||||
s_do_tuning(reference_data, &timing_configs, false);
|
||||
|
||||
//Delayline
|
||||
drv = (mspi_tuning_cfg_drv_t) {
|
||||
.psram_tuning_type = MSPI_TIMING_TUNING_MSPI_DELAYLINE,
|
||||
.sweep_test_nums = MSPI_TIMING_DELAYLINE_TEST_NUMS,
|
||||
.psram_init_mspi = mspi_timing_psram_init,
|
||||
.psram_tune_mspi = mspi_timing_config_psram_set_tuning_delayline,
|
||||
.psram_read = mspi_timing_config_psram_read_data,
|
||||
.psram_select_best_tuning_config = mspi_timing_psram_select_best_tuning_delayline,
|
||||
.psram_set_best_tuning_config = mspi_timing_psram_set_best_tuning_delayline,
|
||||
};
|
||||
s_register_config_driver(&drv, is_flash);
|
||||
mspi_timing_get_psram_tuning_delaylines(&timing_configs);
|
||||
s_do_tuning(reference_data, &timing_configs, false);
|
||||
#endif
|
||||
|
||||
mspi_timing_enter_high_speed_early();
|
||||
}
|
||||
|
||||
#else
|
||||
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
|
||||
}
|
||||
#endif //MSPI_TIMING_PSRAM_NEEDS_TUNING
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* APIs to make SPI0 (and SPI1) FLASH work for high/low freq
|
||||
*----------------------------------------------------------------------------*/
|
||||
void __attribute__((weak)) mspi_timing_flash_config_clear_tuning_regs(bool control_both_mspi)
|
||||
{
|
||||
(void)control_both_mspi;
|
||||
//for compatibility, will be replaced by the actual implementation once flash timing tuning is ready
|
||||
}
|
||||
|
||||
void __attribute__((weak)) mspi_timing_flash_config_set_tuning_regs(bool control_both_mspi)
|
||||
{
|
||||
(void)control_both_mspi;
|
||||
//for compatibility, will be replaced by the actual implementation once flash timing tuning is ready
|
||||
}
|
||||
|
||||
uint32_t mspi_timing_get_psram_low_speed_freq_mhz(void)
|
||||
{
|
||||
return 20;
|
||||
}
|
||||
|
||||
void mspi_timing_enter_low_speed_mode(bool control_spi1)
|
||||
{
|
||||
#if MSPI_TIMING_LL_FLASH_CLK_SRC_CHANGEABLE
|
||||
_mspi_timing_ll_set_flash_clk_src(0, FLASH_CLK_SRC_ROM_DEFAULT);
|
||||
#endif
|
||||
|
||||
#if SOC_SPI_MEM_SUPPORT_TIMING_TUNING
|
||||
/**
|
||||
* Here we are going to slow the SPI1 frequency to 20Mhz, so we need to set SPI1 din_num and din_mode regs.
|
||||
*
|
||||
* Because SPI0 and SPI1 share the din_num and din_mode regs, so if we clear SPI1 din_num and din_mode to
|
||||
* 0, if the SPI0 flash module clock is still in high freq, it may not work correctly.
|
||||
*
|
||||
* Therefore, here we need to slow both the SPI0 and SPI1 and related timing tuning regs to 20Mhz configuration.
|
||||
*
|
||||
* Currently we only need to change these clocks on chips with timing tuning
|
||||
* Should be extended to other no-timing-tuning chips if needed. e.g.:
|
||||
* we still need to turn down Flash / PSRAM clock speed at a certain period of time
|
||||
*/
|
||||
uint32_t low_speed_freq_mhz = mspi_timing_get_psram_low_speed_freq_mhz();
|
||||
mspi_timing_config_set_flash_clock(low_speed_freq_mhz, MSPI_TIMING_SPEED_MODE_LOW_PERF, control_spi1);
|
||||
mspi_timing_config_set_psram_clock(low_speed_freq_mhz, MSPI_TIMING_SPEED_MODE_LOW_PERF, control_spi1);
|
||||
#if MSPI_TIMING_FLASH_NEEDS_TUNING || MSPI_TIMING_PSRAM_NEEDS_TUNING
|
||||
mspi_timing_flash_config_clear_tuning_regs(control_spi1);
|
||||
mspi_timing_psram_config_clear_tuning_regs(control_spi1);
|
||||
#endif //#if MSPI_TIMING_FLASH_NEEDS_TUNING || MSPI_TIMING_PSRAM_NEEDS_TUNING
|
||||
#endif //#if SOC_SPI_MEM_SUPPORT_TIMING_TUNING
|
||||
}
|
||||
|
||||
/**
|
||||
* Set FLASH and PSRAM module clock, din_num, din_mode and extra dummy,
|
||||
* 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 `mspi_timing_flash_tuning` or `calculate_best_flash_tuning_config`
|
||||
*/
|
||||
void mspi_timing_enter_high_speed_mode(bool control_spi1)
|
||||
{
|
||||
#if MSPI_TIMING_LL_FLASH_CLK_SRC_CHANGEABLE
|
||||
_mspi_timing_ll_set_flash_clk_src(0, FLASH_CLK_SRC_DEFAULT);
|
||||
#endif
|
||||
|
||||
#if SOC_SPI_MEM_SUPPORT_TIMING_TUNING
|
||||
/**
|
||||
* Currently we only need to change these clocks on chips with timing tuning
|
||||
* Should be extended to other no-timing-tuning chips if needed. e.g.:
|
||||
* we still need to turn down Flash / PSRAM clock speed at a certain period of time
|
||||
*/
|
||||
mspi_timing_config_set_flash_clock(FLASH_FREQUENCY_MHZ, MSPI_TIMING_SPEED_MODE_NORMAL_PERF, control_spi1);
|
||||
#if CONFIG_SPIRAM
|
||||
mspi_timing_config_set_psram_clock(CONFIG_SPIRAM_SPEED, MSPI_TIMING_SPEED_MODE_NORMAL_PERF, control_spi1);
|
||||
#endif //#if CONFIG_SPIRAM
|
||||
#endif //#if SOC_SPI_MEM_SUPPORT_TIMING_TUNING
|
||||
|
||||
#if MSPI_TIMING_FLASH_NEEDS_TUNING || MSPI_TIMING_PSRAM_NEEDS_TUNING
|
||||
mspi_timing_flash_config_set_tuning_regs(control_spi1);
|
||||
mspi_timing_psram_config_set_tuning_regs(control_spi1);
|
||||
#endif //#if MSPI_TIMING_FLASH_NEEDS_TUNING || MSPI_TIMING_PSRAM_NEEDS_TUNING
|
||||
}
|
||||
|
||||
void mspi_timing_change_speed_mode_cache_safe(bool switch_down)
|
||||
{
|
||||
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE && !CONFIG_FREERTOS_UNICORE
|
||||
// For esp chips with two levels of Cache, if another core attempts to access SPI Flash or PSRAM after the
|
||||
// cache is freeze, the access will fail and will keep retrying. This will completely block the L1 Cache,
|
||||
// causing the current core to be unable to access the stack and data in the L2 RAM, which will causes a
|
||||
// deadlock, so we need to stall another core at first.
|
||||
esp_ipc_isr_stall_other_cpu();
|
||||
#endif
|
||||
/**
|
||||
* If a no-cache-freeze-supported chip needs timing tuning, add a protection way:
|
||||
* - spinlock
|
||||
* - or other way
|
||||
*
|
||||
* for preventing concurrent from MSPI to external memory
|
||||
*/
|
||||
#if SOC_CACHE_FREEZE_SUPPORTED
|
||||
#if !ESP_TEE_BUILD
|
||||
esp_cache_freeze_ext_mem_cache();
|
||||
#else
|
||||
/* NOTE: [ESP-TEE] Check implementation when SoCs with 2-level cache are supported */
|
||||
cache_hal_freeze(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
|
||||
#endif
|
||||
#endif //#if SOC_CACHE_FREEZE_SUPPORTED
|
||||
|
||||
if (switch_down) {
|
||||
//enter MSPI low speed mode, extra delays should be removed
|
||||
#if CONFIG_IDF_TARGET_ESP32C5
|
||||
// ESP32-C5 needs to perform encrypted flash writes even when CPU frequency is reduced.
|
||||
// Since encrypted writes use SPI1, we need to configure SPI1 timing registers as well
|
||||
// during runtime frequency switching to ensure proper operation.
|
||||
mspi_timing_enter_low_speed_mode(true);
|
||||
#else
|
||||
mspi_timing_enter_low_speed_mode(false);
|
||||
#endif
|
||||
} else {
|
||||
//enter MSPI high speed mode, extra delays should be considered
|
||||
#if CONFIG_IDF_TARGET_ESP32C5
|
||||
// ESP32-C5 needs to perform encrypted flash writes even when CPU frequency is reduced.
|
||||
// Since encrypted writes use SPI1, we need to configure SPI1 timing registers as well
|
||||
// during runtime frequency switching to ensure proper operation.
|
||||
mspi_timing_enter_high_speed_mode(true);
|
||||
#else
|
||||
mspi_timing_enter_high_speed_mode(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if SOC_CACHE_FREEZE_SUPPORTED
|
||||
#if !ESP_TEE_BUILD
|
||||
esp_cache_unfreeze_ext_mem_cache();
|
||||
#else
|
||||
cache_hal_unfreeze(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
|
||||
#endif
|
||||
#endif //#if SOC_CACHE_FREEZE_SUPPORTED
|
||||
|
||||
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE && !CONFIG_FREERTOS_UNICORE
|
||||
esp_ipc_isr_release_other_cpu();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Early-init MSPI speed switch (see mspi_timing_tuning.h)
|
||||
*----------------------------------------------------------------------------*/
|
||||
#if ESP_TEE_BUILD
|
||||
#include "riscv/rv_utils.h"
|
||||
extern void rom_spi_flash_disable_cache(uint32_t cpuid, uint32_t *saved_state);
|
||||
extern void rom_spi_flash_restore_cache(uint32_t cpuid, uint32_t saved_state);
|
||||
|
||||
static void disable_cache(uint32_t cpuid, uint32_t *saved_state)
|
||||
{
|
||||
#if SOC_BRANCH_PREDICTOR_SUPPORTED
|
||||
rv_utils_dis_branch_predictor();
|
||||
#endif
|
||||
rom_spi_flash_disable_cache(cpuid, saved_state);
|
||||
}
|
||||
|
||||
static void restore_cache(uint32_t cpuid, uint32_t saved_state)
|
||||
{
|
||||
rom_spi_flash_restore_cache(cpuid, saved_state);
|
||||
#if SOC_BRANCH_PREDICTOR_SUPPORTED
|
||||
rv_utils_en_branch_predictor();
|
||||
#endif
|
||||
}
|
||||
#else // ESP_TEE_BUILD
|
||||
|
||||
static void disable_cache(uint32_t cpuid, uint32_t *saved_state)
|
||||
{
|
||||
#if SOC_BRANCH_PREDICTOR_SUPPORTED
|
||||
esp_cpu_branch_prediction_disable();
|
||||
#endif
|
||||
spi_flash_disable_cache(cpuid, saved_state);
|
||||
}
|
||||
|
||||
static void restore_cache(uint32_t cpuid, uint32_t saved_state)
|
||||
{
|
||||
spi_flash_restore_cache(cpuid, saved_state);
|
||||
#if SOC_BRANCH_PREDICTOR_SUPPORTED
|
||||
esp_cpu_branch_prediction_enable();
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void mspi_timing_enter_low_speed_early(void)
|
||||
{
|
||||
uint32_t cache_state = 0;
|
||||
disable_cache(0, &cache_state);
|
||||
mspi_timing_enter_low_speed_mode(true);
|
||||
restore_cache(0, cache_state);
|
||||
}
|
||||
|
||||
void mspi_timing_enter_high_speed_early(void)
|
||||
{
|
||||
uint32_t cache_state = 0;
|
||||
disable_cache(0, &cache_state);
|
||||
mspi_timing_enter_high_speed_mode(true);
|
||||
restore_cache(0, cache_state);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* APIs to inform SPI1 Flash driver of necessary timing configurations
|
||||
*----------------------------------------------------------------------------*/
|
||||
bool spi_flash_timing_is_tuned(void)
|
||||
{
|
||||
#if MSPI_TIMING_MSPI1_IS_INVOLVED
|
||||
//esp flash driver needs to be notified
|
||||
#if MSPI_TIMING_FLASH_NEEDS_TUNING || MSPI_TIMING_PSRAM_NEEDS_TUNING
|
||||
//either flash or psram or both is tuned, needs notify flash driver
|
||||
return true;
|
||||
#else
|
||||
//otherwise no need
|
||||
return false;
|
||||
#endif
|
||||
#else
|
||||
//if mspi1 is not involved in timing tuning
|
||||
return false;
|
||||
#endif //MSPI_TIMING_MSPI1_IS_INVOLVED
|
||||
}
|
||||
|
||||
#if MSPI_TIMING_MSPI1_IS_INVOLVED && (MSPI_TIMING_FLASH_NEEDS_TUNING || MSPI_TIMING_PSRAM_NEEDS_TUNING)
|
||||
void spi_timing_get_flash_timing_param(spi_flash_hal_timing_config_t *out_timing_config)
|
||||
{
|
||||
// Get clock configuration directly from system.
|
||||
out_timing_config->clock_config.spimem = mspi_timing_config_get_flash_clock_reg();
|
||||
|
||||
// Get extra dummy length here. Therefore, no matter what freq, or mode.
|
||||
// If it needs tuning, it will return correct extra dummy len. If no tuning, it will return 0.
|
||||
|
||||
out_timing_config->extra_dummy = mspi_timing_config_get_flash_extra_dummy();
|
||||
|
||||
#if MSPI_TIMING_LL_FLASH_FDUMMY_RIN_SUPPORTED
|
||||
out_timing_config->fdummy_rin = mspi_timing_config_get_flash_fdummy_rin();
|
||||
#endif
|
||||
|
||||
// Get CS setup/hold value here.
|
||||
mspi_timing_config_get_cs_timing(&out_timing_config->cs_setup, &out_timing_config->cs_hold);
|
||||
}
|
||||
#else
|
||||
void spi_timing_get_flash_timing_param(spi_flash_hal_timing_config_t *out_timing_config)
|
||||
{
|
||||
// This function shouldn't be called if timing tuning is not used.
|
||||
abort();
|
||||
}
|
||||
#endif // #if MSPI_TIMING_MSPI1_IS_INVOLVED && (MSPI_TIMING_FLASH_NEEDS_TUNING || MSPI_TIMING_PSRAM_NEEDS_TUNING)
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Common settings
|
||||
*----------------------------------------------------------------------------*/
|
||||
void mspi_timing_set_pin_drive_strength(void)
|
||||
{
|
||||
#if CONFIG_IDF_TARGET_ESP32S3
|
||||
//Set default pin drive
|
||||
mspi_timing_ll_set_all_pin_drive(0, 3);
|
||||
#endif
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
target_include_directories(${COMPONENT_LIB} PUBLIC . include)
|
||||
|
||||
set(srcs)
|
||||
|
||||
if(NOT BOOTLOADER_BUILD)
|
||||
if(NOT CONFIG_APP_BUILD_TYPE_PURE_RAM_APP)
|
||||
list(APPEND srcs "mspi_timing_config.c")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
target_sources(${COMPONENT_LIB} PRIVATE ${srcs})
|
||||
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_types.h"
|
||||
#include "esp_log.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
#include "esp_private/mspi_timing_config.h"
|
||||
#include "mspi_timing_tuning_configs.h"
|
||||
#include "hal/psram_ctrlr_ll.h"
|
||||
#include "hal/mspi_ll.h"
|
||||
|
||||
#define FLASH_LOW_SPEED_CORE_CLOCK_MHZ MSPI_TIMING_LL_CORE_CLOCK_MHZ_DEFAULT
|
||||
#define FLASH_HIGH_SPEED_CORE_CLOCK_MHZ MSPI_TIMING_CORE_CLOCK_MHZ
|
||||
#define PSRAM_LOW_SPEED_CORE_CLOCK_MHZ MSPI_TIMING_LL_CORE_CLOCK_MHZ_DEFAULT
|
||||
#define PSRAM_HIGH_SPEED_CORE_CLOCK_MHZ MSPI_TIMING_CORE_CLOCK_MHZ
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "MSPI Timing");
|
||||
|
||||
//-------------------------------------MSPI Clock Setting-------------------------------------//
|
||||
static void s_mspi_flash_set_core_clock(uint8_t mspi_id, uint32_t core_clock_mhz)
|
||||
{
|
||||
ESP_DRAM_LOGV(TAG, "flash core clock: %d", core_clock_mhz);
|
||||
mspi_timing_ll_set_core_clock(mspi_id, core_clock_mhz);
|
||||
}
|
||||
|
||||
static void s_mspi_psram_set_core_clock(uint8_t mspi_id, uint32_t core_clock_mhz)
|
||||
{
|
||||
ESP_DRAM_LOGV(TAG, "psram core clock: %d", core_clock_mhz);
|
||||
mspi_timing_ll_set_core_clock(mspi_id, core_clock_mhz);
|
||||
}
|
||||
|
||||
void mspi_timing_config_set_flash_clock(uint32_t flash_freq_mhz, mspi_timing_speed_mode_t speed_mode, bool control_both_mspi)
|
||||
{
|
||||
uint32_t core_clock_mhz = 0;
|
||||
if (speed_mode == MSPI_TIMING_SPEED_MODE_LOW_PERF) {
|
||||
core_clock_mhz = FLASH_LOW_SPEED_CORE_CLOCK_MHZ;
|
||||
} else {
|
||||
core_clock_mhz = FLASH_HIGH_SPEED_CORE_CLOCK_MHZ;
|
||||
}
|
||||
//SPI0 and SPI1 share the register for core clock. So we only set SPI0 here.
|
||||
s_mspi_flash_set_core_clock(MSPI_TIMING_LL_MSPI_ID_0, core_clock_mhz);
|
||||
|
||||
uint32_t freqdiv = core_clock_mhz / flash_freq_mhz;
|
||||
ESP_DRAM_LOGV(TAG, "flash freqdiv: %d", freqdiv);
|
||||
assert(freqdiv > 0);
|
||||
uint32_t reg_val = mspi_timing_ll_calculate_clock_reg(freqdiv);
|
||||
mspi_timing_ll_set_flash_clock(MSPI_TIMING_LL_MSPI_ID_0, reg_val);
|
||||
if (control_both_mspi) {
|
||||
mspi_timing_ll_set_flash_clock(MSPI_TIMING_LL_MSPI_ID_1, reg_val);
|
||||
}
|
||||
}
|
||||
|
||||
void mspi_timing_config_set_psram_clock(uint32_t psram_freq_mhz, mspi_timing_speed_mode_t speed_mode, bool control_both_mspi)
|
||||
{
|
||||
(void)control_both_mspi; // for compatibility
|
||||
uint32_t core_clock_mhz = 0;
|
||||
if (speed_mode == MSPI_TIMING_SPEED_MODE_LOW_PERF) {
|
||||
core_clock_mhz = PSRAM_LOW_SPEED_CORE_CLOCK_MHZ;
|
||||
} else {
|
||||
core_clock_mhz = PSRAM_HIGH_SPEED_CORE_CLOCK_MHZ;
|
||||
}
|
||||
//SPI0 and SPI1 share the register for core clock. So we only set SPI0 here.
|
||||
s_mspi_psram_set_core_clock(MSPI_TIMING_LL_MSPI_ID_0, core_clock_mhz);
|
||||
|
||||
uint32_t freqdiv = core_clock_mhz / psram_freq_mhz;
|
||||
ESP_DRAM_LOGV(TAG, "psram freqdiv: %d", freqdiv);
|
||||
assert(freqdiv > 0);
|
||||
uint32_t reg_val = mspi_timing_ll_calculate_clock_reg(freqdiv);
|
||||
mspi_timing_ll_set_psram_clock(MSPI_TIMING_LL_MSPI_ID_0, reg_val);
|
||||
}
|
||||
-155
@@ -1,155 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_assert.h"
|
||||
#include "esp_flash_partitions.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define MSPI_TIMING_MSPI1_IS_INVOLVED (CONFIG_ESPTOOLPY_FLASHFREQ_80M || 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 0x100000
|
||||
#define MSPI_TIMING_FLASH_TEST_DATA_ADDR ESP_BOOTLOADER_OFFSET
|
||||
|
||||
//--------------------------------------FLASH Sampling Mode --------------------------------------//
|
||||
#define MSPI_TIMING_FLASH_STR_MODE 1
|
||||
//--------------------------------------FLASH Module Clock --------------------------------------//
|
||||
#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
|
||||
#elif CONFIG_ESPTOOLPY_FLASHFREQ_120M
|
||||
#define MSPI_TIMING_FLASH_MODULE_CLOCK 120
|
||||
#endif
|
||||
//------------------------------------FLASH Needs Tuning or not-------------------------------------//
|
||||
#if MSPI_TIMING_FLASH_STR_MODE
|
||||
#define MSPI_TIMING_FLASH_NEEDS_TUNING (MSPI_TIMING_FLASH_MODULE_CLOCK > 40)
|
||||
#endif
|
||||
|
||||
//--------------------------------------PSRAM Sampling Mode --------------------------------------//
|
||||
#define MSPI_TIMING_PSRAM_STR_MODE 1
|
||||
//--------------------------------------PSRAM Module Clock --------------------------------------//
|
||||
#if CONFIG_SPIRAM
|
||||
#if CONFIG_SPIRAM_SPEED_40M
|
||||
#define MSPI_TIMING_PSRAM_MODULE_CLOCK 40
|
||||
#elif CONFIG_SPIRAM_SPEED_80M
|
||||
#define MSPI_TIMING_PSRAM_MODULE_CLOCK 80
|
||||
#else //CONFIG_SPIRAM_SPEED_120M
|
||||
#define MSPI_TIMING_PSRAM_MODULE_CLOCK 120
|
||||
#endif
|
||||
#else //Disable PSRAM
|
||||
#define MSPI_TIMING_PSRAM_MODULE_CLOCK 10 //Define this to 10MHz
|
||||
#endif
|
||||
//------------------------------------PSRAM Needs Tuning or not-------------------------------------//
|
||||
#if MSPI_TIMING_PSRAM_STR_MODE
|
||||
#define MSPI_TIMING_PSRAM_NEEDS_TUNING (MSPI_TIMING_PSRAM_MODULE_CLOCK > 40)
|
||||
#endif
|
||||
|
||||
///////////////////////////////////// FLASH CORE CLOCK /////////////////////////////////////
|
||||
//FLASH 80M
|
||||
#if CONFIG_ESPTOOLPY_FLASHFREQ_80M
|
||||
#define MSPI_TIMING_FLASH_EXPECTED_CORE_CLK_MHZ 80
|
||||
#define MSPI_TIMING_FLASH_CONSECUTIVE_LEN_MAX 6
|
||||
#endif
|
||||
|
||||
//FLASH 120M
|
||||
#if CONFIG_ESPTOOLPY_FLASHFREQ_120M
|
||||
#define MSPI_TIMING_FLASH_EXPECTED_CORE_CLK_MHZ 120
|
||||
#define MSPI_TIMING_FLASH_CONSECUTIVE_LEN_MAX 4
|
||||
#endif
|
||||
|
||||
///////////////////////////////////// PSRAM CORE CLOCK /////////////////////////////////////
|
||||
//PSRAM 80M
|
||||
#if CONFIG_SPIRAM_SPEED_80M
|
||||
#define MSPI_TIMING_PSRAM_EXPECTED_CORE_CLK_MHZ 80
|
||||
#endif
|
||||
|
||||
//PSRAM 120M
|
||||
#if CONFIG_SPIRAM_SPEED_120M
|
||||
#define MSPI_TIMING_PSRAM_EXPECTED_CORE_CLK_MHZ 120
|
||||
#endif //PSRAM 120M DTR
|
||||
|
||||
//------------------------------------------Determine the Core Clock-----------------------------------------------//
|
||||
/**
|
||||
* @note
|
||||
* Limitation 1:
|
||||
* MSPI FLASH and PSRAM share the core clock register. Therefore,
|
||||
* the expected CORE CLOCK frequencies should be the same.
|
||||
*/
|
||||
#if MSPI_TIMING_FLASH_NEEDS_TUNING && MSPI_TIMING_PSRAM_NEEDS_TUNING
|
||||
ESP_STATIC_ASSERT(MSPI_TIMING_FLASH_EXPECTED_CORE_CLK_MHZ == MSPI_TIMING_PSRAM_EXPECTED_CORE_CLK_MHZ, "FLASH and PSRAM Mode configuration are not supported");
|
||||
#define MSPI_TIMING_CORE_CLOCK_MHZ MSPI_TIMING_FLASH_EXPECTED_CORE_CLK_MHZ
|
||||
|
||||
//If only FLASH needs tuning, the core clock COULD be as FLASH expected
|
||||
#elif MSPI_TIMING_FLASH_NEEDS_TUNING && !MSPI_TIMING_PSRAM_NEEDS_TUNING
|
||||
ESP_STATIC_ASSERT(MSPI_TIMING_FLASH_EXPECTED_CORE_CLK_MHZ % MSPI_TIMING_PSRAM_MODULE_CLOCK == 0, "FLASH and PSRAM Mode configuration are not supported");
|
||||
#define MSPI_TIMING_CORE_CLOCK_MHZ MSPI_TIMING_FLASH_EXPECTED_CORE_CLK_MHZ
|
||||
|
||||
//If only PSRAM needs tuning, the core clock COULD be as PSRAM expected
|
||||
#elif !MSPI_TIMING_FLASH_NEEDS_TUNING && MSPI_TIMING_PSRAM_NEEDS_TUNING
|
||||
ESP_STATIC_ASSERT(MSPI_TIMING_PSRAM_EXPECTED_CORE_CLK_MHZ % MSPI_TIMING_FLASH_MODULE_CLOCK == 0, "FLASH and PSRAM Mode configuration are not supported");
|
||||
#define MSPI_TIMING_CORE_CLOCK_MHZ MSPI_TIMING_PSRAM_EXPECTED_CORE_CLK_MHZ
|
||||
|
||||
#else
|
||||
#define MSPI_TIMING_CORE_CLOCK_MHZ 80
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @note
|
||||
* Limitation 2: SDR mode requires the core clock divider (core_clk / div = module_clk) to be even number or 1.
|
||||
*/
|
||||
#if MSPI_TIMING_FLASH_STR_MODE
|
||||
ESP_STATIC_ASSERT((MSPI_TIMING_CORE_CLOCK_MHZ == MSPI_TIMING_FLASH_MODULE_CLOCK) || (MSPI_TIMING_CORE_CLOCK_MHZ % (2 * MSPI_TIMING_FLASH_MODULE_CLOCK) == 0), "FLASH Mode configuration are not supported");
|
||||
#endif
|
||||
#if MSPI_TIMING_PSRAM_STR_MODE
|
||||
ESP_STATIC_ASSERT((MSPI_TIMING_CORE_CLOCK_MHZ == MSPI_TIMING_PSRAM_MODULE_CLOCK) || (MSPI_TIMING_CORE_CLOCK_MHZ % (2 * MSPI_TIMING_PSRAM_MODULE_CLOCK) == 0), "PSRAM Mode configuration are not supported");
|
||||
#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, \
|
||||
.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)
|
||||
#define MSPI_TIMING_PSRAM_GET_TUNING_CONFIG(core_clock_mhz, module_clock_mhz, mode) _GET_TUNING_CONFIG(PSRAM, 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 4
|
||||
|
||||
//FLASH: core clock 80M, module clock 80M, STR mode
|
||||
#define MSPI_TIMING_FLASH_CONFIG_TABLE_CORE_CLK_80M_MODULE_CLK_80M_STR_MODE {{2, 2, 1}, {2, 1, 1}, {2, 0, 1}, {0, 0, 0}, {3, 1, 2}, {2, 3, 2}, {2, 2, 2}, {2, 1, 2}, {2, 0, 2}, {0, 0, 1}, {3, 1, 3}, {2, 3, 3}, {2, 2, 3}, {2, 1, 3}}
|
||||
#define MSPI_TIMING_FLASH_CONFIG_NUM_CORE_CLK_80M_MODULE_CLK_80M_STR_MODE 14
|
||||
#define MSPI_TIMING_FLASH_DEFAULT_CONFIG_ID_CORE_CLK_80M_MODULE_CLK_80M_STR_MODE 4
|
||||
|
||||
//PSRAM: core clock 120M, module clock 120M, STR mode
|
||||
#define MSPI_TIMING_PSRAM_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_PSRAM_CONFIG_NUM_CORE_CLK_120M_MODULE_CLK_120M_STR_MODE 12
|
||||
#define MSPI_TIMING_PSRAM_DEFAULT_CONFIG_ID_CORE_CLK_120M_MODULE_CLK_120M_STR_MODE 4
|
||||
|
||||
//PSRAM: core clock 80M, module clock 80M, STR mode
|
||||
#define MSPI_TIMING_PSRAM_CONFIG_TABLE_CORE_CLK_80M_MODULE_CLK_80M_STR_MODE {{2, 2, 1}, {2, 1, 1}, {2, 0, 1}, {0, 0, 0}, {3, 1, 2}, {2, 3, 2}, {2, 2, 2}, {2, 1, 2}, {2, 0, 2}, {0, 0, 1}, {3, 1, 3}, {2, 3, 3}, {2, 2, 3}, {2, 1, 3}}
|
||||
#define MSPI_TIMING_PSRAM_CONFIG_NUM_CORE_CLK_80M_MODULE_CLK_80M_STR_MODE 14
|
||||
#define MSPI_TIMING_PSRAM_DEFAULT_CONFIG_ID_CORE_CLK_80M_MODULE_CLK_80M_STR_MODE 4
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,11 +0,0 @@
|
||||
target_include_directories(${COMPONENT_LIB} PUBLIC . include)
|
||||
|
||||
set(srcs)
|
||||
|
||||
if(NOT BOOTLOADER_BUILD)
|
||||
if(NOT CONFIG_APP_BUILD_TYPE_PURE_RAM_APP)
|
||||
list(APPEND srcs "mspi_timing_config.c")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
target_sources(${COMPONENT_LIB} PRIVATE ${srcs})
|
||||
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_types.h"
|
||||
#include "esp_log.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
#include "esp_private/mspi_timing_config.h"
|
||||
#include "mspi_timing_tuning_configs.h"
|
||||
#include "hal/psram_ctrlr_ll.h"
|
||||
#include "hal/mspi_ll.h"
|
||||
|
||||
#define FLASH_LOW_SPEED_CORE_CLOCK_MHZ MSPI_TIMING_LL_CORE_CLOCK_MHZ_DEFAULT
|
||||
#define FLASH_HIGH_SPEED_CORE_CLOCK_MHZ MSPI_TIMING_CORE_CLOCK_MHZ
|
||||
#define PSRAM_LOW_SPEED_CORE_CLOCK_MHZ MSPI_TIMING_LL_CORE_CLOCK_MHZ_DEFAULT
|
||||
#define PSRAM_HIGH_SPEED_CORE_CLOCK_MHZ MSPI_TIMING_CORE_CLOCK_MHZ
|
||||
|
||||
const static char *TAG = "MSPI Timing";
|
||||
|
||||
//-------------------------------------MSPI Clock Setting-------------------------------------//
|
||||
static void s_mspi_flash_set_core_clock(uint8_t mspi_id, uint32_t core_clock_mhz)
|
||||
{
|
||||
ESP_DRAM_LOGV(TAG, "flash core clock: %d", core_clock_mhz);
|
||||
mspi_timing_ll_set_core_clock(mspi_id, core_clock_mhz);
|
||||
}
|
||||
|
||||
static void s_mspi_psram_set_core_clock(uint8_t mspi_id, uint32_t core_clock_mhz)
|
||||
{
|
||||
ESP_DRAM_LOGV(TAG, "psram core clock: %d", core_clock_mhz);
|
||||
mspi_timing_ll_set_core_clock(mspi_id, core_clock_mhz);
|
||||
}
|
||||
|
||||
void mspi_timing_config_set_flash_clock(uint32_t flash_freq_mhz, mspi_timing_speed_mode_t speed_mode, bool control_both_mspi)
|
||||
{
|
||||
uint32_t core_clock_mhz = 0;
|
||||
if (speed_mode == MSPI_TIMING_SPEED_MODE_LOW_PERF) {
|
||||
core_clock_mhz = FLASH_LOW_SPEED_CORE_CLOCK_MHZ;
|
||||
} else {
|
||||
core_clock_mhz = FLASH_HIGH_SPEED_CORE_CLOCK_MHZ;
|
||||
}
|
||||
//SPI0 and SPI1 share the register for core clock. So we only set SPI0 here.
|
||||
s_mspi_flash_set_core_clock(MSPI_TIMING_LL_MSPI_ID_0, core_clock_mhz);
|
||||
|
||||
uint32_t freqdiv = core_clock_mhz / flash_freq_mhz;
|
||||
ESP_DRAM_LOGV(TAG, "flash freqdiv: %d", freqdiv);
|
||||
assert(freqdiv > 0);
|
||||
uint32_t reg_val = mspi_timing_ll_calculate_clock_reg(freqdiv);
|
||||
mspi_timing_ll_set_flash_clock(MSPI_TIMING_LL_MSPI_ID_0, reg_val);
|
||||
if (control_both_mspi) {
|
||||
mspi_timing_ll_set_flash_clock(MSPI_TIMING_LL_MSPI_ID_1, reg_val);
|
||||
}
|
||||
}
|
||||
|
||||
void mspi_timing_config_set_psram_clock(uint32_t psram_freq_mhz, mspi_timing_speed_mode_t speed_mode, bool control_both_mspi)
|
||||
{
|
||||
(void)control_both_mspi; // for compatibility
|
||||
uint32_t core_clock_mhz = 0;
|
||||
if (speed_mode == MSPI_TIMING_SPEED_MODE_LOW_PERF) {
|
||||
core_clock_mhz = PSRAM_LOW_SPEED_CORE_CLOCK_MHZ;
|
||||
} else {
|
||||
core_clock_mhz = PSRAM_HIGH_SPEED_CORE_CLOCK_MHZ;
|
||||
}
|
||||
//SPI0 and SPI1 share the register for core clock. So we only set SPI0 here.
|
||||
s_mspi_psram_set_core_clock(MSPI_TIMING_LL_MSPI_ID_0, core_clock_mhz);
|
||||
|
||||
uint32_t freqdiv = core_clock_mhz / psram_freq_mhz;
|
||||
ESP_DRAM_LOGV(TAG, "psram freqdiv: %d", freqdiv);
|
||||
assert(freqdiv > 0);
|
||||
uint32_t reg_val = mspi_timing_ll_calculate_clock_reg(freqdiv);
|
||||
mspi_timing_ll_set_psram_clock(MSPI_TIMING_LL_MSPI_ID_0, reg_val);
|
||||
}
|
||||
-154
@@ -1,154 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_assert.h"
|
||||
#include "esp_flash_partitions.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#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 0x100000
|
||||
#define MSPI_TIMING_FLASH_TEST_DATA_ADDR ESP_BOOTLOADER_OFFSET
|
||||
|
||||
//--------------------------------------FLASH Sampling Mode --------------------------------------//
|
||||
#define MSPI_TIMING_FLASH_STR_MODE 1
|
||||
//--------------------------------------FLASH Module Clock --------------------------------------//
|
||||
#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
|
||||
#elif CONFIG_ESPTOOLPY_FLASHFREQ_120M
|
||||
#define MSPI_TIMING_FLASH_MODULE_CLOCK 120
|
||||
#endif
|
||||
//------------------------------------FLASH Needs Tuning or not-------------------------------------//
|
||||
#define MSPI_TIMING_FLASH_NEEDS_TUNING (MSPI_TIMING_FLASH_MODULE_CLOCK > 80)
|
||||
|
||||
//--------------------------------------PSRAM Sampling Mode --------------------------------------//
|
||||
#define MSPI_TIMING_PSRAM_STR_MODE 1
|
||||
//--------------------------------------PSRAM Module Clock --------------------------------------//
|
||||
#if CONFIG_SPIRAM
|
||||
#if CONFIG_SPIRAM_SPEED_40M
|
||||
#define MSPI_TIMING_PSRAM_MODULE_CLOCK 40
|
||||
#elif CONFIG_SPIRAM_SPEED_80M
|
||||
#define MSPI_TIMING_PSRAM_MODULE_CLOCK 80
|
||||
#elif CONFIG_SPIRAM_SPEED_120M
|
||||
#define MSPI_TIMING_PSRAM_MODULE_CLOCK 120
|
||||
#endif
|
||||
#else //Disable PSRAM
|
||||
#define MSPI_TIMING_PSRAM_MODULE_CLOCK 10 //Define this to 10MHz
|
||||
#endif
|
||||
//------------------------------------PSRAM Needs Tuning or not-------------------------------------//
|
||||
#if MSPI_TIMING_PSRAM_STR_MODE && !CONFIG_SECURE_ENABLE_TEE
|
||||
#define MSPI_TIMING_PSRAM_NEEDS_TUNING (MSPI_TIMING_PSRAM_MODULE_CLOCK > 40)
|
||||
#endif
|
||||
|
||||
///////////////////////////////////// FLASH CORE CLOCK /////////////////////////////////////
|
||||
//FLASH 80M
|
||||
#if CONFIG_ESPTOOLPY_FLASHFREQ_80M
|
||||
#define MSPI_TIMING_FLASH_EXPECTED_CORE_CLK_MHZ 80
|
||||
#define MSPI_TIMING_FLASH_CONSECUTIVE_LEN_MAX 6
|
||||
#endif
|
||||
|
||||
//FLASH 120M
|
||||
#if CONFIG_ESPTOOLPY_FLASHFREQ_120M
|
||||
#define MSPI_TIMING_FLASH_EXPECTED_CORE_CLK_MHZ 120
|
||||
#define MSPI_TIMING_FLASH_CONSECUTIVE_LEN_MAX 4
|
||||
#endif
|
||||
|
||||
///////////////////////////////////// PSRAM CORE CLOCK /////////////////////////////////////
|
||||
//PSRAM 80M
|
||||
#if CONFIG_SPIRAM_SPEED_80M
|
||||
#define MSPI_TIMING_PSRAM_EXPECTED_CORE_CLK_MHZ 80
|
||||
#endif
|
||||
|
||||
//PSRAM 120M
|
||||
#if CONFIG_SPIRAM_SPEED_120M
|
||||
#define MSPI_TIMING_PSRAM_EXPECTED_CORE_CLK_MHZ 120
|
||||
#endif //PSRAM 120M DTR
|
||||
|
||||
//------------------------------------------Determine the Core Clock-----------------------------------------------//
|
||||
/**
|
||||
* @note
|
||||
* Limitation 1:
|
||||
* MSPI FLASH and PSRAM share the core clock register. Therefore,
|
||||
* the expected CORE CLOCK frequencies should be the same.
|
||||
*/
|
||||
#if MSPI_TIMING_FLASH_NEEDS_TUNING && MSPI_TIMING_PSRAM_NEEDS_TUNING
|
||||
ESP_STATIC_ASSERT(MSPI_TIMING_FLASH_EXPECTED_CORE_CLK_MHZ == MSPI_TIMING_PSRAM_EXPECTED_CORE_CLK_MHZ, "FLASH and PSRAM Mode configuration are not supported");
|
||||
#define MSPI_TIMING_CORE_CLOCK_MHZ MSPI_TIMING_FLASH_EXPECTED_CORE_CLK_MHZ
|
||||
|
||||
//If only FLASH needs tuning, the core clock COULD be as FLASH expected
|
||||
#elif MSPI_TIMING_FLASH_NEEDS_TUNING && !MSPI_TIMING_PSRAM_NEEDS_TUNING
|
||||
ESP_STATIC_ASSERT(MSPI_TIMING_FLASH_EXPECTED_CORE_CLK_MHZ % MSPI_TIMING_PSRAM_MODULE_CLOCK == 0, "FLASH and PSRAM Mode configuration are not supported");
|
||||
#define MSPI_TIMING_CORE_CLOCK_MHZ MSPI_TIMING_FLASH_EXPECTED_CORE_CLK_MHZ
|
||||
|
||||
//If only PSRAM needs tuning, the core clock COULD be as PSRAM expected
|
||||
#elif !MSPI_TIMING_FLASH_NEEDS_TUNING && MSPI_TIMING_PSRAM_NEEDS_TUNING
|
||||
ESP_STATIC_ASSERT(MSPI_TIMING_PSRAM_EXPECTED_CORE_CLK_MHZ % MSPI_TIMING_FLASH_MODULE_CLOCK == 0, "FLASH and PSRAM Mode configuration are not supported");
|
||||
#define MSPI_TIMING_CORE_CLOCK_MHZ MSPI_TIMING_PSRAM_EXPECTED_CORE_CLK_MHZ
|
||||
|
||||
#else
|
||||
#define MSPI_TIMING_CORE_CLOCK_MHZ 80
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @note
|
||||
* Limitation 2: SDR mode requires the core clock divider (core_clk / div = module_clk) to be even number or 1.
|
||||
*/
|
||||
#if MSPI_TIMING_FLASH_STR_MODE
|
||||
ESP_STATIC_ASSERT((MSPI_TIMING_CORE_CLOCK_MHZ == MSPI_TIMING_FLASH_MODULE_CLOCK) || (MSPI_TIMING_CORE_CLOCK_MHZ % (2 * MSPI_TIMING_FLASH_MODULE_CLOCK) == 0), "FLASH Mode configuration are not supported");
|
||||
#endif
|
||||
#if MSPI_TIMING_PSRAM_STR_MODE
|
||||
ESP_STATIC_ASSERT((MSPI_TIMING_CORE_CLOCK_MHZ == MSPI_TIMING_PSRAM_MODULE_CLOCK) || (MSPI_TIMING_CORE_CLOCK_MHZ % (2 * MSPI_TIMING_PSRAM_MODULE_CLOCK) == 0), "PSRAM Mode configuration are not supported");
|
||||
#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, \
|
||||
.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)
|
||||
#define MSPI_TIMING_PSRAM_GET_TUNING_CONFIG(core_clock_mhz, module_clock_mhz, mode) _GET_TUNING_CONFIG(PSRAM, 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
|
||||
|
||||
//FLASH: core clock 80M, module clock 80M, STR mode
|
||||
#define MSPI_TIMING_FLASH_CONFIG_TABLE_CORE_CLK_80M_MODULE_CLK_80M_STR_MODE {{2, 2, 1}, {2, 1, 1}, {2, 0, 1}, {0, 0, 0}, {3, 1, 2}, {2, 3, 2}, {2, 2, 2}, {2, 1, 2}, {2, 0, 1}, {0, 0, 1}, {3, 1, 3}, {2, 3, 3}, {2, 2, 3}, {2, 1, 3}}
|
||||
#define MSPI_TIMING_FLASH_CONFIG_NUM_CORE_CLK_80M_MODULE_CLK_80M_STR_MODE 14
|
||||
#define MSPI_TIMING_FLASH_DEFAULT_CONFIG_ID_CORE_CLK_80M_MODULE_CLK_80M_STR_MODE 4
|
||||
|
||||
//PSRAM: core clock 120M, module clock 120M, STR mode
|
||||
#define MSPI_TIMING_PSRAM_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_PSRAM_CONFIG_NUM_CORE_CLK_120M_MODULE_CLK_120M_STR_MODE 12
|
||||
#define MSPI_TIMING_PSRAM_DEFAULT_CONFIG_ID_CORE_CLK_120M_MODULE_CLK_120M_STR_MODE 4
|
||||
|
||||
//PSRAM: core clock 80M, module clock 80M, STR mode
|
||||
#define MSPI_TIMING_PSRAM_CONFIG_TABLE_CORE_CLK_80M_MODULE_CLK_80M_STR_MODE {{2, 2, 1}, {2, 1, 1}, {2, 0, 1}, {0, 0, 0}, {3, 1, 2}, {2, 3, 2}, {2, 2, 2}, {2, 1, 2}, {2, 0, 1}, {0, 0, 1}, {3, 1, 3}, {2, 3, 3}, {2, 2, 3}, {2, 1, 3}}
|
||||
#define MSPI_TIMING_PSRAM_CONFIG_NUM_CORE_CLK_80M_MODULE_CLK_80M_STR_MODE 14
|
||||
#define MSPI_TIMING_PSRAM_DEFAULT_CONFIG_ID_CORE_CLK_80M_MODULE_CLK_80M_STR_MODE 4
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,11 +0,0 @@
|
||||
target_include_directories(${COMPONENT_LIB} PUBLIC .)
|
||||
|
||||
set(srcs)
|
||||
|
||||
if(NOT BOOTLOADER_BUILD)
|
||||
if(NOT CONFIG_APP_BUILD_TYPE_PURE_RAM_APP)
|
||||
list(APPEND srcs "mspi_timing_config.c")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
target_sources(${COMPONENT_LIB} PRIVATE "${srcs}")
|
||||
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_types.h"
|
||||
#include "esp_log.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
#include "esp_private/mspi_timing_config.h"
|
||||
#include "mspi_timing_tuning_configs.h"
|
||||
#include "hal/psram_ctrlr_ll.h"
|
||||
#include "hal/mspi_ll.h"
|
||||
#include "soc/hp_sys_clkrst_struct.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "MSPI Timing");
|
||||
|
||||
//-------------------------------------MSPI Clock Setting-------------------------------------//
|
||||
void mspi_timing_config_set_psram_clock(uint32_t psram_freq_mhz, mspi_timing_speed_mode_t speed_mode, bool control_both_mspi)
|
||||
{
|
||||
uint32_t freqdiv = MSPI_TIMING_MPLL_FREQ_MHZ / MSPI_TIMING_CORE_CLOCK_DIV / psram_freq_mhz;
|
||||
assert(freqdiv > 0);
|
||||
ESP_DRAM_LOGD(TAG, "psram_freq_mhz: %" PRIu32 " mhz, bus clock div: %" PRIu32, psram_freq_mhz, freqdiv);
|
||||
PERIPH_RCC_ATOMIC() {
|
||||
//MSPI2 and MSPI3 share the register for core clock. So we only set MSPI2 here.
|
||||
psram_ctrlr_ll_enable_core_clock(PSRAM_CTRLR_LL_MSPI_ID_2, true);
|
||||
psram_ctrlr_ll_set_core_clock_div(PSRAM_CTRLR_LL_MSPI_ID_2, MSPI_TIMING_CORE_CLOCK_DIV);
|
||||
psram_ctrlr_ll_set_bus_clock(PSRAM_CTRLR_LL_MSPI_ID_3, freqdiv);
|
||||
psram_ctrlr_ll_set_bus_clock(PSRAM_CTRLR_LL_MSPI_ID_2, freqdiv);
|
||||
}
|
||||
}
|
||||
|
||||
void mspi_timing_config_set_flash_clock(uint32_t flash_freq_mhz, mspi_timing_speed_mode_t speed_mode, bool control_both_mspi)
|
||||
{
|
||||
#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_HP_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
|
||||
}
|
||||
-85
@@ -1,85 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_assert.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#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
|
||||
#define MSPI_TIMING_PSRAM_NEEDS_TUNING 1
|
||||
#define MSPI_TIMING_MPLL_FREQ_MHZ 500
|
||||
#elif CONFIG_SPIRAM_SPEED_200M
|
||||
#define MSPI_TIMING_PSRAM_NEEDS_TUNING 1
|
||||
#define MSPI_TIMING_MPLL_FREQ_MHZ 400
|
||||
#elif CONFIG_SPIRAM_SPEED_80M
|
||||
#define MSPI_TIMING_PSRAM_NEEDS_TUNING 1
|
||||
#define MSPI_TIMING_MPLL_FREQ_MHZ 320
|
||||
#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
|
||||
|
||||
/**
|
||||
* @note
|
||||
* Limitation 1: SDR mode requires the core clock divider (core_clk / div = module_clk) to be even number or 1.
|
||||
*/
|
||||
#if MSPI_TIMING_FLASH_STR_MODE
|
||||
ESP_STATIC_ASSERT((MSPI_TIMING_FLASH_CORE_CLOCK_MHZ == MSPI_TIMING_FLASH_MODULE_CLOCK) || (MSPI_TIMING_FLASH_CORE_CLOCK_MHZ % (2 * MSPI_TIMING_FLASH_MODULE_CLOCK) == 0), "FLASH Mode configuration are not supported");
|
||||
#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
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,11 +0,0 @@
|
||||
target_include_directories(${COMPONENT_LIB} PUBLIC . include)
|
||||
|
||||
set(srcs)
|
||||
|
||||
if(NOT BOOTLOADER_BUILD)
|
||||
if(NOT CONFIG_APP_BUILD_TYPE_PURE_RAM_APP)
|
||||
list(APPEND srcs "mspi_timing_config.c" "mspi_timing_by_mspi_delay.c")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
target_sources(${COMPONENT_LIB} PRIVATE ${srcs})
|
||||
-885
@@ -1,885 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* This file contains configuration APIs doing MSPI timing tuning by MSPI delay
|
||||
* This file will only be built, when `SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY == 1`
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "string.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_types.h"
|
||||
#include "esp_log.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "hal/mspi_ll.h"
|
||||
#include "hal/clk_tree_ll.h"
|
||||
#include "esp_private/mspi_timing_config.h"
|
||||
#include "esp_private/mspi_timing_by_mspi_delay.h"
|
||||
#include "bootloader_flash.h"
|
||||
#include "esp32s3/rom/spi_flash.h"
|
||||
#include "esp32s3/rom/opi_flash.h"
|
||||
#if CONFIG_SPIRAM_TIMING_TUNING_POINT_VIA_TEMPERATURE_SENSOR
|
||||
#include "mspi_timing_tuning_configs.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "esp_private/cache_utils.h"
|
||||
#include "esp_private/sar_periph_ctrl.h"
|
||||
#include "esp_private/startup_internal.h"
|
||||
#endif // CONFIG_SPIRAM_TIMING_TUNING_POINT_VIA_TEMPERATURE_SENSOR
|
||||
|
||||
#define OPI_PSRAM_SYNC_READ 0x0000
|
||||
#define OPI_PSRAM_SYNC_WRITE 0x8080
|
||||
#define OCT_PSRAM_RD_DUMMY_NUM (2*(10-1))
|
||||
#define OCT_PSRAM_WR_DUMMY_NUM (2*(5-1))
|
||||
|
||||
#define QPI_PSRAM_FAST_READ 0XEB
|
||||
#define QPI_PSRAM_WRITE 0X38
|
||||
#define QPI_PSRAM_FAST_READ_DUMMY 6
|
||||
|
||||
#define NOT_INIT_INT 127
|
||||
|
||||
/////////////////////////////////////////TIMING TUNING IS NEEDED//////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if MSPI_TIMING_FLASH_NEEDS_TUNING || MSPI_TIMING_PSRAM_NEEDS_TUNING
|
||||
ESP_LOG_ATTR_TAG(TAG, "MSPI Timing");
|
||||
|
||||
//If one of the FLASH / PSRAM or both of them need timing tuning, we should build following code
|
||||
typedef enum {
|
||||
PSRAM_CMD_QPI,
|
||||
PSRAM_CMD_SPI,
|
||||
} psram_cmd_mode_t;
|
||||
|
||||
static uint8_t s_rom_flash_extra_dummy[2] = {NOT_INIT_INT, NOT_INIT_INT};
|
||||
|
||||
#if CONFIG_SPIRAM_MODE_QUAD
|
||||
static uint8_t s_psram_extra_dummy;
|
||||
extern void psram_exec_cmd(int spi_num, psram_cmd_mode_t mode,
|
||||
uint32_t cmd, int cmd_bit_len,
|
||||
uint32_t addr, int addr_bit_len,
|
||||
int dummy_bits,
|
||||
uint8_t* mosi_data, int mosi_bit_len,
|
||||
uint8_t* miso_data, int miso_bit_len,
|
||||
uint32_t cs_mask,
|
||||
bool is_write_erase_operation);
|
||||
#endif
|
||||
|
||||
//-------------------------------------FLASH timing tuning register config-------------------------------------//
|
||||
void mspi_timing_get_flash_tuning_configs(mspi_timing_config_t *config)
|
||||
{
|
||||
#if MSPI_TIMING_FLASH_DTR_MODE
|
||||
#define FLASH_MODE DTR_MODE
|
||||
#else //MSPI_TIMING_FLASH_STR_MODE
|
||||
#define FLASH_MODE STR_MODE
|
||||
#endif
|
||||
|
||||
#if CONFIG_ESPTOOLPY_FLASHFREQ_80M
|
||||
*config = MSPI_TIMING_FLASH_GET_TUNING_CONFIG(MSPI_TIMING_CORE_CLOCK_MHZ, 80, FLASH_MODE);
|
||||
#elif CONFIG_ESPTOOLPY_FLASHFREQ_120M
|
||||
*config = MSPI_TIMING_FLASH_GET_TUNING_CONFIG(MSPI_TIMING_CORE_CLOCK_MHZ, 120, FLASH_MODE);
|
||||
#else
|
||||
assert(false && "should never reach here");
|
||||
#endif
|
||||
|
||||
#undef FLASH_MODE
|
||||
}
|
||||
|
||||
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(0);
|
||||
}
|
||||
|
||||
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 uint32_t spi_timing_config_get_dummy(void)
|
||||
{
|
||||
mspi_timing_ll_flash_mode_t mode = mspi_timing_ll_get_flash_mode(0);
|
||||
if (mode == MSPI_TIMING_LL_FLASH_OPI_MODE) {
|
||||
abort();
|
||||
}
|
||||
|
||||
#if CONFIG_SPI_FLASH_HPM_DC_ON
|
||||
if (spi_flash_hpm_dummy_adjust()) { // HPM-DC is enabled
|
||||
const spi_flash_hpm_dummy_conf_t *hpm_dummy = spi_flash_hpm_get_dummy();
|
||||
switch (mode) {
|
||||
case MSPI_TIMING_LL_FLASH_QIO_MODE:
|
||||
return hpm_dummy->qio_dummy - 1;
|
||||
case MSPI_TIMING_LL_FLASH_QUAD_MODE:
|
||||
return hpm_dummy->qout_dummy - 1;
|
||||
case MSPI_TIMING_LL_FLASH_DIO_MODE:
|
||||
return hpm_dummy->dio_dummy - 1;
|
||||
case MSPI_TIMING_LL_FLASH_DUAL_MODE:
|
||||
return hpm_dummy->dout_dummy - 1;
|
||||
case MSPI_TIMING_LL_FLASH_FAST_MODE:
|
||||
return hpm_dummy->fastrd_dummy - 1;
|
||||
case MSPI_TIMING_LL_FLASH_SLOW_MODE:
|
||||
return 0;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{ // HPM-DC is not enabled
|
||||
switch (mode) {
|
||||
case MSPI_TIMING_LL_FLASH_QIO_MODE:
|
||||
return SPI1_R_QIO_DUMMY_CYCLELEN;
|
||||
case MSPI_TIMING_LL_FLASH_QUAD_MODE:
|
||||
return SPI1_R_FAST_DUMMY_CYCLELEN;
|
||||
case MSPI_TIMING_LL_FLASH_DIO_MODE:
|
||||
return SPI1_R_DIO_DUMMY_CYCLELEN;
|
||||
case MSPI_TIMING_LL_FLASH_DUAL_MODE:
|
||||
return SPI1_R_FAST_DUMMY_CYCLELEN;
|
||||
case MSPI_TIMING_LL_FLASH_FAST_MODE:
|
||||
return SPI1_R_FAST_DUMMY_CYCLELEN;
|
||||
case MSPI_TIMING_LL_FLASH_SLOW_MODE:
|
||||
return 0;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void s_set_flash_extra_dummy(uint8_t spi_num, uint8_t extra_dummy)
|
||||
{
|
||||
if (bootloader_flash_is_octal_mode_enabled()) {
|
||||
mspi_timing_ll_set_octal_flash_extra_dummy(spi_num, extra_dummy);
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* HW workaround:
|
||||
* The `SPI_MEM_TIMING_CALI_REG` register is only used for OPI on 728
|
||||
* Here we only need to update this global variable for extra dummy. Since we use the ROM Flash API, which will set the dummy based on this.
|
||||
* We only initialise the SPI0. And leave the SPI1 for flash driver to configure.
|
||||
*/
|
||||
if (s_rom_flash_extra_dummy[spi_num] == NOT_INIT_INT) {
|
||||
s_rom_flash_extra_dummy[spi_num] = g_rom_spiflash_dummy_len_plus[spi_num];
|
||||
}
|
||||
g_rom_spiflash_dummy_len_plus[spi_num] = s_rom_flash_extra_dummy[spi_num] + extra_dummy;
|
||||
|
||||
// Only Quad Flash will run into this branch.
|
||||
uint32_t dummy = spi_timing_config_get_dummy();
|
||||
mspi_timing_ll_set_quad_flash_dummy(spi_num, dummy + g_rom_spiflash_dummy_len_plus[spi_num]);
|
||||
}
|
||||
|
||||
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(0, params->spi_din_mode, params->spi_din_num);
|
||||
s_set_flash_extra_dummy(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 (bootloader_flash_is_octal_mode_enabled()) {
|
||||
// note that in spi_flash_read API, there is a wait-idle stage, since flash can only be read in idle state.
|
||||
// but after we change the timing settings, we might not read correct idle status via RDSR.
|
||||
// so, here we should use a read API that won't check idle status.
|
||||
mspi_timing_ll_clear_fifo(1);
|
||||
esp_rom_opiflash_read_raw(addr, buf, len);
|
||||
} else {
|
||||
esp_rom_spiflash_read(addr, (uint32_t *)buf, len);
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------PSRAM timing tuning register config-------------------------------------//
|
||||
void mspi_timing_get_psram_tuning_configs(mspi_timing_config_t *config)
|
||||
{
|
||||
#if MSPI_TIMING_PSRAM_DTR_MODE
|
||||
#define PSRAM_MODE DTR_MODE
|
||||
#else //MSPI_TIMING_PSRAM_STR_MODE
|
||||
#define PSRAM_MODE STR_MODE
|
||||
#endif
|
||||
|
||||
#if CONFIG_SPIRAM_SPEED_80M
|
||||
*config = MSPI_TIMING_PSRAM_GET_TUNING_CONFIG(MSPI_TIMING_CORE_CLOCK_MHZ, 80, PSRAM_MODE);
|
||||
#elif CONFIG_SPIRAM_SPEED_120M
|
||||
*config = MSPI_TIMING_PSRAM_GET_TUNING_CONFIG(MSPI_TIMING_CORE_CLOCK_MHZ, 120, PSRAM_MODE);
|
||||
#else
|
||||
assert(false && "should never reach here");
|
||||
#endif
|
||||
|
||||
#undef PSRAM_MODE
|
||||
}
|
||||
|
||||
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_timing_adjust_clk(0);
|
||||
}
|
||||
|
||||
static void s_set_psram_din_mode_num(uint8_t spi_num, uint8_t din_mode, uint8_t din_num)
|
||||
{
|
||||
mspi_timing_ll_set_psram_din_mode(spi_num, din_mode);
|
||||
mspi_timing_ll_set_psram_din_num(spi_num, din_num);
|
||||
}
|
||||
|
||||
static void s_set_psram_extra_dummy(uint8_t spi_num, uint8_t extra_dummy)
|
||||
{
|
||||
#if CONFIG_SPIRAM_MODE_OCT
|
||||
mspi_timing_ll_set_octal_psram_extra_dummy(spi_num, extra_dummy);
|
||||
#elif CONFIG_SPIRAM_MODE_QUAD
|
||||
//HW workaround: Use normal dummy register to set extra dummy, the calibration dedicated extra dummy register doesn't work for quad mode
|
||||
mspi_timing_ll_set_quad_psram_dummy(spi_num, (QPI_PSRAM_FAST_READ_DUMMY + extra_dummy - 1));
|
||||
#endif
|
||||
}
|
||||
|
||||
void mspi_timing_config_psram_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_SPI_SMEM_DINx_MODE(1), SPI_MEM_SPI_SMEM_DINx_NUM(1) are meaningless
|
||||
* SPI0 and SPI1 share the SPI_MEM_SPI_SMEM_DINx_MODE(0), SPI_MEM_SPI_SMEM_DINx_NUM(0) for PSRAM timing tuning
|
||||
* 2. We use SPI1 to get the best PSRAM timing tuning (mode and num) config
|
||||
*/
|
||||
s_set_psram_din_mode_num(0, params->spi_din_mode, params->spi_din_num);
|
||||
|
||||
#if CONFIG_SPIRAM_MODE_OCT
|
||||
//On 728, for SPI1, flash and psram share the extra dummy register
|
||||
s_set_flash_extra_dummy(1, params->extra_dummy_len);
|
||||
#elif CONFIG_SPIRAM_MODE_QUAD
|
||||
//Update this `s_psram_extra_dummy`, the `s_psram_read_data` will set dummy according to this `s_psram_extra_dummy`
|
||||
s_psram_extra_dummy = params->extra_dummy_len;
|
||||
mspi_timing_ll_set_quad_flash_dummy(1, params->extra_dummy_len - 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
//-------------------------------------------PSRAM Read/Write------------------------------------------//
|
||||
static void s_psram_write_data(uint8_t *buf, uint32_t addr, uint32_t len)
|
||||
{
|
||||
#if CONFIG_SPIRAM_MODE_OCT
|
||||
esp_rom_opiflash_exec_cmd(1, ESP_ROM_SPIFLASH_OPI_DTR_MODE,
|
||||
OPI_PSRAM_SYNC_WRITE, 16,
|
||||
addr, 32,
|
||||
OCT_PSRAM_WR_DUMMY_NUM,
|
||||
buf, len * 8,
|
||||
NULL, 0,
|
||||
BIT(1),
|
||||
false);
|
||||
#elif CONFIG_SPIRAM_MODE_QUAD
|
||||
psram_exec_cmd(1, 0,
|
||||
QPI_PSRAM_WRITE, 8,
|
||||
addr, 24,
|
||||
0,
|
||||
buf, len * 8,
|
||||
NULL, 0,
|
||||
SPI_MEM_CS1_DIS_M,
|
||||
false);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void s_psram_read_data(uint8_t *buf, uint32_t addr, uint32_t len)
|
||||
{
|
||||
#if CONFIG_SPIRAM_MODE_OCT
|
||||
mspi_timing_ll_clear_fifo(1);
|
||||
esp_rom_opiflash_exec_cmd(1, ESP_ROM_SPIFLASH_OPI_DTR_MODE,
|
||||
OPI_PSRAM_SYNC_READ, 16,
|
||||
addr, 32,
|
||||
OCT_PSRAM_RD_DUMMY_NUM,
|
||||
NULL, 0,
|
||||
buf, len * 8,
|
||||
BIT(1),
|
||||
false);
|
||||
#elif CONFIG_SPIRAM_MODE_QUAD
|
||||
psram_exec_cmd(1, 0,
|
||||
QPI_PSRAM_FAST_READ, 8,
|
||||
addr, 24,
|
||||
QPI_PSRAM_FAST_READ_DUMMY + s_psram_extra_dummy,
|
||||
NULL, 0,
|
||||
buf, len * 8,
|
||||
SPI_MEM_CS1_DIS_M,
|
||||
false);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void s_psram_execution(uint8_t *buf, uint32_t addr, uint32_t len, bool is_read)
|
||||
{
|
||||
while (len) {
|
||||
uint32_t length = MIN(len, 32);
|
||||
if (is_read) {
|
||||
s_psram_read_data(buf, addr, length);
|
||||
} else {
|
||||
s_psram_write_data(buf, addr, length);
|
||||
}
|
||||
addr += length;
|
||||
buf += length;
|
||||
len -= length;
|
||||
}
|
||||
}
|
||||
|
||||
void mspi_timing_config_psram_prepare_reference_data(uint8_t *buf, uint32_t len)
|
||||
{
|
||||
assert((len == MSPI_TIMING_TEST_DATA_LEN) && (len % 4 == 0));
|
||||
for (int i=0; i < len/4; i++) {
|
||||
((uint32_t *)buf)[i] = 0xa5ff005a;
|
||||
}
|
||||
}
|
||||
|
||||
void mspi_timing_config_psram_write_data(uint8_t *buf, uint32_t addr, uint32_t len)
|
||||
{
|
||||
s_psram_execution(buf, addr, len, false);
|
||||
}
|
||||
|
||||
void mspi_timing_config_psram_read_data(uint8_t *buf, uint32_t addr, uint32_t len)
|
||||
{
|
||||
s_psram_execution(buf, addr, len, true);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------------------------------
|
||||
* Best Timing Tuning Params Selection
|
||||
*-------------------------------------------------------------------------------------------------*/
|
||||
#if (MSPI_TIMING_FLASH_DTR_MODE || MSPI_TIMING_PSRAM_DTR_MODE) && (MSPI_TIMING_CORE_CLOCK_MHZ == 240)
|
||||
static bool get_working_pll_freq(const uint8_t *reference_data, bool is_flash, uint32_t *out_max_freq, uint32_t *out_min_freq)
|
||||
{
|
||||
uint8_t read_data[MSPI_TIMING_TEST_DATA_LEN] = {0};
|
||||
rtc_cpu_freq_config_t previous_config;
|
||||
rtc_clk_cpu_freq_get_config(&previous_config);
|
||||
|
||||
uint32_t big_num = MSPI_TIMING_PLL_FREQ_SCAN_RANGE_MHZ_MAX * 2; //This number should be larger than MSPI_TIMING_PLL_FREQ_SCAN_RANGE_MHZ_MAX, for error handling
|
||||
uint32_t max_freq = 0;
|
||||
uint32_t min_freq = big_num;
|
||||
soc_xtal_freq_t xtal_freq = rtc_clk_xtal_freq_get();
|
||||
|
||||
for (int pll_mhz_tuning = MSPI_TIMING_PLL_FREQ_SCAN_RANGE_MHZ_MIN; pll_mhz_tuning <= MSPI_TIMING_PLL_FREQ_SCAN_RANGE_MHZ_MAX; pll_mhz_tuning += 8) {
|
||||
//bbpll calibration start
|
||||
clk_ll_bbpll_calibration_start();
|
||||
|
||||
/**
|
||||
* pll_mhz = xtal_mhz * (oc_div + 4) / (oc_ref_div + 1)
|
||||
*/
|
||||
clk_ll_bbpll_set_frequency_for_mspi_tuning(xtal_freq, pll_mhz_tuning, ((pll_mhz_tuning / 4) - 4), 9);
|
||||
|
||||
//wait calibration done
|
||||
while(!clk_ll_bbpll_calibration_is_done());
|
||||
|
||||
//bbpll calibration stop
|
||||
clk_ll_bbpll_calibration_stop();
|
||||
|
||||
memset(read_data, 0, MSPI_TIMING_TEST_DATA_LEN);
|
||||
if (is_flash) {
|
||||
mspi_timing_config_flash_read_data(read_data, MSPI_TIMING_FLASH_TEST_DATA_ADDR, MSPI_TIMING_TEST_DATA_LEN);
|
||||
} else {
|
||||
mspi_timing_config_psram_read_data(read_data, MSPI_TIMING_PSRAM_TEST_DATA_ADDR, MSPI_TIMING_TEST_DATA_LEN);
|
||||
}
|
||||
|
||||
if (memcmp(read_data, reference_data, MSPI_TIMING_TEST_DATA_LEN) == 0) {
|
||||
max_freq = MAX(pll_mhz_tuning, max_freq);
|
||||
min_freq = MIN(pll_mhz_tuning, min_freq);
|
||||
|
||||
//Continue to find successful cases
|
||||
continue;
|
||||
}
|
||||
|
||||
if (max_freq != 0) {
|
||||
//The first fail case after successful case(s) is the end
|
||||
break;
|
||||
}
|
||||
|
||||
//If no break, no successful case found, continue to find successful cases
|
||||
}
|
||||
|
||||
//restore PLL config
|
||||
clk_ll_bbpll_set_freq_mhz(previous_config.source_freq_mhz);
|
||||
//bbpll calibration start
|
||||
clk_ll_bbpll_calibration_start();
|
||||
//set pll
|
||||
clk_ll_bbpll_set_config(previous_config.source_freq_mhz, xtal_freq);
|
||||
//wait calibration done
|
||||
while(!clk_ll_bbpll_calibration_is_done());
|
||||
//bbpll calibration stop
|
||||
clk_ll_bbpll_calibration_stop();
|
||||
|
||||
*out_max_freq = max_freq;
|
||||
*out_min_freq = min_freq;
|
||||
|
||||
return (max_freq != 0);
|
||||
}
|
||||
#endif //Frequency Scanning
|
||||
|
||||
#if CONFIG_SPIRAM_TIMING_TUNING_POINT_VIA_TEMPERATURE_SENSOR
|
||||
// These arrays store the frequency scan result of the timing points
|
||||
int psram_pass_freq_min[MSPI_TIMING_CONFIG_NUM_MAX] = {0};
|
||||
int psram_pass_freq_max[MSPI_TIMING_CONFIG_NUM_MAX] = {0};
|
||||
#endif // CONFIG_SPIRAM_TIMING_TUNING_POINT_VIA_TEMPERATURE_SENSOR
|
||||
|
||||
static uint32_t s_select_best_tuning_config_dtr(const mspi_timing_config_t *configs, uint32_t consecutive_length, uint32_t end, const uint8_t *reference_data, bool is_flash)
|
||||
{
|
||||
#if (MSPI_TIMING_CORE_CLOCK_MHZ == 160)
|
||||
//Core clock 160M DTR best point scheme
|
||||
uint32_t best_point;
|
||||
|
||||
//Define these magic number in macros in `spi_timing_config.h`. TODO: IDF-3663
|
||||
if (consecutive_length <= 2 || consecutive_length >= 6) {
|
||||
//tuning is FAIL, select default point, and generate a warning
|
||||
best_point = configs->default_config_id;
|
||||
ESP_DRAM_LOGW(TAG, "tuning fail, best point is fallen back to index %"PRIu32"", best_point);
|
||||
} else if (consecutive_length <= 4) {
|
||||
//consecutive length : 3 or 4
|
||||
best_point = end - 1;
|
||||
ESP_DRAM_LOGD(TAG, "tuning success, best point is index %"PRIu32"", best_point);
|
||||
} else {
|
||||
//consecutive point list length equals 5
|
||||
best_point = end - 2;
|
||||
ESP_DRAM_LOGD(TAG, "tuning success, best point is index %"PRIu32"", best_point);
|
||||
}
|
||||
|
||||
return best_point;
|
||||
|
||||
#elif (MSPI_TIMING_CORE_CLOCK_MHZ == 240)
|
||||
|
||||
uint32_t best_point = 0;
|
||||
uint32_t current_point = end + 1 - consecutive_length;
|
||||
bool ret = false;
|
||||
|
||||
//This `max_freq` is the max pll frequency that per MSPI timing tuning config can work
|
||||
uint32_t temp_max_freq = 0;
|
||||
uint32_t temp_min_freq = 0;
|
||||
|
||||
#if !CONFIG_SPIRAM_TIMING_TUNING_POINT_VIA_TEMPERATURE_SENSOR
|
||||
uint32_t max_freq = 0;
|
||||
for (; current_point <= end; current_point++) {
|
||||
if (is_flash) {
|
||||
mspi_timing_config_flash_set_tuning_regs(configs, current_point);
|
||||
} else {
|
||||
mspi_timing_config_psram_set_tuning_regs(configs, current_point);
|
||||
}
|
||||
|
||||
ret = get_working_pll_freq(reference_data, is_flash, &temp_max_freq, &temp_min_freq);
|
||||
if (ret && temp_min_freq <= MSPI_TIMING_PLL_FREQ_SCAN_THRESH_MHZ_LOW && temp_max_freq >= MSPI_TIMING_PLL_FREQ_SCAN_THRESH_MHZ_HIGH && temp_max_freq > max_freq) {
|
||||
max_freq = temp_max_freq;
|
||||
best_point = current_point;
|
||||
}
|
||||
ESP_DRAM_LOGD(TAG, "sample point %" PRIu32 ", max pll is %" PRIu32 " mhz, min pll is %" PRIu32, current_point, temp_max_freq, temp_min_freq);
|
||||
}
|
||||
if (max_freq == 0) {
|
||||
ESP_DRAM_LOGW(TAG, "freq scan tuning fail, best point is fallen back to index %" PRIu32, end + 1 - consecutive_length);
|
||||
best_point = end + 1 - consecutive_length;
|
||||
} else {
|
||||
ESP_DRAM_LOGD(TAG, "freq scan success, max pll is %" PRIu32 "mhz, best point is index %" PRIu32, max_freq, best_point);
|
||||
}
|
||||
#else
|
||||
uint32_t freq_diff_min = 0xffffffff;
|
||||
for (; current_point <= end; current_point++) {
|
||||
if (is_flash) {
|
||||
mspi_timing_config_flash_set_tuning_regs(configs, current_point);
|
||||
} else {
|
||||
mspi_timing_config_psram_set_tuning_regs(configs, current_point);
|
||||
}
|
||||
|
||||
ret = get_working_pll_freq(reference_data, is_flash, &temp_max_freq, &temp_min_freq);
|
||||
if (ret == true) {
|
||||
if (temp_min_freq == MSPI_TIMING_PLL_FREQ_SCAN_RANGE_MHZ_MIN) {
|
||||
// divided by 4 for mspi clk frequency
|
||||
psram_pass_freq_min[current_point] = (temp_max_freq - MSPI_TIMING_PLL_FREQ_SCAN_WIDTH_MHZ) / 4; // use MSPI_TIMING_PLL_FREQ_SCAN_WIDTH_MHZ to calculate the real frequency
|
||||
psram_pass_freq_max[current_point] = temp_max_freq / 4;
|
||||
} else if (temp_max_freq == MSPI_TIMING_PLL_FREQ_SCAN_RANGE_MHZ_MAX) {
|
||||
psram_pass_freq_min[current_point] = temp_min_freq / 4;
|
||||
psram_pass_freq_max[current_point] = (temp_min_freq + MSPI_TIMING_PLL_FREQ_SCAN_WIDTH_MHZ) / 4; // use MSPI_TIMING_PLL_FREQ_SCAN_WIDTH_MHZ to calculate the real frequency
|
||||
} else {
|
||||
psram_pass_freq_min[current_point] = temp_min_freq / 4;
|
||||
psram_pass_freq_max[current_point] = temp_max_freq / 4;
|
||||
}
|
||||
ESP_DRAM_LOGD(TAG, "sample point %" PRIu32 ", max pll is %" PRIu32 " mhz, min pll is %" PRIu32 " mhz, max spi is %" PRIu32 " mhz, min spi is %" PRIu32 " mhz", current_point, temp_max_freq, temp_min_freq, psram_pass_freq_max[current_point], psram_pass_freq_min[current_point]);
|
||||
|
||||
// calculate the difference to psram_pass_freq and 120MHz
|
||||
int temp_min_freq_diff = abs(120 - psram_pass_freq_min[current_point]);
|
||||
int temp_max_freq_diff = abs(psram_pass_freq_max[current_point] - 120);
|
||||
|
||||
if (abs(temp_min_freq_diff - temp_max_freq_diff) < freq_diff_min) {
|
||||
freq_diff_min = abs(temp_min_freq_diff - temp_max_freq_diff);
|
||||
best_point = current_point;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (freq_diff_min == 0xffffffff) {
|
||||
ESP_DRAM_LOGW(TAG, "freq scan tuning fail, best point is fallen back to index %" PRIu32, end + 1 - consecutive_length);
|
||||
best_point = end + 1 - consecutive_length;
|
||||
} else {
|
||||
ESP_DRAM_LOGD(TAG, "freq scan success, best point is index %" PRIu32, best_point);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return best_point;
|
||||
|
||||
#else
|
||||
//won't reach here
|
||||
abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
static uint32_t s_select_best_tuning_config_str(const mspi_timing_config_t *configs, uint32_t consecutive_length, uint32_t end)
|
||||
{
|
||||
#if (MSPI_TIMING_CORE_CLOCK_MHZ == 120 || MSPI_TIMING_CORE_CLOCK_MHZ == 240)
|
||||
//STR best point scheme
|
||||
uint32_t best_point;
|
||||
|
||||
if (consecutive_length <= 2|| consecutive_length >= 5) {
|
||||
//tuning is FAIL, select default point, and generate a warning
|
||||
best_point = configs->default_config_id;
|
||||
ESP_DRAM_LOGW(TAG, "tuning fail, best point is fallen back to index %"PRIu32"", best_point);
|
||||
} else {
|
||||
//consecutive length : 3 or 4
|
||||
best_point = end - consecutive_length / 2;
|
||||
ESP_DRAM_LOGD(TAG, "tuning success, best point is index %"PRIu32"", best_point);
|
||||
}
|
||||
|
||||
return best_point;
|
||||
#else
|
||||
//won't reach here
|
||||
abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
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) {
|
||||
best_point = s_select_best_tuning_config_dtr(configs, consecutive_length, end, reference_data, is_flash);
|
||||
} 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_DRAM_LOGD(TAG, "Flash timing tuning index: %"PRIu32"", best_point);
|
||||
|
||||
return best_point;
|
||||
}
|
||||
|
||||
uint32_t mspi_timing_psram_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, false);
|
||||
ESP_DRAM_LOGD(TAG, "PSRAM 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(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(0, 0);
|
||||
|
||||
//Won't touch SPI1 registers if not control_both_mspi
|
||||
if (control_both_mspi) {
|
||||
s_set_flash_extra_dummy(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(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(1, s_flash_best_timing_tuning_config.extra_dummy_len);
|
||||
} else {
|
||||
//Won't touch SPI1 registers
|
||||
}
|
||||
}
|
||||
|
||||
void mspi_timing_psram_config_clear_tuning_regs(bool control_both_mspi)
|
||||
{
|
||||
(void)control_both_mspi; //for compatibility
|
||||
s_set_psram_din_mode_num(0, 0, 0);
|
||||
s_set_psram_extra_dummy(0, 0);
|
||||
}
|
||||
|
||||
void mspi_timing_psram_config_set_tuning_regs(bool control_both_mspi)
|
||||
{
|
||||
(void)control_both_mspi; //for compatibility
|
||||
s_set_psram_din_mode_num(0, s_psram_best_timing_tuning_config.spi_din_mode, s_psram_best_timing_tuning_config.spi_din_num);
|
||||
s_set_psram_extra_dummy(0, s_psram_best_timing_tuning_config.extra_dummy_len);
|
||||
}
|
||||
#endif //#if MSPI_TIMING_FLASH_NEEDS_TUNING || MSPI_TIMING_PSRAM_NEEDS_TUNING
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------------------------------
|
||||
* 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-S3, 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(0);
|
||||
*hold_time = mspi_timing_ll_get_cs_hold_val(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(0)) {
|
||||
*setup_time += 1;
|
||||
} else {
|
||||
*setup_time = 0;
|
||||
}
|
||||
if (mspi_timing_ll_is_cs_hold_enabled(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(1);
|
||||
}
|
||||
|
||||
uint8_t mspi_timing_config_get_flash_extra_dummy(void)
|
||||
{
|
||||
#if MSPI_TIMING_FLASH_NEEDS_TUNING
|
||||
return s_flash_best_timing_tuning_config.extra_dummy_len;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if CONFIG_SPIRAM_TIMING_TUNING_POINT_VIA_TEMPERATURE_SENSOR
|
||||
|
||||
#define INTERVAL_IN_SECOND CONFIG_SPIRAM_TIMING_MEASURE_TEMPERATURE_INTERVAL_SECOND
|
||||
|
||||
// These arrays store the frequency scan result of the timing points
|
||||
static int s_point_temp_range_min[MSPI_TIMING_CONFIG_NUM_MAX] = {0};
|
||||
static int s_point_temp_range_max[MSPI_TIMING_CONFIG_NUM_MAX] = {0};
|
||||
static uint32_t s_psram_best_point_idx = 0;
|
||||
|
||||
void mspi_timing_setting_temperature_adjustment_best_point(uint32_t best_point)
|
||||
{
|
||||
s_psram_best_point_idx = best_point;
|
||||
}
|
||||
|
||||
static void mspi_timing_set_psram_point_idx(uint32_t point_idx)
|
||||
{
|
||||
mspi_timing_config_t timing_configs = {0};
|
||||
s_psram_best_point_idx = point_idx;
|
||||
mspi_timing_get_psram_tuning_configs(&timing_configs);
|
||||
|
||||
mspi_timing_psram_set_best_tuning_config(&timing_configs, point_idx);
|
||||
mspi_timing_config_psram_set_tuning_regs(&timing_configs, point_idx);
|
||||
}
|
||||
|
||||
static void set_timing_point(uint32_t point_idx)
|
||||
{
|
||||
// Disable cache in order that cache would not touch psram
|
||||
spi_flash_disable_interrupts_caches_and_other_cpu();
|
||||
mspi_timing_set_psram_point_idx(point_idx);
|
||||
spi_flash_enable_interrupts_caches_and_other_cpu();
|
||||
}
|
||||
|
||||
// A mean filter with window to make the temperature value smoother
|
||||
static esp_err_t temperature_sensor_get_celsius_filtered(int16_t *temp_filtered)
|
||||
{
|
||||
const int filter_window_len = 7;
|
||||
int16_t temp_arr[filter_window_len];
|
||||
int16_t temp_sum = 0;
|
||||
uint8_t temp_min_idx = 0;
|
||||
uint8_t temp_max_idx = 0;
|
||||
|
||||
for (uint8_t idx = 0; idx < filter_window_len; idx++) {
|
||||
temp_arr[idx] = temp_sensor_get_raw_value(NULL);
|
||||
// record the index of the max and min temperature value
|
||||
if (temp_arr[idx] > temp_arr[temp_max_idx]) temp_max_idx = idx;
|
||||
if (temp_arr[idx] < temp_arr[temp_min_idx]) temp_min_idx = idx;
|
||||
temp_sum += temp_arr[idx];
|
||||
}
|
||||
// remove the max and min temperature value
|
||||
temp_sum -= temp_arr[temp_max_idx];
|
||||
temp_sum -= temp_arr[temp_min_idx];
|
||||
*temp_filtered = temp_sum / (filter_window_len - 2); // Don't calculate the temp_max and temp_min
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* This task will:
|
||||
* 1. Calculate temperature ranges of timing points
|
||||
* 2. Monitor current temperature
|
||||
* 3. Switch timing point if temperature is beyond the range
|
||||
*/
|
||||
void adjust_psram_timing_point_task(void *arg)
|
||||
{
|
||||
int16_t temp_refer = 0, temp_curr = 0;
|
||||
(void)arg;
|
||||
temperature_sensor_power_acquire();
|
||||
temperature_sensor_get_celsius_filtered(&temp_refer); // get the refer temperature
|
||||
|
||||
int temperature_freq_radio = 5; // It means that the frequency will reduce by 1MHz when the temperature rises 5℃
|
||||
const int temperature_safe_range = 5; // A temperature buffer zone to avoid switching timing points frequently
|
||||
// make sure the frequency of current timing point is greater than freq_thres_max and less than freq_thres_min
|
||||
const int freq_thres_max = 128; // threshold for maximum threshold frequency in specific temperature, should not change
|
||||
const int freq_thres_min = 112; // threshold for minimum threshold frequency in specific temperature, should not change
|
||||
int point_curr = s_psram_best_point_idx;
|
||||
bool valid_point[MSPI_TIMING_CONFIG_NUM_MAX] = {false};
|
||||
|
||||
// 1. Get the delta of frequency we get at the specific temperature (freq_min) with the frequency min threshold (freq_diff = freq_thres_min - freq_min)
|
||||
// 2. Convert frequency difference to temperature difference by radio (5), temperature_diff = freq_diff * radio
|
||||
// 3. Calculate the range of temperature: temperature_thre_min = freq_min - temperature_diff
|
||||
// Same for the temperature_thre_max.
|
||||
|
||||
// calculate temperature ranges of the every timing point
|
||||
for (uint32_t point = 0; point < MSPI_TIMING_CONFIG_NUM_MAX; point++) {
|
||||
if (psram_pass_freq_min[point] == 0 && psram_pass_freq_max[point] == 0) {
|
||||
continue;
|
||||
}
|
||||
valid_point[point] = true;
|
||||
uint32_t pass_freq_min = psram_pass_freq_min[point];
|
||||
uint32_t pass_freq_max = psram_pass_freq_max[point];
|
||||
|
||||
if (pass_freq_max >= freq_thres_max) {
|
||||
// frequency pass_freq_max greater than freq_thres_max, it will decrease to freq_thres_max until temperature rise to s_point_temp_range_max
|
||||
s_point_temp_range_max[point] = temp_refer + (pass_freq_max - freq_thres_max) * temperature_freq_radio;
|
||||
} else {
|
||||
// frequency pass_freq_max less than freq_thres_max, it will increase to freq_thres_max until temperature drop to s_point_temp_range_max
|
||||
s_point_temp_range_max[point] = temp_refer - (freq_thres_max - pass_freq_max) * temperature_freq_radio;
|
||||
}
|
||||
|
||||
if (pass_freq_min <= freq_thres_min) {
|
||||
// frequency pass_freq_min less than freq_thres_min, it will increase to freq_thres_min until temperature drop to s_point_temp_range_min
|
||||
s_point_temp_range_min[point] = temp_refer - (freq_thres_min - pass_freq_min) * temperature_freq_radio;
|
||||
} else {
|
||||
// frequency pass_freq_min greater than freq_thres_min, it will decrease to freq_thres_min until temperature rise to s_point_temp_range_min
|
||||
s_point_temp_range_min[point] = temp_refer + (pass_freq_min - freq_thres_min) * temperature_freq_radio;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t point = 0; point < MSPI_TIMING_CONFIG_NUM_MAX - 1; point++) {
|
||||
if (valid_point[point] && valid_point[point + 1]) {
|
||||
// check temperature intersection
|
||||
if (s_point_temp_range_max[point] <= s_point_temp_range_min[point + 1]) {
|
||||
ESP_DRAM_LOGE(TAG, "no temperature intersection of neighboring phase points");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (1) {
|
||||
vTaskDelay(INTERVAL_IN_SECOND * 1000 / portTICK_PERIOD_MS);
|
||||
|
||||
point_curr = s_psram_best_point_idx;
|
||||
temperature_sensor_get_celsius_filtered(&temp_curr);
|
||||
ESP_DRAM_LOGD(TAG, "Getting current temperature value is: %d", temp_curr);
|
||||
|
||||
// Switch timing point if temperature is beyond the range
|
||||
if (s_point_temp_range_max[point_curr] == 0 && s_point_temp_range_min[point_curr] == 0) {
|
||||
// The current timing point has no frequency scan result (psram_pass_freq_min and psram_pass_freq_min equal to 0),
|
||||
// use the previous or next timing point's temperature range to decide what temperature to switch timing point.
|
||||
|
||||
// Use previous timing point's temperature range
|
||||
|
||||
if (point_curr - 1 >= 0) {
|
||||
if (s_point_temp_range_max[point_curr - 1] != 0 && s_point_temp_range_min[point_curr - 1] != 0) {
|
||||
if (temp_curr < (s_point_temp_range_max[point_curr - 1] - temperature_safe_range)) {
|
||||
int point_next = point_curr - 1;
|
||||
set_timing_point(point_next);
|
||||
ESP_DRAM_LOGD(TAG, "PSRAM set timing point from %d to %ld\n", point_curr, point_next);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Use next timing point's temperature range
|
||||
if (point_curr + 1 < MSPI_TIMING_CONFIG_NUM_MAX) {
|
||||
if (s_point_temp_range_max[point_curr + 1] != 0 && s_point_temp_range_min[point_curr + 1] != 0) {
|
||||
if (temp_curr > s_point_temp_range_min[point_curr + 1] + temperature_safe_range) {
|
||||
int point_next = point_curr + 1;
|
||||
set_timing_point(point_next);
|
||||
ESP_DRAM_LOGD(TAG, "PSRAM set timing point from %d to %ld\n", point_curr, point_next);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Current temperature is greater than the range, switch to next timing point
|
||||
if (point_curr + 1 < MSPI_TIMING_CONFIG_NUM_MAX) {
|
||||
if (temp_curr > s_point_temp_range_max[point_curr]) {
|
||||
int point_next = point_curr + 1;
|
||||
set_timing_point(point_next);
|
||||
ESP_DRAM_LOGD(TAG, "PSRAM set timing point from %d to %ld\n", point_curr, point_next);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Current temperature is less than the range, switch to previous timing point
|
||||
if (point_curr - 1 >= 0) {
|
||||
if (temp_curr < s_point_temp_range_min[point_curr]) {
|
||||
int point_next = point_curr - 1;
|
||||
set_timing_point(point_next);
|
||||
ESP_DRAM_LOGD(TAG, "PSRAM set timing point from %d to %ld\n", point_curr, point_next);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static esp_err_t psram_adjust_timing_point_via_tsens(void)
|
||||
{
|
||||
esp_rom_spiflash_chip_t *chip = &rom_spiflash_legacy_data->chip;
|
||||
uint8_t vender_id = (chip->device_id >> 16) & 0xff;
|
||||
if (vender_id == 0xC8 || vender_id == 0x20) {
|
||||
xTaskCreatePinnedToCore(adjust_psram_timing_point_task, "adjust_psram_timing_point_task", 1024 * 5, NULL, configMAX_PRIORITIES - 2, NULL, 0);
|
||||
} else {
|
||||
ESP_DRAM_LOGE(TAG, "The flash model has not been verified support this feature, please contact espressif business support");
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
ESP_SYSTEM_INIT_FN(psram_adjust_timing_point_via_temperature, SECONDARY, BIT(0), 240)
|
||||
{
|
||||
return psram_adjust_timing_point_via_tsens();
|
||||
}
|
||||
|
||||
#endif //CONFIG_SPIRAM_TIMING_TUNING_POINT_VIA_TEMPERATURE_SENSOR
|
||||
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_types.h"
|
||||
#include "esp_log.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "esp_private/mspi_timing_config.h"
|
||||
#include "mspi_timing_tuning_configs.h"
|
||||
#include "hal/mspi_ll.h"
|
||||
|
||||
#define FLASH_LOW_SPEED_CORE_CLOCK_MHZ MSPI_TIMING_LL_CORE_CLOCK_MHZ_DEFAULT
|
||||
#define FLASH_HIGH_SPEED_CORE_CLOCK_MHZ MSPI_TIMING_CORE_CLOCK_MHZ
|
||||
#define PSRAM_LOW_SPEED_CORE_CLOCK_MHZ MSPI_TIMING_LL_CORE_CLOCK_MHZ_DEFAULT
|
||||
#define PSRAM_HIGH_SPEED_CORE_CLOCK_MHZ MSPI_TIMING_CORE_CLOCK_MHZ
|
||||
|
||||
/**
|
||||
* Currently we only need these on chips with timing tuning
|
||||
*/
|
||||
//-------------------------------------MSPI Clock Setting-------------------------------------//
|
||||
static void s_mspi_flash_set_core_clock(uint8_t spi_num, uint32_t core_clock_mhz)
|
||||
{
|
||||
mspi_timing_ll_set_core_clock(spi_num, core_clock_mhz);
|
||||
}
|
||||
|
||||
static void s_mspi_psram_set_core_clock(uint8_t spi_num, uint32_t core_clock_mhz)
|
||||
{
|
||||
mspi_timing_ll_set_core_clock(spi_num, core_clock_mhz);
|
||||
}
|
||||
|
||||
void mspi_timing_config_set_flash_clock(uint32_t flash_freq_mhz, mspi_timing_speed_mode_t speed_mode, bool control_both_mspi)
|
||||
{
|
||||
uint32_t core_clock_mhz = 0;
|
||||
if (speed_mode == MSPI_TIMING_SPEED_MODE_LOW_PERF) {
|
||||
core_clock_mhz = FLASH_LOW_SPEED_CORE_CLOCK_MHZ;
|
||||
} else {
|
||||
core_clock_mhz = FLASH_HIGH_SPEED_CORE_CLOCK_MHZ;
|
||||
}
|
||||
//SPI0 and SPI1 share the register for core clock. So we only set SPI0 here.
|
||||
s_mspi_flash_set_core_clock(0, core_clock_mhz);
|
||||
|
||||
uint32_t freqdiv = core_clock_mhz / flash_freq_mhz;
|
||||
assert(freqdiv > 0);
|
||||
mspi_timing_ll_set_flash_clock(0, freqdiv);
|
||||
if (control_both_mspi) {
|
||||
mspi_timing_ll_set_flash_clock(1, freqdiv);
|
||||
}
|
||||
}
|
||||
|
||||
void mspi_timing_config_set_psram_clock(uint32_t psram_freq_mhz, mspi_timing_speed_mode_t speed_mode, bool control_both_mspi)
|
||||
{
|
||||
(void)control_both_mspi; // for compatibility
|
||||
uint32_t core_clock_mhz = 0;
|
||||
if (speed_mode == MSPI_TIMING_SPEED_MODE_LOW_PERF) {
|
||||
core_clock_mhz = PSRAM_LOW_SPEED_CORE_CLOCK_MHZ;
|
||||
} else {
|
||||
core_clock_mhz = PSRAM_HIGH_SPEED_CORE_CLOCK_MHZ;
|
||||
}
|
||||
//SPI0 and SPI1 share the register for core clock. So we only set SPI0 here.
|
||||
s_mspi_psram_set_core_clock(0, core_clock_mhz);
|
||||
|
||||
uint32_t freqdiv = core_clock_mhz / psram_freq_mhz;
|
||||
assert(freqdiv > 0);
|
||||
mspi_timing_ll_set_psram_clock(0, freqdiv);
|
||||
}
|
||||
-272
@@ -1,272 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_assert.h"
|
||||
#include "esp_flash_partitions.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define MSPI_TIMING_MSPI1_IS_INVOLVED 1 //This means esp flash driver needs to be notified
|
||||
#define MSPI_TIMING_CONFIG_NUM_MAX 20 //This should be larger than the max available timing config num
|
||||
#define MSPI_TIMING_TEST_DATA_LEN 64
|
||||
#define MSPI_TIMING_PSRAM_TEST_DATA_ADDR 0
|
||||
#define MSPI_TIMING_FLASH_TEST_DATA_ADDR ESP_BOOTLOADER_OFFSET
|
||||
/**
|
||||
* @note BACKGROUND:
|
||||
*
|
||||
* The SPI FLASH module clock and SPI PSRAM module clock is divided from the SPI core clock, core clock is from system clock:
|
||||
*
|
||||
* PLL ----| |---- FLASH Module Clock
|
||||
* XTAL ----|----> Core Clock ---->|
|
||||
* RTC8M ----| |---- PSRAM Module Clock
|
||||
*
|
||||
*
|
||||
* DDR stands for double data rate, MSPI samples at both posedge and negedge. So the real speed will be doubled.
|
||||
* Speed from high to low: 120M DDR > 80M DDR > 120 SDR > 80M SDR > ...
|
||||
*
|
||||
* Module with speed lower than 120M SDR doesn't need to be tuned
|
||||
*
|
||||
* @note LIMITATION:
|
||||
* How to determine the core clock on 728. There are 2 limitations.
|
||||
*
|
||||
* 1. MSPI FLASH and PSRAM share the core clock register. Therefore:
|
||||
* MSPI_TIMING_FLASH_EXPECTED_CORE_CLK_MHZ == MSPI_TIMING_PSRAM_EXPECTED_CORE_CLK_MHZ
|
||||
*
|
||||
* 2. DDR mode requires the core clock divider (core_clk / div = module_clk) to be power of 2.
|
||||
*/
|
||||
//--------------------------------------FLASH Sampling Mode --------------------------------------//
|
||||
#define MSPI_TIMING_FLASH_DTR_MODE CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_DTR
|
||||
#define MSPI_TIMING_FLASH_STR_MODE CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_STR
|
||||
//--------------------------------------FLASH Module Clock --------------------------------------//
|
||||
#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
|
||||
//------------------------------------FLASH Needs Tuning or not-------------------------------------//
|
||||
#if MSPI_TIMING_FLASH_DTR_MODE
|
||||
#define MSPI_TIMING_FLASH_NEEDS_TUNING (MSPI_TIMING_FLASH_MODULE_CLOCK > 40)
|
||||
#elif MSPI_TIMING_FLASH_STR_MODE
|
||||
#define MSPI_TIMING_FLASH_NEEDS_TUNING (MSPI_TIMING_FLASH_MODULE_CLOCK > 80)
|
||||
#endif
|
||||
|
||||
//--------------------------------------PSRAM Sampling Mode --------------------------------------//
|
||||
#define MSPI_TIMING_PSRAM_DTR_MODE CONFIG_SPIRAM_MODE_OCT
|
||||
#define MSPI_TIMING_PSRAM_STR_MODE !CONFIG_SPIRAM_MODE_OCT
|
||||
//--------------------------------------PSRAM Module Clock --------------------------------------//
|
||||
#if CONFIG_SPIRAM
|
||||
#if CONFIG_SPIRAM_SPEED_40M
|
||||
#define MSPI_TIMING_PSRAM_MODULE_CLOCK 40
|
||||
#elif CONFIG_SPIRAM_SPEED_80M
|
||||
#define MSPI_TIMING_PSRAM_MODULE_CLOCK 80
|
||||
#else //CONFIG_SPIRAM_SPEED_120M
|
||||
#define MSPI_TIMING_PSRAM_MODULE_CLOCK 120
|
||||
#endif
|
||||
#else //Disable PSRAM
|
||||
#define MSPI_TIMING_PSRAM_MODULE_CLOCK 10 //Define this to 10MHz, because we rely on `MSPI_TIMING_PSRAM_MODULE_CLOCK` macro for calculation and check below, see `Determine the Core Clock` chapter
|
||||
#endif
|
||||
//------------------------------------PSRAM Needs Tuning or not-------------------------------------//
|
||||
#if MSPI_TIMING_PSRAM_DTR_MODE
|
||||
#define MSPI_TIMING_PSRAM_NEEDS_TUNING (MSPI_TIMING_PSRAM_MODULE_CLOCK > 40)
|
||||
#elif MSPI_TIMING_PSRAM_STR_MODE
|
||||
#define MSPI_TIMING_PSRAM_NEEDS_TUNING (MSPI_TIMING_PSRAM_MODULE_CLOCK > 80)
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* @note Define A feasible core clock below: MSPI_TIMING_FLASH_EXPECTED_CORE_CLK_MHZ and MSPI_TIMING_PSRAM_EXPECTED_CORE_CLK_MHZ
|
||||
*/
|
||||
/**
|
||||
* Due to MSPI core clock is used by both MSPI Flash and PSRAM clock,
|
||||
* define the STR/DTR mode here for selecting the core clock:
|
||||
* @note If either Flash or PSRAM, or both of them are set to DTR mode, then we use DIV 2
|
||||
*/
|
||||
#if (MSPI_TIMING_FLASH_DTR_MODE || MSPI_TIMING_PSRAM_DTR_MODE)
|
||||
#define MSPI_TIMING_CORE_CLOCK_DIV 2
|
||||
#else //#if (MSPI_TIMING_FLASH_STR_MODE && (MSPI_TIMING_PSRAM_STR_MODE))
|
||||
#define MSPI_TIMING_CORE_CLOCK_DIV 1
|
||||
#endif
|
||||
|
||||
///////////////////////////////////// FLASH CORE CLOCK /////////////////////////////////////
|
||||
//FLASH 80M DTR
|
||||
#if MSPI_TIMING_FLASH_DTR_MODE && CONFIG_ESPTOOLPY_FLASHFREQ_80M
|
||||
#define MSPI_TIMING_FLASH_EXPECTED_CORE_CLK_MHZ 160
|
||||
#endif
|
||||
|
||||
//FLASH 120M DTR
|
||||
#if MSPI_TIMING_FLASH_DTR_MODE && CONFIG_ESPTOOLPY_FLASHFREQ_120M
|
||||
#define MSPI_TIMING_FLASH_EXPECTED_CORE_CLK_MHZ 240
|
||||
#endif
|
||||
|
||||
//FLASH 120M STR
|
||||
#if MSPI_TIMING_FLASH_STR_MODE && CONFIG_ESPTOOLPY_FLASHFREQ_120M
|
||||
#if (MSPI_TIMING_CORE_CLOCK_DIV == 2)
|
||||
#define MSPI_TIMING_FLASH_EXPECTED_CORE_CLK_MHZ 240
|
||||
#elif (MSPI_TIMING_CORE_CLOCK_DIV == 1)
|
||||
#define MSPI_TIMING_FLASH_EXPECTED_CORE_CLK_MHZ 120
|
||||
#endif
|
||||
#endif //FLASH 120M STR
|
||||
|
||||
///////////////////////////////////// PSRAM CORE CLOCK /////////////////////////////////////
|
||||
//PSRAM 80M DTR
|
||||
#if MSPI_TIMING_PSRAM_DTR_MODE && CONFIG_SPIRAM_SPEED_80M
|
||||
#define MSPI_TIMING_PSRAM_EXPECTED_CORE_CLK_MHZ 160
|
||||
#endif
|
||||
|
||||
//PSRAM 120M STR
|
||||
#if MSPI_TIMING_PSRAM_STR_MODE && CONFIG_SPIRAM_SPEED_120M
|
||||
#if (MSPI_TIMING_CORE_CLOCK_DIV == 2)
|
||||
#define MSPI_TIMING_PSRAM_EXPECTED_CORE_CLK_MHZ 240
|
||||
#elif (MSPI_TIMING_CORE_CLOCK_DIV == 1)
|
||||
#define MSPI_TIMING_PSRAM_EXPECTED_CORE_CLK_MHZ 120
|
||||
#endif
|
||||
#endif //PSRAM 120M STR
|
||||
|
||||
//PSRAM 120M STR
|
||||
#if MSPI_TIMING_PSRAM_DTR_MODE && CONFIG_SPIRAM_SPEED_120M
|
||||
#define MSPI_TIMING_PSRAM_EXPECTED_CORE_CLK_MHZ 240
|
||||
#endif //PSRAM 120M DTR
|
||||
|
||||
|
||||
//------------------------------------------Determine the Core Clock-----------------------------------------------//
|
||||
/**
|
||||
* @note
|
||||
* Limitation 1:
|
||||
* On 728, MSPI FLASH and PSRAM share the core clock register. Therefore,
|
||||
* the expected CORE CLOCK frequencies should be the same.
|
||||
*/
|
||||
#if MSPI_TIMING_FLASH_NEEDS_TUNING && MSPI_TIMING_PSRAM_NEEDS_TUNING
|
||||
ESP_STATIC_ASSERT(MSPI_TIMING_FLASH_EXPECTED_CORE_CLK_MHZ == MSPI_TIMING_PSRAM_EXPECTED_CORE_CLK_MHZ, "FLASH and PSRAM Mode configuration are not supported");
|
||||
#define MSPI_TIMING_CORE_CLOCK_MHZ MSPI_TIMING_FLASH_EXPECTED_CORE_CLK_MHZ
|
||||
|
||||
//If only FLASH needs tuning, the core clock COULD be as FLASH expected
|
||||
#elif MSPI_TIMING_FLASH_NEEDS_TUNING && !MSPI_TIMING_PSRAM_NEEDS_TUNING
|
||||
ESP_STATIC_ASSERT(MSPI_TIMING_FLASH_EXPECTED_CORE_CLK_MHZ % MSPI_TIMING_PSRAM_MODULE_CLOCK == 0, "FLASH and PSRAM Mode configuration are not supported");
|
||||
#define MSPI_TIMING_CORE_CLOCK_MHZ MSPI_TIMING_FLASH_EXPECTED_CORE_CLK_MHZ
|
||||
|
||||
//If only PSRAM needs tuning, the core clock COULD be as PSRAM expected
|
||||
#elif !MSPI_TIMING_FLASH_NEEDS_TUNING && MSPI_TIMING_PSRAM_NEEDS_TUNING
|
||||
ESP_STATIC_ASSERT(MSPI_TIMING_PSRAM_EXPECTED_CORE_CLK_MHZ % MSPI_TIMING_FLASH_MODULE_CLOCK == 0, "FLASH and PSRAM Mode configuration are not supported");
|
||||
#define MSPI_TIMING_CORE_CLOCK_MHZ MSPI_TIMING_PSRAM_EXPECTED_CORE_CLK_MHZ
|
||||
|
||||
#else
|
||||
#define MSPI_TIMING_CORE_CLOCK_MHZ 80
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @note
|
||||
* Limitation 2: DDR mode requires the core clock divider (core_clk / div = module_clk) to be power of 2.
|
||||
*/
|
||||
#define CHECK_POWER_OF_2(n) ((((n) & ((~(n)) + 1))) == (n))
|
||||
|
||||
#if MSPI_TIMING_FLASH_DTR_MODE
|
||||
ESP_STATIC_ASSERT(CHECK_POWER_OF_2(MSPI_TIMING_CORE_CLOCK_MHZ / MSPI_TIMING_FLASH_MODULE_CLOCK), "FLASH and PSRAM Mode configuration are not supported");
|
||||
#endif
|
||||
#if MSPI_TIMING_PSRAM_DTR_MODE
|
||||
ESP_STATIC_ASSERT(CHECK_POWER_OF_2(MSPI_TIMING_CORE_CLOCK_MHZ / MSPI_TIMING_PSRAM_MODULE_CLOCK), "FLASH and PSRAM Mode configuration are not supported");
|
||||
#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, \
|
||||
.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)
|
||||
#define MSPI_TIMING_PSRAM_GET_TUNING_CONFIG(core_clock_mhz, module_clock_mhz, mode) _GET_TUNING_CONFIG(PSRAM, core_clock_mhz, module_clock_mhz, mode)
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Timing Tuning Parameters
|
||||
*/
|
||||
//FLASH: core clock 160M, module clock 40M, DTR mode
|
||||
#define MSPI_TIMING_FLASH_CONFIG_TABLE_CORE_CLK_160M_MODULE_CLK_40M_DTR_MODE {{1, 0, 0}, {0, 0, 0}, {2, 1, 1}, {2, 0, 1}, {2, 2, 2}, {2, 1, 2}, {1, 0, 1}, {0, 0, 1}}
|
||||
#define MSPI_TIMING_FLASH_CONFIG_NUM_CORE_CLK_160M_MODULE_CLK_40M_DTR_MODE 8
|
||||
#define MSPI_TIMING_FLASH_DEFAULT_CONFIG_ID_CORE_CLK_160M_MODULE_CLK_40M_DTR_MODE 2
|
||||
|
||||
//FLASH: core clock 160M, module clock 80M, DTR mode
|
||||
#define MSPI_TIMING_FLASH_CONFIG_TABLE_CORE_CLK_160M_MODULE_CLK_80M_DTR_MODE {{0, 0, 0}, {4, 2, 2}, {2, 1, 2}, {4, 1, 2}, {1, 0, 1}, {4, 0, 2}, {0, 0, 1}, {4, 2, 3}, {2, 1, 3}, {4, 1, 3}, {1, 0, 2}, {4, 0, 3}, {0, 0, 2}, {4, 2, 4}}
|
||||
#define MSPI_TIMING_FLASH_CONFIG_NUM_CORE_CLK_160M_MODULE_CLK_80M_DTR_MODE 14
|
||||
#define MSPI_TIMING_FLASH_DEFAULT_CONFIG_ID_CORE_CLK_160M_MODULE_CLK_80M_DTR_MODE 1
|
||||
|
||||
//FLASH: core clock 240M, module clock 120M, DTR mode
|
||||
#define MSPI_TIMING_FLASH_CONFIG_TABLE_CORE_CLK_240M_MODULE_CLK_120M_DTR_MODE {{0, 0, 0}, {4, 1, 2}, {1, 0, 1}, {4, 0, 2}, {0, 0, 1}, {4, 1, 3}, {1, 0, 2}, {4, 0, 3}, {0, 0, 2}, {4, 1, 4}, {1, 0, 3}, {4, 0, 4}, {0, 0, 3}, {4, 1, 5}}
|
||||
#define MSPI_TIMING_FLASH_CONFIG_NUM_CORE_CLK_240M_MODULE_CLK_120M_DTR_MODE 14
|
||||
#define MSPI_TIMING_FLASH_DEFAULT_CONFIG_ID_CORE_CLK_240M_MODULE_CLK_120M_DTR_MODE 1
|
||||
|
||||
//FLASH: core clock 160M, module clock 80M, STR mode
|
||||
#define MSPI_TIMING_FLASH_CONFIG_TABLE_CORE_CLK_160M_MODULE_CLK_80M_STR_MODE {{1, 0, 0}, {0, 0, 0}, {2, 1, 1}, {2, 0, 1}, {2, 2, 2}, {2, 1, 2}, {1, 0, 1}, {0, 0, 1}}
|
||||
#define MSPI_TIMING_FLASH_CONFIG_NUM_CORE_CLK_160M_MODULE_CLK_80M_STR_MODE 8
|
||||
#define MSPI_TIMING_FLASH_DEFAULT_CONFIG_ID_CORE_CLK_160M_MODULE_CLK_80M_STR_MODE 2
|
||||
|
||||
//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}, {1, 0, 1}, {2, 0, 2}, {0, 0, 1}, {2, 2, 3}, {1, 0, 2}, {2, 0, 3}, {0, 0, 2}, {2, 2, 4}, {1, 0, 3}}
|
||||
#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
|
||||
|
||||
//FLASH: core clock 240M, module clock 120M, STR mode
|
||||
#define MSPI_TIMING_FLASH_CONFIG_TABLE_CORE_CLK_240M_MODULE_CLK_120M_STR_MODE {{1, 0, 0}, {0, 0, 0}, {1, 1, 1}, {2, 3, 2}, {1, 0, 1}, {0, 0, 1}, {1, 1, 2}, {2, 3, 3}, {1, 0, 2}, {0, 0, 2}, {1, 1, 3}, {2, 3, 4}}
|
||||
#define MSPI_TIMING_FLASH_CONFIG_NUM_CORE_CLK_240M_MODULE_CLK_120M_STR_MODE 12
|
||||
#define MSPI_TIMING_FLASH_DEFAULT_CONFIG_ID_CORE_CLK_240M_MODULE_CLK_120M_STR_MODE 2
|
||||
|
||||
//PSRAM: core clock 80M, module clock 40M, DTR mode
|
||||
#define MSPI_TIMING_PSRAM_CONFIG_TABLE_CORE_CLK_80M_MODULE_CLK_40M_DTR_MODE {{1, 0, 0}, {2, 1, 1}, {2, 0, 1}, {0, 0, 0}, {3, 1, 1}, {3, 0, 1}, {1, 0, 1}, {2, 1, 2}, {2, 0, 2}, {0, 0, 1}, {3, 1, 2}, {3, 0, 2}}
|
||||
#define MSPI_TIMING_PSRAM_CONFIG_NUM_CORE_CLK_80M_MODULE_CLK_40M_DTR_MODE 12
|
||||
#define MSPI_TIMING_PSRAM_DEFAULT_CONFIG_ID_CORE_CLK_80M_MODULE_CLK_40M_DTR_MODE 4
|
||||
|
||||
//PSRAM: core clock 160M, module clock 80M, DTR mode
|
||||
#define MSPI_TIMING_PSRAM_CONFIG_TABLE_CORE_CLK_160M_MODULE_CLK_80M_DTR_MODE {{0, 0, 0}, {4, 2, 2}, {2, 1, 2}, {4, 1, 2}, {1, 0, 1}, {4, 0, 2}, {0, 0, 1}, {4, 2, 3}, {2, 1, 3}, {4, 1, 3}, {1, 0, 2}, {4, 0, 3}, {0, 0, 2}, {4, 2, 4}}
|
||||
#define MSPI_TIMING_PSRAM_CONFIG_NUM_CORE_CLK_160M_MODULE_CLK_80M_DTR_MODE 14
|
||||
#define MSPI_TIMING_PSRAM_DEFAULT_CONFIG_ID_CORE_CLK_160M_MODULE_CLK_80M_DTR_MODE 5
|
||||
|
||||
//PSRAM: core clock 240M, module clock 120M, STR mode
|
||||
#define MSPI_TIMING_PSRAM_CONFIG_TABLE_CORE_CLK_240M_MODULE_CLK_120M_STR_MODE {{1, 0, 0}, {0, 0, 0}, {1, 1, 1}, {2, 3, 2}, {1, 0, 1}, {0, 0, 1}, {1, 1, 2}, {2, 3, 3}, {1, 0, 2}, {0, 0, 2}, {1, 1, 3}, {2, 3, 4}}
|
||||
#define MSPI_TIMING_PSRAM_CONFIG_NUM_CORE_CLK_240M_MODULE_CLK_120M_STR_MODE 12
|
||||
#define MSPI_TIMING_PSRAM_DEFAULT_CONFIG_ID_CORE_CLK_240M_MODULE_CLK_120M_STR_MODE 2
|
||||
|
||||
//PSRAM: core clock 120M, module clock 120M, STR mode
|
||||
#define MSPI_TIMING_PSRAM_CONFIG_TABLE_CORE_CLK_120M_MODULE_CLK_120M_STR_MODE {{2, 0, 1}, {0, 0, 0}, {2, 2, 2}, {1, 0, 1}, {2, 0, 2}, {0, 0, 1}, {2, 2, 3}, {1, 0, 2}, {2, 0, 3}, {0, 0, 2}, {2, 2, 4}, {1, 0, 3}}
|
||||
#define MSPI_TIMING_PSRAM_CONFIG_NUM_CORE_CLK_120M_MODULE_CLK_120M_STR_MODE 12
|
||||
#define MSPI_TIMING_PSRAM_DEFAULT_CONFIG_ID_CORE_CLK_120M_MODULE_CLK_120M_STR_MODE 2
|
||||
|
||||
|
||||
//PSRAM: core clock 240M, module clock 120M, DTR mode
|
||||
#define MSPI_TIMING_PSRAM_CONFIG_TABLE_CORE_CLK_240M_MODULE_CLK_120M_DTR_MODE {{0, 0, 0}, {4, 1, 2}, {1, 0, 1}, {4, 0, 2}, {0, 0, 1}, {4, 1, 3}, {1, 0, 2}, {4, 0, 3}, {0, 0, 2}, {4, 1, 4}, {1, 0, 3}, {4, 0, 4}, {0, 0, 3}, {4, 1, 5}}
|
||||
#define MSPI_TIMING_PSRAM_CONFIG_NUM_CORE_CLK_240M_MODULE_CLK_120M_DTR_MODE 14
|
||||
#define MSPI_TIMING_PSRAM_DEFAULT_CONFIG_ID_CORE_CLK_240M_MODULE_CLK_120M_DTR_MODE 1
|
||||
|
||||
//------------------------------------------Frequency Scanning Related-----------------------------------------------//
|
||||
/**
|
||||
* On ESP32S3, only module clock 120M, DDR mode needs frequency scan. Frequency scanning is to get the max workable PLL
|
||||
* frequency under each successful timing tuning configuration. PLL frequency may fluctuate under high temperature,
|
||||
* this method is to get the tuning configuration that can work under higher PLL frequency.
|
||||
*/
|
||||
#if CONFIG_SPIRAM_TIMING_TUNING_POINT_VIA_TEMPERATURE_SENSOR
|
||||
#define MSPI_TIMING_PLL_FREQ_SCAN_RANGE_MHZ_MIN 424
|
||||
#else
|
||||
#define MSPI_TIMING_PLL_FREQ_SCAN_RANGE_MHZ_MIN 440
|
||||
#endif
|
||||
#define MSPI_TIMING_PLL_FREQ_SCAN_RANGE_MHZ_MAX 600
|
||||
#define MSPI_TIMING_PLL_FREQ_SCAN_THRESH_MHZ_LOW 448
|
||||
#define MSPI_TIMING_PLL_FREQ_SCAN_THRESH_MHZ_HIGH 520
|
||||
#define MSPI_TIMING_PLL_FREQ_SCAN_WIDTH_MHZ 160
|
||||
#define MSPI_TIMING_PLL_FREQ_SCAN_STEP_MHZ_MODULE_CLK_120M 8
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,11 +0,0 @@
|
||||
target_include_directories(${COMPONENT_LIB} PUBLIC .)
|
||||
|
||||
set(srcs)
|
||||
|
||||
if(NOT BOOTLOADER_BUILD)
|
||||
if(NOT CONFIG_APP_BUILD_TYPE_PURE_RAM_APP)
|
||||
list(APPEND srcs "mspi_timing_config.c")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
target_sources(${COMPONENT_LIB} PRIVATE "${srcs}")
|
||||
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_types.h"
|
||||
#include "esp_log.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
#include "esp_private/mspi_timing_config.h"
|
||||
#include "mspi_timing_tuning_configs.h"
|
||||
#include "hal/psram_ctrlr_ll.h"
|
||||
#include "hal/mspi_ll.h"
|
||||
#include "soc/hp_sys_clkrst_struct.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "MSPI Timing");
|
||||
|
||||
//-------------------------------------MSPI Clock Setting-------------------------------------//
|
||||
void mspi_timing_config_set_psram_clock(uint32_t psram_freq_mhz, mspi_timing_speed_mode_t speed_mode, bool control_both_mspi)
|
||||
{
|
||||
uint32_t freqdiv = MSPI_TIMING_MPLL_FREQ_MHZ / MSPI_TIMING_CORE_CLOCK_DIV / psram_freq_mhz;
|
||||
assert(freqdiv > 0);
|
||||
ESP_DRAM_LOGD(TAG, "psram_freq_mhz: %" PRIu32 " mhz, bus clock div: %" PRIu32, psram_freq_mhz, freqdiv);
|
||||
PERIPH_RCC_ATOMIC() {
|
||||
//MSPI2 and MSPI3 share the register for core clock. So we only set MSPI2 here.
|
||||
psram_ctrlr_ll_enable_core_clock(PSRAM_CTRLR_LL_MSPI_ID_2, true);
|
||||
psram_ctrlr_ll_set_core_clock_div(PSRAM_CTRLR_LL_MSPI_ID_2, MSPI_TIMING_CORE_CLOCK_DIV);
|
||||
psram_ctrlr_ll_set_bus_clock(PSRAM_CTRLR_LL_MSPI_ID_3, freqdiv);
|
||||
psram_ctrlr_ll_set_bus_clock(PSRAM_CTRLR_LL_MSPI_ID_2, freqdiv);
|
||||
}
|
||||
}
|
||||
|
||||
void mspi_timing_config_set_flash_clock(uint32_t flash_freq_mhz, mspi_timing_speed_mode_t speed_mode, bool control_both_mspi)
|
||||
{
|
||||
#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_HP_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
|
||||
}
|
||||
-60
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#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
|
||||
#define MSPI_TIMING_PSRAM_NEEDS_TUNING 1
|
||||
#define MSPI_TIMING_MPLL_FREQ_MHZ 500
|
||||
#elif CONFIG_SPIRAM_SPEED_200M
|
||||
#define MSPI_TIMING_PSRAM_NEEDS_TUNING 1
|
||||
#define MSPI_TIMING_MPLL_FREQ_MHZ 400
|
||||
#elif CONFIG_SPIRAM_SPEED_100M
|
||||
#define MSPI_TIMING_PSRAM_NEEDS_TUNING 1
|
||||
#define MSPI_TIMING_MPLL_FREQ_MHZ 400
|
||||
#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_OCT
|
||||
#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)
|
||||
-164
@@ -1,164 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* This file contains configuration APIs doing MSPI timing tuning by MSPI DQS
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "soc/soc_caps.h"
|
||||
#if SOC_MEMSPI_TIMING_TUNING_BY_DQS
|
||||
#include "esp_private/mspi_timing_impl_types.h"
|
||||
#include "mspi_timing_tuning_configs.h"
|
||||
#include "hal/mspi_ll.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if SOC_MEMSPI_TIMING_TUNING_BY_DQS
|
||||
|
||||
#define IS_DDR 1
|
||||
#define IS_SDR (!IS_DDR)
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------------------------------
|
||||
* Timing Required APIs
|
||||
*-------------------------------------------------------------------------------------------------*/
|
||||
/**
|
||||
* @brief Init MSPI for PSRAM timing tuning
|
||||
*
|
||||
* @param[in] psram_freq_mhz PSRAM frequency in MHz
|
||||
*/
|
||||
void mspi_timing_psram_init(uint32_t psram_freq_mhz);
|
||||
|
||||
/**
|
||||
* @brief Prepare reference data buffer
|
||||
*/
|
||||
void mspi_timing_config_psram_prepare_reference_data(uint8_t *buf, uint32_t len);
|
||||
|
||||
/**
|
||||
* @brief Configure PSRAM to write data via MSPI3
|
||||
*
|
||||
* @param[in] buf buffer
|
||||
* @param[in] addr address
|
||||
* @param[in] len length
|
||||
*/
|
||||
void mspi_timing_config_psram_write_data(uint8_t *buf, uint32_t addr, uint32_t len);
|
||||
|
||||
/**
|
||||
* @brief Configure PSRAM to read data via MSPI3
|
||||
*
|
||||
* @param[out] buf buffer
|
||||
* @param[in] addr address
|
||||
* @param[in] len length
|
||||
*/
|
||||
void mspi_timing_config_psram_read_data(uint8_t *buf, uint32_t addr, uint32_t len);
|
||||
|
||||
/**
|
||||
* @brief Get PSRAM tuning configurations for phase
|
||||
*
|
||||
* @param[out] config Pointer to PSRAM tuning configurations
|
||||
*/
|
||||
void mspi_timing_get_psram_tuning_phases(mspi_timing_config_t *configs);
|
||||
|
||||
/**
|
||||
* @brief Tune PSRAM timing registers for MSPI3 accessing PSRAM
|
||||
*
|
||||
* @param[in] configs Timing configs
|
||||
* @param[in] id Config ID
|
||||
*/
|
||||
void mspi_timing_config_psram_set_tuning_phase(const void *configs, uint8_t id);
|
||||
|
||||
/**
|
||||
* @brief Select PSRAM 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_psram_select_best_tuning_phase(const void *configs, uint32_t consecutive_length, uint32_t end, const uint8_t *reference_data, bool is_ddr);
|
||||
|
||||
/**
|
||||
* @brief Set best PSRAM 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_psram_set_best_tuning_phase(const void *configs, uint8_t best_id);
|
||||
|
||||
/**
|
||||
* @brief Get PSRAM tuning configurations for delayline
|
||||
*
|
||||
* @param[out] config Pointer to PSRAM tuning configurations
|
||||
*/
|
||||
void mspi_timing_get_psram_tuning_delaylines(mspi_timing_config_t *configs);
|
||||
|
||||
/**
|
||||
* @brief Tune PSRAM timing registers for MSPI3 accessing PSRAM
|
||||
*
|
||||
* @param[in] configs Timing configs
|
||||
* @param[in] id Config ID
|
||||
*/
|
||||
void mspi_timing_config_psram_set_tuning_delayline(const void *configs, uint8_t id);
|
||||
|
||||
/**
|
||||
* @brief Select PSRAM 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_psram_select_best_tuning_delayline(const void *configs, uint32_t consecutive_length, uint32_t end, const uint8_t *reference_data, bool is_ddr);
|
||||
|
||||
/**
|
||||
* @brief Set best PSRAM 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_psram_set_best_tuning_delayline(const void *configs, uint8_t best_id);
|
||||
|
||||
/*-------------------------------------------------------------------------------------------------
|
||||
* General Timing APIs
|
||||
*-------------------------------------------------------------------------------------------------*/
|
||||
/**
|
||||
* @brief Set PSRAM 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 MSPI3 as well
|
||||
*/
|
||||
void mspi_timing_psram_config_set_tuning_regs(bool control_both_mspi);
|
||||
|
||||
/**
|
||||
* @brief Clear PSRAM 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 MSPI3 as well
|
||||
*/
|
||||
void mspi_timing_psram_config_clear_tuning_regs(bool control_both_mspi);
|
||||
|
||||
#endif //#if SOC_MEMSPI_TIMING_TUNING_BY_DQS
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
-153
@@ -1,153 +0,0 @@
|
||||
/*
|
||||
* 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 "esp_private/mspi_timing_impl_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);
|
||||
|
||||
/**
|
||||
* @brief Get Flash dummy rin_reg
|
||||
*
|
||||
* @return Flash dummy rin_reg
|
||||
*/
|
||||
uint32_t mspi_timing_config_get_flash_fdummy_rin(void);
|
||||
|
||||
#endif //#if SOC_MEMSPI_TIMING_TUNING_BY_FLASH_DELAY
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
-243
@@ -1,243 +0,0 @@
|
||||
/*
|
||||
* 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 "sdkconfig.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#if SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY
|
||||
#include "esp_private/mspi_timing_impl_types.h"
|
||||
#include "mspi_timing_tuning_configs.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY
|
||||
|
||||
#define IS_DDR 1
|
||||
#define IS_SDR (!IS_DDR)
|
||||
|
||||
|
||||
#if MSPI_TIMING_FLASH_NEEDS_TUNING || MSPI_TIMING_PSRAM_NEEDS_TUNING
|
||||
/*-------------------------------------------------------------------------------------------------
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* @brief Get PSRAM tuning all configurations
|
||||
*
|
||||
* @param[out] config Pointer to PSRAM tuning configurations
|
||||
*/
|
||||
void mspi_timing_get_psram_tuning_configs(mspi_timing_config_t *config);
|
||||
|
||||
/**
|
||||
* @brief Init MSPI for PSRAM timing tuning
|
||||
*
|
||||
* @param[in] psram_freq_mhz PSRAM frequency in MHz
|
||||
*/
|
||||
void mspi_timing_psram_init(uint32_t psram_freq_mhz);
|
||||
|
||||
/**
|
||||
* @brief Tune PSRAM timing registers for SPI1 accessing PSRAM
|
||||
*
|
||||
* @param[in] configs Timing configs
|
||||
* @param[in] id Config ID
|
||||
*/
|
||||
void mspi_timing_config_psram_set_tuning_regs(const void *configs, uint8_t id);
|
||||
|
||||
/**
|
||||
* @brief Prepare reference data buffer
|
||||
*/
|
||||
void mspi_timing_config_psram_prepare_reference_data(uint8_t *buf, uint32_t len);
|
||||
|
||||
/**
|
||||
* @brief Configure PSRAM to write data via SPI1
|
||||
*
|
||||
* @param[in] buf buffer
|
||||
* @param[in] addr address
|
||||
* @param[in] len length
|
||||
*/
|
||||
void mspi_timing_config_psram_write_data(uint8_t *buf, uint32_t addr, uint32_t len);
|
||||
|
||||
/**
|
||||
* @brief Configure PSRAM to read data via SPI1
|
||||
*
|
||||
* @param[out] buf buffer
|
||||
* @param[in] addr address
|
||||
* @param[in] len length
|
||||
*/
|
||||
void mspi_timing_config_psram_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);
|
||||
|
||||
/**
|
||||
* @brief Select PSRAM 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_psram_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 PSRAM 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_psram_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);
|
||||
|
||||
/**
|
||||
* @brief Clear PSRAM 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_psram_config_clear_tuning_regs(bool control_both_mspi);
|
||||
|
||||
/**
|
||||
* @brief Set PSRAM 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_psram_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 MSPI_TIMING_FLASH_NEEDS_TUNING || MSPI_TIMING_PSRAM_NEEDS_TUNING
|
||||
|
||||
#endif //#if SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY
|
||||
|
||||
#if CONFIG_SPIRAM_TIMING_TUNING_POINT_VIA_TEMPERATURE_SENSOR
|
||||
/**
|
||||
* @brief Set best point for psram timing tuning dynamic temperature scheme
|
||||
*/
|
||||
void mspi_timing_setting_temperature_adjustment_best_point(uint32_t best_point);
|
||||
#endif // CONFIG_SPIRAM_TIMING_TUNING_POINT_VIA_TEMPERATURE_SENSOR
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
-85
@@ -1,85 +0,0 @@
|
||||
/*
|
||||
* 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_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
|
||||
-242
@@ -1,242 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* This file contains configuration APIs doing MSPI timing tuning by MSPI dqs
|
||||
* This file will only be built, when `SOC_MEMSPI_TIMING_TUNING_BY_DQS == 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 "esp_private/mspi_timing_by_dqs.h"
|
||||
#include "mspi_timing_tuning_configs.h"
|
||||
#include "esp_private/mspi_timing_config.h"
|
||||
#include "esp_private/rtc_clk.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
#include "hal/psram_ctrlr_ll.h"
|
||||
#include "hal/mspi_ll.h"
|
||||
|
||||
#define AP_HEX_PSRAM_SYNC_READ 0x0000
|
||||
#define AP_HEX_PSRAM_SYNC_WRITE 0x8080
|
||||
#define AP_HEX_PSRAM_RD_CMD_BITLEN 16
|
||||
#define AP_HEX_PSRAM_WR_CMD_BITLEN 16
|
||||
#define AP_HEX_PSRAM_ADDR_BITLEN 32
|
||||
#if CONFIG_SPIRAM_SPEED_250M
|
||||
#define AP_HEX_PSRAM_RD_DUMMY_BITLEN (2*(18-1))
|
||||
#define AP_HEX_PSRAM_WR_DUMMY_BITLEN (2*(9-1))
|
||||
#elif CONFIG_SPIRAM_SPEED_200M
|
||||
#define AP_HEX_PSRAM_RD_DUMMY_BITLEN (2*(14-1))
|
||||
#define AP_HEX_PSRAM_WR_DUMMY_BITLEN (2*(7-1))
|
||||
#else
|
||||
#define AP_HEX_PSRAM_RD_DUMMY_BITLEN (2*(10-1))
|
||||
#define AP_HEX_PSRAM_WR_DUMMY_BITLEN (2*(5-1))
|
||||
#endif
|
||||
|
||||
#define WRONG_DELAYLINE 16
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "MSPI DQS");
|
||||
const static uint32_t s_test_data[MSPI_TIMING_TEST_DATA_LEN] = {0x7f786655, 0xa5ff005a, 0x3f3c33aa, 0xa5ff5a00, 0x1f1e9955, 0xa5005aff, 0x0f0fccaa, 0xa55a00ff,
|
||||
0x07876655, 0xffa55a00, 0x03c333aa, 0xff00a55a, 0x01e19955, 0xff005aa5, 0x00f0ccaa, 0xff5a00a5,
|
||||
0x80786655, 0x00a5ff5a, 0xc03c33aa, 0x00a55aff, 0xe01e9355, 0x00ff5aa5, 0xf00fccaa, 0x005affa5,
|
||||
0xf8876655, 0x5aa5ff00, 0xfcc333aa, 0x5affa500, 0xfee19955, 0x5a00a5ff, 0x11f0ccaa, 0x5a00ffa5
|
||||
};
|
||||
const static mspi_timing_config_t s_test_delayline_config = {
|
||||
.delayline_table = {{0, 15}, {0, 14}, {0, 13}, {0, 12}, {0, 11}, {0, 10}, {0, 9}, {0, 8}, {0, 7}, {0, 6}, {0, 5}, {0, 4}, {0, 3}, {0, 2}, {0, 1},
|
||||
{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}, {5, 0}, {6, 0}, {7, 0}, {8, 0}, {9, 0}, {10, 0}, {11, 0}, {12, 0}, {13, 0}, {14, 0}, {15, 0}
|
||||
},
|
||||
.available_config_num = 31,
|
||||
};
|
||||
static mspi_ll_dqs_phase_t s_psram_best_phase = MSPI_LL_DQS_PHASE_MAX;
|
||||
static delayline_config_t s_psram_best_delayline = {WRONG_DELAYLINE, WRONG_DELAYLINE};
|
||||
|
||||
void mspi_timing_psram_init(uint32_t psram_freq_mhz)
|
||||
{
|
||||
psram_ctrlr_ll_enable_variable_dummy(PSRAM_CTRLR_LL_MSPI_ID_3, false);
|
||||
mspi_timing_config_set_psram_clock(psram_freq_mhz, MSPI_TIMING_SPEED_MODE_NORMAL_PERF, true);
|
||||
}
|
||||
|
||||
void mspi_timing_config_psram_prepare_reference_data(uint8_t *buf, uint32_t len)
|
||||
{
|
||||
assert(len == MSPI_TIMING_TEST_DATA_LEN);
|
||||
|
||||
memcpy(buf, &s_test_data, len);
|
||||
}
|
||||
|
||||
void mspi_timing_config_psram_write_data(uint8_t *buf, uint32_t addr, uint32_t len)
|
||||
{
|
||||
uint8_t *w_ptr = buf;
|
||||
|
||||
while (len) {
|
||||
int len_to_send = MIN(len, PSRAM_CTRLR_LL_FIFO_MAX_BYTES);
|
||||
psram_ctrlr_ll_common_transaction(PSRAM_CTRLR_LL_MSPI_ID_3,
|
||||
AP_HEX_PSRAM_SYNC_WRITE, AP_HEX_PSRAM_WR_CMD_BITLEN,
|
||||
addr, AP_HEX_PSRAM_ADDR_BITLEN,
|
||||
AP_HEX_PSRAM_WR_DUMMY_BITLEN,
|
||||
w_ptr, len_to_send * 8,
|
||||
NULL, 0,
|
||||
false);
|
||||
w_ptr += len_to_send;
|
||||
addr += len_to_send;
|
||||
len -= len_to_send;
|
||||
}
|
||||
}
|
||||
|
||||
void mspi_timing_config_psram_read_data(uint8_t *buf, uint32_t addr, uint32_t len)
|
||||
{
|
||||
uint8_t *r_ptr = buf;
|
||||
|
||||
while (len) {
|
||||
int len_to_recv = MIN(len, PSRAM_CTRLR_LL_FIFO_MAX_BYTES);
|
||||
psram_ctrlr_ll_common_transaction(PSRAM_CTRLR_LL_MSPI_ID_3,
|
||||
AP_HEX_PSRAM_SYNC_READ, AP_HEX_PSRAM_RD_CMD_BITLEN,
|
||||
addr, AP_HEX_PSRAM_ADDR_BITLEN,
|
||||
AP_HEX_PSRAM_RD_DUMMY_BITLEN,
|
||||
NULL, 0,
|
||||
r_ptr, len_to_recv * 8,
|
||||
false);
|
||||
r_ptr += len_to_recv;
|
||||
addr += len_to_recv;
|
||||
len -= len_to_recv;
|
||||
}
|
||||
}
|
||||
|
||||
void mspi_timing_get_psram_tuning_phases(mspi_timing_config_t *configs)
|
||||
{
|
||||
*configs = (mspi_timing_config_t) {
|
||||
.phase = {MSPI_LL_DQS_PHASE_67_5, MSPI_LL_DQS_PHASE_78_75, MSPI_LL_DQS_PHASE_90, MSPI_LL_DQS_PHASE_101_25},
|
||||
.available_phase_num = 4,
|
||||
};
|
||||
}
|
||||
|
||||
void mspi_timing_config_psram_set_tuning_phase(const void *configs, uint8_t id)
|
||||
{
|
||||
mspi_ll_dqs_phase_t phase = ((mspi_timing_config_t *)configs)->phase[id];
|
||||
mspi_timing_ll_set_dqs_phase(MSPI_LL_DQS_ID_0, phase);
|
||||
#if MSPI_LL_PSRAM_DQS1_SUPPORTED
|
||||
mspi_timing_ll_set_dqs_phase(MSPI_LL_DQS_ID_1, phase);
|
||||
#endif
|
||||
ESP_DRAM_LOGD(TAG, "set to phase: %d", phase);
|
||||
}
|
||||
|
||||
uint32_t mspi_timing_psram_select_best_tuning_phase(const void *configs, uint32_t consecutive_length, uint32_t end, const uint8_t *reference_data, bool is_ddr)
|
||||
{
|
||||
assert(consecutive_length < 5);
|
||||
uint32_t best_phase_id = 0;
|
||||
|
||||
bool success = true;
|
||||
if (consecutive_length == 0) {
|
||||
best_phase_id = 0;
|
||||
success = false;
|
||||
} else {
|
||||
best_phase_id = (end - consecutive_length + 1);
|
||||
}
|
||||
|
||||
if (success) {
|
||||
ESP_DRAM_LOGD(TAG, "tuning success, best phase id is %"PRIu32, best_phase_id);
|
||||
} else {
|
||||
ESP_DRAM_LOGW(TAG, "tuning fail, best phase id is fallen back to index %"PRIu32"", best_phase_id);
|
||||
}
|
||||
|
||||
return best_phase_id;
|
||||
}
|
||||
|
||||
void mspi_timing_psram_set_best_tuning_phase(const void *configs, uint8_t best_id)
|
||||
{
|
||||
s_psram_best_phase = ((const mspi_timing_config_t *)configs)->phase[best_id];
|
||||
}
|
||||
|
||||
void mspi_timing_get_psram_tuning_delaylines(mspi_timing_config_t *configs)
|
||||
{
|
||||
ESP_DRAM_LOGD(TAG, "sizeof(delayline_config_t): %d, sizeof(test_config): %d", sizeof(delayline_config_t), sizeof(s_test_delayline_config));
|
||||
memcpy(configs, &s_test_delayline_config, sizeof(s_test_delayline_config));
|
||||
}
|
||||
|
||||
void mspi_timing_config_psram_set_tuning_delayline(const void *configs, uint8_t id)
|
||||
{
|
||||
assert(s_psram_best_phase != MSPI_LL_DQS_PHASE_MAX);
|
||||
mspi_timing_ll_set_dqs_phase(MSPI_LL_DQS_ID_0, s_psram_best_phase);
|
||||
#if MSPI_LL_PSRAM_DQS1_SUPPORTED
|
||||
mspi_timing_ll_set_dqs_phase(MSPI_LL_DQS_ID_1, s_psram_best_phase);
|
||||
#endif
|
||||
ESP_DRAM_LOGD(TAG, "set to best phase: %d", s_psram_best_phase);
|
||||
|
||||
const delayline_config_t *delayline_config = &((mspi_timing_config_t *)configs)->delayline_table[id];
|
||||
for (int i = 0; i < MSPI_LL_PIN_MAX; i++) {
|
||||
if (i == MSPI_LL_PIN_DQS0) {
|
||||
mspi_timing_ll_set_delayline(i, delayline_config->dqs_delayline);
|
||||
}
|
||||
#if MSPI_LL_PSRAM_DQS1_SUPPORTED
|
||||
else if (i == MSPI_LL_PIN_DQS1) {
|
||||
mspi_timing_ll_set_delayline(i, delayline_config->dqs_delayline);
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
mspi_timing_ll_set_delayline(i, delayline_config->data_delayline);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t mspi_timing_psram_select_best_tuning_delayline(const void *configs, uint32_t consecutive_length, uint32_t end, const uint8_t *reference_data, bool is_ddr)
|
||||
{
|
||||
assert(consecutive_length <= 32);
|
||||
uint32_t bset_delayline_id = 0;
|
||||
|
||||
if (consecutive_length <= 1) {
|
||||
bset_delayline_id = 0;
|
||||
ESP_DRAM_LOGW(TAG, "tuning fail, best delayline id is fallen back to index %"PRIu32"", bset_delayline_id);
|
||||
} else {
|
||||
bset_delayline_id = end - consecutive_length / 2;
|
||||
ESP_DRAM_LOGD(TAG, "tuning success, best delayline id is %"PRIu32, bset_delayline_id);
|
||||
}
|
||||
|
||||
return bset_delayline_id;
|
||||
}
|
||||
|
||||
void mspi_timing_psram_set_best_tuning_delayline(const void *configs, uint8_t best_id)
|
||||
{
|
||||
s_psram_best_delayline = ((mspi_timing_config_t *)configs)->delayline_table[best_id];
|
||||
}
|
||||
|
||||
void mspi_timing_psram_config_clear_tuning_regs(bool control_both_mspi)
|
||||
{
|
||||
mspi_timing_ll_set_dqs_phase(MSPI_LL_DQS_ID_0, 0);
|
||||
#if MSPI_LL_PSRAM_DQS1_SUPPORTED
|
||||
mspi_timing_ll_set_dqs_phase(MSPI_LL_DQS_ID_1, 0);
|
||||
#endif
|
||||
for (int i = 0; i < MSPI_LL_PIN_MAX; i++) {
|
||||
mspi_timing_ll_set_delayline(i, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void mspi_timing_psram_config_set_tuning_regs(bool control_both_mspi)
|
||||
{
|
||||
mspi_timing_ll_set_dqs_phase(MSPI_LL_DQS_ID_0, s_psram_best_phase);
|
||||
#if MSPI_LL_PSRAM_DQS1_SUPPORTED
|
||||
mspi_timing_ll_set_dqs_phase(MSPI_LL_DQS_ID_1, s_psram_best_phase);
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < MSPI_LL_PIN_MAX; i++) {
|
||||
if (i == MSPI_LL_PIN_DQS0) {
|
||||
mspi_timing_ll_set_delayline(i, s_psram_best_delayline.dqs_delayline);
|
||||
}
|
||||
#if MSPI_LL_PSRAM_DQS1_SUPPORTED
|
||||
else if (i == MSPI_LL_PIN_DQS1) {
|
||||
mspi_timing_ll_set_delayline(i, s_psram_best_delayline.dqs_delayline);
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
mspi_timing_ll_set_delayline(i, s_psram_best_delayline.data_delayline);
|
||||
}
|
||||
}
|
||||
}
|
||||
-282
@@ -1,282 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024-2026 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 "esp_private/mspi_timing_by_flash_delay.h"
|
||||
#include "mspi_timing_tuning_configs.h"
|
||||
#include "esp_private/mspi_timing_config.h"
|
||||
#include "hal/mspi_ll.h"
|
||||
#include "rom/spi_flash.h"
|
||||
#include "esp_private/spi_flash_os.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(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_DRAM_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 && CONFIG_SPI_FLASH_HPM_ON
|
||||
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_DRAM_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_DRAM_LOGW(TAG, "tuning fail, best point is fallen back to index %"PRIu32"", best_point);
|
||||
} else {
|
||||
best_point = end - consecutive_length / 2;
|
||||
ESP_DRAM_LOGD(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;
|
||||
assert(!is_ddr);
|
||||
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_DRAM_LOGD(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);
|
||||
}
|
||||
}
|
||||
|
||||
#if MSPI_TIMING_FLASH_NEEDS_TUNING && CONFIG_SPI_FLASH_HPM_ON
|
||||
static uint32_t spi_timing_config_get_dummy(void)
|
||||
{
|
||||
mspi_timing_ll_flash_mode_t mode = mspi_timing_ll_get_flash_mode(0);
|
||||
|
||||
if (spi_flash_hpm_dummy_adjust()) { // HPM-DC is enabled
|
||||
const spi_flash_hpm_dummy_conf_t *hpm_dummy = spi_flash_hpm_get_dummy();
|
||||
switch (mode) {
|
||||
case MSPI_TIMING_LL_FLASH_QIO_MODE:
|
||||
return hpm_dummy->qio_dummy - 1;
|
||||
case MSPI_TIMING_LL_FLASH_QUAD_MODE:
|
||||
return hpm_dummy->qout_dummy - 1;
|
||||
case MSPI_TIMING_LL_FLASH_DIO_MODE:
|
||||
return hpm_dummy->dio_dummy - 1;
|
||||
case MSPI_TIMING_LL_FLASH_DUAL_MODE:
|
||||
return hpm_dummy->dout_dummy - 1;
|
||||
case MSPI_TIMING_LL_FLASH_FAST_MODE:
|
||||
return hpm_dummy->fastrd_dummy - 1;
|
||||
case MSPI_TIMING_LL_FLASH_SLOW_MODE:
|
||||
return 0;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
} else { // HPM-DC is not enabled
|
||||
switch (mode) {
|
||||
case MSPI_TIMING_LL_FLASH_QIO_MODE:
|
||||
return SPI1_R_QIO_DUMMY_CYCLELEN;
|
||||
case MSPI_TIMING_LL_FLASH_QUAD_MODE:
|
||||
return SPI1_R_FAST_DUMMY_CYCLELEN;
|
||||
case MSPI_TIMING_LL_FLASH_DIO_MODE:
|
||||
return SPI1_R_DIO_DUMMY_CYCLELEN;
|
||||
case MSPI_TIMING_LL_FLASH_DUAL_MODE:
|
||||
return SPI1_R_FAST_DUMMY_CYCLELEN;
|
||||
case MSPI_TIMING_LL_FLASH_FAST_MODE:
|
||||
return SPI1_R_FAST_DUMMY_CYCLELEN;
|
||||
case MSPI_TIMING_LL_FLASH_SLOW_MODE:
|
||||
return 0;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // MSPI_TIMING_FLASH_NEEDS_TUNING && CONFIG_SPI_FLASH_HPM_ON
|
||||
|
||||
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 MSPI_TIMING_FLASH_NEEDS_TUNING && CONFIG_SPI_FLASH_HPM_ON
|
||||
uint32_t dummy_len = spi_timing_config_get_dummy();
|
||||
#if CONFIG_ESPTOOLPY_FLASHMODE_QIO && !CONFIG_BOOTLOADER_CACHE_32BIT_ADDR_QUAD_FLASH
|
||||
// In the ROM configuration, when esp_rom_spi_set_rd_cmd_bit_len issues the read command in QIO mode, it automatically inserts two dummy cycles.
|
||||
// Therefore, when validating the dummy cycles at 120 MHz, the effective value should be 10 − 2, i.e. 8 dummy cycles.
|
||||
// However, when the 32 MHz cache access configuration is enabled, the corresponding register will be overwritten,
|
||||
// so the extra two dummy cycles no longer exist. In that case, the dummy cycle setting should simply be 10.
|
||||
mspi_timing_ll_set_flash_user_dummy(MSPI_TIMING_LL_MSPI_ID_0, dummy_len - 2);
|
||||
#else
|
||||
mspi_timing_ll_set_flash_user_dummy(MSPI_TIMING_LL_MSPI_ID_0, dummy_len);
|
||||
#endif // CONFIG_ESPTOOLPY_FLASHMODE_QIO && !CONFIG_BOOTLOADER_CACHE_32BIT_ADDR_QUAD_FLASH
|
||||
#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_DRAM_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;
|
||||
}
|
||||
|
||||
uint32_t mspi_timing_config_get_flash_fdummy_rin(void)
|
||||
{
|
||||
return mspi_timing_ll_get_invalid_dqs_mask(MSPI_TIMING_LL_MSPI_ID_1);
|
||||
}
|
||||
-434
@@ -1,434 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* This file contains configuration APIs doing MSPI timing tuning by MSPI delay
|
||||
* This file will only be built, when `SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY == 1`
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "string.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_types.h"
|
||||
#include "esp_log.h"
|
||||
#include "rom/spi_flash.h"
|
||||
#include "hal/mspi_ll.h"
|
||||
#include "hal/psram_types.h"
|
||||
#include "hal/psram_ctrlr_ll.h"
|
||||
#include "esp_private/mspi_timing_config.h"
|
||||
#include "esp_private/mspi_timing_by_mspi_delay.h"
|
||||
#include "mspi_timing_tuning_configs.h"
|
||||
#include "bootloader_flash.h"
|
||||
|
||||
#define QPI_PSRAM_FAST_READ 0XEB
|
||||
#define QPI_PSRAM_WRITE 0X38
|
||||
#define QPI_PSRAM_FAST_READ_DUMMY 6
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "MSPI Timing");
|
||||
|
||||
//-------------------------------------FLASH timing tuning register config-------------------------------------//
|
||||
void mspi_timing_get_flash_tuning_configs(mspi_timing_config_t *config)
|
||||
{
|
||||
#if MSPI_TIMING_FLASH_DTR_MODE
|
||||
#define FLASH_MODE DTR_MODE
|
||||
#else //MSPI_TIMING_FLASH_STR_MODE
|
||||
#define FLASH_MODE STR_MODE
|
||||
#endif
|
||||
|
||||
#if CONFIG_ESPTOOLPY_FLASHFREQ_80M
|
||||
*config = MSPI_TIMING_FLASH_GET_TUNING_CONFIG(MSPI_TIMING_CORE_CLOCK_MHZ, 80, FLASH_MODE);
|
||||
#elif CONFIG_ESPTOOLPY_FLASHFREQ_120M
|
||||
*config = MSPI_TIMING_FLASH_GET_TUNING_CONFIG(MSPI_TIMING_CORE_CLOCK_MHZ, 120, FLASH_MODE);
|
||||
#else
|
||||
assert(false && "should never reach here");
|
||||
#endif
|
||||
|
||||
#undef FLASH_MODE
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static void s_set_flash_din_mode_num(uint8_t mspi_id, uint8_t din_mode, uint8_t din_num)
|
||||
{
|
||||
mspi_timing_ll_set_flash_din_mode(mspi_id, din_mode);
|
||||
mspi_timing_ll_set_flash_din_num(mspi_id, din_num);
|
||||
}
|
||||
|
||||
static void s_set_flash_extra_dummy(uint8_t mspi_id, uint8_t extra_dummy)
|
||||
{
|
||||
mspi_timing_ll_set_flash_extra_dummy(mspi_id, 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 && CONFIG_SPI_FLASH_HPM_ON
|
||||
g_rom_spiflash_dummy_len_plus[1] = 4;
|
||||
#endif
|
||||
if (bootloader_flash_is_octal_mode_enabled()) {
|
||||
// note that in spi_flash_read API, there is a wait-idle stage, since flash can only be read in idle state.
|
||||
// but after we change the timing settings, we might not read correct idle status via RDSR.
|
||||
// so, here we should use a read API that won't check idle status.
|
||||
mspi_timing_ll_clear_fifo(MSPI_TIMING_LL_MSPI_ID_1);
|
||||
// to add opi read api here when octal flash is used
|
||||
assert(false);
|
||||
} else {
|
||||
esp_rom_spiflash_read(addr, (uint32_t *)buf, len);
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------PSRAM timing tuning register config-------------------------------------//
|
||||
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_timing_adjust_clk(MSPI_TIMING_LL_MSPI_ID_0);
|
||||
}
|
||||
|
||||
void mspi_timing_get_psram_tuning_configs(mspi_timing_config_t *config)
|
||||
{
|
||||
#if MSPI_TIMING_PSRAM_DTR_MODE
|
||||
#define PSRAM_MODE DTR_MODE
|
||||
#else //MSPI_TIMING_PSRAM_STR_MODE
|
||||
#define PSRAM_MODE STR_MODE
|
||||
#endif
|
||||
|
||||
#if CONFIG_SPIRAM_SPEED_80M
|
||||
*config = MSPI_TIMING_PSRAM_GET_TUNING_CONFIG(MSPI_TIMING_CORE_CLOCK_MHZ, 80, STR_MODE);
|
||||
#elif CONFIG_SPIRAM_SPEED_120M
|
||||
*config = MSPI_TIMING_PSRAM_GET_TUNING_CONFIG(MSPI_TIMING_CORE_CLOCK_MHZ, 120, PSRAM_MODE);
|
||||
#else
|
||||
assert(false && "should never reach here");
|
||||
#endif
|
||||
|
||||
#undef PSRAM_MODE
|
||||
}
|
||||
|
||||
static void s_set_psram_din_mode_num(uint8_t mspi_id, uint8_t din_mode, uint8_t din_num)
|
||||
{
|
||||
mspi_timing_ll_set_psram_din_mode(mspi_id, din_mode);
|
||||
mspi_timing_ll_set_psram_din_num(mspi_id, din_num);
|
||||
}
|
||||
|
||||
static void s_set_psram_extra_dummy(uint8_t mspi_id, uint8_t extra_dummy)
|
||||
{
|
||||
mspi_timing_ll_set_psram_extra_dummy(mspi_id, extra_dummy);
|
||||
}
|
||||
|
||||
void mspi_timing_config_psram_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_SPI_SMEM_DINx_MODE(1), SPI_MEM_SPI_SMEM_DINx_NUM(1) are meaningless
|
||||
* SPI0 and SPI1 share the SPI_MEM_SPI_SMEM_DINx_MODE(0), SPI_MEM_SPI_SMEM_DINx_NUM(0) for PSRAM timing tuning
|
||||
* 2. We use SPI1 to get the best PSRAM timing tuning (mode and num) config
|
||||
*/
|
||||
s_set_psram_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);
|
||||
}
|
||||
|
||||
//-------------------------------------------PSRAM Read/Write------------------------------------------//
|
||||
static void psram_exec_cmd(int mspi_id, psram_cmd_mode_t mode,
|
||||
uint32_t cmd, int cmd_bit_len,
|
||||
uint32_t addr, int addr_bit_len,
|
||||
int dummy_bits,
|
||||
uint8_t* mosi_data, int mosi_bit_len,
|
||||
uint8_t* miso_data, int miso_bit_len,
|
||||
uint32_t cs_mask,
|
||||
bool is_write_erase_operation)
|
||||
{
|
||||
esp_rom_spiflash_read_mode_t rd_mode = (mode == PSRAM_HAL_CMD_QPI) ? ESP_ROM_SPIFLASH_QIO_MODE : ESP_ROM_SPIFLASH_SLOWRD_MODE;
|
||||
|
||||
esp_rom_spi_set_op_mode(mspi_id, rd_mode);
|
||||
if (mode == PSRAM_HAL_CMD_QPI) {
|
||||
psram_ctrlr_ll_enable_quad_command(PSRAM_CTRLR_LL_MSPI_ID_1, true);
|
||||
}
|
||||
psram_ctrlr_ll_common_transaction_base(mspi_id, rd_mode,
|
||||
cmd, cmd_bit_len,
|
||||
addr, addr_bit_len,
|
||||
dummy_bits,
|
||||
mosi_data, mosi_bit_len,
|
||||
miso_data, miso_bit_len,
|
||||
cs_mask,
|
||||
is_write_erase_operation);
|
||||
}
|
||||
|
||||
#define FIFO_SIZE_BYTE 32
|
||||
static void s_psram_write_data(uint8_t *buf, uint32_t addr, uint32_t len)
|
||||
{
|
||||
if (len % FIFO_SIZE_BYTE != 0) {
|
||||
ESP_DRAM_LOGE(TAG, "wrong length %d", len);
|
||||
assert(false);
|
||||
}
|
||||
|
||||
uint8_t mspi_id = MSPI_TIMING_LL_MSPI_ID_1;
|
||||
uint8_t cmd = QPI_PSRAM_WRITE;
|
||||
uint8_t cmd_len = 8;
|
||||
uint8_t dummy_len = 0;
|
||||
uint8_t addr_len = 24;
|
||||
psram_cmd_mode_t spi_mode = PSRAM_HAL_CMD_QPI;
|
||||
for (uint32_t idx= 0; idx < len / FIFO_SIZE_BYTE; idx++) {
|
||||
psram_exec_cmd(mspi_id, spi_mode,
|
||||
cmd, cmd_len,
|
||||
addr + idx * FIFO_SIZE_BYTE, addr_len,
|
||||
dummy_len,
|
||||
buf + idx * FIFO_SIZE_BYTE, FIFO_SIZE_BYTE * 8,
|
||||
NULL, 0,
|
||||
PSRAM_LL_CS_SEL,
|
||||
false);
|
||||
}
|
||||
}
|
||||
|
||||
static void s_psram_read_data(uint8_t *buf, uint32_t addr, uint32_t len)
|
||||
{
|
||||
if (len % FIFO_SIZE_BYTE != 0) {
|
||||
ESP_DRAM_LOGE(TAG, "wrong length %d", len);
|
||||
assert(false);
|
||||
}
|
||||
|
||||
uint8_t mspi_id = MSPI_TIMING_LL_MSPI_ID_1;
|
||||
uint8_t cmd = QPI_PSRAM_FAST_READ;
|
||||
uint8_t cmd_len = 8;
|
||||
uint8_t dummy_len = QPI_PSRAM_FAST_READ_DUMMY;
|
||||
uint8_t addr_len = 24;
|
||||
psram_cmd_mode_t spi_mode = PSRAM_HAL_CMD_QPI;
|
||||
for (uint32_t idx = 0; idx < len/FIFO_SIZE_BYTE; idx++) {
|
||||
psram_exec_cmd(mspi_id, spi_mode,
|
||||
cmd, cmd_len,
|
||||
addr + idx*FIFO_SIZE_BYTE, addr_len,
|
||||
dummy_len,
|
||||
NULL, 0,
|
||||
buf + idx*FIFO_SIZE_BYTE, FIFO_SIZE_BYTE * 8,
|
||||
PSRAM_LL_CS_SEL,
|
||||
false);
|
||||
}
|
||||
}
|
||||
|
||||
static void s_psram_execution(uint8_t *buf, uint32_t addr, uint32_t len, bool is_read)
|
||||
{
|
||||
while (len) {
|
||||
uint32_t length = MIN(len, 32);
|
||||
if (is_read) {
|
||||
s_psram_read_data(buf, addr, length);
|
||||
} else {
|
||||
s_psram_write_data(buf, addr, length);
|
||||
}
|
||||
addr += length;
|
||||
buf += length;
|
||||
len -= length;
|
||||
}
|
||||
}
|
||||
|
||||
void mspi_timing_config_psram_prepare_reference_data(uint8_t *buf, uint32_t len)
|
||||
{
|
||||
assert((len == MSPI_TIMING_TEST_DATA_LEN) && (len % 4 == 0));
|
||||
for (int i = 0; i < len / 4; i++) {
|
||||
((uint32_t *)buf)[i] = 0xa5ff005a;
|
||||
}
|
||||
}
|
||||
|
||||
void mspi_timing_config_psram_write_data(uint8_t *buf, uint32_t addr, uint32_t len)
|
||||
{
|
||||
s_psram_execution(buf, addr, len, false);
|
||||
}
|
||||
|
||||
void mspi_timing_config_psram_read_data(uint8_t *buf, uint32_t addr, uint32_t len)
|
||||
{
|
||||
s_psram_execution(buf, addr, len, true);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------------------------------
|
||||
* 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 = 0;
|
||||
|
||||
if (consecutive_length < 3) {
|
||||
//tuning is FAIL, select default point, and generate a warning
|
||||
best_point = configs->default_config_id;
|
||||
ESP_DRAM_LOGW(TAG, "tuning fail, best point is fallen back to index %"PRIu32"", best_point);
|
||||
}
|
||||
#if MSPI_TIMING_FLASH_CONSECUTIVE_LEN_MAX
|
||||
else if (consecutive_length > MSPI_TIMING_FLASH_CONSECUTIVE_LEN_MAX) {
|
||||
best_point = configs->default_config_id;
|
||||
ESP_DRAM_LOGW(TAG, "tuning fail, best point is fallen back to index %"PRIu32"", best_point);
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
best_point = end - consecutive_length / 2;
|
||||
ESP_DRAM_LOGD(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;
|
||||
assert(!is_ddr);
|
||||
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_DRAM_LOGD(TAG, "Flash timing tuning index: %"PRIu32"", best_point);
|
||||
|
||||
return best_point;
|
||||
}
|
||||
|
||||
uint32_t mspi_timing_psram_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, false);
|
||||
ESP_DRAM_LOGD(TAG, "PSRAM 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(MSPI_TIMING_LL_MSPI_ID_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 MSPI_TIMING_FLASH_NEEDS_TUNING && CONFIG_ESPTOOLPY_FLASHMODE_QIO && CONFIG_SPI_FLASH_HPM_ON
|
||||
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_DRAM_LOGV(TAG, "flash, 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);
|
||||
}
|
||||
|
||||
void mspi_timing_psram_config_clear_tuning_regs(bool control_both_mspi)
|
||||
{
|
||||
(void)control_both_mspi; //for compatibility
|
||||
s_set_psram_din_mode_num(MSPI_TIMING_LL_MSPI_ID_0, 0, 0);
|
||||
s_set_psram_extra_dummy(MSPI_TIMING_LL_MSPI_ID_0, 0);
|
||||
}
|
||||
|
||||
void mspi_timing_psram_config_set_tuning_regs(bool control_both_mspi)
|
||||
{
|
||||
(void)control_both_mspi; //for compatibility
|
||||
s_set_psram_din_mode_num(MSPI_TIMING_LL_MSPI_ID_0, s_psram_best_timing_tuning_config.spi_din_mode, s_psram_best_timing_tuning_config.spi_din_num);
|
||||
s_set_psram_extra_dummy(MSPI_TIMING_LL_MSPI_ID_0, s_psram_best_timing_tuning_config.extra_dummy_len);
|
||||
|
||||
int spi0_usr_rdummy = 0;
|
||||
int spi0_extra_dummy = 0;
|
||||
mspi_timing_ll_get_psram_dummy(MSPI_TIMING_LL_MSPI_ID_0, &spi0_usr_rdummy, &spi0_extra_dummy);
|
||||
ESP_DRAM_LOGV(TAG, "psram, spi0_usr_rdummy: %d, spi0_extra_dummy: %d", spi0_usr_rdummy, spi0_extra_dummy);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------------------------------
|
||||
* To let upper layer (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-S3, 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(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;
|
||||
}
|
||||
@@ -40,7 +40,6 @@
|
||||
#include "esp_private/sleep_gpio.h"
|
||||
#include "esp_private/spi_flash_os.h"
|
||||
#include "esp_private/startup_internal.h"
|
||||
#include "bootloader_flash.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "sleep_gpio");
|
||||
|
||||
@@ -152,7 +151,7 @@ void esp_sleep_config_gpio_isolate(void)
|
||||
gpio_sleep_set_pull_mode(esp_mspi_get_io(ESP_MSPI_IO_HD), GPIO_PULLUP_ONLY);
|
||||
gpio_sleep_set_pull_mode(esp_mspi_get_io(ESP_MSPI_IO_WP), GPIO_PULLUP_ONLY);
|
||||
#if SOC_SPI_MEM_SUPPORT_FLASH_OPI_MODE
|
||||
bool octal_mspi_required = bootloader_flash_is_octal_mode_enabled();
|
||||
bool octal_mspi_required = spi_flash_is_octal_mode_enabled();
|
||||
#if CONFIG_SPIRAM_MODE_OCT
|
||||
octal_mspi_required |= true;
|
||||
#endif // CONFIG_SPIRAM_MODE_OCT
|
||||
|
||||
@@ -22,18 +22,6 @@ components/esp_hw_support/test_apps/host_test_linux:
|
||||
depends_components:
|
||||
- esp_hw_support
|
||||
|
||||
components/esp_hw_support/test_apps/mspi:
|
||||
depends_components:
|
||||
- esp_hw_support
|
||||
- spi_flash
|
||||
- esp_partition
|
||||
- esp_hal_mspi
|
||||
- soc
|
||||
disable:
|
||||
- if: IDF_TARGET not in ["esp32s3", "esp32p4", "esp32c61", "esp32c5", "esp32s31"]
|
||||
- if: CONFIG_NAME in ["generic_timing_tuning_log_safe", "generic_timing_tuning_xip"] and IDF_TARGET in ["esp32s31"]
|
||||
- if: CONFIG_NAME == "120sdr_120sdr" and IDF_TARGET in ["esp32s3", "esp32p4", "esp32s31"]
|
||||
|
||||
components/esp_hw_support/test_apps/mspi_psram_with_dfs:
|
||||
depends_components:
|
||||
- esp_hw_support
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
# This is the project CMakeLists.txt file for the test subproject
|
||||
cmake_minimum_required(VERSION 3.22)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
|
||||
# "Trim" the build. Include the minimal set of components, main, and anything it depends on. We also depend on esp_psram
|
||||
# as we set CONFIG_SPIRAM_... options.
|
||||
set(COMPONENTS main esp_psram)
|
||||
|
||||
project(mspi_test_app)
|
||||
@@ -1,7 +0,0 @@
|
||||
| Supported Targets | ESP32-C5 | ESP32-C61 | ESP32-P4 | ESP32-S3 | ESP32-S31 |
|
||||
| ----------------- | -------- | --------- | -------- | -------- | --------- |
|
||||
|
||||
This project tests if Flash and PSRAM can work under different configurations.
|
||||
To add new configuration, create one more sdkconfig.ci.NAME file in this directory.
|
||||
|
||||
If you need to test for anything other than flash and psram, create another test project.
|
||||
@@ -1,11 +0,0 @@
|
||||
set(srcs
|
||||
"test_app_main.c"
|
||||
"test_flash_psram.c"
|
||||
"test_mspi.c"
|
||||
)
|
||||
|
||||
# In order for the cases defined by `TEST_CASE` to be linked into the final elf,
|
||||
# the component can be registered as WHOLE_ARCHIVE
|
||||
idf_component_register(SRCS ${srcs}
|
||||
PRIV_REQUIRES unity esp_timer spi_flash esp_partition esp_hal_mspi
|
||||
WHOLE_ARCHIVE)
|
||||
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "unity.h"
|
||||
#include "unity_test_utils.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_newlib.h"
|
||||
|
||||
// load partition table in tests will use memory
|
||||
#define TEST_MEMORY_LEAK_THRESHOLD (600)
|
||||
|
||||
void setUp(void)
|
||||
{
|
||||
unity_utils_record_free_mem();
|
||||
}
|
||||
|
||||
void tearDown(void)
|
||||
{
|
||||
esp_reent_cleanup(); //clean up some of the newlib's lazy allocations
|
||||
unity_utils_evaluate_leaks_direct(TEST_MEMORY_LEAK_THRESHOLD);
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
printf("\n");
|
||||
printf("===================TEST MSPI=================\n");
|
||||
unity_run_menu();
|
||||
}
|
||||
@@ -1,197 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "unity.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_flash.h"
|
||||
#include "esp_partition.h"
|
||||
#if CONFIG_IDF_TARGET_ESP32S3
|
||||
#include "esp32s3/rom/spi_flash.h"
|
||||
#include "esp32s3/rom/opi_flash.h"
|
||||
#endif
|
||||
|
||||
__attribute__((unused)) const static char *TAG = "MSPI";
|
||||
|
||||
//-----------------------------------------SPI0 PSRAM TEST-----------------------------------------------//
|
||||
#if CONFIG_SPIRAM
|
||||
|
||||
#if CONFIG_SPIRAM_MODE_OCT
|
||||
#define SPI0_PSRAM_TEST_LEN (512 * 1024)
|
||||
#define LENGTH_PER_TIME 1024
|
||||
#else
|
||||
#define SPI0_PSRAM_TEST_LEN (128 * 1024)
|
||||
#define LENGTH_PER_TIME 1024
|
||||
#endif
|
||||
|
||||
TEST_CASE("MSPI: Test_SPI0_PSRAM", "[mspi]")
|
||||
{
|
||||
printf("----------SPI0 PSRAM Test----------\n");
|
||||
|
||||
uint8_t *psram_rd_buf = (uint8_t *)heap_caps_malloc(LENGTH_PER_TIME, MALLOC_CAP_32BIT | MALLOC_CAP_SPIRAM);
|
||||
if (!psram_rd_buf) {
|
||||
printf("no memory\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
uint8_t *psram_wr_buf = (uint8_t *)heap_caps_malloc(SPI0_PSRAM_TEST_LEN, MALLOC_CAP_32BIT | MALLOC_CAP_SPIRAM);
|
||||
if (!psram_wr_buf) {
|
||||
printf("no memory\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
srand(399);
|
||||
for (int i = 0; i < SPI0_PSRAM_TEST_LEN / LENGTH_PER_TIME; i++) {
|
||||
for (int j = 0; j < sizeof(psram_rd_buf); j++) {
|
||||
psram_rd_buf[j] = rand();
|
||||
}
|
||||
memcpy(psram_wr_buf + i * LENGTH_PER_TIME, psram_rd_buf, LENGTH_PER_TIME);
|
||||
|
||||
if (memcmp(psram_wr_buf + i * LENGTH_PER_TIME, psram_rd_buf, LENGTH_PER_TIME) != 0) {
|
||||
free(psram_wr_buf);
|
||||
free(psram_rd_buf);
|
||||
TEST_FAIL_MESSAGE("SPI0 PSRAM Test Fail");
|
||||
}
|
||||
}
|
||||
free(psram_wr_buf);
|
||||
free(psram_rd_buf);
|
||||
printf(DRAM_STR("----------SPI0 PSRAM Test Success----------\n\n"));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//-----------------------------------------SPI1 FLASH TEST-----------------------------------------------//
|
||||
#define SPI1_FLASH_TEST_LEN 512
|
||||
#define SECTOR_LEN 4096
|
||||
#define SPI1_FLASH_TEST_NUM (SECTOR_LEN / SPI1_FLASH_TEST_LEN)
|
||||
#define SPI1_FLASH_TEST_ADDR 0x2a0000
|
||||
|
||||
static uint8_t rd_buf[SPI1_FLASH_TEST_LEN];
|
||||
static uint8_t wr_buf[SPI1_FLASH_TEST_LEN];
|
||||
|
||||
static const esp_partition_t *get_test_flash_partition(void)
|
||||
{
|
||||
/* This finds "flash_test" partition defined in partition_table_unit_test_app.csv */
|
||||
const esp_partition_t *result = esp_partition_find_first(ESP_PARTITION_TYPE_DATA,
|
||||
ESP_PARTITION_SUBTYPE_ANY, "flash_test");
|
||||
assert(result != NULL); /* means partition table set wrong */
|
||||
return result;
|
||||
}
|
||||
|
||||
TEST_CASE("MSPI: Test_SPI1_Flash", "[mspi]")
|
||||
{
|
||||
printf(DRAM_STR("----------SPI1 Flash Test----------\n"));
|
||||
|
||||
//We need to use SPI1
|
||||
const esp_partition_t* part = get_test_flash_partition();
|
||||
esp_flash_erase_region(part->flash_chip, part->address, part->size);
|
||||
|
||||
for (int i = 0; i < SPI1_FLASH_TEST_NUM; i++) {
|
||||
for (int j = i + 10; j < SPI1_FLASH_TEST_LEN; j++) {
|
||||
wr_buf[j] = j;
|
||||
}
|
||||
|
||||
uint32_t test_flash_addr = SPI1_FLASH_TEST_ADDR;
|
||||
esp_flash_write(part->flash_chip, wr_buf, part->address, sizeof(wr_buf));
|
||||
esp_flash_read(part->flash_chip, rd_buf, part->address, sizeof(rd_buf));
|
||||
|
||||
if (memcmp(wr_buf, rd_buf, SPI1_FLASH_TEST_LEN) != 0) {
|
||||
printf(DRAM_STR("error happened between 0x%x and 0x%x!!!!\n"), test_flash_addr, test_flash_addr + SPI1_FLASH_TEST_LEN);
|
||||
for (int i = 0; i < SPI1_FLASH_TEST_LEN; i++) {
|
||||
if (wr_buf[i] != rd_buf[i]) {
|
||||
printf(DRAM_STR("err: wr[%d]: 0x%02x -- rd[%d]: 0x%02x\n"), i, wr_buf[i], i, rd_buf[i]);
|
||||
}
|
||||
}
|
||||
TEST_FAIL_MESSAGE("SPI1 Flash Test Fail");
|
||||
}
|
||||
memset(rd_buf, 0x0, SPI1_FLASH_TEST_LEN);
|
||||
}
|
||||
|
||||
printf(DRAM_STR("----------SPI1 Flash Test Success----------\n\n"));
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------SPI0 FLASH TEST-----------------------------------------------//
|
||||
#define SPI0_FLASH_TEST_LEN 32
|
||||
#define SPI0_FLASH_TEST_BUF {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, \
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F}
|
||||
|
||||
static const uint8_t flash_rd_buf[SPI0_FLASH_TEST_LEN] = SPI0_FLASH_TEST_BUF;
|
||||
extern int _flash_rodata_start;
|
||||
extern int _rodata_reserved_end;
|
||||
|
||||
TEST_CASE("MSPI: Test_SPI0_Flash", "[mspi]")
|
||||
{
|
||||
printf("----------SPI0 Flash Test----------\n");
|
||||
//Check if the flash_rd_buf is in .rodata
|
||||
assert(((intptr_t)flash_rd_buf >= (intptr_t)&_flash_rodata_start) && ((intptr_t)flash_rd_buf < (intptr_t)&_rodata_reserved_end));
|
||||
|
||||
uint8_t cmp_buf[SPI0_FLASH_TEST_LEN] = SPI0_FLASH_TEST_BUF;
|
||||
|
||||
for (int i = 0; i < SPI0_FLASH_TEST_LEN; i++) {
|
||||
if (flash_rd_buf[i] != cmp_buf[i]) {
|
||||
TEST_FAIL_MESSAGE("SPI0 Flash Test Fail");
|
||||
}
|
||||
}
|
||||
printf(DRAM_STR("----------SPI0 Flash Test Success----------\n\n"));
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
XIP + PSRAM Stack + Flash API
|
||||
---------------------------------------------------------------*/
|
||||
#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS && CONFIG_SPIRAM_RODATA
|
||||
typedef struct {
|
||||
SemaphoreHandle_t sem;
|
||||
const esp_partition_t *part;
|
||||
} test_flash_api_ctx_t;
|
||||
|
||||
static void test_flash_api_on_psram_when_xip(void *arg)
|
||||
{
|
||||
test_flash_api_ctx_t *ctx = (test_flash_api_ctx_t *)arg;
|
||||
SemaphoreHandle_t test_semphr = ctx->sem;
|
||||
|
||||
TEST_ESP_OK(esp_flash_erase_region(ctx->part->flash_chip, ctx->part->address, ctx->part->size));
|
||||
|
||||
uint32_t test_val = 0x55;
|
||||
uint32_t read_val = 0;
|
||||
TEST_ESP_OK(esp_flash_write(ctx->part->flash_chip, &test_val, ctx->part->address, 4));
|
||||
TEST_ESP_OK(esp_flash_read(ctx->part->flash_chip, &read_val, ctx->part->address, 4));
|
||||
TEST_ASSERT(test_val == read_val);
|
||||
|
||||
xSemaphoreGive(test_semphr);
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
TEST_CASE("test Flash API work with PSRAM stack when XIP_PSRAM", "[psram]")
|
||||
{
|
||||
SemaphoreHandle_t test_semphr = xSemaphoreCreateBinary();
|
||||
TEST_ASSERT(test_semphr);
|
||||
const esp_partition_t *part = get_test_flash_partition();
|
||||
ESP_LOGI(TAG, "found partition '%s' at offset 0x%"PRIx32" with size 0x%"PRIx32, part->label, part->address, part->size);
|
||||
|
||||
test_flash_api_ctx_t ctx = {
|
||||
.sem = test_semphr,
|
||||
.part = part,
|
||||
};
|
||||
|
||||
int size_stack = 1024 * 4;
|
||||
StackType_t *stack_for_task = (StackType_t *) heap_caps_calloc(1, size_stack, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||
printf("init_task: current addr_stack = %p, stack_for_task = %p\n", esp_cpu_get_sp(), stack_for_task);
|
||||
static StaticTask_t task_buf;
|
||||
xTaskCreateStaticPinnedToCore(test_flash_api_on_psram_when_xip, "test_flash_api_on_psram_when_xip", size_stack, &ctx, 5, stack_for_task, &task_buf, 0);
|
||||
|
||||
xSemaphoreTake(test_semphr, portMAX_DELAY);
|
||||
vSemaphoreDelete(test_semphr);
|
||||
free(stack_for_task);
|
||||
}
|
||||
#endif //CONFIG_SPIRAM_FETCH_INSTRUCTIONS && CONFIG_SPIRAM_RODATA
|
||||
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
|
||||
#include "unity.h"
|
||||
#include "esp_timer.h"
|
||||
#include "esp_private/mspi_timing_tuning.h"
|
||||
|
||||
|
||||
static void sorted_array_insert(uint32_t *array, uint32_t *size, uint32_t item)
|
||||
{
|
||||
uint32_t pos;
|
||||
for (pos = *size; pos > 0; pos--) {
|
||||
if (array[pos - 1] <= item) {
|
||||
break;
|
||||
}
|
||||
array[pos] = array[pos - 1];
|
||||
}
|
||||
array[pos] = item;
|
||||
(*size)++;
|
||||
}
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32S3
|
||||
#define TEST_TIME_CNT 10
|
||||
#define TEST_TIME_LIMIT_US 10
|
||||
#elif CONFIG_IDF_TARGET_ESP32P4
|
||||
#define TEST_TIME_CNT 30
|
||||
#define TEST_TIME_LIMIT_US 30
|
||||
#else
|
||||
#define TEST_TIME_CNT 20
|
||||
#define TEST_TIME_LIMIT_US 20
|
||||
#endif
|
||||
|
||||
TEST_CASE("MSPI: Test mspi timing tuning time cost", "[mspi]")
|
||||
{
|
||||
uint64_t start, end;
|
||||
uint32_t cost, index_1 = 0, index_2 = 0;
|
||||
uint32_t slow_down_time[TEST_TIME_CNT], speed_up_time[TEST_TIME_CNT];
|
||||
|
||||
printf("\nFunc call `mspi_timing_change_speed_mode_cache_safe` should spend time less than %d us\n", TEST_TIME_LIMIT_US);
|
||||
for (uint8_t i = 0; i < TEST_TIME_CNT; i++) {
|
||||
start = esp_timer_get_time();
|
||||
mspi_timing_change_speed_mode_cache_safe(true);
|
||||
end = esp_timer_get_time();
|
||||
cost = end - start;
|
||||
sorted_array_insert(slow_down_time, &index_1, cost);
|
||||
printf("mspi psram slow down cost %ld\t", cost);
|
||||
|
||||
start = esp_timer_get_time();
|
||||
mspi_timing_change_speed_mode_cache_safe(false);
|
||||
end = esp_timer_get_time();
|
||||
cost = end - start;
|
||||
sorted_array_insert(speed_up_time, &index_2, cost);
|
||||
printf("mspi psram speed up cost %ld\n", cost);
|
||||
}
|
||||
|
||||
TEST_ASSERT_LESS_THAN_UINT32(TEST_TIME_LIMIT_US, slow_down_time[TEST_TIME_CNT / 2]);
|
||||
TEST_ASSERT_LESS_THAN_UINT32(TEST_TIME_LIMIT_US, speed_up_time[TEST_TIME_CNT / 2]);
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
|
||||
nvs, data, nvs, 0x9000, 0x6000,
|
||||
phy_init, data, phy, 0xf000, 0x1000,
|
||||
factory, app, factory, 0x10000, 1M,
|
||||
flash_test, data, fat, , 512K,
|
||||
|
@@ -1,118 +0,0 @@
|
||||
# SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
import os
|
||||
import pathlib
|
||||
|
||||
import pytest
|
||||
from pytest_embedded_idf import IdfDut
|
||||
from pytest_embedded_idf.utils import idf_parametrize
|
||||
|
||||
MSPI_F8R8_configs = [
|
||||
p.name.replace('sdkconfig.ci.', '')
|
||||
for p in pathlib.Path(os.path.dirname(__file__)).glob('sdkconfig.ci.esp32s3_f8r8*')
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.MSPI_F8R8
|
||||
@pytest.mark.parametrize('config', MSPI_F8R8_configs, indirect=True)
|
||||
@idf_parametrize('target', ['esp32s3'], indirect=['target'])
|
||||
def test_flash8_psram8(dut: IdfDut) -> None:
|
||||
dut.run_all_single_board_cases()
|
||||
|
||||
|
||||
# For F4R8 board (Quad Flash and Octal PSRAM)
|
||||
MSPI_F4R8_configs = [
|
||||
p.name.replace('sdkconfig.ci.', '')
|
||||
for p in pathlib.Path(os.path.dirname(__file__)).glob('sdkconfig.ci.esp32s3_f4r8*')
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.MSPI_F4R8
|
||||
@pytest.mark.parametrize('config', MSPI_F4R8_configs, indirect=True)
|
||||
@idf_parametrize('target', ['esp32s3'], indirect=['target'])
|
||||
def test_flash4_psram8(dut: IdfDut) -> None:
|
||||
dut.run_all_single_board_cases()
|
||||
|
||||
|
||||
# For F4R4 board (Quad Flash and Quad PSRAM)
|
||||
MSPI_F4R4_configs = [
|
||||
p.name.replace('sdkconfig.ci.', '')
|
||||
for p in pathlib.Path(os.path.dirname(__file__)).glob('sdkconfig.ci.esp32s3_f4r4*')
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.MSPI_F4R4
|
||||
@pytest.mark.parametrize('config', MSPI_F4R4_configs, indirect=True)
|
||||
@idf_parametrize('target', ['esp32s3'], indirect=['target'])
|
||||
def test_flash4_psram4(dut: IdfDut) -> None:
|
||||
dut.run_all_single_board_cases()
|
||||
|
||||
|
||||
@pytest.mark.flash_120m
|
||||
@pytest.mark.parametrize(
|
||||
'config',
|
||||
[
|
||||
'esp32p4_120sdr_200ddr',
|
||||
],
|
||||
indirect=True,
|
||||
)
|
||||
@idf_parametrize('target', ['esp32p4'], indirect=['target'])
|
||||
def test_flash_psram_esp32p4(dut: IdfDut) -> None:
|
||||
dut.run_all_single_board_cases()
|
||||
|
||||
|
||||
@pytest.mark.generic
|
||||
@pytest.mark.parametrize(
|
||||
'config',
|
||||
[
|
||||
'120sdr_120sdr',
|
||||
],
|
||||
indirect=True,
|
||||
)
|
||||
@idf_parametrize('target', ['esp32c5', 'esp32c61'], indirect=['target'])
|
||||
def test_flash_psram_120sdr_120sdr(dut: IdfDut) -> None:
|
||||
dut.run_all_single_board_cases()
|
||||
|
||||
|
||||
@pytest.mark.generic
|
||||
@pytest.mark.parametrize(
|
||||
'config',
|
||||
[
|
||||
'esp32s31_120sdr_200ddr',
|
||||
],
|
||||
indirect=True,
|
||||
)
|
||||
@idf_parametrize('target', ['esp32s31'], indirect=['target'])
|
||||
def test_flash_psram_esp32s31(dut: IdfDut) -> None:
|
||||
dut.run_all_single_board_cases()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'config',
|
||||
[
|
||||
'generic_timing_tuning_log_safe',
|
||||
'generic_timing_tuning_xip',
|
||||
],
|
||||
indirect=True,
|
||||
)
|
||||
@idf_parametrize(
|
||||
'target,markers',
|
||||
[
|
||||
# S3 has no flash support auto suspend, this test is not applicable
|
||||
(
|
||||
'esp32p4',
|
||||
(pytest.mark.generic,),
|
||||
),
|
||||
(
|
||||
'esp32c5',
|
||||
(pytest.mark.generic,),
|
||||
),
|
||||
(
|
||||
'esp32c61',
|
||||
(pytest.mark.generic,),
|
||||
),
|
||||
],
|
||||
indirect=['target'],
|
||||
)
|
||||
def test_flash_psram_generic(dut: IdfDut) -> None:
|
||||
dut.run_all_single_board_cases()
|
||||
@@ -1,6 +0,0 @@
|
||||
CONFIG_SPIRAM=y
|
||||
CONFIG_SPIRAM_SPEED_120M=y
|
||||
CONFIG_ESPTOOLPY_FLASHFREQ_120M=y
|
||||
CONFIG_SPI_FLASH_HPM_ENA=y
|
||||
CONFIG_BOOTLOADER_FLASH_DC_AWARE=y
|
||||
CONFIG_SPI_FLASH_AUTO_SUSPEND=y
|
||||
@@ -1,7 +0,0 @@
|
||||
CONFIG_IDF_TARGET="esp32p4"
|
||||
|
||||
CONFIG_SPIRAM=y
|
||||
CONFIG_SPIRAM_SPEED_200M=y
|
||||
CONFIG_ESPTOOLPY_FLASHFREQ_120M=y
|
||||
CONFIG_SPI_FLASH_HPM_ENA=y
|
||||
CONFIG_BOOTLOADER_FLASH_DC_AWARE=y
|
||||
@@ -1,10 +0,0 @@
|
||||
CONFIG_IDF_TARGET="esp32s31"
|
||||
|
||||
CONFIG_IDF_EXPERIMENTAL_FEATURES=y
|
||||
CONFIG_SPIRAM=y
|
||||
CONFIG_SPIRAM_SPEED_200M=y
|
||||
|
||||
#use 80 until 120 is supported TODO: IDF-14653
|
||||
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
|
||||
#CONFIG_SPI_FLASH_HPM_ENA=y
|
||||
#CONFIG_BOOTLOADER_FLASH_DC_AWARE=y
|
||||
@@ -1,11 +0,0 @@
|
||||
# Legacy, F4R4, Flash 120M SDR, PSRAM disable
|
||||
|
||||
CONFIG_IDF_TARGET="esp32s3"
|
||||
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
||||
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
|
||||
CONFIG_SPI_FLASH_HPM_ENA=y
|
||||
CONFIG_ESPTOOLPY_FLASHFREQ_120M=y
|
||||
CONFIG_BOOTLOADER_FLASH_DC_AWARE=y
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||
@@ -1,13 +0,0 @@
|
||||
# Legacy, F4R4, Flash 120M SDR, PSRAM 120M SDR
|
||||
|
||||
CONFIG_IDF_TARGET="esp32s3"
|
||||
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
||||
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
|
||||
CONFIG_SPI_FLASH_HPM_ENA=y
|
||||
CONFIG_ESPTOOLPY_FLASHFREQ_120M=y
|
||||
CONFIG_BOOTLOADER_FLASH_DC_AWARE=y
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||
CONFIG_SPIRAM=y
|
||||
CONFIG_SPIRAM_SPEED_120M=y
|
||||
@@ -1,13 +0,0 @@
|
||||
# Legacy, F4R4, Flash 120M SDR, PSRAM 40M SDR
|
||||
|
||||
CONFIG_IDF_TARGET="esp32s3"
|
||||
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
||||
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
|
||||
CONFIG_SPI_FLASH_HPM_ENA=y
|
||||
CONFIG_ESPTOOLPY_FLASHFREQ_120M=y
|
||||
CONFIG_BOOTLOADER_FLASH_DC_AWARE=y
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||
CONFIG_SPIRAM=y
|
||||
CONFIG_SPIRAM_SPEED_40M=y
|
||||
-15
@@ -1,15 +0,0 @@
|
||||
# Legacy, F4R4, Flash 120M SDR, PSRAM disable
|
||||
|
||||
# config for build only
|
||||
|
||||
CONFIG_IDF_TARGET="esp32s3"
|
||||
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
||||
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
|
||||
CONFIG_SPI_FLASH_HPM_ENA=y
|
||||
CONFIG_ESPTOOLPY_FLASHFREQ_120M=y
|
||||
CONFIG_BOOTLOADER_FLASH_DC_AWARE=y
|
||||
CONFIG_SPI_FLASH_HPM_ON=y
|
||||
CONFIG_SPI_FLASH_HPM_DC_DISABLE=y
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||
@@ -1,15 +0,0 @@
|
||||
# Legacy, F4R4, Flash 120M SDR, PSRAM disable, compiler -Os and silent
|
||||
|
||||
CONFIG_IDF_TARGET="esp32s3"
|
||||
|
||||
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
|
||||
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
|
||||
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
||||
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
|
||||
CONFIG_SPI_FLASH_HPM_ENA=y
|
||||
CONFIG_ESPTOOLPY_FLASHFREQ_120M=y
|
||||
CONFIG_BOOTLOADER_FLASH_DC_AWARE=y
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||
@@ -1,11 +0,0 @@
|
||||
# Legacy, F4R4, Flash 40M SDR, PSRAM 120M SDR
|
||||
|
||||
CONFIG_IDF_TARGET="esp32s3"
|
||||
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
||||
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
|
||||
CONFIG_ESPTOOLPY_FLASHFREQ_40M=y
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||
CONFIG_SPIRAM=y
|
||||
CONFIG_SPIRAM_SPEED_120M=y
|
||||
@@ -1,11 +0,0 @@
|
||||
# Legacy, F4R4, Flash 80M SDR, PSRAM 80M SDR
|
||||
|
||||
CONFIG_IDF_TARGET="esp32s3"
|
||||
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
||||
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
|
||||
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||
CONFIG_SPIRAM=y
|
||||
CONFIG_SPIRAM_SPEED_80M=y
|
||||
@@ -1,11 +0,0 @@
|
||||
# Legacy, F4R8, Flash 120M SDR, PSRAM disable
|
||||
|
||||
CONFIG_IDF_TARGET="esp32s3"
|
||||
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
||||
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
|
||||
CONFIG_SPI_FLASH_HPM_ENA=y
|
||||
CONFIG_ESPTOOLPY_FLASHFREQ_120M=y
|
||||
CONFIG_BOOTLOADER_FLASH_DC_AWARE=y
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||
@@ -1,12 +0,0 @@
|
||||
# Legacy, F4R8, Flash 80M SDR, PSRAM 40M DDR
|
||||
|
||||
CONFIG_IDF_TARGET="esp32s3"
|
||||
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
||||
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
|
||||
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||
CONFIG_SPIRAM=y
|
||||
CONFIG_SPIRAM_MODE_OCT=y
|
||||
CONFIG_SPIRAM_SPEED_40M=y
|
||||
@@ -1,12 +0,0 @@
|
||||
# Legacy, F4R8, Flash 80M SDR, PSRAM 80M DDR
|
||||
|
||||
CONFIG_IDF_TARGET="esp32s3"
|
||||
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
||||
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
|
||||
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||
CONFIG_SPIRAM=y
|
||||
CONFIG_SPIRAM_MODE_OCT=y
|
||||
CONFIG_SPIRAM_SPEED_80M=y
|
||||
@@ -1,12 +0,0 @@
|
||||
# Legacy, F8R8, Flash 120M SDR, PSRAM disable
|
||||
|
||||
CONFIG_IDF_TARGET="esp32s3"
|
||||
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
||||
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
|
||||
CONFIG_ESPTOOLPY_OCT_FLASH=y
|
||||
CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_STR=y
|
||||
CONFIG_ESPTOOLPY_FLASHFREQ_120M=y
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||
CONFIG_SPIRAM=n
|
||||
@@ -1,14 +0,0 @@
|
||||
# Legacy, F8R8, Flash 40M DDR, PSRAM 40M DDR
|
||||
|
||||
CONFIG_IDF_TARGET="esp32s3"
|
||||
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
||||
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
|
||||
CONFIG_ESPTOOLPY_OCT_FLASH=y
|
||||
CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_DTR=y
|
||||
CONFIG_ESPTOOLPY_FLASHFREQ_40M=y
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||
CONFIG_SPIRAM=y
|
||||
CONFIG_SPIRAM_MODE_OCT=y
|
||||
CONFIG_SPIRAM_SPEED_40M=y
|
||||
@@ -1,14 +0,0 @@
|
||||
# Legacy, F8R8, Flash 40M DDR, PSRAM 80M DDR
|
||||
|
||||
CONFIG_IDF_TARGET="esp32s3"
|
||||
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
||||
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
|
||||
CONFIG_ESPTOOLPY_OCT_FLASH=y
|
||||
CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_DTR=y
|
||||
CONFIG_ESPTOOLPY_FLASHFREQ_40M=y
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||
CONFIG_SPIRAM=y
|
||||
CONFIG_SPIRAM_MODE_OCT=y
|
||||
CONFIG_SPIRAM_SPEED_80M=y
|
||||
@@ -1,14 +0,0 @@
|
||||
# Legacy, F8R8, Flash 80M DDR, PSRAM 40M DDR
|
||||
|
||||
CONFIG_IDF_TARGET="esp32s3"
|
||||
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
||||
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
|
||||
CONFIG_ESPTOOLPY_OCT_FLASH=y
|
||||
CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_DTR=y
|
||||
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||
CONFIG_SPIRAM=y
|
||||
CONFIG_SPIRAM_MODE_OCT=y
|
||||
CONFIG_SPIRAM_SPEED_40M=y
|
||||
@@ -1,14 +0,0 @@
|
||||
# Legacy, F8R8, Flash 80M DDR, PSRAM 80M DDR
|
||||
|
||||
CONFIG_IDF_TARGET="esp32s3"
|
||||
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
||||
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
|
||||
CONFIG_ESPTOOLPY_OCT_FLASH=y
|
||||
CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_DTR=y
|
||||
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||
CONFIG_SPIRAM=y
|
||||
CONFIG_SPIRAM_MODE_OCT=y
|
||||
CONFIG_SPIRAM_SPEED_80M=y
|
||||
@@ -1,15 +0,0 @@
|
||||
# Legacy, F8R8, Flash 80M DDR, PSRAM 80M DDR
|
||||
|
||||
CONFIG_IDF_TARGET="esp32s3"
|
||||
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
||||
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
|
||||
CONFIG_ESPTOOLPY_OCT_FLASH=y
|
||||
CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_DTR=y
|
||||
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||
CONFIG_SPIRAM=y
|
||||
CONFIG_SPIRAM_MODE_OCT=y
|
||||
CONFIG_SPIRAM_SPEED_80M=y
|
||||
CONFIG_SPIRAM_ECC_ENABLE=y
|
||||
@@ -1,14 +0,0 @@
|
||||
# Legacy, F8R8, Flash 80M SDR, PSRAM 80M DDR
|
||||
|
||||
CONFIG_IDF_TARGET="esp32s3"
|
||||
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
||||
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
|
||||
CONFIG_ESPTOOLPY_OCT_FLASH=y
|
||||
CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_STR=y
|
||||
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||
CONFIG_SPIRAM=y
|
||||
CONFIG_SPIRAM_MODE_OCT=y
|
||||
CONFIG_SPIRAM_SPEED_80M=y
|
||||
@@ -1,5 +0,0 @@
|
||||
CONFIG_SPIRAM=y
|
||||
CONFIG_SPIRAM_SPEED_80M=y
|
||||
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
|
||||
CONFIG_SPI_FLASH_AUTO_SUSPEND=y
|
||||
CONFIG_LOG_IN_IRAM=n
|
||||
@@ -1,4 +0,0 @@
|
||||
CONFIG_SPIRAM=y
|
||||
CONFIG_SPIRAM_SPEED_80M=y
|
||||
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
|
||||
CONFIG_SPIRAM_XIP_FROM_PSRAM=y
|
||||
@@ -1,6 +0,0 @@
|
||||
CONFIG_FREERTOS_HZ=1000
|
||||
CONFIG_ESP_TASK_WDT_EN=n
|
||||
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
||||
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
|
||||
Reference in New Issue
Block a user