esp_psram: new psram component

This commit is contained in:
Armando 2022-05-11 10:32:56 +08:00
parent 44f771c713
commit 38e5043ae8
79 changed files with 1396 additions and 2200 deletions

View File

@ -94,6 +94,7 @@
/components/esp_netif/ @esp-idf-codeowners/network
/components/esp_phy/ @esp-idf-codeowners/bluetooth @esp-idf-codeowners/wifi @esp-idf-codeowners/ieee802154
/components/esp_pm/ @esp-idf-codeowners/power-management @esp-idf-codeowners/bluetooth @esp-idf-codeowners/wifi
/components/esp_psram/ @esp-idf-codeowners/peripherals @esp-idf-codeowners/system
/components/esp_ringbuf/ @esp-idf-codeowners/system
/components/esp_rom/ @esp-idf-codeowners/system @esp-idf-codeowners/bluetooth @esp-idf-codeowners/wifi
/components/esp_serial_slave_link/ @esp-idf-codeowners/peripherals

View File

@ -1,3 +1,3 @@
idf_component_register(SRC_DIRS .
PRIV_REQUIRES cmock test_utils spi_flash
PRIV_REQUIRES cmock test_utils spi_flash esp_psram
)

View File

@ -11,7 +11,7 @@
#include "soc/soc.h"
#include "esp_system.h"
#if CONFIG_IDF_TARGET_ESP32
#include "spiram.h"
#include "esp_private/esp_psram_extram.h"
#endif
#include "test_utils.h"
@ -95,7 +95,7 @@ static void write_spiram_and_reset(void)
}
printf("Flushing cache\n");
// Flush the cache out to SPIRAM before resetting.
esp_spiram_writeback_cache();
esp_psram_extram_writeback_cache();
printf("Restarting\n");
// Reset to test that noinit memory is left intact.

View File

@ -43,26 +43,8 @@ idf_component_register(SRCS ${srcs}
idf_build_get_property(target IDF_TARGET)
add_subdirectory(port/${target})
if(CONFIG_IDF_TARGET_ESP32 AND CONFIG_SPIRAM_CACHE_WORKAROUND AND NOT BOOTLOADER_BUILD)
# Note: Adding as a PUBLIC compile option here causes this option to propagate to all
# components that depend on esp32.
#
# To handle some corner cases, the same flag is set in project_include.cmake
target_compile_options(${COMPONENT_LIB} PUBLIC -mfix-esp32-psram-cache-issue)
# also, make sure we link with this option so correct toolchain libs are pulled in
target_link_libraries(${COMPONENT_LIB} PUBLIC -mfix-esp32-psram-cache-issue)
# set strategy selected
# note that we don't need to set link options as the library linked is independent of this
if(CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_DUPLDST)
target_compile_options(${COMPONENT_LIB} PUBLIC -mfix-esp32-psram-cache-strategy=dupldst)
target_link_libraries(${COMPONENT_LIB} PUBLIC -mfix-esp32-psram-cache-strategy=dupldst)
endif()
if(CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_MEMW)
target_compile_options(${COMPONENT_LIB} PUBLIC -mfix-esp32-psram-cache-strategy=memw)
target_link_libraries(${COMPONENT_LIB} PUBLIC -mfix-esp32-psram-cache-strategy=memw)
endif()
if(CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_NOPS)
target_compile_options(${COMPONENT_LIB} PUBLIC -mfix-esp32-psram-cache-strategy=nops)
target_link_libraries(${COMPONENT_LIB} PUBLIC -mfix-esp32-psram-cache-strategy=nops)
if(NOT BOOTLOADER_BUILD)
if(CONFIG_SPIRAM)
idf_component_optional_requires(PRIVATE esp_psram)
endif()
endif()

View File

@ -12,7 +12,9 @@
#include "soc/soc_caps.h"
#include "esp_attr.h"
#include "esp_memory_utils.h"
#include "esp_private/spiram_private.h"
#if CONFIG_SPIRAM
#include "esp_private/esp_psram_extram.h"
#endif
bool esp_ptr_dma_ext_capable(const void *p)
@ -23,7 +25,7 @@ bool esp_ptr_dma_ext_capable(const void *p)
#if CONFIG_SPIRAM
intptr_t vaddr_start = 0;
intptr_t vaddr_end = 0;
esp_spiram_get_mapped_range(&vaddr_start, &vaddr_end);
esp_psram_extram_get_mapped_range(&vaddr_start, &vaddr_end);
return (intptr_t)p >= vaddr_start && (intptr_t)p < vaddr_end;
#else
return false;
@ -44,7 +46,7 @@ bool esp_ptr_byte_accessible(const void *p)
#if CONFIG_SPIRAM
intptr_t vaddr_start = 0;
intptr_t vaddr_end = 0;
esp_spiram_get_mapped_range(&vaddr_start, &vaddr_end);
esp_psram_extram_get_mapped_range(&vaddr_start, &vaddr_end);
r |= (ip >= vaddr_start && ip < vaddr_end);
#endif
return r;
@ -58,7 +60,7 @@ bool esp_ptr_external_ram(const void *p)
#if CONFIG_SPIRAM
intptr_t vaddr_start = 0;
intptr_t vaddr_end = 0;
esp_spiram_get_mapped_range(&vaddr_start, &vaddr_end);
esp_psram_extram_get_mapped_range(&vaddr_start, &vaddr_end);
return (intptr_t)p >= vaddr_start && (intptr_t)p < vaddr_end;
#else
return false;
@ -70,7 +72,7 @@ bool esp_stack_ptr_in_extram(uint32_t sp)
{
intptr_t vaddr_start = 0;
intptr_t vaddr_end = 0;
esp_spiram_get_mapped_range(&vaddr_start, &vaddr_end);
esp_psram_extram_get_mapped_range(&vaddr_start, &vaddr_end);
//Check if stack ptr is in between SOC_EXTRAM_DATA_LOW and SOC_EXTRAM_DATA_HIGH, and 16 byte aligned.
return !(sp < vaddr_start + 0x10 || sp > vaddr_end - 0x10 || ((sp & 0xF) != 0));
}

View File

@ -1,57 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stddef.h>
#include "esp_err.h"
#include "soc/soc_caps.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
ESP_SPIRAM_SIZE_16MBITS = 0, /*!< SPI RAM size is 16 MBits */
ESP_SPIRAM_SIZE_32MBITS = 1, /*!< SPI RAM size is 32 MBits */
ESP_SPIRAM_SIZE_64MBITS = 2, /*!< SPI RAM size is 64 MBits */
ESP_SPIRAM_SIZE_INVALID, /*!< SPI RAM size is invalid */
} esp_spiram_size_t;
/**
* @brief Get the size of the attached SPI RAM chip selected in menuconfig
*
* @return Size in bytes, or 0 if no external RAM chip support compiled in.
*/
size_t esp_spiram_get_size(void);
/**
* @brief Get the psram mapped vaddr range
*
* @param[out] out_vstart PSRAM virtual address start
* @param[out] out_vend PSRAM virtual address end
*
* @return
* - ESP_OK On success
* - ESP_ERR_INVALID_STATE PSRAM is not initialized successfully
*/
esp_err_t esp_spiram_get_mapped_range(intptr_t *out_vstart, intptr_t *out_vend);
/**
* @brief Get the psram alloced vaddr range
*
* @param[out] out_vstart PSRAM virtual address start
* @param[out] out_vend PSRAM virtual address end
*
* @return
* - ESP_OK On success
* - ESP_ERR_INVALID_STATE PSRAM is not initialized successfully
*/
esp_err_t esp_spiram_get_alloced_range(intptr_t *out_vstart, intptr_t *out_vend);
#ifdef __cplusplus
}
#endif

View File

@ -1,102 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __ESP_SPIRAM_H
#define __ESP_SPIRAM_H
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
//TODO: IDF-4382, unify `target/spiram.h`, update migration guide as well
/**
* @brief Initialize spiram interface/hardware. Normally called from cpu_start.c.
*
* @return ESP_OK on success
*/
esp_err_t esp_spiram_init(void);
/**
* @brief Configure Cache/MMU for access to external SPI RAM.
*
* Normally this function is called from cpu_start, if CONFIG_SPIRAM_BOOT_INIT
* option is enabled. Applications which need to enable SPI RAM at run time
* can disable CONFIG_SPIRAM_BOOT_INIT, and call this function later.
*
* @attention this function must be called with flash cache disabled.
*/
void esp_spiram_init_cache(void);
/**
* @brief Memory test for SPI RAM. Should be called after SPI RAM is initialized and
* (in case of a dual-core system) the app CPU is online. This test overwrites the
* memory with crap, so do not call after e.g. the heap allocator has stored important
* stuff in SPI RAM.
*
* @return true on success, false on failed memory test
*/
bool esp_spiram_test(void);
/**
* @brief Add the initialized SPI RAM to the heap allocator.
*/
esp_err_t esp_spiram_add_to_heapalloc(void);
/**
* @brief Force a writeback of the data in the SPI RAM cache. This is to be called whenever
* cache is disabled, because disabling cache on the ESP32 discards the data in the SPI
* RAM cache.
*
* This is meant for use from within the SPI flash code.
*/
void esp_spiram_writeback_cache(void);
/**
* @brief get psram CS IO
*
* This interface should be called after PSRAM is enabled, otherwise it will
* return an invalid value -1/0xff.
*
* @return psram CS IO or -1/0xff if psram not enabled
*/
uint8_t esp_spiram_get_cs_io(void);
/**
* @brief Reserve a pool of internal memory for specific DMA/internal allocations
*
* @param size Size of reserved pool in bytes
*
* @return
* - ESP_OK on success
* - ESP_ERR_NO_MEM when no memory available for pool
*/
esp_err_t esp_spiram_reserve_dma_pool(size_t size);
/**
* @brief If SPI RAM(PSRAM) has been initialized
*
* @return
* - true SPI RAM has been initialized successfully
* - false SPI RAM hasn't been initialized or initialized failed
*/
bool esp_spiram_is_initialized(void);
#ifdef __cplusplus
}
#endif
#endif // __ESP_SPIRAM_H

View File

@ -1,72 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <sys/param.h>
#include "esp_err.h"
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
esp_err_t mmu_map_psram(uint32_t start_paddr, uint32_t map_length, uint32_t *out_start_vaddr);
#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS
esp_err_t mmu_config_psram_text_segment(uint32_t start_page, uint32_t psram_size, uint32_t *out_page);
/**
* @brief Get the start page number of the instruction in SPI flash
*
* @return start page number
*/
uint32_t instruction_flash_start_page_get(void);
/**
* @brief Get the end page number of the instruction in SPI flash
*
* @return end page number
*/
uint32_t instruction_flash_end_page_get(void);
/**
* @brief Get the offset of instruction from SPI flash to SPI RAM
*
* @return instruction offset
*/
int instruction_flash2spiram_offset(void);
#endif
#if CONFIG_SPIRAM_RODATA
esp_err_t mmu_config_psram_rodata_segment(uint32_t start_page, uint32_t psram_size, uint32_t *out_page);
/**
* @brief Get the start page number of the rodata in SPI flash
*
* @return start page number
*/
uint32_t rodata_flash_start_page_get(void);
/**
* @brief Get the end page number of the rodata in SPI flash
*
* @return end page number
*/
uint32_t rodata_flash_end_page_get(void);
/**
* @brief Get the offset number of rodata from SPI flash to SPI RAM
*
* @return rodata offset
*/
int rodata_flash2spiram_offset(void);
#endif
#ifdef __cplusplus
}
#endif

View File

@ -1,75 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __ESP_SPIRAM_H
#define __ESP_SPIRAM_H
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Initialize spiram interface/hardware. Normally called from cpu_start.c.
*
* @return ESP_OK on success
*/
esp_err_t esp_spiram_init(void);
/**
* @brief Add the initialized SPI RAM to the heap allocator.
*/
esp_err_t esp_spiram_add_to_heapalloc(void);
/**
* @brief Force a writeback of the data in the SPI RAM cache. This is to be called whenever
* cache is disabled, because disabling cache on the ESP32 discards the data in the SPI
* RAM cache.
*
* This is meant for use from within the SPI flash code.
*/
void esp_spiram_writeback_cache(void);
/**
* @brief get psram CS IO
*
* This interface should be called after PSRAM is enabled, otherwise it will
* return an invalid value -1/0xff.
*
* @return psram CS IO or -1/0xff if psram not enabled
*/
uint8_t esp_spiram_get_cs_io(void);
/**
* @brief Reserve a pool of internal memory for specific DMA/internal allocations
*
* @param size Size of reserved pool in bytes
*
* @return
* - ESP_OK on success
* - ESP_ERR_NO_MEM when no memory available for pool
*/
esp_err_t esp_spiram_reserve_dma_pool(size_t size);
/**
* @brief If SPI RAM(PSRAM) has been initialized
*
* @return
* - true SPI RAM has been initialized successfully
* - false SPI RAM hasn't been initialized or initialized failed
*/
bool esp_spiram_is_initialized(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,71 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <sys/param.h>
#include "esp_err.h"
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS
esp_err_t mmu_config_psram_text_segment(uint32_t start_page, uint32_t psram_size, uint32_t *out_page);
/**
* @brief Get the start page number of the instruction in SPI flash
*
* @return start page number
*/
uint32_t instruction_flash_start_page_get(void);
/**
* @brief Get the end page number of the instruction in SPI flash
*
* @return end page number
*/
uint32_t instruction_flash_end_page_get(void);
/**
* @brief Get the offset of instruction from SPI flash to SPI RAM
*
* @return instruction offset
*/
int instruction_flash2spiram_offset(void);
#endif
#if CONFIG_SPIRAM_RODATA
esp_err_t mmu_config_psram_rodata_segment(uint32_t start_page, uint32_t psram_size, uint32_t *out_page);
/**
* @brief Get the start page number of the rodata in SPI flash
*
* @return start page number
*/
uint32_t rodata_flash_start_page_get(void);
/**
* @brief Get the end page number of the rodata in SPI flash
*
* @return end page number
*/
uint32_t rodata_flash_end_page_get(void);
/**
* @brief Get the offset number of rodata from SPI flash to SPI RAM
*
* @return rodata offset
*/
int rodata_flash2spiram_offset(void);
#endif
#ifdef __cplusplus
}
#endif

View File

@ -1,82 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Initialize spiram interface/hardware. Normally called from cpu_start.c.
*
* @return ESP_OK on success
*/
esp_err_t esp_spiram_init(void);
/**
* @brief Add the initialized SPI RAM to the heap allocator.
*/
esp_err_t esp_spiram_add_to_heapalloc(void);
/**
* @brief Force a writeback of the data in the SPI RAM cache. This is to be called whenever
* cache is disabled, because disabling cache on the ESP32 discards the data in the SPI
* RAM cache.
*
* This is meant for use from within the SPI flash code.
*/
void esp_spiram_writeback_cache(void);
/**
* @brief If SPI RAM(PSRAM) has been initialized
*
* @return
* - true SPI RAM has been initialized successfully
* - false SPI RAM hasn't been initialized or initialized failed
*/
bool esp_spiram_is_initialized(void);
/**
* @brief get psram CS IO
*
* This interface should be called after PSRAM is enabled, otherwise it will
* return an invalid value -1/0xff.
*
* @return psram CS IO or -1/0xff if psram not enabled
*/
uint8_t esp_spiram_get_cs_io(void);
/**
* @brief Reserve a pool of internal memory for specific DMA/internal allocations
*
* @param size Size of reserved pool in bytes
*
* @return
* - ESP_OK on success
* - ESP_ERR_NO_MEM when no memory available for pool
*/
esp_err_t esp_spiram_reserve_dma_pool(size_t size);
/**
* @brief If SPI RAM(PSRAM) has been initialized
*
* @return
* - true SPI RAM has been initialized successfully
* - false SPI RAM hasn't been initialized or initialized failed
*/
bool esp_spiram_is_initialized(void);
#ifdef __cplusplus
}
#endif

View File

@ -10,14 +10,6 @@ entries:
rtc_time (noflash_text)
if IDF_TARGET_ESP32 = y || IDF_TARGET_ESP32S2 = y:
rtc_wdt (noflash_text)
if IDF_TARGET_ESP32S3 = y:
if SPIRAM_MODE_QUAD = y:
spiram_psram (noflash)
if SPIRAM_MODE_OCT = y:
opiram_psram (noflash)
if SPIRAM:
if IDF_TARGET_ESP32S2 = y || IDF_TARGET_ESP32S3 = y:
mmu_psram (noflash)
if PERIPH_CTRL_FUNC_IN_IRAM = y:
periph_ctrl: periph_module_reset (noflash)
periph_ctrl: wifi_module_enable (noflash)

View File

@ -11,10 +11,7 @@ set(srcs
"chip_info.c")
if(NOT BOOTLOADER_BUILD)
list(APPEND srcs "cache_sram_mmu.c"
"esp_himem.c"
"spiram.c"
"spiram_psram.c")
list(APPEND srcs "cache_sram_mmu.c")
endif()
add_prefix(srcs "${CMAKE_CURRENT_LIST_DIR}/" "${srcs}")

View File

@ -1,360 +0,0 @@
/*
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.
*/
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <string.h>
#include <sys/param.h>
#include "sdkconfig.h"
#include "esp_attr.h"
#include "esp_err.h"
#include "esp32/spiram.h"
#include "esp_private/spiram_private.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 "esp_himem.h"
#include "esp32/rom/cache.h"
#if CONFIG_FREERTOS_UNICORE
#define PSRAM_MODE PSRAM_VADDR_MODE_NORMAL
#else
#define PSRAM_MODE PSRAM_VADDR_MODE_LOWHIGH
#endif
#if CONFIG_SPIRAM
static const char* TAG = "spiram";
#if CONFIG_SPIRAM_SPEED_40M && CONFIG_ESPTOOLPY_FLASHFREQ_40M
#define PSRAM_SPEED PSRAM_CACHE_F40M_S40M
#elif CONFIG_SPIRAM_SPEED_40M && CONFIG_ESPTOOLPY_FLASHFREQ_80M
#define PSRAM_SPEED PSRAM_CACHE_F80M_S40M
#elif CONFIG_SPIRAM_SPEED_80M && CONFIG_ESPTOOLPY_FLASHFREQ_80M
#define PSRAM_SPEED PSRAM_CACHE_F80M_S80M
#else
#error "FLASH speed can only be equal to or higher than SRAM speed while SRAM is enabled!"
#endif
#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
extern uint8_t _ext_ram_bss_start, _ext_ram_bss_end;
#endif
#if CONFIG_SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY
extern uint8_t _ext_ram_noinit_start, _ext_ram_noinit_end;
#endif
//These variables are in bytes
static intptr_t s_allocable_vaddr_start;
static intptr_t s_allocable_vaddr_end;
static intptr_t s_mapped_vaddr_start;
static intptr_t s_mapped_vaddr_end;
static bool spiram_inited=false;
//If no function in esp_himem.c is used, this function will be linked into the
//binary instead of the one in esp_himem.c, automatically making sure no memory
//is reserved if no himem function is used.
size_t __attribute__((weak)) esp_himem_reserved_area_size(void) {
return 0;
}
static size_t spiram_size_usable_for_malloc(void)
{
/* SPIRAM chip may be larger than the size we can map into address space */
size_t s = MIN(esp_spiram_get_size(), SOC_EXTRAM_DATA_SIZE);
return s - esp_himem_reserved_area_size();
}
/*
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)
{
#if CONFIG_SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY
const void *keepout_addr_low = (const void*)&_ext_ram_noinit_start;
const void *keepout_addr_high = (const void*)&_ext_ram_noinit_end;
#else
const void *keepout_addr_low = 0;
const void *keepout_addr_high = 0;
#endif
volatile int *spiram=(volatile int*)SOC_EXTRAM_DATA_LOW;
size_t p;
size_t s=spiram_size_usable_for_malloc();
int errct=0;
int initial_err=-1;
for (p=0; p<(s/sizeof(int)); p+=8) {
const void *addr = (const void *)&spiram[p];
if ((keepout_addr_low <= addr) && (addr < keepout_addr_high)) {
continue;
}
spiram[p]=p^0xAAAAAAAA;
}
for (p=0; p<(s/sizeof(int)); p+=8) {
const void *addr = (const void *)&spiram[p];
if ((keepout_addr_low <= addr) && (addr < keepout_addr_high)) {
continue;
}
if (spiram[p]!=(p^0xAAAAAAAA)) {
errct++;
if (errct==1) initial_err=p*4;
}
}
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)
{
int size = esp_spiram_get_size();
if (size > 4 * 1024 * 1024) size = 4 * 1024 * 1024; // we can map at most 4MByte
//Enable external RAM in MMU
cache_sram_mmu_set(0, 0, SOC_EXTRAM_DATA_LOW, 0, 32, (size / 1024 / 32));
//Flush and enable icache for APP CPU
#if !CONFIG_FREERTOS_UNICORE
DPORT_CLEAR_PERI_REG_MASK(DPORT_APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MASK_DRAM1);
cache_sram_mmu_set(1, 0, SOC_EXTRAM_DATA_LOW, 0, 32, (size / 1024 / 32));
#endif
s_mapped_vaddr_start = (intptr_t)SOC_EXTRAM_DATA_LOW;
s_mapped_vaddr_end = s_mapped_vaddr_start + size;
}
esp_spiram_size_t esp_spiram_get_chip_size(void)
{
if (!spiram_inited) {
ESP_EARLY_LOGE(TAG, "SPI RAM not initialized");
abort();
}
psram_size_t psram_size = psram_get_size();
switch (psram_size) {
case PSRAM_SIZE_16MBITS:
return ESP_SPIRAM_SIZE_16MBITS;
case PSRAM_SIZE_32MBITS:
return ESP_SPIRAM_SIZE_32MBITS;
case PSRAM_SIZE_64MBITS:
return ESP_SPIRAM_SIZE_64MBITS;
default:
return ESP_SPIRAM_SIZE_INVALID;
}
}
esp_err_t esp_spiram_init(void)
{
assert(!spiram_inited);
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; //note: this needs to be set before esp_spiram_get_chip_*/esp_spiram_get_size calls
#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_F40M_S40M ? "flash 40m sram 40m" : \
PSRAM_SPEED == PSRAM_CACHE_F80M_S40M ? "flash 80m sram 40m" : \
PSRAM_SPEED == PSRAM_CACHE_F80M_S80M ? "flash 80m sram 80m" : "ERROR");
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)
{
//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.
s_allocable_vaddr_start = (intptr_t)SOC_EXTRAM_DATA_LOW;
#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
if (s_allocable_vaddr_start < (intptr_t)&_ext_ram_bss_end) {
s_allocable_vaddr_start = (intptr_t)&_ext_ram_bss_end;
}
#endif
#if CONFIG_SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY
if (s_allocable_vaddr_start < (intptr_t)&_ext_ram_noinit_end) {
s_allocable_vaddr_start = (intptr_t)&_ext_ram_noinit_end;
}
#endif
s_allocable_vaddr_end = (intptr_t)SOC_EXTRAM_DATA_LOW + spiram_size_usable_for_malloc() - 1;
ESP_EARLY_LOGI(TAG, "Adding pool of %dK of external SPI memory to heap allocator", (s_allocable_vaddr_end - s_allocable_vaddr_start)/1024);
return heap_caps_add_region(s_allocable_vaddr_start, s_allocable_vaddr_end);
}
esp_err_t IRAM_ATTR esp_spiram_get_mapped_range(intptr_t *out_vstart, intptr_t *out_vend)
{
if (!out_vstart || !out_vend) {
return ESP_ERR_INVALID_ARG;
}
if (!spiram_inited) {
return ESP_ERR_INVALID_STATE;
}
*out_vstart = s_mapped_vaddr_start;
*out_vend = s_mapped_vaddr_end;
return ESP_OK;
}
esp_err_t esp_spiram_get_alloced_range(intptr_t *out_vstart, intptr_t *out_vend)
{
if (!out_vstart || !out_vend) {
return ESP_ERR_INVALID_ARG;
}
if (!spiram_inited) {
return ESP_ERR_INVALID_STATE;
}
*out_vstart = s_allocable_vaddr_start;
*out_vend = s_allocable_vaddr_end;
return ESP_OK;
}
static uint8_t *dma_heap;
esp_err_t esp_spiram_reserve_dma_pool(size_t size) {
ESP_EARLY_LOGI(TAG, "Reserving pool of %dK of internal memory for DMA/internal allocations", size/1024);
/* Pool may be allocated in multiple non-contiguous chunks, depending on available RAM */
while (size > 0) {
size_t next_size = heap_caps_get_largest_free_block(MALLOC_CAP_DMA|MALLOC_CAP_INTERNAL);
next_size = MIN(next_size, size);
ESP_EARLY_LOGD(TAG, "Allocating block of size %d bytes", next_size);
dma_heap = heap_caps_malloc(next_size, MALLOC_CAP_DMA|MALLOC_CAP_INTERNAL);
if (!dma_heap || next_size == 0) {
return ESP_ERR_NO_MEM;
}
uint32_t caps[] = { 0, MALLOC_CAP_DMA|MALLOC_CAP_INTERNAL, MALLOC_CAP_8BIT|MALLOC_CAP_32BIT };
esp_err_t e = heap_caps_add_region_with_caps(caps, (intptr_t) dma_heap, (intptr_t) dma_heap+next_size-1);
if (e != ESP_OK) {
return e;
}
size -= next_size;
}
return ESP_OK;
}
size_t esp_spiram_get_size(void)
{
psram_size_t size=esp_spiram_get_chip_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 CONFIG_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.
Note that this routine assumes some unique mapping for the first 2 banks of the PSRAM memory range, as well as the
2 banks after the 2 MiB mark.
*/
void IRAM_ATTR esp_spiram_writeback_cache(void)
{
int x;
volatile int i=0;
volatile uint8_t *psram=(volatile uint8_t*)SOC_EXTRAM_DATA_LOW;
int cache_was_disabled=0;
if (!spiram_inited) return;
//We need cache enabled for this to work. Re-enable it if needed; make sure we
//disable it again on exit as well.
if (DPORT_REG_GET_BIT(DPORT_PRO_CACHE_CTRL_REG, DPORT_PRO_CACHE_ENABLE)==0) {
cache_was_disabled|=(1<<0);
DPORT_SET_PERI_REG_BITS(DPORT_PRO_CACHE_CTRL_REG, 1, 1, DPORT_PRO_CACHE_ENABLE_S);
}
#ifndef CONFIG_FREERTOS_UNICORE
if (DPORT_REG_GET_BIT(DPORT_APP_CACHE_CTRL_REG, DPORT_APP_CACHE_ENABLE)==0) {
cache_was_disabled|=(1<<1);
DPORT_SET_PERI_REG_BITS(DPORT_APP_CACHE_CTRL_REG, 1, 1, DPORT_APP_CACHE_ENABLE_S);
}
#endif
#if (PSRAM_MODE != PSRAM_VADDR_MODE_LOWHIGH)
/*
Single-core and even/odd mode only have 32K of cache evenly distributed over the address lines. We can clear
the cache by just reading 64K worth of cache lines.
*/.
for (x=0; x<1024*64; x+=32) {
i+=psram[x];
}
#else
/*
Low/high psram cache mode uses one 32K cache for the lowest 2MiB of SPI flash and another 32K for the highest
2MiB. Clear this by reading from both regions.
Note: this assumes the amount of external RAM is >2M. If it is 2M or less, what this code does is undefined. If
we ever support external RAM chips of 2M or smaller, this may need adjusting.
*/
for (x=0; x<1024*64; x+=32) {
i+=psram[x];
i+=psram[x+(1024*1024*2)];
}
#endif
if (cache_was_disabled&(1<<0)) {
while (DPORT_GET_PERI_REG_BITS2(DPORT_PRO_DCACHE_DBUG0_REG, DPORT_PRO_CACHE_STATE, DPORT_PRO_CACHE_STATE_S) != 1) ;
DPORT_SET_PERI_REG_BITS(DPORT_PRO_CACHE_CTRL_REG, 1, 0, DPORT_PRO_CACHE_ENABLE_S);
}
#ifndef CONFIG_FREERTOS_UNICORE
if (cache_was_disabled&(1<<1)) {
while (DPORT_GET_PERI_REG_BITS2(DPORT_APP_DCACHE_DBUG0_REG, DPORT_APP_CACHE_STATE, DPORT_APP_CACHE_STATE_S) != 1);
DPORT_SET_PERI_REG_BITS(DPORT_APP_CACHE_CTRL_REG, 1, 0, DPORT_APP_CACHE_ENABLE_S);
}
#endif
}
/**
* @brief If SPI RAM(PSRAM) has been initialized
*
* @return true SPI RAM has been initialized successfully
* @return false SPI RAM hasn't been initialized or initialized failed
*/
bool esp_spiram_is_initialized(void)
{
return spiram_inited;
}
uint8_t esp_spiram_get_cs_io(void)
{
return psram_get_cs_io();
}
#endif

View File

@ -1,77 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _PSRAM_H
#define _PSRAM_H
#include "soc/spi_periph.h"
#include "esp_err.h"
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
PSRAM_CACHE_F80M_S40M = 0,
PSRAM_CACHE_F40M_S40M,
PSRAM_CACHE_F80M_S80M,
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);
/**
* @brief get psram CS IO
*
* @return psram CS IO
*/
uint8_t psram_get_cs_io(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -18,9 +18,6 @@ if(NOT BOOTLOADER_BUILD)
"esp_crypto_lock.c"
"esp_ds.c")
if(CONFIG_SPIRAM)
list(APPEND srcs "spiram.c" "mmu_psram.c" "spiram_psram.c")
endif()
endif()
add_prefix(srcs "${CMAKE_CURRENT_LIST_DIR}/" "${srcs}")

View File

@ -1,251 +0,0 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <sys/param.h>
#include "esp_attr.h"
#include "esp_log.h"
#include "esp_private/mmu_psram.h"
#include "esp32s2/rom/cache.h"
#include "esp32s2/rom/ets_sys.h"
#include "soc/ext_mem_defs.h"
#include "soc/extmem_reg.h"
#define MMU_PAGE_SIZE (0x10000)
#define MMU_PAGE_TO_BYTES(page_id) ((page_id) * MMU_PAGE_SIZE)
#define BYTES_TO_MMU_PAGE(bytes) ((bytes) / MMU_PAGE_SIZE)
const static char *TAG = "mmu_psram";
//------------------------------------Copy Flash .text to PSRAM-------------------------------------//
#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS
extern int _instruction_reserved_start;
extern int _instruction_reserved_end;
static uint32_t instruction_in_spiram;
static uint32_t instr_start_page;
static uint32_t instr_end_page;
static int instr_flash2spiram_offs;
uint32_t esp_spiram_instruction_access_enabled(void);
int instruction_flash2spiram_offset(void);
uint32_t instruction_flash_start_page_get(void);
uint32_t instruction_flash_end_page_get(void);
#endif //CONFIG_SPIRAM_FETCH_INSTRUCTIONS
//------------------------------------Copy Flash .rodata to PSRAM-------------------------------------//
#if CONFIG_SPIRAM_RODATA
extern int _rodata_reserved_start;
extern int _rodata_reserved_end;
static uint32_t rodata_in_spiram;
static int rodata_flash2spiram_offs;
static uint32_t rodata_start_page;
static uint32_t rodata_end_page;
uint32_t esp_spiram_rodata_access_enabled(void);
int rodata_flash2spiram_offset(void);
uint32_t rodata_flash_start_page_get(void);
uint32_t rodata_flash_end_page_get(void);
#endif //#if CONFIG_SPIRAM_RODATA
#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS || CONFIG_SPIRAM_RODATA
// Helper macro to make a MMU entry invalid
#define INVALID_PHY_PAGE 0xffff
//TODO IDF-4387
static uint32_t page0_mapped = 0;
static uint32_t page0_page = INVALID_PHY_PAGE;
#endif //#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS || CONFIG_SPIRAM_RODATA
#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS
esp_err_t mmu_config_psram_text_segment(uint32_t start_page, uint32_t psram_size, uint32_t *out_page)
{
uint32_t page_id = start_page;
/**
* TODO IDF-4387
* `Cache_Count_Flash_Pages` seems give wrong results. Need to confirm this.
* FOR NOW, leave these logics just as it used to be.
*/
uint32_t flash_pages = 0;
flash_pages += Cache_Count_Flash_Pages(PRO_CACHE_IBUS0, &page0_mapped);
flash_pages += Cache_Count_Flash_Pages(PRO_CACHE_IBUS1, &page0_mapped);
if ((flash_pages + page_id) > BYTES_TO_MMU_PAGE(psram_size)) {
ESP_EARLY_LOGE(TAG, "PSRAM space not enough for the Flash instructions, need %d B, from %d B to %d B",
MMU_PAGE_TO_BYTES(flash_pages), MMU_PAGE_TO_BYTES(start_page), MMU_PAGE_TO_BYTES(flash_pages + page_id));
return ESP_FAIL;
}
//Enable DRAM0_BUS, which is used for copying FLASH .text to PSRAM
REG_CLR_BIT(EXTMEM_PRO_DCACHE_CTRL1_REG, EXTMEM_PRO_DCACHE_MASK_DRAM0);
uint32_t instr_page_cnt = ((uint32_t)&_instruction_reserved_end - (uint32_t)&_instruction_reserved_start + MMU_PAGE_SIZE - 1) / MMU_PAGE_SIZE;
uint32_t instr_mmu_offset = ((uint32_t)&_instruction_reserved_start & MMU_VADDR_MASK) / MMU_PAGE_SIZE;
instr_start_page = ((volatile uint32_t *)(DR_REG_MMU_TABLE + PRO_CACHE_IBUS0_MMU_START))[instr_mmu_offset];
instr_start_page &= MMU_VALID_VAL_MASK;
instr_end_page = instr_start_page + instr_page_cnt - 1;
instr_flash2spiram_offs = instr_start_page - page_id;
ESP_EARLY_LOGV(TAG, "Instructions from flash page%d copy to SPIRAM page%d, Offset: %d", instr_start_page, page_id, instr_flash2spiram_offs);
page_id = Cache_Flash_To_SPIRAM_Copy(PRO_CACHE_IBUS0, IRAM0_ADDRESS_LOW, page_id, &page0_page);
page_id = Cache_Flash_To_SPIRAM_Copy(PRO_CACHE_IBUS1, IRAM1_ADDRESS_LOW, page_id, &page0_page);
instruction_in_spiram = 1;
ESP_EARLY_LOGV(TAG, "after copy instruction, page_id is %d", page_id);
ESP_EARLY_LOGI(TAG, "Instructions copied and mapped to SPIRAM");
/**
* Disable DRAM0_BUS.
* .text (instructions) are mapped in `Cache_Flash_To_SPIRAM_Copy` to both `PRO_CACHE_IBUS0` and `PRO_CACHE_IBUS1`.
*
* For now, this bus (DRAM0) is only used for copying, so can be disabled. If it is used later, other code
* should be responsible for enabling it.
*/
REG_SET_BIT(EXTMEM_PRO_DCACHE_CTRL1_REG, EXTMEM_PRO_DCACHE_MASK_DRAM0);
*out_page = page_id - start_page;
return ESP_OK;
}
#endif //#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS
#if CONFIG_SPIRAM_RODATA
esp_err_t mmu_config_psram_rodata_segment(uint32_t start_page, uint32_t psram_size, uint32_t *out_page)
{
uint32_t page_id = start_page;
/**
* TODO IDF-4387
* `Cache_Count_Flash_Pages` seems give wrong results. Need to confirm this.
* FOR NOW, leave these logics just as it used to be.
*/
uint32_t flash_pages = 0;
flash_pages += Cache_Count_Flash_Pages(PRO_CACHE_IBUS2, &page0_mapped);
flash_pages += Cache_Count_Flash_Pages(PRO_CACHE_DBUS0, &page0_mapped);
flash_pages += Cache_Count_Flash_Pages(PRO_CACHE_DBUS1, &page0_mapped);
flash_pages += Cache_Count_Flash_Pages(PRO_CACHE_DBUS2, &page0_mapped);
if ((flash_pages + page_id) > BYTES_TO_MMU_PAGE(psram_size)) {
ESP_EARLY_LOGE(TAG, "SPI RAM space not enough for the instructions, need to copy to %d B.", MMU_PAGE_TO_BYTES(flash_pages + page_id));
return ESP_FAIL;
}
//Enable DRAM0_BUS, which is used for copying FLASH .rodata to PSRAM
REG_CLR_BIT(EXTMEM_PRO_DCACHE_CTRL1_REG, EXTMEM_PRO_DCACHE_MASK_DRAM0);
uint32_t rodata_page_cnt = ((uint32_t)&_rodata_reserved_end - (uint32_t)&_rodata_reserved_start + MMU_PAGE_SIZE - 1) / MMU_PAGE_SIZE;
uint32_t rodata_mmu_offset = ((uint32_t)&_rodata_reserved_start & MMU_VADDR_MASK) / MMU_PAGE_SIZE;
rodata_start_page = ((volatile uint32_t *)(DR_REG_MMU_TABLE + PRO_CACHE_IBUS2_MMU_START))[rodata_mmu_offset];
rodata_start_page &= MMU_VALID_VAL_MASK;
rodata_end_page = rodata_start_page + rodata_page_cnt - 1;
rodata_flash2spiram_offs = rodata_start_page - page_id;
ESP_EARLY_LOGV(TAG, "Rodata from flash page%d copy to SPIRAM page%d, Offset: %d", rodata_start_page, page_id, rodata_flash2spiram_offs);
page_id = Cache_Flash_To_SPIRAM_Copy(PRO_CACHE_IBUS2, DROM0_ADDRESS_LOW, page_id, &page0_page);
page_id = Cache_Flash_To_SPIRAM_Copy(PRO_CACHE_DBUS0, DRAM0_ADDRESS_LOW, page_id, &page0_page);
page_id = Cache_Flash_To_SPIRAM_Copy(PRO_CACHE_DBUS1, DRAM1_ADDRESS_LOW, page_id, &page0_page);
page_id = Cache_Flash_To_SPIRAM_Copy(PRO_CACHE_DBUS2, DPORT_ADDRESS_LOW, page_id, &page0_page);
rodata_in_spiram = 1;
ESP_EARLY_LOGV(TAG, "after copy rodata, page_id is %d", page_id);
ESP_EARLY_LOGI(TAG, "Read only data copied and mapped to SPIRAM");
/**
* Disable DRAM0_BUS.
* .text (instructions) are mapped in `Cache_Flash_To_SPIRAM_Copy` to both `PRO_CACHE_IBUS0` and `PRO_CACHE_IBUS1`.
*
* For now, this bus (DRAM0) is only used for copying, so can be disabled. If it is used later, other code
* should be responsible for enabling it.
*/
REG_SET_BIT(EXTMEM_PRO_DCACHE_CTRL1_REG, EXTMEM_PRO_DCACHE_MASK_DRAM0);
*out_page = page_id - start_page;
return ESP_OK;
}
#endif //#if CONFIG_SPIRAM_RODATA
/**
* On ESP32S2, DPORT_BUS, DRAM1_BUS, DRAM0_BUS are consecutive, from low to high
*/
esp_err_t mmu_map_psram(uint32_t start_paddr, uint32_t end_paddr, uint32_t *out_start_vaddr)
{
/**
* @note For now, this function should only run when virtual address is enough
* Decide these logics when there's a real PSRAM with larger size
*/
uint32_t map_length = end_paddr - start_paddr;
if (map_length > SOC_EXTRAM_DATA_SIZE) {
//Decide these logics when there's a real PSRAM with larger size
ESP_EARLY_LOGE(TAG, "PSRAM physical size is too large, not support mapping it yet!");
return ESP_ERR_INVALID_ARG;
}
//should be MMU page aligned
assert((start_paddr % MMU_PAGE_SIZE) == 0);
uint32_t start_vaddr = DPORT_CACHE_ADDRESS_LOW;
uint32_t end_vaddr = start_vaddr + map_length;
uint32_t cache_bus_mask = 0;
cache_bus_mask |= (end_vaddr > 0) ? EXTMEM_PRO_DCACHE_MASK_DPORT : 0;
cache_bus_mask |= (end_vaddr >= DPORT_ADDRESS_HIGH) ? EXTMEM_PRO_DCACHE_MASK_DRAM1 : 0;
cache_bus_mask |= (end_vaddr >= DRAM1_ADDRESS_HIGH) ? EXTMEM_PRO_DCACHE_MASK_DRAM0 : 0;
assert(end_vaddr <= DRAM0_CACHE_ADDRESS_HIGH);
ESP_EARLY_LOGV(TAG, "start_paddr is %x, map_length is %xB, %d pages", start_paddr, map_length, BYTES_TO_MMU_PAGE(map_length));
//No need to disable cache, this file is put in Internal RAM
Cache_Dbus_MMU_Set(MMU_ACCESS_SPIRAM, start_vaddr, start_paddr, 64, BYTES_TO_MMU_PAGE(map_length), 0);
REG_CLR_BIT(EXTMEM_PRO_DCACHE_CTRL1_REG, cache_bus_mask);
*out_start_vaddr = start_vaddr;
return ESP_OK;
}
#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS
uint32_t esp_spiram_instruction_access_enabled(void)
{
return instruction_in_spiram;
}
int instruction_flash2spiram_offset(void)
{
return instr_flash2spiram_offs;
}
uint32_t instruction_flash_start_page_get(void)
{
return instr_start_page;
}
uint32_t instruction_flash_end_page_get(void)
{
return instr_end_page;
}
#endif //CONFIG_SPIRAM_FETCH_INSTRUCTIONS
#if CONFIG_SPIRAM_RODATA
uint32_t esp_spiram_rodata_access_enabled(void)
{
return rodata_in_spiram;
}
int rodata_flash2spiram_offset(void)
{
return rodata_flash2spiram_offs;
}
uint32_t rodata_flash_start_page_get(void)
{
return rodata_start_page;
}
uint32_t rodata_flash_end_page_get(void)
{
return rodata_end_page;
}
#endif //#if CONFIG_SPIRAM_RODATA

View File

@ -1,279 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/*----------------------------------------------------------------------------------------------------
* Abstraction layer for PSRAM. PSRAM device related registers and MMU/Cache related code shouls be
* abstracted to lower layers.
*
* When we add more types of external RAM memory, this can be made into a more intelligent dispatcher.
*----------------------------------------------------------------------------------------------------*/
#include <sys/param.h>
#include "sdkconfig.h"
#include "esp_attr.h"
#include "esp_err.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/xtensa_api.h"
#include "esp_heap_caps_init.h"
#include "esp_private/spiram_private.h"
#include "esp32s2/spiram.h"
#include "esp_private/mmu_psram.h"
#include "spiram_psram.h"
#define PSRAM_MODE PSRAM_VADDR_MODE_NORMAL
#if CONFIG_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 MMU_PAGE_TO_BYTES(page_id) ((page_id) << 16)
#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
extern uint8_t _ext_ram_bss_start;
extern uint8_t _ext_ram_bss_end;
#endif //#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
//These variables are in bytes
static intptr_t s_allocable_vaddr_start;
static intptr_t s_allocable_vaddr_end;
static intptr_t s_mapped_vaddr_start;
static intptr_t s_mapped_vaddr_end;
static bool s_spiram_inited;
static const char* TAG = "spiram";
static bool esp_spiram_test(uint32_t v_start, uint32_t size);
esp_err_t esp_spiram_init(void)
{
assert(!s_spiram_inited);
esp_err_t ret;
ret = psram_enable(PSRAM_SPEED, PSRAM_MODE);
if (ret != ESP_OK) {
#if CONFIG_SPIRAM_IGNORE_NOTFOUND
ESP_EARLY_LOGE(TAG, "SPI RAM enabled but initialization failed. Bailing out.");
#endif
return ret;
}
s_spiram_inited = true;
uint32_t psram_physical_size = 0;
ret = psram_get_physical_size(&psram_physical_size);
assert(ret == ESP_OK);
#if (CONFIG_SPIRAM_SIZE != -1)
if (psram_physical_size != CONFIG_SPIRAM_SIZE) {
ESP_EARLY_LOGE(TAG, "Expected %dMB chip but found %dMB chip. Bailing out..", CONFIG_SPIRAM_SIZE / 1024 / 1024, psram_physical_size / 1024 / 1024);
return ESP_ERR_INVALID_SIZE;
}
#endif
ESP_EARLY_LOGI(TAG, "Found %dMBit SPI RAM device", psram_physical_size / (1024 * 1024));
ESP_EARLY_LOGI(TAG, "Speed: %dMHz", CONFIG_SPIRAM_SPEED);
uint32_t psram_available_size = 0;
ret = psram_get_available_size(&psram_available_size);
assert(ret == ESP_OK);
__attribute__((unused)) uint32_t total_available_size = psram_available_size;
/**
* `start_page` is the psram physical address in MMU page size.
* MMU page size on ESP32S2 is 64KB
* e.g.: psram physical address 16 is in page 0
*
* Here we plan to copy FLASH instructions to psram physical address 0, which is the No.0 page.
*/
uint32_t start_page = 0;
#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS || CONFIG_SPIRAM_RODATA
uint32_t used_page = 0;
#endif
//------------------------------------Copy Flash .text to PSRAM-------------------------------------//
#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS
ret = mmu_config_psram_text_segment(start_page, total_available_size, &used_page);
if (ret != ESP_OK) {
ESP_EARLY_LOGE(TAG, "No enough psram memory for instructon!");
abort();
}
start_page += used_page;
psram_available_size -= MMU_PAGE_TO_BYTES(used_page);
ESP_EARLY_LOGV(TAG, "after copy .text, used page is %d, start_page is %d, psram_available_size is %d B", used_page, start_page, psram_available_size);
#endif //#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS
//------------------------------------Copy Flash .rodata to PSRAM-------------------------------------//
#if CONFIG_SPIRAM_RODATA
ret = mmu_config_psram_rodata_segment(start_page, total_available_size, &used_page);
if (ret != ESP_OK) {
ESP_EARLY_LOGE(TAG, "No enough psram memory for rodata!");
abort();
}
start_page += used_page;
psram_available_size -= MMU_PAGE_TO_BYTES(used_page);
ESP_EARLY_LOGV(TAG, "after copy .rodata, used page is %d, start_page is %d, psram_available_size is %d B", used_page, start_page, psram_available_size);
#endif //#if CONFIG_SPIRAM_RODATA
//----------------------------------Map the PSRAM physical range to MMU-----------------------------//
static DRAM_ATTR uint32_t vaddr_start = 0;
mmu_map_psram(MMU_PAGE_TO_BYTES(start_page), MMU_PAGE_TO_BYTES(start_page) + psram_available_size, &vaddr_start);
if (ret != ESP_OK) {
ESP_EARLY_LOGE(TAG, "MMU PSRAM mapping wrong!");
abort();
}
#if CONFIG_SPIRAM_MEMTEST
//After mapping, simple test SPIRAM first
bool ext_ram_ok = esp_spiram_test(vaddr_start, psram_available_size);
if (!ext_ram_ok) {
ESP_EARLY_LOGE(TAG, "External RAM failed memory test!");
abort();
}
#endif //#if CONFIG_SPIRAM_MEMTEST
/*------------------------------------------------------------------------------
* After mapping, we DON'T care about the PSRAM PHYSICAL ADDRESSS ANYMORE!
*----------------------------------------------------------------------------*/
s_mapped_vaddr_start = vaddr_start;
s_mapped_vaddr_end = vaddr_start + psram_available_size;
s_allocable_vaddr_start = vaddr_start;
s_allocable_vaddr_end = vaddr_start + psram_available_size;
//------------------------------------Configure .bss in PSRAM-------------------------------------//
#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
//should never be negative number
uint32_t ext_bss_size = ((intptr_t)&_ext_ram_bss_end - (intptr_t)&_ext_ram_bss_start);
ESP_EARLY_LOGV(TAG, "ext_bss_size is %d", ext_bss_size);
s_allocable_vaddr_start += ext_bss_size;
#endif //#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
ESP_EARLY_LOGV(TAG, "s_allocable_vaddr_start is 0x%x, s_allocable_vaddr_end is 0x%x", s_allocable_vaddr_start, s_allocable_vaddr_end);
return ESP_OK;
}
/**
* Add the PSRAM available region to heap allocator. Heap allocator knows the capabilities of this type of memory,
* so there's no need to explicitly specify them.
*/
esp_err_t esp_spiram_add_to_heapalloc(void)
{
ESP_EARLY_LOGI(TAG, "Adding pool of %dK of external SPI memory to heap allocator", (s_allocable_vaddr_end - s_allocable_vaddr_start) / 1024);
return heap_caps_add_region(s_allocable_vaddr_start, s_allocable_vaddr_end);
}
esp_err_t IRAM_ATTR esp_spiram_get_mapped_range(intptr_t *out_vstart, intptr_t *out_vend)
{
if (!out_vstart || !out_vend) {
return ESP_ERR_INVALID_ARG;
}
if (!s_spiram_inited) {
return ESP_ERR_INVALID_STATE;
}
*out_vstart = s_mapped_vaddr_start;
*out_vend = s_mapped_vaddr_end;
return ESP_OK;
}
esp_err_t esp_spiram_get_alloced_range(intptr_t *out_vstart, intptr_t *out_vend)
{
if (!out_vstart || !out_vend) {
return ESP_ERR_INVALID_ARG;
}
if (!s_spiram_inited) {
return ESP_ERR_INVALID_STATE;
}
*out_vstart = s_allocable_vaddr_start;
*out_vend = s_allocable_vaddr_end;
return ESP_OK;
}
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);
uint8_t *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);
}
/*
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();
}
/**
* @brief If SPI RAM(PSRAM) has been initialized
*
* @return true SPI RAM has been initialized successfully
* @return false SPI RAM hasn't been initialized or initialized failed
*/
bool esp_spiram_is_initialized(void)
{
return s_spiram_inited;
}
uint8_t esp_spiram_get_cs_io(void)
{
return psram_get_cs_io();
}
/*
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.
*/
static bool esp_spiram_test(uint32_t v_start, uint32_t size)
{
volatile int *spiram = (volatile int *)v_start;
size_t s = size;
size_t p;
int errct = 0;
int initial_err = -1;
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 {
return true;
}
}
#endif //#if CONFIG_SPIRAM

View File

@ -16,16 +16,6 @@ if(NOT BOOTLOADER_BUILD)
"esp_hmac.c"
"esp_ds.c"
"esp_crypto_lock.c")
if(CONFIG_SPIRAM)
list(APPEND srcs "spiram.c" "mmu_psram.c")
if(CONFIG_SPIRAM_MODE_QUAD)
list(APPEND srcs "spiram_psram.c")
elseif(CONFIG_SPIRAM_MODE_OCT)
list(APPEND srcs "opiram_psram.c")
endif()
endif()
endif()
add_prefix(srcs "${CMAKE_CURRENT_LIST_DIR}/" "${srcs}")

View File

@ -1,276 +0,0 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <sys/param.h>
#include "esp_attr.h"
#include "esp_log.h"
#include "esp_private/mmu_psram.h"
#include "esp32s3/rom/cache.h"
#include "esp32s3/rom/ets_sys.h"
#include "soc/ext_mem_defs.h"
#include "soc/extmem_reg.h"
#define MMU_PAGE_SIZE 0x10000
#define MMU_PAGE_TO_BYTES(page_id) ((page_id) * MMU_PAGE_SIZE)
#define BYTES_TO_MMU_PAGE(bytes) ((bytes) / MMU_PAGE_SIZE)
const static char *TAG = "mmu_psram";
//------------------------------------Copy Flash .text to PSRAM-------------------------------------//
#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS
extern int _instruction_reserved_start;
extern int _instruction_reserved_end;
static uint32_t instruction_in_spiram;
static uint32_t instr_start_page;
static uint32_t instr_end_page;
static int instr_flash2spiram_offs;
uint32_t esp_spiram_instruction_access_enabled(void);
int instruction_flash2spiram_offset(void);
uint32_t instruction_flash_start_page_get(void);
uint32_t instruction_flash_end_page_get(void);
#endif //CONFIG_SPIRAM_FETCH_INSTRUCTIONS
//------------------------------------Copy Flash .rodata to PSRAM-------------------------------------//
#if CONFIG_SPIRAM_RODATA
extern int _rodata_reserved_start;
extern int _rodata_reserved_end;
static uint32_t rodata_in_spiram;
static int rodata_flash2spiram_offs;
static uint32_t rodata_start_page;
static uint32_t rodata_end_page;
uint32_t esp_spiram_rodata_access_enabled(void);
int rodata_flash2spiram_offset(void);
uint32_t rodata_flash_start_page_get(void);
uint32_t rodata_flash_end_page_get(void);
#endif //#if CONFIG_SPIRAM_RODATA
#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS || CONFIG_SPIRAM_RODATA
//TODO IDF-4387
static uint32_t page0_mapped = 0;
static uint32_t page0_page = INVALID_PHY_PAGE;
#endif //#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS || CONFIG_SPIRAM_RODATA
#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS
esp_err_t mmu_config_psram_text_segment(uint32_t start_page, uint32_t psram_size, uint32_t *out_page)
{
uint32_t page_id = start_page;
/**
* TODO IDF-4387
* `Cache_Count_Flash_Pages` seems give wrong results. Need to confirm this.
* FOR NOW, leave these logics just as it used to be.
*/
uint32_t flash_pages = 0;
flash_pages += Cache_Count_Flash_Pages(CACHE_IBUS, &page0_mapped);
if ((flash_pages + page_id) > BYTES_TO_MMU_PAGE(psram_size)) {
ESP_EARLY_LOGE(TAG, "PSRAM space not enough for the Flash instructions, need %d B, from %d B to %d B",
MMU_PAGE_TO_BYTES(flash_pages), MMU_PAGE_TO_BYTES(start_page), MMU_PAGE_TO_BYTES(flash_pages + page_id));
return ESP_FAIL;
}
//Enable DBUS, which is used for copying FLASH .text to PSRAM
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
// uint32_t instr_page_cnt = ((uint32_t)&_instruction_reserved_end - (uint32_t)&_instruction_reserved_start + MMU_PAGE_SIZE - 1) / MMU_PAGE_SIZE;
// uint32_t instr_mmu_offset = ((uint32_t)&_instruction_reserved_start & MMU_VADDR_MASK) / MMU_PAGE_SIZE;
// instr_start_page = ((volatile uint32_t *)(DR_REG_MMU_TABLE + PRO_CACHE_IBUS0_MMU_START))[instr_mmu_offset];
// instr_start_page &= MMU_VALID_VAL_MASK;
// instr_end_page = instr_start_page + instr_page_cnt - 1;
// instr_flash2spiram_offs = instr_start_page - page_id;
// ESP_EARLY_LOGV(TAG, "Instructions from flash page%d copy to SPIRAM page%d, Offset: %d", instr_start_page, page_id, instr_flash2spiram_offs);
ets_printf(DRAM_STR("_instruction_reserved_end addr is %x\n"), (uint32_t)&_instruction_reserved_start);
uint32_t instr_page_cnt = ((uint32_t)&_instruction_reserved_end - SOC_IROM_LOW + MMU_PAGE_SIZE - 1) / MMU_PAGE_SIZE;
instr_start_page = *(volatile uint32_t *)(DR_REG_MMU_TABLE + CACHE_IROM_MMU_START);
instr_start_page &= MMU_VALID_VAL_MASK;
instr_end_page = instr_start_page + instr_page_cnt - 1;
instr_flash2spiram_offs = instr_start_page - page_id;
ESP_EARLY_LOGE(TAG, "Instructions from flash page%d copy to SPIRAM page%d, Offset: %d", instr_start_page, page_id, instr_flash2spiram_offs);
// page_id = Cache_Flash_To_SPIRAM_Copy(PRO_CACHE_IBUS0, IRAM0_ADDRESS_LOW, page_id, &page0_page);
// page_id = Cache_Flash_To_SPIRAM_Copy(PRO_CACHE_IBUS1, IRAM1_ADDRESS_LOW, page_id, &page0_page);
// instruction_in_spiram = 1;
// ESP_EARLY_LOGV(TAG, "after copy instruction, page_id is %d", page_id);
// ESP_EARLY_LOGI(TAG, "Instructions copied and mapped to SPIRAM");
page_id = Cache_Flash_To_SPIRAM_Copy(CACHE_IBUS, IRAM0_CACHE_ADDRESS_LOW, page_id, &page0_page);
instruction_in_spiram = 1;
ESP_EARLY_LOGV(TAG, "after copy instruction, page_id is %d", page_id);
ESP_EARLY_LOGI(TAG, "Instructions copied and mapped to SPIRAM");
/**
* Disable DRAM0_BUS.
* .text (instructions) are mapped in `Cache_Flash_To_SPIRAM_Copy` to both `PRO_CACHE_IBUS0` and `PRO_CACHE_IBUS1`.
*
* For now, this bus (DRAM0) is only used for copying, so can be disabled. If it is used later, other code
* should be responsible for enabling it.
*/
REG_SET_BIT(EXTMEM_DCACHE_CTRL1_REG, EXTMEM_DCACHE_SHUT_CORE0_BUS);
#if !CONFIG_FREERTOS_UNICORE
REG_SET_BIT(EXTMEM_DCACHE_CTRL1_REG, EXTMEM_DCACHE_SHUT_CORE1_BUS);
#endif
*out_page = page_id - start_page;
return ESP_OK;
}
#endif //#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS
#if CONFIG_SPIRAM_RODATA
esp_err_t mmu_config_psram_rodata_segment(uint32_t start_page, uint32_t psram_size, uint32_t *out_page)
{
uint32_t page_id = start_page;
/**
* TODO IDF-4387
* `Cache_Count_Flash_Pages` seems give wrong results. Need to confirm this.
* FOR NOW, leave these logics just as it used to be.
*/
uint32_t flash_pages = 0;
flash_pages += Cache_Count_Flash_Pages(CACHE_DBUS, &page0_mapped);
if ((flash_pages + page_id) > BYTES_TO_MMU_PAGE(psram_size)) {
ESP_EARLY_LOGE(TAG, "SPI RAM space not enough for the instructions, need to copy to %d B.", MMU_PAGE_TO_BYTES(flash_pages + page_id));
return ESP_FAIL;
}
//Enable DBUS, which is used for copying FLASH .text to PSRAM
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
// uint32_t rodata_page_cnt = ((uint32_t)&_rodata_reserved_end - (uint32_t)&_rodata_reserved_start + MMU_PAGE_SIZE - 1) / MMU_PAGE_SIZE;
// uint32_t rodata_mmu_offset = ((uint32_t)&_rodata_reserved_start & MMU_VADDR_MASK) / MMU_PAGE_SIZE;
// rodata_start_page = ((volatile uint32_t *)(DR_REG_MMU_TABLE + PRO_CACHE_IBUS2_MMU_START))[rodata_mmu_offset];
// rodata_start_page &= MMU_VALID_VAL_MASK;
// rodata_end_page = rodata_start_page + rodata_page_cnt - 1;
// rodata_flash2spiram_offs = rodata_start_page - page_id;
// ESP_EARLY_LOGV(TAG, "Rodata from flash page%d copy to SPIRAM page%d, Offset: %d", rodata_start_page, page_id, rodata_flash2spiram_offs);
uint32_t rodata_page_cnt = ((uint32_t)&_rodata_reserved_end - ((uint32_t)&_rodata_reserved_start & ~ (MMU_PAGE_SIZE - 1)) + MMU_PAGE_SIZE - 1) / MMU_PAGE_SIZE;
rodata_start_page = *(volatile uint32_t *)(DR_REG_MMU_TABLE + CACHE_DROM_MMU_START);
rodata_start_page &= MMU_VALID_VAL_MASK;
rodata_end_page = rodata_start_page + rodata_page_cnt - 1;
rodata_flash2spiram_offs = rodata_start_page - page_id;
ESP_EARLY_LOGE(TAG, "Rodata from flash page%d copy to SPIRAM page%d, Offset: %d", rodata_start_page, page_id, rodata_flash2spiram_offs);
// page_id = Cache_Flash_To_SPIRAM_Copy(PRO_CACHE_IBUS2, DROM0_ADDRESS_LOW, page_id, &page0_page);
// page_id = Cache_Flash_To_SPIRAM_Copy(PRO_CACHE_DBUS0, DRAM0_ADDRESS_LOW, page_id, &page0_page);
// page_id = Cache_Flash_To_SPIRAM_Copy(PRO_CACHE_DBUS1, DRAM1_ADDRESS_LOW, page_id, &page0_page);
// page_id = Cache_Flash_To_SPIRAM_Copy(PRO_CACHE_DBUS2, DPORT_ADDRESS_LOW, page_id, &page0_page);
// rodata_in_spiram = 1;
// ESP_EARLY_LOGV(TAG, "after copy rodata, page_id is %d", page_id);
// ESP_EARLY_LOGI(TAG, "Read only data copied and mapped to SPIRAM");
page_id = Cache_Flash_To_SPIRAM_Copy(CACHE_DBUS, DRAM0_CACHE_ADDRESS_LOW, page_id, &page0_page);
rodata_in_spiram = 1;
ESP_EARLY_LOGV(TAG, "after copy rodata, page_id is %d", page_id);
ESP_EARLY_LOGI(TAG, "Read only data copied and mapped to SPIRAM");
/**
* Disable DRAM0_BUS.
* .text (instructions) are mapped in `Cache_Flash_To_SPIRAM_Copy` to both `PRO_CACHE_IBUS0` and `PRO_CACHE_IBUS1`.
*
* For now, this bus (DRAM0) is only used for copying, so can be disabled. If it is used later, other code
* should be responsible for enabling it.
*/
REG_SET_BIT(EXTMEM_DCACHE_CTRL1_REG, EXTMEM_DCACHE_SHUT_CORE0_BUS);
#if !CONFIG_FREERTOS_UNICORE
REG_SET_BIT(EXTMEM_DCACHE_CTRL1_REG, EXTMEM_DCACHE_SHUT_CORE1_BUS);
#endif
*out_page = page_id - start_page;
return ESP_OK;
}
#endif //#if CONFIG_SPIRAM_RODATA
#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS
uint32_t esp_spiram_instruction_access_enabled(void)
{
return instruction_in_spiram;
}
int instruction_flash2spiram_offset(void)
{
return instr_flash2spiram_offs;
}
uint32_t instruction_flash_start_page_get(void)
{
return instr_start_page;
}
uint32_t instruction_flash_end_page_get(void)
{
return instr_end_page;
}
#endif //CONFIG_SPIRAM_FETCH_INSTRUCTIONS
#if CONFIG_SPIRAM_RODATA
uint32_t esp_spiram_rodata_access_enabled(void)
{
return rodata_in_spiram;
}
int rodata_flash2spiram_offset(void)
{
return rodata_flash2spiram_offs;
}
uint32_t rodata_flash_start_page_get(void)
{
return rodata_start_page;
}
uint32_t rodata_flash_end_page_get(void)
{
return rodata_end_page;
}
#endif //#if CONFIG_SPIRAM_RODATA

View File

@ -1,90 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "soc/spi_mem_reg.h"
#include "esp_err.h"
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
#define PSRAM_SIZE_2MB (2 * 1024 * 1024)
#define PSRAM_SIZE_4MB (4 * 1024 * 1024)
#define PSRAM_SIZE_8MB (8 * 1024 * 1024)
#define PSRAM_SIZE_16MB (16 * 1024 * 1024)
#define PSRAM_SIZE_32MB (32 * 1024 * 1024)
typedef enum {
PSRAM_CACHE_S80M = 1,
PSRAM_CACHE_S40M,
PSRAM_CACHE_MAX,
} psram_cache_mode_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 To get the physical psram size in bytes.
*
* @param[out] out_size_bytes physical psram size in bytes.
*/
esp_err_t psram_get_physical_size(uint32_t *out_size_bytes);
/**
* @brief To get the available physical psram size in bytes.
*
* If ECC is enabled, available PSRAM size will be 15/16 times its physical size.
* If not, it equals to the physical psram size.
* @note For now ECC is only enabled on ESP32S3 Octal PSRAM
*
* @param[out] out_size_bytes availabe physical psram size in bytes.
*/
esp_err_t psram_get_available_size(uint32_t *out_size_bytes);
/**
* @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);
/**
* @brief get psram CS IO
*
* @return psram CS IO
*/
uint8_t psram_get_cs_io(void);
#ifdef __cplusplus
}
#endif

View File

@ -6,10 +6,5 @@
#pragma once
#if CONFIG_IDF_TARGET_ESP32
#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_psram.h"
#warning "esp_spiram.h is deprecated, please migrate to esp_psram.h"

View File

@ -21,12 +21,8 @@
#include "esp_private/sleep_gpio.h"
#include "bootloader_common.h"
#ifdef CONFIG_IDF_TARGET_ESP32
#include "esp32/spiram.h"
#elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/spiram.h"
#elif CONFIG_IDF_TARGET_ESP32S3
#include "esp32s3/spiram.h"
#if CONFIG_SPIRAM
#include "esp_private/esp_psram_io.h"
#endif
static const char *TAG = "sleep";
@ -63,7 +59,7 @@ void esp_sleep_config_gpio_isolate(void)
}
}
#if CONFIG_ESP_SLEEP_PSRAM_LEAKAGE_WORKAROUND && CONFIG_SPIRAM
gpio_sleep_set_pull_mode(esp_spiram_get_cs_io(), GPIO_PULLUP_ONLY);
gpio_sleep_set_pull_mode(esp_psram_io_get_cs_io(), GPIO_PULLUP_ONLY);
#endif
#if CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND
gpio_sleep_set_pull_mode(bootloader_flash_get_cs_io(), GPIO_PULLUP_ONLY);

View File

@ -1,5 +1,5 @@
idf_component_register(SRC_DIRS "."
PRIV_INCLUDE_DIRS "${include_dirs}"
PRIV_REQUIRES cmock test_utils esp_hw_support driver efuse esp_timer)
PRIV_REQUIRES cmock test_utils esp_hw_support driver efuse esp_timer esp_psram)
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u ld_include_test_dport_xt_highint5")

View File

@ -21,3 +21,7 @@ idf_component_register(SRCS ${srcs}
INCLUDE_DIRS ${includes}
PRIV_REQUIRES ${priv_requires}
LDFRAGMENTS linker.lf)
if(CONFIG_SPIRAM)
idf_component_optional_requires(PRIVATE esp_psram)
endif()

View File

@ -32,7 +32,7 @@
#include "driver/gpio.h"
#include "esp_private/periph_ctrl.h"
#if CONFIG_SPIRAM
#include "spiram.h"
#include "esp_psram.h"
#endif
#include "esp_lcd_common.h"
#include "soc/lcd_periph.h"
@ -139,7 +139,7 @@ esp_err_t esp_lcd_new_rgb_panel(const esp_lcd_rgb_panel_config_t *rgb_panel_conf
// fb_in_psram is only an option, if there's no PSRAM on board, we still alloc from SRAM
if (rgb_panel_config->flags.fb_in_psram) {
#if CONFIG_SPIRAM_USE_MALLOC || CONFIG_SPIRAM_USE_CAPS_ALLOC
if (esp_spiram_is_initialized()) {
if (esp_psram_is_initialized()) {
alloc_from_psram = true;
}
#endif

View File

@ -0,0 +1,58 @@
idf_build_get_property(target IDF_TARGET)
set(includes "include")
set(priv_requires efuse heap spi_flash)
if(${target} STREQUAL "esp32")
list(APPEND priv_requires bootloader_support)
# [refactor-todo]: requires "driver" for `spicommon_periph_claim`
list(APPEND priv_requires driver)
endif()
set(srcs)
if(CONFIG_SPIRAM)
list(APPEND srcs "esp_psram.c"
"mmu.c"
"mmu_psram.c")
if(${target} STREQUAL "esp32")
list(APPEND srcs "esp32/esp_psram_extram_cache.c"
"esp32/esp_himem.c")
endif()
if(CONFIG_SPIRAM_MODE_QUAD)
list(APPEND srcs "${target}/esp_psram_impl_quad.c")
elseif(CONFIG_SPIRAM_MODE_OCT)
list(APPEND srcs "${target}/esp_psram_impl_octal.c")
endif()
endif()
idf_component_register(SRCS ${srcs}
INCLUDE_DIRS ${includes}
PRIV_REQUIRES ${priv_requires}
LDFRAGMENTS linker.lf)
if(CONFIG_IDF_TARGET_ESP32 AND CONFIG_SPIRAM_CACHE_WORKAROUND AND NOT BOOTLOADER_BUILD)
# Note: Adding as a PUBLIC compile option here causes this option to propagate to all
# components that depend on esp_psram.
#
# To handle some corner cases, the same flag is set in project_include.cmake
target_compile_options(${COMPONENT_LIB} PUBLIC -mfix-esp32-psram-cache-issue)
# also, make sure we link with this option so correct toolchain libs are pulled in
target_link_libraries(${COMPONENT_LIB} PUBLIC -mfix-esp32-psram-cache-issue)
# set strategy selected
# note that we don't need to set link options as the library linked is independent of this
if(CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_DUPLDST)
target_compile_options(${COMPONENT_LIB} PUBLIC -mfix-esp32-psram-cache-strategy=dupldst)
target_link_libraries(${COMPONENT_LIB} PUBLIC -mfix-esp32-psram-cache-strategy=dupldst)
endif()
if(CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_MEMW)
target_compile_options(${COMPONENT_LIB} PUBLIC -mfix-esp32-psram-cache-strategy=memw)
target_link_libraries(${COMPONENT_LIB} PUBLIC -mfix-esp32-psram-cache-strategy=memw)
endif()
if(CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_NOPS)
target_compile_options(${COMPONENT_LIB} PUBLIC -mfix-esp32-psram-cache-strategy=nops)
target_link_libraries(${COMPONENT_LIB} PUBLIC -mfix-esp32-psram-cache-strategy=nops)
endif()
endif()

View File

@ -0,0 +1,7 @@
menu "ESP PSRAM"
# Will be refactored after !18050 to merge target-specific items
orsource "./$IDF_TARGET/Kconfig.spiram"
endmenu # ESP PSRAM

View File

@ -30,14 +30,6 @@ menu "SPI RAM config"
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
choice SPIRAM_SPEED
prompt "Set RAM clock speed"
default SPIRAM_SPEED_40M
@ -62,8 +54,12 @@ menu "SPI RAM config"
bool "80MHz clock speed"
endchoice
# insert non-chip-specific items here
source "$IDF_PATH/components/esp_hw_support/Kconfig.spiram.common"
config SPIRAM_SPEED
int
default 80 if SPIRAM_SPEED_80M
default 40 if SPIRAM_SPEED_40M
source "$IDF_PATH/components/esp_psram/Kconfig.spiram.common" # insert non-chip-specific items here
config SPIRAM_CACHE_WORKAROUND
bool "Enable workaround for bug in SPI RAM cache for Rev1 ESP32s"
@ -244,7 +240,7 @@ menu "SPI RAM config"
memories, but these have to be bank-switched in and out of this address space. Enabling this allows you
to reserve some MMU pages for this, which allows the use of the esp_himem api to manage these banks.
#Note that this is limited to 62 banks, as esp_spiram_writeback_cache needs some kind of mapping of
#Note that this is limited to 62 banks, as esp_psram_extram_writeback_cache needs some kind of mapping of
#some banks below that mark to work. We cannot at this moment guarantee this to exist when himem is
#enabled.

View File

@ -6,14 +6,15 @@
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp32/spiram.h"
#include "esp_private/spiram_private.h"
#include "esp_psram.h"
#include "esp_private/esp_psram_extram.h"
#include "esp32/rom/cache.h"
#include "sdkconfig.h"
#include "esp_himem.h"
#include "esp32/himem.h"
#include "soc/soc.h"
#include "esp_log.h"
#include "esp_check.h"
#include "../esp_psram_impl.h"
/*
So, why does the API look this way and is so inflexible to not allow any maps beyond the full 32K chunks? Most of
@ -112,7 +113,9 @@ static void set_bank(int virt_bank, int phys_bank, int ct)
size_t esp_himem_get_phys_size(void)
{
int paddr_start = (4096 * 1024) - (CACHE_BLOCKSIZE * SPIRAM_BANKSWITCH_RESERVE);
return esp_spiram_get_size()-paddr_start;
uint32_t psram_available_size = 0;
esp_psram_impl_get_available_size(&psram_available_size);
return psram_available_size - paddr_start;
}
size_t esp_himem_get_free_size(void)
@ -132,7 +135,8 @@ size_t esp_himem_reserved_area_size(void) {
void __attribute__((constructor)) esp_himem_init(void)
{
if (SPIRAM_BANKSWITCH_RESERVE == 0) return;
int maxram=esp_spiram_get_size();
uint32_t maxram = 0;
esp_psram_impl_get_available_size(&maxram);
//catch double init
ESP_RETURN_ON_FALSE(s_ram_descriptor == NULL, , TAG, "already initialized"); //Looks weird; last arg is empty so it expands to 'return ;'
ESP_RETURN_ON_FALSE(s_range_descriptor == NULL, , TAG, "already initialized");
@ -350,7 +354,7 @@ esp_err_t esp_himem_unmap(esp_himem_rangehandle_t range, void *ptr, size_t len)
s_ram_descriptor[ramblock].is_mapped = 0;
s_range_descriptor[range->block_start + i + range_block].is_mapped = 0;
}
esp_spiram_writeback_cache();
esp_psram_extram_writeback_cache();
portEXIT_CRITICAL(&spinlock);
return ESP_OK;
}

View File

@ -0,0 +1,77 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "soc/dport_reg.h"
#include "esp_psram.h"
#include "esp_private/esp_psram_extram.h"
#if CONFIG_FREERTOS_UNICORE
#define PSRAM_MODE PSRAM_VADDR_MODE_NORMAL
#else
#define PSRAM_MODE PSRAM_VADDR_MODE_LOWHIGH
#endif
/*
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.
Note that this routine assumes some unique mapping for the first 2 banks of the PSRAM memory range, as well as the
2 banks after the 2 MiB mark.
*/
void IRAM_ATTR esp_psram_extram_writeback_cache(void)
{
int x;
volatile int i=0;
volatile uint8_t *psram=(volatile uint8_t*)SOC_EXTRAM_DATA_LOW;
int cache_was_disabled=0;
if (!esp_psram_is_initialized()) return;
//We need cache enabled for this to work. Re-enable it if needed; make sure we
//disable it again on exit as well.
if (DPORT_REG_GET_BIT(DPORT_PRO_CACHE_CTRL_REG, DPORT_PRO_CACHE_ENABLE)==0) {
cache_was_disabled|=(1<<0);
DPORT_SET_PERI_REG_BITS(DPORT_PRO_CACHE_CTRL_REG, 1, 1, DPORT_PRO_CACHE_ENABLE_S);
}
#ifndef CONFIG_FREERTOS_UNICORE
if (DPORT_REG_GET_BIT(DPORT_APP_CACHE_CTRL_REG, DPORT_APP_CACHE_ENABLE)==0) {
cache_was_disabled|=(1<<1);
DPORT_SET_PERI_REG_BITS(DPORT_APP_CACHE_CTRL_REG, 1, 1, DPORT_APP_CACHE_ENABLE_S);
}
#endif
#if (PSRAM_MODE != PSRAM_VADDR_MODE_LOWHIGH)
/*
Single-core and even/odd mode only have 32K of cache evenly distributed over the address lines. We can clear
the cache by just reading 64K worth of cache lines.
*/
for (x=0; x<1024*64; x+=32) {
i+=psram[x];
}
#else
/*
Low/high psram cache mode uses one 32K cache for the lowest 2MiB of SPI flash and another 32K for the highest
2MiB. Clear this by reading from both regions.
Note: this assumes the amount of external RAM is >2M. If it is 2M or less, what this code does is undefined. If
we ever support external RAM chips of 2M or smaller, this may need adjusting.
*/
for (x=0; x<1024*64; x+=32) {
i+=psram[x];
i+=psram[x+(1024*1024*2)];
}
#endif
if (cache_was_disabled&(1<<0)) {
while (DPORT_GET_PERI_REG_BITS2(DPORT_PRO_DCACHE_DBUG0_REG, DPORT_PRO_CACHE_STATE, DPORT_PRO_CACHE_STATE_S) != 1) ;
DPORT_SET_PERI_REG_BITS(DPORT_PRO_CACHE_CTRL_REG, 1, 0, DPORT_PRO_CACHE_ENABLE_S);
}
#ifndef CONFIG_FREERTOS_UNICORE
if (cache_was_disabled&(1<<1)) {
while (DPORT_GET_PERI_REG_BITS2(DPORT_APP_DCACHE_DBUG0_REG, DPORT_APP_CACHE_STATE, DPORT_APP_CACHE_STATE_S) != 1);
DPORT_SET_PERI_REG_BITS(DPORT_APP_CACHE_CTRL_REG, 1, 0, DPORT_APP_CACHE_ENABLE_S);
}
#endif
}

View File

@ -16,7 +16,7 @@
#include "esp_types.h"
#include "esp_log.h"
#include "esp_efuse.h"
#include "spiram_psram.h"
#include "../esp_psram_impl.h"
#include "esp32/rom/spi_flash.h"
#include "esp32/rom/cache.h"
#include "esp32/rom/efuse.h"
@ -24,6 +24,7 @@
#include "soc/dport_reg.h"
#include "soc/efuse_periph.h"
#include "soc/soc_caps.h"
#include "soc/spi_periph.h"
#include "driver/gpio.h"
#include "hal/gpio_hal.h"
#include "driver/spi_common_internal.h"
@ -123,6 +124,23 @@ typedef enum {
#define PICO_V3_02_PSRAM_CLK_IO 10
#define PICO_V3_02_PSRAM_CS_IO 9
typedef enum {
PSRAM_CACHE_F80M_S40M = 0,
PSRAM_CACHE_F40M_S40M,
PSRAM_CACHE_F80M_S80M,
PSRAM_CACHE_MAX,
} psram_cache_speed_t;
#if CONFIG_SPIRAM_SPEED_40M && CONFIG_ESPTOOLPY_FLASHFREQ_40M
#define PSRAM_SPEED PSRAM_CACHE_F40M_S40M
#elif CONFIG_SPIRAM_SPEED_40M && CONFIG_ESPTOOLPY_FLASHFREQ_80M
#define PSRAM_SPEED PSRAM_CACHE_F80M_S40M
#elif CONFIG_SPIRAM_SPEED_80M && CONFIG_ESPTOOLPY_FLASHFREQ_80M
#define PSRAM_SPEED PSRAM_CACHE_F80M_S80M
#else
#error "FLASH speed can only be equal to or higher than SRAM speed while SRAM is enabled!"
#endif
typedef struct {
uint8_t flash_clk_io;
uint8_t flash_cs_io;
@ -165,7 +183,7 @@ typedef struct {
#define PSRAM_SPICLKEN DPORT_SPI01_CLK_EN
#endif
static const char* TAG = "psram";
static const char* TAG = "quad_psram";
typedef enum {
PSRAM_SPI_1 = 0x1,
PSRAM_SPI_2,
@ -173,7 +191,7 @@ typedef enum {
PSRAM_SPI_MAX ,
} psram_spi_num_t;
static psram_cache_mode_t s_psram_mode = PSRAM_CACHE_MAX;
static psram_cache_speed_t s_psram_mode = PSRAM_CACHE_MAX;
static psram_clk_mode_t s_clk_mode = PSRAM_CLK_MODE_DCLK;
static uint64_t s_psram_id = 0;
static bool s_2t_mode_enabled = false;
@ -198,11 +216,11 @@ typedef struct {
uint32_t dummyBitLen;
} psram_cmd_t;
static void psram_cache_init(psram_cache_mode_t psram_cache_mode, psram_vaddr_mode_t vaddrmode);
static void psram_cache_init(psram_cache_speed_t psram_cache_mode, psram_vaddr_mode_t vaddrmode);
static uint8_t s_psram_cs_io = (uint8_t)-1;
uint8_t psram_get_cs_io(void)
uint8_t esp_psram_impl_get_cs_io(void)
{
return s_psram_cs_io;
}
@ -667,7 +685,7 @@ void psram_set_cs_timing(psram_spi_num_t spi_num, psram_clk_mode_t clk_mode)
}
//spi param init for psram
void IRAM_ATTR psram_spi_init(psram_spi_num_t spi_num, psram_cache_mode_t mode)
void IRAM_ATTR psram_spi_init(psram_spi_num_t spi_num, psram_cache_speed_t mode)
{
CLEAR_PERI_REG_MASK(SPI_SLAVE_REG(spi_num), SPI_TRANS_DONE << 5);
// SPI_CPOL & SPI_CPHA
@ -687,7 +705,7 @@ void IRAM_ATTR psram_spi_init(psram_spi_num_t spi_num, psram_cache_mode_t mode)
}
//psram gpio init , different working frequency we have different solutions
static void IRAM_ATTR psram_gpio_config(psram_io_t *psram_io, psram_cache_mode_t mode)
static void IRAM_ATTR psram_gpio_config(psram_io_t *psram_io, psram_cache_speed_t mode)
{
int spi_cache_dummy = 0;
uint32_t rd_mode_reg = READ_PERI_REG(SPI_CTRL_REG(0));
@ -784,19 +802,6 @@ static void IRAM_ATTR psram_gpio_config(psram_io_t *psram_io, psram_cache_mode_t
}
}
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 s_2t_mode_enabled ? PSRAM_SIZE_32MBITS : 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;
}
}
//used in UT only
bool psram_is_32mbit_ver0(void)
{
@ -807,8 +812,9 @@ bool psram_is_32mbit_ver0(void)
* 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
esp_err_t IRAM_ATTR esp_psram_impl_enable(psram_vaddr_mode_t vaddrmode) //psram init
{
psram_cache_speed_t mode = PSRAM_SPEED;
psram_io_t psram_io={0};
uint32_t pkg_ver = esp_efuse_get_pkg_ver();
if (pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32D2WDQ5) {
@ -1010,7 +1016,7 @@ esp_err_t IRAM_ATTR psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vad
}
//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)
static void IRAM_ATTR psram_cache_init(psram_cache_speed_t psram_cache_mode, psram_vaddr_mode_t vaddrmode)
{
switch (psram_cache_mode) {
case PSRAM_CACHE_F80M_S80M:
@ -1093,4 +1099,31 @@ static void IRAM_ATTR psram_cache_init(psram_cache_mode_t psram_cache_mode, psra
CLEAR_PERI_REG_MASK(SPI_PIN_REG(0), SPI_CS1_DIS_M); //ENABLE SPI0 CS1 TO PSRAM(CS0--FLASH; CS1--SRAM)
}
esp_err_t esp_psram_impl_get_physical_size(uint32_t *out_size_bytes)
{
if (!out_size_bytes) {
return ESP_ERR_INVALID_ARG;
}
if ((PSRAM_SIZE_ID(s_psram_id) == PSRAM_EID_SIZE_64MBITS) || PSRAM_IS_64MBIT_TRIAL(s_psram_id)) {
*out_size_bytes = s_2t_mode_enabled ? PSRAM_SIZE_4MB : PSRAM_SIZE_8MB;
} else if (PSRAM_SIZE_ID(s_psram_id) == PSRAM_EID_SIZE_32MBITS) {
*out_size_bytes = PSRAM_SIZE_4MB;
} else if (PSRAM_SIZE_ID(s_psram_id) == PSRAM_EID_SIZE_16MBITS) {
*out_size_bytes = PSRAM_SIZE_2MB;
} else {
return ESP_ERR_NOT_SUPPORTED;
}
return ESP_OK;
}
/**
* This function is to get the available physical psram size in bytes.
* On ESP32, all of the PSRAM physical region are available
*/
esp_err_t esp_psram_impl_get_available_size(uint32_t *out_size_bytes)
{
return esp_psram_impl_get_physical_size(out_size_bytes);
}
#endif // CONFIG_SPIRAM

View File

@ -33,14 +33,6 @@ menu "SPI RAM config"
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
menu "PSRAM clock and cs IO for ESP32S2"
depends on SPIRAM
config DEFAULT_PSRAM_CLK_IO
@ -96,6 +88,6 @@ menu "SPI RAM config"
default 40 if SPIRAM_SPEED_26M
default 40 if SPIRAM_SPEED_20M
source "$IDF_PATH/components/esp_hw_support/Kconfig.spiram.common" #insert non-chip-specific items here
source "$IDF_PATH/components/esp_psram/Kconfig.spiram.common" # insert non-chip-specific items here
endmenu

View File

@ -15,28 +15,15 @@
#include "esp_err.h"
#include "esp_types.h"
#include "esp_log.h"
#include "spiram_psram.h"
#include "../esp_psram_impl.h"
#include "esp32s2/rom/spi_flash.h"
#include "esp32s2/rom/opi_flash.h"
#include "esp32s2/rom/cache.h"
#include "esp32s2/rom/efuse.h"
#include "esp_rom_efuse.h"
#include "soc/dport_reg.h"
#include "soc/efuse_periph.h"
#include "soc/soc_caps.h"
#include "soc/spi_reg.h"
#include "soc/io_mux_reg.h"
#include "soc/syscon_reg.h"
#include "soc/efuse_reg.h"
#include "soc/soc.h"
#include "driver/gpio.h"
#include "driver/spi_common_internal.h"
#include "driver/spi_common.h"
#include "esp_private/periph_ctrl.h"
#include "bootloader_common.h"
#include "soc/rtc.h"
static const char* TAG = "psram";
static const char* TAG = "quad_psram";
//Commands for PSRAM chip
#define PSRAM_READ 0x03
@ -153,15 +140,31 @@ typedef enum {
PSRAM_CMD_SPI,
} psram_cmd_mode_t;
typedef enum {
PSRAM_CACHE_S80M = 1,
PSRAM_CACHE_S40M,
PSRAM_CACHE_S26M,
PSRAM_CACHE_S20M,
PSRAM_CACHE_MAX,
} psram_cache_speed_t;
#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
typedef esp_rom_spi_cmd_t psram_cmd_t;
static uint32_t s_psram_id = 0;
static void psram_cache_init(psram_cache_mode_t psram_cache_mode, psram_vaddr_mode_t vaddrmode);
static void psram_cache_init(psram_cache_speed_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 uint8_t s_psram_cs_io = (uint8_t)-1;
uint8_t psram_get_cs_io(void)
uint8_t esp_psram_impl_get_cs_io(void)
{
return s_psram_cs_io;
}
@ -357,7 +360,7 @@ static void psram_set_spi0_cache_cs_timing(psram_clk_mode_t clk_mode)
}
//psram gpio init , different working frequency we have different solutions
static void IRAM_ATTR psram_gpio_config(psram_cache_mode_t mode)
static void IRAM_ATTR psram_gpio_config(psram_cache_speed_t mode)
{
psram_io_t psram_io = PSRAM_IO_CONF_DEFAULT();
const uint32_t spiconfig = esp_rom_efuse_get_flash_gpio_info();
@ -395,8 +398,9 @@ static void psram_set_clk_mode(int spi_num, psram_clk_mode_t 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
esp_err_t IRAM_ATTR esp_psram_impl_enable(psram_vaddr_mode_t vaddrmode) //psram init
{
psram_cache_speed_t mode = PSRAM_SPEED;
assert(mode < PSRAM_CACHE_MAX && "we don't support any other mode for now.");
// GPIO related settings
psram_gpio_config(mode);
@ -468,7 +472,7 @@ static void IRAM_ATTR psram_clock_set(int spi_num, int8_t freqdiv)
}
//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)
static void IRAM_ATTR psram_cache_init(psram_cache_speed_t psram_cache_mode, psram_vaddr_mode_t vaddrmode)
{
int extra_dummy = 0;
switch (psram_cache_mode) {
@ -533,7 +537,7 @@ static void IRAM_ATTR psram_cache_init(psram_cache_mode_t psram_cache_mode, psra
*
* Consider moving these to another file if this kind of APIs grows dramatically
*-------------------------------------------------------------------------------*/
esp_err_t psram_get_physical_size(uint32_t *out_size_bytes)
esp_err_t esp_psram_impl_get_physical_size(uint32_t *out_size_bytes)
{
if (!out_size_bytes) {
return ESP_ERR_INVALID_ARG;
@ -555,7 +559,7 @@ esp_err_t psram_get_physical_size(uint32_t *out_size_bytes)
* This function is to get the available physical psram size in bytes.
* On ESP32S2, all of the PSRAM physical region are available
*/
esp_err_t psram_get_available_size(uint32_t *out_size_bytes)
esp_err_t esp_psram_impl_get_available_size(uint32_t *out_size_bytes)
{
return psram_get_physical_size(out_size_bytes);
return esp_psram_impl_get_physical_size(out_size_bytes);
}

View File

@ -42,16 +42,6 @@ menu "SPI RAM config"
bool "ESP-PSRAM64 , LY68L6400 or APS6408"
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 16777216 if SPIRAM_TYPE_ESPPSRAM128
default 33554432 if SPIRAM_TYPE_ESPPSRAM256
default 0
menu "PSRAM Clock and CS IO for ESP32S3"
depends on SPIRAM
config DEFAULT_PSRAM_CLK_IO
@ -104,6 +94,6 @@ menu "SPI RAM config"
default 80 if SPIRAM_SPEED_80M
default 40 if SPIRAM_SPEED_40M
source "$IDF_PATH/components/esp_hw_support/Kconfig.spiram.common" # insert non-chip-specific items here
source "$IDF_PATH/components/esp_psram/Kconfig.spiram.common" # insert non-chip-specific items here
endmenu

View File

@ -10,22 +10,14 @@
#include "esp_err.h"
#include "esp_types.h"
#include "esp_log.h"
#include "spiram_psram.h"
#include "../esp_psram_impl.h"
#include "esp32s3/rom/ets_sys.h"
#include "esp32s3/rom/spi_flash.h"
#include "esp32s3/rom/opi_flash.h"
#include "esp32s3/rom/gpio.h"
#include "esp32s3/rom/cache.h"
#include "soc/gpio_periph.h"
#include "soc/io_mux_reg.h"
#include "soc/dport_reg.h"
#include "soc/syscon_reg.h"
#include "soc/gpio_sig_map.h"
#include "soc/efuse_reg.h"
#include "driver/gpio.h"
#include "driver/spi_common.h"
#include "esp_private/periph_ctrl.h"
#include "soc/rtc.h"
#include "esp_private/spi_flash_os.h"
#define OPI_PSRAM_SYNC_READ 0x0000
@ -102,11 +94,11 @@ typedef struct {
} mr8;
} opi_psram_mode_reg_t;
static const char* TAG = "opi psram";
static const char* TAG = "octal_psram";
static uint32_t s_psram_size; //this stands for physical psram size in bytes
static void s_config_psram_spi_phases(void);
uint8_t psram_get_cs_io(void)
uint8_t esp_psram_impl_get_cs_io(void)
{
return OCT_PSRAM_CS1_IO;
}
@ -295,7 +287,7 @@ static void s_configure_psram_ecc(void)
#endif
}
esp_err_t psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vaddrmode)
esp_err_t esp_psram_impl_enable(psram_vaddr_mode_t vaddrmode)
{
s_init_psram_pins();
s_set_psram_cs_timing();
@ -379,7 +371,7 @@ static void s_config_psram_spi_phases(void)
*
* Consider moving these to another file if this kind of APIs grows dramatically
*-------------------------------------------------------------------------------*/
esp_err_t psram_get_physical_size(uint32_t *out_size_bytes)
esp_err_t esp_psram_impl_get_physical_size(uint32_t *out_size_bytes)
{
if (!out_size_bytes) {
return ESP_ERR_INVALID_ARG;
@ -393,7 +385,7 @@ esp_err_t psram_get_physical_size(uint32_t *out_size_bytes)
* This function is to get the available physical psram size in bytes.
* If ECC is enabled, available PSRAM size will be 15/16 times its physical size.
*/
esp_err_t psram_get_available_size(uint32_t *out_size_bytes)
esp_err_t esp_psram_impl_get_available_size(uint32_t *out_size_bytes)
{
if (!out_size_bytes) {
return ESP_ERR_INVALID_ARG;

View File

@ -11,30 +11,15 @@
#include "esp_err.h"
#include "esp_types.h"
#include "esp_log.h"
#include "spiram_psram.h"
#include "../esp_psram_impl.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/soc_caps.h"
#include "soc/io_mux_reg.h"
#include "soc/efuse_reg.h"
#include "soc/soc.h"
#include "soc/io_mux_reg.h"
#include "driver/gpio.h"
#include "hal/gpio_hal.h"
#include "driver/spi_common_internal.h"
#include "driver/spi_common.h"
#include "esp_private/periph_ctrl.h"
#include "bootloader_common.h"
#include "soc/rtc.h"
#include "esp_private/spi_flash_os.h"
static const char* TAG = "psram";
static const char* TAG = "quad_psram";
//Commands for PSRAM chip
#define PSRAM_READ 0x03
@ -96,8 +81,6 @@ static const char* TAG = "psram";
#define SPI1_NUM 1
#define SPI0_NUM 0
typedef enum {
PSRAM_CMD_QPI,
PSRAM_CMD_SPI,
@ -112,7 +95,7 @@ extern void esp_rom_spi_set_op_mode(int spi_num, esp_rom_spiflash_read_mode_t mo
static uint8_t s_psram_cs_io = (uint8_t)-1;
uint8_t psram_get_cs_io(void)
uint8_t esp_psram_impl_get_cs_io(void)
{
return s_psram_cs_io;
}
@ -314,14 +297,8 @@ static void psram_gpio_config(void)
esp_rom_spiflash_select_qio_pins(wp_io, spiconfig);
}
/*
* 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 psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vaddrmode) //psram init
esp_err_t esp_psram_impl_enable(psram_vaddr_mode_t vaddrmode) //psram init
{
assert(mode < PSRAM_CACHE_MAX && "we don't support any other mode for now.");
psram_gpio_config();
psram_set_cs_timing();
@ -401,7 +378,7 @@ static void config_psram_spi_phases(void)
*
* Consider moving these to another file if this kind of APIs grows dramatically
*-------------------------------------------------------------------------------*/
esp_err_t psram_get_physical_size(uint32_t *out_size_bytes)
esp_err_t esp_psram_impl_get_physical_size(uint32_t *out_size_bytes)
{
if (!out_size_bytes) {
return ESP_ERR_INVALID_ARG;
@ -417,7 +394,7 @@ esp_err_t psram_get_physical_size(uint32_t *out_size_bytes)
* When ECC is enabled, the available size will be reduced.
* On S3 Quad PSRAM, ECC is not enabled for now.
*/
esp_err_t psram_get_available_size(uint32_t *out_size_bytes)
esp_err_t esp_psram_impl_get_available_size(uint32_t *out_size_bytes)
{
if (!out_size_bytes) {
return ESP_ERR_INVALID_ARG;

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -11,37 +11,50 @@
*
* When we add more types of external RAM memory, this can be made into a more intelligent dispatcher.
*----------------------------------------------------------------------------------------------------*/
#include <stdint.h>
#include <string.h>
#include <sys/param.h>
#include "sdkconfig.h"
#include "esp_attr.h"
#include "esp_err.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/xtensa_api.h"
#include "esp_heap_caps_init.h"
#include "esp_private/spiram_private.h"
#include "esp32s3/spiram.h"
#include "spiram_psram.h"
#include "hal/mmu_hal.h"
#include "hal/cache_ll.h"
#include "esp_private/mmu_psram.h"
#include "esp_private/esp_psram_io.h"
#include "esp_private/esp_psram_extram.h"
#include "esp_private/mmu.h"
#include "esp_psram_impl.h"
#include "esp_psram.h"
#define PSRAM_MODE PSRAM_VADDR_MODE_NORMAL
#define MMU_PAGE_SIZE (0x10000)
#define ALIGN_UP_BY(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
#define MMU_PAGE_TO_BYTES(page_id) ((page_id) << 16)
#if CONFIG_SPIRAM_SPEED_40M
#define PSRAM_SPEED PSRAM_CACHE_S40M
#else //#if CONFIG_SPIRAM_SPEED_80M
#define PSRAM_SPEED PSRAM_CACHE_S80M
#if CONFIG_IDF_TARGET_ESP32
#include "esp32/himem.h"
#include "esp32/rom/cache.h"
#endif
static const char *TAG = "spiram";
static bool s_spiram_inited;
#if CONFIG_IDF_TARGET_ESP32
#if CONFIG_FREERTOS_UNICORE
#define PSRAM_MODE PSRAM_VADDR_MODE_NORMAL
#else
#define PSRAM_MODE PSRAM_VADDR_MODE_LOWHIGH
#endif
#else
#define PSRAM_MODE PSRAM_VADDR_MODE_NORMAL
#endif
#if CONFIG_SPIRAM
#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
extern uint8_t _ext_ram_bss_start;
extern uint8_t _ext_ram_bss_end;
#endif //#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
#if CONFIG_SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY
extern uint8_t _ext_ram_noinit_start;
extern uint8_t _ext_ram_noinit_end;
#endif //#if CONFIG_SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY
//These variables are in bytes
static intptr_t s_allocable_vaddr_start;
@ -49,22 +62,37 @@ static intptr_t s_allocable_vaddr_end;
static intptr_t s_mapped_vaddr_start;
static intptr_t s_mapped_vaddr_end;
#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
extern uint8_t _ext_ram_bss_start;
extern uint8_t _ext_ram_bss_end;
#endif //#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
static bool s_spiram_inited;
static const char* TAG = "esp_psram";
static bool esp_spiram_test(uint32_t v_start, uint32_t size);
#if CONFIG_IDF_TARGET_ESP32
//If no function in esp_himem.c is used, this function will be linked into the
//binary instead of the one in esp_himem.c, automatically making sure no memory
//is reserved if no himem function is used.
size_t __attribute__((weak)) esp_himem_reserved_area_size(void) {
return 0;
}
esp_err_t esp_spiram_init(void)
static void IRAM_ATTR s_mapping(int v_start, int size)
{
assert(!s_spiram_inited);
//Enable external RAM in MMU
cache_sram_mmu_set(0, 0, v_start, 0, 32, (size / 1024 / 32));
//Flush and enable icache for APP CPU
#if !CONFIG_FREERTOS_UNICORE
DPORT_CLEAR_PERI_REG_MASK(DPORT_APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MASK_DRAM1);
cache_sram_mmu_set(1, 0, v_start, 0, 32, (size / 1024 / 32));
#endif
}
#endif //CONFIG_IDF_TARGET_ESP32
esp_err_t esp_psram_init(void)
{
if (s_spiram_inited) {
return ESP_ERR_INVALID_STATE;
}
esp_err_t ret;
uint32_t psram_physical_size = 0;
ret = psram_enable(PSRAM_SPEED, PSRAM_MODE);
ret = esp_psram_impl_enable(PSRAM_MODE);
if (ret != ESP_OK) {
#if CONFIG_SPIRAM_IGNORE_NOTFOUND
ESP_EARLY_LOGE(TAG, "SPI RAM enabled but initialization failed. Bailing out.");
@ -73,23 +101,23 @@ esp_err_t esp_spiram_init(void)
}
s_spiram_inited = true;
ret = psram_get_physical_size(&psram_physical_size);
uint32_t psram_physical_size = 0;
ret = esp_psram_impl_get_physical_size(&psram_physical_size);
assert(ret == ESP_OK);
#if (CONFIG_SPIRAM_SIZE != -1)
if (psram_physical_size != CONFIG_SPIRAM_SIZE) {
ESP_EARLY_LOGE(TAG, "Expected %dMB chip but found %dMB chip. Bailing out..", (CONFIG_SPIRAM_SIZE / 1024 / 1024), (psram_physical_size / 1024 / 1024));
return ESP_ERR_INVALID_SIZE;
}
#endif
ESP_EARLY_LOGI(TAG, "Found %dMB SPI RAM device", psram_physical_size / (1024 * 1024));
ESP_EARLY_LOGI(TAG, "Found %dMBit SPI RAM device", psram_physical_size / (1024 * 1024));
ESP_EARLY_LOGI(TAG, "Speed: %dMHz", CONFIG_SPIRAM_SPEED);
#if CONFIG_IDF_TARGET_ESP32
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");
#endif
uint32_t psram_available_size = 0;
ret = psram_get_available_size(&psram_available_size);
ret = esp_psram_impl_get_available_size(&psram_available_size);
assert(ret == ESP_OK);
__attribute__((unused)) uint32_t total_available_size = psram_available_size;
/**
* `start_page` is the psram physical address in MMU page size.
@ -98,7 +126,7 @@ esp_err_t esp_spiram_init(void)
*
* Here we plan to copy FLASH instructions to psram physical address 0, which is the No.0 page.
*/
uint32_t start_page = 0;
__attribute__((unused)) uint32_t start_page = 0;
#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS || CONFIG_SPIRAM_RODATA
uint32_t used_page = 0;
#endif
@ -128,22 +156,16 @@ esp_err_t esp_spiram_init(void)
#endif //#if CONFIG_SPIRAM_RODATA
//----------------------------------Map the PSRAM physical range to MMU-----------------------------//
uint32_t vaddr_start = 0;
extern uint32_t _rodata_reserved_end;
uint32_t rodata_end_aligned = ALIGN_UP_BY((uint32_t)&_rodata_reserved_end, MMU_PAGE_SIZE);
vaddr_start = rodata_end_aligned;
ESP_EARLY_LOGV(TAG, "rodata_end_aligned is 0x%x bytes", rodata_end_aligned);
if (vaddr_start + psram_available_size > DRAM0_CACHE_ADDRESS_HIGH) {
//Decide these logics when there's a real PSRAM with larger size
ESP_EARLY_LOGE(TAG, "Virtual address not enough for PSRAM!");
abort();
intptr_t vaddr_start = mmu_get_psram_vaddr_start();
if (vaddr_start + psram_available_size > mmu_get_psram_vaddr_end()) {
ESP_EARLY_LOGV(TAG, "Virtual address not enough for PSRAM!");
psram_available_size = mmu_get_psram_vaddr_end() - vaddr_start;
}
//On ESP32S3, MMU is shared for both of the cores. Note this when porting `spiram.c`
#if CONFIG_IDF_TARGET_ESP32
s_mapping(vaddr_start, psram_available_size);
#else
uint32_t actual_mapped_len = 0;
mmu_hal_map_region(0, MMU_TARGET_PSRAM0, vaddr_start, MMU_PAGE_TO_BYTES(start_page), psram_available_size, &actual_mapped_len);
ESP_EARLY_LOGV(TAG, "actual_mapped_len is 0x%x bytes", actual_mapped_len);
@ -154,16 +176,7 @@ esp_err_t esp_spiram_init(void)
bus_mask = cache_ll_l1_get_bus(1, vaddr_start, actual_mapped_len);
cache_ll_l1_enable_bus(1, bus_mask);
#endif
#if CONFIG_SPIRAM_MEMTEST
//After mapping, simple test SPIRAM first
bool ext_ram_ok = esp_spiram_test(vaddr_start, psram_available_size);
if (!ext_ram_ok) {
ESP_EARLY_LOGE(TAG, "External RAM failed memory test!");
abort();
}
#endif //#if CONFIG_SPIRAM_MEMTEST
#endif //#if CONFIG_IDF_TARGET_ESP32
/*------------------------------------------------------------------------------
* After mapping, we DON'T care about the PSRAM PHYSICAL ADDRESSS ANYMORE!
@ -173,16 +186,24 @@ esp_err_t esp_spiram_init(void)
s_allocable_vaddr_start = vaddr_start;
s_allocable_vaddr_end = vaddr_start + psram_available_size;
//------------------------------------Configure .bss in PSRAM-------------------------------------//
#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
//should never be negative number
uint32_t ext_bss_size = ((intptr_t)&_ext_ram_bss_end - (intptr_t)&_ext_ram_bss_start);
ESP_EARLY_LOGV(TAG, "_ext_ram_bss_start is 0x%x, _ext_ram_bss_start is 0x%x, ext_bss_size is 0x%x bytes", &_ext_ram_bss_start, &_ext_ram_bss_end, ext_bss_size);
ESP_EARLY_LOGV(TAG, "ext_bss_size is %d", ext_bss_size);
s_allocable_vaddr_start += ext_bss_size;
#endif //#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
#if CONFIG_SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY
uint32_t ext_noinit_size = ((intptr_t)&_ext_ram_noinit_end - (intptr_t)&_ext_ram_noinit_start);
ESP_EARLY_LOGV(TAG, "ext_noinit_size is %d", ext_noinit_size);
s_allocable_vaddr_start += ext_noinit_size;
#endif
#if CONFIG_IDF_TARGET_ESP32
s_allocable_vaddr_end -= esp_himem_reserved_area_size() - 1;
#endif
ESP_EARLY_LOGV(TAG, "s_allocable_vaddr_start is 0x%x, s_allocable_vaddr_end is 0x%x", s_allocable_vaddr_start, s_allocable_vaddr_end);
return ESP_OK;
}
@ -191,13 +212,13 @@ esp_err_t esp_spiram_init(void)
* Add the PSRAM available region to heap allocator. Heap allocator knows the capabilities of this type of memory,
* so there's no need to explicitly specify them.
*/
esp_err_t esp_spiram_add_to_heapalloc(void)
esp_err_t esp_psram_extram_add_to_heap_allocator(void)
{
ESP_EARLY_LOGI(TAG, "Adding pool of %dK of external SPI memory to heap allocator", (s_allocable_vaddr_end - s_allocable_vaddr_start) / 1024);
return heap_caps_add_region(s_allocable_vaddr_start, s_allocable_vaddr_end);
}
esp_err_t IRAM_ATTR esp_spiram_get_mapped_range(intptr_t *out_vstart, intptr_t *out_vend)
esp_err_t IRAM_ATTR esp_psram_extram_get_mapped_range(intptr_t *out_vstart, intptr_t *out_vend)
{
if (!out_vstart || !out_vend) {
return ESP_ERR_INVALID_ARG;
@ -212,7 +233,7 @@ esp_err_t IRAM_ATTR esp_spiram_get_mapped_range(intptr_t *out_vstart, intptr_t *
return ESP_OK;
}
esp_err_t esp_spiram_get_alloced_range(intptr_t *out_vstart, intptr_t *out_vend)
esp_err_t esp_psram_extram_get_alloced_range(intptr_t *out_vstart, intptr_t *out_vend)
{
if (!out_vstart || !out_vend) {
return ESP_ERR_INVALID_ARG;
@ -227,12 +248,36 @@ esp_err_t esp_spiram_get_alloced_range(intptr_t *out_vstart, intptr_t *out_vend)
return ESP_OK;
}
esp_err_t esp_spiram_reserve_dma_pool(size_t size)
#if CONFIG_IDF_TARGET_ESP32
esp_err_t esp_psram_extram_reserve_dma_pool(size_t size) {
ESP_EARLY_LOGI(TAG, "Reserving pool of %dK of internal memory for DMA/internal allocations", size/1024);
/* Pool may be allocated in multiple non-contiguous chunks, depending on available RAM */
while (size > 0) {
size_t next_size = heap_caps_get_largest_free_block(MALLOC_CAP_DMA|MALLOC_CAP_INTERNAL);
next_size = MIN(next_size, size);
ESP_EARLY_LOGD(TAG, "Allocating block of size %d bytes", next_size);
uint8_t *dma_heap = heap_caps_malloc(next_size, MALLOC_CAP_DMA|MALLOC_CAP_INTERNAL);
if (!dma_heap || next_size == 0) {
return ESP_ERR_NO_MEM;
}
uint32_t caps[] = { 0, MALLOC_CAP_DMA|MALLOC_CAP_INTERNAL, MALLOC_CAP_8BIT|MALLOC_CAP_32BIT };
esp_err_t e = heap_caps_add_region_with_caps(caps, (intptr_t) dma_heap, (intptr_t) dma_heap+next_size-1);
if (e != ESP_OK) {
return e;
}
size -= next_size;
}
return ESP_OK;
}
#else
esp_err_t esp_psram_extram_reserve_dma_pool(size_t size)
{
if (size == 0) {
return ESP_OK;
return ESP_OK; //no-op
}
ESP_EARLY_LOGI(TAG, "Reserving pool of %dK of internal memory for DMA/internal allocations", size / 1024);
ESP_EARLY_LOGI(TAG, "Reserving pool of %dK of internal memory for DMA/internal allocations", size/1024);
uint8_t *dma_heap = heap_caps_malloc(size, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
if (!dma_heap) {
return ESP_ERR_NO_MEM;
@ -240,31 +285,27 @@ esp_err_t esp_spiram_reserve_dma_pool(size_t size)
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);
}
#endif
/*
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();
}
/**
* @brief If SPI RAM(PSRAM) has been initialized
*
* @return true SPI RAM has been initialized successfully
* @return false SPI RAM hasn't been initialized or initialized failed
*/
bool esp_spiram_is_initialized(void)
bool IRAM_ATTR esp_psram_is_initialized(void)
{
return s_spiram_inited;
}
uint8_t esp_spiram_get_cs_io(void)
size_t esp_psram_get_size(void)
{
return psram_get_cs_io();
uint32_t available_size = 0;
esp_err_t ret = esp_psram_impl_get_available_size(&available_size);
if (ret != ESP_OK) {
//This means PSRAM isn't initialised, to keep back-compatibility, set size to 0.
available_size = 0;
}
return (size_t)available_size;
}
uint8_t esp_psram_io_get_cs_io(void)
{
return esp_psram_impl_get_cs_io();
}
/*
@ -272,34 +313,45 @@ uint8_t esp_spiram_get_cs_io(void)
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.
*/
static bool esp_spiram_test(uint32_t v_start, uint32_t size)
bool esp_psram_extram_test(void)
{
volatile int *spiram = (volatile int *)v_start;
#if CONFIG_SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY
const void *keepout_addr_low = (const void*)&_ext_ram_noinit_start;
const void *keepout_addr_high = (const void*)&_ext_ram_noinit_end;
#else
const void *keepout_addr_low = 0;
const void *keepout_addr_high = 0;
#endif
size_t s = size;
volatile int *spiram = (volatile int *)s_mapped_vaddr_start;
size_t p;
int errct = 0;
int initial_err = -1;
for (p = 0; p < (s / sizeof(int)); p += 8) {
spiram[p] = p ^ 0xAAAAAAAA;
size_t s = s_mapped_vaddr_end - s_mapped_vaddr_start;
int errct=0;
int initial_err=-1;
for (p=0; p<(s/sizeof(int)); p+=8) {
const void *addr = (const void *)&spiram[p];
if ((keepout_addr_low <= addr) && (addr < keepout_addr_high)) {
continue;
}
spiram[p]=p^0xAAAAAAAA;
}
for (p = 0; p < (s / sizeof(int)); p += 8) {
if (spiram[p] != (p ^ 0xAAAAAAAA)) {
for (p=0; p<(s/sizeof(int)); p+=8) {
const void *addr = (const void *)&spiram[p];
if ((keepout_addr_low <= addr) && (addr < keepout_addr_high)) {
continue;
}
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==1) initial_err=p*4;
}
}
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);
ESP_EARLY_LOGE(TAG, "SPI SRAM memory test fail. %d/%d writes failed, first @ %X\n", errct, s/32, initial_err + s_mapped_vaddr_start);
return false;
} else {
ESP_EARLY_LOGI(TAG, "SPI SRAM memory test OK");
return true;
}
}
#endif //#if CONFIG_SPIRAM

View File

@ -6,7 +6,6 @@
#pragma once
#include "soc/spi_mem_reg.h"
#include "esp_err.h"
#include "sdkconfig.h"
@ -17,14 +16,8 @@ extern "C" {
#define PSRAM_SIZE_2MB (2 * 1024 * 1024)
#define PSRAM_SIZE_4MB (4 * 1024 * 1024)
#define PSRAM_SIZE_8MB (8 * 1024 * 1024)
typedef enum {
PSRAM_CACHE_S80M = 1,
PSRAM_CACHE_S40M,
PSRAM_CACHE_S26M,
PSRAM_CACHE_S20M,
PSRAM_CACHE_MAX,
} psram_cache_mode_t;
#define PSRAM_SIZE_16MB (16 * 1024 * 1024)
#define PSRAM_SIZE_32MB (32 * 1024 * 1024)
/*
@ -45,41 +38,28 @@ typedef enum {
*
* @param[out] out_size_bytes physical psram size in bytes.
*/
esp_err_t psram_get_physical_size(uint32_t *out_size_bytes);
esp_err_t esp_psram_impl_get_physical_size(uint32_t *out_size_bytes);
/**
* @brief To get the available physical psram size in bytes.
*
* @note On ESP32S2, all of the PSRAM physical region are available
*
* @param[out] out_size_bytes availabe physical psram size in bytes.
*/
esp_err_t psram_get_available_size(uint32_t *out_size_bytes);
esp_err_t esp_psram_impl_get_available_size(uint32_t *out_size_bytes);
/**
* @brief psram cache enable function
* @brief Enable psram and configure it to a ready state
*
* 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.
* @return
* - ESP_OK: On success,
* - ESP_ERR_INVALID_STATE: On esp32, 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);
esp_err_t esp_psram_impl_enable(psram_vaddr_mode_t vaddrmode);
/**
* @brief get psram CS IO
*
* @return psram CS IO
*/
uint8_t psram_get_cs_io(void);
uint8_t esp_psram_impl_get_cs_io(void);

View File

@ -0,0 +1,84 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stddef.h>
#include <stdbool.h>
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Get the psram mapped vaddr range
*
* @param[out] out_vstart PSRAM virtual address start
* @param[out] out_vend PSRAM virtual address end
*
* @return
* - ESP_OK On success
* - ESP_ERR_INVALID_STATE PSRAM is not initialized successfully
*/
esp_err_t esp_psram_extram_get_mapped_range(intptr_t *out_vstart, intptr_t *out_vend);
/**
* @brief Get the psram alloced vaddr range
*
* @param[out] out_vstart PSRAM virtual address start
* @param[out] out_vend PSRAM virtual address end
*
* @return
* - ESP_OK On success
* - ESP_ERR_INVALID_STATE PSRAM is not initialized successfully
*/
esp_err_t esp_psram_extram_get_alloced_range(intptr_t *out_vstart, intptr_t *out_vend);
/**
* @brief Add the initialized PSRAM to the heap allocator.
*
* @return
* - ESP_OK: On success
* Other error type, see `heap_caps_add_region`.
*/
esp_err_t esp_psram_extram_add_to_heap_allocator(void);
/**
* @brief Reserve a pool of internal memory for specific DMA/internal allocations
*
* @param size Size of reserved pool in bytes
*
* @return
* - ESP_OK: On success
* - ESP_ERR_NO_MEM: When no memory available for pool
*/
esp_err_t esp_psram_extram_reserve_dma_pool(size_t size);
/**
* @brief Memory test for PSRAM. Should be called after PSRAM is initialized and
* (in case of a dual-core system) the app CPU is online. This test overwrites the
* memory with crap, so do not call after e.g. the heap allocator has stored important
* stuff in PSRAM.
*
* @return true on success, false on failed memory test
*/
bool esp_psram_extram_test(void);
#if CONFIG_IDF_TARGET_ESP32
/**
* @brief Force a writeback of the data in the PSRAM cache. This is to be called whenever
* cache is disabled, because disabling cache on the ESP32 discards the data in the PSRAM
* cache.
*
* This is meant for use from within the SPI flash code.
*/
void esp_psram_extram_writeback_cache(void);
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,31 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stddef.h>
#include <stdbool.h>
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief get psram CS IO
*
* This interface should be called after PSRAM is enabled, otherwise it will
* return an invalid value -1/0xff.
*
* @return psram CS IO or -1/0xff if psram not enabled
*/
uint8_t esp_psram_io_get_cs_io(void);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,140 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* This file will be redesigned into MMU driver, to maintain all the external
* memory contexts including:
* - Flash
* - PSRAM
* - DDR
*
* Now only MMU-PSRAM related private APIs
*/
#pragma once
#include <sys/param.h>
#include "esp_err.h"
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
#if CONFIG_IDF_TARGET_ESP32
#define MMU_PAGE_SIZE 0x8000
#else
#define MMU_PAGE_SIZE 0x10000
#define MMU_PAGE_TO_BYTES(page_id) ((page_id) * MMU_PAGE_SIZE)
#define BYTES_TO_MMU_PAGE(bytes) ((bytes) / MMU_PAGE_SIZE)
#endif
/**
* @brief Get the vaddr start for PSRAM
*
* @return PSRAM vaddr start address
*/
intptr_t mmu_get_psram_vaddr_start(void);
/**
* @brief Get the vaddr end for PSRAM
*
* @return PSRAM vaddr end address
*/
intptr_t mmu_get_psram_vaddr_end(void);
#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS
/**
* @brief Copy Flash texts to PSRAM
*
* @param[in] start_page PSRAM physical start page
* @param[in] psram_size PSRAM available size
* @param[out] out_page Used pages
*/
esp_err_t mmu_config_psram_text_segment(uint32_t start_page, uint32_t psram_size, uint32_t *out_page);
/**
* @brief Init other file requested MMU variables
*
* - These logics are abstracted from the PSRAM driver
* - These functions are only required by `flash_mmap.c` for converting paddr to vaddr, and vice versa
* - The `flash_mmpa.c` will be rewritten into MMU driver
*
* Therefore, keep the APIs here for now
*/
void instruction_flash_page_info_init(uint32_t psram_start_physical_page);
/**
* @brief Get the start page number of the instruction in SPI flash
*
* @return start page number
*/
uint32_t instruction_flash_start_page_get(void);
/**
* @brief Get the end page number of the instruction in SPI flash
*
* @return end page number
*/
uint32_t instruction_flash_end_page_get(void);
/**
* @brief Get the offset of instruction from SPI flash to SPI RAM
*
* @return instruction offset
*/
int instruction_flash2spiram_offset(void);
#endif // #if CONFIG_SPIRAM_FETCH_INSTRUCTIONS
#if CONFIG_SPIRAM_RODATA
/**
* @brief Copy Flash rodata to PSRAM
*
* @param[in] start_page PSRAM physical start page
* @param[in] psram_size PSRAM available size
* @param[out] out_page Used pages
*/
esp_err_t mmu_config_psram_rodata_segment(uint32_t start_page, uint32_t psram_size, uint32_t *out_page);
/**
* @brief Init other file requested MMU variables
*
* - These logics are abstracted from the PSRAM driver
* - These functions are only required by `flash_mmap.c` for converting paddr to vaddr, and vice versa
* - The `flash_mmpa.c` will be rewritten into MMU driver
*
* Therefore, keep the APIs here for now
*/
void rodata_flash_page_info_init(uint32_t psram_start_physical_page);
/**
* @brief Get the start page number of the rodata in SPI flash
*
* @return start page number
*/
uint32_t rodata_flash_start_page_get(void);
/**
* @brief Get the end page number of the rodata in SPI flash
*
* @return end page number
*/
uint32_t rodata_flash_end_page_get(void);
/**
* @brief Get the offset number of rodata from SPI flash to SPI RAM
*
* @return rodata offset
*/
int rodata_flash2spiram_offset(void);
#endif // #if CONFIG_SPIRAM_RODATA
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,47 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Initialize PSRAM interface/hardware.
*
* @return
* - ESP_OK: On success
* - ESP_FAIL: PSRAM isn't initialized successfully, potential reason would be: wrong VDDSDIO, invalid chip ID, etc.
* - ESP_ERR_INVALID_STATE: PSRAM is initialized already
*/
esp_err_t esp_psram_init(void);
/**
* @brief If PSRAM has been initialized
*
* @return
* - true: PSRAM has been initialized successfully
* - false: PSRAM hasn't been initialized or initialized failed
*/
bool esp_psram_is_initialized(void);
/**
* @brief Get the available size of the attached PSRAM chip
*
* @return Size in bytes, or 0 if PSRAM isn't successfully initialized
*/
size_t esp_psram_get_size(void);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,17 @@
[mapping:esp_psram]
archive: libesp_psram.a
entries:
if SPIRAM = y:
mmu (noflash)
if SPIRAM_MODE_QUAD = y:
if IDF_TARGET_ESP32S3 = y:
esp_psram_impl_quad (noflash)
if IDF_TARGET_ESP32S3 = y:
if SPIRAM_MODE_OCT = y:
esp_psram_impl_octal (noflash)
if IDF_TARGET_ESP32S2 = y || IDF_TARGET_ESP32S3 = y:
mmu_psram (noflash)

171
components/esp_psram/mmu.c Normal file
View File

@ -0,0 +1,171 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* This file will be redesigned into MMU driver, to maintain all the external
* memory contexts including:
* - Flash
* - PSRAM
* - DDR
*
* Now only MMU-PSRAM related private APIs
*/
#include <stdint.h>
#include <sys/param.h>
#include "sdkconfig.h"
#include "esp_attr.h"
#include "esp_log.h"
#include "soc/ext_mem_defs.h"
#include "esp_private/mmu.h"
#if CONFIG_IDF_TARGET_ESP32S2
#include "soc/extmem_reg.h"
#include "esp32s2/rom/cache.h"
#elif CONFIG_IDF_TARGET_ESP32S3
#include "soc/extmem_reg.h"
#include "esp32s3/rom/cache.h"
#endif
#define ALIGN_UP_BY(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
__attribute__((unused)) static const char *TAG = "mmu";
extern int _instruction_reserved_start;
extern int _instruction_reserved_end;
extern int _rodata_reserved_start;
extern int _rodata_reserved_end;
intptr_t mmu_get_psram_vaddr_start(void)
{
#if CONFIG_IDF_TARGET_ESP32S3
intptr_t rodata_end_aligned = ALIGN_UP_BY((intptr_t)&_rodata_reserved_end, MMU_PAGE_SIZE);
ESP_EARLY_LOGV(TAG, "rodata_end_aligned is 0x%x bytes", rodata_end_aligned);
return rodata_end_aligned;
#elif CONFIG_IDF_TARGET_ESP32S2
return DPORT_CACHE_ADDRESS_LOW;
#else //CONFIG_IDF_TARGET_ESP32
return DRAM1_CACHE_ADDRESS_LOW;
#endif
}
intptr_t mmu_get_psram_vaddr_end(void)
{
#if CONFIG_IDF_TARGET_ESP32S3
return DRAM0_CACHE_ADDRESS_HIGH;
#elif CONFIG_IDF_TARGET_ESP32S2
return DRAM0_CACHE_ADDRESS_HIGH;
#else //CONFIG_IDF_TARGET_ESP32
return DRAM1_CACHE_ADDRESS_HIGH;
#endif
}
//------------------------------------Copy Flash .text to PSRAM-------------------------------------//
#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS
static uint32_t instruction_in_spiram;
static uint32_t instr_start_page;
static uint32_t instr_end_page;
static int instr_flash2spiram_offs;
/**
* - These logics are abstracted from the PSRAM driver
* - These functions are only required by `flash_mmap.c` for converting paddr to vaddr, and vice versa
* - The `flash_mmpa.c` will be rewritten into MMU driver
*
* Therefore, keep the APIs here for now
*/
void instruction_flash_page_info_init(uint32_t psram_start_physical_page)
{
#if CONFIG_IDF_TARGET_ESP32S2
uint32_t instr_page_cnt = ((uint32_t)&_instruction_reserved_end - (uint32_t)&_instruction_reserved_start + MMU_PAGE_SIZE - 1) / MMU_PAGE_SIZE;
uint32_t instr_mmu_offset = ((uint32_t)&_instruction_reserved_start & MMU_VADDR_MASK) / MMU_PAGE_SIZE;
instr_start_page = ((volatile uint32_t *)(DR_REG_MMU_TABLE + PRO_CACHE_IBUS0_MMU_START))[instr_mmu_offset];
#elif CONFIG_IDF_TARGET_ESP32S3
uint32_t instr_page_cnt = ((uint32_t)&_instruction_reserved_end - SOC_IROM_LOW + MMU_PAGE_SIZE - 1) / MMU_PAGE_SIZE;
instr_start_page = *((volatile uint32_t *)(DR_REG_MMU_TABLE + CACHE_IROM_MMU_START));
#endif
instr_start_page &= MMU_VALID_VAL_MASK;
instr_end_page = instr_start_page + instr_page_cnt - 1;
instr_flash2spiram_offs = instr_start_page - psram_start_physical_page;
instruction_in_spiram = 1;
ESP_DRAM_LOGV("mmu_psram", "Instructions from flash page%d copy to SPIRAM page%d, Offset: %d", instr_start_page, psram_start_physical_page, instr_flash2spiram_offs);
}
uint32_t esp_spiram_instruction_access_enabled(void)
{
return instruction_in_spiram;
}
int instruction_flash2spiram_offset(void)
{
return instr_flash2spiram_offs;
}
uint32_t instruction_flash_start_page_get(void)
{
return instr_start_page;
}
uint32_t instruction_flash_end_page_get(void)
{
return instr_end_page;
}
#endif //CONFIG_SPIRAM_FETCH_INSTRUCTIONS
#if CONFIG_SPIRAM_RODATA
//------------------------------------Copy Flash .rodata to PSRAM-------------------------------------//
static uint32_t rodata_in_spiram;
static int rodata_flash2spiram_offs;
static uint32_t rodata_start_page;
static uint32_t rodata_end_page;
/**
* - These logics are abstracted from the PSRAM driver
* - These functions are only required by `flash_mmap.c` for converting paddr to vaddr, and vice versa
* - The `flash_mmpa.c` will be rewritten into MMU driver
*
* Therefore, keep the APIs here for now
*/
void rodata_flash_page_info_init(uint32_t psram_start_physical_page)
{
#if CONFIG_IDF_TARGET_ESP32S2
uint32_t rodata_page_cnt = ((uint32_t)&_rodata_reserved_end - (uint32_t)&_rodata_reserved_start + MMU_PAGE_SIZE - 1) / MMU_PAGE_SIZE;
uint32_t rodata_mmu_offset = ((uint32_t)&_rodata_reserved_start & MMU_VADDR_MASK) / MMU_PAGE_SIZE;
rodata_start_page = ((volatile uint32_t *)(DR_REG_MMU_TABLE + PRO_CACHE_IBUS2_MMU_START))[rodata_mmu_offset];
#elif CONFIG_IDF_TARGET_ESP32S3
uint32_t rodata_page_cnt = ((uint32_t)&_rodata_reserved_end - ((uint32_t)&_rodata_reserved_start & ~ (MMU_PAGE_SIZE - 1)) + MMU_PAGE_SIZE - 1) / MMU_PAGE_SIZE;
rodata_start_page = *(volatile uint32_t *)(DR_REG_MMU_TABLE + CACHE_DROM_MMU_START);
#endif
rodata_start_page &= MMU_VALID_VAL_MASK;
rodata_end_page = rodata_start_page + rodata_page_cnt - 1;
rodata_flash2spiram_offs = rodata_start_page - psram_start_physical_page;
rodata_in_spiram = 1;
ESP_DRAM_LOGV("mmu_psram", "Rodata from flash page%d copy to SPIRAM page%d, Offset: %d", rodata_start_page, psram_start_physical_page, rodata_flash2spiram_offs);
}
uint32_t esp_spiram_rodata_access_enabled(void)
{
return rodata_in_spiram;
}
int rodata_flash2spiram_offset(void)
{
return rodata_flash2spiram_offs;
}
uint32_t rodata_flash_start_page_get(void)
{
return rodata_start_page;
}
uint32_t rodata_flash_end_page_get(void)
{
return rodata_end_page;
}
#endif //#if CONFIG_SPIRAM_RODATA

View File

@ -0,0 +1,144 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* This file will be redesigned into MMU driver, to maintain all the external
* memory contexts including:
* - Flash
* - PSRAM
* - DDR
*
* Now only MMU-PSRAM related private APIs
*/
#include <sys/param.h>
#include "sdkconfig.h"
#include "esp_log.h"
#include "esp_attr.h"
#include "soc/ext_mem_defs.h"
#include "hal/cache_types.h"
#include "hal/cache_ll.h"
#include "esp_private/mmu.h"
#if CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/rom/cache.h"
#elif CONFIG_IDF_TARGET_ESP32S3
#include "esp32s3/rom/cache.h"
#endif
#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS || CONFIG_SPIRAM_RODATA
const static char *TAG = "mmu_psram";
//TODO IDF-4387
static uint32_t page0_mapped = 0;
static uint32_t page0_page = INVALID_PHY_PAGE;
#endif //#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS || CONFIG_SPIRAM_RODATA
#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS
esp_err_t mmu_config_psram_text_segment(uint32_t start_page, uint32_t psram_size, uint32_t *out_page)
{
uint32_t page_id = start_page;
/**
* TODO IDF-4387
* `Cache_Count_Flash_Pages` seems give wrong results. Need to confirm this.
* FOR NOW, leave these logics just as it used to be.
*
* The rom API will be redesigned into a MMU driver layer function
*/
uint32_t flash_pages = 0;
#if CONFIG_IDF_TARGET_ESP32S2
flash_pages += Cache_Count_Flash_Pages(PRO_CACHE_IBUS0, &page0_mapped);
flash_pages += Cache_Count_Flash_Pages(PRO_CACHE_IBUS1, &page0_mapped);
#elif CONFIG_IDF_TARGET_ESP32S3
flash_pages += Cache_Count_Flash_Pages(CACHE_IBUS, &page0_mapped);
#endif
if ((flash_pages + page_id) > BYTES_TO_MMU_PAGE(psram_size)) {
ESP_EARLY_LOGE(TAG, "PSRAM space not enough for the Flash instructions, need %d B, from %d B to %d B",
MMU_PAGE_TO_BYTES(flash_pages), MMU_PAGE_TO_BYTES(start_page), MMU_PAGE_TO_BYTES(flash_pages + page_id));
return ESP_FAIL;
}
//Enable the most high bus, which is used for copying FLASH .text to PSRAM
cache_bus_mask_t bus_mask = cache_ll_l1_get_bus(0, SOC_EXTRAM_DATA_HIGH, 0);
cache_ll_l1_enable_bus(0, bus_mask);
#if !CONFIG_FREERTOS_UNICORE
bus_mask = cache_ll_l1_get_bus(1, SOC_EXTRAM_DATA_HIGH, 0);
cache_ll_l1_enable_bus(1, bus_mask);
#endif
instruction_flash_page_info_init(page_id);
#if CONFIG_IDF_TARGET_ESP32S2
page_id = Cache_Flash_To_SPIRAM_Copy(PRO_CACHE_IBUS0, IRAM0_ADDRESS_LOW, page_id, &page0_page);
page_id = Cache_Flash_To_SPIRAM_Copy(PRO_CACHE_IBUS1, IRAM1_ADDRESS_LOW, page_id, &page0_page);
#elif CONFIG_IDF_TARGET_ESP32S3
page_id = Cache_Flash_To_SPIRAM_Copy(CACHE_IBUS, IRAM0_CACHE_ADDRESS_LOW, page_id, &page0_page);
#endif
ESP_EARLY_LOGV(TAG, "after copy instruction, page_id is %d", page_id);
ESP_EARLY_LOGI(TAG, "Instructions copied and mapped to SPIRAM");
*out_page = page_id - start_page;
return ESP_OK;
}
#endif //#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS
#if CONFIG_SPIRAM_RODATA
esp_err_t mmu_config_psram_rodata_segment(uint32_t start_page, uint32_t psram_size, uint32_t *out_page)
{
uint32_t page_id = start_page;
/**
* TODO IDF-4387
* `Cache_Count_Flash_Pages` seems give wrong results. Need to confirm this.
* FOR NOW, leave these logics just as it used to be.
*
* The rom API will be redesigned into a MMU driver layer function
*/
uint32_t flash_pages = 0;
#if CONFIG_IDF_TARGET_ESP32S2
flash_pages += Cache_Count_Flash_Pages(PRO_CACHE_IBUS2, &page0_mapped);
flash_pages += Cache_Count_Flash_Pages(PRO_CACHE_DBUS0, &page0_mapped);
flash_pages += Cache_Count_Flash_Pages(PRO_CACHE_DBUS1, &page0_mapped);
flash_pages += Cache_Count_Flash_Pages(PRO_CACHE_DBUS2, &page0_mapped);
#elif CONFIG_IDF_TARGET_ESP32S3
flash_pages += Cache_Count_Flash_Pages(CACHE_DBUS, &page0_mapped);
#endif
if ((flash_pages + page_id) > BYTES_TO_MMU_PAGE(psram_size)) {
ESP_EARLY_LOGE(TAG, "SPI RAM space not enough for the instructions, need to copy to %d B.", MMU_PAGE_TO_BYTES(flash_pages + page_id));
return ESP_FAIL;
}
//Enable the most high bus, which is used for copying FLASH .text to PSRAM
cache_bus_mask_t bus_mask = cache_ll_l1_get_bus(0, SOC_EXTRAM_DATA_HIGH, 0);
cache_ll_l1_enable_bus(0, bus_mask);
#if !CONFIG_FREERTOS_UNICORE
bus_mask = cache_ll_l1_get_bus(1, SOC_EXTRAM_DATA_HIGH, 0);
cache_ll_l1_enable_bus(1, bus_mask);
#endif
rodata_flash_page_info_init(page_id);
#if CONFIG_IDF_TARGET_ESP32S2
page_id = Cache_Flash_To_SPIRAM_Copy(PRO_CACHE_IBUS2, DROM0_ADDRESS_LOW, page_id, &page0_page);
page_id = Cache_Flash_To_SPIRAM_Copy(PRO_CACHE_DBUS0, DRAM0_ADDRESS_LOW, page_id, &page0_page);
page_id = Cache_Flash_To_SPIRAM_Copy(PRO_CACHE_DBUS1, DRAM1_ADDRESS_LOW, page_id, &page0_page);
page_id = Cache_Flash_To_SPIRAM_Copy(PRO_CACHE_DBUS2, DPORT_ADDRESS_LOW, page_id, &page0_page);
#elif CONFIG_IDF_TARGET_ESP32S3
page_id = Cache_Flash_To_SPIRAM_Copy(CACHE_DBUS, DRAM0_CACHE_ADDRESS_LOW, page_id, &page0_page);
#endif
ESP_EARLY_LOGV(TAG, "after copy rodata, page_id is %d", page_id);
ESP_EARLY_LOGI(TAG, "Read only data copied and mapped to SPIRAM");
*out_page = page_id - start_page;
return ESP_OK;
}
#endif //#if CONFIG_SPIRAM_RODATA

View File

@ -0,0 +1,5 @@
# This is the project CMakeLists.txt file for the test subproject
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(psram_test)

View File

@ -0,0 +1,4 @@
| Supported Targets | ESP32 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- |
This test app is used to test PSRAM

View File

@ -0,0 +1,13 @@
idf_build_get_property(target IDF_TARGET)
set(srcs "test_app_main.c"
"test_psram.c")
if(${target} STREQUAL "esp32")
list(APPEND srcs "test_himem.c")
endif()
# In order for the cases defined by `TEST_CASE` to be linked into the final elf,
# the component can be registered as WHOLE_ARCHIVE
idf_component_register(SRCS ${srcs}
WHOLE_ARCHIVE)

View File

@ -0,0 +1,40 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: CC0-1.0
*/
#include "unity.h"
#include "unity_test_runner.h"
#include "esp_heap_caps.h"
#define TEST_MEMORY_LEAK_THRESHOLD (-600)
static size_t before_free_8bit;
static size_t before_free_32bit;
static void check_leak(size_t before_free, size_t after_free, const char *type)
{
ssize_t delta = after_free - before_free;
printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, before_free, after_free, delta);
TEST_ASSERT_MESSAGE(delta >= TEST_MEMORY_LEAK_THRESHOLD, "memory leak");
}
void setUp(void)
{
before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
}
void tearDown(void)
{
size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
check_leak(before_free_8bit, after_free_8bit, "8BIT");
check_leak(before_free_32bit, after_free_32bit, "32BIT");
}
void app_main(void)
{
unity_run_menu();
}

View File

@ -14,7 +14,7 @@
#include "sdkconfig.h"
#if CONFIG_IDF_TARGET_ESP32
#include "esp_himem.h"
#include "esp32/himem.h"
#if CONFIG_SPIRAM_BANKSWITCH_ENABLE

View File

@ -11,14 +11,13 @@
#include "esp_attr.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "test_utils.h"
#include "unity.h"
#include "esp_heap_caps.h"
#include "esp_private/spiram_private.h"
#if CONFIG_SPIRAM
#include "spiram.h"
#include "esp_private/esp_psram_io.h"
#include "esp_psram.h"
#include "esp_private/esp_psram_extram.h"
const static char *TAG = "PSRAM";
__attribute__((unused)) const static char *TAG = "PSRAM";
#if CONFIG_SPIRAM_MODE_OCT
@ -31,7 +30,7 @@ static bool s_check_valid_psram_alloced_range(const void *p)
{
intptr_t vaddr_start = 0;
intptr_t vaddr_end = 0;
esp_spiram_get_alloced_range(&vaddr_start, &vaddr_end);
esp_psram_extram_get_alloced_range(&vaddr_start, &vaddr_end);
return (intptr_t)p >= vaddr_start && (intptr_t)p < vaddr_end;
}
@ -58,8 +57,9 @@ TEST_CASE("test psram heap allocable","[psram]")
#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS && CONFIG_SPIRAM_RODATA
#include "esp_timer.h"
#include "esp32s3/rom/spi_flash.h"
#include "esp_partition.h"
#include "driver/gptimer.h"
#include "esp_rom_spiflash.h"
#define SECTOR_LEN 4096
#define TEST_NUM 10
@ -68,29 +68,61 @@ TEST_CASE("test psram heap allocable","[psram]")
static uint32_t s_timer_cb_exe_times;
static const uint8_t s_test_buf[TEST_NUM] = TEST_BUF;
static void NOINLINE_ATTR s_test_printf(void *arg)
static const esp_partition_t *s_get_partition(void)
{
//Find the "storage1" partition defined in `partitions.csv`
const esp_partition_t *result = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "storage1");
if (!result) {
ESP_LOGE(TAG, "Can't find the partition, please define it correctly in `partitions.csv`");
abort();
}
return result;
}
static bool NOINLINE_ATTR s_test_rodata(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_ctx)
{
s_timer_cb_exe_times ++;
uint8_t cmp_buf[TEST_NUM] = TEST_BUF;
TEST_ASSERT(memcmp(cmp_buf, s_test_buf, TEST_NUM) == 0);
return false;
}
TEST_CASE("test spi1 flash operation after putting .text and .rodata into psram", "[psram]")
{
//Create flash partition for test
const esp_partition_t *part = get_test_data_partition();
size_t start = part->address;
ESP_LOGI(TAG, "test data partition: 0x%x", start);
//Get the partition used for SPI1 erase operation
const esp_partition_t *part = s_get_partition();
ESP_LOGI(TAG, "found partition '%s' at offset 0x%x with size 0x%x", part->label, part->address, part->size);
//Erase whole region
TEST_ESP_OK(esp_flash_erase_region(part->flash_chip, part->address, part->size));
esp_timer_handle_t timer;
esp_timer_create_args_t timer_args = {
.callback = &s_test_printf,
gptimer_handle_t gptimer = NULL;
gptimer_config_t timer_config = {
.resolution_hz = 1 * 1000 * 1000,
.clk_src = GPTIMER_CLK_SRC_DEFAULT,
.direction = GPTIMER_COUNT_UP,
};
TEST_ESP_OK(esp_timer_create(&timer_args, &timer));
TEST_ESP_OK(gptimer_new_timer(&timer_config, &gptimer));
gptimer_alarm_config_t alarm_config = {
.reload_count = 0,
.alarm_count = 10, // 10us
.flags.auto_reload_on_alarm = true,
};
TEST_ESP_OK(gptimer_set_alarm_action(gptimer, &alarm_config));
gptimer_event_callbacks_t cbs = {
.on_alarm = s_test_rodata,
};
TEST_ESP_OK(gptimer_register_event_callbacks(gptimer, &cbs, NULL));
esp_rom_spiflash_result_t ret;
size_t start = part->address;
ESP_LOGI(TAG, "test data partition: 0x%x", start);
uint32_t sector_num = start / SECTOR_LEN;
TEST_ESP_OK(esp_timer_start_periodic(timer, 1 * 10));
TEST_ESP_OK(gptimer_enable(gptimer));
TEST_ESP_OK(gptimer_start(gptimer));
ret = esp_rom_spiflash_erase_sector(sector_num);
if (ret != ESP_ROM_SPIFLASH_RESULT_OK) {
@ -98,10 +130,12 @@ TEST_CASE("test spi1 flash operation after putting .text and .rodata into psram"
TEST_ASSERT(false);
}
TEST_ESP_OK(esp_timer_stop(timer));
TEST_ESP_OK(gptimer_stop(gptimer));
TEST_ASSERT(s_timer_cb_exe_times > 0);
printf("timer callback runs %d times\n", s_timer_cb_exe_times);
ESP_LOGI(TAG, "Finish");
TEST_ESP_OK(gptimer_disable(gptimer));
TEST_ESP_OK(gptimer_del_timer(gptimer));
}
#endif //CONFIG_SPIRAM_FETCH_INSTRUCTIONS && CONFIG_SPIRAM_RODATA
#endif //#if CONFIG_SPIRAM

View File

@ -0,0 +1,6 @@
# Name, Type, SubType, Offset, Size, Flags
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
nvs, data, nvs, 0x9000, 0x6000,
phy_init, data, phy, 0xf000, 0x1000,
factory, app, factory, 0x10000, 1M,
storage1, data, fat, , 512K,
1 # Name, Type, SubType, Offset, Size, Flags
2 # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
3 nvs, data, nvs, 0x9000, 0x6000,
4 phy_init, data, phy, 0xf000, 0x1000,
5 factory, app, factory, 0x10000, 1M,
6 storage1, data, fat, , 512K,

View File

@ -0,0 +1,68 @@
# SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0
import pytest
from pytest_embedded import Dut
@pytest.mark.esp32
@pytest.mark.generic
@pytest.mark.parametrize(
'config',
[
'esp32_release',
],
indirect=True,
)
def test_psram_esp32(dut: Dut) -> None:
dut.expect_exact('Press ENTER to see the list of tests')
dut.write('*')
dut.expect_unity_test_output()
@pytest.mark.esp32s2
@pytest.mark.generic
@pytest.mark.parametrize(
'config',
[
'esp32s2_release',
'esp32s2_advanced',
],
indirect=True,
)
def test_psram_esp32s2(dut: Dut) -> None:
dut.expect_exact('Press ENTER to see the list of tests')
dut.write('*')
dut.expect_unity_test_output()
@pytest.mark.esp32s3
@pytest.mark.quad_psram
@pytest.mark.parametrize(
'config',
[
'esp32s3_quad_release',
'esp32s3_quad_advanced',
],
indirect=True,
)
def test_psram_esp32s3(dut: Dut) -> None:
dut.expect_exact('Press ENTER to see the list of tests')
dut.write('*')
dut.expect_unity_test_output()
@pytest.mark.esp32s3
@pytest.mark.octal_psram
@pytest.mark.parametrize(
'config',
[
'esp32s3_octal_release',
'esp32s3_octal_advanced',
],
indirect=True,
)
def test_psram_esp32s3_octal(dut: Dut) -> None:
dut.expect_exact('Press ENTER to see the list of tests')
dut.write('*')
dut.expect_unity_test_output()

View File

@ -0,0 +1,9 @@
CONFIG_IDF_TARGET="esp32"
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
CONFIG_ESP32_SPIRAM_SUPPORT=y
CONFIG_ESP_INT_WDT_TIMEOUT_MS=800
CONFIG_SPIRAM_OCCUPY_NO_HOST=y

View File

@ -0,0 +1,9 @@
CONFIG_IDF_TARGET="esp32s2"
CONFIG_ESP32S2_SPIRAM_SUPPORT=y
CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y
CONFIG_SPIRAM_RODATA=y
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"

View File

@ -0,0 +1,7 @@
CONFIG_IDF_TARGET="esp32s2"
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
CONFIG_ESP32S2_SPIRAM_SUPPORT=y

View File

@ -0,0 +1,10 @@
CONFIG_IDF_TARGET="esp32s3"
CONFIG_ESP32S3_SPIRAM_SUPPORT=y
CONFIG_SPIRAM_MODE_OCT=y
CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y
CONFIG_SPIRAM_RODATA=y
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"

View File

@ -0,0 +1,8 @@
CONFIG_IDF_TARGET="esp32s3"
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
CONFIG_ESP32S3_SPIRAM_SUPPORT=y
CONFIG_SPIRAM_MODE_OCT=y

View File

@ -0,0 +1,10 @@
CONFIG_IDF_TARGET="esp32s3"
CONFIG_ESP32S3_SPIRAM_SUPPORT=y
CONFIG_SPIRAM_MODE_QUAD=y
CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y
CONFIG_SPIRAM_RODATA=y
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"

View File

@ -0,0 +1,8 @@
CONFIG_IDF_TARGET="esp32s3"
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
CONFIG_ESP32S3_SPIRAM_SUPPORT=y
CONFIG_SPIRAM_MODE_QUAD=y

View File

@ -0,0 +1,2 @@
CONFIG_FREERTOS_HZ=1000
CONFIG_ESP_TASK_WDT=n

View File

@ -102,3 +102,9 @@ endif()
if(CONFIG_SW_COEXIST_ENABLE OR CONFIG_EXTERNAL_COEX_ENABLE)
idf_component_optional_requires(PRIVATE esp_wifi)
endif()
if(NOT BOOTLOADER_BUILD)
if(CONFIG_SPIRAM)
idf_component_optional_requires(PRIVATE esp_psram)
endif()
endif()

View File

@ -27,17 +27,13 @@
#include "soc/dport_reg.h"
#include "esp32/rtc.h"
#include "esp32/rom/cache.h"
#include "esp32/spiram.h"
#elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/rtc.h"
#include "esp32s2/rom/cache.h"
#include "esp32s2/spiram.h"
#include "esp32s2/memprot.h"
#elif CONFIG_IDF_TARGET_ESP32S3
#include "esp32s3/rtc.h"
#include "esp32s3/rom/cache.h"
#include "esp32s3/spiram.h"
#include "esp_private/mmu_psram.h"
#include "esp_memprot.h"
#include "soc/assist_debug_reg.h"
#include "soc/system_reg.h"
@ -57,6 +53,11 @@
#include "esp32c2/memprot.h"
#endif
#if CONFIG_SPIRAM
#include "esp_psram.h"
#include "esp_private/esp_psram_extram.h"
#endif
#include "esp_private/spi_flash_os.h"
#include "bootloader_flash_config.h"
#include "bootloader_flash.h"
@ -385,7 +386,7 @@ void IRAM_ATTR call_start_cpu0(void)
bootloader_init_mem();
#if CONFIG_SPIRAM_BOOT_INIT
if (esp_spiram_init() != ESP_OK) {
if (esp_psram_init() != ESP_OK) {
#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
ESP_EARLY_LOGE(TAG, "Failed to init external RAM, needed for external .bss segment");
abort();
@ -399,12 +400,6 @@ void IRAM_ATTR call_start_cpu0(void)
abort();
#endif
}
//TODO: IDF-4382
#if CONFIG_IDF_TARGET_ESP32
if (g_spiram_ok) {
esp_spiram_init_cache();
}
#endif //#if CONFIG_IDF_TARGET_ESP32, //TODO: IDF-4382
#endif
#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
@ -433,26 +428,25 @@ void IRAM_ATTR call_start_cpu0(void)
#endif // SOC_CPU_CORES_NUM > 1
#if CONFIG_SPIRAM_MEMTEST
//TODO: IDF-4382
#if CONFIG_IDF_TARGET_ESP32
if (g_spiram_ok) {
bool ext_ram_ok = esp_spiram_test();
bool ext_ram_ok = esp_psram_extram_test();
if (!ext_ram_ok) {
ESP_EARLY_LOGE(TAG, "External RAM failed memory test!");
abort();
}
}
#endif //CONFIG_IDF_TARGET_ESP32, //TODO: IDF-4382
#endif //CONFIG_SPIRAM_MEMTEST
//TODO: IDF-5023, replace with MMU driver
#if CONFIG_IDF_TARGET_ESP32S3
int s_instr_flash2spiram_off = 0;
int s_rodata_flash2spiram_off = 0;
#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS
extern int instruction_flash2spiram_offset(void);
s_instr_flash2spiram_off = instruction_flash2spiram_offset();
#endif
#if CONFIG_SPIRAM_RODATA
extern int rodata_flash2spiram_offset(void);
s_rodata_flash2spiram_off = rodata_flash2spiram_offset();
#endif

View File

@ -71,13 +71,8 @@
#include "esp_rom_sys.h"
// [refactor-todo] make this file completely target-independent
#if CONFIG_IDF_TARGET_ESP32
#include "esp32/spiram.h"
#elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/spiram.h"
#elif CONFIG_IDF_TARGET_ESP32S3
#include "esp32s3/spiram.h"
#if CONFIG_SPIRAM
#include "esp_private/esp_psram_extram.h"
#endif
/***********************************************/
@ -253,7 +248,7 @@ static void do_core_init(void)
if (g_spiram_ok) {
#if CONFIG_SPIRAM_BOOT_INIT && (CONFIG_SPIRAM_USE_CAPS_ALLOC || CONFIG_SPIRAM_USE_MALLOC)
esp_err_t r=esp_spiram_add_to_heapalloc();
esp_err_t r=esp_psram_extram_add_to_heap_allocator();
if (r != ESP_OK) {
ESP_EARLY_LOGE(TAG, "External RAM could not be added to heap!");
abort();

View File

@ -165,3 +165,7 @@ if(CONFIG_FREERTOS_RUN_TIME_STATS_USING_ESP_TIMER)
# Introduce a port wrapper function to avoid including esp_timer.h into the public header
idf_component_optional_requires(PUBLIC esp_timer)
endif()
if(CONFIG_SPIRAM)
idf_component_optional_requires(PRIVATE esp_psram)
endif()

View File

@ -28,7 +28,9 @@
#include "esp_task_wdt.h"
#include "esp_heap_caps_init.h"
#include "esp_freertos_hooks.h"
#include "esp32/spiram.h" /* Required by esp_spiram_reserve_dma_pool() */
#if CONFIG_SPIRAM
#include "esp_private/esp_psram_extram.h" /* Required by esp_psram_extram_reserve_dma_pool() */
#endif
#ifdef CONFIG_APPTRACE_ENABLE
#include "esp_app_trace.h"
#endif
@ -181,7 +183,7 @@ static void main_task(void* args)
// Now we have startup stack RAM available for heap, enable any DMA pool memory
#if CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL
if (g_spiram_ok) {
esp_err_t r = esp_spiram_reserve_dma_pool(CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL);
esp_err_t r = esp_psram_extram_reserve_dma_pool(CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL);
if (r != ESP_OK) {
ESP_EARLY_LOGE(TAG, "Could not reserve internal/DMA pool (error 0x%x)", r);
abort();

View File

@ -20,12 +20,8 @@
#include "esp_freertos_hooks.h"
#include "sdkconfig.h"
#if CONFIG_IDF_TARGET_ESP32
#include "esp32/spiram.h"
#elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/spiram.h"
#elif CONFIG_IDF_TARGET_ESP32S3
#include "esp32s3/spiram.h"
#if CONFIG_SPIRAM
#include "esp_private/esp_psram_extram.h"
#endif
#if CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL
@ -94,7 +90,7 @@ static void main_task(void* args)
// Now we have startup stack RAM available for heap, enable any DMA pool memory
#if CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL
if (g_spiram_ok) {
esp_err_t r = esp_spiram_reserve_dma_pool(CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL);
esp_err_t r = esp_psram_extram_reserve_dma_pool(CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL);
if (r != ESP_OK) {
ESP_EARLY_LOGE(TAG, "Could not reserve internal/DMA pool (error 0x%x)", r);
abort();

View File

@ -8,6 +8,7 @@
#pragma once
#include <stdbool.h>
#include "soc/dport_reg.h"
#include "soc/ext_mem_defs.h"
#include "hal/cache_types.h"

View File

@ -76,3 +76,11 @@ if(CMAKE_C_COMPILER_ID MATCHES "GNU")
set_property(SOURCE ${cache_srcs} APPEND_STRING PROPERTY COMPILE_FLAGS
" -fno-inline-small-functions -fno-inline-functions-called-once")
endif()
if(NOT BOOTLOADER_BUILD)
if(CONFIG_SPIRAM)
# [refactor-todo]: requires "esp_psram" for few MMU usages in `flash_mmap.c`
# will be replaced with MMU requirements
idf_component_optional_requires(PRIVATE esp_psram)
endif()
endif()

View File

@ -24,15 +24,11 @@
#if CONFIG_IDF_TARGET_ESP32
#include "soc/dport_reg.h"
#include "esp32/rom/cache.h"
#include "esp32/spiram.h"
#elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/rom/cache.h"
#include "esp_private/mmu_psram.h"
#include "soc/extmem_reg.h"
#elif CONFIG_IDF_TARGET_ESP32S3
#include "esp32s3/rom/cache.h"
#include "esp_private/mmu_psram.h"
#include "esp32s3/spiram.h"
#include "soc/extmem_reg.h"
#elif CONFIG_IDF_TARGET_ESP32C3
#include "esp32c3/rom/cache.h"
@ -42,6 +38,11 @@
#include "esp32c2/rom/cache.h"
#endif
#if CONFIG_SPIRAM
#include "esp_private/esp_psram_extram.h"
#include "esp_private/mmu.h"
#endif
#ifndef NDEBUG
// Enable built-in checks in queue.h in debug builds
#define INVARIANTS
@ -259,7 +260,7 @@ esp_err_t IRAM_ATTR spi_flash_mmap_pages(const int *pages, size_t page_count, sp
if (need_flush) {
#if CONFIG_IDF_TARGET_ESP32
#if CONFIG_SPIRAM
esp_spiram_writeback_cache();
esp_psram_extram_writeback_cache();
#endif // CONFIG_SPIRAM
Cache_Flush(0);
#if !CONFIG_FREERTOS_UNICORE
@ -497,7 +498,7 @@ IRAM_ATTR bool spi_flash_check_and_flush_cache(size_t start_addr, size_t length)
if (is_page_mapped_in_cache(page, &vaddr)) {
#if CONFIG_IDF_TARGET_ESP32
#if CONFIG_SPIRAM
esp_spiram_writeback_cache();
esp_psram_extram_writeback_cache();
#endif
Cache_Flush(0);
#ifndef CONFIG_FREERTOS_UNICORE

View File

@ -8,7 +8,7 @@ INPUT += \
$(PROJECT_PATH)/components/driver/include/driver/rmt_rx.h \
$(PROJECT_PATH)/components/driver/include/driver/rmt_tx.h \
$(PROJECT_PATH)/components/driver/include/driver/rmt_types.h \
$(PROJECT_PATH)/components/esp_hw_support/include/esp_himem.h \
$(PROJECT_PATH)/components/esp_psram/include/esp32/himem.h \
$(PROJECT_PATH)/components/esp_system/include/esp_ipc.h \
$(PROJECT_PATH)/components/esp_system/include/esp_ipc_isr.h \
$(PROJECT_PATH)/components/hal/include/hal/mcpwm_types.h \

View File

@ -30,4 +30,4 @@ An example doing a simple memory test of the high memory range is available in e
API Reference
-------------
.. include-build-file:: inc/esp_himem.inc
.. include-build-file:: inc/himem.inc

View File

@ -45,11 +45,8 @@ ESP HW Support
PSRAM
^^^^^
- The header file ``esp_spiram.h`` file has been deleted. Users should use the ``<target>/spiram.h`` file instead.
- The header file ``esp32/himem.h`` file has been deleted. Users should use the esp_himem.h file instead.
- `esp_spiram_get_chip_size` has been deleted.
- `esp_spiram_get_size` has been moved to `esp_private/spiram_private.h`
- The target specific header files ``spiram.h`` have been deleted. The header file ``esp_spiram.h`` has been deleted. A new component ``esp_psram`` is created, you should include ``esp_psram.h`` instead. Besides, you might need to add ``esp_psram`` component to the list of component requirements in CMakeLists.txt.
- ``esp_spiram_get_chip_size`` and ``esp_spiram_get_size`` have been deleted. You should use ``esp_psram_get_size`` instead.
ESP Common
----------

View File

@ -15,7 +15,7 @@ if("${TARGET}" IN_LIST targets)
# although esptool_py does not generate static library,
# processing the component is needed for flashing related
# targets and file generation
COMPONENTS freertos esptool_py
COMPONENTS freertos esptool_py esp_psram
SDKCONFIG ${CMAKE_CURRENT_LIST_DIR}/sdkconfig
BUILD_DIR ${CMAKE_BINARY_DIR})
else()
@ -33,7 +33,7 @@ add_executable(${elf_file} main.c)
# Link the static libraries to the executable
if("${TARGET}" IN_LIST targets)
target_link_libraries(${elf_file} idf::freertos idf::spi_flash)
target_link_libraries(${elf_file} idf::freertos idf::spi_flash idf::esp_psram)
# Attach additional targets to the executable file for flashing,
# linker script generation, partition_table generation, etc.
idf_build_executable(${elf_file})

View File

@ -15,9 +15,8 @@
#include "esp_system.h"
#include "nvs_flash.h"
#include "esp_heap_caps.h"
#include "esp32/spiram.h"
#include "sdkconfig.h"
#include "esp_himem.h"
#include "esp32/himem.h"
//Fill memory with pseudo-random data generated from the given seed.