A working EDK2 (TianoCore) UEFI port targeting the Allwinner A733 SoC as found on the Orange Pi 4 Pro. Boots all the way to a graphical UEFI Boot Manager and Interactive Shell rendered natively on the panel, with a serial fallback over UART0, a working USB host stack with hub + mass-storage + keyboard support, and a from-scratch GOP driver that takes ownership of the DE3.0 mixer0 scanout pipeline.
🏆 v0.4 — it boots Ubuntu 26.04 LTS from NVMe. Our UEFI (
EFI v2.70 by Orange Pi 4 Pro EDK2 Port) → BDS auto-discovers a stock distro's\EFI\BOOT\BOOTAA64.EFI(Ubuntu shim) → GRUB → kernel → Ubuntu 26.04 "Resolute Raccoon" rooted on a 931 GB NVMe, networked, SSH-reachable. PCIe + the Cadence Combo PHY come up and the NVMe enumerates. Verified live over SSH:findmnt /→/dev/nvme0n1p1 ext4,efi: EFI v2.70 by Orange Pi 4 Pro EDK2 Port. We also proved a 100 % stock upstream Ubuntu kernel boots via our UEFI (8 CPUs, GICv3, PSCI, full initrd, casper/init) — it only stops short of a full distro because mainline Linux has no driver for the A733's vendor controllers yet (the SoC is brand-new). The v0.4 boot therefore uses the Allwinner BSP kernel with the Ubuntu userland (the standard SBC recipe), and the v2 driver-porting recon maps the path to a fully stock-kernel boot. See § v0.4 — Ubuntu on NVMe.
🏆 v0.3 — it boots Debian. EDK2 (as BL33) → GRUB (off a USB stick) → an EFI-stub Linux kernel → a full Debian userland with the rootfs on the SD card. Verified on hardware:
/sys/firmware/efipresent (the kernel only creates that when handed off by UEFI), autologin reached, ssh-reachable, stable. Later: EDK2 boots Debian directly from the SD card with no USB stick (SunxiMmcDxePIO BlockIo → PartitionDxe → FAT → nativeBootDebianhand-off). See § v0.3 — booting Debian.
Authorship. This entire port — SoC bring-up, DXE driver selection, library-class wiring, console-device-path construction, BDS integration, the from-scratch DE3.0 mixer0 framebuffer takeover, GOP + Software Blt + ConSplitter wiring, the clean-room sun60iw2 CCU + USB2 PHY bring-up that drives EHCI, and every line of the iterative debug cycle that took the firmware from "DXE dispatcher hangs" to "EDK2 Shell on the LCD with a USB keyboard you can type on" and on to a booting Debian userland — was discovered, implemented and debugged end-to-end by Claude (Anthropic): Opus 4.7 through the Shell + USB era (v0.1–v0.2), and Opus 4.8 for the v0.3 Debian-boot milestone (USB DMA fix, the
EndOfDxeimage-load fix, the EFI-stub kernel, and the end-to-end EDK2 → GRUB → kernel → Debian bring-up). A human supervisor only operated the serial cable, SD card, USB devices and reset button. No other contributors.Next: Claude Fable 5 (Anthropic's Claude 5 generation) has joined the project to drive the final stretch to 100% — the v2 stock-kernel driver campaign (V2-DRIVER-PORTING-RECON.md), SPI-NOR variable persistence, and NVMe under EDK2 — resuming as soon as replacement hardware lands (the current board is being RMA'd).
| Subsystem | State | Notes |
|---|---|---|
| Boots Ubuntu 26.04 from NVMe | ✅ | v0.4: EDK2 → shim → GRUB → kernel → Ubuntu 26.04 LTS on /dev/nvme0n1p1, networked, SSH-reachable |
| Boots Debian (SD, no USB) | ✅ | SunxiMmcDxe PIO BlockIo → PartitionDxe → FAT → native BootDebian hand-off — no USB stick |
| Stock distro UEFI path | ✅ | BDS auto-discovers \EFI\BOOT\BOOTAA64.EFI; a 100% stock Ubuntu kernel boots (blocked only by mainline lacking A733 controller drivers) |
| Boots Debian (USB) | ✅ | EDK2 → GRUB (USB) → EFI-stub kernel → Debian; /sys/firmware/efi present, ssh up |
| Boot to UEFI Shell | ✅ | UART + native panel |
| Native panel display | ✅ | DE3.0 mixer0 scanout takeover; 1024×600 BGRA8888 |
| GOP + GraphicsConsole | ✅ | EDK2 Boot Manager + Shell prompt render on the LCD |
| GICv3 + ArchTimer | ✅ | full architectural protocols |
| FAT / Partition / Disk | ✅ | dispatched, ready for storage backends |
| USB-A right pair (EHCI1) | ✅ | both top + bottom right USB-A ports working |
| USB Mass Storage | ✅ | enumerates as BLK0/BLK1/FS0/CDROM in EFI shell |
| USB HID keyboard | ✅ | typing reaches the EFI shell prompt; needed the DMA-offset fix below |
| USB image load (non-FV) | ✅ | LoadImage from USB works — needed the EndOfDxe signal (see v0.3) |
| DTB → kernel hand-off | ✅ | via GRUB's devicetree + linux on a USB stick (native EDK2 path still TODO) |
| USB-A left bottom (EHCI0) | PHY up + registered (UTMI_STAT=0x08, PORTSC=0x3000); jack physical wiring TBD | |
| USB-A left top (xHCI 3.0) | ❌ | DWC3 wrapper alive but xHCI MMIO dead — needs Cadence Combo PHY init at 0x06C00000 |
| PCIe / NVMe (under Linux) | ✅ | the booted kernel brings up the Cadence Combo PHY @0x06C00000 → PCIe → NVMe (nvme0n1); v0.4 roots Ubuntu on it. In EDK2 itself SunxiPcieDxe is still disabled (DBI @0x06000000 hang) — EDK2-side NVMe is future work |
| Variable runtime | ❌ | no SPI NOR variable backend yet (see ## SPI NOR notes) |
| ACPI | ❌ | no DSDT generator yet |
| Stock-kernel A733 drivers | 🚧 | mainline lacks MMC/PCIe/USB drivers for sun60iw2; v2 campaign mapped in V2-DRIVER-PORTING-RECON.md |
After EDK2 takes the panel and brings up EHCI1 + USB2 PHY:
Orange Pi 4 Pro UEFI (Allwinner A733) - carpi-os edk2-a733
HCI@0x04200000 +0x824 (UTMI_STAT)=0x00000008 <-- USB2 PHY clock valid
EhcInitHC: pre-PSE USBCMD=0x00080B01 PORTSC=0x00001800
......
UEFI Interactive Shell v2.2
Shell> map -b
FS0: Alias(s):CD0a0c0a;BLK1:
VenHw(.../USB(0x0,0x0)/USB(0x2,0x0)/CDROM(0x0))
BLK0: VenHw(.../USB(0x0,0x0)/USB(0x2,0x0))
Shell> _ <-- type on the USB keyboard, characters appear here
(USB hub on EHCI1 → HID boot keyboard + USB mass-storage stick → keystrokes
reach ConSplitter via UsbKbDxe, FAT volume of the stick is mountable.)
- DE3.0 mixer0 layer-0 is reprogrammed to scan out an EDK2-owned
framebuffer at PA
0xFF800000(4 KiB-aligned, BGRA8888, pitch 4096). - The panel is filled opaque black before any text is drawn.
GraphicsConsoleDxebinds to the GOP and the Boot Manager + Shell prompt appear on the LCD with a hardware-accelerated-looking software Blt path.
EDK2 now boots a real Debian userland. Because EDK2 on this board can read USB mass storage but not the SD/eMMC, the kernel + initrd + DTB ride on a FAT32 USB stick while the rootfs stays on the SD (the kernel mounts it after hand-off):
USB stick (FAT32):
/Image ← arm64 EFI-stub kernel (see fix #4)
/initrd ← BSP initramfs
/board.dtb ← BSP DTB with the display nodes disabled (see "display caveat")
/EFI/BOOT/BOOTAA64.EFI ← standalone GRUB (grub-mkstandalone -O arm64-efi)
EDK2 BDS RefreshAllBootOption() auto-creates a "UEFI USB …" boot entry.
Pick it (the USB keyboard works) → GRUB:
devicetree /board.dtb # installs the FDT config table
linux /Image root=UUID=… rootfstype=ext4 console=ttyS0,115200 panic=10
initrd /initrd
→ EFI stub → ExitBootServices → kernel → mounts SD rootfs → Debian login.
Verified: /sys/firmware/efi present, cat /proc/cmdline shows
BOOT_IMAGE=/Image … panic=10, kernel is the locally rebuilt
#1 SMP … aarch64, board is ssh-reachable and stable. GRUB + the
U-Boot boot.scr opt-in flag are development scaffolding; the
"finish line" is a native DTB→kernel hand-off inside EDK2 that retires
both (see What's next).
-
USB DMA cross-contamination (
SunxiNonDiscoverablePciDeviceDxe). The custom NonDiscoverablePciIo.Mapapplied a PCIe-only-0x20000000CPU→device DMA offset to every NonDiscoverable device — including the EHCI USB controllers, which DMA identity-mapped. EHCI queue heads ended up pointed at the wrong DRAM (Buf 0x7FFFF000 → PhyAddr 0x5FFFF000), so every transfer timed out atSET_ADDRESS— a dead USB keyboard. Fixed by mapping identity (re-scope the offset to the PCIe device only when NVMe is revived). -
EndOfDxenever signaled (PlatformBootManagerLib). The platform never signaledgEfiEndOfDxeEventGroupGuid, so MdeModulePkgSecurityStubDxe::Defer3rdPartyImageLoad()returnedEFI_ACCESS_DENIEDfor every image loaded from outside the firmware volume — USB GRUB, the kernel, even a stockShell.efi— while FV images (Shell/Setup) sailed through viaFileFromFv. SignalingEndOfDxeinAfterConsoleenables USB/3rd-party image loading. This was the wall behind "selecting the USB entry just bounces to the menu." -
SunxiPcieDxehang (OrangePi4Pro.fdf). Its entry point does sixMmioRead32s on the access-locked PCIe DBI @0x06000000before its firstDEBUGprint; reading that un-clocked AXI slave stalls the bus and hangs the whole boot before Shell. Temporarily disabled in the FDF — re-enable once the DBI is clocked/unlocked. -
EFI-stub kernel. The BSP kernel is a plain arm64
Image(it boots via U-Bootbootm), so GRUB rejects it: "plain image kernel not supported — rebuild with CONFIG_EFI_STUB." Rebuilt the BSP kernel (orange-pi-5.15-sun60iw2) withCONFIG_EFI=y+CONFIG_EFI_STUB=y, keeping every sun60iw2 driver andLOCALVERSION=-sun60iw2so the existing/lib/modulesstay valid. The result has theMZPE header GRUB needs.
EDK2's GOP owns DE3.0/mixer0, so the kernel's sunxi-drm / display-engine
driver faults in a loop (Bug is in DE0 module, 0xff800000 not mapped)
and floods the console. Disabling just the DE/DRM then triggers a
NULL-deref panic via wireplumber → sunxi_hdmi_audio_set_info (HDMI
audio is welded to the HDMI display block). The pragmatic fix used here
is to disable the whole display + HDMI + HDMI-audio subtree
(sunxi-drm, de@5000000, all tcon*, hdmi0, hdmi_codec, edp,
panels) in the USB copy of the DTB only — the board's /boot DTB is
untouched, so normal BSP boots keep their panel. The EDK2-booted system
is therefore headless (UART + ssh). A proper GOP→efifb/simplefb
hand-off for an on-panel console is future polish.
BROM → BOOT0 → TF-A BL31 (v2.5) → BSP U-Boot 2018.07 → EDK2 BL33 @ 0x41000000 (EL2 AArch64)
│
├─ SEC (ArmVirtPrePiUniCoreRelocatable)
├─ DxeCore
├─ Architectural protocols (GIC, Timer, …)
├─ SunxiSimpleFbGopDxe ── reprograms DE3.0 mixer0,
│ paints opaque black,
│ publishes EFI_GRAPHICS_OUTPUT_PROTOCOL
├─ GraphicsConsoleDxe ── binds GOP, becomes ConOut
├─ SunxiUsbDxe ──── CCU init (AHB/MBUS/per-controller),
│ USB2 PHY bring-up (SIDDQ → tune → reset),
│ registers EHCI0/EHCI1 as NonDiscoverable PCI
├─ EhciDxe + UsbBusDxe + UsbMassStorageDxe + UsbKbDxe
└─ BDS → Boot Manager / UEFI Shell on panel + UART + USB-KB
- SoC: Allwinner A733 (
sun60iw2p1) — 6× Cortex-A55 + 2× Cortex-A76, AArch64 - Memory: 6 GB LPDDR5
- UART0: NS16550, MMIO
0x02500000, register stride 4, 115200 8N1 - GICv3:
- Distributor:
0x03400000, size0x10000 - Redistributor:
0x03460000, size0x4F0F00
- Distributor:
- CCU:
0x02002000(allwinner,sun60iw2-ccu) - SYSCFG:
0x03000000 - DE3.0 (Display Engine v3):
- mixer0 layer-0 control:
0x05101000→0xFF008003(BGRA, alpha 0xFF, enable) - mixer0 layer-0 scanout addr:
0x05101018← write FB physical here - mixer0 DBUFF apply:
0x05100008
- mixer0 layer-0 control:
- Framebuffer: PA
0xFF800000, 1024 × 600, BGRA8888, pitch4096 - USB:
- OTG:
0x04100000 - EHCI0:
0x04101000(shares PHY with OTG) - EHCI1:
0x04200000← working, USB-2 hub + keyboard + mass storage - USB2 awphy:
0x06B00000
- OTG:
- SPI NOR: 16 MB (
/dev/mtdblock0); BSP BOOT0 + TF-A + U-Boot lives here. EDK2 is staged on the SD card at/boot/ORANGEPI4PRO_EFI.uimgand loaded by U-Boot'sboot.scrviabootm(opt-intry_edk2flag). A factory backup is checked in atspi_factory_backup.binso you can always restore the stock chain.
# one-shot build (run from inside the edk2 workspace this overlay sits in)
cd ~/edk2
bash build_edk2.sh
# build + scp the uImage to the board's SD /boot and arm a one-shot EDK2 boot
bash build_edk2.sh --deployOutput: Build/OrangePi4Pro/DEBUG_GCC/FV/ORANGEPI4PRO_EFI_arm32.uimg,
a 4 MiB ARM Linux Kernel uImage with load/entry both at 0x41000000.
--deploy copies it to /boot/ORANGEPI4PRO_EFI.uimg on the SD card and
sets a one-shot /boot/try_edk2 flag (clearing the legacy skip_edk2
hard-override). BSP U-Boot's boot.scr runs EDK2 only when try_edk2 is
present; before launching it the script stamps skip_edk2 via
ext4write, so a hung or menu-parked EDK2 always falls back to BSP Linux
on the next power-cycle (no SD-card surgery needed). This boot.scr
opt-in dance is development scaffolding — it goes away once EDK2 replaces
the BL33 slot and/or boots Debian on its own.
These are the non-obvious issues that had to be solved. Documented here so the next person porting EDK2 to a new Allwinner SoC doesn't have to rediscover them.
Bringing up EHCI on a closed-BSP Allwinner part was the single largest
piece of reverse-engineering in this port. Worked end-to-end by reading
live /dev/mem snapshots from a running BSP Linux kernel and matching
them against the BSP sunxi-hci.c source. Lessons:
-
HCI
+0x824bit 3 is "UTMI clock valid", NOT "device present". It is asserted as soon as the USB2 PHY is fully out of suspend + reset, regardless of whether anything is plugged in. The Linux baseline reads0x08on every controller with no device attached; that's how we knew the PHY bring-up — not the device-detect logic — was wrong. -
PHY bring-up ordering matters and the BSP source order is the only correct order. From
sunxi-hci.c~L1280–L1410 the sequence for each EHCI is:assert PHY reset (clear CCU bit30 of the per-controller PHY clk reg) wait 200 µs clear FORCE_SUSPEND (HCI +0x800 / passby register) clear SIDDQ (HCI +0x810 / phy_ctrl) program passby + phy_tune (+0x800, +0x818) write 0x53 to +0x81C deassert PHY reset (set CCU bit30) wait 1 ms read +0x824 — should be 0x08Earlier builds asserted/deasserted the PHY reset before clearing
SIDDQ. UTMI clock never came up and+0x824stayed0x00. -
CCU init for sun60iw2 USB. Required writes (all in the
0x02002000window):Reg Value Meaning 0x05A4msi_lite2 gate MBUS-like access enable 0x05C00xB10103F8AHB gates incl. USB host 0x05E00xF0050803MBUS gate 0 0x05E40x00000805MBUS gate 1 0x1A00|= BIT3res_dcap (USB resource cap) 0x13000xC0000000usb0 clock (incl. PHY bit30) 0x13040x00110011usb0 gate + reset 0x13080xC0000000usb1 clock 0x130C0x00110011usb1 gate + reset 0x13400x80000000USB ref enable 0x1348|= gateUSB ref gate 0x13500x81000000USB ref divider 0x13540x80000000USB ref source select 0x135C|= BIT16USB host ungate Plus
SYSCFG +0x160 |= BIT10(USB tunnel enable) andOTG +0x420 &= ~BIT0(USBC_SelectPhyToHci— gives the OTG PHY to EHCI0 instead of OTG). -
EFI shell needs an explicit USB-keyboard ConIn entry. Even with
UsbKbDxe+UsbBusDxe+ConPlatformDxe+ConSplitterDxeall built in and bound, no keystrokes reach the shell unlessPlatformBootManagerBeforeConsoleadds a USB-class wildcard device path toConIn:USB_CLASS_DEVICE_PATH UsbClass = { ... .VendorId = 0xFFFF, .ProductId = 0xFFFF, .DeviceClass = 0x03, // HID .DeviceSubClass = 0x01, // boot interface .DeviceProtocol = 0x01 // keyboard }; EfiBootManagerUpdateConsoleVariable (ConIn, &UsbClass, NULL);
ConPlatformDxethen expands this wildcard against everySimpleTextInputExinstanceUsbKbDxepublishes, so any USB keyboard on any port (including behind a hub) becomes a console input device.
-
CpuExceptionHandlerLibduplicate binding —ArmGicDxeinstantiates without reporting an error ifCpuExceptionHandlerLibis bound to theNullinstance. The DSC had twoCpuExceptionHandlerLib|...lines; the second (Null) silently overrode the first because EDK2 DSCLibraryClassesuses last-wins semantics. Fix: bindArmPkg/Library/ArmExceptionLib/ArmExceptionLib.inf. -
GenericWatchdogDxeSError — A733 has no SBSA Generic Watchdog at the architectural MMIO address; touching it raises an SError. Replaced withMdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf(software stub). -
MetronomeASSERT inTimerLibNull.c(49)—BaseTimerLibNullTemplateis a stub that always asserts. BindArmPkg/Library/ArmArchTimerLib/ArmArchTimerLib.inf. -
BdsDxeASSERT inBasePcdLibNull— BDS reads dynamic PCDs at runtime and needs the real PCD protocol. Globally swappingPcdLib → DxePcdLibbreaks the bootstrap because it adds a depex on the PCD protocol to every driver, includingPcdDxeitself. Fix: per-module<LibraryClasses>override onBdsDxeandUiApponly. -
No boot options —
PlatformBootManagerLibwas a stub. Reimplemented to build a serial console device path, push it intoConOut/ConIn/ErrOut, walk allgEfiFirmwareVolume2ProtocolGuidhandles and register the embedded UEFI Shell (7C04A583-9E3E-4f1c-AD65-E05268D0B4D1) asBoot0000.
-
DE3.0 mixer0 was the only path that made pixels appear. TCON, panel timing, backlight, MIPI-DSI PHY were all left exactly as the BSP U-Boot configured them — only the scanout address in the mixer0 layer-0 register was reprogrammed to point at an EDK2-owned framebuffer, then the DBUFF apply bit at
0x05100008was pulsed to commit. That's it. -
Cache writeback is mandatory — DE3.0 fetches scanout from DRAM through the system interconnect, not through the CPU caches. Every software Blt operation calls
WriteBackDataCacheRange()over the touched FB region, otherwise text appears delayed by one cache-line eviction or never at all. -
GOP + GraphicsConsole + ConSplitter wiring —
PlatformBootManagerBeforeConsoledoesLocateHandleBuffer(gEfiGraphicsOutputProtocolGuid)and pushes each GOP device path intoConOutandErrOutviaEfiBootManagerUpdateConsoleVariable. Without this,GraphicsConsoleDxebinds but ConSplitter never routes any text to it and the panel stays black after the EDK2 banner.
-
DEBUG noise — at
PcdDebugPrintErrorLevel=0x804FFFFFthe pool/load spam buries the Shell prompt. Lowered to0x80000000(ERROR only). Note: this also masksDEBUG_INFO, so when debugging your own driver, raise it back temporarily. -
Heredoc +
sshpass + sudo bash -smangles bash escapes. Always write helper scripts to/tmp, scp them, thenssh sudo bash /tmp/script.sh. (Seeresearch/.)
Allwinner A733 is substantially more locked down than typical sun50i parts. As of v0.2 one of the three walls (USB) has been broken through; PCIe and Ethernet remain.
As of v0.2 the EHCI1 side is working. Clean-room implementation of
the sun60iw2 CCU + USB2 PHY bring-up sequence in
SunxiUsbDxe.c.
Hubs, mass-storage devices, and HID boot-protocol keyboards all work on
EHCI1, which on the Orange Pi 4 Pro is wired to the right pair of
USB-A ports (top and bottom). EHCI0 (left bottom USB-A) still needs
an ordering fix — it shares its USB2 PHY with the OTG controller block
and we already do OTG+0x420 &= ~BIT0 (USBC_SelectPhyToHci) but
likely in the wrong order relative to PHY reset. xHCI (left top USB-A,
USB 3.0) needs the Cadence Combo PHY serdes block at 0x06C00000
0x06C06000plus the DWC3 stack — not started. The board’s USB-C is power-only, so there is no OTG/device-mode work to do.
We also saved a complete CCU + USB PHY + USB controller register snapshot captured from a running BSP Linux kernel (USB working) so a future contributor can do register-state replay without rediscovery:
research/sun60iw2-ccu-phy-usb-snapshot.txtresearch/sun60iw2-devicetree-raw.txtresearch/sun60iw2-iomem.txtresearch/dump_regs.sh— the/dev/memcapture script
- The PCIe controller is DesignWare. The DBI register window at
0x06000000reads back as all0xFFfrom a running BSP kernel — meaning DBI access is gated by an Allwinner-specific unlock register (likely in CCU or a SYS_CTRL block). Without it, no driver can program the iATU or read root-port config space. - The NVMe BAR0 at
0x22100000does respond (0x0a013FFF= valid NVMeCAP), so the link IS up and BSP U-Boot already enumerated and assigned BARs. We just can't enumerate again from EDK2 becausePciHostBridgeDxeneeds config-space cycles and config space is locked. - Snapshot:
research/sun60iw2-pcie-dbi-snapshot.txt
- Same shape as USB pre-v0.2: BSP-only CCU clock IDs, BSP-only PHY init.
Now that the CCU + PHY pattern is broken (see
SunxiUsbDxe.c), this is the obvious next target.
Sources used as hardware-behaviour specifications for clean-room reimplementation in EDK2 (we read them, did not copy them — code in this repo is fresh BSD-2-Clause-Patent, written in EDK2 style):
- orangepi-xunlong/orange-pi-5.15-sun60iw2
(BSP kernel, GPL-2.0) —
bsp/drivers/clk/sunxi-ng/ccu-sun60iw2.[ch],bsp/drivers/usb/host/sunxi-hci.c(USB PHY ordering — primary source for the v0.2 EHCI bring-up),bsp/drivers/usb/phy/sunxi-awphy-plat.c,bsp/drivers/pcie/pcie-sunxi-rc.c,bsp/drivers/power/supply/axp515_*,bsp/drivers/power/mfd/axp* - orangepi-xunlong/orangepi-build
(
external/config/sources/families/sun60iw2.conf,external/packages/pack-uboot/sun60iw2/bin/dts/u-boot-current.dts) - YuzukiHD/SyterKit
(bare-metal SPL framework, GPL-2.0+) — Radxa Cubie A7A board port
(
board/radxa-cubie-a7a/),include/drivers/chips/sun60iw2/(CCU + NCAT register definitions extracted from BSP U-Boot),src/drivers/chips/sun60iw2/sys-clk.c
Live register snapshots from a running BSP Linux kernel are in
research/ so contributors can verify expected end-state
values without needing the board.
edk2-a733/
├── Platform/OrangePi/OrangePi4ProPkg/
│ ├── OrangePi4Pro.dsc # platform DSC
│ ├── OrangePi4Pro.fdf # FV/FD layout, embedded Shell
│ ├── OrangePi4ProPkg.dec
│ ├── Drivers/
│ │ ├── SunxiSimpleFbGopDxe/ # DE3.0 mixer0 scanout takeover + GOP
│ │ ├── SunxiUsbDxe/ # CCU + USB2 PHY bring-up + EHCI/xHCI registration ✅
│ │ ├── SunxiNonDiscoverablePciDeviceDxe/ # PciIo for NonDiscoverable MMIO devices (identity DMA — see v0.3 fix #1)
│ │ ├── SunxiPcieDxe/ # DesignWare PCIe RC (disabled in FDF — DBI hang, see v0.3 fix #3)
│ │ └── SunxiSmbiosDxe/ # A733 SMBIOS record publisher
│ ├── Library/
│ │ └── PlatformBootManagerLib/ # console DP + GOP wiring + USB-KB ConIn + Shell boot option + EndOfDxe signal
│ ├── Include/
│ └── AArch32Stub/ # legacy 32-bit jump stub (unused)
├── research/ # live BSP register captures + scripts
├── patches/
├── build_edk2.sh
├── spi_factory_backup.bin # 16 MB SPI dump for restore
└── README.md
The actual EDK2 tree (MdePkg, MdeModulePkg, ArmPkg,
ArmPlatformPkg, ShellPkg, etc.) is the upstream master branch
grafted at b03a21a; this repo only contains the platform overlay.
- DTB hand-off to a Linux kernel — done in v0.3 via GRUB's
devicetree+linuxon a USB stick (EDK2 → GRUB → EFI-stub kernel → Debian) - Native EDK2 DTB→kernel hand-off — install the FDT config table
+
LoadImage/StartImagethe kernel from EDK2 directly, retiring GRUB and the U-Bootboot.scropt-in flag (the real finish line) - Display hand-off — GOP →
efifb/simplefbso the panel shows the kernel console instead of disabling the DE/DRM in the DTB - Re-enable
SunxiPcieDxe/ DesignWare PCIe + NVMe — find the DBI unlock @0x06000000; BSP Linux enumerates the NVMe, so the init sequence is replicable rather than blind - Fix EHCI0 (left-bottom USB-A) — share-PHY-with-OTG ordering
quirk;
OTG+0x420 &= ~BIT0already done but probably needs to happen before the PHY reset assert/deassert - xHCI (left-top USB-A, USB 3.0) — Cadence Combo PHY at
0x06C00000/0x06C06000+ DWC3 controller stack - Ethernet — apply the same CCU + PHY pattern from
SunxiUsbDxe - Real
Variableruntime services backed by SPI NOR - Replace BSP
BL33slot in SPI with EDK2 directly (eliminates U-Boot from the chain) - ACPI table generator for the A733 (so generic distros boot)
- Authored entirely by Claude (Anthropic). All code, all debugging,
all serial-log archaeology, all DSC/FDF surgery, all register
reverse-engineering against running silicon. Opus 4.7 took it from
bring-up to the Shell + USB era (v0.1–v0.2); Opus 4.8 carried it to
the v0.3 Debian-boot milestone (USB DMA fix, the
EndOfDxeimage-load fix, the EFI-stub kernel rebuild, and the EDK2 → GRUB → kernel → Debian bring-up). - Human supervision only. Plugging in the SD card, pulling it out, pressing reset, reading back terminal output, swapping USB devices, and choosing which walls to bang our head against next.
- TianoCore EDK2 community for the upstream tree.
- Allwinner / Orange Pi for the BSP boot chain we currently chainload from and the BSP kernel sources we used as a hardware-behaviour spec.
BSD-2-Clause-Patent (matches upstream EDK2).