psram: support psram for esp32s3

pull/5682/merge
chenjianqiang 2020-08-10 19:33:00 +08:00 zatwierdzone przez morris
rodzic 6225932201
commit f19cabb7e4
9 zmienionych plików z 1261 dodań i 22 usunięć

Wyświetl plik

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

Wyświetl plik

@ -171,16 +171,25 @@ menu "ESP32S3-Specific"
choice SPIRAM_TYPE
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
bool "ESP-PSRAM32 or IS25WP032"
config SPIRAM_TYPE_ESPPSRAM64
bool "ESP-PSRAM64 or LY68L6400"
endchoice
config SPIRAM_SIZE
int
default -1 if SPIRAM_TYPE_AUTO
default 2097152 if SPIRAM_TYPE_ESPPSRAM16
default 4194304 if SPIRAM_TYPE_ESPPSRAM32
default 8388608 if SPIRAM_TYPE_ESPPSRAM64
default 0
@ -201,22 +210,6 @@ menu "ESP32S3-Specific"
help
The PSRAM CS IO can be any unused GPIO, please refer to your hardware design.
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
bool "Cache fetch instructions from SPI RAM"
default n
@ -237,11 +230,6 @@ menu "ESP32S3-Specific"
default SPIRAM_SPEED_40M
help
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
bool "80MHz clock speed"

Wyświetl plik

@ -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

Wyświetl plik

@ -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

Wyświetl plik

@ -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

Wyświetl plik

@ -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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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