diff --git a/components/esp_hw_support/mspi_timing_tuning/port/esp32c61/CMakeLists.txt b/components/esp_hw_support/mspi_timing_tuning/port/esp32c61/CMakeLists.txt new file mode 100644 index 0000000000..b8b6e61170 --- /dev/null +++ b/components/esp_hw_support/mspi_timing_tuning/port/esp32c61/CMakeLists.txt @@ -0,0 +1,11 @@ +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}) diff --git a/components/esp_hw_support/mspi_timing_tuning/port/esp32c61/mspi_timing_config.c b/components/esp_hw_support/mspi_timing_tuning/port/esp32c61/mspi_timing_config.c new file mode 100644 index 0000000000..0d1474060b --- /dev/null +++ b/components/esp_hw_support/mspi_timing_tuning/port/esp32c61/mspi_timing_config.c @@ -0,0 +1,78 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#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_EARLY_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_EARLY_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_EARLY_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_EARLY_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); +} diff --git a/components/esp_hw_support/mspi_timing_tuning/port/esp32c61/mspi_timing_tuning_configs.h b/components/esp_hw_support/mspi_timing_tuning/port/esp32c61/mspi_timing_tuning_configs.h new file mode 100644 index 0000000000..42755b434f --- /dev/null +++ b/components/esp_hw_support/mspi_timing_tuning/port/esp32c61/mspi_timing_tuning_configs.h @@ -0,0 +1,119 @@ +/* + * SPDX-FileCopyrightText: 2025 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" + +#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 + +//--------------------------------------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 0 + +//--------------------------------------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 +#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/PSRAM CORE CLOCK ///////////////////////////////////// +#if ((CONFIG_ESPTOOLPY_FLASHFREQ_80M && !CONFIG_SPIRAM) || (CONFIG_ESPTOOLPY_FLASHFREQ_80M && CONFIG_SPIRAM_SPEED_80M)) +#define MSPI_TIMING_FLASH_EXPECTED_CORE_CLK_MHZ 80 +#define MSPI_TIMING_PSRAM_EXPECTED_CORE_CLK_MHZ 80 +#define MSPI_TIMING_FLASH_CONSECUTIVE_LEN_MAX 6 +#else +#define MSPI_TIMING_FLASH_EXPECTED_CORE_CLK_MHZ 240 +#define MSPI_TIMING_PSRAM_EXPECTED_CORE_CLK_MHZ 240 +#define MSPI_TIMING_FLASH_CONSECUTIVE_LEN_MAX 4 +#endif + +//------------------------------------------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 + + +//------------------------------------------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 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 240M, module clock 120M, STR mode +#define MSPI_TIMING_PSRAM_CONFIG_TABLE_CORE_CLK_240M_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_240M_MODULE_CLK_120M_STR_MODE 12 +#define MSPI_TIMING_PSRAM_DEFAULT_CONFIG_ID_CORE_CLK_240M_MODULE_CLK_120M_STR_MODE 4 + +//PSRAM: core clock 240M, module clock 80M, STR mode +#define MSPI_TIMING_PSRAM_CONFIG_TABLE_CORE_CLK_240M_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_240M_MODULE_CLK_80M_STR_MODE 14 +#define MSPI_TIMING_PSRAM_DEFAULT_CONFIG_ID_CORE_CLK_240M_MODULE_CLK_80M_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 diff --git a/components/hal/esp32c61/include/hal/mspi_ll.h b/components/hal/esp32c61/include/hal/mspi_ll.h index 855d5cf3fa..0e048874d4 100644 --- a/components/hal/esp32c61/include/hal/mspi_ll.h +++ b/components/hal/esp32c61/include/hal/mspi_ll.h @@ -23,6 +23,8 @@ #include "soc/soc.h" #include "soc/clk_tree_defs.h" #include "soc/pcr_struct.h" +#include "soc/spi_mem_struct.h" +#include "soc/spi_mem_reg.h" #include "hal/misc.h" #include "hal/assert.h" @@ -99,6 +101,333 @@ static inline __attribute__((always_inline)) void mspi_timing_ll_enable_core_clo } +/** + * Reset the MSPI clock + */ +static inline __attribute__((always_inline)) void _mspi_timing_ll_reset_mspi(void) +{ + PCR.mspi_clk_conf.mspi_axi_rst_en = 1; + PCR.mspi_clk_conf.mspi_axi_rst_en = 0; + // Wait for mspi to be ready + while (!PCR.mspi_conf.mspi_ready) { + ; + }; +} + +/** + * Calculate spi_flash clock frequency division parameters for register. + * + * @param clkdiv frequency division factor + * + * @return Register setting for the given clock division factor. + */ +static inline uint32_t mspi_timing_ll_calculate_clock_reg(uint8_t clkdiv) +{ + uint32_t div_parameter; + // See comments of `clock` in `spi_mem_struct.h` + if (clkdiv == 1) { + div_parameter = (1 << 31); + } else { + div_parameter = ((clkdiv - 1) | (((clkdiv - 1) / 2 & 0xff) << 8 ) | (((clkdiv - 1) & 0xff) << 16)); + } + return div_parameter; +} + +/** + * Clear MSPI hw fifo + * + * @param mspi_id SPI0 / SPI1 + */ +__attribute__((always_inline)) +static inline void mspi_timing_ll_clear_fifo(uint8_t mspi_id) +{ + for (int i = 0; i < 16; i++) { + REG_WRITE(SPI_MEM_W0_REG(mspi_id) + i * 4, 0); + } +} + +/*--------------------------------------------------------------- + FLASH +---------------------------------------------------------------*/ +/** + * @brief Set Flash clock + * + * @param mspi_id mspi_id + * @param clock_conf Configuration value for flash clock + */ +__attribute__((always_inline)) +static inline void mspi_timing_ll_set_flash_clock(uint32_t mspi_id, uint32_t clock_conf) +{ + if (mspi_id == MSPI_TIMING_LL_MSPI_ID_0) { + SPIMEM0.mem_clock.val = clock_conf; + } else if (mspi_id == MSPI_TIMING_LL_MSPI_ID_1) { + SPIMEM1.clock.val = clock_conf; + } +} + +/** + * Enable Flash timing adjust clock + * + * @param mspi_id SPI0 / SPI1 + */ +__attribute__((always_inline)) +static inline void mspi_timinng_ll_enable_flash_timing_adjust_clk(uint8_t mspi_id) +{ + SPIMEM0.mem_timing_cali.mem_timing_clk_ena = true; +} + +/** + * Set MSPI Flash din mode + * + * @param mspi_id SPI0 / SPI1 + * @param din_mode Din mode value + */ +__attribute__((always_inline)) +static inline void mspi_timing_ll_set_flash_din_mode(uint8_t mspi_id, uint8_t din_mode) +{ + uint32_t reg_val = (REG_READ(SPI_MEM_DIN_MODE_REG(mspi_id)) & (~(SPI_MEM_DIN0_MODE_M | SPI_MEM_DIN1_MODE_M | SPI_MEM_DIN2_MODE_M | SPI_MEM_DIN3_MODE_M | SPI_MEM_DIN4_MODE_M | SPI_MEM_DIN5_MODE_M | SPI_MEM_DIN6_MODE_M | SPI_MEM_DIN7_MODE_M | SPI_MEM_DINS_MODE_M))) + | (din_mode << SPI_MEM_DIN0_MODE_S) | (din_mode << SPI_MEM_DIN1_MODE_S) | (din_mode << SPI_MEM_DIN2_MODE_S) | (din_mode << SPI_MEM_DIN3_MODE_S) + | (din_mode << SPI_MEM_DIN4_MODE_S) | (din_mode << SPI_MEM_DIN5_MODE_S) | (din_mode << SPI_MEM_DIN6_MODE_S) | (din_mode << SPI_MEM_DIN7_MODE_S) | (din_mode << SPI_MEM_DINS_MODE_S); + REG_WRITE(SPI_MEM_DIN_MODE_REG(mspi_id), reg_val); + REG_SET_BIT(SPI_MEM_TIMING_CALI_REG(MSPI_TIMING_LL_MSPI_ID_0), SPI_MEM_TIMING_CALI_UPDATE); +} + +/** + * Set MSPI Flash din num + * + * @param mspi_id SPI0 / SPI1 + * @param din_num Din num value + */ +__attribute__((always_inline)) +static inline void mspi_timing_ll_set_flash_din_num(uint8_t mspi_id, uint8_t din_num) +{ + uint32_t reg_val = (REG_READ(SPI_MEM_DIN_NUM_REG(mspi_id)) & (~(SPI_MEM_DIN0_NUM_M | SPI_MEM_DIN1_NUM_M | SPI_MEM_DIN2_NUM_M | SPI_MEM_DIN3_NUM_M | SPI_MEM_DIN4_NUM_M | SPI_MEM_DIN5_NUM_M | SPI_MEM_DIN6_NUM_M | SPI_MEM_DIN7_NUM_M | SPI_MEM_DINS_NUM_M))) + | (din_num << SPI_MEM_DIN0_NUM_S) | (din_num << SPI_MEM_DIN1_NUM_S) | (din_num << SPI_MEM_DIN2_NUM_S) | (din_num << SPI_MEM_DIN3_NUM_S) + | (din_num << SPI_MEM_DIN4_NUM_S) | (din_num << SPI_MEM_DIN5_NUM_S) | (din_num << SPI_MEM_DIN6_NUM_S) | (din_num << SPI_MEM_DIN7_NUM_S) | (din_num << SPI_MEM_DINS_NUM_S); + REG_WRITE(SPI_MEM_DIN_NUM_REG(mspi_id), reg_val); + REG_SET_BIT(SPI_MEM_TIMING_CALI_REG(MSPI_TIMING_LL_MSPI_ID_0), SPI_MEM_TIMING_CALI_UPDATE); +} + +/** + * Set MSPI Flash extra dummy + * + * @param mspi_id SPI0 / SPI1 + * @param extra_dummy Extra dummy + */ +__attribute__((always_inline)) +static inline void mspi_timing_ll_set_flash_extra_dummy(uint8_t mspi_id, uint8_t extra_dummy) +{ + if (extra_dummy > 0) { + SET_PERI_REG_MASK(SPI_MEM_TIMING_CALI_REG(mspi_id), SPI_MEM_TIMING_CALI_M); + SET_PERI_REG_BITS(SPI_MEM_TIMING_CALI_REG(mspi_id), SPI_MEM_EXTRA_DUMMY_CYCLELEN_V, extra_dummy, SPI_MEM_EXTRA_DUMMY_CYCLELEN_S); + } else { + CLEAR_PERI_REG_MASK(SPI_MEM_TIMING_CALI_REG(mspi_id), SPI_MEM_TIMING_CALI_M); + SET_PERI_REG_BITS(SPI_MEM_TIMING_CALI_REG(mspi_id), SPI_MEM_EXTRA_DUMMY_CYCLELEN_V, 0, SPI_MEM_EXTRA_DUMMY_CYCLELEN_S); + } + REG_SET_BIT(SPI_MEM_TIMING_CALI_REG(MSPI_TIMING_LL_MSPI_ID_0), SPI_MEM_TIMING_CALI_UPDATE); +} + +/** + * Get MSPI flash dummy info + * + * @param mspi_id SPI0 / SPI1 + * @param usr_dummy User dummy + * @param extra_dummy Extra dummy + */ +__attribute__((always_inline)) +static inline void mspi_timing_ll_get_flash_dummy(uint8_t mspi_id, int *usr_dummy, int *extra_dummy) +{ + *usr_dummy = REG_GET_FIELD(SPI_MEM_USER1_REG(mspi_id), SPI_MEM_USR_DUMMY_CYCLELEN); + *extra_dummy = REG_GET_FIELD(SPI_MEM_TIMING_CALI_REG(mspi_id), SPI_MEM_EXTRA_DUMMY_CYCLELEN); +} + +/** + * Enable/Disable Flash variable dummy + * + * @param mspi_id SPI0 / SPI1 + * @param enable Enable / Disable + */ +__attribute__((always_inline)) +static inline void mspi_timing_ll_enable_flash_variable_dummy(uint8_t mspi_id, bool enable) +{ + REG_SET_FIELD(SPI_MEM_DDR_REG(mspi_id), SPI_FMEM_VAR_DUMMY, enable); +} + +/** + * Get if cs setup is enabled or not + * + * @param mspi_id SPI0 / SPI1 + * + * @return + * true: enabled; false: disabled + */ +__attribute__((always_inline)) +static inline bool mspi_timing_ll_is_cs_setup_enabled(uint8_t mspi_id) +{ + return REG_GET_BIT(SPI_MEM_USER_REG(mspi_id), SPI_MEM_CS_SETUP); +} + +/** + * Get cs setup val + * + * @param mspi_id SPI0 / SPI1 + * + * @return + * cs setup reg val + */ +static inline uint32_t mspi_timing_ll_get_cs_setup_val(uint8_t mspi_id) +{ + return REG_GET_FIELD(SPI_MEM_CTRL2_REG(mspi_id), SPI_MEM_CS_SETUP_TIME); +} + +/** + * Get if cs hold is enabled or not + * + * @param mspi_id SPI0 / SPI1 + * + * @return + * true: enabled; false: disabled + */ +__attribute__((always_inline)) +static inline bool mspi_timing_ll_is_cs_hold_enabled(uint8_t mspi_id) +{ + return REG_GET_FIELD(SPI_MEM_USER_REG(mspi_id), SPI_MEM_CS_HOLD); +} + +/** + * Get cs hold val + * + * @param mspi_id SPI0 / SPI1 + * + * @return + * cs hold reg val + */ +static inline uint32_t mspi_timing_ll_get_cs_hold_val(uint8_t mspi_id) +{ + return REG_GET_FIELD(SPI_MEM_CTRL2_REG(mspi_id), SPI_MEM_CS_HOLD_TIME); +} + +/** + * Get clock reg val + * + * @param mspi_id SPI0 / SPI1 + * + * @return + * clock reg val + */ +__attribute__((always_inline)) +static inline uint32_t mspi_timing_ll_get_clock_reg(uint8_t mspi_id) +{ + return READ_PERI_REG(SPI_MEM_CLOCK_REG(mspi_id)); +} + +/*--------------------------------------------------------------- + PSRAM +---------------------------------------------------------------*/ +/** + * @brief Set PSRAM clock + * + * @param mspi_id mspi_id + * @param clock_conf Configuration value for psram clock + */ +__attribute__((always_inline)) +static inline void mspi_timing_ll_set_psram_clock(uint32_t mspi_id, uint32_t clock_conf) +{ + SPIMEM0.mem_sram_clk.val = clock_conf; +} + +/** + * @brief Set SPI1 bus clock to initialise PSRAM + * + * @param mspi_id mspi_id + * @param clock_conf Configuration value for psram clock + */ +__attribute__((always_inline)) +static inline void mspi_timing_ll_set_spi1_bus_clock(uint32_t mspi_id, uint32_t clock_conf) +{ + HAL_ASSERT(mspi_id == MSPI_TIMING_LL_MSPI_ID_1); + SPIMEM1.clock.val = clock_conf; +} + +/** + * Enable PSRAM timing adjust clock + * + * @param mspi_id SPI0 / SPI1 + */ +__attribute__((always_inline)) +static inline void mspi_timinng_ll_enable_psram_timing_adjust_clk(uint8_t mspi_id) +{ + SPIMEM0.smem_timing_cali.smem_timing_clk_ena = true; +} + +/** + * Set MSPI PSRAM din mode + * + * @param mspi_id SPI0 / SPI1 + * @param din_mode Din mode value + */ +__attribute__((always_inline)) +static inline void mspi_timing_ll_set_psram_din_mode(uint8_t mspi_id, uint8_t din_mode) +{ + uint32_t reg_val = (REG_READ(SPI_SMEM_DIN_MODE_REG(mspi_id)) & (~(SPI_SMEM_DIN0_MODE_M | SPI_SMEM_DIN1_MODE_M | SPI_SMEM_DIN2_MODE_M | SPI_SMEM_DIN3_MODE_M | SPI_SMEM_DIN4_MODE_M | SPI_SMEM_DIN5_MODE_M | SPI_SMEM_DIN6_MODE_M | SPI_SMEM_DIN7_MODE_M | SPI_SMEM_DINS_MODE_M))) + | (din_mode << SPI_SMEM_DIN0_MODE_S) | (din_mode << SPI_SMEM_DIN1_MODE_S) | (din_mode << SPI_SMEM_DIN2_MODE_S) | (din_mode << SPI_SMEM_DIN3_MODE_S) + | (din_mode << SPI_SMEM_DIN4_MODE_S) | (din_mode << SPI_SMEM_DIN5_MODE_S) | (din_mode << SPI_SMEM_DIN6_MODE_S) | (din_mode << SPI_SMEM_DIN7_MODE_S) | (din_mode << SPI_SMEM_DINS_MODE_S); + REG_WRITE(SPI_SMEM_DIN_MODE_REG(mspi_id), reg_val); + REG_SET_BIT(SPI_MEM_TIMING_CALI_REG(MSPI_TIMING_LL_MSPI_ID_0), SPI_MEM_TIMING_CALI_UPDATE); +} + +/** + * Set MSPI PSRAM din num + * + * @param mspi_id SPI0 / SPI1 + * @param din_num Din num value + */ +__attribute__((always_inline)) +static inline void mspi_timing_ll_set_psram_din_num(uint8_t mspi_id, uint8_t din_num) +{ + uint32_t reg_val = (REG_READ(SPI_SMEM_DIN_NUM_REG(mspi_id)) & (~(SPI_SMEM_DIN0_NUM_M | SPI_SMEM_DIN1_NUM_M | SPI_SMEM_DIN2_NUM_M | SPI_SMEM_DIN3_NUM_M | SPI_SMEM_DIN4_NUM_M | SPI_SMEM_DIN5_NUM_M | SPI_SMEM_DIN6_NUM_M | SPI_SMEM_DIN7_NUM_M | SPI_SMEM_DINS_NUM_M))) + | (din_num << SPI_SMEM_DIN0_NUM_S) | (din_num << SPI_SMEM_DIN1_NUM_S) | (din_num << SPI_SMEM_DIN2_NUM_S) | (din_num << SPI_SMEM_DIN3_NUM_S) + | (din_num << SPI_SMEM_DIN4_NUM_S) | (din_num << SPI_SMEM_DIN5_NUM_S) | (din_num << SPI_SMEM_DIN6_NUM_S) | (din_num << SPI_SMEM_DIN7_NUM_S) | (din_num << SPI_SMEM_DINS_NUM_S); + REG_WRITE(SPI_SMEM_DIN_NUM_REG(mspi_id), reg_val); + REG_SET_BIT(SPI_MEM_TIMING_CALI_REG(MSPI_TIMING_LL_MSPI_ID_0), SPI_MEM_TIMING_CALI_UPDATE); +} + +/** + * Set MSPI Octal PSRAM extra dummy + * + * @param mspi_id SPI0 / SPI1 + * @param extra_dummy Extra dummy + */ +__attribute__((always_inline)) +static inline void mspi_timing_ll_set_psram_extra_dummy(uint8_t mspi_id, uint8_t extra_dummy) +{ + if (extra_dummy > 0) { + SET_PERI_REG_MASK(SPI_SMEM_TIMING_CALI_REG(mspi_id), SPI_SMEM_TIMING_CALI_M); + SET_PERI_REG_BITS(SPI_SMEM_TIMING_CALI_REG(mspi_id), SPI_SMEM_EXTRA_DUMMY_CYCLELEN_V, extra_dummy, + SPI_SMEM_EXTRA_DUMMY_CYCLELEN_S); + } else { + CLEAR_PERI_REG_MASK(SPI_SMEM_TIMING_CALI_REG(mspi_id), SPI_SMEM_TIMING_CALI_M); + SET_PERI_REG_BITS(SPI_SMEM_TIMING_CALI_REG(mspi_id), SPI_SMEM_EXTRA_DUMMY_CYCLELEN_V, 0, + SPI_SMEM_EXTRA_DUMMY_CYCLELEN_S); + } + REG_SET_BIT(SPI_MEM_TIMING_CALI_REG(MSPI_TIMING_LL_MSPI_ID_0), SPI_MEM_TIMING_CALI_UPDATE); +} + +/** + * Get MSPI PSRAM dummy info + * + * @param mspi_id SPI0 / SPI1 + * @param usr_rdummy User read dummy + * @param extra_dummy Extra dummy + */ +__attribute__((always_inline)) +static inline void mspi_timing_ll_get_psram_dummy(uint8_t mspi_id, int *usr_rdummy, int *extra_dummy) +{ + *usr_rdummy = REG_GET_FIELD(SPI_MEM_CACHE_SCTRL_REG(mspi_id), SPI_MEM_SRAM_RDUMMY_CYCLELEN); + *extra_dummy = REG_GET_FIELD(SPI_SMEM_TIMING_CALI_REG(mspi_id), SPI_SMEM_EXTRA_DUMMY_CYCLELEN); +} + + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32c61/include/hal/spimem_flash_ll.h b/components/hal/esp32c61/include/hal/spimem_flash_ll.h index 2174d97944..b5cabfaf5f 100644 --- a/components/hal/esp32c61/include/hal/spimem_flash_ll.h +++ b/components/hal/esp32c61/include/hal/spimem_flash_ll.h @@ -624,11 +624,39 @@ static inline void spimem_flash_ll_set_hold(spi_mem_dev_t *dev, uint32_t hold_n) // Not supported on esp32c61 } +/** + * Set CS setup time. + * + * @param dev Beginning address of the peripheral registers. + * @param cs_setup_time CS setup time config used by the host. + */ static inline void spimem_flash_ll_set_cs_setup(spi_mem_dev_t *dev, uint32_t cs_setup_time) { // Not supported on esp32c61 } +/** + * Set extra dummy. + * + * @param dev Beginning address of the peripheral registers. + * @param extra_dummy Extra dummy + */ +static inline void spimem_flash_ll_set_extra_dummy(spi_mem_dev_t *dev, uint32_t extra_dummy) +{ + //for compatibility +} + +/** + * Set FDUMMY_RIN. + * + * @param dev Beginning address of the peripheral registers. + * @param fdummy_rin fdummy_rin value + */ +static inline void spimem_flash_ll_set_fdummy_rin(spi_mem_dev_t *dev, uint32_t fdummy_rin) +{ + dev->ctrl.fdummy_rin = fdummy_rin; +} + /** * Get the spi flash source clock frequency. Used for calculating * the divider parameters. diff --git a/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in index a241416a55..4697c679ae 100644 --- a/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in @@ -855,10 +855,18 @@ config SOC_SPI_MEM_SUPPORT_WRAP bool default y +config SOC_SPI_MEM_SUPPORT_TIMING_TUNING + bool + default y + config SOC_SPI_MEM_SUPPORT_TSUS_TRES_SEPERATE_CTR bool default y +config SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY + bool + default y + config SOC_MEMSPI_SRC_FREQ_80M_SUPPORTED bool default y diff --git a/components/soc/esp32c61/include/soc/soc_caps.h b/components/soc/esp32c61/include/soc/soc_caps.h index 2a02538e74..8f24373341 100644 --- a/components/soc/esp32c61/include/soc/soc_caps.h +++ b/components/soc/esp32c61/include/soc/soc_caps.h @@ -354,7 +354,9 @@ #define SOC_SPI_MEM_SUPPORT_SW_SUSPEND (1) #define SOC_SPI_MEM_SUPPORT_CHECK_SUS (1) #define SOC_SPI_MEM_SUPPORT_WRAP (1) +#define SOC_SPI_MEM_SUPPORT_TIMING_TUNING (1) #define SOC_SPI_MEM_SUPPORT_TSUS_TRES_SEPERATE_CTR (1) +#define SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY (1) #define SOC_MEMSPI_SRC_FREQ_80M_SUPPORTED 1 #define SOC_MEMSPI_SRC_FREQ_40M_SUPPORTED 1