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 */
