diff --git a/arch/xtensa/src/esp32s3/esp32s3_himem.c b/arch/xtensa/src/esp32s3/esp32s3_himem.c index e1855d3f6d..25d832c029 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_himem.c +++ b/arch/xtensa/src/esp32s3/esp32s3_himem.c @@ -32,6 +32,7 @@ #include "xtensa.h" #include "esp32s3_spiram.h" #include "esp32s3_himem.h" +#include "esp32s3_spiflash_mtd.h" #include "hardware/esp32s3_soc.h" #include "hardware/esp32s3_cache_memory.h" #include "hardware/esp32s3_extmem.h" @@ -82,7 +83,6 @@ # define SPIRAM_BANKSWITCH_RESERVE 0 #endif -#define MMU_PAGE_SIZE 0x10000 #define MMU_PAGE_TO_BYTES(page_num) ((page_num) * MMU_PAGE_SIZE) #define BYTES_TO_MMU_PAGE(bytes) ((bytes) / MMU_PAGE_SIZE) @@ -129,7 +129,6 @@ extern int cache_dbus_mmu_set(uint32_t ext_ram, uint32_t vaddr, static inline bool ramblock_idx_valid(int ramblock_idx); static inline bool rangeblock_idx_valid(int rangeblock_idx); -static void set_bank(int virt_bank, int phys_bank, int ct); static uint32_t esp_himem_get_range_start(void); static uint32_t esp_himem_get_range_block(void); static uint32_t esp_himem_get_phy_block(void); @@ -209,47 +208,6 @@ static inline bool rangeblock_idx_valid(int rangeblock_idx) return (rangeblock_idx >= 0 && rangeblock_idx < g_rangeblockcnt); } -/**************************************************************************** - * Name: set_bank - * - * Description: - * Set DCache mmu mapping. - * - * Input Parameters: - * virt_bank - Beginning of the virtual bank - * phys_bank - Beginning of the physical bank - * ct - Number of banks - * - * Returned Value: - * None. - * - ****************************************************************************/ - -static void set_bank(int virt_bank, int phys_bank, int ct) -{ - uint32_t regval; - - /* Suspend DRAM Case during configuration */ - - cache_suspend_dcache(); - ASSERT(cache_dbus_mmu_set(MMU_ACCESS_SPIRAM, - SOC_EXTRAM_DATA_LOW + - MMU_PAGE_TO_BYTES(virt_bank), - MMU_PAGE_TO_BYTES(phys_bank), 64, ct, 0) == 0); - - regval = getreg32(EXTMEM_DCACHE_CTRL1_REG); - regval &= ~EXTMEM_DCACHE_SHUT_CORE0_BUS; - putreg32(regval, EXTMEM_DCACHE_CTRL1_REG); - -#if defined(CONFIG_SMP) - regval = getreg32(EXTMEM_DCACHE_CTRL1_REG); - regval &= ~EXTMEM_DCACHE_SHUT_CORE1_BUS; - putreg32(regval, EXTMEM_DCACHE_CTRL1_REG); -#endif - - cache_resume_dcache(0); -} - /**************************************************************************** * Name: esp_himem_get_range_start * @@ -974,7 +932,7 @@ int esp_himem_map(esp_himem_handle_t handle, { virt_bank = himem_mmu_start + range->block_start + i + range_block; phys_bank = himem_phy_start + handle->block[i + ram_block]; - set_bank(virt_bank, phys_bank, 1); + esp32s3_set_bank(virt_bank, phys_bank, 1); } /* Set out pointer */ diff --git a/arch/xtensa/src/esp32s3/esp32s3_spiflash_mtd.c b/arch/xtensa/src/esp32s3/esp32s3_spiflash_mtd.c index 2ac6d66424..24eb4a6b56 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_spiflash_mtd.c +++ b/arch/xtensa/src/esp32s3/esp32s3_spiflash_mtd.c @@ -39,9 +39,11 @@ #include #include "hardware/esp32s3_soc.h" +#include "hardware/esp32s3_cache_memory.h" #include "xtensa_attr.h" #include "esp32s3_spiflash.h" +#include "esp32s3_spiram.h" #include "rom/esp32s3_spiflash.h" #include "esp32s3_spiflash_mtd.h" @@ -71,6 +73,7 @@ enum spiflash_op_code_e SPIFLASH_OP_CODE_WRITE = 0, SPIFLASH_OP_CODE_READ, SPIFLASH_OP_CODE_ERASE, + SPIFLASH_OP_CODE_SET_BANK, SPIFLASH_OP_CODE_ENCRYPT_READ, SPIFLASH_OP_CODE_ENCRYPT_WRITE }; @@ -99,6 +102,7 @@ struct spiflash_work_arg uint32_t addr; uint8_t *buffer; uint32_t size; + uint32_t paddr; } op_arg; volatile int ret; @@ -144,7 +148,8 @@ static void esp32s3_spiflash_work(void *arg); static int esp32s3_async_op(enum spiflash_op_code_e opcode, uint32_t addr, const uint8_t *buffer, - uint32_t size); + uint32_t size, + uint32_t paddr); #endif /**************************************************************************** @@ -259,6 +264,12 @@ static void esp32s3_spiflash_work(void *arg) work_arg->ret = spi_flash_erase_range(work_arg->op_arg.addr, work_arg->op_arg.size); } + else if (work_arg->op_code == SPIFLASH_OP_CODE_SET_BANK) + { + work_arg->ret = cache_dbus_mmu_map(work_arg->op_arg.addr, + work_arg->op_arg.paddr, + work_arg->op_arg.size); + } else if (work_arg->op_code == SPIFLASH_OP_CODE_ENCRYPT_READ) { work_arg->ret = spi_flash_read_encrypted(work_arg->op_arg.addr, @@ -300,7 +311,8 @@ static void esp32s3_spiflash_work(void *arg) static int esp32s3_async_op(enum spiflash_op_code_e opcode, uint32_t addr, const uint8_t *buffer, - uint32_t size) + uint32_t size, + uint32_t paddr) { int ret; struct spiflash_work_arg work_arg = @@ -311,6 +323,7 @@ static int esp32s3_async_op(enum spiflash_op_code_e opcode, .addr = addr, .buffer = (uint8_t *)buffer, .size = size, + .paddr = paddr, }, .sem = NXSEM_INITIALIZER(0, 0) }; @@ -370,7 +383,8 @@ static int esp32s3_erase(struct mtd_dev_s *dev, off_t startblock, #ifdef CONFIG_ESP32S3_SPI_FLASH_SUPPORT_PSRAM_STACK if (stack_is_psram()) { - ret = esp32s3_async_op(SPIFLASH_OP_CODE_ERASE, offset, NULL, nbytes); + ret = esp32s3_async_op(SPIFLASH_OP_CODE_ERASE, offset, NULL, + nbytes, 0); } else #endif @@ -438,7 +452,7 @@ static ssize_t esp32s3_read(struct mtd_dev_s *dev, off_t offset, if (stack_is_psram()) { ret = esp32s3_async_op(SPIFLASH_OP_CODE_READ, offset, - buffer, nbytes); + buffer, nbytes, 0); } else #endif @@ -544,7 +558,7 @@ static ssize_t esp32s3_read_decrypt(struct mtd_dev_s *dev, if (stack_is_psram()) { ret = esp32s3_async_op(SPIFLASH_OP_CODE_ENCRYPT_READ, offset, - buffer, nbytes); + buffer, nbytes, 0); } else #endif @@ -656,7 +670,7 @@ static ssize_t esp32s3_write(struct mtd_dev_s *dev, off_t offset, if (stack_is_psram()) { ret = esp32s3_async_op(SPIFLASH_OP_CODE_WRITE, offset, - buffer, nbytes); + buffer, nbytes, 0); } else #endif @@ -720,7 +734,7 @@ static ssize_t esp32s3_bwrite_encrypt(struct mtd_dev_s *dev, if (stack_is_psram()) { ret = esp32s3_async_op(SPIFLASH_OP_CODE_ENCRYPT_WRITE, addr, - buffer, size); + buffer, size, 0); } else #endif @@ -863,6 +877,43 @@ static int esp32s3_ioctl(struct mtd_dev_s *dev, int cmd, * Public Functions ****************************************************************************/ +/**************************************************************************** + * Name: esp32s3_set_bank + * + * Description: + * Set Ext-SRAM-Cache mmu mapping. + * + * Input Parameters: + * virt_bank - Beginning of the virtual bank + * phys_bank - Beginning of the physical bank + * ct - Number of banks + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void esp32s3_set_bank(int virt_bank, int phys_bank, int ct) +{ + int ret; + uint32_t vaddr = SOC_EXTRAM_DATA_LOW + MMU_PAGE_SIZE * virt_bank; + uint32_t paddr = phys_bank * MMU_PAGE_SIZE; +#ifdef CONFIG_ESP32S3_SPI_FLASH_SUPPORT_PSRAM_STACK + if (stack_is_psram()) + { + ret = esp32s3_async_op(SPIFLASH_OP_CODE_SET_BANK, vaddr, NULL, ct, + paddr); + } + else +#endif + { + ret = cache_dbus_mmu_map(vaddr, paddr, ct); + } + + DEBUGASSERT(ret == 0); + UNUSED(ret); +} + /**************************************************************************** * Name: esp32s3_spiflash_alloc_mtdpart * diff --git a/arch/xtensa/src/esp32s3/esp32s3_spiflash_mtd.h b/arch/xtensa/src/esp32s3/esp32s3_spiflash_mtd.h index 86f1c1f174..d459fe7cd9 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_spiflash_mtd.h +++ b/arch/xtensa/src/esp32s3/esp32s3_spiflash_mtd.h @@ -46,6 +46,24 @@ extern "C" * Public Function Prototypes ****************************************************************************/ +/**************************************************************************** + * Name: esp32s3_set_bank + * + * Description: + * Set Ext-SRAM-Cache mmu mapping. + * + * Input Parameters: + * virt_bank - Beginning of the virtual bank + * phys_bank - Beginning of the physical bank + * ct - Number of banks + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void esp32s3_set_bank(int virt_bank, int phys_bank, int ct); + /**************************************************************************** * Name: esp32s3_spiflash_mtd * diff --git a/arch/xtensa/src/esp32s3/esp32s3_spiram.c b/arch/xtensa/src/esp32s3/esp32s3_spiram.c index 8edf42e447..39e24347d1 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_spiram.c +++ b/arch/xtensa/src/esp32s3/esp32s3_spiram.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include "xtensa.h" @@ -66,6 +67,22 @@ #define SPIRAM_VADDR_MAP_SIZE 0 #endif +/* Max MMU available paddr page num. + * `MMU_MAX_PADDR_PAGE_NUM * MMU_PAGE_SIZE` means the max paddr + * address supported by the MMU. e.g.: 16384 * 64KB, means MMU can + * support 1GB paddr at most + */ + +#define MMU_MAX_PADDR_PAGE_NUM 16384 + +/* This is the mask used for mapping. e.g.: 0x4200_0000 & MMU_VADDR_MASK */ + +#define MMU_VADDR_MASK 0x1FFFFFF + +/* MMU entry num */ + +#define MMU_ENTRY_NUM 512 + static bool g_spiram_inited; /* These variables are in bytes */ @@ -109,6 +126,7 @@ extern void cache_resume_dcache(uint32_t val); extern int cache_dbus_mmu_set(uint32_t ext_ram, uint32_t vaddr, uint32_t paddr, uint32_t psize, uint32_t num, uint32_t fixed); +extern int cache_invalidate_addr(uint32_t addr, uint32_t size); /**************************************************************************** * Private Functions @@ -142,10 +160,189 @@ static inline uint32_t mmu_valid_space(uint32_t *start_address) return 0; } +/**************************************************************************** + * Name: mmu_check_valid_paddr_region + * + * Description: + * Check if the paddr region is valid. + * + * Input Parameters: + * paddr_start - start of the physical address + * len - length, in bytes + * + * Returned Value: + * True for valid. + * + ****************************************************************************/ + +static inline bool mmu_check_valid_paddr_region(uint32_t paddr_start, + uint32_t len) +{ + return (paddr_start < (MMU_PAGE_SIZE * MMU_MAX_PADDR_PAGE_NUM)) && + (len < (MMU_PAGE_SIZE * MMU_MAX_PADDR_PAGE_NUM)) && + ((paddr_start + len - 1) < + (MMU_PAGE_SIZE * MMU_MAX_PADDR_PAGE_NUM)); +} + +/**************************************************************************** + * Name: mmu_check_valid_ext_vaddr_region + * + * Description: + * Check if the external memory vaddr region is valid. + * + * Input Parameters: + * vaddr_start - start of the virtual address + * len - length, in bytes + * + * Returned Value: + * True for valid. + * + ****************************************************************************/ + +static inline bool mmu_check_valid_ext_vaddr_region(uint32_t vaddr_start, + uint32_t len) +{ + uint32_t vaddr_end = vaddr_start + len - 1; + bool valid = false; + valid |= (ADDRESS_IN_IRAM0_CACHE(vaddr_start) && + ADDRESS_IN_IRAM0_CACHE(vaddr_end)) | + (ADDRESS_IN_DRAM0_CACHE(vaddr_start) && + ADDRESS_IN_DRAM0_CACHE(vaddr_end)); + return valid; +} + +/**************************************************************************** + * Name: esp_mmu_map_region + * + * Description: + * To map a virtual address block to a physical memory block. + * + * Input Parameters: + * vaddr - Virtual address in CPU address space + * paddr - Physical address in Ext-SRAM + * len - Length to be mapped, in bytes + * mem_type - MMU target physical memory + * + * Returned Value: + * Actual mapped length. + * + ****************************************************************************/ + +static int IRAM_ATTR esp_mmu_map_region(uint32_t vaddr, uint32_t paddr, + uint32_t len, uint32_t mem_type) +{ + DEBUGASSERT(vaddr % MMU_PAGE_SIZE == 0); + DEBUGASSERT(paddr % MMU_PAGE_SIZE == 0); + DEBUGASSERT(mmu_check_valid_paddr_region(paddr, len)); + DEBUGASSERT(mmu_check_valid_ext_vaddr_region(vaddr, len)); + + uint32_t mmu_val; + uint32_t entry_id; + uint32_t page_num = (len + MMU_PAGE_SIZE - 1) / MMU_PAGE_SIZE; + uint32_t ret = page_num * MMU_PAGE_SIZE; + mmu_val = paddr >> 16; + bool write_back = false; + + while (page_num) + { + entry_id = (vaddr & MMU_VADDR_MASK) >> 16; + DEBUGASSERT(entry_id < MMU_ENTRY_NUM); + if (write_back == false && FLASH_MMU_TABLE[entry_id] != MMU_INVALID) + { + esp_spiram_writeback_cache(); + write_back = true; + } + + FLASH_MMU_TABLE[entry_id] = mmu_val | mem_type; + vaddr += MMU_PAGE_SIZE; + mmu_val++; + page_num--; + } + + return ret; +} + /**************************************************************************** * Public Functions ****************************************************************************/ +/**************************************************************************** + * Name: cache_dbus_mmu_map + * + * Description: + * Set Ext-SRAM-Cache mmu mapping. + * + * Input Parameters: + * vaddr - Virtual address in CPU address space + * paddr - Physical address in Ext-SRAM + * num - Pages to be set + * + * Returned Value: + * 0 if success or a negative value if fail. + * + ****************************************************************************/ + +int IRAM_ATTR cache_dbus_mmu_map(int vaddr, int paddr, int num) +{ + uint32_t regval; + irqstate_t flags; + uint32_t actual_mapped_len; + uint32_t cache_state[CONFIG_SMP_NCPUS]; + int cpu = up_cpu_index(); +#ifdef CONFIG_SMP + bool smp_start = OSINIT_OS_READY(); + int other_cpu = cpu ? 0 : 1; +#endif + + /* The MMU registers are implemented in such a way that lookups from the + * cache subsystem may collide with CPU access to the MMU registers. We use + * cache_suspend_dcache to make sure the cache is disabled. + */ + + flags = enter_critical_section(); + +#ifdef CONFIG_SMP + /* The other CPU might be accessing the cache at the same time, just by + * using variables in external RAM. + */ + + if (smp_start) + { + up_cpu_pause(other_cpu); + } + + cache_state[other_cpu] = cache_suspend_dcache(); +#endif + cache_state[cpu] = cache_suspend_dcache(); + + esp_mmu_map_region(vaddr, paddr, num * MMU_PAGE_SIZE, MMU_ACCESS_SPIRAM); + + regval = getreg32(EXTMEM_DCACHE_CTRL1_REG); + regval &= ~EXTMEM_DCACHE_SHUT_CORE0_BUS; + putreg32(regval, EXTMEM_DCACHE_CTRL1_REG); + +#if defined(CONFIG_SMP) + regval = getreg32(EXTMEM_DCACHE_CTRL1_REG); + regval &= ~EXTMEM_DCACHE_SHUT_CORE1_BUS; + putreg32(regval, EXTMEM_DCACHE_CTRL1_REG); +#endif + + cache_invalidate_addr(vaddr, num * MMU_PAGE_SIZE); + + cache_resume_dcache(cache_state[cpu]); + +#ifdef CONFIG_SMP + cache_resume_dcache(cache_state[other_cpu]); + if (smp_start) + { + up_cpu_resume(other_cpu); + } +#endif + + leave_critical_section(flags); + return 0; +} + /* Initially map all psram physical address to virtual address. * If psram physical size is larger than virtual address range, then only * map the virtual address range. diff --git a/arch/xtensa/src/esp32s3/esp32s3_spiram.h b/arch/xtensa/src/esp32s3/esp32s3_spiram.h index be46bf53a9..6bd24ec7cc 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_spiram.h +++ b/arch/xtensa/src/esp32s3/esp32s3_spiram.h @@ -34,6 +34,24 @@ extern "C" { #endif +/**************************************************************************** + * Name: cache_dbus_mmu_map + * + * Description: + * Set Ext-SRAM-Cache mmu mapping. + * + * Input Parameters: + * vaddr - Virtual address in CPU address space + * paddr - Physical address in Ext-SRAM + * num - Pages to be set + * + * Returned Value: + * 0 if success or a negative value if fail. + * + ****************************************************************************/ + +int cache_dbus_mmu_map(int vaddr, int paddr, int num); + /* Initialize spiram interface/hardware. Normally called from * cpu_start.c. *