Chasing a PCIe Ghost on Raspberry Pi 5
How a simple expansion experiment turned into a deep dive through link training, oscilloscopes, kernel patches, and a plan to build my own PCB.
The setup
I wanted to connect standard PCIe cards to a Raspberry Pi 5. I used the 52Pi P02 (EP-0219) adapter: a full-size PCIe slot connected to the Pi's external PCIe FFC connector. The Pi exposes one lane, so even physically wider cards operate at x1.
My test hardware included an AXAGON PCEE-G25 RTL8125B 2.5GbE NIC, a 10Gtek four-port RTL8125 NIC behind an ASMedia ASM1806 switch, a standalone ASM1184E switch card, and a Broadcom/LSI SAS9300-8i (SAS3008) HBA.
The results were not what I expected.
A puzzling compatibility matrix
| Device | Raspberry Pi 5 + P02 result |
|---|---|
| AXAGON RTL8125B | No link; ends in Polling.Compliance |
| ASM1184E | No usable link; sometimes reaches Polling.Configuration |
| 10Gtek ASM1806 | Upstream link works; switch and downstream bridges enumerate |
| 10Gtek 4× RTL8125 | No NIC endpoints enumerate |
| SAS3008 | Works, including Gen3 8.0 GT/s x1, with no reported AER errors |
The SAS3008 was a particularly useful control. It demonstrated that the same Pi, FFC cable, and P02 could carry a working Gen3 link. But that did not prove every electrical and timing characteristic of the adapter was correct for every endpoint.
Watching PCIe link training
I enabled the Raspberry Pi Broadcom driver's LTSSM tracing:
pcie-brcmstb.trace_ltssm=1
For the AXAGON, the result was repeatable across Gen1, Gen2, and Gen3 settings:
Detect.Active
Polling.Active
~24 ms later: Polling.Compliance
link down
The ASM1184E behaved differently. At Gen2/Gen3 it could reach Polling.Configuration, but still never established a usable link. Working cards advanced through Configuration.Link, the other configuration substates, and ultimately L0.
These are different failure stages, not one universal symptom.
Ruling out the obvious
I tested Raspberry Pi kernel 6.12 and 6.18; the behavior persisted. I forced Gen1/Gen2/Gen3, tried a 500 ms delay before PERST# release, changed the P02's power arrangement, and tested with CLKREQ held low. I checked the 5 V supply and PCIe slot's 3.3 V rails. None of these changes fixed the failing cards.
With a FNIRSI DPOX180H oscilloscope, I verified that PERST# was released during the link-training window and reasserted after failure. I also observed an approximately 100 MHz REFCLK during training on the AXAGON and ASM1184E. So the reset and clock signals were not simply absent.
The scope cannot resolve a PCIe 2.5 GT/s eye diagram, but it can reveal coarse activity. The AXAGON showed activity from the card toward the Pi; comparable Pi-to-card training activity was not clearly visible. The ASM1184E showed Pi-to-card activity and progressed farther in the LTSSM.
An approximately 208 mV receiver-detect-looking event was visible with an empty slot, and a similar event appeared with the working 10Gtek. I did not see an equally clear event with the AXAGON. This was an interesting comparison, not a compliance-grade measurement or proof of a particular receiver-detection failure.
Eventually, probing the tiny FFC connector with ordinary multimeter probes became more risky than useful. Adjacent contacts were too easy to bridge, and continuity readings could be misleading.
A kernel patch: retry without PERST#
One hypothesis was that the RTL8125 needed more time after startup. I patched the Raspberry Pi 6.18 pcie-brcmstb driver to toggle the root port's Link Disable bit after the initial failure, restarting link training without reasserting PERST#.
The first attempt produced:
Detect.Active → Polling.Active → Polling.Compliance
The retry produced the same sequence. The second capture reported zero timestamps because tracing began after the restart, so those timestamps were not useful for timing analysis. The meaningful result was that the warm LTSSM retry did not recover the AXAGON.
This weakened the simple “endpoint was not ready yet” explanation, although it did not reveal the underlying cause.
The x86 cross-check changed everything
Later I tested the cards in an x86-64 PC. Every card worked. The ASM1184E exposed its four ports; the 10Gtek enumerated its ASM1806 switch and all four RTL8125 NICs; and the AXAGON worked. A separate PCIe x1-to-x16 riser/extender also successfully detected an RTL8127.
This ruled out treating the endpoint cards as generally defective.
It also exposed a problem with the early “RTL8125 versus BCM2712” theory: on the 10Gtek, the four RTL8125 controllers are behind the ASM1806 switch, not directly connected to the Raspberry Pi PHY. A direct BCM2712-to-RTL8125 electrical mismatch alone cannot explain every observation.
The common failure environment is the Pi 5 + FFC cable + 52Pi P02 combination. Plausible causes still include P02 signal integrity or power/reset implementation, BCM2712 external PCIe interoperability, or an interaction between them. Successful HATs such as Hailo setups show that the Pi's external PCIe can work, but they do not isolate the P02 because they replace the adapter path entirely.
The adapter became the unknown
I consulted the 52Pi EP-0219 wiki and the official Raspberry Pi 5 PCIe connector specification. The official J20 signal assignment includes:
| J20 pin | Signal |
|---|---|
| 4 / 5 | PCIe reference clock P / N |
| 7 / 8 | PCIe RX P / N |
| 10 / 11 | PCIe TX P / N |
| 13 | PCIe power enable |
| 14 | PCIe detect / wake |
| 15 | PCIe CLKREQ# |
| 16 | PCIe reset |
Without a full, verified P02 schematic and layout—or another equivalent PCIe slot adapter for A/B testing—I could not confidently separate the board's behavior from the Pi's own PCIe behavior. Basic continuity measurements were not going to tell me enough about AC coupling, controlled impedance, clock routing, and reset or power sequencing.
Next: designing my own PCIe PCB
I'm going to design and build a custom PCB with all required onboard power converters and a full-size PCIe connector, replacing the 52Pi P02 adapter in my test setup.
The design will include a Pi 5-compatible FFC interface, regulated 12 V and 3.3 V slot supplies sized for the intended cards, controlled-impedance PCIe TX/RX and REFCLK routing, correct reset and sideband handling, and accessible test points for power and low-speed signals. The slot will accept wider physical cards, while the Pi connection remains one PCIe lane. I'll also make the schematic, component choices, and power sequencing fully inspectable.
I have not proven that the P02 is defective. The purpose of the custom PCB is to remove an opaque adapter from the experiment and make the entire signal and power path understandable and measurable.
If the same cards fail on the new PCB, the evidence will shift toward Pi 5 / BCM2712 behavior or a shared design assumption. If they work, the P02 implementation or its connection will become the much stronger suspect.
Either outcome is progress. The next chapter will be about designing, assembling, and testing the replacement board.