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

xiaoxiang781216 pushed a commit to branch releases/13.1
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit a670a61320cce761da3d25b92269fe30cb04e432
Author: Marco Casaroli <[email protected]>
AuthorDate: Wed Oct 7 09:10:56 2026 +0200

    arch/arm/rp23xx: Save and restore the QSPI state around flash writes.
    
    The bootrom flash functions reset the QMI window 1 (chip select 1)
    registers and the QSPI pads.  flash_flush_cache() also discards dirty
    XIP cache lines.  The flash MTD driver did not save anything, so after
    the first erase or program the PSRAM on chip select 1 read garbage,
    and PSRAM writes still in the cache were lost.
    
    Do what the Pico SDK hardware_flash library does:
    
    - Clean the XIP cache before the operation.  Clean by set/way through
      the top of the maintenance window, to avoid erratum RP2350-E11.
    - Save the QSPI pads and the five QMI M1 registers before, and write
      them back after XIP is restored.  Also keep XIP_CTRL.WRITABLE_M1.
    
    rp23xx_psram_restore() was the earlier fix for this, but nothing called
    it.  Remove it.
    
    Assisted-by: Claude Code:claude-opus-5-5
    Signed-off-by: Marco Casaroli <[email protected]>
---
 .../rp23xx/boards/pimoroni-pico-2-plus/index.rst   |   7 +-
 arch/arm/src/rp23xx/rp23xx_flash_mtd.c             | 112 ++++++++++++++++++---
 arch/arm/src/rp23xx/rp23xx_psram.c                 |  16 +--
 arch/arm/src/rp23xx/rp23xx_psram.h                 |  15 ---
 4 files changed, 102 insertions(+), 48 deletions(-)

diff --git 
a/Documentation/platforms/arm/rp23xx/boards/pimoroni-pico-2-plus/index.rst 
b/Documentation/platforms/arm/rp23xx/boards/pimoroni-pico-2-plus/index.rst
index 8269cc7788c..b9cd2ca9e79 100644
--- a/Documentation/platforms/arm/rp23xx/boards/pimoroni-pico-2-plus/index.rst
+++ b/Documentation/platforms/arm/rp23xx/boards/pimoroni-pico-2-plus/index.rst
@@ -66,10 +66,9 @@ heap, separate heap, or user heap) is selectable.  See the
 
    The PSRAM is considerably slower than the internal SRAM.  The QMI is
    shared with the flash: writing to the flash goes through the bootrom,
-   which reconfigures the QMI for chip select 0 and disturbs the PSRAM
-   configuration on chip select 1.  ``rp23xx_psram_restore()`` re-applies it
-   and is intended to be called from the flash write path after each erase or
-   program.
+   which resets the PSRAM configuration on chip select 1.  The flash MTD
+   driver (``RP23XX_FLASH_MTD``) saves that configuration before each erase
+   or program and restores it afterwards.
 
 Supported Capabilities
 ======================
diff --git a/arch/arm/src/rp23xx/rp23xx_flash_mtd.c 
b/arch/arm/src/rp23xx/rp23xx_flash_mtd.c
index 890ba8e6ce9..e4279b4f46c 100644
--- a/arch/arm/src/rp23xx/rp23xx_flash_mtd.c
+++ b/arch/arm/src/rp23xx/rp23xx_flash_mtd.c
@@ -74,6 +74,9 @@
 #include "rp23xx_flash_mtd.h"
 #include "rp23xx_rom.h"
 #include "hardware/rp23xx_memorymap.h"
+#include "hardware/rp23xx_pads_qspi.h"
+#include "hardware/rp23xx_qmi.h"
+#include "hardware/rp23xx_xip.h"
 
 /****************************************************************************
  * Pre-processor Definitions
@@ -87,6 +90,24 @@
 
 #define RP23XX_XIP_NOCACHE_BASE   0x14000000
 
+/* XIP cache maintenance window.  A clean by set/way must use the top of the
+ * window to avoid erratum RP2350-E11, as the Pico SDK does.
+ */
+
+#define RP23XX_XIP_MAINT_BASE     0x18000000
+#define XIP_CACHE_SIZE            (16 * 1024)
+#define XIP_CACHE_LINE_SIZE       8
+#define XIP_CACHE_CLEAN_SET_WAY   1
+#define XIP_CACHE_CLEAN_BASE      (RP23XX_XIP_MAINT_BASE + 0x04000000 - \
+                                   XIP_CACHE_SIZE + XIP_CACHE_CLEAN_SET_WAY)
+
+/* QSPI pads (SCLK, SD0-SD3, SS) and QMI window 1 registers (TIMING, RFMT,
+ * RCMD, WFMT, WCMD).  The bootrom flash functions change both.
+ */
+
+#define QSPI_PAD_COUNT            6
+#define QMI_M1_REG_COUNT          5
+
 /* Largest flash the XIP window can address, used only to sanity check a
  * pointer before it is called with the flash interface torn down.
  */
@@ -136,6 +157,15 @@ struct rp23xx_flash_dev_s
   mutex_t          lock;
 };
 
+/* QSPI state saved over a flash operation */
+
+struct rp23xx_qspi_state_s
+{
+  uint32_t pads[QSPI_PAD_COUNT];
+  uint32_t m1[QMI_M1_REG_COUNT];
+  uint32_t xip_ctrl;
+};
+
 typedef void (*connect_internal_flash_f)(void);
 typedef void (*flash_exit_xip_f)(void);
 typedef void (*flash_range_erase_f)(uint32_t, size_t, uint32_t, uint8_t);
@@ -368,16 +398,60 @@ static void leave_smp_isolation(struct smp_isolation_s 
*const data)
 #endif /* CONFIG_SMP */
 
 /****************************************************************************
- * Name: rp23xx_flash_restore_xip
+ * Name: rp23xx_flash_begin
+ *
+ * Description:
+ *   Save the QSPI state and put the flash in serial command mode, as the
+ *   Pico SDK does.  Must run from RAM: XIP is not available until
+ *   rp23xx_flash_end() returns.
+ *
+ ****************************************************************************/
+
+static void RAM_CODE(rp23xx_flash_begin)(struct rp23xx_qspi_state_s *state)
+{
+  int i;
+
+  /* Write back dirty PSRAM lines.  flash_flush_cache() discards them. */
+
+  for (i = 0; i < XIP_CACHE_SIZE; i += XIP_CACHE_LINE_SIZE)
+    {
+      putreg8(0, XIP_CACHE_CLEAN_BASE + i);
+    }
+
+  UP_DSB();
+  UP_ISB();
+
+  for (i = 0; i < QSPI_PAD_COUNT; i++)
+    {
+      state->pads[i] = getreg32(RP23XX_PADS_QSPI_GPIO_QSPI_SCLK + 4 * i);
+    }
+
+  for (i = 0; i < QMI_M1_REG_COUNT; i++)
+    {
+      state->m1[i] = getreg32(RP23XX_QMI_M1_TIMING + 4 * i);
+    }
+
+  state->xip_ctrl = getreg32(RP23XX_XIP_CTRL_BASE);
+
+  __asm__ volatile ("" : : : "memory");
+
+  g_rom.connect_internal_flash();
+  g_rom.flash_exit_xip();
+}
+
+/****************************************************************************
+ * Name: rp23xx_flash_end
  *
  * Description:
- *   Put the QSPI interface back into execute-in-place mode.  Must run from
- *   RAM: until it returns, nothing can be fetched from flash.
+ *   Put the QSPI interface back into execute-in-place mode, then restore
+ *   the pads and the chip select 1 (PSRAM) window that the bootrom reset.
  *
  ****************************************************************************/
 
-static void RAM_CODE(rp23xx_flash_restore_xip)(void)
+static void RAM_CODE(rp23xx_flash_end)(struct rp23xx_qspi_state_s *state)
 {
+  int i;
+
   g_rom.flash_flush_cache();
 
   /* Ask the bootrom to put the flash back into a fast quad read mode.  It
@@ -391,6 +465,20 @@ static void RAM_CODE(rp23xx_flash_restore_xip)(void)
     {
       g_rom.flash_enter_cmd_xip();
     }
+
+  for (i = 0; i < QSPI_PAD_COUNT; i++)
+    {
+      putreg32(state->pads[i], RP23XX_PADS_QSPI_GPIO_QSPI_SCLK + 4 * i);
+    }
+
+  for (i = 0; i < QMI_M1_REG_COUNT; i++)
+    {
+      putreg32(state->m1[i], RP23XX_QMI_M1_TIMING + 4 * i);
+    }
+
+  putreg32(getreg32(RP23XX_XIP_CTRL_BASE) |
+           (state->xip_ctrl & RP23XX_XIP_CTRL_WRITABLE_M1),
+           RP23XX_XIP_CTRL_BASE);
 }
 
 /****************************************************************************
@@ -404,10 +492,9 @@ static void RAM_CODE(rp23xx_flash_restore_xip)(void)
 
 static void RAM_CODE(do_erase)(uint32_t addr, size_t count)
 {
-  __asm__ volatile ("" : : : "memory");
+  struct rp23xx_qspi_state_s state;
 
-  g_rom.connect_internal_flash();
-  g_rom.flash_exit_xip();
+  rp23xx_flash_begin(&state);
 
   /* The bootrom erases whole 64K blocks where address and length allow it
    * and falls back to 4K sectors otherwise.
@@ -416,7 +503,7 @@ static void RAM_CODE(do_erase)(uint32_t addr, size_t count)
   g_rom.flash_range_erase(addr, count, FLASH_BLOCK_SIZE,
                           FLASH_BLOCK_ERASE_CMD);
 
-  rp23xx_flash_restore_xip();
+  rp23xx_flash_end(&state);
 }
 
 /****************************************************************************
@@ -426,14 +513,11 @@ static void RAM_CODE(do_erase)(uint32_t addr, size_t 
count)
 static void RAM_CODE(do_write)(uint32_t addr, const uint8_t *data,
                                size_t count)
 {
-  __asm__ volatile ("" : : : "memory");
-
-  g_rom.connect_internal_flash();
-  g_rom.flash_exit_xip();
+  struct rp23xx_qspi_state_s state;
 
+  rp23xx_flash_begin(&state);
   g_rom.flash_range_program(addr, data, count);
-
-  rp23xx_flash_restore_xip();
+  rp23xx_flash_end(&state);
 }
 
 /****************************************************************************
diff --git a/arch/arm/src/rp23xx/rp23xx_psram.c 
b/arch/arm/src/rp23xx/rp23xx_psram.c
index 1acc2a2e546..82b83762907 100644
--- a/arch/arm/src/rp23xx/rp23xx_psram.c
+++ b/arch/arm/src/rp23xx/rp23xx_psram.c
@@ -165,8 +165,7 @@ rp23xx_psram_wait_busy(void)
  *
  * Description:
  *   Program the QMI M1 timing/format/command registers and mark the region
- *   writable.  Shared by the initial configuration and the post-flash
- *   restore.  Runs from RAM.
+ *   writable.  Runs from RAM.
  *
  ****************************************************************************/
 
@@ -374,17 +373,4 @@ size_t rp23xx_psram_size(void)
   return g_psram_size;
 }
 
-/****************************************************************************
- * Name: rp23xx_psram_restore
- ****************************************************************************/
-
-void RP23XX_PSRAM_RAMFUNC
-rp23xx_psram_restore(void)
-{
-  if (g_psram_size != 0)
-    {
-      rp23xx_psram_apply_format();
-    }
-}
-
 #endif /* CONFIG_RP23XX_PSRAM */
diff --git a/arch/arm/src/rp23xx/rp23xx_psram.h 
b/arch/arm/src/rp23xx/rp23xx_psram.h
index 58d5ce907d2..88a5327cc83 100644
--- a/arch/arm/src/rp23xx/rp23xx_psram.h
+++ b/arch/arm/src/rp23xx/rp23xx_psram.h
@@ -71,19 +71,4 @@ size_t rp23xx_psramconfig(void);
 
 size_t rp23xx_psram_size(void);
 
-/****************************************************************************
- * Name: rp23xx_psram_restore
- *
- * Description:
- *   Re-apply the QMI M1 (PSRAM) format and timing registers.  Programming
- *   the flash goes through the bootrom, which reconfigures the shared QMI
- *   interface for chip select 0; this restores the CS1 configuration
- *   afterwards so the memory-mapped PSRAM keeps working across a flash
- *   erase or program.  Runs from RAM and does nothing when no PSRAM was
- *   detected.
- *
- ****************************************************************************/
-
-void rp23xx_psram_restore(void);
-
 #endif /* __ARCH_ARM_SRC_RP23XX_RP23XX_PSRAM_H */

Reply via email to