Merge branch 'feat/xip_psram_c5' into 'master'

psram: xip_psram support on c5/c61, also fixed cache writeback/invalidate not work issue on c61

Closes IDF-8688, IDF-9292, and IDF-11008

See merge request espressif/esp-idf!33265
This commit is contained in:
Armando (Dou Yiwen)
2024-09-06 10:39:57 +08:00
23 changed files with 236 additions and 15 deletions

View File

@@ -875,7 +875,7 @@ static void set_cache_and_start_app(
}
//we use the MMU_LL_END_DROM_ENTRY_ID mmu entry as a map page for app to find the boot partition
mmu_hal_map_region(0, MMU_TARGET_FLASH0, MMU_LL_END_DROM_ENTRY_VADDR, drom_addr_aligned, CONFIG_MMU_PAGE_SIZE, &actual_mapped_len);
ESP_EARLY_LOGV(TAG, "mapped one page of the rodata, from paddr=0x%08" PRIx32 " and vaddr=0x%08" PRIx32 ", 0x%" PRIx32 " bytes are mapped", drom_addr_aligned, drom_load_addr_aligned, actual_mapped_len);
ESP_EARLY_LOGV(TAG, "mapped one page of the rodata, from paddr=0x%08" PRIx32 " and vaddr=0x%08" PRIx32 ", 0x%" PRIx32 " bytes are mapped", drom_addr_aligned, MMU_LL_END_DROM_ENTRY_VADDR, actual_mapped_len);
#endif
//-----------------------MAP IROM--------------------------

View File

@@ -44,5 +44,39 @@ menu "SPI RAM config"
default 80 if SPIRAM_SPEED_80M
default 40 if SPIRAM_SPEED_40M
config SPIRAM_FETCH_INSTRUCTIONS
bool
help
Enable this option allows moving application's instruction segment from the SPI Flash to PSRAM
config SPIRAM_RODATA
bool
help
Enable this option allows moving application's rodata segment from the SPI Flash to
PSRAM
config SPIRAM_XIP_FROM_PSRAM
bool "Enable Executable in place from (XiP) from PSRAM feature (READ HELP)"
default n
select SPIRAM_FETCH_INSTRUCTIONS
select SPIRAM_RODATA
select SPIRAM_FLASH_LOAD_TO_PSRAM
help
If enabled, firmware in flash including instructions and data will be moved into PSRAM on startup,
firmware code will execute directly from PSRAM.
With this option enabled, code that requires execution during an MSPI1 Flash operation
does not have to be placed in IRAM. Therefore codes that need to be executing during Flash
operations can continue working normally.
This feature is useful for high throughput peripheral involved applications to improve
the performance during MSPI1 flash operations.
config SPIRAM_FLASH_LOAD_TO_PSRAM
bool
help
This is a helper indicating this condition:
`CONFIG_SPIRAM_XIP_FROM_PSRAM && CONFIG_IDF_TARGET_ESP32C5`
source "$IDF_PATH/components/esp_psram/Kconfig.spiram.common" # insert non-chip-specific items here
endmenu

View File

@@ -44,5 +44,39 @@ menu "SPI RAM config"
default 80 if SPIRAM_SPEED_80M
default 40 if SPIRAM_SPEED_40M
config SPIRAM_FETCH_INSTRUCTIONS
bool
help
Enable this option allows moving application's instruction segment from the SPI Flash to PSRAM
config SPIRAM_RODATA
bool
help
Enable this option allows moving application's rodata segment from the SPI Flash to
PSRAM
config SPIRAM_XIP_FROM_PSRAM
bool "Enable Executable in place from (XiP) from PSRAM feature (READ HELP)"
default n
select SPIRAM_FETCH_INSTRUCTIONS
select SPIRAM_RODATA
select SPIRAM_FLASH_LOAD_TO_PSRAM
help
If enabled, firmware in flash including instructions and data will be moved into PSRAM on startup,
firmware code will execute directly from PSRAM.
With this option enabled, code that requires execution during an MSPI1 Flash operation
does not have to be placed in IRAM. Therefore codes that need to be executing during Flash
operations can continue working normally.
This feature is useful for high throughput peripheral involved applications to improve
the performance during MSPI1 flash operations.
config SPIRAM_FLASH_LOAD_TO_PSRAM
bool
help
This is a helper indicating this condition:
`CONFIG_SPIRAM_XIP_FROM_PSRAM && CONFIG_IDF_TARGET_ESP32C61`
source "$IDF_PATH/components/esp_psram/Kconfig.spiram.common" # insert non-chip-specific items here
endmenu

View File

@@ -30,7 +30,7 @@ extern "C" {
#if CONFIG_IDF_TARGET_ESP32
#define MMU_PAGE_SIZE 0x8000
#else
#define MMU_PAGE_SIZE 0x10000
#define MMU_PAGE_SIZE CONFIG_MMU_PAGE_SIZE
#define MMU_PAGE_TO_BYTES(page_id) ((page_id) * MMU_PAGE_SIZE)
#define BYTES_TO_MMU_PAGE(bytes) ((bytes) / MMU_PAGE_SIZE)
#endif

View File

@@ -85,7 +85,7 @@ esp_err_t mmu_config_psram_text_segment(uint32_t start_page, uint32_t psram_size
uint32_t flash_irom_paddr_start = 0;
image_process_get_flash_segments_info(&flash_drom_paddr_start, &flash_irom_paddr_start);
flash_irom_paddr_start = ALIGN_DOWN_BY(flash_irom_paddr_start, CONFIG_MMU_PAGE_SIZE);
ESP_EARLY_LOGI(TAG, "flash_irom_paddr_start: 0x%x", flash_irom_paddr_start);
ESP_EARLY_LOGV(TAG, "flash_irom_paddr_start: 0x%x", flash_irom_paddr_start);
if ((MMU_PAGE_TO_BYTES(start_page) + irom_size) > psram_size) {
ESP_EARLY_LOGE(TAG, "PSRAM space not enough for the Flash instructions, need %"PRId32" B, from %"PRId32" B to %"PRId32" B", irom_size, MMU_PAGE_TO_BYTES(start_page), MMU_PAGE_TO_BYTES(start_page) + irom_size);
@@ -106,6 +106,7 @@ esp_err_t mmu_config_psram_text_segment(uint32_t start_page, uint32_t psram_size
start_page += BYTES_TO_MMU_PAGE(irom_size);
*out_page = start_page;
ESP_EARLY_LOGI(TAG, ".text xip on psram");
return ESP_OK;
}
#endif //#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS
@@ -120,7 +121,7 @@ esp_err_t mmu_config_psram_rodata_segment(uint32_t start_page, uint32_t psram_si
uint32_t flash_irom_paddr_start = 0;
image_process_get_flash_segments_info(&flash_drom_paddr_start, &flash_irom_paddr_start);
flash_drom_paddr_start = ALIGN_DOWN_BY(flash_drom_paddr_start, CONFIG_MMU_PAGE_SIZE);
ESP_EARLY_LOGI(TAG, "flash_drom_paddr_start: 0x%x", flash_drom_paddr_start);
ESP_EARLY_LOGV(TAG, "flash_drom_paddr_start: 0x%x", flash_drom_paddr_start);
if ((MMU_PAGE_TO_BYTES(start_page) + drom_size) > psram_size) {
ESP_EARLY_LOGE(TAG, "PSRAM space not enough for the Flash rodata, need %"PRId32" B, from %"PRId32" B to %"PRId32" B", drom_size, MMU_PAGE_TO_BYTES(start_page), MMU_PAGE_TO_BYTES(start_page) + drom_size);
@@ -141,6 +142,7 @@ esp_err_t mmu_config_psram_rodata_segment(uint32_t start_page, uint32_t psram_si
start_page += BYTES_TO_MMU_PAGE(drom_size);
*out_page = start_page;
ESP_EARLY_LOGI(TAG, ".rodata xip on psram");
return ESP_OK;
}
#endif //#if CONFIG_SPIRAM_RODATA

View File

@@ -94,6 +94,7 @@ def test_psram_esp32p4(dut: Dut) -> None:
'config',
[
'esp32c5_release',
'esp32c5_advanced',
],
indirect=True,
)
@@ -107,6 +108,7 @@ def test_psram_esp32c5(dut: Dut) -> None:
'config',
[
'esp32c61_release',
'esp32c61_advanced',
],
indirect=True,
)

View File

@@ -0,0 +1,15 @@
CONFIG_IDF_TARGET="esp32c5"
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
CONFIG_SPIRAM=y
CONFIG_SPIRAM_SPEED_80M=y
CONFIG_SPIRAM_XIP_FROM_PSRAM=y
CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY=y
CONFIG_SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY=y
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"

View File

@@ -0,0 +1,15 @@
CONFIG_IDF_TARGET="esp32c61"
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
CONFIG_SPIRAM=y
CONFIG_SPIRAM_SPEED_80M=y
CONFIG_SPIRAM_XIP_FROM_PSRAM=y
CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY=y
CONFIG_SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY=y
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"

View File

@@ -67,6 +67,10 @@ if(CONFIG_ESP_ROM_HAS_FLASH_COUNT_PAGES_BUG OR CONFIG_ESP_ROM_HAS_CACHE_WRITEBAC
list(APPEND sources "patches/esp_rom_cache_esp32s2_esp32s3.c")
endif()
if(CONFIG_ESP_ROM_CACHE_WB_INVLD_LOW_RANGE)
list(APPEND sources "patches/esp_rom_cache_esp32c61.c")
endif()
if(CONFIG_ESP_ROM_HAS_CACHE_WRITEBACK_BUG)
list(APPEND sources "patches/esp_rom_cache_writeback_esp32s3.S")
endif()

View File

@@ -102,3 +102,7 @@ config ESP_ROM_USB_OTG_NUM
config ESP_ROM_HAS_OUTPUT_PUTC_FUNC
bool
default y
config ESP_ROM_CACHE_WB_INVLD_LOW_RANGE
bool
default y

View File

@@ -31,3 +31,4 @@
#define ESP_ROM_HAS_SW_FLOAT (1) // ROM has libgcc software floating point emulation functions
#define ESP_ROM_USB_OTG_NUM (-1) // No USB_OTG CDC in the ROM, set -1 for Kconfig usage.
#define ESP_ROM_HAS_OUTPUT_PUTC_FUNC (1) // ROM has esp_rom_output_putc (or ets_write_char_uart)
#define ESP_ROM_CACHE_WB_INVLD_LOW_RANGE (1) // ROM `Cache_WriteBack_Addr` and `Cache_Invalidate_Addr` can only access low vaddr parts

View File

@@ -192,9 +192,9 @@ MMU_Set_Page_Mode = 0x40000624;
MMU_Get_Page_Mode = 0x40000628;
Cache_Sync_Items = 0x4000062c;
Cache_Op_Addr = 0x40000630;
Cache_Invalidate_Addr = 0x40000634;
/*Cache_Invalidate_Addr = 0x40000634; rom version API has issue that unable to access higher vaddr range, use IDF patch */
Cache_Clean_Addr = 0x40000638;
Cache_WriteBack_Addr = 0x4000063c;
/*Cache_WriteBack_Addr = 0x4000063c; rom version API has issue that unable to access higher vaddr range, use IDF patch */
Cache_WriteBack_Invalidate_Addr = 0x40000640;
Cache_Invalidate_All = 0x40000644;
Cache_Clean_All = 0x40000648;

View File

@@ -8,6 +8,8 @@ entries:
esp_rom_cache_esp32s2_esp32s3 (noflash)
if ESP_ROM_HAS_CACHE_WRITEBACK_BUG = y:
esp_rom_cache_writeback_esp32s3 (noflash)
if ESP_ROM_CACHE_WB_INVLD_LOW_RANGE = y:
esp_rom_cache_esp32c61 (noflash)
if HEAP_TLSF_USE_ROM_IMPL = y && (ESP_ROM_TLSF_CHECK_PATCH = y || HEAP_TLSF_CHECK_PATCH = y):
esp_rom_tlsf (noflash)
if SOC_SYSTIMER_SUPPORTED = y:

View File

@@ -0,0 +1,97 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <stdbool.h>
#include "sdkconfig.h"
#include "esp_rom_caps.h"
#include "soc/soc_caps.h"
#include "soc/cache_reg.h"
#include "soc/cache_struct.h"
#include "soc/ext_mem_defs.h"
#include "hal/assert.h"
#include "esp32c61/rom/cache.h"
#include "esp_rom_sys.h"
#define CACHE_MAX_SYNC_NUM ((CACHE_SYNC_SIZE + 1) >> 1)
/**
* @brief Sync Cache items
*
* @param type sync type
* @param addr address
* @param bytes bytes to be synced
*/
__attribute__((always_inline))
static inline void s_cache_sync_items(uint32_t type, uint32_t addr, uint32_t bytes)
{
REG_WRITE(CACHE_SYNC_ADDR_REG, addr);
REG_SET_FIELD(CACHE_SYNC_SIZE_REG, CACHE_SYNC_SIZE, bytes);
REG_SET_BIT(CACHE_SYNC_CTRL_REG, type);
while (!REG_GET_BIT(CACHE_SYNC_CTRL_REG, CACHE_SYNC_DONE))
;
}
int Cache_Invalidate_Addr(uint32_t vaddr, uint32_t size)
{
uint32_t plus = 0;
uint32_t cache_line_size = 32;
uint32_t cache_max_sync_size = CACHE_MAX_SYNC_NUM;
if (size == 0) {
HAL_ASSERT(false);
}
//aligned start address to cache line size
plus = vaddr & (cache_line_size - 1);
vaddr -= plus;
//make the length fit the start address
size += plus;
//aligned the length to cache line size(0->0)
size = (size + cache_line_size - 1) & ~(cache_line_size - 1);
while (size > 0) {
//aligned to cache_max_sync_size, (0->cache_max_sync_size)
uint32_t this_size = ((vaddr + cache_max_sync_size) & ~(cache_max_sync_size - 1)) - vaddr;
if (this_size > size) {
this_size = size;
}
s_cache_sync_items(CACHE_SYNC_INVALIDATE, vaddr, this_size);
vaddr += this_size;
size -= this_size;
}
return 0;
}
int Cache_WriteBack_Addr(uint32_t vaddr, uint32_t size)
{
uint32_t plus = 0;
uint32_t cache_line_size = 32;
uint32_t cache_max_sync_size = CACHE_MAX_SYNC_NUM;
if (size == 0) {
HAL_ASSERT(false);
}
//aligned start address to cache line size
plus = vaddr & (cache_line_size - 1);
vaddr -= plus;
//make the length fit the start address
size += plus;
//aligned the length to cache line size(0->0)
size = (size + cache_line_size - 1) & ~(cache_line_size - 1);
while (size > 0) {
//aligned to cache_max_sync_size, (0->cache_max_sync_size)
uint32_t this_size = ((vaddr + cache_max_sync_size) & ~(cache_max_sync_size - 1)) - vaddr;
if (this_size > size) {
this_size = size;
}
s_cache_sync_items(CACHE_SYNC_WRITEBACK, vaddr, this_size);
vaddr += this_size;
size -= this_size;
}
return 0;
}

View File

@@ -176,6 +176,9 @@ static esp_err_t process_segment(int index, uint32_t flash_addr, esp_image_segme
ESP_RETURN_ON_FALSE_ISR(false, ESP_ERR_INVALID_STATE, TAG, "unaligned segment length 0x%"PRIx32, data_len);
}
mmu_ll_set_entry_invalid(0, MMU_LL_END_DROM_ENTRY_ID);
s_current_read_mapping = UINT32_MAX;
return ESP_OK;
}

View File

@@ -24,6 +24,8 @@
extern "C" {
#endif
#define MMU_LL_FLASH_MMU_ID 0
#define MMU_LL_PSRAM_MMU_ID 0
#define MMU_LL_END_DROM_ENTRY_VADDR (SOC_DRAM_FLASH_ADDRESS_HIGH - SOC_MMU_PAGE_SIZE)
#define MMU_LL_END_DROM_ENTRY_ID (SOC_MMU_ENTRY_NUM - 1)

View File

@@ -20,6 +20,8 @@
extern "C" {
#endif
#define MMU_LL_FLASH_MMU_ID 0
#define MMU_LL_PSRAM_MMU_ID 0
#define MMU_LL_END_DROM_ENTRY_VADDR (SOC_DRAM_FLASH_ADDRESS_HIGH - SOC_MMU_PAGE_SIZE)
#define MMU_LL_END_DROM_ENTRY_ID (SOC_MMU_ENTRY_NUM - 1)
@@ -212,7 +214,6 @@ static inline uint32_t mmu_ll_format_paddr(uint32_t mmu_id, uint32_t paddr, mmu_
__attribute__((always_inline)) static inline void mmu_ll_write_entry(uint32_t mmu_id, uint32_t entry_id, uint32_t mmu_val, mmu_target_t target)
{
(void)mmu_id;
(void)target;
uint32_t mmu_raw_value;
if (mmu_ll_cache_encryption_enabled()) {
mmu_val |= SOC_MMU_SENSITIVE;

View File

@@ -58,7 +58,7 @@ extern "C" {
* valid bit + value bits
* valid bit is BIT(9), so value bits are 0x1ff
*/
#define SOC_MMU_VALID_VAL_MASK (SOC_MMU_ACCESS_SPIRAM-1)
#define SOC_MMU_VALID_VAL_MASK (SOC_MMU_ACCESS_SPIRAM - 1)
/**
* Max MMU available paddr page num.
* `SOC_MMU_MAX_PADDR_PAGE_NUM * SOC_MMU_PAGE_SIZE` means the max paddr address supported by the MMU. e.g.:
@@ -72,7 +72,7 @@ extern "C" {
* This is the mask used for mapping. e.g.:
* 0x4200_0000 & SOC_MMU_VADDR_MASK
*/
#define SOC_MMU_VADDR_MASK ((SOC_MMU_PAGE_SIZE) * SOC_MMU_ENTRY_NUM - 1)
#define SOC_MMU_VADDR_MASK ((SOC_MMU_PAGE_SIZE) * SOC_MMU_ENTRY_NUM - 1)
#define SOC_MMU_DBUS_VADDR_BASE 0x42000000
#define SOC_MMU_IBUS_VADDR_BASE 0x42000000

View File

@@ -58,7 +58,7 @@ extern "C" {
* valid bit + value bits
* valid bit is BIT(9), so value bits are 0x1ff
*/
#define SOC_MMU_VALID_VAL_MASK 0x3ff
#define SOC_MMU_VALID_VAL_MASK (SOC_MMU_ACCESS_SPIRAM - 1)
/**
* Max MMU available paddr page num.
* `SOC_MMU_MAX_PADDR_PAGE_NUM * SOC_MMU_PAGE_SIZE` means the max paddr address supported by the MMU. e.g.:

View File

@@ -277,7 +277,7 @@ const void * spi_flash_phys2cache(size_t phys_offs, spi_flash_mmap_memory_t memo
mmu_target_t target = MMU_TARGET_FLASH0;
__attribute__((unused)) uint32_t phys_page = phys_offs / CONFIG_MMU_PAGE_SIZE;
#if !SOC_MMU_PER_EXT_MEM_TARGET
#if !CONFIG_SPIRAM_FLASH_LOAD_TO_PSRAM
#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS
if (phys_page >= instruction_flash_start_page_get() && phys_page <= instruction_flash_end_page_get()) {
target = MMU_TARGET_PSRAM0;
@@ -291,7 +291,7 @@ const void * spi_flash_phys2cache(size_t phys_offs, spi_flash_mmap_memory_t memo
phys_offs -= rodata_flash2spiram_offset() * CONFIG_MMU_PAGE_SIZE;
}
#endif
#endif //#if !SOC_MMU_PER_EXT_MEM_TARGET
#endif //#if !CONFIG_SPIRAM_FLASH_LOAD_TO_PSRAM
mmu_vaddr_t type = (memory == SPI_FLASH_MMAP_DATA) ? MMU_VADDR_DATA : MMU_VADDR_INSTRUCTION;
ret = esp_mmu_paddr_to_vaddr(phys_offs, target, type, &ptr);
@@ -383,7 +383,7 @@ size_t spi_flash_cache2phys(const void *cached)
int offset = 0;
#if !SOC_MMU_PER_EXT_MEM_TARGET //TODO: IDF-9049
#if !CONFIG_SPIRAM_FLASH_LOAD_TO_PSRAM
#if CONFIG_SPIRAM_RODATA
if ((uint32_t)cached >= (uint32_t)&_rodata_reserved_start && (uint32_t)cached <= (uint32_t)&_rodata_reserved_end) {
offset = rodata_flash2spiram_offset();
@@ -394,7 +394,7 @@ size_t spi_flash_cache2phys(const void *cached)
offset = instruction_flash2spiram_offset();
}
#endif
#endif //#if !SOC_MMU_PER_EXT_MEM_TARGET
#endif //#if !CONFIG_SPIRAM_FLASH_LOAD_TO_PSRAM
return paddr + offset * CONFIG_MMU_PAGE_SIZE;
}

View File

@@ -1,6 +1,5 @@
# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
import pytest
from pytest_embedded import Dut
@@ -38,6 +37,8 @@ def test_flash_mmap_rom_impl(dut: Dut) -> None:
XIP_CONFIGS = [
pytest.param('xip_psram_esp32s2', marks=[pytest.mark.esp32s2]),
pytest.param('xip_psram_esp32s3', marks=[pytest.mark.esp32s3]),
pytest.param('xip_psram_esp32c5', marks=[pytest.mark.esp32c5]),
pytest.param('xip_psram_esp32c61', marks=[pytest.mark.esp32c61]),
]

View File

@@ -0,0 +1,2 @@
CONFIG_IDF_TARGET="esp32c5"
CONFIG_SPIRAM_XIP_FROM_PSRAM=y

View File

@@ -0,0 +1,2 @@
CONFIG_IDF_TARGET="esp32c61"
CONFIG_SPIRAM_XIP_FROM_PSRAM=y