Procházet zdrojové kódy

psram: support psram for esp32s3

chenjianqiang před 5 roky
rodič
revize
f19cabb7e4

+ 2 - 0
components/esp32s3/CMakeLists.txt

@@ -22,6 +22,8 @@ else()
              "pm_esp32s3.c"
              "pm_esp32s3.c"
              "pm_trace.c"
              "pm_trace.c"
              "sleep_modes.c"
              "sleep_modes.c"
+             "spiram.c"
+             "spiram_psram.c"
              "system_api_esp32s3.c")
              "system_api_esp32s3.c")
     set(include_dirs "include")
     set(include_dirs "include")
 
 

+ 10 - 22
components/esp32s3/Kconfig

@@ -171,16 +171,25 @@ menu "ESP32S3-Specific"
 
 
         choice SPIRAM_TYPE
         choice SPIRAM_TYPE
             prompt "Type of SPI RAM chip in use"
             prompt "Type of SPI RAM chip in use"
-            default SPIRAM_TYPE_ESPPSRAM32
+            default SPIRAM_TYPE_AUTO
+
+            config SPIRAM_TYPE_AUTO
+                bool "Auto-detect"
+
+            config SPIRAM_TYPE_ESPPSRAM16
+                bool "ESP-PSRAM16 or APS1604"
 
 
             config SPIRAM_TYPE_ESPPSRAM32
             config SPIRAM_TYPE_ESPPSRAM32
                 bool "ESP-PSRAM32 or IS25WP032"
                 bool "ESP-PSRAM32 or IS25WP032"
+
             config SPIRAM_TYPE_ESPPSRAM64
             config SPIRAM_TYPE_ESPPSRAM64
                 bool "ESP-PSRAM64 or LY68L6400"
                 bool "ESP-PSRAM64 or LY68L6400"
         endchoice
         endchoice
 
 
         config SPIRAM_SIZE
         config SPIRAM_SIZE
             int
             int
+            default -1 if SPIRAM_TYPE_AUTO
+            default 2097152 if SPIRAM_TYPE_ESPPSRAM16
             default 4194304 if SPIRAM_TYPE_ESPPSRAM32
             default 4194304 if SPIRAM_TYPE_ESPPSRAM32
             default 8388608 if SPIRAM_TYPE_ESPPSRAM64
             default 8388608 if SPIRAM_TYPE_ESPPSRAM64
             default 0
             default 0
@@ -201,22 +210,6 @@ menu "ESP32S3-Specific"
                 help
                 help
                     The PSRAM CS IO can be any unused GPIO, please refer to your hardware design.
                     The PSRAM CS IO can be any unused GPIO, please refer to your hardware design.
         endmenu
         endmenu
-
-        config SPIRAM_SPIWP_SD3_PIN
-            int "SPI PSRAM WP(SD3) Pin when customizing pins via eFuse (read help)"
-            depends on ESPTOOLPY_FLASHMODE_DIO || ESPTOOLPY_FLASHMODE_DOUT
-            range 0 33
-            default 28
-            help
-                This value is ignored unless flash mode is set to DIO or DOUT and the SPI flash pins have been
-                overridden by setting the eFuses SPI_PAD_CONFIG_xxx.
-
-                Different from esp32 chip, on esp32-s3, the WP pin would also be defined in efuse.
-                This value would only be used if the WP pin recorded in efuse SPI_PAD_CONFIG_xxx is invalid.
-
-                When flash mode is set to QIO or QOUT,
-                the PSRAM WP pin will be set as the value configured in bootloader.
-
         config SPIRAM_FETCH_INSTRUCTIONS
         config SPIRAM_FETCH_INSTRUCTIONS
             bool "Cache fetch instructions from SPI RAM"
             bool "Cache fetch instructions from SPI RAM"
             default n
             default n
@@ -237,11 +230,6 @@ menu "ESP32S3-Specific"
             default SPIRAM_SPEED_40M
             default SPIRAM_SPEED_40M
             help
             help
                 Select the speed for the SPI RAM chip.
                 Select the speed for the SPI RAM chip.
-                If SPI RAM is enabled, we only support three combinations of SPI speed mode we supported now:
-
-                1. Flash SPI running at 40Mhz and RAM SPI running at 40Mhz
-                2. Flash SPI running at 80Mhz and RAM SPI running at 40Mhz
-                3. Flash SPI running at 80Mhz and RAM SPI running at 80Mhz
 
 
             config SPIRAM_SPEED_80M
             config SPIRAM_SPEED_80M
                 bool "80MHz clock speed"
                 bool "80MHz clock speed"

+ 323 - 0
components/esp32s3/spiram.c

@@ -0,0 +1,323 @@
+/*
+Abstraction layer for spi-ram. For now, it's no more than a stub for the spiram_psram functions, but if
+we add more types of external RAM memory, this can be made into a more intelligent dispatcher.
+*/
+
+// Copyright 2015-2017 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 <stdint.h>
+#include <string.h>
+#include <sys/param.h>
+#include "sdkconfig.h"
+#include "esp_attr.h"
+#include "esp_err.h"
+#include "esp32s3/spiram.h"
+#include "spiram_psram.h"
+#include "esp_log.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/xtensa_api.h"
+#include "soc/soc.h"
+#include "esp_heap_caps_init.h"
+#include "soc/soc_memory_layout.h"
+#include "soc/dport_reg.h"
+#include "esp32s3/rom/cache.h"
+#include "soc/cache_memory.h"
+#include "soc/extmem_reg.h"
+
+#define PSRAM_MODE PSRAM_VADDR_MODE_NORMAL
+
+#if CONFIG_SPIRAM
+
+static const char* TAG = "spiram";
+
+#if CONFIG_SPIRAM_SPEED_40M
+#define PSRAM_SPEED PSRAM_CACHE_S40M
+#elif CONFIG_SPIRAM_SPEED_80M
+#define PSRAM_SPEED PSRAM_CACHE_S80M
+#else
+#define PSRAM_SPEED PSRAM_CACHE_S20M
+#endif
+
+#define SPIRAM_SIZE  esp_spiram_get_size()
+
+static bool spiram_inited=false;
+
+
+/*
+ Simple RAM test. Writes a word every 32 bytes. Takes about a second to complete for 4MiB. Returns
+ true when RAM seems OK, false when test fails. WARNING: Do not run this before the 2nd cpu has been
+ initialized (in a two-core system) or after the heap allocator has taken ownership of the memory.
+*/
+bool esp_spiram_test(void)
+{
+    volatile int *spiram=(volatile int*)(SOC_EXTRAM_DATA_HIGH - SPIRAM_SIZE);
+    size_t p;
+    size_t s=SPIRAM_SIZE;
+    int errct=0;
+    int initial_err=-1;
+
+    if ((SOC_EXTRAM_DATA_HIGH - SOC_EXTRAM_DATA_LOW) < SPIRAM_SIZE) {
+        ESP_EARLY_LOGW(TAG, "Only test spiram from %08x to %08x\n", SOC_EXTRAM_DATA_LOW, SOC_EXTRAM_DATA_HIGH);
+        spiram=(volatile int*)SOC_EXTRAM_DATA_LOW;
+        s = SOC_EXTRAM_DATA_HIGH - SOC_EXTRAM_DATA_LOW;
+    }
+    for (p=0; p<(s/sizeof(int)); p+=8) {
+        spiram[p]=p^0xAAAAAAAA;
+    }
+    for (p=0; p<(s/sizeof(int)); p+=8) {
+        if (spiram[p]!=(p^0xAAAAAAAA)) {
+            errct++;
+            if (errct==1) initial_err=p*4;
+            if (errct < 4) {
+                ESP_EARLY_LOGE(TAG, "SPI SRAM error@%08x:%08x/%08x \n", &spiram[p], spiram[p], p^0xAAAAAAAA);
+            }
+        }
+    }
+    if (errct) {
+        ESP_EARLY_LOGE(TAG, "SPI SRAM memory test fail. %d/%d writes failed, first @ %X\n", errct, s/32, initial_err+SOC_EXTRAM_DATA_LOW);
+        return false;
+    } else {
+        ESP_EARLY_LOGI(TAG, "SPI SRAM memory test OK");
+        return true;
+    }
+}
+
+void IRAM_ATTR esp_spiram_init_cache(void)
+{
+    Cache_Suspend_DCache();
+    if ((SOC_EXTRAM_DATA_HIGH - SOC_EXTRAM_DATA_LOW) >= SPIRAM_SIZE) {
+        Cache_Dbus_MMU_Set(MMU_ACCESS_SPIRAM, SOC_EXTRAM_DATA_HIGH - SPIRAM_SIZE, 0, 64, SPIRAM_SIZE >> 16, 0);
+    } else {
+        Cache_Dbus_MMU_Set(MMU_ACCESS_SPIRAM, SOC_EXTRAM_DATA_HIGH - SPIRAM_SIZE, 0, 64, (SOC_EXTRAM_DATA_HIGH - SOC_EXTRAM_DATA_LOW) >> 16, 0);
+    }
+    REG_CLR_BIT(EXTMEM_DCACHE_CTRL1_REG, EXTMEM_DCACHE_SHUT_CORE0_BUS);
+#if !CONFIG_FREERTOS_UNICORE
+    REG_CLR_BIT(EXTMEM_DCACHE_CTRL1_REG, EXTMEM_DCACHE_SHUT_CORE1_BUS);
+#endif
+    Cache_Resume_DCache(0);
+}
+
+static uint32_t pages_for_flash = 0;
+static uint32_t page0_mapped = 0;
+static uint32_t page0_page = INVALID_PHY_PAGE;
+static uint32_t instrcution_in_spiram = 0;
+static uint32_t rodata_in_spiram = 0;
+
+#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS
+static int instr_flash2spiram_offs = 0;
+static uint32_t instr_start_page = 0;
+static uint32_t instr_end_page = 0;
+#endif
+
+#if CONFIG_SPIRAM_RODATA
+static int rodata_flash2spiram_offs = 0;
+static uint32_t rodata_start_page = 0;
+static uint32_t rodata_end_page = 0;
+#endif
+
+uint32_t esp_spiram_instruction_access_enabled(void)
+{
+    return instrcution_in_spiram;
+}
+
+uint32_t esp_spiram_rodata_access_enabled(void)
+{
+    return rodata_in_spiram;
+}
+
+#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS
+esp_err_t esp_spiram_enable_instruction_access(void)
+{
+    uint32_t pages_in_flash = 0;
+    pages_in_flash += Cache_Count_Flash_Pages(PRO_CACHE_IBUS0, &page0_mapped);
+    pages_in_flash += Cache_Count_Flash_Pages(PRO_CACHE_IBUS1, &page0_mapped);
+    if ((pages_in_flash + pages_for_flash) > (SPIRAM_SIZE >> 16)) {
+        ESP_EARLY_LOGE(TAG, "SPI RAM space not enough for the instructions, has %d pages, need %d pages.", (SPIRAM_SIZE >> 16), (pages_in_flash + pages_for_flash));
+        return ESP_FAIL;
+    }
+    ESP_EARLY_LOGI(TAG, "Instructions copied and mapped to SPIRAM");
+    uint32_t instr_mmu_offset = ((uint32_t)&_instruction_reserved_start & 0xFFFFFF)/MMU_PAGE_SIZE;
+    uint32_t mmu_value = *(volatile uint32_t *)(DR_REG_MMU_TABLE + PRO_CACHE_IBUS0_MMU_START + instr_mmu_offset*sizeof(uint32_t));
+    mmu_value &= MMU_ADDRESS_MASK;
+    instr_flash2spiram_offs = mmu_value - pages_for_flash;
+    ESP_EARLY_LOGV(TAG, "Instructions from flash page%d copy to SPIRAM page%d, Offset: %d", mmu_value, pages_for_flash, instr_flash2spiram_offs);
+    pages_for_flash = Cache_Flash_To_SPIRAM_Copy(PRO_CACHE_IBUS0, IRAM0_ADDRESS_LOW, pages_for_flash, &page0_page);
+    pages_for_flash = Cache_Flash_To_SPIRAM_Copy(PRO_CACHE_IBUS1, IRAM1_ADDRESS_LOW, pages_for_flash, &page0_page);
+    instrcution_in_spiram = 1;
+    return ESP_OK;
+}
+#endif
+
+#if CONFIG_SPIRAM_RODATA
+esp_err_t esp_spiram_enable_rodata_access(void)
+{
+    uint32_t pages_in_flash = 0;
+    pages_in_flash += Cache_Count_Flash_Pages(PRO_CACHE_IBUS2, &page0_mapped);
+    pages_in_flash += Cache_Count_Flash_Pages(PRO_CACHE_DBUS0, &page0_mapped);
+    pages_in_flash += Cache_Count_Flash_Pages(PRO_CACHE_DBUS1, &page0_mapped);
+    pages_in_flash += Cache_Count_Flash_Pages(PRO_CACHE_DBUS2, &page0_mapped);
+
+    if ((pages_in_flash + pages_for_flash) > (SPIRAM_SIZE >> 16)) {
+        ESP_EARLY_LOGE(TAG, "SPI RAM space not enough for the read only data.");
+        return ESP_FAIL;
+    }
+
+    ESP_EARLY_LOGI(TAG, "Read only data copied and mapped to SPIRAM");
+    uint32_t rodata_mmu_offset = ((uint32_t)&_rodata_reserved_start & 0xFFFFFF)/MMU_PAGE_SIZE;
+    uint32_t mmu_value = *(volatile uint32_t *)(DR_REG_MMU_TABLE + PRO_CACHE_IBUS2_MMU_START + rodata_mmu_offset*sizeof(uint32_t));
+    mmu_value &= MMU_ADDRESS_MASK;
+    rodata_flash2spiram_offs = mmu_value - pages_for_flash;
+    ESP_EARLY_LOGV(TAG, "Rodata from flash page%d copy to SPIRAM page%d, Offset: %d", mmu_value, pages_for_flash, rodata_flash2spiram_offs);
+    pages_for_flash = Cache_Flash_To_SPIRAM_Copy(PRO_CACHE_IBUS2, DROM0_ADDRESS_LOW, pages_for_flash, &page0_page);
+    pages_for_flash = Cache_Flash_To_SPIRAM_Copy(PRO_CACHE_DBUS0, DRAM0_ADDRESS_LOW, pages_for_flash, &page0_page);
+    pages_for_flash = Cache_Flash_To_SPIRAM_Copy(PRO_CACHE_DBUS1, DRAM1_ADDRESS_LOW, pages_for_flash, &page0_page);
+    pages_for_flash = Cache_Flash_To_SPIRAM_Copy(PRO_CACHE_DBUS2, DPORT_ADDRESS_LOW, pages_for_flash, &page0_page);
+    rodata_in_spiram = 1;
+    return ESP_OK;
+}
+#endif
+
+#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS
+void instruction_flash_page_info_init(void)
+{
+    uint32_t instr_page_cnt = ((uint32_t)&_instruction_reserved_end - SOC_IROM_LOW + MMU_PAGE_SIZE - 1)/MMU_PAGE_SIZE;
+    uint32_t instr_mmu_offset = ((uint32_t)&_instruction_reserved_start & 0xFFFFFF)/MMU_PAGE_SIZE;
+
+    instr_start_page = *(volatile uint32_t *)(DR_REG_MMU_TABLE + PRO_CACHE_IBUS0_MMU_START + instr_mmu_offset*sizeof(uint32_t));
+    instr_start_page &= MMU_ADDRESS_MASK;
+    instr_end_page = instr_start_page + instr_page_cnt - 1;
+}
+
+uint32_t IRAM_ATTR instruction_flash_start_page_get(void)
+{
+    return instr_start_page;
+}
+
+uint32_t IRAM_ATTR instruction_flash_end_page_get(void)
+{
+    return instr_end_page;
+}
+
+int IRAM_ATTR instruction_flash2spiram_offset(void)
+{
+    return instr_flash2spiram_offs;
+}
+#endif
+
+#if CONFIG_SPIRAM_RODATA
+void rodata_flash_page_info_init(void)
+{
+    uint32_t rodata_page_cnt = ((uint32_t)&_rodata_reserved_end - SOC_DROM_LOW + MMU_PAGE_SIZE - 1)/MMU_PAGE_SIZE;
+    uint32_t rodata_mmu_offset = ((uint32_t)&_rodata_reserved_start & 0xFFFFFF)/MMU_PAGE_SIZE;
+
+    rodata_start_page = *(volatile uint32_t *)(DR_REG_MMU_TABLE + PRO_CACHE_IBUS2_MMU_START + rodata_mmu_offset*sizeof(uint32_t));
+    rodata_start_page &= MMU_ADDRESS_MASK;
+    rodata_end_page = rodata_start_page + rodata_page_cnt - 1;
+}
+
+uint32_t IRAM_ATTR rodata_flash_start_page_get(void)
+{
+    return rodata_start_page;
+}
+
+uint32_t IRAM_ATTR rodata_flash_end_page_get(void)
+{
+    return rodata_end_page;
+}
+
+int IRAM_ATTR rodata_flash2spiram_offset(void)
+{
+    return rodata_flash2spiram_offs;
+}
+#endif
+
+esp_err_t esp_spiram_init(void)
+{
+    esp_err_t r;
+    r = psram_enable(PSRAM_SPEED, PSRAM_MODE);
+    if (r != ESP_OK) {
+#if CONFIG_SPIRAM_IGNORE_NOTFOUND
+        ESP_EARLY_LOGE(TAG, "SPI RAM enabled but initialization failed. Bailing out.");
+#endif
+        return r;
+    }
+
+    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);
+        return ESP_ERR_INVALID_SIZE;
+    }
+#endif
+
+    ESP_EARLY_LOGI(TAG, "Found %dMBit SPI RAM device",
+                                          (esp_spiram_get_size()*8)/(1024*1024));
+    ESP_EARLY_LOGI(TAG, "SPI RAM mode: %s", PSRAM_SPEED == PSRAM_CACHE_S40M ? "sram 40m" : \
+                                          PSRAM_SPEED == PSRAM_CACHE_S80M ? "sram 80m" : "sram 20m");
+    ESP_EARLY_LOGI(TAG, "PSRAM initialized, cache is in %s mode.", \
+                                          (PSRAM_MODE==PSRAM_VADDR_MODE_EVENODD)?"even/odd (2-core)": \
+                                          (PSRAM_MODE==PSRAM_VADDR_MODE_LOWHIGH)?"low/high (2-core)": \
+                                          (PSRAM_MODE==PSRAM_VADDR_MODE_NORMAL)?"normal (1-core)":"ERROR");
+    return ESP_OK;
+}
+
+
+esp_err_t esp_spiram_add_to_heapalloc(void)
+{
+    uint32_t size_for_flash = (pages_for_flash << 16);
+    ESP_EARLY_LOGI(TAG, "Adding pool of %dK of external SPI memory to heap allocator", (SPIRAM_SIZE - (pages_for_flash << 16))/1024);
+    //Add entire external RAM region to heap allocator. Heap allocator knows the capabilities of this type of memory, so there's
+    //no need to explicitly specify them.
+
+    return heap_caps_add_region((intptr_t)SOC_EXTRAM_DATA_HIGH - SPIRAM_SIZE + size_for_flash, (intptr_t)SOC_EXTRAM_DATA_HIGH -1);
+}
+
+
+static uint8_t *dma_heap;
+
+esp_err_t esp_spiram_reserve_dma_pool(size_t size) {
+    if (size==0) return ESP_OK; //no-op
+    ESP_EARLY_LOGI(TAG, "Reserving pool of %dK of internal memory for DMA/internal allocations", size/1024);
+    dma_heap=heap_caps_malloc(size, MALLOC_CAP_DMA|MALLOC_CAP_INTERNAL);
+    if (!dma_heap) return ESP_ERR_NO_MEM;
+    uint32_t caps[]={MALLOC_CAP_DMA|MALLOC_CAP_INTERNAL, 0, MALLOC_CAP_8BIT|MALLOC_CAP_32BIT};
+    return heap_caps_add_region_with_caps(caps, (intptr_t) dma_heap, (intptr_t) dma_heap+size-1);
+}
+
+size_t esp_spiram_get_size(void)
+{
+    if (!spiram_inited) {
+        ESP_EARLY_LOGE(TAG, "SPI RAM not initialized");
+        abort();
+    }
+
+    psram_size_t size=psram_get_size();
+    if (size==PSRAM_SIZE_16MBITS) return 2*1024*1024;
+    if (size==PSRAM_SIZE_32MBITS) return 4*1024*1024;
+    if (size==PSRAM_SIZE_64MBITS) return 8*1024*1024;
+    return SPIRAM_SIZE;
+}
+
+/*
+ Before flushing the cache, if psram is enabled as a memory-mapped thing, we need to write back the data in the cache to the psram first,
+ otherwise it will get lost. For now, we just read 64/128K of random PSRAM memory to do this.
+*/
+void IRAM_ATTR esp_spiram_writeback_cache(void)
+{
+    extern void Cache_WriteBack_All(void);
+    Cache_WriteBack_All();
+}
+
+#endif

+ 541 - 0
components/esp32s3/spiram_psram.c

@@ -0,0 +1,541 @@
+/*
+ Driver bits for PSRAM chips (at the moment only the ESP-PSRAM32 chip).
+*/
+
+// Copyright 2013-2017 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 "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/spi_flash.h"
+#include "esp32s3/rom/opi_flash.h"
+#include "esp32s3/rom/cache.h"
+#include "esp32s3/rom/efuse.h"
+#include "esp_rom_gpio.h"
+#include "esp_rom_efuse.h"
+#include "soc/dport_reg.h"
+#include "soc/efuse_periph.h"
+#include "soc/spi_caps.h"
+#include "soc/io_mux_reg.h"
+#include "soc/apb_ctrl_reg.h"
+#include "soc/efuse_reg.h"
+#include "soc/soc.h"
+#include "soc/io_mux_reg.h"
+#include "driver/gpio.h"
+#include "driver/spi_common_internal.h"
+#include "driver/spi_common.h"
+#include "driver/periph_ctrl.h"
+#include "bootloader_common.h"
+
+#if CONFIG_SPIRAM
+#include "soc/rtc.h"
+
+static const char* TAG = "psram";
+
+//Commands for PSRAM chip
+#define PSRAM_READ                 0x03
+#define PSRAM_FAST_READ            0x0B
+#define PSRAM_FAST_READ_DUMMY      0x3
+#define PSRAM_FAST_READ_QUAD       0xEB
+#define PSRAM_FAST_READ_QUAD_DUMMY 0x5
+#define PSRAM_WRITE                0x02
+#define PSRAM_QUAD_WRITE           0x38
+#define PSRAM_ENTER_QMODE          0x35
+#define PSRAM_EXIT_QMODE           0xF5
+#define PSRAM_RESET_EN             0x66
+#define PSRAM_RESET                0x99
+#define PSRAM_SET_BURST_LEN        0xC0
+#define PSRAM_DEVICE_ID            0x9F
+// ID 
+#define PSRAM_ID_KGD_M          0xff
+#define PSRAM_ID_KGD_S             8
+#define PSRAM_ID_KGD            0x5d
+#define PSRAM_ID_EID_M          0xff
+#define PSRAM_ID_EID_S            16
+
+// Use the [7:5](bit7~bit5) of EID to distinguish the psram size:
+//
+//   BIT7  |  BIT6  |  BIT5  |  SIZE(MBIT)
+//   -------------------------------------
+//    0    |   0    |   0    |     16
+//    0    |   0    |   1    |     32
+//    0    |   1    |   0    |     64
+#define PSRAM_EID_SIZE_M         0x07
+#define PSRAM_EID_SIZE_S            5
+
+#define PSRAM_KGD(id)         (((id) >> PSRAM_ID_KGD_S) & PSRAM_ID_KGD_M)
+#define PSRAM_EID(id)         (((id) >> PSRAM_ID_EID_S) & PSRAM_ID_EID_M)
+#define PSRAM_SIZE_ID(id)     ((PSRAM_EID(id) >> PSRAM_EID_SIZE_S) & PSRAM_EID_SIZE_M)
+#define PSRAM_IS_VALID(id)    (PSRAM_KGD(id) == PSRAM_ID_KGD)
+
+// For the old version 32Mbit psram, using the spicial driver */
+#define PSRAM_IS_32MBIT_VER0(id)  (PSRAM_EID(id) == 0x20)
+#define PSRAM_IS_64MBIT_TRIAL(id) (PSRAM_EID(id) == 0x26)
+
+// IO-pins for PSRAM.
+// WARNING: PSRAM shares all but the CS and CLK pins with the flash, so these defines
+// hardcode the flash pins as well, making this code incompatible with either a setup
+// that has the flash on non-standard pins or ESP32s with built-in flash.
+#define FLASH_CLK_IO          SPI_CLK_GPIO_NUM
+#define FLASH_CS_IO           SPI_CS0_GPIO_NUM
+// PSRAM clock and cs IO should be configured based on hardware design.
+#define PSRAM_CLK_IO     CONFIG_DEFAULT_PSRAM_CLK_IO  // Default value is 30
+#define PSRAM_CS_IO      CONFIG_DEFAULT_PSRAM_CS_IO   // Default value is 26
+#define PSRAM_SPIQ_SD0_IO     SPI_Q_GPIO_NUM
+#define PSRAM_SPID_SD1_IO     SPI_D_GPIO_NUM
+#define PSRAM_SPIWP_SD3_IO    SPI_WP_GPIO_NUM
+#define PSRAM_SPIHD_SD2_IO    SPI_HD_GPIO_NUM
+
+#define CS_PSRAM_SEL   SPI_MEM_CS1_DIS_M
+#define CS_FLASH_SEL   SPI_MEM_CS0_DIS_M
+
+#define PSRAM_IO_MATRIX_DUMMY_20M   0
+#define PSRAM_IO_MATRIX_DUMMY_40M   0
+#define PSRAM_IO_MATRIX_DUMMY_80M   0
+#define _SPI_CACHE_PORT             0
+#define _SPI_FLASH_PORT             1
+#define _SPI_80M_CLK_DIV            1
+#define _SPI_40M_CLK_DIV            2
+#define _SPI_20M_CLK_DIV            4
+
+typedef enum {
+    PSRAM_CLK_MODE_NORM = 0,  /*!< Normal SPI mode */
+    PSRAM_CLK_MODE_A1C,       /*!< ONE extra clock cycles after CS is set high level */
+    PSRAM_CLK_MODE_A2C,       /*!< Two extra clock cycles after CS is set high level */
+    PSRAM_CLK_MODE_ALON,      /*!< clock always on */
+    PSRAM_CLK_MODE_MAX,
+} psram_clk_mode_t;
+
+
+typedef enum {
+    PSRAM_EID_SIZE_16MBITS = 0,
+    PSRAM_EID_SIZE_32MBITS = 1,
+    PSRAM_EID_SIZE_64MBITS = 2,
+} psram_eid_size_t;
+
+typedef struct {
+    uint8_t flash_clk_io;
+    uint8_t flash_cs_io;
+    uint8_t psram_clk_io;
+    uint8_t psram_cs_io;
+    uint8_t psram_spiq_sd0_io;
+    uint8_t psram_spid_sd1_io;
+    uint8_t psram_spiwp_sd3_io;
+    uint8_t psram_spihd_sd2_io;
+} psram_io_t;
+
+#define PSRAM_IO_CONF_DEFAULT() {             \
+    .flash_clk_io       = FLASH_CLK_IO,       \
+    .flash_cs_io        = FLASH_CS_IO,        \
+    .psram_clk_io       = PSRAM_CLK_IO,       \
+    .psram_cs_io        = PSRAM_CS_IO,        \
+    .psram_spiq_sd0_io  = PSRAM_SPIQ_SD0_IO,  \
+    .psram_spid_sd1_io  = PSRAM_SPID_SD1_IO,  \
+    .psram_spiwp_sd3_io = PSRAM_SPIWP_SD3_IO, \
+    .psram_spihd_sd2_io = PSRAM_SPIHD_SD2_IO,  \
+}
+
+typedef enum {
+    PSRAM_SPI_1  = 0x1,
+    /* PSRAM_SPI_2, */
+    /* PSRAM_SPI_3, */
+    PSRAM_SPI_MAX ,
+} psram_spi_num_t;
+
+typedef enum {
+    PSRAM_CMD_QPI,
+    PSRAM_CMD_SPI,
+} psram_cmd_mode_t;
+
+typedef esp_rom_spi_cmd_t psram_cmd_t;
+
+static uint32_t s_psram_id = 0;
+static void IRAM_ATTR psram_cache_init(psram_cache_mode_t psram_cache_mode, psram_vaddr_mode_t vaddrmode);
+extern void esp_rom_spi_set_op_mode(int spi_num, esp_rom_spiflash_read_mode_t mode);
+
+static void psram_set_op_mode(int spi_num, psram_cmd_mode_t mode)
+{
+    if (mode == PSRAM_CMD_QPI) {
+        esp_rom_spi_set_op_mode(spi_num, ESP_ROM_SPIFLASH_QIO_MODE);
+        SET_PERI_REG_MASK(SPI_MEM_CTRL_REG(spi_num), SPI_MEM_FCMD_QUAD_M);
+    } else if (mode == PSRAM_CMD_SPI) {
+        esp_rom_spi_set_op_mode(spi_num, ESP_ROM_SPIFLASH_SLOWRD_MODE);
+    }
+}
+static void _psram_exec_cmd(int spi_num,
+    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)
+{
+    esp_rom_spi_cmd_t conf;
+    uint32_t _addr = addr;
+    conf.addr = &_addr;
+    conf.addrBitLen = addr_bit_len;
+    conf.cmd = cmd;
+    conf.cmdBitLen = cmd_bit_len;
+    conf.dummyBitLen = dummy_bits; // There is a hardware approach on chip723
+    conf.txData = (uint32_t*) mosi_data;
+    conf.txDataBitLen = mosi_bit_len;
+    conf.rxData = (uint32_t*) miso_data;
+    conf.rxDataBitLen = miso_bit_len;
+    esp_rom_spi_cmd_config(spi_num, &conf);
+}
+
+void psram_exec_cmd(int spi_num, psram_cmd_mode_t mode,
+    uint32_t cmd, int cmd_bit_len,
+    uint32_t addr, int addr_bit_len,
+    int dummy_bits,
+    uint8_t* mosi_data, int mosi_bit_len,
+    uint8_t* miso_data, int miso_bit_len,
+    uint32_t cs_mask,
+    bool is_write_erase_operation)
+{
+    uint32_t backup_usr = READ_PERI_REG(SPI_MEM_USER_REG(spi_num));
+    uint32_t backup_usr1 = READ_PERI_REG(SPI_MEM_USER1_REG(spi_num));
+    uint32_t backup_usr2 = READ_PERI_REG(SPI_MEM_USER2_REG(spi_num));
+    uint32_t backup_ctrl = READ_PERI_REG(SPI_MEM_CTRL_REG(spi_num));
+    psram_set_op_mode(spi_num, mode);
+    _psram_exec_cmd(spi_num, cmd, cmd_bit_len, addr, addr_bit_len,
+        dummy_bits, mosi_data, mosi_bit_len, miso_data, miso_bit_len);
+    esp_rom_spi_cmd_start(spi_num, miso_data, miso_bit_len / 8, cs_mask, is_write_erase_operation);
+    
+    WRITE_PERI_REG(SPI_MEM_USER_REG(spi_num), backup_usr);
+    WRITE_PERI_REG(SPI_MEM_USER1_REG(spi_num), backup_usr1);
+    WRITE_PERI_REG(SPI_MEM_USER2_REG(spi_num), backup_usr2);
+    WRITE_PERI_REG(SPI_MEM_CTRL_REG(spi_num), backup_ctrl);
+}
+
+//exit QPI mode(set back to SPI mode)
+static void psram_disable_qio_mode(int spi_num)
+{
+    psram_exec_cmd(spi_num, PSRAM_CMD_QPI,
+    PSRAM_EXIT_QMODE, 8,              /* command and command bit len*/
+    0, 0,  /* address and address bit len*/
+    0,                                /* dummy bit len */
+    NULL, 0,                          /* tx data and tx bit len*/
+    NULL, 0,                          /* rx data and rx bit len*/
+    CS_PSRAM_SEL,                     /* cs bit mask*/
+    false);                           /* whether is program/erase operation */
+}
+
+//switch psram burst length(32 bytes or 1024 bytes)
+//datasheet says it should be 1024 bytes by default
+static void psram_set_wrap_burst_length(int spi_num, psram_cmd_mode_t mode)
+{
+    psram_exec_cmd(spi_num, mode,
+    PSRAM_SET_BURST_LEN, 8,           /* command and command bit len*/
+    0, 0,  /* address and address bit len*/
+    0,                                /* dummy bit len */
+    NULL, 0,                          /* tx data and tx bit len*/
+    NULL, 0,                          /* rx data and rx bit len*/
+    CS_PSRAM_SEL,                     /* cs bit mask*/
+    false);                           /* whether is program/erase operation */
+}
+
+//send reset command to psram, in spi mode
+static void psram_reset_mode(int spi_num)
+{
+    psram_exec_cmd(spi_num, PSRAM_CMD_SPI,
+    PSRAM_RESET_EN, 8,                /* command and command bit len*/
+    0, 0,  /* address and address bit len*/
+    0,                                /* dummy bit len */
+    NULL, 0,                          /* tx data and tx bit len*/
+    NULL, 0,                          /* rx data and rx bit len*/
+    CS_PSRAM_SEL,                     /* cs bit mask*/
+    false);                           /* whether is program/erase operation */
+
+    psram_exec_cmd(spi_num, PSRAM_CMD_SPI,
+    PSRAM_RESET, 8,                   /* command and command bit len*/
+    0, 0,  /* address and address bit len*/
+    0,                                /* dummy bit len */
+    NULL, 0,                          /* tx data and tx bit len*/
+    NULL, 0,                          /* rx data and rx bit len*/
+    CS_PSRAM_SEL,                     /* cs bit mask*/
+    false);                           /* whether is program/erase operation */
+}
+
+esp_err_t psram_enable_wrap(uint32_t wrap_size)
+{
+    static int current_wrap_size = 0;
+    if (current_wrap_size == wrap_size) {
+        return ESP_OK;
+    }
+    switch (wrap_size) {
+        case 32:
+        case 0:
+            psram_set_wrap_burst_length(PSRAM_SPI_1, PSRAM_CMD_QPI);
+            current_wrap_size = wrap_size;
+            return ESP_OK;
+        case 16:
+        case 64:
+        default:
+            return ESP_FAIL;
+    }
+}
+
+bool psram_support_wrap_size(uint32_t wrap_size)
+{
+    switch (wrap_size) {
+        case 0:
+        case 32:
+            return true;
+        case 16:
+        case 64:
+        default:
+            return false;
+    }
+
+}
+
+//read psram id, should issue `psram_disable_qio_mode` before calling this
+static void psram_read_id(int spi_num, uint32_t* dev_id)
+{
+    psram_exec_cmd(spi_num, PSRAM_CMD_SPI,
+    PSRAM_DEVICE_ID, 8,               /* command and command bit len*/
+    0, 24,                            /* address and address bit len*/
+    0,                                /* dummy bit len */
+    NULL, 0,                          /* tx data and tx bit len*/
+    (uint8_t*) dev_id, 24,            /* rx data and rx bit len*/
+    CS_PSRAM_SEL,                     /* cs bit mask*/
+    false);                           /* whether is program/erase operation */
+}
+
+//enter QPI mode
+static void IRAM_ATTR psram_enable_qio_mode(int spi_num)
+{
+    psram_exec_cmd(spi_num, PSRAM_CMD_SPI,
+    PSRAM_ENTER_QMODE, 8,             /* command and command bit len*/
+    0, 0,  /* address and address bit len*/
+    0,                                /* dummy bit len */
+    NULL, 0,                          /* tx data and tx bit len*/
+    NULL, 0,                          /* rx data and rx bit len*/
+    CS_PSRAM_SEL,                     /* cs bit mask*/
+    false);                           /* whether is program/erase operation */
+}
+
+static void psram_set_spi1_cmd_cs_timing(psram_clk_mode_t clk_mode)
+{
+    if (clk_mode == PSRAM_CLK_MODE_NORM) {
+        // SPI1 Flash Operation port
+        SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(_SPI_FLASH_PORT), SPI_MEM_CS_HOLD_TIME_V, 1, SPI_MEM_CS_HOLD_TIME_S);
+        SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(_SPI_FLASH_PORT), SPI_MEM_CS_SETUP_TIME_V, 0, SPI_MEM_CS_SETUP_TIME_S);
+        SET_PERI_REG_MASK(SPI_MEM_USER_REG(_SPI_FLASH_PORT), SPI_MEM_CS_HOLD_M | SPI_MEM_CS_SETUP_M);
+    } else {
+        SET_PERI_REG_MASK(SPI_MEM_USER_REG(_SPI_FLASH_PORT), SPI_MEM_CS_HOLD_M | SPI_MEM_CS_SETUP_M);
+    }
+}
+
+static void psram_set_spi0_cache_cs_timing(psram_clk_mode_t clk_mode)
+{
+    if (clk_mode == PSRAM_CLK_MODE_NORM) {
+        // SPI0 SRAM Cache port
+        SET_PERI_REG_BITS(SPI_MEM_SPI_SMEM_AC_REG(_SPI_CACHE_PORT), SPI_MEM_SPI_SMEM_CS_HOLD_TIME_V, 1, SPI_MEM_SPI_SMEM_CS_HOLD_TIME_S);
+        SET_PERI_REG_BITS(SPI_MEM_SPI_SMEM_AC_REG(_SPI_CACHE_PORT), SPI_MEM_SPI_SMEM_CS_SETUP_TIME_V, 0, SPI_MEM_SPI_SMEM_CS_SETUP_TIME_S);
+        SET_PERI_REG_MASK(SPI_MEM_SPI_SMEM_AC_REG(_SPI_CACHE_PORT), SPI_MEM_SPI_SMEM_CS_HOLD_M | SPI_MEM_SPI_SMEM_CS_SETUP_M);
+        // SPI0 Flash Cache port
+        SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(_SPI_CACHE_PORT), SPI_MEM_CS_HOLD_TIME_V, 0, SPI_MEM_CS_HOLD_TIME_S);
+        SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(_SPI_CACHE_PORT), SPI_MEM_CS_SETUP_TIME_V, 0, SPI_MEM_CS_SETUP_TIME_S);
+        SET_PERI_REG_MASK(SPI_MEM_USER_REG(_SPI_CACHE_PORT), SPI_MEM_CS_HOLD_M | SPI_MEM_CS_SETUP_M);
+    } else {
+        CLEAR_PERI_REG_MASK(SPI_MEM_USER_REG(_SPI_CACHE_PORT), SPI_CS_HOLD_M | SPI_CS_SETUP_M);
+    }
+}
+
+//psram gpio init , different working frequency we have different solutions
+static void IRAM_ATTR psram_gpio_config(psram_cache_mode_t mode)
+{
+    psram_io_t psram_io = PSRAM_IO_CONF_DEFAULT();
+    const uint32_t spiconfig = esp_rom_efuse_get_flash_gpio_info();
+    if (spiconfig == ESP_ROM_EFUSE_FLASH_DEFAULT_SPI) {
+        /* FLASH pins(except wp / hd) are all configured via IO_MUX in rom. */
+    } else {
+        // FLASH pins are all configured via GPIO matrix in ROM.
+        psram_io.flash_clk_io       = EFUSE_SPICONFIG_RET_SPICLK(spiconfig);
+        psram_io.flash_cs_io        = EFUSE_SPICONFIG_RET_SPICS0(spiconfig);
+        psram_io.psram_spiq_sd0_io  = EFUSE_SPICONFIG_RET_SPIQ(spiconfig);
+        psram_io.psram_spid_sd1_io  = EFUSE_SPICONFIG_RET_SPID(spiconfig);
+        psram_io.psram_spihd_sd2_io = EFUSE_SPICONFIG_RET_SPIHD(spiconfig);
+        psram_io.psram_spiwp_sd3_io = esp_rom_efuse_get_flash_wp_gpio();
+    }
+    esp_rom_spiflash_select_qio_pins(psram_io.psram_spiwp_sd3_io, spiconfig);
+
+    if (psram_io.psram_cs_io == SPI_CS1_GPIO_NUM) {
+        PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[psram_io.psram_cs_io],  FUNC_SPICS1_SPICS1);
+    } else {
+        esp_rom_gpio_connect_out_signal(psram_io.psram_cs_io, SPICS1_OUT_IDX, 0, 0);
+        PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[psram_io.psram_cs_io],  PIN_FUNC_GPIO);
+    }
+}
+
+psram_size_t psram_get_size(void)
+{
+    if ((PSRAM_SIZE_ID(s_psram_id) == PSRAM_EID_SIZE_64MBITS) || PSRAM_IS_64MBIT_TRIAL(s_psram_id)) {
+        return PSRAM_SIZE_64MBITS;
+    } else if (PSRAM_SIZE_ID(s_psram_id) == PSRAM_EID_SIZE_32MBITS) {
+        return PSRAM_SIZE_32MBITS;
+    } else if (PSRAM_SIZE_ID(s_psram_id) == PSRAM_EID_SIZE_16MBITS) {
+        return PSRAM_SIZE_16MBITS;
+    } else {
+        return PSRAM_SIZE_MAX;
+    }
+    return PSRAM_SIZE_MAX;
+}
+
+//used in UT only
+bool psram_is_32mbit_ver0(void)
+{
+    return PSRAM_IS_32MBIT_VER0(s_psram_id);
+}
+
+static void psram_set_clk_mode(int spi_num, psram_clk_mode_t clk_mode)
+{
+    if (spi_num == _SPI_CACHE_PORT) {
+        REG_SET_FIELD(SPI_MEM_SRAM_CMD_REG(0), SPI_MEM_SCLK_MODE, clk_mode);
+    } else if (spi_num == _SPI_FLASH_PORT) {
+        REG_SET_FIELD(SPI_MEM_CTRL1_REG(1), SPI_MEM_CLK_MODE, clk_mode);
+    }
+}
+
+/*
+ * Psram mode init will overwrite original flash speed mode, so that it is possible to change psram and flash speed after OTA.
+ * Flash read mode(QIO/QOUT/DIO/DOUT) will not be changed in app bin. It is decided by bootloader, OTA can not change this mode.
+ */
+esp_err_t IRAM_ATTR psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vaddrmode)   //psram init
+{
+    assert(mode < PSRAM_CACHE_MAX && "we don't support any other mode for now.");
+    // GPIO related settings
+    psram_gpio_config(mode);
+
+    /* SPI1: set spi1 clk mode, in order to send commands on SPI1 */
+    /* SPI1: set cs timing(hold time) in order to send commands on SPI1 */
+    psram_set_clk_mode(_SPI_FLASH_PORT, PSRAM_CLK_MODE_A1C);
+    psram_set_spi1_cmd_cs_timing(PSRAM_CLK_MODE_A1C);
+
+    int spi_num = PSRAM_SPI_1;
+    psram_disable_qio_mode(spi_num);
+    psram_read_id(spi_num, &s_psram_id);
+    if (!PSRAM_IS_VALID(s_psram_id)) {
+        /* 16Mbit psram ID read error workaround:
+         * treat the first read id as a dummy one as the pre-condition,
+         * Send Read ID command again
+         */
+        psram_read_id(spi_num, &s_psram_id);
+        if (!PSRAM_IS_VALID(s_psram_id)) {
+            ESP_EARLY_LOGE(TAG, "PSRAM ID read error: 0x%08x", s_psram_id);
+            return ESP_FAIL;
+        }
+    }
+
+    psram_clk_mode_t clk_mode = PSRAM_CLK_MODE_MAX;
+    if (psram_is_32mbit_ver0()) {
+        clk_mode = PSRAM_CLK_MODE_A1C;
+        // SPI1: keep clock mode and cs timing for spi1
+    } else {
+        // For other psram, we don't need any extra clock cycles after cs get back to high level
+        clk_mode = PSRAM_CLK_MODE_NORM;
+        // SPI1: set clock mode and cs timing to normal mode
+        psram_set_clk_mode(_SPI_FLASH_PORT, PSRAM_CLK_MODE_NORM);
+        psram_set_spi1_cmd_cs_timing(PSRAM_CLK_MODE_NORM);
+    }
+
+    /* SPI1: send psram reset command */
+    /* SPI1: send QPI enable command  */
+	psram_reset_mode(PSRAM_SPI_1);
+    psram_enable_qio_mode(PSRAM_SPI_1);
+
+    // after sending commands, set spi1 clock mode and cs timing to normal mode.
+    // since all the operations are sent via SPI0 Cache
+    /* SPI1: set clock mode to normal mode. */
+    /* SPI1: set cs timing to normal        */
+    psram_set_clk_mode(_SPI_FLASH_PORT, PSRAM_CLK_MODE_NORM);
+    psram_set_spi1_cmd_cs_timing(PSRAM_CLK_MODE_NORM);
+
+    /* SPI0: set spi0 clock mode             */
+    /* SPI0: set spi0 flash/cache cs timing  */
+    psram_set_clk_mode(_SPI_CACHE_PORT, clk_mode);
+    psram_set_spi0_cache_cs_timing(clk_mode);
+
+    // SPI0: init SPI commands for Cache
+    psram_cache_init(mode, vaddrmode);
+
+    return ESP_OK;
+}
+
+static void IRAM_ATTR psram_clock_set(int spi_num, int8_t freqdiv)
+{
+    uint32_t  freqbits;
+    if (1 >= freqdiv) {
+        WRITE_PERI_REG(SPI_MEM_SRAM_CLK_REG(spi_num), SPI_MEM_SCLK_EQU_SYSCLK);
+    } else {
+        freqbits = (((freqdiv-1)<<SPI_MEM_SCLKCNT_N_S)) | (((freqdiv/2-1)<<SPI_MEM_SCLKCNT_H_S)) | ((freqdiv-1)<<SPI_MEM_SCLKCNT_L_S);
+        WRITE_PERI_REG(SPI_MEM_SRAM_CLK_REG(spi_num), freqbits);
+    }
+}
+
+//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)
+{
+    int extra_dummy = 0;
+    switch (psram_cache_mode) {
+        case PSRAM_CACHE_S80M:
+            psram_clock_set(0, 1);
+            extra_dummy = PSRAM_IO_MATRIX_DUMMY_80M;
+            break;
+        case PSRAM_CACHE_S40M:
+            psram_clock_set(0, 2);
+            extra_dummy = PSRAM_IO_MATRIX_DUMMY_40M;
+            break;
+        case PSRAM_CACHE_S26M:
+            psram_clock_set(0, 3);
+            extra_dummy = PSRAM_IO_MATRIX_DUMMY_20M;
+            break;
+        case PSRAM_CACHE_S20M:
+            psram_clock_set(0, 4);
+            extra_dummy = PSRAM_IO_MATRIX_DUMMY_20M;
+            break;
+        default:
+            psram_clock_set(0, 2);
+            break;
+    }
+
+    CLEAR_PERI_REG_MASK(SPI_MEM_CACHE_SCTRL_REG(0), SPI_MEM_USR_SRAM_DIO_M);       //disable dio mode for cache command
+    SET_PERI_REG_MASK(SPI_MEM_CACHE_SCTRL_REG(0), SPI_MEM_USR_SRAM_QIO_M);         //enable qio mode for cache command
+    SET_PERI_REG_MASK(SPI_MEM_CACHE_SCTRL_REG(0), SPI_MEM_CACHE_SRAM_USR_RCMD_M);  //enable cache read command
+    SET_PERI_REG_MASK(SPI_MEM_CACHE_SCTRL_REG(0), SPI_MEM_CACHE_SRAM_USR_WCMD_M);  //enable cache write command
+    SET_PERI_REG_BITS(SPI_MEM_CACHE_SCTRL_REG(0), SPI_MEM_SRAM_ADDR_BITLEN_V, 23, SPI_MEM_SRAM_ADDR_BITLEN_S); //write address for cache command.
+    SET_PERI_REG_MASK(SPI_MEM_CACHE_SCTRL_REG(0), SPI_MEM_USR_RD_SRAM_DUMMY_M);    //enable cache read dummy
+
+    //config sram cache r/w command
+    SET_PERI_REG_BITS(SPI_MEM_SRAM_DWR_CMD_REG(0), SPI_MEM_CACHE_SRAM_USR_WR_CMD_BITLEN, 7,
+            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, PSRAM_QUAD_WRITE,
+            SPI_MEM_CACHE_SRAM_USR_WR_CMD_VALUE_S); //0x38
+    SET_PERI_REG_BITS(SPI_MEM_SRAM_DRD_CMD_REG(0), SPI_MEM_CACHE_SRAM_USR_RD_CMD_BITLEN_V, 7,
+            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, PSRAM_FAST_READ_QUAD,
+            SPI_MEM_CACHE_SRAM_USR_RD_CMD_VALUE_S); //0x0b
+    SET_PERI_REG_BITS(SPI_MEM_CACHE_SCTRL_REG(0), SPI_MEM_SRAM_RDUMMY_CYCLELEN_V, PSRAM_FAST_READ_QUAD_DUMMY + extra_dummy,
+            SPI_MEM_SRAM_RDUMMY_CYCLELEN_S); //dummy, psram cache :  40m--+1dummy,80m--+2dummy
+
+    CLEAR_PERI_REG_MASK(SPI_MEM_MISC_REG(0), SPI_MEM_CS1_DIS_M); //ENABLE SPI0 CS1 TO PSRAM(CS0--FLASH; CS1--SRAM)
+}
+#endif // CONFIG_SPIRAM

+ 80 - 0
components/esp32s3/spiram_psram.h

@@ -0,0 +1,80 @@
+// Copyright 2015-2016 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.
+
+
+#ifndef _PSRAM_H
+#define _PSRAM_H
+#include "soc/spi_mem_reg.h"
+#include "esp_err.h"
+#include "sdkconfig.h"
+
+typedef enum {
+    PSRAM_CACHE_S80M = 1,
+    PSRAM_CACHE_S40M,
+    PSRAM_CACHE_S26M,
+    PSRAM_CACHE_S20M,
+    PSRAM_CACHE_MAX,
+} psram_cache_mode_t;
+
+typedef enum {
+    PSRAM_SIZE_16MBITS = 0,
+    PSRAM_SIZE_32MBITS = 1,
+    PSRAM_SIZE_64MBITS = 2,
+    PSRAM_SIZE_MAX,
+} psram_size_t;
+
+/*
+See the TRM, chapter PID/MPU/MMU, header 'External RAM' for the definitions of these modes.
+
+Important is that NORMAL works with the app CPU cache disabled, but gives huge cache coherency
+issues when both app and pro CPU are enabled. LOWHIGH and EVENODD do not have these coherency
+issues but cannot be used when the app CPU cache is disabled.
+*/
+typedef enum {
+    PSRAM_VADDR_MODE_NORMAL=0, ///< App and pro CPU use their own flash cache for external RAM access
+    PSRAM_VADDR_MODE_LOWHIGH,  ///< App and pro CPU share external RAM caches: pro CPU has low 2M, app CPU has high 2M
+    PSRAM_VADDR_MODE_EVENODD,  ///< App and pro CPU share external RAM caches: pro CPU does even 32yte ranges, app does odd ones.
+} psram_vaddr_mode_t;
+
+/**
+ * @brief get psram size
+ * @return
+ *     - PSRAM_SIZE_MAX if psram not enabled or not valid
+ *     - PSRAM size
+ */
+psram_size_t psram_get_size(void);
+
+/**
+ * @brief psram cache enable function
+ *
+ * Esp-idf uses this to initialize cache for psram, mapping it into the main memory
+ * address space.
+ *
+ * @param mode       SPI mode to access psram in
+ * @param vaddrmode  Mode the psram cache works in.
+ * @return ESP_OK on success, ESP_ERR_INVALID_STATE when VSPI peripheral is needed but cannot be claimed.
+ */
+esp_err_t psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vaddrmode);
+
+typedef enum {
+    SPIRAM_WRAP_MODE_16B,
+    SPIRAM_WRAP_MODE_32B,
+    SPIRAM_WRAP_MODE_64B,
+    SPIRAM_WRAP_MODE_DISABLE
+} spiram_wrap_mode_t;
+
+esp_err_t esp_spiram_wrap_set(spiram_wrap_mode_t mode);
+
+
+#endif

+ 299 - 0
components/esp_rom/include/esp32s3/rom/opi_flash.h

@@ -0,0 +1,299 @@
+/*
+ * copyright (c) Espressif System 2019
+ *
+ */
+
+#ifndef _ROM_OPI_FLASH_H_
+#define _ROM_OPI_FLASH_H_
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include "spi_flash.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+    uint16_t cmd;                /*!< Command value */
+    uint16_t cmdBitLen;          /*!< Command byte length*/
+    uint32_t *addr;              /*!< Point to address value*/
+    uint32_t addrBitLen;         /*!< Address byte length*/
+    uint32_t *txData;            /*!< Point to send data buffer*/
+    uint32_t txDataBitLen;       /*!< Send data byte length.*/
+    uint32_t *rxData;            /*!< Point to recevie data buffer*/
+    uint32_t rxDataBitLen;       /*!< Recevie Data byte length.*/
+    uint32_t dummyBitLen;
+} esp_rom_spi_cmd_t;
+
+#define ESP_ROM_OPIFLASH_MUX_TAKE()
+#define ESP_ROM_OPIFLASH_MUX_GIVE()
+#define ESP_ROM_OPIFLASH_SEL_CS0     (BIT(0))
+#define ESP_ROM_OPIFLASH_SEL_CS1     (BIT(1))
+
+// Definition of MX25UM25645G Octa Flash
+// SPI status register
+#define ESP_ROM_SPIFLASH_BUSY_FLAG     BIT0
+#define ESP_ROM_SPIFLASH_WRENABLE_FLAG BIT1
+#define ESP_ROM_SPIFLASH_BP0           BIT2
+#define ESP_ROM_SPIFLASH_BP1           BIT3
+#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 FLASH_OP_MODE_RDCMD_DOUT       0x3B
+#define ESP_ROM_FLASH_SECTOR_SIZE      0x1000
+#define ESP_ROM_FLASH_BLOCK_SIZE_64K   0x10000
+#define ESP_ROM_FLASH_PAGE_SIZE        256
+
+// FLASH commands
+#define ROM_FLASH_CMD_RDID             0x9F
+#define ROM_FLASH_CMD_WRSR             0x01
+#define ROM_FLASH_CMD_WRSR2            0x31 /* Not all SPI flash uses this command */
+#define ROM_FLASH_CMD_WREN             0x06
+#define ROM_FLASH_CMD_WRDI             0x04
+#define ROM_FLASH_CMD_RDSR             0x05
+#define ROM_FLASH_CMD_RDSR2            0x35 /* Not all SPI flash uses this command */
+#define ROM_FLASH_CMD_ERASE_SEC        0x20
+#define ROM_FLASH_CMD_ERASE_BLK_32K    0x52
+#define ROM_FLASH_CMD_ERASE_BLK_64K    0xD8
+#define ROM_FLASH_CMD_OTPEN            0x3A /* Enable OTP mode, not all SPI flash uses this command */
+#define ROM_FLASH_CMD_RSTEN            0x66
+#define ROM_FLASH_CMD_RST              0x99
+
+#define ROM_FLASH_CMD_SE4B             0x21
+#define ROM_FLASH_CMD_SE4B_OCT         0xDE21
+#define ROM_FLASH_CMD_BE4B             0xDC
+#define ROM_FLASH_CMD_BE4B_OCT         0x23DC
+#define ROM_FLASH_CMD_RSTEN_OCT        0x9966
+#define ROM_FLASH_CMD_RST_OCT          0x6699
+
+#define ROM_FLASH_CMD_FSTRD4B_STR      0x13EC
+#define ROM_FLASH_CMD_FSTRD4B_DTR      0x11EE
+#define ROM_FLASH_CMD_FSTRD4B          0x0C
+#define ROM_FLASH_CMD_PP4B             0x12
+#define ROM_FLASH_CMD_PP4B_OCT         0xED12
+
+#define ROM_FLASH_CMD_RDID_OCT         0x609F
+#define ROM_FLASH_CMD_WREN_OCT         0xF906
+#define ROM_FLASH_CMD_RDSR_OCT         0xFA05
+#define ROM_FLASH_CMD_RDCR2            0x71
+#define ROM_FLASH_CMD_RDCR2_OCT        0x8E71
+#define ROM_FLASH_CMD_WRCR2            0x72
+#define ROM_FLASH_CMD_WRCR2_OCT        0x8D72
+
+// Definitions for GigaDevice GD25LX256E Flash
+#define ROM_FLASH_CMD_RDFSR_GD            0x70
+#define ROM_FLASH_CMD_RD_GD               0x03
+#define ROM_FLASH_CMD_RD4B_GD             0x13
+#define ROM_FLASH_CMD_FSTRD_GD            0x0B
+#define ROM_FLASH_CMD_FSTRD4B_GD          0x0C
+#define ROM_FLASH_CMD_FSTRD_OOUT_GD       0x8B
+#define ROM_FLASH_CMD_FSTRD4B_OOUT_GD     0x7C
+#define ROM_FLASH_CMD_FSTRD_OIOSTR_GD     0xCB
+#define ROM_FLASH_CMD_FSTRD4B_OIOSTR_GD   0xCC
+#define ROM_FLASH_CMD_FSTRD4B_OIODTR_GD   0xFD
+
+#define ROM_FLASH_CMD_PP_GD               0x02
+#define ROM_FLASH_CMD_PP4B_GD             0x12
+#define ROM_FLASH_CMD_PP_OOUT_GD          0x82
+#define ROM_FLASH_CMD_PP4B_OOUT_GD        0x84
+#define ROM_FLASH_CMD_PP_OIO_GD           0xC2
+#define ROM_FLASH_CMD_PP4B_OIOSTR_GD      0x8E
+
+#define ROM_FLASH_CMD_SE_GD               0x20
+#define ROM_FLASH_CMD_SE4B_GD             0x21
+#define ROM_FLASH_CMD_BE32K_GD            0x52
+#define ROM_FLASH_CMD_BE32K4B_GD          0x5C
+#define ROM_FLASH_CMD_BE64K_GD            0xD8
+#define ROM_FLASH_CMD_BE64K4B_GD          0xDC
+
+#define ROM_FLASH_CMD_EN4B_GD             0xB7
+#define ROM_FLASH_CMD_DIS4B_GD            0xE9
+
+// spi user mode command config
+
+/**
+ * @brief Config the spi user command
+ * @param spi_num spi port
+ * @param pcmd pointer to accept the spi command struct
+ */
+void esp_rom_spi_cmd_config(int spi_num, esp_rom_spi_cmd_t* pcmd);
+
+/**
+ * @brief Start a spi user command sequence
+ * @param spi_num spi port
+ * @param rx_buf buffer pointer to receive data
+ * @param rx_len receive data length in byte
+ * @param cs_en_mask decide which cs to use, 0 for cs0, 1 for cs1
+ * @param is_write_erase to indicate whether this is a write or erase operation, since the CPU would check permission
+ */
+void esp_rom_spi_cmd_start(int spi_num, uint8_t* rx_buf, uint16_t rx_len, uint8_t cs_en_mask, bool is_write_erase);
+
+/**
+ * @brief Config opi flash pads according to efuse settings.
+ */
+void esp_rom_opiflash_pin_config(void);
+
+// set SPI read/write mode
+/**
+ * @brief Set SPI operation mode
+ * @param spi_num spi port
+ * @param mode Flash Read Mode
+ */
+void esp_rom_spi_set_op_mode(int spi_num, esp_rom_spiflash_read_mode_t mode);
+
+/**
+ * @brief Set data swap mode in DTR(DDR) mode
+ * @param spi_num spi port
+ * @param wr_swap to decide whether to swap fifo data in dtr write operation
+ * @param rd_swap to decide whether to swap fifo data in dtr read operation
+ */
+void esp_rom_spi_set_dtr_swap_mode(int spi, bool wr_swap, bool rd_swap);
+
+
+/**
+ * @brief to send reset command in spi/opi-str/opi-dtr mode(for MX25UM25645G)
+ * @param spi_num spi port
+ */
+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
+ * @param mode Flash Read Mode
+ * @param cmd data to send in command field
+ * @param cmd_bit_len bit length of command field
+ * @param addr data to send in address field
+ * @param addr_bit_len bit length of address field
+ * @param dummy_bits bit length of dummy field
+ * @param mosi_data data buffer to be sent in mosi field
+ * @param mosi_bit_len bit length of data buffer to be sent in mosi field
+ * @param miso_data data buffer to accept data in miso field
+ * @param miso_bit_len bit length of data buffer to accept data in miso field
+ * @param cs_mark decide which cs pin to use. 0: cs0, 1: cs1
+ * @param is_write_erase_operation to indicate whether this a write or erase flash operation
+ */
+void esp_rom_opiflash_exec_cmd(int spi_num, esp_rom_spiflash_read_mode_t mode,
+                                  uint32_t cmd, int cmd_bit_len,
+                                  uint32_t addr, int addr_bit_len,
+                                  int dummy_bits,
+                                  uint8_t* mosi_data, int mosi_bit_len,
+                                  uint8_t* miso_data, int miso_bit_len,
+                                  uint32_t cs_mask,
+                                  bool is_write_erase_operation);
+
+/**
+ * @brief send reset command to opi flash
+ * @param spi_num spi port
+ * @param mode Flash Operation 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
+ * @return opi flash status value
+ */
+uint8_t esp_rom_opiflash_rdsr(int spi_num, esp_rom_spiflash_read_mode_t mode);
+
+/**
+ * @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
+ * @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);
+
+/**
+ * @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
+ * @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);
+
+/**
+ * @brief to erase a flash area define by start address and length(for MX25UM25645G)
+ * @param spi_num spi port
+ * @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);
+
+/**
+ * @brief to read data from opi flash(for MX25UM25645G)
+ * @param spi_num spi port
+ * @param mode flash operation mode
+ * @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);
+
+/**
+ * @brief to write data to opi flash(for MX25UM25645G)
+ * @param spi_num spi port
+ * @param mode flash operation mode
+ * @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);
+
+/**
+ * @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
+ */
+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
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 3 - 0
components/esp_system/startup.c

@@ -64,6 +64,9 @@
 #elif CONFIG_IDF_TARGET_ESP32S2
 #elif CONFIG_IDF_TARGET_ESP32S2
 #include "esp32s2/spiram.h"
 #include "esp32s2/spiram.h"
 #include "esp32s2/brownout.h"
 #include "esp32s2/brownout.h"
+#elif CONFIG_IDF_TARGET_ESP32S3
+#include "esp32s3/spiram.h"
+#include "esp32s3/brownout.h"
 #endif
 #endif
 /***********************************************/
 /***********************************************/
 
 

+ 2 - 0
components/freertos/xtensa/port.c

@@ -127,6 +127,8 @@
 #include "esp32/spiram.h"
 #include "esp32/spiram.h"
 #elif CONFIG_IDF_TARGET_ESP32S2
 #elif CONFIG_IDF_TARGET_ESP32S2
 #include "esp32s2/spiram.h"
 #include "esp32s2/spiram.h"
+#elif CONFIG_IDF_TARGET_ESP32S3
+#include "esp32s3/spiram.h"
 #endif
 #endif
 
 
 #include "esp_private/startup_internal.h" // [refactor-todo] for g_spiram_ok
 #include "esp_private/startup_internal.h" // [refactor-todo] for g_spiram_ok

+ 1 - 0
components/soc/soc/esp32s3/include/soc/io_mux_reg.h

@@ -139,6 +139,7 @@
 #define U0RXD_GPIO_NUM 44
 #define U0RXD_GPIO_NUM 44
 #define U0TXD_GPIO_NUM 43
 #define U0TXD_GPIO_NUM 43
 
 
+#define SPI_CS1_GPIO_NUM 26
 #define SPI_HD_GPIO_NUM  27
 #define SPI_HD_GPIO_NUM  27
 #define SPI_WP_GPIO_NUM  28
 #define SPI_WP_GPIO_NUM  28
 #define SPI_CS0_GPIO_NUM 29
 #define SPI_CS0_GPIO_NUM 29