Findings on Rev 4 hardware

Board errata

What bring-up on Rev 4 hardware proved broken, and what remains observed but not yet attributed to the board.

Updated 2026-09-01

Status from on-hardware bring-up — serial, JTAG and network debug of Ethernet, boot, eMMC and PCIe against a Pi 5 host. Items are split two ways: proven wrong, and observed but not yet attributed to the board.

They have not been re-verified on later boards.

Confirmed errata

Fault E1 — PCIe TX pairs are not AC-coupled on the card

The SOM TX pairs (GTR_DPn_M2C → J4 PET pins B14/15, B19/20, B23/24, B27/28) run direct, with no series capacitors. Per UG1091, “no transceiver capacitors are added to the data lanes on the PS-GTR transceivers” on the K26 SOM, and PCIe CEM places TX coupling on the add-in card — so these pairs must be AC-coupled here, and are not.

Meanwhile C15–C22 sit on the RX pairs (GTR_DPn_C2M, J4 PER pins), where the host already provides coupling; those extra series caps are redundant but harmless.

Impact: violates CEM for the upstream direction, and is the leading explanation for the link failure in O1.

The mechanism, per the LTSSM evidence in O1: receiver detection succeeds — the card’s uncoupled TX sees the host’s 50 Ω termination directly, so it advances Detect → Polling.Active and begins sending TS1 ordered sets — but the host never answers, Polling times out, and the card falls back to Detect. A DC-coupled transmit pair drives the card’s TX common-mode voltage straight into the host’s receiver, which has no coupling capacitor of its own (CEM assigns that to the add-in card) and therefore sits outside its required common-mode range and cannot recover the bit stream. Net effect: the card talks, the host cannot hear it, and the link cycles forever.

Confidence: consistent with every measurement taken, but not proven — the rework below is the experiment that settles it. Two earlier mechanisms for this erratum were wrong, and are recorded in O1 so the reasoning isn’t repeated.

Minimal rework for x1 bring-up: cut and fit 100 nF (0402) in series on the lane-0 pair at J4 B14/B15 only. Full x4 needs the same on all four pairs.

Open observations

Not yet attributable to the board.

Every firmware precondition has now been verified on the running board with the PCIe-endpoint FSBL:

checkregistervalueverdict
PCIe core clockPCIE_REF_CTRL 0xFD1A00B40x01000200matches psu_init intent
Lane 0 PLL lockL0_PLL_STATUS_READ_1 0xFD4023E40x38 (bit 4 set)locked
Lane protocol muxICM_CFG0/1 0xFD410010/140x11 / 0x11all 4 lanes = PCIe
Resets releasedRST_FPD_TOP 0xFD1A0100bits 17, 18, 19 clearreleased
Endpoint attributesATTR_* 0xFD4800xxprogrammed, port type 0 (EP)correct
ECO_0 (LTSSM hold)0xFD4803140x0not holding
LTSSM0xFD480228 bits[8:3]0 = Detect.Quietstuck
Link status0xFD4802380x2 (0x3 = up)down

Nothing in software remains to enable: the controller is clocked, out of reset, configured as an endpoint, and its LTSSM is not held. Clearing ECO_0 by hand changes nothing. zynqmp-pspcie-epdma is a host-side DMA/PIO datapath driver and does not perform link bring-up, so it isn’t the missing piece either. psu_init’s PCIe section demonstrably ran — the ID register reads 0x10EED011 as written.

Link training can be forced, and it partially works. Toggling pcie_ctrl_reset (RST_FPD_TOP bit 17) is a PERST equivalent and restarts the LTSSM. Doing that while the host simultaneously retrains — unbind/bind the Pi’s brcm-pcie root port — advances the card past Detect. A 3000-sample histogram of 0xFD480228 taken across a host retrain:

2916 samples  0x04  state 0 = Detect.Quiet
  84 samples  0x14  state 2 = Polling.Active

So the card does detect a receiver and does enter Polling.Active, where it transmits TS1 ordered sets — then times out with no reply and drops back to Detect, roughly a 3% duty cycle. It is cycling, not hung.

That measurement kills two earlier explanations: the link is not blocked by anything in firmware, and receiver detection is not failing — an uncoupled TX sees the far-end termination more readily, not less. What remains is the transmit path: the card talks and the host never answers. See E1.

Open O2 — QSPI left in a non-POR state after boot

Two symptoms, one likely mechanism.

  1. U-Boot sf probe reads garbage JEDEC IDs — e0/40/20, 43/49, c0 patterns, varying per cold boot, unaffected by SPI clock.
  2. Warm reset hangs the board, 100% reproducibly. Verified with continuous serial capture: reset from U-Boot, with the PL never loaded and Linux never run, prints resetting ... and dies before any BootROM, FSBL or U-Boot output. Only a power cycle recovers. Cold boots are 100% reliable.

The mechanism consistent with both: the boot-time QSPI driver (FSBL and/or the U-Boot env load) leaves the mt25qu512 in a volatile non-power-on state — 4-byte addressing and/or quad protocol. Later accessors that assume POR state (U-Boot’s sf layer, and critically the BootROM after a warm reset) then read garbage. Power cycling resets the flash and everything works.

The earlier suspicion that PCIe cable attach caused the sf garbage was likely coincidence with a boot-image change made the same hour.

Operational impact: warm reset is unsupported — use POR, the bench PSU switch. Candidate fix: patch the FSBL to issue a flash software reset after loading (exit-4-byte 0xE9, reset-enable 0x66 + reset 0x99), and audit U-Boot’s env-load path. Until then, treat warm reset as broken by design.

Open O3 — Power-on serial noise aborts U-Boot autoboot

Bytes land in the UART FIFO at power-on; the likely source is board-powered USB-serial adapter enumeration rather than the board itself. Any pending byte aborts the autoboot countdown.

Mitigated in the BOOT-emmc.BIN lineage by patching the default env to bootdelay=-2, which skips the abort check. Current images boot through reliably regardless of noise.