Files
retroDE_ps2/docs/ch318-lpddr-fb-bringup.md
T
thejayman77 ec82764bef Initial commit: retroDE_ps2 — first-of-its-kind PS2 GS FPGA core (DE25-Nano / Agilex 5)
RTL (GS rasterizer, EE core stub, platform bridge, LPDDR4B path), sim regression
(272 TBs), docs, and tooling. Copyrighted PS2 content (BIOS, game code, GS dumps,
and all dump-derived textures/traces) is excluded via .gitignore and stays local.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 20:10:50 -04:00

3.4 KiB
Raw Blame History

Ch318 — LPDDR framebuffer write/readback: board bring-up

ONE bitstream. All test controls are runtime, via HPS bridge registers — no rebuild to go disabled → canary → full. Defaults are safe: arm OFF, canary ON, base 0x80000000. The booted core writes nothing to LPDDR until the HPS arms it.

Runnable script

docs/hardware/ps2_lpddr_test.sh (same style as ps2_status.sh; bridge base defaults to 0x40000000, busybox devmem):

./ps2_lpddr_test.sh            # read-only LPDDR status (safe)
./ps2_lpddr_test.sh --canary   # arm canary, verify 32 B vs expected, PASS/FAIL, auto-disarm
./ps2_lpddr_test.sh --full     # arm full frame, hash 8 KiB vs expected md5, PASS/FAIL, auto-disarm
./ps2_lpddr_test.sh --disarm   # force disarm (LPDDR_CTRL=0x2)

The manual register/dd reference below is what the script automates.

Build

QSF (already set): GS_TILE_PSMCT16FB_DEMO=1 + GS_LPDDR_FB=1 (plus the usual GS_RMW_DEMO). Build/load the .rbf once. That's the only build.

HPS bridge register map (new in Ch318)

Offsets are relative to the PS2 HPS-bridge base — the same base retrodesd already uses to reach CORE_ID/OSD_CTRL/INPUT_P1 on this core (the HPS2FPGA bridge window). 32-bit accesses.

Offset Name R/W Meaning
0x018 LPDDR_CTRL RW bit0 = arm (1 = permit AXI writes), bit1 = canary (1 = write only the 32-byte top line). Reset = 0x2 (disarmed, canary).
0x01C LPDDR_FB_BASE RW LPDDR byte base address. Reset = 0x8000_0000.
0x02C LPDDR_STATUS R bit0 = idle, bit1 = bresp error seen, bit2 = FIFO overflow seen.
0x030 LPDDR_BYTES R total bytes written.
0x034 LPDDR_BURSTS R total 32-byte bursts issued.

The framebuffer itself is read from physical LPDDR 0x8000_0000 (the f2sdram AXI address is the HPS physical address — the qsys slave maps a flat 4 GiB), which is the reserved region from /proc/iomem (below Linux System RAM at 0x82000000 — safe).

Canary test (32-byte write, deterministic)

  1. Confirm defaults: read LPDDR_CTRL (expect 0x2), LPDDR_FB_BASE (expect 0x8000_0000).
  2. Baseline: sudo dd if=/dev/mem bs=1 skip=2147483648 count=32 2>/dev/null | hexdump -C
  3. Arm in canary mode: write LPDDR_CTRL = 0x3 (arm=1, canary=1).
  4. Re-read the 32 bytes (same dd). Expect the top scanline (PSMCT16 green = 0x8200): 00 82 00 82 00 82 00 82 00 82 00 82 00 82 00 82 (×2 lines = 32 bytes).
  5. Optional: read LPDDR_BURSTS (advancing) + LPDDR_STATUS (bit1/bit2 = 0). PASS = bytes changed baseline → the 00 82 pattern (fabric reached LPDDR at the expected physical address). Then disarm: write LPDDR_CTRL = 0x2.

Full-frame test (8 KiB)

  1. Arm full: write LPDDR_CTRL = 0x1 (arm=1, canary=0).
  2. sudo dd if=/dev/mem bs=4096 skip=524288 count=2 2>/dev/null | md5sum Expect 3b12baffc00bb6419fa66272c75b2cc7 (the exact sim image).
  3. Confirm LPDDR_STATUS bits 1,2 = 0 (no bresp/FIFO errors). Disarm when done (0x2).

Notes

  • 0x80000000 = 2147483648 bytes; skip=524288 blocks × 4096 = same address.
  • Never read/write 0x820000000xBFFFFFFF (live Linux RAM).
  • If a hardened kernel blocks /dev/mem to the reserved region, use the same devmem/mmap path the existing runtime uses; if a readback looks stale, it's CPU caching of that address — read uncached.
  • Scanout from LPDDR is Ch319 — start only after this write/readback passes.