From 9cf41266563a620ce1047226683d53f764b5afb6 Mon Sep 17 00:00:00 2001 From: Armando Date: Wed, 12 Jan 2022 15:03:26 +0800 Subject: [PATCH 1/2] psram: add a ut for putting flash.text and rodata in psram --- .gitlab/ci/target-test.yml | 2 +- components/esp_hw_support/test/test_psram.c | 57 ++++++++++++++++++--- 2 files changed, 52 insertions(+), 7 deletions(-) diff --git a/.gitlab/ci/target-test.yml b/.gitlab/ci/target-test.yml index ba84e6e852..ebf24fe7f5 100644 --- a/.gitlab/ci/target-test.yml +++ b/.gitlab/ci/target-test.yml @@ -725,7 +725,7 @@ UT_046: UT_047: extends: .unit_test_esp32s2_template - parallel: 6 + parallel: 5 tags: - ESP32S2_IDF - UT_T1_1 diff --git a/components/esp_hw_support/test/test_psram.c b/components/esp_hw_support/test/test_psram.c index c5f87a551d..2ec2b7b859 100644 --- a/components/esp_hw_support/test/test_psram.c +++ b/components/esp_hw_support/test/test_psram.c @@ -1,23 +1,22 @@ /* - * SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ - - #include "sdkconfig.h" #include #include #include "esp_log.h" +#include "esp_attr.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" #include "test_utils.h" #include "unity.h" #include "esp_heap_caps.h" - #if CONFIG_SPIRAM #include "spiram.h" - const static char *TAG = "PSRAM"; #if CONFIG_SPIRAM_MODE_OCT @@ -26,7 +25,6 @@ const static char *TAG = "PSRAM"; #define TEST_ALLOC_SIZE (1 * 1024 * 1024) #endif - TEST_CASE("test psram heap allocable","[psram]") { uint32_t *ext_buffer = (uint32_t *)heap_caps_calloc(TEST_ALLOC_SIZE, 1, MALLOC_CAP_SPIRAM); @@ -49,4 +47,51 @@ TEST_CASE("test psram heap allocable","[psram]") free(ext_buffer); } +#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS && CONFIG_SPIRAM_RODATA +#include "esp_timer.h" +#include "esp32s3/rom/spi_flash.h" + +#define SECTOR_LEN 4096 +#define TEST_NUM 10 +#define TEST_BUF {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9} + +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) +{ + s_timer_cb_exe_times ++; + uint8_t cmp_buf[TEST_NUM] = TEST_BUF; + TEST_ASSERT(memcmp(cmp_buf, s_test_buf, TEST_NUM) == 0); +} + +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); + + esp_timer_handle_t timer; + esp_timer_create_args_t timer_args = { + .callback = &s_test_printf, + }; + TEST_ESP_OK(esp_timer_create(&timer_args, &timer)); + + esp_rom_spiflash_result_t ret; + uint32_t sector_num = start / SECTOR_LEN; + TEST_ESP_OK(esp_timer_start_periodic(timer, 1 * 10)); + + ret = esp_rom_spiflash_erase_sector(sector_num); + if (ret != ESP_ROM_SPIFLASH_RESULT_OK) { + ESP_LOGE(TAG, "erase fail!"); + TEST_ASSERT(false); + } + + TEST_ESP_OK(esp_timer_stop(timer)); + TEST_ASSERT(s_timer_cb_exe_times > 0); + printf("timer callback runs %d times\n", s_timer_cb_exe_times); +} +#endif //CONFIG_SPIRAM_FETCH_INSTRUCTIONS && CONFIG_SPIRAM_RODATA + #endif //#if CONFIG_SPIRAM From 7240ad2b3a74fdb44ffcf5f99a30eb7c82ff3f3d Mon Sep 17 00:00:00 2001 From: Armando Date: Wed, 12 Jan 2022 15:03:50 +0800 Subject: [PATCH 2/2] psram: refactor spiram.c on esp32s2 --- .../soc/esp32s2/esp_private/mmu_psram.h | 78 ++++ .../include/soc/esp32s2/spiram.h | 76 +--- components/esp_hw_support/linker.lf | 2 + .../port/esp32s2/CMakeLists.txt | 1 + .../esp_hw_support/port/esp32s2/mmu_psram.c | 242 +++++++++++ .../esp_hw_support/port/esp32s2/rtc_init.c | 91 ++-- .../esp_hw_support/port/esp32s2/spiram.c | 406 +++++------------- components/esp_system/port/cpu_start.c | 13 +- components/spi_flash/flash_mmap.c | 4 +- tools/unit-test-app/configs/psram_s2_advanced | 6 + tools/unit-test-app/configs/psram_s2_base | 3 + 11 files changed, 509 insertions(+), 413 deletions(-) create mode 100644 components/esp_hw_support/include/soc/esp32s2/esp_private/mmu_psram.h create mode 100644 components/esp_hw_support/port/esp32s2/mmu_psram.c create mode 100644 tools/unit-test-app/configs/psram_s2_advanced create mode 100644 tools/unit-test-app/configs/psram_s2_base 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 new file mode 100644 index 0000000000..cb76435697 --- /dev/null +++ b/components/esp_hw_support/include/soc/esp32s2/esp_private/mmu_psram.h @@ -0,0 +1,78 @@ +/* + * 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 +extern int _instruction_reserved_start; +extern int _instruction_reserved_end; + +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 +extern int _rodata_reserved_start; +extern int _rodata_reserved_end; + +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 index 70d07e61a8..15b9868764 100644 --- a/components/esp_hw_support/include/soc/esp32s2/spiram.h +++ b/components/esp_hw_support/include/soc/esp32s2/spiram.h @@ -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 */ @@ -24,35 +24,11 @@ extern "C" { */ 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 Get the size of the attached SPI RAM chip selected in menuconfig * @@ -60,7 +36,6 @@ esp_err_t esp_spiram_add_to_heapalloc(void); */ size_t esp_spiram_get_size(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 @@ -80,7 +55,6 @@ void esp_spiram_writeback_cache(void); */ uint8_t esp_spiram_get_cs_io(void); - /** * @brief Reserve a pool of internal memory for specific DMA/internal allocations * @@ -101,54 +75,6 @@ esp_err_t esp_spiram_reserve_dma_pool(size_t size); */ bool esp_spiram_is_initialized(void); -#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS - -extern int _instruction_reserved_start, _instruction_reserved_end; - -/** - * @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 - -extern int _rodata_reserved_start, _rodata_reserved_end; - -/** - * @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/linker.lf b/components/esp_hw_support/linker.lf index 0a542bccff..0bae8f25d8 100644 --- a/components/esp_hw_support/linker.lf +++ b/components/esp_hw_support/linker.lf @@ -16,3 +16,5 @@ entries: spiram_psram (noflash) if SPIRAM_MODE_OCT = y: opiram_psram (noflash) + if IDF_TARGET_ESP32S2 = y: + mmu_psram (noflash) diff --git a/components/esp_hw_support/port/esp32s2/CMakeLists.txt b/components/esp_hw_support/port/esp32s2/CMakeLists.txt index 5254de95a4..336bfd1b84 100644 --- a/components/esp_hw_support/port/esp32s2/CMakeLists.txt +++ b/components/esp_hw_support/port/esp32s2/CMakeLists.txt @@ -21,6 +21,7 @@ if(NOT BOOTLOADER_BUILD) "esp_ds.c" "dport_access.c" "spiram.c" + "mmu_psram.c" "spiram_psram.c") endif() diff --git a/components/esp_hw_support/port/esp32s2/mmu_psram.c b/components/esp_hw_support/port/esp32s2/mmu_psram.c new file mode 100644 index 0000000000..f72e88a972 --- /dev/null +++ b/components/esp_hw_support/port/esp32s2/mmu_psram.c @@ -0,0 +1,242 @@ +/* + * 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/cache_memory.h" +#include "soc/extmem_reg.h" + +#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 +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 +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(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 & BUS_ADDR_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_ADDRESS_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 & BUS_ADDR_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_ADDRESS_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/rtc_init.c b/components/esp_hw_support/port/esp32s2/rtc_init.c index 7932a89aa0..b3fd093726 100644 --- a/components/esp_hw_support/port/esp32s2/rtc_init.c +++ b/components/esp_hw_support/port/esp32s2/rtc_init.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 */ @@ -236,52 +236,55 @@ static void set_ocode_by_efuse(int calib_version) REGI2C_WRITE_MASK(I2C_ULP, I2C_ULP_IR_FORCE_CODE, 1); } +/** + * TODO IDF-4141, this seems influence flash, + */ static void calibrate_ocode(void) { - /* - Bandgap output voltage is not precise when calibrate o-code by hardware sometimes, so need software o-code calibration (must turn off PLL). - Method: - 1. read current cpu config, save in old_config; - 2. switch cpu to xtal because PLL will be closed when o-code calibration; - 3. begin o-code calibration; - 4. wait o-code calibration done flag(odone_flag & bg_odone_flag) or timeout; - 5. set cpu to old-config. - */ - rtc_slow_freq_t slow_clk_freq = rtc_clk_slow_freq_get(); - rtc_slow_freq_t rtc_slow_freq_x32k = RTC_SLOW_FREQ_32K_XTAL; - rtc_slow_freq_t rtc_slow_freq_8MD256 = RTC_SLOW_FREQ_8MD256; - rtc_cal_sel_t cal_clk = RTC_CAL_RTC_MUX; - if (slow_clk_freq == (rtc_slow_freq_x32k)) { - cal_clk = RTC_CAL_32K_XTAL; - } else if (slow_clk_freq == rtc_slow_freq_8MD256) { - cal_clk = RTC_CAL_8MD256; - } + // /* + // Bandgap output voltage is not precise when calibrate o-code by hardware sometimes, so need software o-code calibration (must turn off PLL). + // Method: + // 1. read current cpu config, save in old_config; + // 2. switch cpu to xtal because PLL will be closed when o-code calibration; + // 3. begin o-code calibration; + // 4. wait o-code calibration done flag(odone_flag & bg_odone_flag) or timeout; + // 5. set cpu to old-config. + // */ + // rtc_slow_freq_t slow_clk_freq = rtc_clk_slow_freq_get(); + // rtc_slow_freq_t rtc_slow_freq_x32k = RTC_SLOW_FREQ_32K_XTAL; + // rtc_slow_freq_t rtc_slow_freq_8MD256 = RTC_SLOW_FREQ_8MD256; + // rtc_cal_sel_t cal_clk = RTC_CAL_RTC_MUX; + // if (slow_clk_freq == (rtc_slow_freq_x32k)) { + // cal_clk = RTC_CAL_32K_XTAL; + // } else if (slow_clk_freq == rtc_slow_freq_8MD256) { + // cal_clk = RTC_CAL_8MD256; + // } - uint64_t max_delay_time_us = 10000; - uint32_t slow_clk_period = rtc_clk_cal(cal_clk, 100); - uint64_t max_delay_cycle = rtc_time_us_to_slowclk(max_delay_time_us, slow_clk_period); - uint64_t cycle0 = rtc_time_get(); - uint64_t timeout_cycle = cycle0 + max_delay_cycle; - uint64_t cycle1 = 0; + // uint64_t max_delay_time_us = 10000; + // uint32_t slow_clk_period = rtc_clk_cal(cal_clk, 100); + // uint64_t max_delay_cycle = rtc_time_us_to_slowclk(max_delay_time_us, slow_clk_period); + // uint64_t cycle0 = rtc_time_get(); + // uint64_t timeout_cycle = cycle0 + max_delay_cycle; + // uint64_t cycle1 = 0; - rtc_cpu_freq_config_t old_config; - rtc_clk_cpu_freq_get_config(&old_config); - rtc_clk_cpu_freq_set_xtal(); + // rtc_cpu_freq_config_t old_config; + // rtc_clk_cpu_freq_get_config(&old_config); + // rtc_clk_cpu_freq_set_xtal(); - REGI2C_WRITE_MASK(I2C_ULP, I2C_ULP_IR_RESETB, 0); - REGI2C_WRITE_MASK(I2C_ULP, I2C_ULP_IR_RESETB, 1); - bool odone_flag = 0; - bool bg_odone_flag = 0; - while(1) { - odone_flag = REGI2C_READ_MASK(I2C_ULP, I2C_ULP_O_DONE_FLAG); - bg_odone_flag = REGI2C_READ_MASK(I2C_ULP, I2C_ULP_BG_O_DONE_FLAG); - cycle1 = rtc_time_get(); - if (odone_flag && bg_odone_flag) - break; - if (cycle1 >= timeout_cycle) { - SOC_LOGW(TAG, "o_code calibration fail"); - break; - } - } - rtc_clk_cpu_freq_set_config(&old_config); + // REGI2C_WRITE_MASK(I2C_ULP, I2C_ULP_IR_RESETB, 0); + // REGI2C_WRITE_MASK(I2C_ULP, I2C_ULP_IR_RESETB, 1); + // bool odone_flag = 0; + // bool bg_odone_flag = 0; + // while(1) { + // odone_flag = REGI2C_READ_MASK(I2C_ULP, I2C_ULP_O_DONE_FLAG); + // bg_odone_flag = REGI2C_READ_MASK(I2C_ULP, I2C_ULP_BG_O_DONE_FLAG); + // cycle1 = rtc_time_get(); + // if (odone_flag && bg_odone_flag) + // break; + // if (cycle1 >= timeout_cycle) { + // SOC_LOGW(TAG, "o_code calibration fail"); + // break; + // } + // } + // rtc_clk_cpu_freq_set_config(&old_config); } diff --git a/components/esp_hw_support/port/esp32s2/spiram.c b/components/esp_hw_support/port/esp32s2/spiram.c index ebb2be078b..ff3d46f48f 100644 --- a/components/esp_hw_support/port/esp32s2/spiram.c +++ b/components/esp_hw_support/port/esp32s2/spiram.c @@ -1,39 +1,32 @@ /* -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-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ -#include -#include + +/*---------------------------------------------------------------------------------------------------- + * 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 "esp32s2/spiram.h" -#include "spiram_psram.h" #include "esp_log.h" #include "freertos/FreeRTOS.h" #include "freertos/xtensa_api.h" -#include "soc/soc.h" #include "esp_heap_caps_init.h" -#include "soc/soc_memory_layout.h" -#include "soc/dport_reg.h" -#include "esp32s2/rom/cache.h" -#include "soc/cache_memory.h" -#include "soc/extmem_reg.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 -static const char* TAG = "spiram"; - #if CONFIG_SPIRAM_SPEED_40M #define PSRAM_SPEED PSRAM_CACHE_S40M #elif CONFIG_SPIRAM_SPEED_80M @@ -42,206 +35,23 @@ static const char* TAG = "spiram"; #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 uint32_t s_allocable_vaddr_start; +static uint32_t s_allocable_vaddr_end; + static bool spiram_inited=false; +static const char* TAG = "spiram"; -#define DRAM0_ONLY_CACHE_SIZE BUS_IRAM0_CACHE_SIZE -#define DRAM0_DRAM1_CACHE_SIZE (BUS_IRAM0_CACHE_SIZE + BUS_IRAM1_CACHE_SIZE) -#define DRAM0_DRAM1_DPORT_CACHE_SIZE (BUS_IRAM0_CACHE_SIZE + BUS_IRAM1_CACHE_SIZE + BUS_DPORT_CACHE_SIZE) -#define SPIRAM_SIZE_EXC_DRAM0_DRAM1_DPORT (spiram_size - DRAM0_DRAM1_DPORT_CACHE_SIZE) +bool esp_spiram_test(uint32_t v_start, uint32_t size); -#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY -extern uint8_t _ext_ram_bss_start, _ext_ram_bss_end; -#define ALIGN_UP_BY(num, align) (((num) + ((align) - 1)) & ~((align) - 1)) -#define EXT_BSS_SIZE ((uint32_t)(&_ext_ram_bss_end - &_ext_ram_bss_start)) -#define EXT_BSS_PAGE_ALIGN_SIZE (ALIGN_UP_BY(EXT_BSS_SIZE, 0x10000)) -#endif - -#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY -#define SPIRAM_MAP_PADDR_START EXT_BSS_PAGE_ALIGN_SIZE -#define FREE_DRAM0_DRAM1_DPORT_CACHE_START (DPORT_CACHE_ADDRESS_LOW + EXT_BSS_PAGE_ALIGN_SIZE) -#define FREE_DRAM0_DRAM1_DPORT_CACHE_SIZE (DRAM0_DRAM1_DPORT_CACHE_SIZE - EXT_BSS_PAGE_ALIGN_SIZE) -#else -#define SPIRAM_MAP_PADDR_START 0 -#define FREE_DRAM0_DRAM1_DPORT_CACHE_START (DPORT_CACHE_ADDRESS_LOW) -#define FREE_DRAM0_DRAM1_DPORT_CACHE_SIZE (DRAM0_DRAM1_DPORT_CACHE_SIZE) -#endif // if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY - -#define SPIRAM_MAP_VADDR_START (DRAM0_CACHE_ADDRESS_HIGH - spiram_map_size) -#define SPIRAM_MAP_SIZE spiram_map_size - -static uint32_t next_map_page_num = 0; -static uint32_t instruction_in_spiram = 0; -static uint32_t rodata_in_spiram = 0; -static size_t spiram_size = 0; -static size_t spiram_map_size = 0; - -#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS -static int instr_flash2spiram_offs = 0; -static uint32_t instr_start_page = 0; -static uint32_t instr_end_page = 0; -#endif - -#if CONFIG_SPIRAM_RODATA -static int rodata_flash2spiram_offs = 0; -static uint32_t rodata_start_page = 0; -static uint32_t rodata_end_page = 0; -#endif - -#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS || CONFIG_SPIRAM_RODATA -static uint32_t page0_mapped = 0; -static uint32_t page0_page = INVALID_PHY_PAGE; -#endif - -void IRAM_ATTR esp_spiram_init_cache(void) -{ - spiram_map_size = spiram_size; - Cache_Suspend_DCache(); - -#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY - /*if instruction or rodata in flash will be load to spiram, some subsequent operations require the start - address to be aligned by page, so allocate N pages address space for spiram's bss*/ - Cache_Dbus_MMU_Set(MMU_ACCESS_SPIRAM, DPORT_CACHE_ADDRESS_LOW, 0, 64, EXT_BSS_PAGE_ALIGN_SIZE >> 16, 0); - REG_CLR_BIT(EXTMEM_PRO_DCACHE_CTRL1_REG, EXTMEM_PRO_DCACHE_MASK_DPORT); - next_map_page_num += (EXT_BSS_PAGE_ALIGN_SIZE >> 16); - spiram_map_size -= EXT_BSS_PAGE_ALIGN_SIZE; -#endif - - /* map the address from SPIRAM end to the start, map the address in order: DRAM0, DRAM1, DPORT */ - if (spiram_map_size <= DRAM0_ONLY_CACHE_SIZE) { - /* psram need to be mapped vaddr size <= 3MB + 512 KB, only map DRAM0 bus */ - Cache_Dbus_MMU_Set(MMU_ACCESS_SPIRAM, SPIRAM_MAP_VADDR_START, SPIRAM_MAP_PADDR_START, 64, SPIRAM_MAP_SIZE >> 16, 0); - REG_CLR_BIT(EXTMEM_PRO_DCACHE_CTRL1_REG, EXTMEM_PRO_DCACHE_MASK_DRAM0); - } else if (spiram_map_size <= DRAM0_DRAM1_CACHE_SIZE) { - /* psram need to be mapped vaddr size <= 7MB + 512KB, only map DRAM0 and DRAM1 bus */ - Cache_Dbus_MMU_Set(MMU_ACCESS_SPIRAM, SPIRAM_MAP_VADDR_START, SPIRAM_MAP_PADDR_START, 64, SPIRAM_MAP_SIZE >> 16, 0); - REG_CLR_BIT(EXTMEM_PRO_DCACHE_CTRL1_REG, EXTMEM_PRO_DCACHE_MASK_DRAM1 | EXTMEM_PRO_DCACHE_MASK_DRAM0); - } else if (spiram_size <= DRAM0_DRAM1_DPORT_CACHE_SIZE) { // Equivalent to {spiram_map_size < DRAM0_DRAM1_DPORT_CACHE_SIZE - (spiram_size - spiram_map_size)/*bss size*/} - /* psram need to be mapped vaddr size <= 10MB + 512KB - bss_page_align_size, map DRAM0, DRAM1, DPORT bus */ - Cache_Dbus_MMU_Set(MMU_ACCESS_SPIRAM, SPIRAM_MAP_VADDR_START, SPIRAM_MAP_PADDR_START, 64, SPIRAM_MAP_SIZE >> 16, 0); - REG_CLR_BIT(EXTMEM_PRO_DCACHE_CTRL1_REG, EXTMEM_PRO_DCACHE_MASK_DRAM1 | EXTMEM_PRO_DCACHE_MASK_DRAM0 | EXTMEM_PRO_DCACHE_MASK_DPORT); - } else { - /* psram need to be mapped vaddr size > 10MB + 512KB - bss_page_align_size, map DRAM0, DRAM1, DPORT bus ,discard the memory in the end of spiram */ - Cache_Dbus_MMU_Set(MMU_ACCESS_SPIRAM, FREE_DRAM0_DRAM1_DPORT_CACHE_START, SPIRAM_MAP_PADDR_START, 64, FREE_DRAM0_DRAM1_DPORT_CACHE_SIZE >> 16, 0); - REG_CLR_BIT(EXTMEM_PRO_DCACHE_CTRL1_REG, EXTMEM_PRO_DCACHE_MASK_DRAM1 | EXTMEM_PRO_DCACHE_MASK_DRAM0 | EXTMEM_PRO_DCACHE_MASK_DPORT); - } - Cache_Resume_DCache(0); -} - -uint32_t esp_spiram_instruction_access_enabled(void) -{ - return instruction_in_spiram; -} - -uint32_t esp_spiram_rodata_access_enabled(void) -{ - return rodata_in_spiram; -} - -#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS -esp_err_t esp_spiram_enable_instruction_access(void) -{ - uint32_t pages_in_flash = 0; - pages_in_flash += Cache_Count_Flash_Pages(PRO_CACHE_IBUS0, &page0_mapped); - pages_in_flash += Cache_Count_Flash_Pages(PRO_CACHE_IBUS1, &page0_mapped); - if ((pages_in_flash + next_map_page_num) > (spiram_size >> 16)) { - ESP_EARLY_LOGE(TAG, "SPI RAM space not enough for the instructions, has %d pages, need %d pages.", (spiram_size >> 16), (pages_in_flash + next_map_page_num)); - return ESP_FAIL; - } - ESP_EARLY_LOGI(TAG, "Instructions copied and mapped to SPIRAM"); - uint32_t instr_mmu_offset = ((uint32_t)&_instruction_reserved_start & 0xFFFFFF)/MMU_PAGE_SIZE; - uint32_t mmu_value = *(volatile uint32_t *)(DR_REG_MMU_TABLE + PRO_CACHE_IBUS0_MMU_START + instr_mmu_offset*sizeof(uint32_t)); - mmu_value &= MMU_ADDRESS_MASK; - instr_flash2spiram_offs = mmu_value - next_map_page_num; - ESP_EARLY_LOGV(TAG, "Instructions from flash page%d copy to SPIRAM page%d, Offset: %d", mmu_value, next_map_page_num, instr_flash2spiram_offs); - next_map_page_num = Cache_Flash_To_SPIRAM_Copy(PRO_CACHE_IBUS0, IRAM0_ADDRESS_LOW, next_map_page_num, &page0_page); - next_map_page_num = Cache_Flash_To_SPIRAM_Copy(PRO_CACHE_IBUS1, IRAM1_ADDRESS_LOW, next_map_page_num, &page0_page); - instruction_in_spiram = 1; - return ESP_OK; -} -#endif - -#if CONFIG_SPIRAM_RODATA -esp_err_t esp_spiram_enable_rodata_access(void) -{ - uint32_t pages_in_flash = 0; - pages_in_flash += Cache_Count_Flash_Pages(PRO_CACHE_IBUS2, &page0_mapped); - pages_in_flash += Cache_Count_Flash_Pages(PRO_CACHE_DBUS0, &page0_mapped); - pages_in_flash += Cache_Count_Flash_Pages(PRO_CACHE_DBUS1, &page0_mapped); - pages_in_flash += Cache_Count_Flash_Pages(PRO_CACHE_DBUS2, &page0_mapped); - - if ((pages_in_flash + next_map_page_num) > (spiram_size >> 16)) { - ESP_EARLY_LOGE(TAG, "SPI RAM space not enough for the read only data."); - return ESP_FAIL; - } - - ESP_EARLY_LOGI(TAG, "Read only data copied and mapped to SPIRAM"); - uint32_t rodata_mmu_offset = ((uint32_t)&_rodata_reserved_start & 0xFFFFFF)/MMU_PAGE_SIZE; - uint32_t mmu_value = *(volatile uint32_t *)(DR_REG_MMU_TABLE + PRO_CACHE_IBUS2_MMU_START + rodata_mmu_offset*sizeof(uint32_t)); - mmu_value &= MMU_ADDRESS_MASK; - rodata_flash2spiram_offs = mmu_value - next_map_page_num; - ESP_EARLY_LOGV(TAG, "Rodata from flash page%d copy to SPIRAM page%d, Offset: %d", mmu_value, next_map_page_num, rodata_flash2spiram_offs); - next_map_page_num = Cache_Flash_To_SPIRAM_Copy(PRO_CACHE_IBUS2, DROM0_ADDRESS_LOW, next_map_page_num, &page0_page); - next_map_page_num = Cache_Flash_To_SPIRAM_Copy(PRO_CACHE_DBUS0, DRAM0_ADDRESS_LOW, next_map_page_num, &page0_page); - next_map_page_num = Cache_Flash_To_SPIRAM_Copy(PRO_CACHE_DBUS1, DRAM1_ADDRESS_LOW, next_map_page_num, &page0_page); - next_map_page_num = Cache_Flash_To_SPIRAM_Copy(PRO_CACHE_DBUS2, DPORT_ADDRESS_LOW, next_map_page_num, &page0_page); - rodata_in_spiram = 1; - return ESP_OK; -} -#endif - -#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS -void instruction_flash_page_info_init(void) -{ - uint32_t instr_page_cnt = ((uint32_t)&_instruction_reserved_end - SOC_IROM_LOW + MMU_PAGE_SIZE - 1)/MMU_PAGE_SIZE; - uint32_t instr_mmu_offset = ((uint32_t)&_instruction_reserved_start & 0xFFFFFF)/MMU_PAGE_SIZE; - - instr_start_page = *(volatile uint32_t *)(DR_REG_MMU_TABLE + PRO_CACHE_IBUS0_MMU_START + instr_mmu_offset*sizeof(uint32_t)); - instr_start_page &= MMU_ADDRESS_MASK; - instr_end_page = instr_start_page + instr_page_cnt - 1; -} - -uint32_t IRAM_ATTR instruction_flash_start_page_get(void) -{ - return instr_start_page; -} - -uint32_t IRAM_ATTR instruction_flash_end_page_get(void) -{ - return instr_end_page; -} - -int IRAM_ATTR instruction_flash2spiram_offset(void) -{ - return instr_flash2spiram_offs; -} -#endif - -#if CONFIG_SPIRAM_RODATA -void rodata_flash_page_info_init(void) -{ - uint32_t rodata_page_cnt = ((uint32_t)&_rodata_reserved_end - SOC_DROM_LOW + MMU_PAGE_SIZE - 1)/MMU_PAGE_SIZE; - uint32_t rodata_mmu_offset = ((uint32_t)&_rodata_reserved_start & 0xFFFFFF)/MMU_PAGE_SIZE; - - rodata_start_page = *(volatile uint32_t *)(DR_REG_MMU_TABLE + PRO_CACHE_IBUS2_MMU_START + rodata_mmu_offset*sizeof(uint32_t)); - rodata_start_page &= MMU_ADDRESS_MASK; - rodata_end_page = rodata_start_page + rodata_page_cnt - 1; -} - -uint32_t IRAM_ATTR rodata_flash_start_page_get(void) -{ - return rodata_start_page; -} - -uint32_t IRAM_ATTR rodata_flash_end_page_get(void) -{ - return rodata_end_page; -} - -int IRAM_ATTR rodata_flash2spiram_offset(void) -{ - return rodata_flash2spiram_offs; -} -#endif esp_err_t esp_spiram_init(void) { @@ -256,8 +66,8 @@ esp_err_t esp_spiram_init(void) spiram_inited = true; - spiram_size = esp_spiram_get_size(); - + //TODO IDF-4380 + size_t spiram_size = esp_spiram_get_size(); #if (CONFIG_SPIRAM_SIZE != -1) if (spiram_size != CONFIG_SPIRAM_SIZE) { ESP_EARLY_LOGE(TAG, "Expected %dKiB chip but found %dKiB chip. Bailing out..", CONFIG_SPIRAM_SIZE/1024, spiram_size/1024); @@ -273,62 +83,83 @@ esp_err_t esp_spiram_init(void) (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"); + + uint32_t psram_available_size = spiram_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 + r = mmu_config_psram_text_segment(start_page, spiram_size, &used_page); + if (r != 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 + r = mmu_config_psram_rodata_segment(start_page, spiram_size, &used_page); + if (r != 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 (r != 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_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; } - esp_err_t esp_spiram_add_to_heapalloc(void) { - size_t recycle_pages_size = 0; - size_t map_size = 0; - intptr_t map_vaddr, map_paddr; - ESP_EARLY_LOGI(TAG, "Adding pool of %dK of external SPI memory to heap allocator", (spiram_size - (next_map_page_num << 16))/1024); - -#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY - if(EXT_BSS_SIZE){ - ESP_EARLY_LOGI(TAG, "Adding pool of %d Byte(spiram .bss page unused area) of external SPI memory to heap allocator", EXT_BSS_PAGE_ALIGN_SIZE - EXT_BSS_SIZE); - esp_err_t err_status = heap_caps_add_region(DPORT_CACHE_ADDRESS_LOW + EXT_BSS_SIZE, FREE_DRAM0_DRAM1_DPORT_CACHE_START - 1); - if (err_status != ESP_OK){ - return err_status; - } - } -#endif - -#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS || CONFIG_SPIRAM_RODATA - /* Part of the physical address space in spiram is mapped by IRAM0/DROM0, - so the DPORT_DRAM0_DRAM1 address space of the same size can be released */ - uint32_t occupied_pages_size = (next_map_page_num << 16); - recycle_pages_size = occupied_pages_size - SPIRAM_MAP_PADDR_START; -#endif - - // Small size: means DPORT_DRAM0_DRAM1 bus virtrual address space larger than the spiram size - if (spiram_size <= DRAM0_DRAM1_DPORT_CACHE_SIZE) { - map_vaddr = SPIRAM_MAP_VADDR_START; - return heap_caps_add_region(map_vaddr + recycle_pages_size, map_vaddr + spiram_map_size - 1); // pass rodata & instruction section - } - - // Middle size: means DPORT_DRAM0_DRAM1 bus virtrual address space less than the - // spiram size, but after releasing the virtual address space mapped - // from the rodata or instruction copied from the flash, the released - // virtual address space is enough to map the abandoned physical address - // space in spiram - if (recycle_pages_size >= SPIRAM_SIZE_EXC_DRAM0_DRAM1_DPORT) { - map_vaddr = SPIRAM_MAP_VADDR_START + recycle_pages_size; - map_paddr = SPIRAM_MAP_PADDR_START + recycle_pages_size; - map_size = SPIRAM_MAP_SIZE - recycle_pages_size; - Cache_Dbus_MMU_Set(MMU_ACCESS_SPIRAM, map_vaddr, map_paddr, 64, map_size >> 16, 0); - return heap_caps_add_region(map_vaddr , map_vaddr + map_size - 1); - } - - // Large size: means after releasing the virtual address space mapped from the rodata - // or instruction copied from the flash, the released virtual address space - // still not enough to map the abandoned physical address space in spiram, - // so use all the virtual address space as much as possible - map_vaddr = FREE_DRAM0_DRAM1_DPORT_CACHE_START; - map_paddr = SPIRAM_MAP_PADDR_START + recycle_pages_size; - map_size = FREE_DRAM0_DRAM1_DPORT_CACHE_SIZE; - Cache_Dbus_MMU_Set(MMU_ACCESS_SPIRAM, map_vaddr, map_paddr, 64, map_size >> 16, 0); - return heap_caps_add_region(map_vaddr, map_vaddr + FREE_DRAM0_DRAM1_DPORT_CACHE_SIZE -1); + return heap_caps_add_region(s_allocable_vaddr_start, s_allocable_vaddr_end - 1); } static uint8_t *dma_heap; @@ -342,6 +173,7 @@ esp_err_t esp_spiram_reserve_dma_pool(size_t size) { return heap_caps_add_region_with_caps(caps, (intptr_t) dma_heap, (intptr_t) dma_heap+size-1); } +//TODO IDF-4380 size_t esp_spiram_get_size(void) { if (!spiram_inited) { @@ -387,38 +219,34 @@ 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. */ -bool esp_spiram_test(void) +bool esp_spiram_test(uint32_t v_start, uint32_t size) { - volatile int *spiram = (volatile int*)(SOC_EXTRAM_DATA_HIGH - spiram_map_size); - size_t p; - size_t s = spiram_map_size; - int errct=0; - int initial_err=-1; + volatile int *spiram = (volatile int *)v_start; - if (SOC_EXTRAM_DATA_SIZE < spiram_map_size) { - ESP_EARLY_LOGW(TAG, "Only test spiram from %08x to %08x\n", SOC_EXTRAM_DATA_LOW, SOC_EXTRAM_DATA_HIGH); - spiram=(volatile int*)SOC_EXTRAM_DATA_LOW; - s = SOC_EXTRAM_DATA_SIZE; + 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) { - 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) { + if (spiram[p] != (p ^ 0xAAAAAAAA)) { errct++; - if (errct==1) initial_err=p*4; + 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); + 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); + 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; } } - -#endif +#endif //#if CONFIG_SPIRAM diff --git a/components/esp_system/port/cpu_start.c b/components/esp_system/port/cpu_start.c index d921aeaa82..3cd62463d2 100644 --- a/components/esp_system/port/cpu_start.c +++ b/components/esp_system/port/cpu_start.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 */ @@ -404,9 +404,12 @@ void IRAM_ATTR call_start_cpu0(void) abort(); #endif } + //TODO: IDF-4382 +#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S3 if (g_spiram_ok) { esp_spiram_init_cache(); } +#endif //#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S3, //TODO: IDF-4382 #endif #if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE @@ -435,6 +438,8 @@ 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 || CONFIG_IDF_TARGET_ESP32S3 if (g_spiram_ok) { bool ext_ram_ok = esp_spiram_test(); if (!ext_ram_ok) { @@ -442,8 +447,11 @@ void IRAM_ATTR call_start_cpu0(void) abort(); } } -#endif +#endif //CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S3, //TODO: IDF-4382 +#endif //CONFIG_SPIRAM_MEMTEST + //TODO: IDF-4382 +#if CONFIG_IDF_TARGET_ESP32S3 #if CONFIG_SPIRAM_FETCH_INSTRUCTIONS extern void instruction_flash_page_info_init(void); instruction_flash_page_info_init(); @@ -462,7 +470,6 @@ void IRAM_ATTR call_start_cpu0(void) esp_spiram_enable_rodata_access(); #endif -#if CONFIG_IDF_TARGET_ESP32S3 int s_instr_flash2spiram_off = 0; int s_rodata_flash2spiram_off = 0; #if CONFIG_SPIRAM_FETCH_INSTRUCTIONS diff --git a/components/spi_flash/flash_mmap.c b/components/spi_flash/flash_mmap.c index 9364399fdb..e08c5cc1dd 100644 --- a/components/spi_flash/flash_mmap.c +++ b/components/spi_flash/flash_mmap.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 */ @@ -32,7 +32,7 @@ #define INVALID_PHY_PAGE 0xffff #elif CONFIG_IDF_TARGET_ESP32S2 #include "esp32s2/rom/cache.h" -#include "esp32s2/spiram.h" +#include "esp_private/mmu_psram.h" #include "soc/extmem_reg.h" #include "soc/cache_memory.h" #include "soc/mmu.h" diff --git a/tools/unit-test-app/configs/psram_s2_advanced b/tools/unit-test-app/configs/psram_s2_advanced new file mode 100644 index 0000000000..e712b62518 --- /dev/null +++ b/tools/unit-test-app/configs/psram_s2_advanced @@ -0,0 +1,6 @@ +CONFIG_IDF_TARGET="esp32s2" +TEST_COMPONENTS=esp_hw_support esp_common +CONFIG_ESP32S2_SPIRAM_SUPPORT=y +CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y +CONFIG_SPIRAM_RODATA=y +CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY=y diff --git a/tools/unit-test-app/configs/psram_s2_base b/tools/unit-test-app/configs/psram_s2_base new file mode 100644 index 0000000000..a625628d56 --- /dev/null +++ b/tools/unit-test-app/configs/psram_s2_base @@ -0,0 +1,3 @@ +CONFIG_IDF_TARGET="esp32s2" +TEST_COMPONENTS=esp_hw_support +CONFIG_ESP32S2_SPIRAM_SUPPORT=y