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 <marco.casaroli@gmail.com>
This commit is contained in:
Marco Casaroli 2026-10-07 09:06:12 +02:00 • committed by Alan C. Assis
parent 860577d771
commit ed71eb7bc2

View file

@ -44,6 +44,8 @@
#include <nuttx/irq.h>
#include <arch/board/board.h>
#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