mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
esp_psram: new psram component
This commit is contained in:
parent
44f771c713
commit
38e5043ae8
@ -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
|
||||
|
@ -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
|
||||
)
|
||||
|
@ -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.
|
||||
|
@ -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()
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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)
|
||||
|
@ -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}")
|
||||
|
@ -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
|
@ -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
|
@ -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}")
|
||||
|
@ -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
|
@ -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
|
@ -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}")
|
||||
|
@ -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
|
@ -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
|
@ -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"
|
||||
|
@ -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);
|
||||
|
@ -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")
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
58
components/esp_psram/CMakeLists.txt
Normal file
58
components/esp_psram/CMakeLists.txt
Normal 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()
|
7
components/esp_psram/Kconfig
Normal file
7
components/esp_psram/Kconfig
Normal 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
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
77
components/esp_psram/esp32/esp_psram_extram_cache.c
Normal file
77
components/esp_psram/esp32/esp_psram_extram_cache.c
Normal 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
|
||||
}
|
@ -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
|
@ -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
|
@ -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);
|
||||
}
|
@ -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
|
@ -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;
|
@ -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;
|
@ -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
|
@ -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);
|
84
components/esp_psram/include/esp_private/esp_psram_extram.h
Normal file
84
components/esp_psram/include/esp_private/esp_psram_extram.h
Normal 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
|
31
components/esp_psram/include/esp_private/esp_psram_io.h
Normal file
31
components/esp_psram/include/esp_private/esp_psram_io.h
Normal 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
|
140
components/esp_psram/include/esp_private/mmu.h
Normal file
140
components/esp_psram/include/esp_private/mmu.h
Normal 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
|
47
components/esp_psram/include/esp_psram.h
Normal file
47
components/esp_psram/include/esp_psram.h
Normal 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
|
17
components/esp_psram/linker.lf
Normal file
17
components/esp_psram/linker.lf
Normal 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
171
components/esp_psram/mmu.c
Normal 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
|
144
components/esp_psram/mmu_psram.c
Normal file
144
components/esp_psram/mmu_psram.c
Normal 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
|
5
components/esp_psram/test_apps/psram/CMakeLists.txt
Normal file
5
components/esp_psram/test_apps/psram/CMakeLists.txt
Normal 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)
|
4
components/esp_psram/test_apps/psram/README.md
Normal file
4
components/esp_psram/test_apps/psram/README.md
Normal file
@ -0,0 +1,4 @@
|
||||
| Supported Targets | ESP32 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- |
|
||||
|
||||
This test app is used to test PSRAM
|
13
components/esp_psram/test_apps/psram/main/CMakeLists.txt
Normal file
13
components/esp_psram/test_apps/psram/main/CMakeLists.txt
Normal 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)
|
40
components/esp_psram/test_apps/psram/main/test_app_main.c
Normal file
40
components/esp_psram/test_apps/psram/main/test_app_main.c
Normal 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();
|
||||
}
|
@ -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
|
||||
|
@ -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
|
6
components/esp_psram/test_apps/psram/partitions.csv
Normal file
6
components/esp_psram/test_apps/psram/partitions.csv
Normal 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,
|
|
68
components/esp_psram/test_apps/psram/pytest_psram.py
Normal file
68
components/esp_psram/test_apps/psram/pytest_psram.py
Normal 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()
|
@ -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
|
@ -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"
|
@ -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
|
@ -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"
|
@ -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
|
@ -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"
|
@ -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
|
2
components/esp_psram/test_apps/psram/sdkconfig.defaults
Normal file
2
components/esp_psram/test_apps/psram/sdkconfig.defaults
Normal file
@ -0,0 +1,2 @@
|
||||
CONFIG_FREERTOS_HZ=1000
|
||||
CONFIG_ESP_TASK_WDT=n
|
@ -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()
|
||||
|
@ -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
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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()
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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"
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
@ -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 \
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
----------
|
||||
|
@ -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})
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user