diff --git a/components/bootloader_support/src/bootloader_flash_config_esp32s3.c b/components/bootloader_support/src/bootloader_flash_config_esp32s3.c index 03c5214553..6266a74e8c 100644 --- a/components/bootloader_support/src/bootloader_flash_config_esp32s3.c +++ b/components/bootloader_support/src/bootloader_flash_config_esp32s3.c @@ -21,6 +21,9 @@ #define FLASH_IO_MATRIX_DUMMY_40M 0 #define FLASH_IO_MATRIX_DUMMY_80M 0 #define FLASH_IO_DRIVE_GD_WITH_1V8PSRAM 3 +#define FLASH_CS_SETUP_TIME 3 +#define FLASH_CS_HOLD_TIME 3 +#define FLASH_CS_HOLD_DELAY 2 void bootloader_flash_update_id() { @@ -30,12 +33,18 @@ void bootloader_flash_update_id() void IRAM_ATTR bootloader_flash_cs_timing_config() { + // SPI0/1 share the cs_hold / cs_setup, cd_hold_time / cd_setup_time, cs_hold_delay registers for FLASH/PSRAM, so we only need to set SPI0 related registers here SET_PERI_REG_MASK(SPI_MEM_USER_REG(0), SPI_MEM_CS_HOLD_M | SPI_MEM_CS_SETUP_M); - SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_HOLD_TIME_V, 0, SPI_MEM_CS_HOLD_TIME_S); - SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_SETUP_TIME_V, 0, SPI_MEM_CS_SETUP_TIME_S); - SET_PERI_REG_MASK(SPI_MEM_USER_REG(1), SPI_MEM_CS_HOLD_M | SPI_MEM_CS_SETUP_M); - SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(1), SPI_MEM_CS_HOLD_TIME_V, 1, SPI_MEM_CS_HOLD_TIME_S); - SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(1), SPI_MEM_CS_SETUP_TIME_V, 0, SPI_MEM_CS_SETUP_TIME_S); + SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_HOLD_TIME_V, FLASH_CS_HOLD_TIME, SPI_MEM_CS_HOLD_TIME_S); + SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_SETUP_TIME_V, FLASH_CS_SETUP_TIME, SPI_MEM_CS_SETUP_TIME_S); + + SET_PERI_REG_MASK(SPI_MEM_SPI_SMEM_AC_REG(0), SPI_MEM_SPI_SMEM_CS_HOLD_M | SPI_MEM_SPI_SMEM_CS_SETUP_M); + SET_PERI_REG_BITS(SPI_MEM_SPI_SMEM_AC_REG(0), SPI_MEM_SPI_SMEM_CS_HOLD_TIME_V, FLASH_CS_HOLD_TIME, SPI_MEM_SPI_SMEM_CS_HOLD_TIME_S); + SET_PERI_REG_BITS(SPI_MEM_SPI_SMEM_AC_REG(0), SPI_MEM_SPI_SMEM_CS_SETUP_TIME_V, FLASH_CS_SETUP_TIME, SPI_MEM_SPI_SMEM_CS_SETUP_TIME_S); + + // cs high time + SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_HOLD_DELAY_V, FLASH_CS_HOLD_DELAY, SPI_MEM_CS_HOLD_DELAY_S); + SET_PERI_REG_BITS(SPI_MEM_SPI_SMEM_AC_REG(0), SPI_MEM_SPI_SMEM_CS_HOLD_DELAY_V, FLASH_CS_HOLD_DELAY, SPI_MEM_SPI_SMEM_CS_HOLD_DELAY_S); } void IRAM_ATTR bootloader_flash_clock_config(const esp_image_header_t *pfhdr) diff --git a/components/esp32s3/CMakeLists.txt b/components/esp32s3/CMakeLists.txt index 882bcd6e5f..bf3205df54 100644 --- a/components/esp32s3/CMakeLists.txt +++ b/components/esp32s3/CMakeLists.txt @@ -16,7 +16,7 @@ else() "esp_crypto_lock.c" "memprot.c" "spiram.c" - "spiram_psram.c") + "spi_timing_config.c") set(include_dirs "include") set(requires driver efuse soc xtensa) #unfortunately rom/uart uses SOC registers directly @@ -27,6 +27,12 @@ else() set(priv_requires app_trace app_update bootloader_support log mbedtls nvs_flash pthread spi_flash vfs espcoredump esp_common perfmon esp_timer esp_ipc) + if(CONFIG_SPIRAM_MODE_QUAD) + list(APPEND srcs "spiram_psram.c") + elseif(CONFIG_SPIRAM_MODE_OCT) + list(APPEND srcs "opiram_psram.c") + endif() + idf_component_register(SRCS "${srcs}" INCLUDE_DIRS "${include_dirs}" REQUIRES "${requires}" diff --git a/components/esp32s3/Kconfig b/components/esp32s3/Kconfig index 6ba79b9a73..c4fd9a8c67 100644 --- a/components/esp32s3/Kconfig +++ b/components/esp32s3/Kconfig @@ -169,8 +169,19 @@ menu "ESP32S3-Specific" menu "SPI RAM config" depends on ESP32S3_SPIRAM_SUPPORT + choice SPIRAM_MODE + prompt "Mode (QUAD/OCT) of SPI RAM chip in use" + default SPIRAM_MODE_QUAD + + config SPIRAM_MODE_QUAD + bool "Quad Mode PSRAM" + + config SPIRAM_MODE_OCT + bool "Octal Mode PSRAM" + endchoice + choice SPIRAM_TYPE - prompt "Type of SPI RAM chip in use" + prompt "Type of SPIRAM chip in use" default SPIRAM_TYPE_AUTO config SPIRAM_TYPE_AUTO @@ -178,12 +189,14 @@ menu "ESP32S3-Specific" config SPIRAM_TYPE_ESPPSRAM16 bool "ESP-PSRAM16 or APS1604" + depends on SPIRAM_MODE_QUAD config SPIRAM_TYPE_ESPPSRAM32 bool "ESP-PSRAM32 or IS25WP032" + depends on SPIRAM_MODE_QUAD config SPIRAM_TYPE_ESPPSRAM64 - bool "ESP-PSRAM64 or LY68L6400" + bool "ESP-PSRAM64 , LY68L6400 or APS6408" endchoice config SPIRAM_SIZE @@ -192,6 +205,8 @@ menu "ESP32S3-Specific" default 2097152 if SPIRAM_TYPE_ESPPSRAM16 default 4194304 if SPIRAM_TYPE_ESPPSRAM32 default 8388608 if SPIRAM_TYPE_ESPPSRAM64 + default 16777216 if SPIRAM_TYPE_ESPPSRAM128 + default 33554432 if SPIRAM_TYPE_ESPPSRAM256 default 0 menu "PSRAM Clock and CS IO for ESP32S3" @@ -235,10 +250,6 @@ menu "ESP32S3-Specific" bool "80MHz clock speed" config SPIRAM_SPEED_40M bool "40Mhz clock speed" - config SPIRAM_SPEED_26M - bool "26Mhz clock speed" - config SPIRAM_SPEED_20M - bool "20Mhz clock speed" endchoice # insert non-chip-specific items here diff --git a/components/esp32s3/include/esp32s3/mspi_timing_tuning_configs.h b/components/esp32s3/include/esp32s3/mspi_timing_tuning_configs.h new file mode 100644 index 0000000000..d438d58d48 --- /dev/null +++ b/components/esp32s3/include/esp32s3/mspi_timing_tuning_configs.h @@ -0,0 +1,41 @@ +/* + * SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +//Octal 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 + +//Octal 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 + +//Octal 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 + +//Octal 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 + +//Octal 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 + +//Octal 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 + +//Octal PSRAM: core clock 160M, module clock 80M, DTR mode +#define MSPI_TIMING_PSRAM_CONFIG_TABLE_CORE_CLK_160M_MODULE_CLK_80M_DTR_MODE {{1, 0, 0}, {0, 0, 0}, {3, 0, 1}, {1, 0, 1}, {0, 0, 1}, {3, 0, 2}, {1, 0, 2}, {0, 0, 2}, {3, 0, 3}, {1, 0, 3}, {0, 0, 3}, {3, 0, 4}, {1, 0, 4}, {0, 0, 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 1 diff --git a/components/esp32s3/include/esp32s3/spi_timing_config.h b/components/esp32s3/include/esp32s3/spi_timing_config.h new file mode 100644 index 0000000000..de9462d779 --- /dev/null +++ b/components/esp32s3/include/esp32s3/spi_timing_config.h @@ -0,0 +1,172 @@ +/* + * SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "esp_flash_partitions.h" +#include "esp32s3/rom/spi_flash.h" +#include "esp32s3/rom/opi_flash.h" +#include "esp32s3/mspi_timing_tuning_configs.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +#define SPI_TIMING_CONFIG_NUM_DEFAULT 20 //This should be larger than the max available timing config num +#define SPI_TIMING_TEST_DATA_LEN 64 + +#define SPI_TIMING_PSRAM_TEST_DATA_ADDR 0 +#define SPI_TIMING_FLASH_TEST_DATA_ADDR ESP_BOOTLOADER_OFFSET + +//-------------------------------------------FLASH Operation Mode and Corresponding Timing Tuning Parameter Table --------------------------------------// +#define SPI_TIMING_FLASH_DTR_MODE (CONFIG_ESPTOOLPY_FLASHMODE_OPI_DTR || CONFIG_ESPTOOLPY_FLASHMODE_OIO_DTR) +#define SPI_TIMING_FLASH_STR_MODE (CONFIG_ESPTOOLPY_FLASHMODE_OPI_STR || CONFIG_ESPTOOLPY_FLASHMODE_OIO_STR || CONFIG_ESPTOOLPY_FLASHMODE_OOUT_STR) + +/* Determine A feasible core clock below: SPI_TIMING_FLASH_EXPECTED_CORE_CLK_MHZ and SPI_TIMING_PSRAM_EXPECTED_CORE_CLK_MHZ*/ +//OCTAL FLASH +#if CONFIG_ESPTOOLPY_OCT_FLASH + +// OCT FLASH 40M DTR +#if SPI_TIMING_FLASH_DTR_MODE && CONFIG_ESPTOOLPY_FLASHFREQ_40M +_Static_assert(!CONFIG_ESPTOOLPY_FLASHFREQ_40M, "Octal FLASH 40MHz DDR is not supported. TODO: IDF-1630"); +#define SPI_TIMING_FLASH_EXPECTED_CORE_CLK_MHZ 160 +#endif + +//OCT FLASH 80M DTR +#if SPI_TIMING_FLASH_DTR_MODE && CONFIG_ESPTOOLPY_FLASHFREQ_80M +#define SPI_TIMING_FLASH_EXPECTED_CORE_CLK_MHZ 160 +#endif + +//OCT FLASH 120M DTR +#if SPI_TIMING_FLASH_DTR_MODE && CONFIG_ESPTOOLPY_FLASHFREQ_120M +#define SPI_TIMING_FLASH_EXPECTED_CORE_CLK_MHZ 240 +#endif + +//OCT FLASH 80M STR +#if SPI_TIMING_FLASH_STR_MODE && CONFIG_ESPTOOLPY_FLASHFREQ_80M +#define SPI_TIMING_FLASH_EXPECTED_CORE_CLK_MHZ 160 +#endif + +//OCT FLASH 120M STR +#if SPI_TIMING_FLASH_STR_MODE && CONFIG_ESPTOOLPY_FLASHFREQ_120M +#define SPI_TIMING_FLASH_EXPECTED_CORE_CLK_MHZ 120 +#endif + +#endif //#if CONFIG_ESPTOOLPY_OCT_FLASH +/* QUAD FLASH Operation Mode should be added here if needed */ + + +//---------------------------------------PSRAM Operation Mode and Corresponding Timing Tuning Parameter Table--------------------------------------// +#define SPI_TIMING_PSRAM_DTR_MODE 1 //Currently we only support DTR Octal PSRAM +#define SPI_TIMING_PSRAM_STR_MODE 0 + +//OCTAL PSRAM +#if CONFIG_SPIRAM_MODE_OCT + +//OCT 40M PSRAM +#if SPI_TIMING_PSRAM_DTR_MODE && CONFIG_SPIRAM_SPEED_40M +#define SPI_TIMING_PSRAM_EXPECTED_CORE_CLK_MHZ 80 +#endif + +//OCT 80M PSRAM +#if SPI_TIMING_PSRAM_DTR_MODE && CONFIG_SPIRAM_SPEED_80M +#define SPI_TIMING_PSRAM_EXPECTED_CORE_CLK_MHZ 160 +#endif + +#endif //#if CONFIG_SPIRAM_MODE_OCT +/* QUAD PSRAM Operation Mode should be added here if needed */ + + +//------------------------------------------Get the timing tuning config-----------------------------------------------// +#ifdef SPI_TIMING_FLASH_EXPECTED_CORE_CLK_MHZ +//FLASH needs tuning, and it expects this core clock: SPI_TIMING_FLASH_EXPECTED_CORE_CLK_MHZ +#define SPI_TIMING_FLASH_NEEDS_TUNING 1 +#endif + +#ifdef SPI_TIMING_PSRAM_EXPECTED_CORE_CLK_MHZ +//PSRAM needs tuning, and it expects this core clock: SPI_TIMING_PSRAM_EXPECTED_CORE_CLK_MHZ +#define SPI_TIMING_PSRAM_NEEDS_TUNING 1 +#endif + +//If both FLASH and PSRAM need tuning, the core clock should be same +#if SPI_TIMING_FLASH_NEEDS_TUNING && SPI_TIMING_PSRAM_NEEDS_TUNING +_Static_assert(SPI_TIMING_FLASH_EXPECTED_CORE_CLK_MHZ == SPI_TIMING_PSRAM_EXPECTED_CORE_CLK_MHZ, "FLASH and PSRAM Mode configuration are not supported"); +#define SPI_TIMING_CORE_CLOCK_MHZ SPI_TIMING_FLASH_EXPECTED_CORE_CLK_MHZ + +//If only FLASH needs tuning, the core clock could be as FLASH expected +#elif SPI_TIMING_FLASH_NEEDS_TUNING && !SPI_TIMING_PSRAM_NEEDS_TUNING +#define SPI_TIMING_CORE_CLOCK_MHZ SPI_TIMING_FLASH_EXPECTED_CORE_CLK_MHZ + +//If only PSRAM needs tuning, the core clock could be as PSRAM expected +#elif !SPI_TIMING_FLASH_NEEDS_TUNING && SPI_TIMING_PSRAM_NEEDS_TUNING +#define SPI_TIMING_CORE_CLOCK_MHZ SPI_TIMING_PSRAM_EXPECTED_CORE_CLK_MHZ + +#else +#define SPI_TIMING_CORE_CLOCK_MHZ 80 +#endif + +//------------------------------------------Helper Macros to get FLASH/PSRAM tuning configs-----------------------------------------------// +#define __GET_TUNING_CONFIG(type, core_clock, module_clock, mode) \ + (spi_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 SPI_TIMING_FLASH_GET_TUNING_CONFIG(core_clock_mhz, module_clock_mhz, mode) _GET_TUNING_CONFIG(FLASH, core_clock_mhz, module_clock_mhz, mode) +#define SPI_TIMING_PSRAM_GET_TUNING_CONFIG(core_clock_mhz, module_clock_mhz, mode) _GET_TUNING_CONFIG(PSRAM, core_clock_mhz, module_clock_mhz, mode) + + +/** + * SPI timing tuning registers. The macro `SPI_TIMING_FLASH_CONFIG_TABLE` below is the corresponding register value table. + * 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*/ +} spi_timing_tuning_param_t; + +typedef struct { + spi_timing_tuning_param_t tuning_config_table[SPI_TIMING_CONFIG_NUM_DEFAULT]; //available timing tuning configs + uint32_t available_config_num; + uint32_t default_config_id; //If tuning fails, we use this one as default +} spi_timing_config_t; + +/** + * The SPI FLASH module clock and SPI PSRAM module clock is divided from the SPI core clock, core clock is from system clock: + * + * PLL ----| |---- FLASH Module Clock + * XTAL ----|----> Core Clock ---->| + * RTC8M ----| |---- PSRAM Module Clock + * + */ +typedef enum { + SPI_TIMING_CONFIG_CORE_CLOCK_80M, + SPI_TIMING_CONFIG_CORE_CLOCK_120M, + SPI_TIMING_CONFIG_CORE_CLOCK_160M, + SPI_TIMING_CONFIG_CORE_CLOCK_240M +} spi_timing_config_core_clock_t; + + +spi_timing_config_core_clock_t spi_timing_config_get_core_clock(void); +void spi_timing_config_set_core_clock(uint8_t spi_num, spi_timing_config_core_clock_t core_clock); + +void spi_timing_config_set_flash_clock(uint8_t spi_num, uint32_t freqdiv); +void spi_timing_config_flash_set_din_mode_num(uint8_t spi_num, uint8_t din_mode, uint8_t din_num); +void spi_timing_config_flash_set_extra_dummy(uint8_t spi_num, uint8_t extra_dummy); +void spi_timing_config_flash_read_data(uint8_t spi_num, uint8_t *buf, uint32_t addr, uint32_t len); + +void spi_timing_config_set_psram_clock(uint8_t spi_num, uint32_t freqdiv); +void spi_timing_config_psram_set_din_mode_num(uint8_t spi_num, uint8_t din_mode, uint8_t din_num); +void spi_timing_config_psram_set_extra_dummy(uint8_t spi_num, uint8_t extra_dummy); +void spi_timing_config_psram_write_data(uint8_t spi_num, uint8_t *buf, uint32_t addr, uint32_t len); +void spi_timing_config_psram_read_data(uint8_t spi_num,uint8_t *buf, uint32_t addr, uint32_t len); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp32s3/opiram_psram.c b/components/esp32s3/opiram_psram.c new file mode 100644 index 0000000000..efff2ec4d9 --- /dev/null +++ b/components/esp32s3/opiram_psram.c @@ -0,0 +1,291 @@ +/* + * SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "sdkconfig.h" +#include "string.h" +#include "esp_attr.h" +#include "esp_err.h" +#include "esp_types.h" +#include "esp_log.h" +#include "spiram_psram.h" +#include "esp32s3/rom/ets_sys.h" +#include "esp32s3/rom/spi_flash.h" +#include "esp32s3/rom/opi_flash.h" +#include "esp32s3/rom/gpio.h" +#include "esp32s3/rom/cache.h" +#include "soc/io_mux_reg.h" +#include "soc/dport_reg.h" +#include "soc/apb_ctrl_reg.h" +#include "soc/gpio_sig_map.h" +#include "soc/efuse_reg.h" +#include "driver/gpio.h" +#include "driver/spi_common.h" +#include "driver/periph_ctrl.h" + +#if CONFIG_SPIRAM_MODE_OCT +#include "soc/rtc.h" +#include "spi_flash_private.h" + +#define OPI_PSRAM_SYNC_READ 0x0000 +#define OPI_PSRAM_SYNC_WRITE 0x8080 +#define OPI_PSRAM_REG_READ 0x4040 +#define OPI_PSRAM_REG_WRITE 0xC0C0 +#define OCT_PSRAM_RD_CMD_BITLEN 16 +#define OCT_PSRAM_WR_CMD_BITLEN 16 +#define OCT_PSRAM_ADDR_BITLEN 32 +#define OCT_PSRAM_RD_DUMMY_BITLEN (2*(10-1)) +#define OCT_PSRAM_WR_DUMMY_BITLEN (2*(5-1)) +#define OCT_PSRAM_CS1_IO 26 + +typedef struct { + union { + struct { + uint8_t drive_str: 2; + uint8_t read_latency: 3; + uint8_t lt: 1; + uint8_t rsvd0_1: 2; + }; + uint8_t val; + } mr0; + union { + struct { + uint8_t vendor_id: 5; + uint8_t rsvd0_2: 3; + }; + uint8_t val; + } mr1; + union { + struct { + uint8_t density: 3; + uint8_t dev_id: 2; + uint8_t rsvd1_2: 2; + uint8_t gb: 1; + }; + uint8_t val; + } mr2; + union { + struct { + uint8_t rsvd3_7: 5; + uint8_t srf: 1; + uint8_t vcc: 1; + uint8_t rsvd0: 1; + }; + uint8_t val; + } mr3; + union { + struct { + uint8_t pasr: 3; + uint8_t rf: 1; + uint8_t rsvd3: 1; + uint8_t wr_latency: 3; + }; + uint8_t val; + } mr4; + union { + struct { + uint8_t bl: 2; + uint8_t bt: 1; + uint8_t rsvd0_4: 5; + }; + uint8_t val; + } mr8; +} opi_psram_mode_reg_t; + +static const char* TAG = "opi psram"; +static DRAM_ATTR psram_size_t s_psram_size; +static void IRAM_ATTR psram_cache_init(psram_cache_mode_t psram_cache_mode, psram_vaddr_mode_t vaddrmode); + +/** + * Initialise mode registers of the PSRAM + */ +static void IRAM_ATTR s_init_psram_mode_reg(int spi_num, opi_psram_mode_reg_t *mode_reg_config) +{ + esp_rom_spiflash_read_mode_t mode = ESP_ROM_SPIFLASH_OPI_DTR_MODE; + int cmd_len = 16; + uint32_t addr = 0x0; + int addr_bit_len = 32; + int dummy = OCT_PSRAM_RD_DUMMY_BITLEN; + opi_psram_mode_reg_t mode_reg = {0}; + int data_bit_len = 16; + + //read + esp_rom_opiflash_exec_cmd(spi_num, mode, + OPI_PSRAM_REG_READ, cmd_len, + addr, addr_bit_len, + dummy, + NULL, 0, + &mode_reg.mr0.val, data_bit_len, + BIT(1), + false); + //modify + mode_reg.mr0.lt = mode_reg_config->mr0.lt; + mode_reg.mr0.read_latency = mode_reg_config->mr0.read_latency; + mode_reg.mr0.drive_str = mode_reg_config->mr0.drive_str; + + //write + esp_rom_opiflash_exec_cmd(spi_num, mode, + OPI_PSRAM_REG_WRITE, cmd_len, + addr, addr_bit_len, + 0, + &mode_reg.mr0.val, 16, + NULL, 0, + BIT(1), + false); +} + +static void IRAM_ATTR s_get_psram_mode_reg(int spi_num, opi_psram_mode_reg_t *out_reg) +{ + esp_rom_spiflash_read_mode_t mode = ESP_ROM_SPIFLASH_OPI_DTR_MODE; + int cmd_len = 16; + int addr_bit_len = 32; + int dummy = OCT_PSRAM_RD_DUMMY_BITLEN; + int data_bit_len = 16; + + //Read MR0 register + esp_rom_opiflash_exec_cmd(spi_num, mode, + OPI_PSRAM_REG_READ, cmd_len, + 0x0, addr_bit_len, + dummy, + NULL, 0, + &out_reg->mr0.val, data_bit_len, + BIT(1), + false); + //Read MR2 register + esp_rom_opiflash_exec_cmd(spi_num, mode, + OPI_PSRAM_REG_READ, cmd_len, + 0x2, addr_bit_len, + dummy, + NULL, 0, + &out_reg->mr2.val, data_bit_len, + BIT(1), + false); + //Read MR4 register + esp_rom_opiflash_exec_cmd(spi_num, mode, + OPI_PSRAM_REG_READ, cmd_len, + 0x4, addr_bit_len, + dummy, + NULL, 0, + &out_reg->mr4.val, data_bit_len, + BIT(1), + false); + //Read MR8 register + esp_rom_opiflash_exec_cmd(spi_num, mode, + OPI_PSRAM_REG_READ, cmd_len, + 0x8, addr_bit_len, + dummy, + NULL, 0, + &out_reg->mr8.val, data_bit_len, + BIT(1), + false); +} + +static void IRAM_ATTR s_print_psram_info(opi_psram_mode_reg_t *reg_val) +{ + ESP_EARLY_LOGI(TAG, "vendor id : 0x%02x (%s)", reg_val->mr1.vendor_id, reg_val->mr1.vendor_id == 0x0d ? "AP" : "UNKNOWN"); + ESP_EARLY_LOGI(TAG, "dev id : 0x%02x (generation %d)", reg_val->mr2.dev_id, reg_val->mr2.dev_id + 1); + ESP_EARLY_LOGI(TAG, "density : 0x%02x (%d Mbit)", reg_val->mr2.density, reg_val->mr2.density == 0x1 ? 32 : + reg_val->mr2.density == 0X3 ? 64 : + reg_val->mr2.density == 0x5 ? 128 : + reg_val->mr2.density == 0x7 ? 256 : 0); + ESP_EARLY_LOGI(TAG, "good-die : 0x%02x (%s)", reg_val->mr2.gb, reg_val->mr2.gb == 1 ? "Pass" : "Fail"); + ESP_EARLY_LOGI(TAG, "Latency : 0x%02x (%s)", reg_val->mr0.lt, reg_val->mr0.lt == 1 ? "Fixed" : "Variable"); + ESP_EARLY_LOGI(TAG, "VCC : 0x%02x (%s)", reg_val->mr3.vcc, reg_val->mr3.vcc == 1 ? "3V" : "1.8V"); + ESP_EARLY_LOGI(TAG, "SRF : 0x%02x (%s Refresh)", reg_val->mr3.srf, reg_val->mr3.srf == 0x1 ? "Fast" : "Slow"); + ESP_EARLY_LOGI(TAG, "BurstType : 0x%02x (%s Wrap)", reg_val->mr8.bt, reg_val->mr8.bt == 1 && reg_val->mr8.bl != 3 ? "Hybrid" : ""); + ESP_EARLY_LOGI(TAG, "BurstLen : 0x%02x (%d Byte)", reg_val->mr8.bl, reg_val->mr8.bl == 0x00 ? 16 : + reg_val->mr8.bl == 0x01 ? 32 : + reg_val->mr8.bl == 0x10 ? 64 : 1024); + ESP_EARLY_LOGI(TAG, "Readlatency : 0x%02x (%d cycles@%s)", reg_val->mr0.read_latency, reg_val->mr0.read_latency * 2 + 6, + reg_val->mr0.lt == 1 ? "Fixed" : "Variable"); + ESP_EARLY_LOGI(TAG, "DriveStrength: 0x%02x (1/%d)", reg_val->mr0.drive_str, reg_val->mr0.drive_str == 0x00 ? 1 : + reg_val->mr0.drive_str == 0x01 ? 2 : + reg_val->mr0.drive_str == 0x02 ? 4 : 8); +} + +esp_err_t IRAM_ATTR psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vaddrmode) +{ + // enable CS signal + PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[OCT_PSRAM_CS1_IO], FUNC_SPICS1_SPICS1); + + //enter MSPI slow mode to init PSRAM device registers + spi_timing_enter_mspi_low_speed_mode(); + + //set to variable dummy mode + SET_PERI_REG_MASK(SPI_MEM_DDR_REG(1), SPI_MEM_SPI_FMEM_VAR_DUMMY); +#if CONFIG_ESPTOOLPY_FLASH_VENDOR_MXIC && CONFIG_ESPTOOLPY_FLASHMODE_OPI_DTR + esp_rom_spi_set_dtr_swap_mode(1, false, false); +#endif + + //Set PSRAM read latency and drive strength + static DRAM_ATTR opi_psram_mode_reg_t mode_reg = {0}; + mode_reg.mr0.lt = 1; + mode_reg.mr0.read_latency = 2; + mode_reg.mr0.drive_str = 0; + s_init_psram_mode_reg(1, &mode_reg); + //Print PSRAM info + s_get_psram_mode_reg(1, &mode_reg); + s_print_psram_info(&mode_reg); + s_psram_size = mode_reg.mr2.density == 0x1 ? PSRAM_SIZE_32MBITS : + mode_reg.mr2.density == 0X3 ? PSRAM_SIZE_64MBITS : + mode_reg.mr2.density == 0x5 ? PSRAM_SIZE_128MBITS : + mode_reg.mr2.density == 0x7 ? PSRAM_SIZE_256MBITS : 0; + +#if CONFIG_ESPTOOLPY_FLASH_VENDOR_MXIC && CONFIG_ESPTOOLPY_FLASHMODE_OPI_DTR + esp_rom_spi_set_dtr_swap_mode(1, true, true); +#endif + + spi_timing_psram_tuning(); + + spi_timing_enter_mspi_high_speed_mode(); + + /** + * Tuning may change SPI1 regs, whereas legacy spi_flash APIs rely on these regs. + * This function is to restore SPI1 init state. + */ + spi_flash_set_rom_required_regs(); + + psram_cache_init(mode, vaddrmode); + return ESP_OK; +} + +//register initialization for sram cache params and r/w commands +static void IRAM_ATTR psram_cache_init(psram_cache_mode_t psram_cache_mode, psram_vaddr_mode_t vaddrmode) +{ + //Config Write CMD phase for SPI0 to access PSRAM + SET_PERI_REG_MASK(SPI_MEM_CACHE_SCTRL_REG(0), SPI_MEM_CACHE_SRAM_USR_WCMD_M); + SET_PERI_REG_BITS(SPI_MEM_SRAM_DWR_CMD_REG(0), SPI_MEM_CACHE_SRAM_USR_WR_CMD_BITLEN, OCT_PSRAM_WR_CMD_BITLEN - 1, SPI_MEM_CACHE_SRAM_USR_WR_CMD_BITLEN_S); + SET_PERI_REG_BITS(SPI_MEM_SRAM_DWR_CMD_REG(0), SPI_MEM_CACHE_SRAM_USR_WR_CMD_VALUE, OPI_PSRAM_SYNC_WRITE, SPI_MEM_CACHE_SRAM_USR_WR_CMD_VALUE_S); + + //Config Read CMD phase for SPI0 to access PSRAM + SET_PERI_REG_MASK(SPI_MEM_CACHE_SCTRL_REG(0), SPI_MEM_CACHE_SRAM_USR_RCMD_M); + SET_PERI_REG_BITS(SPI_MEM_SRAM_DRD_CMD_REG(0), SPI_MEM_CACHE_SRAM_USR_RD_CMD_BITLEN_V, OCT_PSRAM_RD_CMD_BITLEN - 1, SPI_MEM_CACHE_SRAM_USR_RD_CMD_BITLEN_S); + SET_PERI_REG_BITS(SPI_MEM_SRAM_DRD_CMD_REG(0), SPI_MEM_CACHE_SRAM_USR_RD_CMD_VALUE_V, OPI_PSRAM_SYNC_READ, SPI_MEM_CACHE_SRAM_USR_RD_CMD_VALUE_S); + + //Config ADDR phase + SET_PERI_REG_BITS(SPI_MEM_CACHE_SCTRL_REG(0), SPI_MEM_SRAM_ADDR_BITLEN_V, OCT_PSRAM_ADDR_BITLEN - 1, SPI_MEM_SRAM_ADDR_BITLEN_S); + SET_PERI_REG_MASK(SPI_MEM_CACHE_SCTRL_REG(0), SPI_MEM_CACHE_USR_SCMD_4BYTE_M); + + //Config RD/WR Dummy phase + SET_PERI_REG_MASK(SPI_MEM_CACHE_SCTRL_REG(0), SPI_MEM_USR_RD_SRAM_DUMMY_M | SPI_MEM_USR_WR_SRAM_DUMMY_M); + SET_PERI_REG_BITS(SPI_MEM_CACHE_SCTRL_REG(0), SPI_MEM_SRAM_RDUMMY_CYCLELEN_V, OCT_PSRAM_RD_DUMMY_BITLEN - 1, SPI_MEM_SRAM_RDUMMY_CYCLELEN_S); + SET_PERI_REG_MASK(SPI_MEM_SPI_SMEM_DDR_REG(0), SPI_MEM_SPI_SMEM_VAR_DUMMY_M); + SET_PERI_REG_BITS(SPI_MEM_CACHE_SCTRL_REG(0), SPI_MEM_SRAM_WDUMMY_CYCLELEN_V, OCT_PSRAM_WR_DUMMY_BITLEN - 1, SPI_MEM_SRAM_WDUMMY_CYCLELEN_S); + + CLEAR_PERI_REG_MASK(SPI_MEM_SPI_SMEM_DDR_REG(0), SPI_MEM_SPI_SMEM_DDR_WDAT_SWP_M | SPI_MEM_SPI_SMEM_DDR_RDAT_SWP_M); + SET_PERI_REG_MASK(SPI_MEM_SPI_SMEM_DDR_REG(0), SPI_MEM_SPI_SMEM_DDR_EN_M); + + SET_PERI_REG_MASK(SPI_MEM_SRAM_CMD_REG(0), SPI_MEM_SDUMMY_OUT_M | SPI_MEM_SCMD_OCT_M | SPI_MEM_SADDR_OCT_M | SPI_MEM_SDOUT_OCT_M | SPI_MEM_SDIN_OCT_M); + SET_PERI_REG_MASK(SPI_MEM_CACHE_SCTRL_REG(0), SPI_MEM_SRAM_OCT_M); + + Cache_Resume_DCache(0); +} + +psram_size_t psram_get_size() +{ + return s_psram_size; +} + +#endif //#if CONFIG_SPIRAM_MODE_OCT diff --git a/components/esp32s3/spi_timing_config.c b/components/esp32s3/spi_timing_config.c new file mode 100644 index 0000000000..079493e856 --- /dev/null +++ b/components/esp32s3/spi_timing_config.c @@ -0,0 +1,197 @@ +/* + * SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "sdkconfig.h" +#include "string.h" +#include "esp_attr.h" +#include "esp_err.h" +#include "esp_types.h" +#include "esp_log.h" +#include "soc/spi_mem_reg.h" +#include "esp32s3/spi_timing_config.h" + +#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)) + + +/////////////////////////////////////////TIMING TUNING IS NEEDED////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#if SPI_TIMING_FLASH_NEEDS_TUNING || SPI_TIMING_PSRAM_NEEDS_TUNING //If one of the FLASH / PSRAM or both of them need timing tuning, we should build following code + +spi_timing_config_core_clock_t IRAM_ATTR spi_timing_config_get_core_clock(void) +{ + switch (SPI_TIMING_CORE_CLOCK_MHZ) { + case 80: + return SPI_TIMING_CONFIG_CORE_CLOCK_80M; + case 120: + return SPI_TIMING_CONFIG_CORE_CLOCK_120M; + case 160: + return SPI_TIMING_CONFIG_CORE_CLOCK_160M; + case 240: + return SPI_TIMING_CONFIG_CORE_CLOCK_240M; + default: + abort(); + } +} + +void IRAM_ATTR spi_timing_config_set_core_clock(uint8_t spi_num, spi_timing_config_core_clock_t core_clock) +{ + uint32_t reg_val = 0; + + switch (core_clock) { + case SPI_TIMING_CONFIG_CORE_CLOCK_80M: + reg_val = 0; + break; + case SPI_TIMING_CONFIG_CORE_CLOCK_120M: + reg_val = 1; + break; + case SPI_TIMING_CONFIG_CORE_CLOCK_160M: + reg_val = 2; + break; + case SPI_TIMING_CONFIG_CORE_CLOCK_240M: + reg_val = 3; + break; + default: + abort(); + } + + REG_SET_FIELD(SPI_MEM_CORE_CLK_SEL_REG(spi_num), SPI_MEM_CORE_CLK_SEL, reg_val); +} + +//-------------------------------------FLASH timing tuning-------------------------------------// +void IRAM_ATTR spi_timing_config_set_flash_clock(uint8_t spi_num, uint32_t freqdiv) +{ + assert(freqdiv > 0); + if (freqdiv == 1) { + WRITE_PERI_REG(SPI_MEM_CLOCK_REG(spi_num), SPI_MEM_CLK_EQU_SYSCLK); + } else { + uint32_t freqbits = (((freqdiv - 1) << SPI_MEM_CLKCNT_N_S)) | (((freqdiv / 2 - 1) << SPI_MEM_CLKCNT_H_S)) | ((freqdiv - 1) << SPI_MEM_CLKCNT_L_S); + WRITE_PERI_REG(SPI_MEM_CLOCK_REG(spi_num), freqbits); + } +} + +void IRAM_ATTR spi_timing_config_flash_set_din_mode_num(uint8_t spi_num, uint8_t din_mode, uint8_t din_num) +{ + uint32_t reg_val = 0; + reg_val = (REG_READ(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); + REG_WRITE(SPI_MEM_DIN_MODE_REG(spi_num), reg_val); + + reg_val = (REG_READ(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); + REG_WRITE(SPI_MEM_DIN_NUM_REG(spi_num), reg_val); +} + +void IRAM_ATTR spi_timing_config_flash_set_extra_dummy(uint8_t spi_num, uint8_t extra_dummy) +{ + 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); + } +} + +//-------------------------------------PSRAM timing tuning-------------------------------------// +void IRAM_ATTR spi_timing_config_set_psram_clock(uint8_t spi_num, uint32_t freqdiv) +{ + if (freqdiv == 1) { + WRITE_PERI_REG(SPI_MEM_SRAM_CLK_REG(spi_num), SPI_MEM_SCLK_EQU_SYSCLK); + } else { + uint32_t freqbits = (((freqdiv-1)< 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); + } +} + +//-------------------------------------------FLASH/PSRAM Read/Write------------------------------------------// +void IRAM_ATTR spi_timing_config_flash_read_data(uint8_t spi_num, uint8_t *buf, uint32_t addr, uint32_t len) +{ +#if CONFIG_ESPTOOLPY_OCT_FLASH + // note that in spi_flash_read API, there is a wait-idle stage, since flash can only be read in idle state. + // but after we change the timing settings, we might not read correct idle status via RDSR. + // so, here we should use a read API that won't check idle status. + for (int i = 0; i < 16; i++) { + REG_WRITE(SPI_MEM_W0_REG(1) + i*4, 0); + } + esp_rom_opiflash_read_raw(addr, buf, len); +#else + abort(); +#endif +} + +void IRAM_ATTR spi_timing_config_psram_write_data(uint8_t spi_num, uint8_t *buf, uint32_t addr, uint32_t len) +{ +#if CONFIG_ESPTOOLPY_OCT_FLASH + uint32_t cmd = OPI_PSRAM_SYNC_WRITE; + int dummy = OCT_PSRAM_WR_DUMMY_NUM; + + esp_rom_opiflash_exec_cmd(spi_num, ESP_ROM_SPIFLASH_OPI_DTR_MODE, + cmd, 16, + addr, 32, + dummy, + buf, 8 * len, + NULL, 0, + BIT(1), + false); +#else + abort(); +#endif +} + +void IRAM_ATTR spi_timing_config_psram_read_data(uint8_t spi_num,uint8_t *buf, uint32_t addr, uint32_t len) +{ +#if CONFIG_ESPTOOLPY_OCT_FLASH + uint32_t cmd = OPI_PSRAM_SYNC_READ; + int dummy = OCT_PSRAM_RD_DUMMY_NUM; + + esp_rom_opiflash_exec_cmd(spi_num, ESP_ROM_SPIFLASH_OPI_DTR_MODE, + cmd, 16, + addr, 32, + dummy, + NULL, 0, + buf, 8 * len, + BIT(1), + false); +#else + abort(); +#endif +} + +#endif //#if SPI_TIMING_FLASH_NEEDS_TUNING || SPI_TIMING_PSRAM_NEEDS_TUNING diff --git a/components/esp32s3/spiram.c b/components/esp32s3/spiram.c index c8a5609b1c..7d8d63a095 100644 --- a/components/esp32s3/spiram.c +++ b/components/esp32s3/spiram.c @@ -50,7 +50,7 @@ static const char *TAG = "spiram"; #define PSRAM_SPEED PSRAM_CACHE_S20M #endif -static bool spiram_inited = false; +static bool s_spiram_inited = false; /* @@ -245,8 +245,7 @@ esp_err_t esp_spiram_init(void) #endif return r; } - - spiram_inited = true; + s_spiram_inited = true; #if (CONFIG_SPIRAM_SIZE != -1) if (esp_spiram_get_size() != CONFIG_SPIRAM_SIZE) { ESP_EARLY_LOGE(TAG, "Expected %dKiB chip but found %dKiB chip. Bailing out..", CONFIG_SPIRAM_SIZE / 1024, esp_spiram_get_size() / 1024); @@ -296,7 +295,7 @@ esp_err_t esp_spiram_reserve_dma_pool(size_t size) size_t esp_spiram_get_size(void) { - if (!spiram_inited) { + if (!s_spiram_inited) { ESP_EARLY_LOGE(TAG, "SPI RAM not initialized"); abort(); } @@ -311,6 +310,12 @@ size_t esp_spiram_get_size(void) if (size == PSRAM_SIZE_64MBITS) { return 8 * 1024 * 1024; } + if (size == PSRAM_SIZE_128MBITS) { + return 16 * 1024 * 1024; + } + if (size == PSRAM_SIZE_256MBITS) { + return 32 * 1024 * 1024; + } return CONFIG_SPIRAM_SIZE; } diff --git a/components/esp32s3/spiram_psram.c b/components/esp32s3/spiram_psram.c index a7e295a135..42d22f24af 100644 --- a/components/esp32s3/spiram_psram.c +++ b/components/esp32s3/spiram_psram.c @@ -45,7 +45,7 @@ #include "driver/periph_ctrl.h" #include "bootloader_common.h" -#if CONFIG_SPIRAM +#if CONFIG_SPIRAM_MODE_QUAD #include "soc/rtc.h" static const char* TAG = "psram"; diff --git a/components/esp32s3/spiram_psram.h b/components/esp32s3/spiram_psram.h index ea7908f030..080bc50c41 100644 --- a/components/esp32s3/spiram_psram.h +++ b/components/esp32s3/spiram_psram.h @@ -28,9 +28,11 @@ typedef enum { } psram_cache_mode_t; typedef enum { - PSRAM_SIZE_16MBITS = 0, - PSRAM_SIZE_32MBITS = 1, - PSRAM_SIZE_64MBITS = 2, + PSRAM_SIZE_16MBITS = 0, + PSRAM_SIZE_32MBITS = 1, + PSRAM_SIZE_64MBITS = 2, + PSRAM_SIZE_128MBITS = 3, + PSRAM_SIZE_256MBITS = 4, PSRAM_SIZE_MAX, } psram_size_t; diff --git a/components/esp_rom/esp32s3/ld/esp32s3.rom.ld b/components/esp_rom/esp32s3/ld/esp32s3.rom.ld index 636d648be7..af0ea28e2a 100644 --- a/components/esp_rom/esp32s3/ld/esp32s3.rom.ld +++ b/components/esp_rom/esp32s3/ld/esp32s3.rom.ld @@ -128,6 +128,7 @@ PROVIDE( esp_rom_opiflash_write = 0x40000930 ); PROVIDE( esp_rom_spi_set_dtr_swap_mode = 0x4000093c ); PROVIDE( esp_rom_opiflash_exit_continuous_read_mode = 0x40000948 ); PROVIDE( esp_rom_opiflash_legacy_driver_init = 0x40000954 ); +PROVIDE( esp_rom_opiflash_read_raw = 0x4004d9d4); /* Data (.data, .bss, .rodata) */ PROVIDE( rom_opiflash_cmd_def = 0x3fcefff4 ); PROVIDE( rom_spi_usr_cmd_legacy_funcs = 0x3fcefff0 ); diff --git a/components/esp_rom/include/esp32s3/rom/opi_flash.h b/components/esp_rom/include/esp32s3/rom/opi_flash.h index be7fcb06a9..8976e7b53e 100644 --- a/components/esp_rom/include/esp32s3/rom/opi_flash.h +++ b/components/esp_rom/include/esp32s3/rom/opi_flash.h @@ -8,12 +8,46 @@ #include #include #include +#include #include "spi_flash.h" #ifdef __cplusplus extern "C" { #endif + + +typedef struct { + uint8_t mode; + uint8_t cmd_bit_len; + uint16_t cmd; + uint32_t addr; + uint8_t addr_bit_len; + uint8_t dummy_bit_len; + uint8_t data_bit_len; + uint8_t cs_sel: 4; + uint8_t is_pe: 4; +} esp_rom_opiflash_cmd_t; + +typedef struct { + uint8_t addr_bit_len; + uint8_t dummy_bit_len; + uint16_t cmd; + uint8_t cmd_bit_len; + uint8_t var_dummy_en; +} esp_rom_opiflash_spi0rd_t; + +typedef struct { + esp_rom_opiflash_cmd_t rdid; + esp_rom_opiflash_cmd_t rdsr; + esp_rom_opiflash_cmd_t wren; + esp_rom_opiflash_cmd_t se; + esp_rom_opiflash_cmd_t be64k; + esp_rom_opiflash_cmd_t read; + esp_rom_opiflash_cmd_t pp; + esp_rom_opiflash_spi0rd_t cache_rd_cmd; +} esp_rom_opiflash_def_t; + typedef struct { uint16_t cmd; /*!< Command value */ uint16_t cmdBitLen; /*!< Command byte length*/ @@ -40,7 +74,6 @@ typedef struct { #define ESP_ROM_SPIFLASH_BP2 BIT4 #define ESP_ROM_SPIFLASH_WR_PROTECT (ESP_ROM_SPIFLASH_BP0|ESP_ROM_SPIFLASH_BP1|ESP_ROM_SPIFLASH_BP2) #define ESP_ROM_SPIFLASH_QE BIT9 -#define ESP_ROM_SPIFLASH_BP_MASK_ISSI (BIT7 | BIT5 | BIT4 | BIT3 | BIT2) #define FLASH_OP_MODE_RDCMD_DOUT 0x3B #define ESP_ROM_FLASH_SECTOR_SIZE 0x1000 @@ -112,8 +145,14 @@ typedef struct { #define ROM_FLASH_CMD_EN4B_GD 0xB7 #define ROM_FLASH_CMD_DIS4B_GD 0xE9 -// spi user mode command config +extern const esp_rom_opiflash_def_t *rom_opiflash_cmd_def; +/** + * @brief init legacy driver for Octal Flash + */ +void esp_rom_opiflash_legacy_driver_init(const esp_rom_opiflash_def_t *flash_cmd_def); + +// spi user mode command config /** * @brief Config the spi user command * @param spi_num spi port @@ -159,8 +198,6 @@ void esp_rom_spi_set_dtr_swap_mode(int spi, bool wr_swap, bool rd_swap); */ void esp_rom_opiflash_mode_reset(int spi_num); -#if 0 -// MX25UM25645G opi flash interface /** * @brief To execute a flash operation command * @param spi_num spi port @@ -193,105 +230,91 @@ void esp_rom_opiflash_exec_cmd(int spi_num, esp_rom_spiflash_read_mode_t mode, */ void esp_rom_opiflash_soft_reset(int spi_num, esp_rom_spiflash_read_mode_t mode); -/** - * @brief to read opi flash ID(for MX25UM25645G) - * @param spi_num spi port - * @param mode Flash Operation Mode - * @return opi flash id - */ -uint32_t esp_rom_opiflash_read_id(int spi_num, esp_rom_spiflash_read_mode_t mode); /** - * @brief to read opi flash status register(for MX25UM25645G) - * @param spi_num spi port - * @param mode Flash Operation Mode + * @brief to read opi flash ID + * @note command format would be defined in initialization + * @param[out] out_id buffer to accept id + * @return flash operation result + */ +esp_rom_spiflash_result_t esp_rom_opiflash_read_id(uint8_t *out_id); + +/** + * @brief to read opi flash status register + * @note command format would be defined in initialization * @return opi flash status value */ -uint8_t esp_rom_opiflash_rdsr(int spi_num, esp_rom_spiflash_read_mode_t mode); +uint8_t esp_rom_opiflash_rdsr(void); /** * @brief wait opi flash status register to be idle - * @param spi_num spi port - * @param mode Flash Operation Mode - */ -void esp_rom_opiflash_wait_idle(int spi_num, esp_rom_spiflash_read_mode_t mode); - -/** - * @brief to read the config register2(for MX25UM25645G) - * @param spi_num spi port - * @param mode Flash Operation Mode - * @param addr the address of configure register - * @return value of config register2 - */ -uint8_t esp_rom_opiflash_rdcr2(int spi_num, esp_rom_spiflash_read_mode_t mode, uint32_t addr); - -/** - * @brief to write the config register2(for MX25UM25645G) - * @param spi_num spi port - * @param mode Flash Operation Mode - * @param addr the address of config register - * @param val the value to write - */ -void esp_rom_opiflash_wrcr2(int spi_num, esp_rom_spiflash_read_mode_t mode, uint32_t addr, uint8_t val); - -/** - * @brief to erase flash sector(for MX25UM25645G) - * @param spi_num spi port - * @param address the sector address to be erased - * @param mode Flash operation mode + * @note command format would be defined in initialization * @return flash operation result */ -esp_rom_spiflash_result_t esp_rom_opiflash_erase_sector(int spi_num, uint32_t address, esp_rom_spiflash_read_mode_t mode); +esp_rom_spiflash_result_t esp_rom_opiflash_wait_idle(void); /** - * @brief to erase flash block(for MX25UM25645G) - * @param spi_num spi port - * @param address the block address to be erased - * @param mode Flash operation mode + * @brief to erase flash sector + * @note command format would be defined in initialization + * @param sector_num the sector to be erased * @return flash operation result */ -esp_rom_spiflash_result_t esp_rom_opiflash_erase_block_64k(int spi_num, uint32_t address, esp_rom_spiflash_read_mode_t mode); +esp_rom_spiflash_result_t esp_rom_opiflash_erase_sector(uint32_t sector_num); /** - * @brief to erase a flash area define by start address and length(for MX25UM25645G) - * @param spi_num spi port + * @brief to erase flash block + * @note command format would be defined in initialization + * @param block_num the block to be erased + * @return flash operation result + */ +esp_rom_spiflash_result_t esp_rom_opiflash_erase_block_64k(uint32_t block_num); + +/** + * @brief to erase a flash area define by start address and length + * @note command format would be defined in initialization * @param start_addr the start address to be erased * @param area_len the erea length to be erased - * @param mode flash operation mode * @return flash operation result */ -esp_rom_spiflash_result_t esp_rom_opiflash_erase_area(int spi_num, uint32_t start_addr, uint32_t area_len, esp_rom_spiflash_read_mode_t mode); +esp_rom_spiflash_result_t esp_rom_opiflash_erase_area(uint32_t start_addr, uint32_t area_len); /** - * @brief to read data from opi flash(for MX25UM25645G) - * @param spi_num spi port - * @param mode flash operation mode + * @brief to read data from opi flash + * @note command format would be defined in initialization * @param flash_addr flash address to read data from * @param data_addr data buffer to accept the data * @param len data length to be read * @return flash operation result */ -esp_rom_spiflash_result_t esp_rom_opiflash_read(int spi_num, esp_rom_spiflash_read_mode_t mode, uint32_t flash_addr, uint8_t *data_addr, int len); +esp_rom_spiflash_result_t esp_rom_opiflash_read(uint32_t flash_addr, void *data_addr, int len); /** - * @brief to write data to opi flash(for MX25UM25645G) - * @param spi_num spi port - * @param mode flash operation mode + * @brief to write data to opi flash + * @note command format would be defined in initialization * @param flash_addr flash address to write data to * @param data_addr data buffer to write to flash * @param len data length to write * @return flash operation result */ -esp_rom_spiflash_result_t esp_rom_opiflash_write(int spi_num, esp_rom_spiflash_read_mode_t mode, uint32_t flash_addr, uint8_t *data_addr, uint32_t len); +esp_rom_spiflash_result_t esp_rom_opiflash_write(uint32_t flash_addr, const uint32_t *data_addr, int len); /** - * @brief to set opi flash operation mode(for MX25UM25645G) - * @param spi_num spi port - * @param cur_mode current operation mode - * @param target the target operation mode to be set + * @brief send WREN command + * @note command format would be defined in initialization + * @param arg not used, set to NULL + * @return flash operation result */ -void esp_rom_opiflash_set_mode(int spi_num, esp_rom_spiflash_read_mode_t cur_mode, esp_rom_spiflash_read_mode_t target_mode); -#endif +esp_rom_spiflash_result_t esp_rom_opiflash_wren(void* arg); + +/** + * @brief to configure SPI0 read flash command format for cache + * @note command format would be defined in initialization + * + */ +void esp_rom_opiflash_cache_mode_config(esp_rom_spiflash_read_mode_t mode, const esp_rom_opiflash_spi0rd_t *cache); + +esp_rom_spiflash_result_t esp_rom_opiflash_read_raw(uint32_t flash_addr, uint8_t* buf, int len); + #ifdef __cplusplus } diff --git a/components/esp_rom/include/esp32s3/rom/spi_flash.h b/components/esp_rom/include/esp32s3/rom/spi_flash.h index 3e71bb6f68..8c5170b5a8 100644 --- a/components/esp_rom/include/esp32s3/rom/spi_flash.h +++ b/components/esp_rom/include/esp32s3/rom/spi_flash.h @@ -121,7 +121,12 @@ typedef enum { ESP_ROM_SPIFLASH_DIO_MODE, ESP_ROM_SPIFLASH_DOUT_MODE, ESP_ROM_SPIFLASH_FASTRD_MODE, - ESP_ROM_SPIFLASH_SLOWRD_MODE + ESP_ROM_SPIFLASH_SLOWRD_MODE, + ESP_ROM_SPIFLASH_OPI_STR_MODE, + ESP_ROM_SPIFLASH_OPI_DTR_MODE, + ESP_ROM_SPIFLASH_OOUT_MODE, + ESP_ROM_SPIFLASH_OIO_STR_MODE, + ESP_ROM_SPIFLASH_OIO_DTR_MODE, } esp_rom_spiflash_read_mode_t; typedef enum { @@ -148,6 +153,34 @@ typedef struct { uint16_t data; } esp_rom_spiflash_common_cmd_t; +typedef void (*spi_flash_func_t)(void); +typedef esp_rom_spiflash_result_t (*spi_flash_op_t)(void); +typedef esp_rom_spiflash_result_t (*spi_flash_erase_t)(uint32_t); +typedef esp_rom_spiflash_result_t (*spi_flash_rd_t)(uint32_t, void*, int); +typedef esp_rom_spiflash_result_t (*spi_flash_wr_t)(uint32_t, const uint32_t*, int); +typedef esp_rom_spiflash_result_t (*spi_flash_ewr_t)(uint32_t, const void*, uint32_t); +typedef esp_rom_spiflash_result_t (*spi_flash_wren_t)(void*); +typedef esp_rom_spiflash_result_t (* spi_flash_erase_area_t)(uint32_t, uint32_t); + +typedef struct { + uint8_t pp_addr_bit_len; + uint8_t se_addr_bit_len; + uint8_t be_addr_bit_len; + uint8_t rd_addr_bit_len; + uint32_t read_sub_len; + uint32_t write_sub_len; + spi_flash_op_t unlock; + spi_flash_erase_t erase_sector; + spi_flash_erase_t erase_block; + spi_flash_rd_t read; + spi_flash_wr_t write; + spi_flash_ewr_t encrypt_write; + spi_flash_func_t check_sus; + spi_flash_wren_t wren; + spi_flash_op_t wait_idle; + spi_flash_erase_area_t erase_area; +} spiflash_legacy_funcs_t; + /** * @brief Fix the bug in SPI hardware communication with Flash/Ext-SRAM in High Speed. @@ -548,33 +581,6 @@ void esp_rom_spiflash_select_qio_pins(uint8_t wp_gpio_num, uint32_t spiconfig); * @return always ESP_ROM_SPIFLASH_RESULT_OK */ esp_rom_spiflash_result_t esp_rom_spiflash_write_disable(void); - -typedef void (* spi_flash_func_t)(void); -typedef SpiFlashOpResult (* spi_flash_op_t)(void); -typedef SpiFlashOpResult (* spi_flash_erase_t)(uint32_t); -typedef SpiFlashOpResult (* spi_flash_rd_t)(uint32_t, uint32_t*, int); -typedef SpiFlashOpResult (* spi_flash_wr_t)(uint32_t, const uint32_t*, int); -typedef SpiFlashOpResult (* spi_flash_ewr_t)(uint32_t, const void*, uint32_t); -typedef SpiFlashOpResult (* spi_flash_wren_t)(void*); - - -typedef struct { - uint32_t read_sub_len; - uint32_t write_sub_len; - spi_flash_op_t unlock; - spi_flash_erase_t erase_sector; - spi_flash_erase_t erase_block; - spi_flash_rd_t read; - spi_flash_wr_t write; - spi_flash_ewr_t encrypt_write; - spi_flash_func_t check_sus; - spi_flash_wren_t wren; - spi_flash_op_t wait_idle; -} spiflash_legacy_funcs_t; - -/* Defined in the interfaces file, default value is rom_default_spiflash_legacy_flash_func */ -extern const spiflash_legacy_funcs_t *rom_spiflash_legacy_funcs; - typedef struct { esp_rom_spiflash_chip_t chip; uint8_t dummy_len_plus[3]; diff --git a/components/esp_system/port/cpu_start.c b/components/esp_system/port/cpu_start.c index 49c65306d9..088eda31a3 100644 --- a/components/esp_system/port/cpu_start.c +++ b/components/esp_system/port/cpu_start.c @@ -54,6 +54,7 @@ #include "soc/assist_debug_reg.h" #include "soc/cache_memory.h" #include "soc/system_reg.h" +#include "esp32s3/rom/opi_flash.h" #elif CONFIG_IDF_TARGET_ESP32C3 #include "esp32c3/rtc.h" #include "esp32c3/rom/cache.h" @@ -62,6 +63,7 @@ #include "esp32c3/memprot.h" #endif +#include "spi_flash_private.h" #include "bootloader_flash_config.h" #include "esp_private/crosscore_int.h" #include "esp_flash_encrypt.h" @@ -353,6 +355,16 @@ void IRAM_ATTR call_start_cpu0(void) Cache_Set_IDROM_MMU_Size(cache_mmu_irom_size, CACHE_DROM_MMU_MAX_END - cache_mmu_irom_size); #endif // CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 +#if CONFIG_ESPTOOLPY_OCT_FLASH + bool efuse_opflash_en = REG_GET_FIELD(EFUSE_RD_REPEAT_DATA3_REG, EFUSE_FLASH_TYPE); + if (!efuse_opflash_en) { + ESP_EARLY_LOGE(TAG, "Octal Flash option selected, but EFUSE not configured!"); + abort(); + } + esp_opiflash_init(); + spi_timing_flash_tuning(); +#endif + bootloader_init_mem(); #if CONFIG_SPIRAM_BOOT_INIT if (esp_spiram_init() != ESP_OK) { diff --git a/components/esptool_py/Kconfig.projbuild b/components/esptool_py/Kconfig.projbuild index 74028a45ca..0bbbe72070 100644 --- a/components/esptool_py/Kconfig.projbuild +++ b/components/esptool_py/Kconfig.projbuild @@ -61,6 +61,33 @@ menu "Serial flasher config" The flasher tool sends a precompiled download stub first by default. That stub allows things like compressed downloads and more. Usually you should not need to disable that feature + config ESPTOOLPY_OCT_FLASH + depends on IDF_TARGET_ESP32S3 + bool "Enable Octal Flash" + default n + + choice ESPTOOLPY_FLASH_VENDOR + depends on ESPTOOLPY_OCT_FLASH + prompt "Select OPI Flash Vendor" + default ESPTOOLPY_FLASH_VENDOR_MXIC + + config ESPTOOLPY_FLASH_VENDOR_MXIC + bool "MXIC OPI FLASH(MX25UM25645G)" + endchoice + + choice ESPTOOLPY_FLASHMODE_OCT + depends on ESPTOOLPY_OCT_FLASH + prompt "Flash OPI mode" + default ESPTOOLPY_FLASHMODE_OPI_DTR + + config ESPTOOLPY_FLASHMODE_OPI_STR + depends on ESPTOOLPY_FLASH_VENDOR_MXIC + bool "OPI_STR" + config ESPTOOLPY_FLASHMODE_OPI_DTR + depends on ESPTOOLPY_FLASH_VENDOR_MXIC + bool "OPI_DTR" + endchoice + choice ESPTOOLPY_FLASHMODE prompt "Flash SPI mode" default ESPTOOLPY_FLASHMODE_DIO @@ -101,6 +128,7 @@ menu "Serial flasher config" bool "40 MHz" config ESPTOOLPY_FLASHFREQ_26M bool "26 MHz" + depends on IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32C3 config ESPTOOLPY_FLASHFREQ_20M bool "20 MHz" endchoice diff --git a/components/soc/esp32s3/include/soc/soc.h b/components/soc/esp32s3/include/soc/soc.h index 404c2da295..20832a12e0 100644 --- a/components/soc/esp32s3/include/soc/soc.h +++ b/components/soc/esp32s3/include/soc/soc.h @@ -70,7 +70,7 @@ #define DR_REG_PCNT_BASE 0x60017000 #define DR_REG_SLC_BASE 0x60018000 #define DR_REG_LEDC_BASE 0x60019000 -#define DR_REG_EFUSE_BASE 0x6001A000 +#define DR_REG_EFUSE_BASE 0x60007000 #define DR_REG_NRX_BASE 0x6001CC00 #define DR_REG_BB_BASE 0x6001D000 #define DR_REG_PWM0_BASE 0x6001E000 diff --git a/components/spi_flash/CMakeLists.txt b/components/spi_flash/CMakeLists.txt index 791a15446f..2a8b11c0ec 100644 --- a/components/spi_flash/CMakeLists.txt +++ b/components/spi_flash/CMakeLists.txt @@ -77,6 +77,14 @@ else() "${target}/spi_flash_rom_patch.c" ) + if(CONFIG_ESPTOOLPY_OCT_FLASH) + list(APPEND srcs "${target}/spi_flash_oct_flash_init.c") + endif() + + if(CONFIG_IDF_TARGET_ESP32S3) + list(APPEND srcs "spi_flash_timing_tuning.c") + endif() + # New implementation after IDF v4.0 list(APPEND srcs "spi_flash_chip_drivers.c" diff --git a/components/spi_flash/component.mk b/components/spi_flash/component.mk index 392cd68a25..03c92cb3a9 100644 --- a/components/spi_flash/component.mk +++ b/components/spi_flash/component.mk @@ -5,6 +5,8 @@ COMPONENT_PRIV_INCLUDEDIRS := include/spi_flash COMPONENT_ADD_LDFRAGMENTS += linker.lf +COMPONENT_OBJEXCLUDE := spi_flash_timing_tuning.o + ifdef IS_BOOTLOADER_BUILD # Bootloader needs updated SPIUnlock from this file COMPONENT_OBJS := esp32/spi_flash_rom_patch.o diff --git a/components/spi_flash/esp32s3/opi_flash_cmd_format_mxic.h b/components/spi_flash/esp32s3/opi_flash_cmd_format_mxic.h new file mode 100644 index 0000000000..06cd8a76fa --- /dev/null +++ b/components/spi_flash/esp32s3/opi_flash_cmd_format_mxic.h @@ -0,0 +1,184 @@ +/* + * SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#if CONFIG_ESPTOOLPY_FLASH_VENDOR_MXIC +#if CONFIG_ESPTOOLPY_FLASHMODE_OPI_STR +#define OPI_CMD_FORMAT() { \ + .rdid = { \ + .mode = ESP_ROM_SPIFLASH_OPI_STR_MODE, \ + .cmd_bit_len = 16, \ + .cmd = 0x609f, \ + .addr = 0, \ + .addr_bit_len = 4*8, \ + .dummy_bit_len = 4, \ + .data_bit_len = 4 * 8, \ + .cs_sel = 0x1, \ + .is_pe = 0, \ + }, \ + .rdsr = { \ + .mode = ESP_ROM_SPIFLASH_OPI_STR_MODE, \ + .cmd_bit_len = 16, \ + .cmd = 0xfa05, \ + .addr = 0, \ + .addr_bit_len = 4*8, \ + .dummy_bit_len = 4, \ + .data_bit_len = 1 * 8, \ + .cs_sel = 0x1, \ + .is_pe = 0, \ + }, \ + .wren = { \ + .mode = ESP_ROM_SPIFLASH_OPI_STR_MODE, \ + .cmd_bit_len = 16, \ + .cmd = 0xf906, \ + .addr = 0, \ + .addr_bit_len = 0, \ + .dummy_bit_len = 0, \ + .data_bit_len = 0, \ + .cs_sel = 0x1, \ + .is_pe = 0, \ + }, \ + .se = { \ + .mode = ESP_ROM_SPIFLASH_OPI_STR_MODE, \ + .cmd_bit_len = 16, \ + .cmd = 0xde21, \ + .addr = 0, \ + .addr_bit_len = 32, \ + .dummy_bit_len = 0, \ + .data_bit_len = 0, \ + .cs_sel = 0x1, \ + .is_pe = 1, \ + }, \ + .be64k = { \ + .mode = ESP_ROM_SPIFLASH_OPI_STR_MODE, \ + .cmd_bit_len = 16, \ + .cmd = 0x23dc, \ + .addr = 0, \ + .addr_bit_len = 32, \ + .dummy_bit_len = 0, \ + .data_bit_len = 0, \ + .cs_sel = 0x1, \ + .is_pe = 1, \ + }, \ + .read = { \ + .mode = ESP_ROM_SPIFLASH_OPI_STR_MODE, \ + .cmd_bit_len = 16, \ + .cmd = 0x13ec, \ + .addr = 0, \ + .addr_bit_len = 32, \ + .dummy_bit_len = 20, \ + .data_bit_len = 0, \ + .cs_sel = 0x1, \ + .is_pe = 0, \ + }, \ + .pp = { \ + .mode = ESP_ROM_SPIFLASH_OPI_STR_MODE, \ + .cmd_bit_len = 16, \ + .cmd = 0xed12, \ + .addr = 0, \ + .addr_bit_len = 32, \ + .dummy_bit_len = 0, \ + .data_bit_len = 0, \ + .cs_sel = 0x1, \ + .is_pe = 1, \ + }, \ + .cache_rd_cmd = { \ + .addr_bit_len = 32, \ + .dummy_bit_len = 20, \ + .cmd = 0x13ec, \ + .cmd_bit_len = 16, \ + .var_dummy_en = 1, \ + } \ +} + +#elif CONFIG_ESPTOOLPY_FLASHMODE_OPI_DTR +#define OPI_CMD_FORMAT() { \ + .rdid = { \ + .mode = ESP_ROM_SPIFLASH_OPI_DTR_MODE, \ + .cmd_bit_len = 16, \ + .cmd = 0x609f, \ + .addr = 0, \ + .addr_bit_len = 4*8, \ + .dummy_bit_len = 4*2, \ + .data_bit_len = 4 * 8, \ + .cs_sel = 0x1, \ + .is_pe = 0, \ + }, \ + .rdsr = { \ + .mode = ESP_ROM_SPIFLASH_OPI_DTR_MODE, \ + .cmd_bit_len = 16, \ + .cmd = 0xfa05, \ + .addr = 0, \ + .addr_bit_len = 4*8, \ + .dummy_bit_len = 4*2, \ + .data_bit_len = 2 * 8, \ + .cs_sel = 0x1, \ + .is_pe = 0, \ + }, \ + .wren = { \ + .mode = ESP_ROM_SPIFLASH_OPI_DTR_MODE, \ + .cmd_bit_len = 16, \ + .cmd = 0xf906, \ + .addr = 0, \ + .addr_bit_len = 0, \ + .dummy_bit_len = 0, \ + .data_bit_len = 0, \ + .cs_sel = 0x1, \ + .is_pe = 0, \ + }, \ + .se = { \ + .mode = ESP_ROM_SPIFLASH_OPI_DTR_MODE, \ + .cmd_bit_len = 16, \ + .cmd = 0xde21, \ + .addr = 0, \ + .addr_bit_len = 32, \ + .dummy_bit_len = 0, \ + .data_bit_len = 0, \ + .cs_sel = 0x1, \ + .is_pe = 1, \ + }, \ + .be64k = { \ + .mode = ESP_ROM_SPIFLASH_OPI_DTR_MODE, \ + .cmd_bit_len = 16, \ + .cmd = 0x23dc, \ + .addr = 0, \ + .addr_bit_len = 32, \ + .dummy_bit_len = 0, \ + .data_bit_len = 0, \ + .cs_sel = 0x1, \ + .is_pe = 1, \ + }, \ + .read = { \ + .mode = ESP_ROM_SPIFLASH_OPI_DTR_MODE, \ + .cmd_bit_len = 16, \ + .cmd = 0x11ee, \ + .addr = 0, \ + .addr_bit_len = 32, \ + .dummy_bit_len = 20*2, \ + .data_bit_len = 0, \ + .cs_sel = 0x1, \ + .is_pe = 0, \ + }, \ + .pp = { \ + .mode = ESP_ROM_SPIFLASH_OPI_DTR_MODE, \ + .cmd_bit_len = 16, \ + .cmd = 0xed12, \ + .addr = 0, \ + .addr_bit_len = 32, \ + .dummy_bit_len = 0, \ + .data_bit_len = 0, \ + .cs_sel = 0x1, \ + .is_pe = 1, \ + }, \ + .cache_rd_cmd = { \ + .addr_bit_len = 32, \ + .dummy_bit_len = 20*2, \ + .cmd = 0x11ee, \ + .cmd_bit_len = 16, \ + .var_dummy_en = 1, \ + } \ +} +#endif +#endif diff --git a/components/spi_flash/esp32s3/spi_flash_oct_flash_init.c b/components/spi_flash/esp32s3/spi_flash_oct_flash_init.c new file mode 100644 index 0000000000..42de479acc --- /dev/null +++ b/components/spi_flash/esp32s3/spi_flash_oct_flash_init.c @@ -0,0 +1,194 @@ +/* + * SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "sdkconfig.h" +#include "esp_err.h" +#include "esp_rom_gpio.h" +#include "esp32s3/rom/gpio.h" +#include "esp32s3/rom/spi_flash.h" +#include "esp32s3/rom/opi_flash.h" +#include "spi_flash_private.h" +#include "soc/spi_mem_reg.h" +#if CONFIG_ESPTOOLPY_FLASH_VENDOR_MXIC +#include "opi_flash_cmd_format_mxic.h" +#endif + +#define SPI_FLASH_SPI_CMD_WRCR2 0x72 +#define SPI_FLASH_SPI_CMD_RDSR 0x05 +#define SPI_FLASH_SPI_CMD_RDCR 0x15 +#define SPI_FLASH_SPI_CMD_WRSRCR 0x01 + +#define SPI_FLASH_OCTCLK_IO 30 +#define SPI_FLASH_OCTDQS_IO 37 +#define SPI_FLASH_OCTD0_IO 32 +#define SPI_FLASH_OCTD1_IO 31 +#define SPI_FLASH_OCTD2_IO 28 +#define SPI_FLASH_OCTD3_IO 27 +#define SPI_FLASH_OCTD4_IO 33 +#define SPI_FLASH_OCTD5_IO 34 +#define SPI_FLASH_OCTD6_IO 35 +#define SPI_FLASH_OCTD7_IO 36 +#define SPI_FLASH_OCTCS_IO 29 +#define SPI_FLASH_OCTCS1_IO 26 + + +// default value is rom_default_spiflash_legacy_flash_func +extern const spiflash_legacy_funcs_t *rom_spiflash_legacy_funcs; +extern int SPI_write_enable(void *spi); +DRAM_ATTR const esp_rom_opiflash_def_t opiflash_cmd_def = OPI_CMD_FORMAT(); + +void s_set_flash_pin_drive_capability(uint8_t drv) +{ + esp_rom_gpio_pad_set_drv(SPI_FLASH_OCTCLK_IO, drv); + esp_rom_gpio_pad_set_drv(SPI_FLASH_OCTDQS_IO, drv); + esp_rom_gpio_pad_set_drv(SPI_FLASH_OCTD0_IO, drv); + esp_rom_gpio_pad_set_drv(SPI_FLASH_OCTD1_IO, drv); + esp_rom_gpio_pad_set_drv(SPI_FLASH_OCTD2_IO, drv); + esp_rom_gpio_pad_set_drv(SPI_FLASH_OCTD3_IO, drv); + esp_rom_gpio_pad_set_drv(SPI_FLASH_OCTD4_IO, drv); + esp_rom_gpio_pad_set_drv(SPI_FLASH_OCTD5_IO, drv); + esp_rom_gpio_pad_set_drv(SPI_FLASH_OCTD6_IO, drv); + esp_rom_gpio_pad_set_drv(SPI_FLASH_OCTD7_IO, drv); + esp_rom_gpio_pad_set_drv(SPI_FLASH_OCTCS_IO, drv); + esp_rom_gpio_pad_set_drv(SPI_FLASH_OCTCS1_IO, drv); +} + +static void s_register_rom_function(void) +{ + static spiflash_legacy_funcs_t rom_func = + { + .read_sub_len = 32, + .write_sub_len = 32, + .unlock = esp_rom_opiflash_wait_idle, + .erase_block = esp_rom_opiflash_erase_block_64k, + .erase_sector = esp_rom_opiflash_erase_sector, + .read = esp_rom_opiflash_read, + .write = esp_rom_opiflash_write, + .wait_idle = esp_rom_opiflash_wait_idle, + .wren = esp_rom_opiflash_wren, + .erase_area = esp_rom_opiflash_erase_area, + }; + rom_spiflash_legacy_funcs = &rom_func; +} + +#if CONFIG_ESPTOOLPY_FLASH_VENDOR_MXIC +// 0x00: SPI; 0x01: STR OPI; 0x02: DTR OPI +static void s_set_flash_dtr_str_opi_mode(int spi_num, uint8_t val) +{ + uint8_t cmd_len = 8; + int addr_bit_len = 32; + int dummy = 0; + int data_bit_len = 8; + + SPI_write_enable(&g_rom_flashchip); + //SPI command, WRCR2 + esp_rom_opiflash_exec_cmd(spi_num, ESP_ROM_SPIFLASH_FASTRD_MODE, + SPI_FLASH_SPI_CMD_WRCR2, cmd_len, + 0, addr_bit_len, + dummy, + (uint8_t *)&val, data_bit_len, + NULL, 0, + ESP_ROM_OPIFLASH_SEL_CS0, + false); +} + +//To set the output driver strength +static void s_set_flash_ouput_driver_strength(int spi_num, uint8_t strength) +{ + uint16_t reg_val = 0; + uint8_t sr_reg_val = 0; + uint8_t cr_reg_val = 0; + uint8_t cmd_len = 8; + uint32_t addr = 0; + int addr_bit_len = 0; + int dummy = 0; + int data_bit_len = 8; + + //Read + //SPI command, RDSR + esp_rom_opiflash_exec_cmd(spi_num, ESP_ROM_SPIFLASH_FASTRD_MODE, + SPI_FLASH_SPI_CMD_RDSR, cmd_len, + addr, addr_bit_len, + dummy, + NULL, 0, + (uint8_t*)&sr_reg_val, data_bit_len, + ESP_ROM_OPIFLASH_SEL_CS0, + false); + + //SPI command, RDCR + esp_rom_opiflash_exec_cmd(spi_num, ESP_ROM_SPIFLASH_FASTRD_MODE, + SPI_FLASH_SPI_CMD_RDCR, cmd_len, + addr, addr_bit_len, + dummy, + NULL, 0, + (uint8_t*)&cr_reg_val, data_bit_len, + ESP_ROM_OPIFLASH_SEL_CS0, + false); + + //Modify + reg_val = (((cr_reg_val & 0xf8) | strength) << 8) | sr_reg_val; + + //Write + //SPI command, WRSR/WRCR + data_bit_len = 16; + SPI_write_enable(&g_rom_flashchip); + esp_rom_opiflash_exec_cmd(spi_num, ESP_ROM_SPIFLASH_FASTRD_MODE, + SPI_FLASH_SPI_CMD_WRSRCR, cmd_len, + addr, addr_bit_len, + dummy, + (uint8_t*)®_val, data_bit_len, + NULL, 0, + ESP_ROM_OPIFLASH_SEL_CS0, + false); +} + +static void s_flash_init_mxic(esp_rom_spiflash_read_mode_t mode) +{ + esp_rom_opiflash_legacy_driver_init(&opiflash_cmd_def); + esp_rom_spiflash_wait_idle(&g_rom_flashchip); + + // increase flash output driver strength + s_set_flash_ouput_driver_strength(1, 7); + + // STR/DTR specific setting + esp_rom_spiflash_wait_idle(&g_rom_flashchip); +#if CONFIG_ESPTOOLPY_FLASHMODE_OPI_STR + s_set_flash_pin_drive_capability(1); + s_set_flash_dtr_str_opi_mode(1, 0x1); + esp_rom_opiflash_cache_mode_config(mode, &rom_opiflash_cmd_def->cache_rd_cmd); + esp_rom_spi_set_dtr_swap_mode(0, false, false); + esp_rom_spi_set_dtr_swap_mode(1, false, false); +#else //CONFIG_ESPTOOLPY_FLASHMODE_OPI_DTR + s_set_flash_pin_drive_capability(3); + s_set_flash_dtr_str_opi_mode(1, 0x2); + esp_rom_opiflash_cache_mode_config(mode, &rom_opiflash_cmd_def->cache_rd_cmd); + esp_rom_spi_set_dtr_swap_mode(0, true, true); + esp_rom_spi_set_dtr_swap_mode(1, true, true); +#endif + + s_register_rom_function(); + esp_rom_opiflash_wait_idle(); +} +#endif // #if CONFIG_FLASH_VENDOR_XXX + +esp_err_t esp_opiflash_init(void) +{ + esp_rom_spiflash_read_mode_t mode; +#if CONFIG_ESPTOOLPY_FLASHMODE_OPI_STR + mode = ESP_ROM_SPIFLASH_OPI_STR_MODE; +#elif CONFIG_ESPTOOLPY_FLASHMODE_OPI_DTR + mode = ESP_ROM_SPIFLASH_OPI_DTR_MODE; +#else + mode = ESP_ROM_SPIFLASH_FASTRD_MODE; +#endif + +#if CONFIG_ESPTOOLPY_FLASH_VENDOR_MXIC + s_flash_init_mxic(mode); +#else + abort(); +#endif + return ESP_OK; +} diff --git a/components/spi_flash/esp32s3/spi_flash_rom_patch.c b/components/spi_flash/esp32s3/spi_flash_rom_patch.c index 2cdec50427..a3a6079529 100644 --- a/components/spi_flash/esp32s3/spi_flash_rom_patch.c +++ b/components/spi_flash/esp32s3/spi_flash_rom_patch.c @@ -1,28 +1,6 @@ -// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -#include "sdkconfig.h" -#include "esp32s3/rom/spi_flash.h" -#include "soc/spi_periph.h" -#include "spi_flash_defs.h" - - -#define SPI_IDX 1 -extern esp_rom_spiflash_chip_t g_rom_spiflash_chip; - -esp_rom_spiflash_result_t esp_rom_spiflash_write_disable(void) -{ - REG_WRITE(SPI_MEM_CMD_REG(SPI_IDX), SPI_MEM_FLASH_WRDI); - while (READ_PERI_REG(PERIPHS_SPI_FLASH_CMD) != 0); - return ESP_ROM_SPIFLASH_RESULT_OK; -} +/* + * SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +// We keep this file here only for future use diff --git a/components/spi_flash/flash_ops.c b/components/spi_flash/flash_ops.c index 8bd33fb3c4..485476d502 100644 --- a/components/spi_flash/flash_ops.c +++ b/components/spi_flash/flash_ops.c @@ -37,6 +37,7 @@ #include "esp32s2/rom/spi_flash.h" #include "esp32s2/clk.h" #elif CONFIG_IDF_TARGET_ESP32S3 +#include "soc/spi_mem_reg.h" #include "esp32s3/rom/spi_flash.h" #include "esp32s3/rom/cache.h" #include "esp32s3/clk.h" @@ -50,6 +51,7 @@ #include "cache_utils.h" #include "esp_flash.h" #include "esp_attr.h" +#include "spi_flash_private.h" esp_rom_spiflash_result_t IRAM_ATTR spi_flash_write_encrypted_chip(size_t dest_addr, const void *src, size_t size); @@ -876,3 +878,16 @@ void spi_flash_dump_counters(void) // TODO esp32s2: Remove once ESP32-S2 & later chips has new SPI Flash API support esp_flash_t *esp_flash_default_chip = NULL; #endif + +void IRAM_ATTR spi_flash_set_rom_required_regs(void) +{ +#if CONFIG_ESPTOOLPY_OCT_FLASH + //Disable the variable dummy mode when doing timing tuning + CLEAR_PERI_REG_MASK(SPI_MEM_DDR_REG(1), SPI_MEM_SPI_FMEM_VAR_DUMMY); + /** + * STR /DTR mode setting is done every time when `esp_rom_opiflash_exec_cmd` is called + * + * Add any registers that are not set in ROM SPI flash functions here in the future + */ +#endif +} diff --git a/components/spi_flash/include/spi_flash_private.h b/components/spi_flash/include/spi_flash_private.h new file mode 100644 index 0000000000..f792faef65 --- /dev/null +++ b/components/spi_flash/include/spi_flash_private.h @@ -0,0 +1,67 @@ +/* + * SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + + +/** + * Currently the MSPI timing tuning related APIs are designed to be private. + * Because: + * 1. now we don't split SPI0 and SPI1, we don't have a component for SPI0, including PSRAM, Cache, etc.. + * 2. SPI0 and SPI1 are strongly coupling. + * + * In the future, we may consider creating a component for SPI0, and spi_flash component will only work on SPI1 (and it + * can rely on SPI0). Therefore, we can put these APIs there. + * + */ +#pragma once + +#if CONFIG_IDF_TARGET_ESP32 +#include "esp32/rom/spi_flash.h" +#elif CONFIG_IDF_TARGET_ESP32S2 +#include "esp32s2/rom/spi_flash.h" +#elif CONFIG_IDF_TARGET_ESP32C3 +#include "esp32c3/rom/spi_flash.h" +#elif CONFIG_IDF_TARGET_ESP32S3 +#include "esp32s3/rom/spi_flash.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Register ROM functions and init flash device registers to make use of octal flash + */ +esp_err_t esp_opiflash_init(void); + +/** + * @brief Make MSPI work under 20Mhz + */ +void spi_timing_enter_mspi_low_speed_mode(void); + +/** + * @brief Make MSPI work under the frequency as users set + */ +void spi_timing_enter_mspi_high_speed_mode(void); + +/** + * @brief Tune MSPI flash timing to make it work under high frequency + */ +void spi_timing_flash_tuning(void); + +/** + * @brief Tune MSPI psram timing to make it work under high frequency + */ +void spi_timing_psram_tuning(void); + +/** + * @brief Set SPI1 registers to make ROM functions work + * @note This function is used for setting SPI1 registers to the state that ROM SPI functions work + */ +void spi_flash_set_rom_required_regs(void); + +#ifdef __cplusplus +} +#endif diff --git a/components/spi_flash/linker.lf b/components/spi_flash/linker.lf index 800d2e1683..ae285a1c2c 100644 --- a/components/spi_flash/linker.lf +++ b/components/spi_flash/linker.lf @@ -10,4 +10,10 @@ entries: memspi_host_driver (noflash) if IDF_TARGET_ESP32 = n: - spi_flash_chip_boya (noflash) + spi_flash_chip_boya (noflash) + + if IDF_TARGET_ESP32S3 = y: + spi_flash_timing_tuning (noflash) + + if IDF_TARGET_ESP32S3 = y && ESPTOOLPY_OCT_FLASH = y: + spi_flash_oct_flash_init (noflash) diff --git a/components/spi_flash/spi_flash_timing_tuning.c b/components/spi_flash/spi_flash_timing_tuning.c new file mode 100644 index 0000000000..705da2c45c --- /dev/null +++ b/components/spi_flash/spi_flash_timing_tuning.c @@ -0,0 +1,348 @@ +/* + * SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "sdkconfig.h" +#include "esp_attr.h" +#include "esp_err.h" +#include "esp_types.h" +#include "esp_log.h" +#include "soc/spi_mem_reg.h" +#include "spi_flash_private.h" +#if CONFIG_IDF_TARGET_ESP32S3 +#include "esp32s3/spi_timing_config.h" +#endif + +static spi_timing_tuning_param_t s_flash_best_timing_tuning_config; +static spi_timing_tuning_param_t s_psram_best_timing_tuning_config; + +static spi_timing_config_core_clock_t get_mspi_core_clock(void) +{ + return spi_timing_config_get_core_clock(); +} + +static uint32_t get_flash_clock_divider(void) +{ +#if CONFIG_ESPTOOLPY_FLASHFREQ_20M + return SPI_TIMING_CORE_CLOCK_MHZ / 20; +#elif CONFIG_ESPTOOLPY_FLASHFREQ_40M + return SPI_TIMING_CORE_CLOCK_MHZ / 40; +#elif CONFIG_ESPTOOLPY_FLASHFREQ_80M + return SPI_TIMING_CORE_CLOCK_MHZ / 80; +#elif CONFIG_ESPTOOLPY_FLASHFREQ_120M + return SPI_TIMING_CORE_CLOCK_MHZ / 120; +#else + abort(); +#endif +} + +static uint32_t get_psram_clock_divider(void) +{ +#if CONFIG_SPIRAM_SPEED_40M + return SPI_TIMING_CORE_CLOCK_MHZ / 40; +#elif CONFIG_SPIRAM_SPEED_80M + return SPI_TIMING_CORE_CLOCK_MHZ / 80; +#else + //Will enter this branch only if PSRAM is not enable + return 0; +#endif +} + +#if SPI_TIMING_FLASH_NEEDS_TUNING || SPI_TIMING_PSRAM_NEEDS_TUNING +/** + * Set timing tuning regs, in order to get successful sample points + */ +static void init_spi1_for_tuning(bool is_flash) +{ + //Get required core clock and module clock settings + spi_timing_config_core_clock_t core_clock = get_mspi_core_clock(); + //Set SPI1 core clock. SPI0 and SPI1 share the register for core clock. So we only set SPI0 here. + spi_timing_config_set_core_clock(0, core_clock); + //Set SPI1 module clock as required + if (is_flash) { + uint32_t flash_div = get_flash_clock_divider(); + spi_timing_config_set_flash_clock(1, flash_div); + //Power on 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 + uint32_t psram_div = get_psram_clock_divider(); + spi_timing_config_set_flash_clock(1, psram_div); + //Power on HCLK + REG_SET_BIT(SPI_MEM_SPI_SMEM_TIMING_CALI_REG(0), SPI_MEM_SPI_SMEM_TIMING_CLK_ENA); + } +} + +/** + * We 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. + */ +static void sweep_for_success_sample_points(uint8_t *reference_data, const spi_timing_config_t *config, bool is_flash, uint8_t *out_array) +{ + uint32_t config_idx = 0; + uint8_t read_data[SPI_TIMING_TEST_DATA_LEN] = {0}; + + for (config_idx = 0; config_idx < config->available_config_num; config_idx++) { + memset(read_data, 0, SPI_TIMING_TEST_DATA_LEN); +#if SPI_TIMING_FLASH_NEEDS_TUNING + if (is_flash) { + /** + * 1. SPI_MEM_DINx_MODE(1), SPI_MEM_DINx_NUM(1) are meaningless + * SPI0 and SPI1 share the SPI_MEM_DINx_MODE(0), SPI_MEM_DINx_NUM(0) for FLASH timing tuning + * 2. We use SPI1 to get the best Flash timing tuning (mode and num) config + */ + spi_timing_config_flash_set_din_mode_num(0, config->tuning_config_table[config_idx].spi_din_mode, config->tuning_config_table[config_idx].spi_din_num); + spi_timing_config_flash_set_extra_dummy(1, config->tuning_config_table[config_idx].extra_dummy_len); + spi_timing_config_flash_read_data(1, read_data, SPI_TIMING_FLASH_TEST_DATA_ADDR, sizeof(read_data)); + } +#endif +#if SPI_TIMING_PSRAM_NEEDS_TUNING + if (!is_flash) { + /** + * 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 + */ + spi_timing_config_psram_set_din_mode_num(0, config->tuning_config_table[config_idx].spi_din_mode, config->tuning_config_table[config_idx].spi_din_num); + spi_timing_config_flash_set_extra_dummy(1, config->tuning_config_table[config_idx].extra_dummy_len); + spi_timing_config_psram_read_data(1, read_data, SPI_TIMING_PSRAM_TEST_DATA_ADDR, SPI_TIMING_TEST_DATA_LEN); + } +#endif + if (memcmp(reference_data, read_data, sizeof(read_data)) == 0) { + out_array[config_idx] = 1; + } + } +} + +/** + * Find consecutive successful sampling points. + * e.g. array: {1, 1, 0, 0, 1, 1, 1, 0} + * out_length: 3 + * outout_end_index: 6 + */ +static void 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; +} + +static void select_best_tuning_config(spi_timing_config_t *config, uint32_t length, uint32_t end, bool is_flash) +{ + uint32_t best_point; + if (length >= 3) { + best_point = end - length / 2; + } else { + best_point = config->default_config_id; + } + + if (is_flash) { + s_flash_best_timing_tuning_config = config->tuning_config_table[best_point]; + } else { + s_psram_best_timing_tuning_config = config->tuning_config_table[best_point]; + } +} + +static void do_tuning(uint8_t *reference_data, spi_timing_config_t *timing_config, bool is_flash) +{ + /** + * We use SPI1 to tune the FLASH timing: + * 1. Get all SPI1 sampling results. + * 2. Find the longest consecutive successful sampling points from the result above. + * 3. The middle one will be the best sampling point. + */ + uint32_t consecutive_length = 0; + uint32_t last_success_point = 0; + uint8_t sample_result[SPI_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, SPI_TIMING_CONFIG_NUM_DEFAULT, &consecutive_length, &last_success_point); + select_best_tuning_config(timing_config, consecutive_length, last_success_point, is_flash); +} +#endif //#if SPI_TIMING_FLASH_NEEDS_TUNING || SPI_TIMING_PSRAM_NEEDS_TUNING + + +//------------------------------------------FLASH Timing Tuning----------------------------------------// +#if SPI_TIMING_FLASH_NEEDS_TUNING +static void get_flash_tuning_configs(spi_timing_config_t *config) +{ +#if SPI_TIMING_FLASH_DTR_MODE +#define FLASH_MODE DTR_MODE +#else //SPI_TIMING_FLASH_STR_MODE +#define FLASH_MODE STR_MODE +#endif + +#if CONFIG_ESPTOOLPY_FLASHFREQ_20M + *config = SPI_TIMING_FLASH_GET_TUNING_CONFIG(SPI_TIMING_CORE_CLOCK_MHZ, 20, FLASH_MODE); +#elif CONFIG_ESPTOOLPY_FLASHFREQ_40M + *config = SPI_TIMING_FLASH_GET_TUNING_CONFIG(SPI_TIMING_CORE_CLOCK_MHZ, 40, FLASH_MODE); +#elif CONFIG_ESPTOOLPY_FLASHFREQ_80M + *config = SPI_TIMING_FLASH_GET_TUNING_CONFIG(SPI_TIMING_CORE_CLOCK_MHZ, 80, FLASH_MODE); +#elif CONFIG_ESPTOOLPY_FLASHFREQ_120M + *config = SPI_TIMING_FLASH_GET_TUNING_CONFIG(SPI_TIMING_CORE_CLOCK_MHZ, 120, FLASH_MODE); +#endif + +#undef FLASH_MODE +} + +void spi_timing_flash_tuning(void) +{ + /** + * set SPI01 related regs to 20mhz configuration, to get reference data from FLASH + * see detailed comments in this function (`spi_timing_enter_mspi_low_speed_mode) + */ + spi_timing_enter_mspi_low_speed_mode(); + + //Disable the variable dummy mode when doing timing tuning + CLEAR_PERI_REG_MASK(SPI_MEM_DDR_REG(1), SPI_MEM_SPI_FMEM_VAR_DUMMY); //GD flash will read error in variable mode with 20MHz + + uint8_t reference_data[SPI_TIMING_TEST_DATA_LEN] = {0}; + spi_timing_config_flash_read_data(1, reference_data, SPI_TIMING_FLASH_TEST_DATA_ADDR, sizeof(reference_data)); + spi_timing_config_t timing_configs = {0}; + get_flash_tuning_configs(&timing_configs); + + do_tuning(reference_data, &timing_configs, true); + spi_timing_enter_mspi_high_speed_mode(); +} +#else +void spi_timing_flash_tuning(void) +{ + //Empty function for compatibility, therefore upper layer won't need to know that FLASH in which operation mode and frequency config needs to be tuned +} +#endif //SPI_TIMING_FLASH_NEEDS_TUNING + + +//------------------------------------------PSRAM Timing Tuning----------------------------------------// +#if SPI_TIMING_PSRAM_NEEDS_TUNING +static void get_psram_tuning_configs(spi_timing_config_t *config) +{ +#if SPI_TIMING_PSRAM_DTR_MODE +#define PSRAM_MODE DTR_MODE +#else //SPI_TIMING_PSRAM_STR_MODE +#define PSRAM_MODE STR_MODE +#endif + +#if CONFIG_SPIRAM_SPEED_40M + *config = SPI_TIMING_PSRAM_GET_TUNING_CONFIG(SPI_TIMING_CORE_CLOCK_MHZ, 40, PSRAM_MODE); +#elif CONFIG_SPIRAM_SPEED_80M + *config = SPI_TIMING_PSRAM_GET_TUNING_CONFIG(SPI_TIMING_CORE_CLOCK_MHZ, 80, PSRAM_MODE); +#endif + +#undef PSRAM_MODE +} + +void spi_timing_psram_tuning(void) +{ + /** + * set SPI01 related regs to 20mhz configuration, to write reference data to PSRAM + * see detailed comments in this function (`spi_timing_enter_mspi_low_speed_mode) + */ + spi_timing_enter_mspi_low_speed_mode(); + + // write data into psram, used to do timing tuning test. + uint8_t reference_data[SPI_TIMING_TEST_DATA_LEN]; + for (int i=0; i < SPI_TIMING_TEST_DATA_LEN/4; i++) { + ((uint32_t *)reference_data)[i] = 0xa5ff005a; + } + spi_timing_config_psram_write_data(1, reference_data, SPI_TIMING_PSRAM_TEST_DATA_ADDR, SPI_TIMING_TEST_DATA_LEN); + spi_timing_config_t timing_configs = {0}; + get_psram_tuning_configs(&timing_configs); + + //Disable the variable dummy mode when doing timing tuning + CLEAR_PERI_REG_MASK(SPI_MEM_DDR_REG(1), SPI_MEM_SPI_FMEM_VAR_DUMMY); + //Get required config, and set them to PSRAM related registers + do_tuning(reference_data, &timing_configs, false); + spi_timing_enter_mspi_high_speed_mode(); +} + +#else +void spi_timing_psram_tuning(void) +{ + //Empty function for compatibility, therefore upper layer won't need to know that FLASH in which operation mode and frequency config needs to be tuned +} +#endif //SPI_TIMING_PSRAM_NEEDS_TUNING + + +//---------------------------------------------APIs to make SPI0 and SPI1 FLASH work for high/low freq-------------------------------// +static void clear_timing_tuning_regs(void) +{ + spi_timing_config_flash_set_din_mode_num(0, 0, 0); //SPI0 and SPI1 share the registers for flash din mode and num setting, so we only set SPI0's reg + spi_timing_config_flash_set_extra_dummy(0, 0); + spi_timing_config_flash_set_extra_dummy(1, 0); +} + +void spi_timing_enter_mspi_low_speed_mode(void) +{ + /** + * Here we are going to slow the SPI1 frequency to 20Mhz, so we need to set SPI1 din_num and din_mode regs. + * + * Because SPI0 and SPI1 share the din_num and din_mode regs, so if we clear SPI1 din_num and din_mode to + * 0, if the SPI0 flash module clock is still in high freq, it may not work correctly. + * + * Therefore, here we need to slow both the SPI0 and SPI1 and related timing tuning regs to 20Mhz configuration. + */ + + //Switch SPI1 and SPI0 clock as 20MHz, set its SPIMEM core clock as 80M and set clock division as 4 + spi_timing_config_set_core_clock(0, SPI_TIMING_CONFIG_CORE_CLOCK_80M); //SPI0 and SPI1 share the register for core clock. So we only set SPI0 here. + spi_timing_config_set_flash_clock(1, 4); + spi_timing_config_set_flash_clock(0, 4); + + clear_timing_tuning_regs(); +} + +static void set_timing_tuning_regs_as_required(void) +{ + //SPI0 and SPI1 share the registers for flash din mode and num setting, so we only set SPI0's reg + spi_timing_config_flash_set_din_mode_num(0, s_flash_best_timing_tuning_config.spi_din_mode, s_flash_best_timing_tuning_config.spi_din_num); + spi_timing_config_flash_set_extra_dummy(0, s_flash_best_timing_tuning_config.extra_dummy_len); + spi_timing_config_flash_set_extra_dummy(1, s_flash_best_timing_tuning_config.extra_dummy_len); + + spi_timing_config_psram_set_din_mode_num(0, s_psram_best_timing_tuning_config.spi_din_mode, s_psram_best_timing_tuning_config.spi_din_num); + spi_timing_config_psram_set_extra_dummy(0, s_psram_best_timing_tuning_config.extra_dummy_len); +} + +/** + * Set SPI0 and SPI1 flash module clock, din_num, din_mode and extra dummy, + * according to the configuration got from timing tuning function (`calculate_best_flash_tuning_config`). + * + * This function should always be called after `spi_timing_flash_tuning` or `calculate_best_flash_tuning_config` + */ +void spi_timing_enter_mspi_high_speed_mode(void) +{ + spi_timing_config_core_clock_t core_clock = get_mspi_core_clock(); + uint32_t flash_div = get_flash_clock_divider(); + uint32_t psram_div = get_psram_clock_divider(); + + //Set SPI01 core clock + spi_timing_config_set_core_clock(0, core_clock); //SPI0 and SPI1 share the register for core clock. So we only set SPI0 here. + //Set FLASH module clock + spi_timing_config_set_flash_clock(0, flash_div); + spi_timing_config_set_flash_clock(1, flash_div); + //Set PSRAM module clock + spi_timing_config_set_psram_clock(0, psram_div); + + set_timing_tuning_regs_as_required(); +} diff --git a/tools/ci/check_public_headers_exceptions.txt b/tools/ci/check_public_headers_exceptions.txt index 77254f60bd..b98e6f1f77 100644 --- a/tools/ci/check_public_headers_exceptions.txt +++ b/tools/ci/check_public_headers_exceptions.txt @@ -148,3 +148,4 @@ components/ulp/include/esp32s2/ulp_riscv.h components/lwip/include/apps/sntp/sntp.h components/mbedtls/esp_crt_bundle/include/esp_crt_bundle.h components/wifi_provisioning/include/wifi_provisioning/scheme_softap.h +components/spi_flash/include/spi_flash_private.h