mirror of
https://github.com/espressif/esp-idf.git
synced 2025-07-30 18:57:19 +02:00
feat(mspi): supported psram 80MHz timing tuning
This commit is contained in:
@ -55,7 +55,7 @@ void IRAM_ATTR bootloader_init_mspi_clock(void)
|
|||||||
// SPLL clock on C5 is 480MHz , and mspi_pll needs 80MHz
|
// SPLL clock on C5 is 480MHz , and mspi_pll needs 80MHz
|
||||||
// in this stage, set divider as 6
|
// in this stage, set divider as 6
|
||||||
_mspi_timing_ll_set_flash_clk_src(0, FLASH_CLK_SRC_SPLL);
|
_mspi_timing_ll_set_flash_clk_src(0, FLASH_CLK_SRC_SPLL);
|
||||||
mspi_ll_fast_set_hs_divider(6);
|
mspi_timing_ll_set_core_clock(MSPI_TIMING_LL_MSPI_ID_0, MSPI_TIMING_LL_CORE_CLOCK_MHZ_DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IRAM_ATTR bootloader_flash_clock_config(const esp_image_header_t *pfhdr)
|
void IRAM_ATTR bootloader_flash_clock_config(const esp_image_header_t *pfhdr)
|
||||||
|
@ -52,7 +52,7 @@ void IRAM_ATTR bootloader_init_mspi_clock(void)
|
|||||||
// SPLL clock on C61 is 480MHz , and mspi_pll needs 80MHz
|
// SPLL clock on C61 is 480MHz , and mspi_pll needs 80MHz
|
||||||
// in this stage, set divider as 6
|
// in this stage, set divider as 6
|
||||||
_mspi_timing_ll_set_flash_clk_src(0, FLASH_CLK_SRC_DEFAULT);
|
_mspi_timing_ll_set_flash_clk_src(0, FLASH_CLK_SRC_DEFAULT);
|
||||||
mspi_ll_fast_set_hs_divider(6);
|
mspi_timing_ll_set_core_clock(MSPI_TIMING_LL_MSPI_ID_0, MSPI_TIMING_LL_CORE_CLOCK_MHZ_DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IRAM_ATTR bootloader_flash_clock_config(const esp_image_header_t *pfhdr)
|
void IRAM_ATTR bootloader_flash_clock_config(const esp_image_header_t *pfhdr)
|
||||||
|
@ -134,8 +134,8 @@ if(NOT non_os_build)
|
|||||||
|
|
||||||
if(NOT CONFIG_APP_BUILD_TYPE_PURE_RAM_APP)
|
if(NOT CONFIG_APP_BUILD_TYPE_PURE_RAM_APP)
|
||||||
list(APPEND srcs "mspi_timing_tuning/mspi_timing_tuning.c")
|
list(APPEND srcs "mspi_timing_tuning/mspi_timing_tuning.c")
|
||||||
if(CONFIG_SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY)
|
if(CONFIG_SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY AND NOT CONFIG_IDF_TARGET_ESP32S3)
|
||||||
if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/mspi_timing_tuning/mspi_timing_by_mspi_delay.c")
|
if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/mspi_timing_tuning/tuning_scheme_impl/mspi_timing_by_mspi_delay.c")
|
||||||
list(APPEND srcs "mspi_timing_tuning/tuning_scheme_impl/mspi_timing_by_mspi_delay.c")
|
list(APPEND srcs "mspi_timing_tuning/tuning_scheme_impl/mspi_timing_by_mspi_delay.c")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
@ -233,6 +233,9 @@ static void s_sweep_for_success_sample_points(uint8_t *reference_data, void *con
|
|||||||
#endif
|
#endif
|
||||||
if (memcmp(reference_data, read_data, sizeof(read_data)) == 0) {
|
if (memcmp(reference_data, read_data, sizeof(read_data)) == 0) {
|
||||||
out_array[config_idx] += 1;
|
out_array[config_idx] += 1;
|
||||||
|
ESP_EARLY_LOGV(TAG, "config_idx: %d, good", config_idx);
|
||||||
|
} else {
|
||||||
|
ESP_EARLY_LOGV(TAG, "config_idx: %d, bad", config_idx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -619,9 +622,8 @@ void spi_timing_get_flash_timing_param(spi_flash_hal_timing_config_t *out_timing
|
|||||||
*----------------------------------------------------------------------------*/
|
*----------------------------------------------------------------------------*/
|
||||||
void mspi_timing_set_pin_drive_strength(void)
|
void mspi_timing_set_pin_drive_strength(void)
|
||||||
{
|
{
|
||||||
#if SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY
|
#if CONFIG_IDF_TARGET_ESP32S3
|
||||||
//For now, set them all to 3. Need to check after QVL test results are out. TODO: IDF-3663
|
|
||||||
//Set default pin drive
|
//Set default pin drive
|
||||||
mspi_timing_ll_set_all_pin_drive(0, 3);
|
mspi_timing_ll_set_all_pin_drive(0, 3);
|
||||||
#endif // #if SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -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})
|
@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 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 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
|
||||||
|
#endif
|
||||||
|
//------------------------------------FLASH Needs Tuning or not-------------------------------------//
|
||||||
|
#if 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_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 CORE CLOCK /////////////////////////////////////
|
||||||
|
#define MSPI_TIMING_FLASH_EXPECTED_CORE_CLK_MHZ 80
|
||||||
|
|
||||||
|
///////////////////////////////////// PSRAM CORE CLOCK /////////////////////////////////////
|
||||||
|
#if CONFIG_SPIRAM_SPEED_80M
|
||||||
|
#define MSPI_TIMING_PSRAM_EXPECTED_CORE_CLK_MHZ 80
|
||||||
|
#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
|
||||||
|
*/
|
||||||
|
//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 5
|
@ -12,6 +12,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include "sdkconfig.h"
|
||||||
#include "soc/soc_caps.h"
|
#include "soc/soc_caps.h"
|
||||||
#if SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY
|
#if SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY
|
||||||
#include "esp_private/mspi_timing_impl_types.h"
|
#include "esp_private/mspi_timing_impl_types.h"
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@ -110,11 +110,8 @@ static uint32_t s_select_best_tuning_config_str(const mspi_timing_config_t *conf
|
|||||||
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)
|
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;
|
uint32_t best_point = 0;
|
||||||
if (is_ddr) {
|
assert(!is_ddr);
|
||||||
assert(false);
|
best_point = s_select_best_tuning_config_str(configs, consecutive_length, end);
|
||||||
} else {
|
|
||||||
best_point = s_select_best_tuning_config_str(configs, consecutive_length, end);
|
|
||||||
}
|
|
||||||
|
|
||||||
return best_point;
|
return best_point;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,368 @@
|
|||||||
|
/*
|
||||||
|
* 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"
|
||||||
|
|
||||||
|
#define QPI_PSRAM_FAST_READ 0XEB
|
||||||
|
#define QPI_PSRAM_WRITE 0X38
|
||||||
|
#define QPI_PSRAM_FAST_READ_DUMMY 6
|
||||||
|
|
||||||
|
const static char *TAG = "MSPI Timing";
|
||||||
|
|
||||||
|
//-------------------------------------FLASH timing tuning register config-------------------------------------//
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------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_EARLY_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_EARLY_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_EARLY_LOGW(TAG, "tuning fail, best point is fallen back to index %"PRIu32"", best_point);
|
||||||
|
} else {
|
||||||
|
best_point = end - consecutive_length / 2;
|
||||||
|
ESP_EARLY_LOGI(TAG, "tuning success, best point is index %"PRIu32"", best_point);
|
||||||
|
}
|
||||||
|
|
||||||
|
return best_point;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t s_select_best_tuning_config(const mspi_timing_config_t *configs, uint32_t consecutive_length, uint32_t end, const uint8_t *reference_data, bool is_ddr, bool is_flash)
|
||||||
|
{
|
||||||
|
uint32_t best_point = 0;
|
||||||
|
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_EARLY_LOGI(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_EARLY_LOGI(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
|
||||||
|
}
|
||||||
|
|
||||||
|
int spi1_usr_dummy = 0;
|
||||||
|
int spi1_extra_dummy = 0;
|
||||||
|
int spi0_usr_dummy = 0;
|
||||||
|
int spi0_extra_dummy = 0;
|
||||||
|
mspi_timing_ll_get_flash_dummy(MSPI_TIMING_LL_MSPI_ID_0, &spi0_usr_dummy, &spi0_extra_dummy);
|
||||||
|
mspi_timing_ll_get_flash_dummy(MSPI_TIMING_LL_MSPI_ID_1, &spi1_usr_dummy, &spi1_extra_dummy);
|
||||||
|
ESP_EARLY_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_EARLY_LOGV(TAG, "psram, spi0_usr_rdummy: %d, spi0_extra_dummy: %d", spi0_usr_rdummy, spi0_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-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)
|
||||||
|
{
|
||||||
|
#if MSPI_TIMING_FLASH_NEEDS_TUNING
|
||||||
|
return s_flash_best_timing_tuning_config.extra_dummy_len;
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
@ -1,2 +1,2 @@
|
|||||||
CONFIG_SPIRAM=y
|
CONFIG_SPIRAM=y
|
||||||
CONFIG_SPIRAM_SPEED_40M=y
|
CONFIG_SPIRAM_SPEED_80M=y
|
||||||
|
@ -23,6 +23,8 @@
|
|||||||
#include "soc/soc.h"
|
#include "soc/soc.h"
|
||||||
#include "soc/clk_tree_defs.h"
|
#include "soc/clk_tree_defs.h"
|
||||||
#include "soc/pcr_struct.h"
|
#include "soc/pcr_struct.h"
|
||||||
|
#include "soc/spi_mem_struct.h"
|
||||||
|
#include "soc/spi_mem_reg.h"
|
||||||
#include "hal/misc.h"
|
#include "hal/misc.h"
|
||||||
#include "hal/assert.h"
|
#include "hal/assert.h"
|
||||||
|
|
||||||
@ -30,9 +32,86 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define MSPI_TIMING_LL_MSPI_ID_0 0
|
||||||
|
#define MSPI_TIMING_LL_MSPI_ID_1 1
|
||||||
|
#define MSPI_LL_CORE_CLOCK_80_MHZ 80
|
||||||
|
#define MSPI_LL_CORE_CLOCK_120_MHZ 120
|
||||||
|
#define MSPI_TIMING_LL_CORE_CLOCK_MHZ_DEFAULT MSPI_LL_CORE_CLOCK_80_MHZ
|
||||||
|
|
||||||
/************************** MSPI pll clock configurations **************************/
|
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------
|
||||||
|
MSPI
|
||||||
|
---------------------------------------------------------------*/
|
||||||
|
/**
|
||||||
|
* @brief Set MSPI_FAST_CLK's high-speed divider (valid when SOC_ROOT clock source is PLL)
|
||||||
|
*
|
||||||
|
* @param mspi_id SPI0 / SPI1
|
||||||
|
* @param core_clk_mhz core clock mhz
|
||||||
|
*/
|
||||||
|
static inline __attribute__((always_inline)) void mspi_timing_ll_set_core_clock(uint32_t mspi_id, uint32_t core_clk_mhz)
|
||||||
|
{
|
||||||
|
HAL_ASSERT(mspi_id == 0);
|
||||||
|
uint32_t divider = 0;
|
||||||
|
switch (core_clk_mhz) {
|
||||||
|
case 80:
|
||||||
|
divider = 6;
|
||||||
|
break;
|
||||||
|
case 120:
|
||||||
|
divider = 4;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
HAL_ASSERT(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
HAL_FORCE_MODIFY_U32_REG_FIELD(PCR.mspi_clk_conf, mspi_fast_div_num, divider - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable the mspi core clock
|
||||||
|
*
|
||||||
|
* @param mspi_id SPI0 / SPI1
|
||||||
|
* @param enable enable the core clock
|
||||||
|
*/
|
||||||
|
static inline __attribute__((always_inline)) void mspi_timing_ll_enable_core_clock(uint32_t mspi_id, bool enable)
|
||||||
|
{
|
||||||
|
PCR.mspi_conf.mspi_clk_en = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------
|
||||||
|
FLASH
|
||||||
|
---------------------------------------------------------------*/
|
||||||
/*
|
/*
|
||||||
* @brief Select FLASH clock source
|
* @brief Select FLASH clock source
|
||||||
*
|
*
|
||||||
@ -59,35 +138,281 @@ static inline void _mspi_timing_ll_set_flash_clk_src(uint32_t mspi_id, soc_perip
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set MSPI_FAST_CLK's high-speed divider (valid when SOC_ROOT clock source is PLL)
|
* @brief Set Flash clock
|
||||||
*
|
*
|
||||||
* @param divider Divider.
|
* @param mspi_id mspi_id
|
||||||
|
* @param clock_conf Configuration value for flash clock
|
||||||
*/
|
*/
|
||||||
static inline __attribute__((always_inline)) void mspi_ll_fast_set_hs_divider(uint32_t divider)
|
__attribute__((always_inline))
|
||||||
|
static inline void mspi_timing_ll_set_flash_clock(uint32_t mspi_id, uint32_t clock_conf)
|
||||||
{
|
{
|
||||||
HAL_FORCE_MODIFY_U32_REG_FIELD(PCR.mspi_clk_conf, mspi_fast_div_num, divider - 1);
|
if (mspi_id == MSPI_TIMING_LL_MSPI_ID_0) {
|
||||||
|
SPIMEM0.clock.val = clock_conf;
|
||||||
|
} else if (mspi_id == MSPI_TIMING_LL_MSPI_ID_1) {
|
||||||
|
SPIMEM1.clock.val = clock_conf;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Enable the mspi bus clock
|
* Enable Flash timing adjust clock
|
||||||
*
|
*
|
||||||
* @param enable enable the bus clock
|
* @param mspi_id SPI0 / SPI1
|
||||||
*/
|
*/
|
||||||
static inline __attribute__((always_inline)) void mspi_ll_enable_bus_clock(bool enable)
|
__attribute__((always_inline))
|
||||||
|
static inline void mspi_timinng_ll_enable_flash_timing_adjust_clk(uint8_t mspi_id)
|
||||||
{
|
{
|
||||||
PCR.mspi_conf.mspi_clk_en = enable;
|
SPIMEM0.mem_timing_cali.mem_timing_clk_ena = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset the MSPI clock
|
* Set MSPI Flash din mode
|
||||||
|
*
|
||||||
|
* @param mspi_id SPI0 / SPI1
|
||||||
|
* @param din_mode Din mode value
|
||||||
*/
|
*/
|
||||||
static inline __attribute__((always_inline)) void _mspi_timing_ll_reset_mspi(void)
|
__attribute__((always_inline))
|
||||||
|
static inline void mspi_timing_ll_set_flash_din_mode(uint8_t mspi_id, uint8_t din_mode)
|
||||||
{
|
{
|
||||||
PCR.mspi_clk_conf.mspi_axi_rst_en = 1;
|
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)))
|
||||||
PCR.mspi_clk_conf.mspi_axi_rst_en = 0;
|
| (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)
|
||||||
// Wait for mspi to be ready
|
| (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);
|
||||||
while (!PCR.mspi_conf.mspi_ready) {
|
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
|
#ifdef __cplusplus
|
||||||
|
@ -649,6 +649,11 @@ static inline void spimem_flash_ll_set_extra_dummy(spi_mem_dev_t *dev, uint32_t
|
|||||||
//for compatibility
|
//for compatibility
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
* Get the spi flash source clock frequency. Used for calculating
|
||||||
* the divider parameters.
|
* the divider parameters.
|
||||||
|
@ -30,6 +30,11 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define MSPI_TIMING_LL_MSPI_ID_0 0
|
||||||
|
#define MSPI_TIMING_LL_MSPI_ID_1 1
|
||||||
|
#define MSPI_LL_CORE_CLOCK_80_MHZ 80
|
||||||
|
#define MSPI_LL_CORE_CLOCK_120_MHZ 120
|
||||||
|
#define MSPI_TIMING_LL_CORE_CLOCK_MHZ_DEFAULT MSPI_LL_CORE_CLOCK_80_MHZ
|
||||||
|
|
||||||
/************************** MSPI pll clock configurations **************************/
|
/************************** MSPI pll clock configurations **************************/
|
||||||
|
|
||||||
@ -61,19 +66,34 @@ static inline void _mspi_timing_ll_set_flash_clk_src(uint32_t mspi_id, soc_perip
|
|||||||
/**
|
/**
|
||||||
* @brief Set MSPI_FAST_CLK's high-speed divider (valid when SOC_ROOT clock source is PLL)
|
* @brief Set MSPI_FAST_CLK's high-speed divider (valid when SOC_ROOT clock source is PLL)
|
||||||
*
|
*
|
||||||
* @param divider Divider.
|
* @param mspi_id SPI0 / SPI1
|
||||||
|
* @param core_clk_mhz core clock mhz
|
||||||
*/
|
*/
|
||||||
static inline __attribute__((always_inline)) void mspi_ll_fast_set_hs_divider(uint32_t divider)
|
static inline __attribute__((always_inline)) void mspi_timing_ll_set_core_clock(uint8_t mspi_id, uint32_t core_clk_mhz)
|
||||||
{
|
{
|
||||||
|
HAL_ASSERT(mspi_id == 0);
|
||||||
|
uint32_t divider = 0;
|
||||||
|
switch (core_clk_mhz) {
|
||||||
|
case 80:
|
||||||
|
divider = 6;
|
||||||
|
break;
|
||||||
|
case 120:
|
||||||
|
divider = 4;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
HAL_ASSERT(false);
|
||||||
|
}
|
||||||
|
|
||||||
HAL_FORCE_MODIFY_U32_REG_FIELD(PCR.mspi_clk_conf, mspi_fast_div_num, divider - 1);
|
HAL_FORCE_MODIFY_U32_REG_FIELD(PCR.mspi_clk_conf, mspi_fast_div_num, divider - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Enable the mspi bus clock
|
* @brief Enable the mspi core clock
|
||||||
*
|
*
|
||||||
* @param enable enable the bus clock
|
* @param mspi_id SPI0 / SPI1
|
||||||
|
* @param enable enable the core clock
|
||||||
*/
|
*/
|
||||||
static inline __attribute__((always_inline)) void mspi_ll_enable_bus_clock(bool enable)
|
static inline __attribute__((always_inline)) void mspi_timing_ll_enable_core_clock(uint8_t mspi_id, bool enable)
|
||||||
{
|
{
|
||||||
PCR.mspi_conf.mspi_clk_en = enable;
|
PCR.mspi_conf.mspi_clk_en = enable;
|
||||||
}
|
}
|
||||||
|
@ -1195,6 +1195,14 @@ config SOC_SPI_MEM_SUPPORT_CACHE_32BIT_ADDR_MAP
|
|||||||
bool
|
bool
|
||||||
default y
|
default y
|
||||||
|
|
||||||
|
config SOC_SPI_MEM_SUPPORT_TIMING_TUNING
|
||||||
|
bool
|
||||||
|
default y
|
||||||
|
|
||||||
|
config SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY
|
||||||
|
bool
|
||||||
|
default y
|
||||||
|
|
||||||
config SOC_MEMSPI_SRC_FREQ_80M_SUPPORTED
|
config SOC_MEMSPI_SRC_FREQ_80M_SUPPORTED
|
||||||
bool
|
bool
|
||||||
default y
|
default y
|
||||||
|
@ -472,6 +472,8 @@
|
|||||||
#define SOC_SPI_MEM_SUPPORT_WRAP (1)
|
#define SOC_SPI_MEM_SUPPORT_WRAP (1)
|
||||||
#define SOC_SPI_MEM_SUPPORT_WB_MODE_INDEPENDENT_CONTROL (1)
|
#define SOC_SPI_MEM_SUPPORT_WB_MODE_INDEPENDENT_CONTROL (1)
|
||||||
#define SOC_SPI_MEM_SUPPORT_CACHE_32BIT_ADDR_MAP (1)
|
#define SOC_SPI_MEM_SUPPORT_CACHE_32BIT_ADDR_MAP (1)
|
||||||
|
#define SOC_SPI_MEM_SUPPORT_TIMING_TUNING (1)
|
||||||
|
#define SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY (1)
|
||||||
|
|
||||||
#define SOC_MEMSPI_SRC_FREQ_80M_SUPPORTED 1
|
#define SOC_MEMSPI_SRC_FREQ_80M_SUPPORTED 1
|
||||||
#define SOC_MEMSPI_SRC_FREQ_40M_SUPPORTED 1
|
#define SOC_MEMSPI_SRC_FREQ_40M_SUPPORTED 1
|
||||||
|
Reference in New Issue
Block a user