arch/arm/rp23xx: Keep flash writes off PSRAM and flash data.

While the bootrom erases or programs the flash, the QMI is in direct
mode, and an access to the XIP space (flash or PSRAM) gives a bus
fault.  The flash MTD driver accessed it in two cases:

- The data to program was in flash or PSRAM.  flash_range_program()
  read it during the operation.  Now the driver copies each such page
  to an SRAM buffer first.
- The caller's stack was in PSRAM.  This is the normal case with
  RP23XX_PSRAM_HEAP_USER, and possible with RP23XX_PSRAM_HEAP_SINGLE.
  The operation pushed to that stack.  Now the driver switches to a
  small SRAM stack for the operation if the stack is in the XIP space.

The operation data is static (SRAM) since the previous commit.

Assisted-by: Claude Code:claude-opus-5-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
This commit is contained in:
Marco Casaroli 2026-10-07 09:17:28 +02:00 • committed by Alan C. Assis
parent 75f8249405
commit cb87f99b6e
2 changed files with 67 additions and 2 deletions

View file

@ -338,6 +338,11 @@ restores the read mode found at boot, or, with
only on the documented bootrom entry point. The driver also saves and
restores the QSPI pads and the PSRAM configuration on chip select 1.
Flash and PSRAM cannot be read while an erase or program is in progress. So
the driver copies a page to SRAM before it programs it if the data is in flash
or PSRAM, and a caller with its stack in PSRAM runs the operation on a small
SRAM stack.
The driver answers the ``BIOC_XIPBASE`` ioctl with the memory-mapped address of
the region, so a filesystem that supports execute in place can hand out real
flash pointers instead of copying into RAM.

View file

@ -109,6 +109,17 @@
#define QSPI_PAD_COUNT 6
#define QMI_M1_REG_COUNT 5
/* True for an address in the XIP space (flash or PSRAM), which cannot be
* accessed while the QMI is in direct mode.
*/
#define IS_XIP_ADDR(a) \
((uintptr_t)(a) >= RP23XX_FLASH_BASE && (uintptr_t)(a) < RP23XX_SRAM_BASE)
/* SRAM stack for a flash operation called with its stack in PSRAM */
#define FLASH_OP_STACK_SIZE 1024
/* Largest flash the XIP window can address, used only to sanity check a
* pointer before it is called with the flash interface torn down.
*/
@ -245,6 +256,14 @@ static bool g_initialized = false;
static struct rp23xx_flash_op_s g_flash_op;
/* SRAM copy of a page whose source is in the XIP space */
static uint8_t g_flash_page[FLASH_PAGE_SIZE] aligned_data(4);
#ifdef CONFIG_RP23XX_PSRAM
static uint64_t g_flash_stack[FLASH_OP_STACK_SIZE / 8];
#endif
#ifdef CONFIG_SMP
static struct smp_isolation_s g_smp_isolation;
#endif
@ -526,6 +545,41 @@ static void RAM_CODE(do_write)(FAR struct rp23xx_flash_op_s *op)
rp23xx_flash_end(&state);
}
/****************************************************************************
* Name: rp23xx_flash_call
*
* Description:
* Call g_flash_op.func. PSRAM is not accessible during the operation,
* so if the stack is in PSRAM, switch to an SRAM stack first.
*
****************************************************************************/
static void rp23xx_flash_call(void)
{
#ifdef CONFIG_RP23XX_PSRAM
if (IS_XIP_ADDR(up_getsp()))
{
__asm__ __volatile__
(
"mov r4, sp\n\t"
"mov sp, %[top]\n\t"
"mov r0, %[op]\n\t"
"blx %[func]\n\t"
"mov sp, r4\n\t"
:
: [top] "r" (&g_flash_stack[FLASH_OP_STACK_SIZE / 8]),
[op] "r" (&g_flash_op),
[func] "r" (g_flash_op.func)
: "r0", "r1", "r2", "r3", "r4", "r12", "lr", "memory", "cc"
);
return;
}
#endif
g_flash_op.func(&g_flash_op);
}
/****************************************************************************
* Name: rp23xx_flash_run
*
@ -545,7 +599,7 @@ static void rp23xx_flash_run(void)
#endif
flags = enter_critical_section();
g_flash_op.func(&g_flash_op);
rp23xx_flash_call();
leave_critical_section(flags);
#ifdef CONFIG_SMP
@ -645,7 +699,7 @@ static ssize_t rp23xx_flash_bread(struct mtd_dev_s *dev, off_t startblock,
*
* Description:
* Program one page at a time, so that interrupts are disabled for one
* page program at most.
* page program at most. Copy a page from flash or PSRAM to SRAM first.
*
****************************************************************************/
@ -674,6 +728,12 @@ static ssize_t rp23xx_flash_bwrite(struct mtd_dev_s *dev, off_t startblock,
g_flash_op.data = buffer + i * FLASH_PAGE_SIZE;
g_flash_op.count = FLASH_PAGE_SIZE;
if (IS_XIP_ADDR(g_flash_op.data))
{
memcpy(g_flash_page, g_flash_op.data, FLASH_PAGE_SIZE);
g_flash_op.data = g_flash_page;
}
rp23xx_flash_run();
}