diff --git a/.gitlab/CODEOWNERS b/.gitlab/CODEOWNERS index 928f8ab7cd..b0c996724a 100644 --- a/.gitlab/CODEOWNERS +++ b/.gitlab/CODEOWNERS @@ -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 diff --git a/components/esp_common/test/CMakeLists.txt b/components/esp_common/test/CMakeLists.txt index e9a94c655a..ba65b322fd 100644 --- a/components/esp_common/test/CMakeLists.txt +++ b/components/esp_common/test/CMakeLists.txt @@ -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 ) diff --git a/components/esp_common/test/test_attr.c b/components/esp_common/test/test_attr.c index 023226d474..23e7603145 100644 --- a/components/esp_common/test/test_attr.c +++ b/components/esp_common/test/test_attr.c @@ -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. diff --git a/components/esp_hw_support/CMakeLists.txt b/components/esp_hw_support/CMakeLists.txt index 0d06027eab..9a0d0f26ba 100644 --- a/components/esp_hw_support/CMakeLists.txt +++ b/components/esp_hw_support/CMakeLists.txt @@ -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() diff --git a/components/esp_hw_support/esp_memory_utils.c b/components/esp_hw_support/esp_memory_utils.c index 7cb083c56d..1c8917418d 100644 --- a/components/esp_hw_support/esp_memory_utils.c +++ b/components/esp_hw_support/esp_memory_utils.c @@ -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)); } diff --git a/components/esp_hw_support/include/esp_private/spiram_private.h b/components/esp_hw_support/include/esp_private/spiram_private.h deleted file mode 100644 index 646f6ce067..0000000000 --- a/components/esp_hw_support/include/esp_private/spiram_private.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#pragma once - -#include -#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 diff --git a/components/esp_hw_support/include/soc/esp32/spiram.h b/components/esp_hw_support/include/soc/esp32/spiram.h deleted file mode 100644 index 9b6105c5c7..0000000000 --- a/components/esp_hw_support/include/soc/esp32/spiram.h +++ /dev/null @@ -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 -#include -#include -#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 diff --git a/components/esp_hw_support/include/soc/esp32s2/esp_private/mmu_psram.h b/components/esp_hw_support/include/soc/esp32s2/esp_private/mmu_psram.h deleted file mode 100644 index f49f85f0db..0000000000 --- a/components/esp_hw_support/include/soc/esp32s2/esp_private/mmu_psram.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ -#pragma once - -#include -#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 diff --git a/components/esp_hw_support/include/soc/esp32s2/spiram.h b/components/esp_hw_support/include/soc/esp32s2/spiram.h deleted file mode 100644 index 49e29247bf..0000000000 --- a/components/esp_hw_support/include/soc/esp32s2/spiram.h +++ /dev/null @@ -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 -#include -#include -#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 diff --git a/components/esp_hw_support/include/soc/esp32s3/esp_private/mmu_psram.h b/components/esp_hw_support/include/soc/esp32s3/esp_private/mmu_psram.h deleted file mode 100644 index 73ce159a0f..0000000000 --- a/components/esp_hw_support/include/soc/esp32s3/esp_private/mmu_psram.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ -#pragma once - -#include -#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 diff --git a/components/esp_hw_support/include/soc/esp32s3/spiram.h b/components/esp_hw_support/include/soc/esp32s3/spiram.h deleted file mode 100644 index 4ecfe90f5f..0000000000 --- a/components/esp_hw_support/include/soc/esp32s3/spiram.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - - -#pragma once - -#include -#include -#include -#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 diff --git a/components/esp_hw_support/linker.lf b/components/esp_hw_support/linker.lf index 03d85e8741..34139cac25 100644 --- a/components/esp_hw_support/linker.lf +++ b/components/esp_hw_support/linker.lf @@ -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) diff --git a/components/esp_hw_support/port/esp32/CMakeLists.txt b/components/esp_hw_support/port/esp32/CMakeLists.txt index 8de4a8725b..a5e40f7b0e 100644 --- a/components/esp_hw_support/port/esp32/CMakeLists.txt +++ b/components/esp_hw_support/port/esp32/CMakeLists.txt @@ -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}") diff --git a/components/esp_hw_support/port/esp32/spiram.c b/components/esp_hw_support/port/esp32/spiram.c deleted file mode 100644 index bc49f3743c..0000000000 --- a/components/esp_hw_support/port/esp32/spiram.c +++ /dev/null @@ -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 -#include -#include - -#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 diff --git a/components/esp_hw_support/port/esp32/spiram_psram.h b/components/esp_hw_support/port/esp32/spiram_psram.h deleted file mode 100644 index abcc98f0ff..0000000000 --- a/components/esp_hw_support/port/esp32/spiram_psram.h +++ /dev/null @@ -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 diff --git a/components/esp_hw_support/port/esp32s2/CMakeLists.txt b/components/esp_hw_support/port/esp32s2/CMakeLists.txt index c1a80d112c..4937884c1a 100644 --- a/components/esp_hw_support/port/esp32s2/CMakeLists.txt +++ b/components/esp_hw_support/port/esp32s2/CMakeLists.txt @@ -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}") diff --git a/components/esp_hw_support/port/esp32s2/mmu_psram.c b/components/esp_hw_support/port/esp32s2/mmu_psram.c index 59a3994595..e69de29bb2 100644 --- a/components/esp_hw_support/port/esp32s2/mmu_psram.c +++ b/components/esp_hw_support/port/esp32s2/mmu_psram.c @@ -1,251 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ -#include -#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 diff --git a/components/esp_hw_support/port/esp32s2/spiram.c b/components/esp_hw_support/port/esp32s2/spiram.c deleted file mode 100644 index c65cab5159..0000000000 --- a/components/esp_hw_support/port/esp32s2/spiram.c +++ /dev/null @@ -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 -#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 diff --git a/components/esp_hw_support/port/esp32s3/CMakeLists.txt b/components/esp_hw_support/port/esp32s3/CMakeLists.txt index 311a3e20e5..5e7926f7f0 100644 --- a/components/esp_hw_support/port/esp32s3/CMakeLists.txt +++ b/components/esp_hw_support/port/esp32s3/CMakeLists.txt @@ -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}") diff --git a/components/esp_hw_support/port/esp32s3/mmu_psram.c b/components/esp_hw_support/port/esp32s3/mmu_psram.c deleted file mode 100644 index bbf9ca4549..0000000000 --- a/components/esp_hw_support/port/esp32s3/mmu_psram.c +++ /dev/null @@ -1,276 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ -#include -#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 diff --git a/components/esp_hw_support/port/esp32s3/spiram_psram.h b/components/esp_hw_support/port/esp32s3/spiram_psram.h deleted file mode 100644 index 2e02363c69..0000000000 --- a/components/esp_hw_support/port/esp32s3/spiram_psram.h +++ /dev/null @@ -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 diff --git a/components/esp_hw_support/port/include/esp_spiram.h b/components/esp_hw_support/port/include/esp_spiram.h index 4740964e24..0d783d92c0 100644 --- a/components/esp_hw_support/port/include/esp_spiram.h +++ b/components/esp_hw_support/port/include/esp_spiram.h @@ -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" diff --git a/components/esp_hw_support/sleep_gpio.c b/components/esp_hw_support/sleep_gpio.c index b9f874c3c6..f84d83ba68 100644 --- a/components/esp_hw_support/sleep_gpio.c +++ b/components/esp_hw_support/sleep_gpio.c @@ -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); diff --git a/components/esp_hw_support/test/CMakeLists.txt b/components/esp_hw_support/test/CMakeLists.txt index 7567e6d1c5..55407b0e2f 100644 --- a/components/esp_hw_support/test/CMakeLists.txt +++ b/components/esp_hw_support/test/CMakeLists.txt @@ -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") diff --git a/components/esp_lcd/CMakeLists.txt b/components/esp_lcd/CMakeLists.txt index 81ca044e4e..a77acae0d9 100644 --- a/components/esp_lcd/CMakeLists.txt +++ b/components/esp_lcd/CMakeLists.txt @@ -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() diff --git a/components/esp_lcd/src/esp_lcd_rgb_panel.c b/components/esp_lcd/src/esp_lcd_rgb_panel.c index 40fc6778a0..89a4e5c08a 100644 --- a/components/esp_lcd/src/esp_lcd_rgb_panel.c +++ b/components/esp_lcd/src/esp_lcd_rgb_panel.c @@ -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 diff --git a/components/esp_psram/CMakeLists.txt b/components/esp_psram/CMakeLists.txt new file mode 100644 index 0000000000..bbff893900 --- /dev/null +++ b/components/esp_psram/CMakeLists.txt @@ -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() diff --git a/components/esp_psram/Kconfig b/components/esp_psram/Kconfig new file mode 100644 index 0000000000..44bcc1534d --- /dev/null +++ b/components/esp_psram/Kconfig @@ -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 diff --git a/components/esp_hw_support/Kconfig.spiram.common b/components/esp_psram/Kconfig.spiram.common similarity index 100% rename from components/esp_hw_support/Kconfig.spiram.common rename to components/esp_psram/Kconfig.spiram.common diff --git a/components/esp_hw_support/port/esp32/Kconfig.spiram b/components/esp_psram/esp32/Kconfig.spiram similarity index 97% rename from components/esp_hw_support/port/esp32/Kconfig.spiram rename to components/esp_psram/esp32/Kconfig.spiram index f02d15e0e5..10803a814e 100644 --- a/components/esp_hw_support/port/esp32/Kconfig.spiram +++ b/components/esp_psram/esp32/Kconfig.spiram @@ -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. diff --git a/components/esp_hw_support/port/esp32/esp_himem.c b/components/esp_psram/esp32/esp_himem.c similarity index 97% rename from components/esp_hw_support/port/esp32/esp_himem.c rename to components/esp_psram/esp32/esp_himem.c index 15c0e26ab6..6964e1ea3c 100644 --- a/components/esp_hw_support/port/esp32/esp_himem.c +++ b/components/esp_psram/esp32/esp_himem.c @@ -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; } diff --git a/components/esp_psram/esp32/esp_psram_extram_cache.c b/components/esp_psram/esp32/esp_psram_extram_cache.c new file mode 100644 index 0000000000..764c23b514 --- /dev/null +++ b/components/esp_psram/esp32/esp_psram_extram_cache.c @@ -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 +} diff --git a/components/esp_hw_support/port/esp32/spiram_psram.c b/components/esp_psram/esp32/esp_psram_impl_quad.c similarity index 96% rename from components/esp_hw_support/port/esp32/spiram_psram.c rename to components/esp_psram/esp32/esp_psram_impl_quad.c index 48b436fa3f..efa7537647 100644 --- a/components/esp_hw_support/port/esp32/spiram_psram.c +++ b/components/esp_psram/esp32/esp_psram_impl_quad.c @@ -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 diff --git a/components/esp_hw_support/port/esp32s2/Kconfig.spiram b/components/esp_psram/esp32s2/Kconfig.spiram similarity index 88% rename from components/esp_hw_support/port/esp32s2/Kconfig.spiram rename to components/esp_psram/esp32s2/Kconfig.spiram index 8cedd4b2ac..20929f1442 100644 --- a/components/esp_hw_support/port/esp32s2/Kconfig.spiram +++ b/components/esp_psram/esp32s2/Kconfig.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 diff --git a/components/esp_hw_support/port/esp32s2/spiram_psram.c b/components/esp_psram/esp32s2/esp_psram_impl_quad.c similarity index 95% rename from components/esp_hw_support/port/esp32s2/spiram_psram.c rename to components/esp_psram/esp32s2/esp_psram_impl_quad.c index 9611486b1d..448100acbc 100644 --- a/components/esp_hw_support/port/esp32s2/spiram_psram.c +++ b/components/esp_psram/esp32s2/esp_psram_impl_quad.c @@ -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); } diff --git a/components/esp_hw_support/port/esp32s3/Kconfig.spiram b/components/esp_psram/esp32s3/Kconfig.spiram similarity index 86% rename from components/esp_hw_support/port/esp32s3/Kconfig.spiram rename to components/esp_psram/esp32s3/Kconfig.spiram index f43c97094e..58eff2f3bc 100644 --- a/components/esp_hw_support/port/esp32s3/Kconfig.spiram +++ b/components/esp_psram/esp32s3/Kconfig.spiram @@ -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 diff --git a/components/esp_hw_support/port/esp32s3/opiram_psram.c b/components/esp_psram/esp32s3/esp_psram_impl_octal.c similarity index 96% rename from components/esp_hw_support/port/esp32s3/opiram_psram.c rename to components/esp_psram/esp32s3/esp_psram_impl_octal.c index fdd0f86c91..24f6bc0b3e 100644 --- a/components/esp_hw_support/port/esp32s3/opiram_psram.c +++ b/components/esp_psram/esp32s3/esp_psram_impl_octal.c @@ -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; diff --git a/components/esp_hw_support/port/esp32s3/spiram_psram.c b/components/esp_psram/esp32s3/esp_psram_impl_quad.c similarity index 93% rename from components/esp_hw_support/port/esp32s3/spiram_psram.c rename to components/esp_psram/esp32s3/esp_psram_impl_quad.c index 2e5ecb377e..5b7b677020 100644 --- a/components/esp_hw_support/port/esp32s3/spiram_psram.c +++ b/components/esp_psram/esp32s3/esp_psram_impl_quad.c @@ -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; diff --git a/components/esp_hw_support/port/esp32s3/spiram.c b/components/esp_psram/esp_psram.c similarity index 53% rename from components/esp_hw_support/port/esp32s3/spiram.c rename to components/esp_psram/esp_psram.c index 1bacb0a368..8b35c7961a 100644 --- a/components/esp_hw_support/port/esp32s3/spiram.c +++ b/components/esp_psram/esp_psram.c @@ -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 -#include #include #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 diff --git a/components/esp_hw_support/port/esp32s2/spiram_psram.h b/components/esp_psram/esp_psram_impl.h similarity index 60% rename from components/esp_hw_support/port/esp32s2/spiram_psram.h rename to components/esp_psram/esp_psram_impl.h index cc21a7de4b..a5a0414189 100644 --- a/components/esp_hw_support/port/esp32s2/spiram_psram.h +++ b/components/esp_psram/esp_psram_impl.h @@ -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); diff --git a/components/esp_hw_support/include/esp_himem.h b/components/esp_psram/include/esp32/himem.h similarity index 100% rename from components/esp_hw_support/include/esp_himem.h rename to components/esp_psram/include/esp32/himem.h diff --git a/components/esp_psram/include/esp_private/esp_psram_extram.h b/components/esp_psram/include/esp_private/esp_psram_extram.h new file mode 100644 index 0000000000..32f8b4ddcf --- /dev/null +++ b/components/esp_psram/include/esp_private/esp_psram_extram.h @@ -0,0 +1,84 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#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 diff --git a/components/esp_psram/include/esp_private/esp_psram_io.h b/components/esp_psram/include/esp_private/esp_psram_io.h new file mode 100644 index 0000000000..d36faee9bf --- /dev/null +++ b/components/esp_psram/include/esp_private/esp_psram_io.h @@ -0,0 +1,31 @@ +/* + * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#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 diff --git a/components/esp_psram/include/esp_private/mmu.h b/components/esp_psram/include/esp_private/mmu.h new file mode 100644 index 0000000000..1925f388ed --- /dev/null +++ b/components/esp_psram/include/esp_private/mmu.h @@ -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 +#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 diff --git a/components/esp_psram/include/esp_psram.h b/components/esp_psram/include/esp_psram.h new file mode 100644 index 0000000000..75487573f0 --- /dev/null +++ b/components/esp_psram/include/esp_psram.h @@ -0,0 +1,47 @@ +/* + * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + + +#pragma once + +#include +#include +#include +#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 diff --git a/components/esp_psram/linker.lf b/components/esp_psram/linker.lf new file mode 100644 index 0000000000..eee8cda0f5 --- /dev/null +++ b/components/esp_psram/linker.lf @@ -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) diff --git a/components/esp_psram/mmu.c b/components/esp_psram/mmu.c new file mode 100644 index 0000000000..3953c6bc91 --- /dev/null +++ b/components/esp_psram/mmu.c @@ -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 +#include +#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 diff --git a/components/esp_psram/mmu_psram.c b/components/esp_psram/mmu_psram.c new file mode 100644 index 0000000000..00c16283b8 --- /dev/null +++ b/components/esp_psram/mmu_psram.c @@ -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 +#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 diff --git a/components/esp_hw_support/project_include.cmake b/components/esp_psram/project_include.cmake similarity index 100% rename from components/esp_hw_support/project_include.cmake rename to components/esp_psram/project_include.cmake diff --git a/components/esp_psram/test_apps/psram/CMakeLists.txt b/components/esp_psram/test_apps/psram/CMakeLists.txt new file mode 100644 index 0000000000..1cfb196410 --- /dev/null +++ b/components/esp_psram/test_apps/psram/CMakeLists.txt @@ -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) diff --git a/components/esp_psram/test_apps/psram/README.md b/components/esp_psram/test_apps/psram/README.md new file mode 100644 index 0000000000..3c1295ae25 --- /dev/null +++ b/components/esp_psram/test_apps/psram/README.md @@ -0,0 +1,4 @@ +| Supported Targets | ESP32 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | + +This test app is used to test PSRAM diff --git a/components/esp_psram/test_apps/psram/main/CMakeLists.txt b/components/esp_psram/test_apps/psram/main/CMakeLists.txt new file mode 100644 index 0000000000..7fa3034028 --- /dev/null +++ b/components/esp_psram/test_apps/psram/main/CMakeLists.txt @@ -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) diff --git a/components/esp_psram/test_apps/psram/main/test_app_main.c b/components/esp_psram/test_apps/psram/main/test_app_main.c new file mode 100644 index 0000000000..e19a4c2c37 --- /dev/null +++ b/components/esp_psram/test_apps/psram/main/test_app_main.c @@ -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(); +} diff --git a/components/esp_hw_support/test/test_himem.c b/components/esp_psram/test_apps/psram/main/test_himem.c similarity index 99% rename from components/esp_hw_support/test/test_himem.c rename to components/esp_psram/test_apps/psram/main/test_himem.c index 3a2249b07e..369b9e7b9e 100644 --- a/components/esp_hw_support/test/test_himem.c +++ b/components/esp_psram/test_apps/psram/main/test_himem.c @@ -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 diff --git a/components/esp_hw_support/test/test_psram.c b/components/esp_psram/test_apps/psram/main/test_psram.c similarity index 54% rename from components/esp_hw_support/test/test_psram.c rename to components/esp_psram/test_apps/psram/main/test_psram.c index 659cedc827..1bb8b587ec 100644 --- a/components/esp_hw_support/test/test_psram.c +++ b/components/esp_psram/test_apps/psram/main/test_psram.c @@ -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 diff --git a/components/esp_psram/test_apps/psram/partitions.csv b/components/esp_psram/test_apps/psram/partitions.csv new file mode 100644 index 0000000000..6b057cd354 --- /dev/null +++ b/components/esp_psram/test_apps/psram/partitions.csv @@ -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, diff --git a/components/esp_psram/test_apps/psram/pytest_psram.py b/components/esp_psram/test_apps/psram/pytest_psram.py new file mode 100644 index 0000000000..e000de1434 --- /dev/null +++ b/components/esp_psram/test_apps/psram/pytest_psram.py @@ -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() diff --git a/components/esp_psram/test_apps/psram/sdkconfig.ci.esp32_release b/components/esp_psram/test_apps/psram/sdkconfig.ci.esp32_release new file mode 100644 index 0000000000..e09a120eda --- /dev/null +++ b/components/esp_psram/test_apps/psram/sdkconfig.ci.esp32_release @@ -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 diff --git a/components/esp_psram/test_apps/psram/sdkconfig.ci.esp32s2_advanced b/components/esp_psram/test_apps/psram/sdkconfig.ci.esp32s2_advanced new file mode 100644 index 0000000000..904da62be7 --- /dev/null +++ b/components/esp_psram/test_apps/psram/sdkconfig.ci.esp32s2_advanced @@ -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" diff --git a/components/esp_psram/test_apps/psram/sdkconfig.ci.esp32s2_release b/components/esp_psram/test_apps/psram/sdkconfig.ci.esp32s2_release new file mode 100644 index 0000000000..985c89362e --- /dev/null +++ b/components/esp_psram/test_apps/psram/sdkconfig.ci.esp32s2_release @@ -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 diff --git a/components/esp_psram/test_apps/psram/sdkconfig.ci.esp32s3_octal_advanced b/components/esp_psram/test_apps/psram/sdkconfig.ci.esp32s3_octal_advanced new file mode 100644 index 0000000000..20f4386487 --- /dev/null +++ b/components/esp_psram/test_apps/psram/sdkconfig.ci.esp32s3_octal_advanced @@ -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" diff --git a/components/esp_psram/test_apps/psram/sdkconfig.ci.esp32s3_octal_release b/components/esp_psram/test_apps/psram/sdkconfig.ci.esp32s3_octal_release new file mode 100644 index 0000000000..517c9cacdc --- /dev/null +++ b/components/esp_psram/test_apps/psram/sdkconfig.ci.esp32s3_octal_release @@ -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 diff --git a/components/esp_psram/test_apps/psram/sdkconfig.ci.esp32s3_quad_advanced b/components/esp_psram/test_apps/psram/sdkconfig.ci.esp32s3_quad_advanced new file mode 100644 index 0000000000..b972c657d1 --- /dev/null +++ b/components/esp_psram/test_apps/psram/sdkconfig.ci.esp32s3_quad_advanced @@ -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" diff --git a/components/esp_psram/test_apps/psram/sdkconfig.ci.esp32s3_quad_release b/components/esp_psram/test_apps/psram/sdkconfig.ci.esp32s3_quad_release new file mode 100644 index 0000000000..124eb97148 --- /dev/null +++ b/components/esp_psram/test_apps/psram/sdkconfig.ci.esp32s3_quad_release @@ -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 diff --git a/components/esp_psram/test_apps/psram/sdkconfig.defaults b/components/esp_psram/test_apps/psram/sdkconfig.defaults new file mode 100644 index 0000000000..b308cb2ddd --- /dev/null +++ b/components/esp_psram/test_apps/psram/sdkconfig.defaults @@ -0,0 +1,2 @@ +CONFIG_FREERTOS_HZ=1000 +CONFIG_ESP_TASK_WDT=n diff --git a/components/esp_system/CMakeLists.txt b/components/esp_system/CMakeLists.txt index fb0cfd6c8f..85f66a6cc6 100644 --- a/components/esp_system/CMakeLists.txt +++ b/components/esp_system/CMakeLists.txt @@ -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() diff --git a/components/esp_system/port/cpu_start.c b/components/esp_system/port/cpu_start.c index e3e33bdb2f..f93159162a 100644 --- a/components/esp_system/port/cpu_start.c +++ b/components/esp_system/port/cpu_start.c @@ -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 diff --git a/components/esp_system/startup.c b/components/esp_system/startup.c index 6bd8d3bac7..eabb0d8c6f 100644 --- a/components/esp_system/startup.c +++ b/components/esp_system/startup.c @@ -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(); diff --git a/components/freertos/CMakeLists.txt b/components/freertos/CMakeLists.txt index f3ab5a11e2..cc5937e49d 100644 --- a/components/freertos/CMakeLists.txt +++ b/components/freertos/CMakeLists.txt @@ -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() diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c index 1e21f7cf3c..27860e004d 100644 --- a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c @@ -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(); diff --git a/components/freertos/FreeRTOS-Kernel/portable/port_common.c b/components/freertos/FreeRTOS-Kernel/portable/port_common.c index 8ae7ae504d..da9fe7883b 100644 --- a/components/freertos/FreeRTOS-Kernel/portable/port_common.c +++ b/components/freertos/FreeRTOS-Kernel/portable/port_common.c @@ -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(); diff --git a/components/hal/esp32/include/hal/cache_ll.h b/components/hal/esp32/include/hal/cache_ll.h index 2241d99779..2ea6cb75b4 100644 --- a/components/hal/esp32/include/hal/cache_ll.h +++ b/components/hal/esp32/include/hal/cache_ll.h @@ -8,6 +8,7 @@ #pragma once +#include #include "soc/dport_reg.h" #include "soc/ext_mem_defs.h" #include "hal/cache_types.h" diff --git a/components/spi_flash/CMakeLists.txt b/components/spi_flash/CMakeLists.txt index 69b95528f8..515d09137e 100644 --- a/components/spi_flash/CMakeLists.txt +++ b/components/spi_flash/CMakeLists.txt @@ -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() diff --git a/components/spi_flash/flash_mmap.c b/components/spi_flash/flash_mmap.c index 12e8b38c0b..38ed5abe66 100644 --- a/components/spi_flash/flash_mmap.c +++ b/components/spi_flash/flash_mmap.c @@ -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 diff --git a/docs/doxygen/Doxyfile_esp32 b/docs/doxygen/Doxyfile_esp32 index c35a4e2ef9..a06385ea47 100644 --- a/docs/doxygen/Doxyfile_esp32 +++ b/docs/doxygen/Doxyfile_esp32 @@ -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 \ diff --git a/docs/en/api-reference/system/himem.rst b/docs/en/api-reference/system/himem.rst index 4809a4e312..530bf09ca7 100644 --- a/docs/en/api-reference/system/himem.rst +++ b/docs/en/api-reference/system/himem.rst @@ -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 diff --git a/docs/en/migration-guides/system.rst b/docs/en/migration-guides/system.rst index 3d6a8921c7..5b918b3b2a 100644 --- a/docs/en/migration-guides/system.rst +++ b/docs/en/migration-guides/system.rst @@ -45,11 +45,8 @@ ESP HW Support PSRAM ^^^^^ - -- The header file ``esp_spiram.h`` file has been deleted. Users should use the ``/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 ---------- diff --git a/examples/build_system/cmake/idf_as_lib/CMakeLists.txt b/examples/build_system/cmake/idf_as_lib/CMakeLists.txt index d9be86955e..3a61956499 100644 --- a/examples/build_system/cmake/idf_as_lib/CMakeLists.txt +++ b/examples/build_system/cmake/idf_as_lib/CMakeLists.txt @@ -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}) diff --git a/examples/system/himem/main/himem_example_main.c b/examples/system/himem/main/himem_example_main.c index 5329c27e97..c619e8a00a 100644 --- a/examples/system/himem/main/himem_example_main.c +++ b/examples/system/himem/main/himem_example_main.c @@ -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.