This is an automated email from the ASF dual-hosted git repository. xiaoxiang pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push: new e2a82f008a xtensa/esp32s3: Invalidate cache if the flash address used has a cache mapping. e2a82f008a is described below commit e2a82f008a00577ca53a33de10c3e813c54dfca2 Author: chen...@espressif.com <chen...@espressif.com> AuthorDate: Wed Sep 20 14:56:21 2023 +0800 xtensa/esp32s3: Invalidate cache if the flash address used has a cache mapping. Signed-off-by: chen...@espressif.com <chen...@espressif.com> --- arch/xtensa/src/esp32s3/esp32s3_spiflash.c | 542 +++++++++++++++++------------ arch/xtensa/src/esp32s3/esp32s3_spiflash.h | 65 ++++ 2 files changed, 380 insertions(+), 227 deletions(-) diff --git a/arch/xtensa/src/esp32s3/esp32s3_spiflash.c b/arch/xtensa/src/esp32s3/esp32s3_spiflash.c index 79d0fb2390..937e55201f 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_spiflash.c +++ b/arch/xtensa/src/esp32s3/esp32s3_spiflash.c @@ -41,7 +41,9 @@ #include "xtensa.h" #include "xtensa_attr.h" +#include "hardware/esp32s3_extmem.h" #include "hardware/esp32s3_spi_mem_reg.h" +#include "hardware/esp32s3_cache_memory.h" #include "rom/esp32s3_spiflash.h" #include "rom/esp32s3_opi_flash.h" #include "esp32s3_irq.h" @@ -54,31 +56,36 @@ /* RO data page in MMU index */ #define DROM0_PAGES_START (2) -#define DROM0_PAGES_END (128) - -/* MMU invalid value */ - -#define INVALID_MMU_VAL (0x100) - -/* MMU page size */ - -#define SPI_FLASH_MMU_PAGE_SIZE (0x10000) +#define DROM0_PAGES_END (512) /* MMU base virtual mapped address */ #define VADDR0_START_ADDR (0x3c020000) +#define VADDR1_START_ADDR (0x42000000) + /* Flash MMU table for CPU */ #define MMU_TABLE ((volatile uint32_t *)DR_REG_MMU_TABLE) -#define MMU_ADDR2PAGE(_addr) ((_addr) / SPI_FLASH_MMU_PAGE_SIZE) -#define MMU_ADDR2OFF(_addr) ((_addr) % SPI_FLASH_MMU_PAGE_SIZE) -#define MMU_BYTES2PAGES(_n) (((_n) + SPI_FLASH_MMU_PAGE_SIZE - 1) / \ - SPI_FLASH_MMU_PAGE_SIZE) +#define MMU_ADDR2PAGE(_addr) ((_addr) / MMU_PAGE_SIZE) +#define MMU_ADDR2OFF(_addr) ((_addr) % MMU_PAGE_SIZE) +#define MMU_BYTES2PAGES(_n) (((_n) + MMU_PAGE_SIZE - 1) / \ + MMU_PAGE_SIZE) #ifdef CONFIG_ESP32S3_SPI_FLASH_DONT_USE_ROM_CODE +#define g_rom_flashchip (rom_spiflash_legacy_data->chip) + +#define MMU_ALIGNUP_SIZE(_s) (((_s) + MMU_PAGE_SIZE - 1) \ + & ~(MMU_PAGE_SIZE - 1)) +#define MMU_ALIGNDOWN_SIZE(_s) ((_s) & ~(MMU_PAGE_SIZE - 1)) + +/* Flash MMU table for APP CPU */ + +#define PRO_IRAM0_FIRST_PAGE (0) +#define IROM0_PAGES_END (2) + /* SPI port number */ # define SPI_PORT (1) @@ -170,35 +177,6 @@ #endif /* CONFIG_ESP32S3_SPI_FLASH_DONT_USE_ROM_CODE */ -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/* SPI Flash map request data */ - -struct spiflash_map_req_s -{ - /* Request mapping SPI Flash base address */ - - uint32_t src_addr; - - /* Request mapping SPI Flash size */ - - uint32_t size; - - /* Mapped memory pointer */ - - void *ptr; - - /* Mapped started MMU page index */ - - uint32_t start_page; - - /* Mapped MMU page count */ - - uint32_t page_cnt; -}; - /**************************************************************************** * Private Functions Declaration ****************************************************************************/ @@ -208,6 +186,7 @@ static void spiflash_end(void); static void spi_flash_disable_cache(uint32_t cpuid); static void spi_flash_restore_cache(uint32_t cpuid); #ifdef CONFIG_SMP +static int spi_flash_op_block_task(int argc, char *argv[]); static int spiflash_init_spi_flash_op_block_task(int cpu); #endif @@ -220,6 +199,7 @@ extern uint32_t cache_suspend_dcache(void); extern void cache_resume_icache(uint32_t val); extern void cache_resume_dcache(uint32_t val); extern int cache_invalidate_addr(uint32_t addr, uint32_t size); +extern void cache_invalidate_icache_all(void); /**************************************************************************** * Private Data @@ -371,6 +351,7 @@ static void spiflash_end(void) DEBUGASSERT(other_cpu != cpu); #endif + cache_invalidate_icache_all(); spiflash_resume_cache(); /* Signal to spi_flash_op_block_task that flash operation is complete */ @@ -645,8 +626,282 @@ static void disable_flash_write(void) } while (1); } + +/**************************************************************************** + * Name: spiflash_pagecached + * + * Description: + * Check if the given page is cached. + * + * Input Parameters: + * phypage - physical address page. + * ptr - Pointer to the virtual address. + * + * Returned Value: + * True if flash address has corresponding cache mapping, false otherwise. + * + ****************************************************************************/ + +static bool IRAM_ATTR spiflash_pagecached(uint32_t phypage, uint32_t *ptr) +{ + int start[2]; + int end[2]; + int i; + int j; + + /* Data ROM start and end pages */ + + start[0] = DROM0_PAGES_START; + end[0] = DROM0_PAGES_END; + + /* Instruction RAM start and end pages */ + + start[1] = PRO_IRAM0_FIRST_PAGE; + end[1] = IROM0_PAGES_END; + + for (i = 0; i < 2; i++) + { + for (j = start[i]; j < end[i]; j++) + { + if (MMU_TABLE[j] == phypage) + { + if (i == 0) + { + /* SPI_FLASH_MMAP_DATA */ + + *ptr = (VADDR0_START_ADDR + + MMU_PAGE_SIZE * (j - start[0])); + } + else + { + /* SPI_FLASH_MMAP_INST */ + + *ptr = (VADDR1_START_ADDR + + MMU_PAGE_SIZE * (j - start[1])); + } + + return true; + } + } + } + + return false; +} + +/**************************************************************************** + * Name: spiflash_flushmapped + * + * Description: + * Writeback PSRAM data and invalidate the cache if the address is mapped. + * + * Input Parameters: + * start - SPI Flash address. + * size - SPI Flash size. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static void IRAM_ATTR spiflash_flushmapped(size_t start, size_t size) +{ + uint32_t page_start; + uint32_t addr; + uint32_t page; + uint32_t vaddr; + + page_start = MMU_ALIGNDOWN_SIZE(start); + size += (start - page_start); + size = MMU_ALIGNUP_SIZE(size); + + for (addr = page_start; addr < page_start + size; + addr += MMU_PAGE_SIZE) + { + page = addr / MMU_PAGE_SIZE; + if (addr >= g_rom_flashchip.chip_size) + { + return; + } + + if (spiflash_pagecached(page, &vaddr)) + { + cache_invalidate_addr(vaddr, MMU_PAGE_SIZE); + } + } +} #endif /* CONFIG_ESP32S3_SPI_FLASH_DONT_USE_ROM_CODE */ +/**************************************************************************** + * Name: spi_flash_disable_cache + * + * Description: + * Disable the I/D cache of a CPU core and save its status value on + * s_flash_op_cache_state. + * + * Input Parameters: + * cpuid - The CPU core whose cache will be disabled. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static void spi_flash_disable_cache(uint32_t cpuid) +{ + s_flash_op_cache_state[cpuid] = cache_suspend_icache() << 16; + s_flash_op_cache_state[cpuid] |= cache_suspend_dcache(); +} + +/**************************************************************************** + * Name: spi_flash_restore_cache + * + * Description: + * Restore the I/D cache of a CPU core using the saved status value on + * s_flash_op_cache_state. + * + * Input Parameters: + * cpuid - The CPU core whose cache will be restored. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static void spi_flash_restore_cache(uint32_t cpuid) +{ + cache_resume_dcache(s_flash_op_cache_state[cpuid] & 0xffff); + cache_resume_icache(s_flash_op_cache_state[cpuid] >> 16); +} + +#ifdef CONFIG_SMP + +/**************************************************************************** + * Name: spi_flash_op_block_task + * + * Description: + * Disable the non-IRAM interrupts on the other core (the one that isn't + * handling the SPI flash operation) and notify that the SPI flash + * operation can start. Wait on a busy loop until it's finished and then + * reenable the non-IRAM interrups. + * + * Input Parameters: + * argc - Not used. + * argv - Not used. + * + * Returned Value: + * Zero (OK) is returned on success. A negated errno value is returned to + * indicate the nature of any failure. + * + ****************************************************************************/ + +static int spi_flash_op_block_task(int argc, char *argv[]) +{ + struct tcb_s *tcb = this_task(); + int cpu = up_cpu_index(); + + for (; ; ) + { + DEBUGASSERT((1 << cpu) & tcb->affinity); + /* Wait for a SPI flash operation to take place and this (the other + * core) being asked to disable its non-IRAM interrupts. + */ + + nxsem_wait(&g_disable_non_iram_isr_on_core[cpu]); + + sched_lock(); + + esp32s3_irq_noniram_disable(); + + /* g_flash_op_complete flag is cleared on *this* CPU, otherwise the + * other CPU may reset the flag back to false before this task has a + * chance to check it (if it's preempted by an ISR taking non-trivial + * amount of time). + */ + + g_flash_op_complete = false; + g_flash_op_can_start = true; + while (!g_flash_op_complete) + { + /* Busy loop here and wait for the other CPU to finish the SPI + * flash operation. + */ + } + + /* Flash operation is complete, re-enable cache */ + + spi_flash_restore_cache(cpu); + + /* Restore interrupts that aren't located in IRAM */ + + esp32s3_irq_noniram_enable(); + + sched_unlock(); + } + + return OK; +} + +/**************************************************************************** + * Name: spiflash_init_spi_flash_op_block_task + * + * Description: + * Starts a kernel thread that waits for a semaphore indicating that a SPI + * flash operation is going to take place in the other CPU. It disables + * non-IRAM interrupts, indicates to the other core that the SPI flash + * operation can start and waits for it to be finished in a busy loop. + * + * Input Parameters: + * cpu - The CPU core that will run the created task to wait on a busy + * loop while the SPI flash operation finishes + * + * Returned Value: + * 0 (OK) on success; A negated errno value on failure. + * + ****************************************************************************/ + +static int spiflash_init_spi_flash_op_block_task(int cpu) +{ + int pid; + int ret = OK; + char *argv[2]; + char arg1[32]; + cpu_set_t cpuset; + + snprintf(arg1, sizeof(arg1), "%p", &cpu); + argv[0] = arg1; + argv[1] = NULL; + + pid = kthread_create("spiflash_op", + SCHED_PRIORITY_MAX, + CONFIG_ESP32S3_SPIFLASH_OP_TASK_STACKSIZE, + spi_flash_op_block_task, + argv); + if (pid > 0) + { + if (cpu < CONFIG_SMP_NCPUS) + { + CPU_ZERO(&cpuset); + CPU_SET(cpu, &cpuset); + ret = nxsched_set_affinity(pid, sizeof(cpuset), &cpuset); + if (ret < 0) + { + return ret; + } + } + } + else + { + return -EPERM; + } + + return ret; +} +#endif /* CONFIG_SMP */ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + /**************************************************************************** * Name: esp32s3_mmap * @@ -665,7 +920,7 @@ static void disable_flash_write(void) * ****************************************************************************/ -static int esp32s3_mmap(struct spiflash_map_req_s *req) +int esp32s3_mmap(struct spiflash_map_req_s *req) { int ret; int i; @@ -680,7 +935,7 @@ static int esp32s3_mmap(struct spiflash_map_req_s *req) start_page < DROM0_PAGES_END; ++start_page) { - if (MMU_TABLE[start_page] == INVALID_MMU_VAL) + if (MMU_TABLE[start_page] == MMU_INVALID) { break; } @@ -692,20 +947,28 @@ static int esp32s3_mmap(struct spiflash_map_req_s *req) if (start_page + page_cnt < DROM0_PAGES_END) { mapped_addr = (start_page - DROM0_PAGES_START) * - SPI_FLASH_MMU_PAGE_SIZE + + MMU_PAGE_SIZE + VADDR0_START_ADDR; for (i = 0; i < page_cnt; i++) { MMU_TABLE[start_page + i] = flash_page + i; - cache_invalidate_addr(mapped_addr + i * SPI_FLASH_MMU_PAGE_SIZE, - SPI_FLASH_MMU_PAGE_SIZE); } req->start_page = start_page; req->page_cnt = page_cnt; req->ptr = (void *)(mapped_addr + MMU_ADDR2OFF(req->src_addr)); ret = OK; + int 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(mapped_addr, page_cnt * MMU_PAGE_SIZE); } else { @@ -731,7 +994,7 @@ static int esp32s3_mmap(struct spiflash_map_req_s *req) * ****************************************************************************/ -static void esp32s3_ummap(const struct spiflash_map_req_s *req) +void esp32s3_ummap(const struct spiflash_map_req_s *req) { int i; @@ -739,16 +1002,12 @@ static void esp32s3_ummap(const struct spiflash_map_req_s *req) for (i = req->start_page; i < req->start_page + req->page_cnt; ++i) { - MMU_TABLE[i] = INVALID_MMU_VAL; + MMU_TABLE[i] = MMU_INVALID; } spiflash_end(); } -/**************************************************************************** - * Public Functions - ****************************************************************************/ - /**************************************************************************** * Name: spi_flash_read_encrypted * @@ -817,7 +1076,7 @@ int spi_flash_erase_sector(uint32_t sector) wait_flash_idle(); disable_flash_write(); - + spiflash_flushmapped(addr, FLASH_SECTOR_SIZE); spiflash_end(); return ret; @@ -858,7 +1117,7 @@ int spi_flash_erase_range(uint32_t start_address, uint32_t size) wait_flash_idle(); disable_flash_write(); - + spiflash_flushmapped(start_address, FLASH_SECTOR_SIZE * size); spiflash_end(); return ret; @@ -931,7 +1190,7 @@ int spi_flash_write(uint32_t dest_addr, const void *buffer, uint32_t size) wait_flash_idle(); disable_flash_write(); - + spiflash_flushmapped(dest_addr, size); spiflash_end(); return ret; @@ -1004,177 +1263,6 @@ int spi_flash_read(uint32_t src_addr, void *dest, uint32_t size) } #endif /* CONFIG_ESP32S3_SPI_FLASH_DONT_USE_ROM_CODE */ -/**************************************************************************** - * Name: spi_flash_disable_cache - * - * Description: - * Disable the I/D cache of a CPU core and save its status value on - * s_flash_op_cache_state. - * - * Input Parameters: - * cpuid - The CPU core whose cache will be disabled. - * - * Returned Value: - * None. - * - ****************************************************************************/ - -static void spi_flash_disable_cache(uint32_t cpuid) -{ - s_flash_op_cache_state[cpuid] = cache_suspend_icache() << 16; - s_flash_op_cache_state[cpuid] |= cache_suspend_dcache(); -} - -/**************************************************************************** - * Name: spi_flash_restore_cache - * - * Description: - * Restore the I/D cache of a CPU core using the saved status value on - * s_flash_op_cache_state. - * - * Input Parameters: - * cpuid - The CPU core whose cache will be restored. - * - * Returned Value: - * None. - * - ****************************************************************************/ - -static void spi_flash_restore_cache(uint32_t cpuid) -{ - cache_resume_dcache(s_flash_op_cache_state[cpuid] & 0xffff); - cache_resume_icache(s_flash_op_cache_state[cpuid] >> 16); -} - -#ifdef CONFIG_SMP - -/**************************************************************************** - * Name: spi_flash_op_block_task - * - * Description: - * Disable the non-IRAM interrupts on the other core (the one that isn't - * handling the SPI flash operation) and notify that the SPI flash - * operation can start. Wait on a busy loop until it's finished and then - * reenable the non-IRAM interrups. - * - * Input Parameters: - * argc - Not used. - * argv - Not used. - * - * Returned Value: - * Zero (OK) is returned on success. A negated errno value is returned to - * indicate the nature of any failure. - * - ****************************************************************************/ - -static int spi_flash_op_block_task(int argc, char *argv[]) -{ - struct tcb_s *tcb = this_task(); - int cpu = up_cpu_index(); - - for (; ; ) - { - DEBUGASSERT((1 << cpu) & tcb->affinity); - /* Wait for a SPI flash operation to take place and this (the other - * core) being asked to disable its non-IRAM interrupts. - */ - - nxsem_wait(&g_disable_non_iram_isr_on_core[cpu]); - - sched_lock(); - - esp32s3_irq_noniram_disable(); - - /* g_flash_op_complete flag is cleared on *this* CPU, otherwise the - * other CPU may reset the flag back to false before this task has a - * chance to check it (if it's preempted by an ISR taking non-trivial - * amount of time). - */ - - g_flash_op_complete = false; - g_flash_op_can_start = true; - while (!g_flash_op_complete) - { - /* Busy loop here and wait for the other CPU to finish the SPI - * flash operation. - */ - } - - /* Flash operation is complete, re-enable cache */ - - spi_flash_restore_cache(cpu); - - /* Restore interrupts that aren't located in IRAM */ - - esp32s3_irq_noniram_enable(); - - sched_unlock(); - } - - return OK; -} - -/**************************************************************************** - * Name: spiflash_init_spi_flash_op_block_task - * - * Description: - * Starts a kernel thread that waits for a semaphore indicating that a SPI - * flash operation is going to take place in the other CPU. It disables - * non-IRAM interrupts, indicates to the other core that the SPI flash - * operation can start and waits for it to be finished in a busy loop. - * - * Input Parameters: - * cpu - The CPU core that will run the created task to wait on a busy - * loop while the SPI flash operation finishes - * - * Returned Value: - * 0 (OK) on success; A negated errno value on failure. - * - ****************************************************************************/ - -int spiflash_init_spi_flash_op_block_task(int cpu) -{ - int pid; - int ret = OK; - char *argv[2]; - char arg1[32]; - cpu_set_t cpuset; - - snprintf(arg1, sizeof(arg1), "%p", &cpu); - argv[0] = arg1; - argv[1] = NULL; - - pid = kthread_create("spiflash_op", - SCHED_PRIORITY_MAX, - CONFIG_ESP32S3_SPIFLASH_OP_TASK_STACKSIZE, - spi_flash_op_block_task, - argv); - if (pid > 0) - { - if (cpu < CONFIG_SMP_NCPUS) - { - CPU_ZERO(&cpuset); - CPU_SET(cpu, &cpuset); - ret = nxsched_set_affinity(pid, sizeof(cpuset), &cpuset); - if (ret < 0) - { - return ret; - } - } - } - else - { - return -EPERM; - } - - return ret; -} -#endif /* CONFIG_SMP */ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - /**************************************************************************** * Name: esp32s3_spiflash_init * diff --git a/arch/xtensa/src/esp32s3/esp32s3_spiflash.h b/arch/xtensa/src/esp32s3/esp32s3_spiflash.h index cb4528e3f2..642c98c20b 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_spiflash.h +++ b/arch/xtensa/src/esp32s3/esp32s3_spiflash.h @@ -42,10 +42,75 @@ extern "C" #define EXTERN extern #endif +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* SPI Flash map request data */ + +struct spiflash_map_req_s +{ + /* Request mapping SPI Flash base address */ + + uint32_t src_addr; + + /* Request mapping SPI Flash size */ + + uint32_t size; + + /* Mapped memory pointer */ + + void *ptr; + + /* Mapped started MMU page index */ + + uint32_t start_page; + + /* Mapped MMU page count */ + + uint32_t page_cnt; +}; + /**************************************************************************** * Public Function Prototypes ****************************************************************************/ +/**************************************************************************** + * Name: esp32s3_mmap + * + * Description: + * Mapped SPI Flash address to ESP32-S3's address bus, so that software + * can read SPI Flash data by reading data from memory access. + * + * If SPI Flash hardware encryption is enable, the read from mapped + * address is decrypted. + * + * Input Parameters: + * req - SPI Flash mapping requesting parameters + * + * Returned Value: + * 0 if success or a negative value if fail. + * + ****************************************************************************/ + +int esp32s3_mmap(struct spiflash_map_req_s *req); + +/**************************************************************************** + * Name: esp32s3_ummap + * + * Description: + * Unmap SPI Flash address in ESP32-S3's address bus, and free resource. + * + * Input Parameters: + * req - SPI Flash mapping requesting parameters + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void esp32s3_ummap(const struct spiflash_map_req_s *req); + /**************************************************************************** * Name: spi_flash_read_encrypted *