You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by ac...@apache.org on 2024/02/26 15:38:36 UTC

(nuttx) branch master updated: xtensa/esp32s3: Fix issue of system blocking when SPIRAM is used as stack 1. Fix issue of system blocking due to disable dcache. 2. Support Ext-SRAM-Cache mmu mapping in SMP mode.

This is an automated email from the ASF dual-hosted git repository.

acassis 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 638df3329b xtensa/esp32s3: Fix issue of system blocking when SPIRAM is used as stack    1. Fix issue of system blocking due to disable dcache.    2. Support Ext-SRAM-Cache mmu mapping in SMP mode.
638df3329b is described below

commit 638df3329b59b1326252cdb5c6a8c461bcf65c00
Author: chenwen@espressif.com <ch...@espressif.com>
AuthorDate: Thu Dec 28 11:48:41 2023 +0800

    xtensa/esp32s3: Fix issue of system blocking when SPIRAM is used as stack
       1. Fix issue of system blocking due to disable dcache.
       2. Support Ext-SRAM-Cache mmu mapping in SMP mode.
    
    Signed-off-by: chenwen@espressif.com <ch...@espressif.com>
---
 arch/xtensa/src/esp32s3/esp32s3_himem.c        |  46 +-----
 arch/xtensa/src/esp32s3/esp32s3_spiflash_mtd.c |  65 +++++++-
 arch/xtensa/src/esp32s3/esp32s3_spiflash_mtd.h |  18 +++
 arch/xtensa/src/esp32s3/esp32s3_spiram.c       | 197 +++++++++++++++++++++++++
 arch/xtensa/src/esp32s3/esp32s3_spiram.h       |  18 +++
 5 files changed, 293 insertions(+), 51 deletions(-)

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 <nuttx/mtd/mtd.h>
 
 #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 <sys/param.h>
 #include <nuttx/config.h>
 #include <nuttx/spinlock.h>
+#include <nuttx/init.h>
 #include <assert.h>
 
 #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.
  *