diff --git a/arch/xtensa/src/esp32s3/esp32s3_psram_octal.c b/arch/xtensa/src/esp32s3/esp32s3_psram_octal.c index 92a9ef067b..f0f90d5e09 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_psram_octal.c +++ b/arch/xtensa/src/esp32s3/esp32s3_psram_octal.c @@ -603,6 +603,12 @@ int IRAM_ATTR psram_enable(int mode, int vaddrmode) psram_reg.mr2.density == 0x5 ? PSRAM_SIZE_16MB : psram_reg.mr2.density == 0x7 ? PSRAM_SIZE_32MB : 0; + /* Do PSRAM timing tuning, we use SPI1 to do the tuning, and set the SPI0 + * PSRAM timing related registers accordingly + */ + + esp32s3_spi_timing_set_mspi_psram_tuning(); + /* Back to the high speed mode. Flash/PSRAM clocks are set to the clock * that user selected. SPI0/1 registers are all set correctly. */ diff --git a/arch/xtensa/src/esp32s3/esp32s3_psram_quad.c b/arch/xtensa/src/esp32s3/esp32s3_psram_quad.c index f45c5968b0..98e2a2e16a 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_psram_quad.c +++ b/arch/xtensa/src/esp32s3/esp32s3_psram_quad.c @@ -29,6 +29,7 @@ #include "esp32s3_gpio.h" #include "esp32s3_psram.h" +#include "esp32s3_spi_timing.h" #include "rom/esp32s3_spiflash.h" #include "rom/esp32s3_opi_flash.h" @@ -453,7 +454,7 @@ int psram_enable(int mode, int vaddrmode) * PSRAM timing related registers accordingly */ - /* FIXME: spi_timing_psram_tuning(); */ + esp32s3_spi_timing_set_mspi_psram_tuning(); /* Configure SPI0 PSRAM related SPI Phases */ diff --git a/arch/xtensa/src/esp32s3/esp32s3_spi_timing.c b/arch/xtensa/src/esp32s3/esp32s3_spi_timing.c index 321e4f1051..47a897b20d 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_spi_timing.c +++ b/arch/xtensa/src/esp32s3/esp32s3_spi_timing.c @@ -23,7 +23,7 @@ ****************************************************************************/ #include - +#include #include #include "xtensa.h" @@ -158,6 +158,35 @@ # define PSRAM_CLOCK_DIVIDER 0 #endif +#define MSPI_TIMING_LL_FLASH_OCT_MASK (SPI_MEM_FCMD_OCT | SPI_MEM_FADDR_OCT | SPI_MEM_FDIN_OCT | SPI_MEM_FDOUT_OCT) +#define MSPI_TIMING_LL_FLASH_QUAD_MASK (SPI_MEM_FASTRD_MODE | SPI_MEM_FREAD_DUAL | SPI_MEM_FREAD_DIO | SPI_MEM_FREAD_QUAD | SPI_MEM_FREAD_QIO) +#define MSPI_TIMING_LL_FLASH_QIO_MODE_MASK (SPI_MEM_FREAD_QIO | SPI_MEM_FASTRD_MODE) +#define MSPI_TIMING_LL_FLASH_QUAD_MODE_MASK (SPI_MEM_FREAD_QUAD | SPI_MEM_FASTRD_MODE) +#define MSPI_TIMING_LL_FLASH_DIO_MODE_MASK (SPI_MEM_FREAD_DIO | SPI_MEM_FASTRD_MODE) +#define MSPI_TIMING_LL_FLASH_DUAL_MODE_MASK (SPI_MEM_FREAD_DUAL | SPI_MEM_FASTRD_MODE) +#define MSPI_TIMING_LL_FLASH_FAST_MODE_MASK (SPI_MEM_FASTRD_MODE) + +#define MSPI_TIMING_PSRAM_DTR_MODE CONFIG_ESP32S3_SPIRAM_MODE_OCT +#define MSPI_TIMING_PSRAM_STR_MODE !CONFIG_ESP32S3_SPIRAM_MODE_OCT +#define MSPI_TIMING_FLASH_DTR_MODE CONFIG_ESP32S3_FLASH_SAMPLE_MODE_DTR +#define MSPI_TIMING_FLASH_STR_MODE CONFIG_ESP32S3_FLASH_SAMPLE_MODE_STR + +#define MSPI_TIMING_TEST_DATA_LEN 64 +#define MSPI_TIMING_PSRAM_TEST_DATA_ADDR 0 +#define MSPI_TIMING_FLASH_TEST_DATA_ADDR 0 + +#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 + +#define g_spiflash_dummy_len_plus (rom_spiflash_legacy_data->dummy_len_plus) + /**************************************************************************** * Private Types ****************************************************************************/ @@ -170,6 +199,88 @@ enum core_clock_e CORE_CLOCK_240M = 3 }; +/**************************************************************************** + * Private Functions Prototypes + ****************************************************************************/ + +static void IRAM_ATTR set_psram_clock(uint8_t spi_num, uint32_t freqdiv); +static void IRAM_ATTR set_flash_clock(uint8_t spi_num, uint32_t freqdiv); +#if ESP32S3_SPI_TIMING_FLASH_TUNING || ESP32S3_SPI_TIMING_PSRAM_TUNING +static void init_spi1_for_tuning(bool is_flash); +static uint32_t get_dummy(void); +static void set_flash_extra_dummy(uint8_t spi_num, uint8_t extra_dummy); +static void set_psram_extra_dummy(uint8_t spi_num, uint8_t extra_dummy); +static void set_flash_din_mode_num(uint8_t spi_num, uint8_t din_mode, + uint8_t din_num); +static void set_psram_din_mode_num(uint8_t spi_num, uint8_t din_mode, + uint8_t din_num); +#if ESP32S3_SPI_TIMING_FLASH_TUNING +static void config_flash_read_data(uint8_t *buf, uint32_t addr, + uint32_t len); +static void config_flash_set_tuning_regs(const tuning_param_s *params); +static void get_flash_tuning_configs(tuning_config_s *config); +#endif +#if ESP32S3_SPI_TIMING_PSRAM_TUNING +static void psram_read_data(uint8_t *buf, uint32_t addr, uint32_t len); +static void psram_write_data(uint8_t *buf, uint32_t addr, uint32_t len); +static void config_psram_read_write_data(uint8_t *buf, uint32_t addr, + uint32_t len, bool is_read); +static void get_psram_tuning_configs(tuning_config_s *config); +static void config_psram_set_tuning_regs(const tuning_param_s *params); +#endif +static void sweep_for_success_sample_points(const uint8_t *reference_data, + const tuning_config_s *config, bool is_flash, uint8_t *out_array); +static void find_max_consecutive_success_points(uint8_t *array, + uint32_t size, uint32_t *out_length, uint32_t *out_end_index); +#if MSPI_TIMING_FLASH_STR_MODE || MSPI_TIMING_PSRAM_STR_MODE +static uint32_t select_best_tuning_config_str(tuning_config_s *config, + uint32_t consecutive_length, uint32_t end); +#endif +#if MSPI_TIMING_FLASH_DTR_MODE || MSPI_TIMING_PSRAM_DTR_MODE +static uint32_t select_best_tuning_config_dtr(tuning_config_s *config, + uint32_t consecutive_length, uint32_t end); +#endif +static void select_best_tuning_config(tuning_config_s *config, + uint32_t consecutive_length, uint32_t end, + const uint8_t *reference_data, bool is_flash); +static void set_timing_tuning_regs(bool control_spi1); +static void clear_timing_tuning_regs(bool control_spi1); +static void do_tuning(const uint8_t *reference_data, + tuning_config_s *timing_config, bool is_flash); +#endif + +/**************************************************************************** + * Extern Functions declaration + ****************************************************************************/ + +#if CONFIG_ESP32S3_SPIRAM_MODE_QUAD +extern void psram_exec_cmd(int spi_num, int 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 + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#if ESP32S3_SPI_TIMING_FLASH_TUNING || ESP32S3_SPI_TIMING_PSRAM_TUNING +#if CONFIG_ESP32S3_SPIRAM_MODE_QUAD +static uint8_t g_psram_extra_dummy; +#endif +static uint8_t g_flash_extra_dummy[2] = +{ + NOT_INIT_INT, + NOT_INIT_INT +}; + +static tuning_param_s g_flash_timing_tuning_config; +static tuning_param_s g_psram_timing_tuning_config; +#endif + /**************************************************************************** * Private Functions ****************************************************************************/ @@ -189,7 +300,7 @@ enum core_clock_e * ****************************************************************************/ -static void set_psram_clock(uint8_t spi_num, uint32_t freqdiv) +static void IRAM_ATTR set_psram_clock(uint8_t spi_num, uint32_t freqdiv) { if (freqdiv == 1) { @@ -238,6 +349,995 @@ static void IRAM_ATTR set_flash_clock(uint8_t spi_num, uint32_t freqdiv) } } +#if ESP32S3_SPI_TIMING_FLASH_TUNING || ESP32S3_SPI_TIMING_PSRAM_TUNING + +/**************************************************************************** + * Name: init_spi1_for_tuning + * + * Description: + * Initialize SPI1 for timing tuning. + * + * Input Parameters: + * is_flash - is flash or not + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static void init_spi1_for_tuning(bool is_flash) +{ + /* Set SPI1 core clock. SPI0 and SPI1 share the register for core clock. + * So we only set SPI0 here. + */ + + REG_SET_FIELD(SPI_MEM_CORE_CLK_SEL_REG(0), + SPI_MEM_CORE_CLK_SEL, + DEFAULT_CORE_CLK_REG); + + /* Set SPI1 module clock as required */ + + if (is_flash) + { + set_flash_clock(1, FLASH_CLOCK_DIVIDER); + + /* Enable Flash HCLK */ + + REG_SET_BIT(SPI_MEM_TIMING_CALI_REG(0), SPI_MEM_TIMING_CLK_ENA); + } + else + { + /* We use SPI1 Flash to tune PSRAM, PSRAM timing related regs + * do nothing on SPI1 + */ + + set_flash_clock(1, PSRAM_CLOCK_DIVIDER); + + /* Enable PSRAM HCLK */ + + REG_SET_BIT(SPI_MEM_SPI_SMEM_TIMING_CALI_REG(0), + SPI_MEM_SPI_SMEM_TIMING_CLK_ENA); + } +} + +/**************************************************************************** + * Name: get_dummy + * + * Description: + * Get dummy cycle length + * + * Input Parameters: + * None + * + * Returned Value: + * Dummy cycle length. + * + ****************************************************************************/ + +static uint32_t get_dummy(void) +{ + uint32_t ctrl_reg = READ_PERI_REG(SPI_MEM_CTRL_REG(0)); + if (ctrl_reg & MSPI_TIMING_LL_FLASH_OCT_MASK) + { + DEBUGPANIC(); + return 0; + } + + switch (ctrl_reg & MSPI_TIMING_LL_FLASH_QUAD_MASK) + { + case MSPI_TIMING_LL_FLASH_QIO_MODE_MASK: + return SPI1_R_QIO_DUMMY_CYCLELEN; + case MSPI_TIMING_LL_FLASH_DIO_MODE_MASK: + return SPI1_R_DIO_DUMMY_CYCLELEN; + case MSPI_TIMING_LL_FLASH_QUAD_MODE_MASK: + case MSPI_TIMING_LL_FLASH_DUAL_MODE_MASK: + case MSPI_TIMING_LL_FLASH_FAST_MODE_MASK: + return SPI1_R_FAST_DUMMY_CYCLELEN; + default: + DEBUGPANIC(); + return 0; + } +} + +/**************************************************************************** + * Name: set_flash_extra_dummy + * + * Description: + * Set MSPI Flash extra dummy + * + * Input Parameters: + * spi_num - SPI0 / 1 + * extra_dummy - extra dummy + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static void set_flash_extra_dummy(uint8_t spi_num, uint8_t extra_dummy) +{ +#ifdef CONFIG_ESP32S3_FLASH_MODE_OCT + if (extra_dummy > 0) + { + SET_PERI_REG_MASK(SPI_MEM_TIMING_CALI_REG(spi_num), + SPI_MEM_TIMING_CALI_M); + SET_PERI_REG_BITS(SPI_MEM_TIMING_CALI_REG(spi_num), + SPI_MEM_EXTRA_DUMMY_CYCLELEN_V, + extra_dummy, + SPI_MEM_EXTRA_DUMMY_CYCLELEN_S); + } + else + { + CLEAR_PERI_REG_MASK(SPI_MEM_TIMING_CALI_REG(spi_num), + SPI_MEM_TIMING_CALI_M); + SET_PERI_REG_BITS(SPI_MEM_TIMING_CALI_REG(spi_num), + SPI_MEM_EXTRA_DUMMY_CYCLELEN_V, 0, + SPI_MEM_EXTRA_DUMMY_CYCLELEN_S); + } + + return; +#endif + if (g_flash_extra_dummy[spi_num] == NOT_INIT_INT) + { + g_flash_extra_dummy[spi_num] = g_spiflash_dummy_len_plus[spi_num]; + } + + g_spiflash_dummy_len_plus[spi_num] = g_flash_extra_dummy[(int)spi_num] + + extra_dummy; + + /* Only Quad Flash will run into this branch. */ + + uint32_t dummy = get_dummy(); + + /* Set MSPI Quad Flash dummy */ + + SET_PERI_REG_MASK(SPI_MEM_USER_REG(spi_num), SPI_MEM_USR_DUMMY); + SET_PERI_REG_BITS(SPI_MEM_USER1_REG(spi_num), SPI_MEM_USR_DUMMY_CYCLELEN_V, + dummy + g_spiflash_dummy_len_plus[spi_num], + SPI_MEM_USR_DUMMY_CYCLELEN_S); +} + +/**************************************************************************** + * Name: set_psram_extra_dummy + * + * Description: + * Set MSPI PSRAM extra dummy + * + * Input Parameters: + * spi_num - SPI0 / 1 + * extra_dummy - extra dummy + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static void set_psram_extra_dummy(uint8_t spi_num, uint8_t extra_dummy) +{ +#if CONFIG_ESP32S3_SPIRAM_MODE_OCT + + /* Set MSPI Octal PSRAM extra dummy */ + + if (extra_dummy > 0) + { + SET_PERI_REG_MASK(SPI_MEM_SPI_SMEM_TIMING_CALI_REG(spi_num), + SPI_MEM_SPI_SMEM_TIMING_CALI_M); + SET_PERI_REG_BITS(SPI_MEM_SPI_SMEM_TIMING_CALI_REG(spi_num), + SPI_MEM_SPI_SMEM_EXTRA_DUMMY_CYCLELEN_V, + extra_dummy, + SPI_MEM_SPI_SMEM_EXTRA_DUMMY_CYCLELEN_S); + } + else + { + CLEAR_PERI_REG_MASK(SPI_MEM_SPI_SMEM_TIMING_CALI_REG(spi_num), + SPI_MEM_SPI_SMEM_TIMING_CALI_M); + SET_PERI_REG_BITS(SPI_MEM_SPI_SMEM_TIMING_CALI_REG(spi_num), + SPI_MEM_SPI_SMEM_EXTRA_DUMMY_CYCLELEN_V, 0, + SPI_MEM_SPI_SMEM_EXTRA_DUMMY_CYCLELEN_S); + } + +#elif CONFIG_ESP32S3_SPIRAM_MODE_QUAD + + /* Set MSPI QUAD PSRAM dummy. + * HW workaround: Use normal dummy register to set extra dummy, the + * calibration dedicated extra dummy register doesn't work for quad mode + */ + + SET_PERI_REG_MASK(SPI_MEM_CACHE_SCTRL_REG(spi_num), + SPI_MEM_USR_RD_SRAM_DUMMY_M); + SET_PERI_REG_BITS(SPI_MEM_CACHE_SCTRL_REG(spi_num), + SPI_MEM_SRAM_RDUMMY_CYCLELEN_V, + (QPI_PSRAM_FAST_READ_DUMMY + extra_dummy - 1), + SPI_MEM_SRAM_RDUMMY_CYCLELEN_S); +#endif +} + +/**************************************************************************** + * Name: set_flash_din_mode_num + * + * Description: + * Set MSPI Flash Din Mode and Din Num + * + * Input Parameters: + * spi_num - SPI0 / 1 + * din_mode - Din mode + * din_num - Din num + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static void set_flash_din_mode_num(uint8_t spi_num, uint8_t din_mode, + uint8_t din_num) +{ + /* Set MSPI Flash din mode */ + + uint32_t reg_val = (getreg32(SPI_MEM_DIN_MODE_REG(spi_num)) & + (~(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); + putreg32(reg_val, SPI_MEM_DIN_MODE_REG(spi_num)); + + /* Set MSPI Flash din num */ + + reg_val = (getreg32(SPI_MEM_DIN_NUM_REG(spi_num)) & + (~(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); + putreg32(reg_val, SPI_MEM_DIN_NUM_REG(spi_num)); +} + +/**************************************************************************** + * Name: set_psram_din_mode_num + * + * Description: + * Set MSPI PSRAM Din Mode and Din Num + * + * Input Parameters: + * spi_num - SPI0 / 1 + * din_mode - Din mode + * din_num - Din num + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static void set_psram_din_mode_num(uint8_t spi_num, uint8_t din_mode, + uint8_t din_num) +{ + /* Set MSPI PSRAM din mode */ + + uint32_t reg_val = (getreg32(SPI_MEM_SPI_SMEM_DIN_MODE_REG(spi_num)) & + (~(SPI_MEM_SPI_SMEM_DIN0_MODE_M | SPI_MEM_SPI_SMEM_DIN1_MODE_M | + SPI_MEM_SPI_SMEM_DIN2_MODE_M | SPI_MEM_SPI_SMEM_DIN3_MODE_M | + SPI_MEM_SPI_SMEM_DIN4_MODE_M | SPI_MEM_SPI_SMEM_DIN5_MODE_M | + SPI_MEM_SPI_SMEM_DIN6_MODE_M | SPI_MEM_SPI_SMEM_DIN7_MODE_M | + SPI_MEM_SPI_SMEM_DINS_MODE_M))) | + (din_mode << SPI_MEM_SPI_SMEM_DIN0_MODE_S) | + (din_mode << SPI_MEM_SPI_SMEM_DIN1_MODE_S) | + (din_mode << SPI_MEM_SPI_SMEM_DIN2_MODE_S) | + (din_mode << SPI_MEM_SPI_SMEM_DIN3_MODE_S) | + (din_mode << SPI_MEM_SPI_SMEM_DIN4_MODE_S) | + (din_mode << SPI_MEM_SPI_SMEM_DIN5_MODE_S) | + (din_mode << SPI_MEM_SPI_SMEM_DIN6_MODE_S) | + (din_mode << SPI_MEM_SPI_SMEM_DIN7_MODE_S) | + (din_mode << SPI_MEM_SPI_SMEM_DINS_MODE_S); + putreg32(reg_val, SPI_MEM_SPI_SMEM_DIN_MODE_REG(spi_num)); + + /* Set MSPI PSRAM din num */ + + reg_val = (getreg32(SPI_MEM_SPI_SMEM_DIN_NUM_REG(spi_num)) & + (~(SPI_MEM_SPI_SMEM_DIN0_NUM_M | SPI_MEM_SPI_SMEM_DIN1_NUM_M | + SPI_MEM_SPI_SMEM_DIN2_NUM_M | SPI_MEM_SPI_SMEM_DIN3_NUM_M | + SPI_MEM_SPI_SMEM_DIN4_NUM_M | SPI_MEM_SPI_SMEM_DIN5_NUM_M | + SPI_MEM_SPI_SMEM_DIN6_NUM_M | SPI_MEM_SPI_SMEM_DIN7_NUM_M | + SPI_MEM_SPI_SMEM_DINS_NUM_M))) | + (din_num << SPI_MEM_SPI_SMEM_DIN0_NUM_S) | + (din_num << SPI_MEM_SPI_SMEM_DIN1_NUM_S) | + (din_num << SPI_MEM_SPI_SMEM_DIN2_NUM_S) | + (din_num << SPI_MEM_SPI_SMEM_DIN3_NUM_S) | + (din_num << SPI_MEM_SPI_SMEM_DIN4_NUM_S) | + (din_num << SPI_MEM_SPI_SMEM_DIN5_NUM_S) | + (din_num << SPI_MEM_SPI_SMEM_DIN6_NUM_S) | + (din_num << SPI_MEM_SPI_SMEM_DIN7_NUM_S) | + (din_num << SPI_MEM_SPI_SMEM_DINS_NUM_S); + putreg32(reg_val, SPI_MEM_SPI_SMEM_DIN_NUM_REG(spi_num)); +} + +#if ESP32S3_SPI_TIMING_FLASH_TUNING + +/**************************************************************************** + * Name: config_flash_read_data + * + * Description: + * Configure Flash to read data via SPI1h + * + * Input Parameters: + * buf - data buffer pointer + * addr - target address value + * len - data length + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static void config_flash_read_data(uint8_t *buf, uint32_t addr, uint32_t len) +{ +#ifdef CONFIG_ESP32S3_FLASH_MODE_OCT + /* Clear MSPI hw fifo */ + + for (int i = 0; i < 16; i++) + { + putreg32(0, SPI_MEM_W0_REG(1) + i * 4); + } + + esp_rom_opiflash_read_raw(addr, buf, len); +#else + esp_rom_spiflash_read(addr, (uint32_t *)buf, len); +#endif +} + +/**************************************************************************** + * Name: config_flash_set_tuning_regs + * + * Description: + * Tune Flash timing registers for SPI1 accessing Flash + * + * Input Parameters: + * params - tuning timing parameters pointer + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static void config_flash_set_tuning_regs(const tuning_param_s *params) +{ + /* SPI_MEM_DINx_MODE(1), SPI_MEM_DINx_NUM(1) are meaningless SPI0 and SPI1 + * share SPI_MEM_DINx_MODE(0), SPI_MEM_DINx_NUM(0) for FLASH timing tuning + * We use SPI1 to get the best Flash timing tuning (mode and num) config + */ + + set_flash_din_mode_num(0, params->spi_din_mode, params->spi_din_num); + set_flash_extra_dummy(1, params->extra_dummy_len); +} + +/**************************************************************************** + * Name: get_flash_tuning_configs + * + * Description: + * Get FLASH tuning configuration. + * + * Input Parameters: + * config - tuning timing configuration pointer + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static void get_flash_tuning_configs(tuning_config_s *config) +{ +#if MSPI_TIMING_FLASH_DTR_MODE +# define FLASH_MODE DTR_MODE +#else +# define FLASH_MODE STR_MODE +#endif + +#if CONFIG_ESP32S3_FLASH_FREQ_20M + *config = MSPI_TIMING_FLASH_GET_TUNING_CONFIG( + ESP32S3_SPI_TIMING_CORE_CLK, 20, FLASH_MODE); +#elif CONFIG_ESP32S3_FLASH_FREQ_40M + *config = MSPI_TIMING_FLASH_GET_TUNING_CONFIG( + ESP32S3_SPI_TIMING_CORE_CLK, 40, FLASH_MODE); +#elif CONFIG_ESP32S3_FLASH_FREQ_80M + *config = MSPI_TIMING_FLASH_GET_TUNING_CONFIG( + ESP32S3_SPI_TIMING_CORE_CLK, 80, FLASH_MODE); +#elif CONFIG_ESP32S3_FLASH_FREQ_120M + *config = MSPI_TIMING_FLASH_GET_TUNING_CONFIG( + ESP32S3_SPI_TIMING_CORE_CLK, 120, FLASH_MODE); +#endif + +#undef FLASH_MODE +} +#endif + +#if ESP32S3_SPI_TIMING_PSRAM_TUNING + +/**************************************************************************** + * Name: psram_read_data + * + * Description: + * Configure PSRAM to read data via SPI1. + * + * Input Parameters: + * buf - data buffer pointer + * addr - target address value + * len - data length + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static void psram_read_data(uint8_t *buf, uint32_t addr, uint32_t len) +{ +#if CONFIG_ESP32S3_SPIRAM_MODE_OCT + + /* Clear MSPI hw fifo */ + + for (int i = 0; i < 16; i++) + { + putreg32(0, SPI_MEM_W0_REG(1) + i * 4); + } + + 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_ESP32S3_SPIRAM_MODE_QUAD + psram_exec_cmd(1, 0, + QPI_PSRAM_FAST_READ, 8, + addr, 24, + QPI_PSRAM_FAST_READ_DUMMY + g_psram_extra_dummy, + NULL, 0, + buf, len * 8, + SPI_MEM_CS1_DIS_M, + false); +#endif +} + +/**************************************************************************** + * Name: psram_write_data + * + * Description: + * Configure PSRAM to write data via SPI1. + * + * Input Parameters: + * buf - data buffer pointer + * addr - target address value + * len - data length + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static void psram_write_data(uint8_t *buf, uint32_t addr, uint32_t len) +{ +#if CONFIG_ESP32S3_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_ESP32S3_SPIRAM_MODE_QUAD + psram_exec_cmd(1, 0, + QPI_PSRAM_WRITE, 8, /* command and command bit len */ + addr, 24, /* address and address bit len */ + 0, /* dummy bit len */ + buf, len * 8, /* tx data and tx bit len */ + NULL, 0, /* rx data and rx bit len */ + SPI_MEM_CS1_DIS_M, /* cs bit mask */ + false); /* whether is program/erase operation */ +#endif +} + +/**************************************************************************** + * Name: config_psram_read_write_data + * + * Description: + * Configure PSRAM to read or write data via SPI1. + * + * Input Parameters: + * buf - data buffer pointer + * addr - target address value + * len - data length + * is_read - is read or write + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static void config_psram_read_write_data(uint8_t *buf, uint32_t addr, + uint32_t len, bool is_read) +{ + while (len > 0) + { + uint32_t length = MIN(len, 32); + if (is_read) + { + psram_read_data(buf, addr, length); + } + else + { + psram_write_data(buf, addr, length); + } + + addr += length; + buf += length; + len -= length; + } +} + +/**************************************************************************** + * Name: get_psram_tuning_configs + * + * Description: + * Get PSRAM tuning configuration. + * + * Input Parameters: + * config - tuning timing configuration pointer + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static void get_psram_tuning_configs(tuning_config_s *config) +{ +#if MSPI_TIMING_PSRAM_DTR_MODE +# define PSRAM_MODE DTR_MODE +#else +# define PSRAM_MODE STR_MODE +#endif + +#if CONFIG_ESP32S3_SPIRAM_SPEED_40M + *config = MSPI_TIMING_PSRAM_GET_TUNING_CONFIG( + ESP32S3_SPI_TIMING_CORE_CLK, 40, PSRAM_MODE); +#elif CONFIG_ESP32S3_SPIRAM_SPEED_80M + *config = MSPI_TIMING_PSRAM_GET_TUNING_CONFIG( + ESP32S3_SPI_TIMING_CORE_CLK, 80, PSRAM_MODE); +#elif CONFIG_ESP32S3_SPIRAM_SPEED_120M + *config = MSPI_TIMING_PSRAM_GET_TUNING_CONFIG( + ESP32S3_SPI_TIMING_CORE_CLK, 120, PSRAM_MODE); +#endif + +#undef PSRAM_MODE +} + +/**************************************************************************** + * Name: config_psram_set_tuning_regs + * + * Description: + * Tune PSRAM timing registers for SPI1 accessing PSRAM + * + * Input Parameters: + * params - tuning timing parameters pointer + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static void config_psram_set_tuning_regs(const tuning_param_s *params) +{ + /* 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 + */ + + set_psram_din_mode_num(0, params->spi_din_mode, params->spi_din_num); +#if CONFIG_ESP32S3_SPIRAM_MODE_OCT + + /* On 728, for SPI1, flash and psram share the extra dummy register */ + + set_flash_extra_dummy(1, params->extra_dummy_len); +#elif CONFIG_ESP32S3_SPIRAM_MODE_QUAD + + /* Update this `g_psram_extra_dummy`, the `psram_read_data` will + * set dummy according to this `g_psram_extra_dummy` + */ + + g_psram_extra_dummy = params->extra_dummy_len; + + /* Set MSPI Quad Flash dummy */ + + SET_PERI_REG_MASK(SPI_MEM_USER_REG(1), SPI_MEM_USR_DUMMY); + SET_PERI_REG_BITS(SPI_MEM_USER1_REG(1), SPI_MEM_USR_DUMMY_CYCLELEN_V, + g_psram_extra_dummy - 1, SPI_MEM_USR_DUMMY_CYCLELEN_S); +#endif +} +#endif + +/**************************************************************************** + * Name: sweep_for_success_sample_points + * + * Description: + * Use different SPI1 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. + * + * Input Parameters: + * reference_data - reference data pointer + * config - tuning timing configuration pointer + * is_flash - is flash or not + * out_array - last success point pointer + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static void sweep_for_success_sample_points(const uint8_t *reference_data, + const tuning_config_s *config, bool is_flash, uint8_t *out_array) +{ + uint32_t config_idx = 0; + uint8_t read_data[MSPI_TIMING_TEST_DATA_LEN]; + + for (config_idx = 0; config_idx < config->config_num; config_idx++) + { + memset(read_data, 0, MSPI_TIMING_TEST_DATA_LEN); +#if ESP32S3_SPI_TIMING_FLASH_TUNING + if (is_flash) + { + config_flash_set_tuning_regs(&(config->config_table[config_idx])); + config_flash_read_data(read_data, MSPI_TIMING_FLASH_TEST_DATA_ADDR, + sizeof(read_data)); + } +#endif + +#if ESP32S3_SPI_TIMING_PSRAM_TUNING + if (!is_flash) + { + config_psram_set_tuning_regs(&(config->config_table[config_idx])); + config_psram_read_write_data(read_data, + MSPI_TIMING_PSRAM_TEST_DATA_ADDR, + MSPI_TIMING_TEST_DATA_LEN, true); + } + +#endif + if (memcmp(reference_data, read_data, sizeof(read_data)) == 0) + { + out_array[config_idx] = 1; + minfo("%d, good\n", config_idx); + } + else + { + minfo("%d, bad\n", config_idx); + } + } +} + +/**************************************************************************** + * Name: find_max_consecutive_success_points + * + * Description: + * Find max consecutive success points. + * + * Input Parameters: + * array - sampling results pointer + * size - sampling results length + * out_length - consecutive length pointer + * out_end_index - last success point pointer + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static void find_max_consecutive_success_points(uint8_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]) + { + match_num++; + } + else + { + if (match_num > max) + { + max = match_num; + end = i - 1; + } + + match_num = 0; + } + + i++; + } + + *out_length = match_num > max ? match_num : max; + *out_end_index = match_num == size ? size : end; +} + +/**************************************************************************** + * Name: select_best_tuning_config_str + * + * Description: + * Select the STR best point + * + * Input Parameters: + * config - tuning timing configuration pointer + * consecutive_length - consecutive length + * end - last success point + * + * Returned Value: + * Returns the STR best point. + * + ****************************************************************************/ + +#if MSPI_TIMING_FLASH_STR_MODE || MSPI_TIMING_PSRAM_STR_MODE +static uint32_t select_best_tuning_config_str(tuning_config_s *config, + uint32_t consecutive_length, uint32_t end) +{ +#if (ESP32S3_SPI_TIMING_CORE_CLK == 120 || ESP32S3_SPI_TIMING_CORE_CLK == 240) + minfo("DO NOT USE FOR MASS PRODUCTION! Timing parameters may be updated"); + + /* 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 = config->default_config_id; + minfo("tuning fail, best point is fallen back to index %d\n", + best_point); + } + else + { + /* consecutive length : 3 or 4 */ + + best_point = end - consecutive_length / 2; + minfo("tuning success, best point is index %d\n", best_point); + } + + return best_point; +#else + /* won't reach here */ + + abort(); +#endif +} +#endif + +/**************************************************************************** + * Name: select_best_tuning_config_dtr + * + * Description: + * Select the DTR best point + * + * Input Parameters: + * config - tuning timing configuration pointer + * consecutive_length - consecutive length + * end - last success point + * + * Returned Value: + * Returns the DTR best point. + * + ****************************************************************************/ + +#if MSPI_TIMING_FLASH_DTR_MODE || MSPI_TIMING_PSRAM_DTR_MODE +static uint32_t select_best_tuning_config_dtr(tuning_config_s *config, + uint32_t consecutive_length, uint32_t end) +{ +#if (ESP32S3_SPI_TIMING_CORE_CLK == 160) + + /* Core clock 160M DTR best point scheme */ + + uint32_t best_point; + + /* These numbers will probably be same on other chips, + * if this version of algorithm is utilised + */ + + if (consecutive_length <= 2 || consecutive_length >= 6) + { + /* tuning is FAIL, select default point, and generate a warning */ + + best_point = config->default_config_id; + minfo("tuning fail, best point is fallen back to index %d\n", + best_point); + } + else if (consecutive_length <= 4) + { + /* consecutive length : 3 or 4 */ + + best_point = end - 1; + minfo("tuning success, best point is index %d\n", best_point); + } + else + { + /* consecutive point list length equals 5 */ + + best_point = end - 2; + minfo("tuning success, best point is index %d\n", best_point); + } + + return best_point; +#else + /* won't reach here */ + + abort(); +#endif +} +#endif + +/**************************************************************************** + * Name: select_best_tuning_config + * + * Description: + * Select the best timing tuning configuration + * + * Input Parameters: + * config - tuning timing configuration pointer + * consecutive_length - consecutive length + * end - last success point + * reference_data - reference data pointer + * is_flash - is flash or not + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static void select_best_tuning_config(tuning_config_s *config, + uint32_t consecutive_length, uint32_t end, + const uint8_t *reference_data, bool is_flash) +{ + uint32_t best_point = 0; + if (is_flash) + { +#if MSPI_TIMING_FLASH_DTR_MODE + best_point = select_best_tuning_config_dtr(config, consecutive_length, + end); +#elif MSPI_TIMING_FLASH_STR_MODE + best_point = select_best_tuning_config_str(config, consecutive_length, + end); +#endif + g_flash_timing_tuning_config = config->config_table[best_point]; + minfo("Flash timing tuning index: %d\n", best_point); + } + else + { +#if MSPI_TIMING_PSRAM_DTR_MODE + best_point = select_best_tuning_config_dtr(config, consecutive_length, + end); +#elif MSPI_TIMING_PSRAM_STR_MODE + best_point = select_best_tuning_config_str(config, consecutive_length, + end); +#endif + g_psram_timing_tuning_config = config->config_table[best_point]; + minfo("PSRAM timing tuning index: %d\n", best_point); + } +} + +/**************************************************************************** + * Name: set_timing_tuning_regs + * + * Description: + * Set timing tuning registers + * + * Input Parameters: + * spi1 - Select whether to control SPI1 + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static void set_timing_tuning_regs(bool control_spi1) +{ + /* SPI0 and SPI1 share the registers for flash din mode and num setting, + * so we only set SPI0's reg + */ + + set_flash_din_mode_num(0, g_flash_timing_tuning_config.spi_din_mode, + g_flash_timing_tuning_config.spi_din_num); + set_flash_extra_dummy(0, g_flash_timing_tuning_config.extra_dummy_len); + if (control_spi1) + { + set_flash_extra_dummy(1, g_flash_timing_tuning_config.extra_dummy_len); + } + + set_psram_din_mode_num(0, g_psram_timing_tuning_config.spi_din_mode, + g_psram_timing_tuning_config.spi_din_num); + set_psram_extra_dummy(0, g_psram_timing_tuning_config.extra_dummy_len); +} + +/**************************************************************************** + * Name: clear_timing_tuning_regs + * + * Description: + * Clear timing tuning registers + * + * Input Parameters: + * spi1 - Select whether to control SPI1 + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static void clear_timing_tuning_regs(bool control_spi1) +{ + /* SPI0 and SPI1 share the registers for flash din mode and num setting, + * so we only set SPI0's reg + */ + + set_flash_din_mode_num(0, 0, 0); + set_flash_extra_dummy(0, 0); + if (control_spi1) + { + set_flash_extra_dummy(1, 0); + } + + set_psram_din_mode_num(0, 0, 0); + set_psram_extra_dummy(0, 0); +} + +/**************************************************************************** + * Name: do_tuning + * + * Description: + * Start to tune the timing: + * + * Input Parameters: + * reference_data - reference data pointer + * timing_config - tuning timing configuration pointer + * is_flash - is flash or not + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static void do_tuning(const uint8_t *reference_data, + tuning_config_s *timing_config, bool is_flash) +{ + /* We use SPI1 to tune the timing: + * 1. Get all SPI1 sampling results. + * 2. Find the longest consecutive successful sampling points. + * 3. The middle one will be the best sampling point. + */ + + uint32_t consecutive_length = 0; + uint32_t last_success_point = 0; + uint8_t sample_result[MSPI_TIMING_CONFIG_NUM_DEFAULT] = + { + 0 + }; + + init_spi1_for_tuning(is_flash); + sweep_for_success_sample_points(reference_data, timing_config, is_flash, + sample_result); + find_max_consecutive_success_points(sample_result, + MSPI_TIMING_CONFIG_NUM_DEFAULT, &consecutive_length, &last_success_point); + select_best_tuning_config(timing_config, consecutive_length, + last_success_point, reference_data, is_flash); +} + +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -318,6 +1418,10 @@ void IRAM_ATTR esp32s3_spi_timing_set_mspi_high_speed(bool spi1) } set_psram_clock(0, psram_div); + +#if ESP32S3_SPI_TIMING_FLASH_TUNING || ESP32S3_SPI_TIMING_PSRAM_TUNING + set_timing_tuning_regs(true); +#endif } /**************************************************************************** @@ -363,4 +1467,106 @@ void IRAM_ATTR esp32s3_spi_timing_set_mspi_low_speed(bool spi1) set_flash_clock(1, 4); } + + set_psram_clock(0, 4); + +#if ESP32S3_SPI_TIMING_FLASH_TUNING || ESP32S3_SPI_TIMING_PSRAM_TUNING + clear_timing_tuning_regs(spi1); +#endif +} + +/**************************************************************************** + * Name: esp32s3_spi_timing_set_mspi_psram_tuning + * + * Description: + * Tune MSPI psram timing to make it work under high frequency + * + * Input Parameters: + * None + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void IRAM_ATTR esp32s3_spi_timing_set_mspi_psram_tuning(void) +{ +#if ESP32S3_SPI_TIMING_PSRAM_TUNING + tuning_config_s timing_configs = + { + 0 + }; + + /* set SPI01 related regs to 20mhz configuration, to write reference data + * to PSRAM. + */ + + esp32s3_spi_timing_set_mspi_low_speed(true); + + /* write data into psram, used to do timing tuning test. */ + + uint8_t reference_data[MSPI_TIMING_TEST_DATA_LEN]; + for (int i = 0; i < MSPI_TIMING_TEST_DATA_LEN / 4; i++) + { + ((uint32_t *)reference_data)[i] = 0xa5ff005a; + } + + config_psram_read_write_data(reference_data, + MSPI_TIMING_PSRAM_TEST_DATA_ADDR, MSPI_TIMING_TEST_DATA_LEN, false); + + get_psram_tuning_configs(&timing_configs); + + /* Disable the variable dummy mode when doing timing tuning */ + + REG_SET_FIELD(SPI_MEM_DDR_REG(1), SPI_MEM_SPI_FMEM_VAR_DUMMY, false); + + /* Get required config, and set them to PSRAM related registers */ + + do_tuning(reference_data, &timing_configs, false); + esp32s3_spi_timing_set_mspi_high_speed(true); +#endif +} + +/**************************************************************************** + * Name: esp32s3_spi_timing_set_mspi_flash_tuning + * + * Description: + * Tune MSPI flash timing to make it work under high frequency + * + * Input Parameters: + * None + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void IRAM_ATTR esp32s3_spi_timing_set_mspi_flash_tuning(void) +{ +#if ESP32S3_SPI_TIMING_FLASH_TUNING + tuning_config_s timing_configs = + { + 0 + }; + + /* set SPI01 related regs to 20mhz configuration, to get reference data + * from FLASH. + */ + + esp32s3_spi_timing_set_mspi_low_speed(true); + + /* Disable the variable dummy mode when doing timing tuning. */ + + REG_SET_FIELD(SPI_MEM_DDR_REG(1), SPI_MEM_SPI_FMEM_VAR_DUMMY, false); + uint8_t reference_data[MSPI_TIMING_TEST_DATA_LEN] = + { + 0 + }; + + config_flash_read_data(reference_data, MSPI_TIMING_FLASH_TEST_DATA_ADDR, + sizeof(reference_data)); + get_flash_tuning_configs(&timing_configs); + do_tuning(reference_data, &timing_configs, true); + esp32s3_spi_timing_set_mspi_high_speed(true); +#endif } diff --git a/arch/xtensa/src/esp32s3/esp32s3_spi_timing.h b/arch/xtensa/src/esp32s3/esp32s3_spi_timing.h index 1e5f67e118..6ca78b7fcf 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_spi_timing.h +++ b/arch/xtensa/src/esp32s3/esp32s3_spi_timing.h @@ -72,10 +72,6 @@ extern "C" # define ESP32S3_SPI_TIMING_FLASH_TUNING 0 #endif -#if ESP32S3_SPI_TIMING_FLASH_TUNING -# error "SPI flash tuning is not supported" -#endif - #if defined(CONFIG_ESP32S3_SPIRAM) # if defined(CONFIG_ESP32S3_SPIRAM_SPEED_40M) # define ESP32S3_SPI_TIMING_PSRAM_CLOCK 40 @@ -104,8 +100,115 @@ extern "C" # define ESP32S3_SPI_TIMING_PSRAM_TUNING 0 #endif -#if ESP32S3_SPI_TIMING_PSRAM_TUNING -# error "SPI PSRAM tuning is not supported" +#if ESP32S3_SPI_TIMING_FLASH_TUNING || ESP32S3_SPI_TIMING_PSRAM_TUNING + +/* This should be larger than the max available timing config num */ + +#define MSPI_TIMING_CONFIG_NUM_DEFAULT 20 + +#define __GET_TUNING_CONFIG(type, core_clock, module_clock, mode) \ + (tuning_config_s) { .config_table = MSPI_TIMING_##type##_CONFIG_TABLE_CORE_CLK_##core_clock##M_MODULE_CLK_##module_clock##M_##mode, \ + .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 + +#endif + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +#if ESP32S3_SPI_TIMING_FLASH_TUNING || ESP32S3_SPI_TIMING_PSRAM_TUNING + +/* SPI 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 */ +} tuning_param_s; + +typedef struct +{ + tuning_param_s config_table[MSPI_TIMING_CONFIG_NUM_DEFAULT]; + uint32_t config_num; + uint32_t default_config_id; /* If tuning fails, we use this one as default */ +} tuning_config_s; + #endif /**************************************************************************** @@ -161,6 +264,38 @@ void esp32s3_spi_timing_set_mspi_high_speed(bool control_spi1); void esp32s3_spi_timing_set_pin_drive_strength(void); +/**************************************************************************** + * Name: esp32s3_spi_timing_set_mspi_psram_tuning + * + * Description: + * Tune MSPI psram timing to make it work under high frequency + * + * Input Parameters: + * None + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void esp32s3_spi_timing_set_mspi_psram_tuning(void); + +/**************************************************************************** + * Name: esp32s3_spi_timing_set_mspi_flash_tuning + * + * Description: + * Tune MSPI flash timing to make it work under high frequency + * + * Input Parameters: + * None + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void esp32s3_spi_timing_set_mspi_flash_tuning(void); + #ifdef __cplusplus } #endif diff --git a/arch/xtensa/src/esp32s3/esp32s3_spiflash_mtd.c b/arch/xtensa/src/esp32s3/esp32s3_spiflash_mtd.c index 8346ad50f3..fad0d5a959 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_spiflash_mtd.c +++ b/arch/xtensa/src/esp32s3/esp32s3_spiflash_mtd.c @@ -123,7 +123,8 @@ static const struct esp32s3_mtd_dev_s g_esp32s3_spiflash = #endif .name = "esp32s3_spiflash" }, - .data = &rom_spiflash_legacy_data, + .data = (const struct spiflash_legacy_data_s **) + (&rom_spiflash_legacy_data), }; static const struct esp32s3_mtd_dev_s g_esp32s3_spiflash_encrypt = @@ -140,7 +141,8 @@ static const struct esp32s3_mtd_dev_s g_esp32s3_spiflash_encrypt = #endif .name = "esp32s3_spiflash_encrypt" }, - .data = &rom_spiflash_legacy_data, + .data = (const struct spiflash_legacy_data_s **) + (&rom_spiflash_legacy_data), }; /* Ensure exclusive access to the driver */ diff --git a/arch/xtensa/src/esp32s3/esp32s3_start.c b/arch/xtensa/src/esp32s3/esp32s3_start.c index 0db7633620..a42fcc2869 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_start.c +++ b/arch/xtensa/src/esp32s3/esp32s3_start.c @@ -356,6 +356,7 @@ void noreturn_function IRAM_ATTR __esp32s3_start(void) esp32s3_spi_timing_set_pin_drive_strength(); #endif + esp32s3_spi_timing_set_mspi_flash_tuning(); #if defined(CONFIG_ESP32S3_SPIRAM_BOOT_INIT) if (esp_spiram_init() != OK) { diff --git a/arch/xtensa/src/esp32s3/rom/esp32s3_spiflash.h b/arch/xtensa/src/esp32s3/rom/esp32s3_spiflash.h index 1ebfcb5c7d..6341cfec21 100644 --- a/arch/xtensa/src/esp32s3/rom/esp32s3_spiflash.h +++ b/arch/xtensa/src/esp32s3/rom/esp32s3_spiflash.h @@ -1008,7 +1008,7 @@ void spi_flash_enable_cache(uint32_t cpuid); * Public Data *****************************************************************************/ -extern const struct spiflash_legacy_data_s *rom_spiflash_legacy_data; +extern struct spiflash_legacy_data_s *rom_spiflash_legacy_data; #ifdef __cplusplus }