From ed71eb7bc296784c109b78b9d8e3594080b0d816 Mon Sep 17 00:00:00 2001 From: Marco Casaroli Date: Wed, 7 Oct 2026 09:06:12 +0200 Subject: [PATCH] arch/arm/rp23xx: Compute the PSRAM QMI timing from the system clock. RP23XX_PSRAM_M1_TIMING was the constant 0x61a07102. The comment said it matched the Pico SDK, but it does not. The SDK computes the timing from clk_sys and the APS6404 limits (133 MHz SCK, 8 us maximum select, 18 ns minimum deselect). At 150 MHz it gives 0x60242202: field old SDK clkdiv 2 2 rxdelay 1 2 max_select 16 18 min_deselect 7 2 select_hold 3 0 The old RX delay samples the read data half a clk_sys cycle earlier than the SDK does. The constant is also wrong for any other clk_sys. Compute the fields from BOARD_SYS_FREQ at build time, with the SDK formula, and stop the build if a field is out of range. The result is identical to the SDK value at 48, 125, 150, 200, 266 and 300 MHz. Assisted-by: Claude Code:claude-opus-5-5 Signed-off-by: Marco Casaroli --- arch/arm/src/rp23xx/rp23xx_psram.c | 45 ++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/arch/arm/src/rp23xx/rp23xx_psram.c b/arch/arm/src/rp23xx/rp23xx_psram.c index 9aa6837c8f8..1acc2a2e546 100644 --- a/arch/arm/src/rp23xx/rp23xx_psram.c +++ b/arch/arm/src/rp23xx/rp23xx_psram.c @@ -44,6 +44,8 @@ #include +#include + #include "arm_internal.h" #include "rp23xx_gpio.h" #include "rp23xx_psram.h" @@ -73,18 +75,51 @@ #define QMI_DIRECT_TX_IWIDTH_Q (2 << RP23XX_QMI_DIRECT_TX_IWIDTH_SHIFT) -/* Final QMI M1 register values for the APS6404 in quad mode. Computed from - * the field layout in the RP2350 datasheet to match the Pico SDK: +/* APS6404 limits, as in the Pico SDK: 133 MHz SCK, 8 us maximum chip + * select time (refresh), 18 ns minimum deselect time. + */ + +#define PSRAM_MAX_FREQ 133000000 +#define PSRAM_MAX_SELECT_NS 8000ull +#define PSRAM_MIN_DESELECT_NS 18ull + +/* QMI M1 timing for clk_sys, computed as the Pico SDK does. Do not use a + * divisor of 1 above 100 MHz, and add one RX delay step above 100 MHz SCK. + */ + +#define PSRAM_CLKDIV_MIN \ + ((BOARD_SYS_FREQ + PSRAM_MAX_FREQ - 1) / PSRAM_MAX_FREQ) +#define PSRAM_CLKDIV \ + (PSRAM_CLKDIV_MIN == 1 && BOARD_SYS_FREQ > 100000000 ? 2 : PSRAM_CLKDIV_MIN) +#define PSRAM_RXDELAY \ + (PSRAM_CLKDIV + (BOARD_SYS_FREQ / PSRAM_CLKDIV > 100000000 ? 1 : 0)) +#define PSRAM_MAX_SELECT \ + (PSRAM_MAX_SELECT_NS * BOARD_SYS_FREQ / (64 * 1000000000ull)) +#define PSRAM_MIN_DESELECT \ + ((PSRAM_MIN_DESELECT_NS * BOARD_SYS_FREQ + 999999999) / 1000000000 - \ + (PSRAM_CLKDIV + 1) / 2) + +#if PSRAM_CLKDIV > 255 || PSRAM_RXDELAY > 7 || PSRAM_MAX_SELECT > 63 || \ + PSRAM_MIN_DESELECT > 31 +# error "BOARD_SYS_FREQ is out of range for the PSRAM timing" +#endif + +/* Final QMI M1 register values for the APS6404 in quad mode: * - * TIMING: COOLDOWN=1, PAGEBREAK=1024, SELECT_HOLD=3, MAX_SELECT=16, - * MIN_DESELECT=7, RXDELAY=1, CLKDIV=2. + * TIMING: COOLDOWN=1, PAGEBREAK=1024, and the values above. * RFMT: quad prefix/addr/suffix/dummy/data, 8-bit prefix, 24 dummy bits. * RCMD: read prefix 0xeb. * WFMT: quad prefix/addr/suffix/dummy/data, 8-bit prefix, no dummy. * WCMD: write prefix 0x38. */ -#define RP23XX_PSRAM_M1_TIMING 0x61a07102 +#define RP23XX_PSRAM_M1_TIMING \ + ((1 << RP23XX_QMI_TIMING_COOLDOWN_SHIFT) | \ + (2 << RP23XX_QMI_TIMING_PAGEBREAK_SHIFT) | \ + ((uint32_t)PSRAM_MAX_SELECT << RP23XX_QMI_TIMING_MAX_SELECT_SHIFT) | \ + ((uint32_t)PSRAM_MIN_DESELECT << RP23XX_QMI_TIMING_MIN_DESELECT_SHIFT) | \ + (PSRAM_RXDELAY << RP23XX_QMI_TIMING_RXDELAY_SHIFT) | \ + PSRAM_CLKDIV) #define RP23XX_PSRAM_M1_RFMT 0x000612aa #define RP23XX_PSRAM_M1_RCMD 0x000000eb #define RP23XX_PSRAM_M1_WFMT 0x000012aa