Technical Reference
Internals, build pipeline, and known pitfalls
Build Pipeline
build-all.sh runs six stages sequentially inside an aarch64 chroot:
build-kernel.sh 6.6.89 + DTS + modules
build-rootfs.sh Arch Linux ARM base + packages
build-mesa.sh Mesa 26 Panfrost
build-emulationstation.sh ES-fcamod + 21 patches
build-retroarch.sh RetroArch 1.22.2 + cores
build-image.sh SD card image (original | clone)Cross-compilation with host GCC 13.3 produces binaries that SIGSEGV on Cortex-A35 (pass in QEMU). Use native chroot only.
Kernel DTS
Source: rk3326-gameconsole-r36s.dts, base rk3326-odroid-go.dtsi.
| Node | Driver | Config |
|---|---|---|
| joypad | adc-joystick + gpio-mux | 4 axes, mainline |
| display | simple-panel-dsi | init-sequence per panel DTBO |
| pmic | rk817 system-power-controller | no pinctrl |
| codec | rk817-codec | use-ext-amplifier |
| usb | u2phy_otg | vcc_host GPIO0_PB7 |
| cpu | cortex-a35 | 1512 MHz, avs=1 |
| gpu | mali-g31 | 600 MHz, 0 overvolt |
| dram | ddr3l | 786 MHz |
Clone diff: volume via adc-keys SARADC ch2 (resistor ladder), not gpio-keys-vol GPIO2 PA0/PA1.
Mesa 26
-Dgallium-drivers=panfrost -Dvulkan-drivers=
-Dgles1=enabled -Dgles2=enabled
-Dglvnd=false -Dplatforms=''
-Dglx=disabled-Dgles1=enabled required for ES. -Dglvnd=false bypasses GLVND dispatch, installs .so directly.
EmulationStation Patches
21 patches on christianhaitian/EmulationStation-fcamod branch 351v:
| Category | Count | Key changes |
|---|---|---|
| Rendering | 5 | GLES profile for KMSDRM, glGetString null safety |
| Performance | 7 | popen() removal (57 to 78 fps), theme cache, NanoSVG static rasterizer |
| Stability | 2 | getShOutput null check, language change restart |
| Boot speed | 3 | MameNames lazy init, dead code removal |
Audio
RK817 BSP codec. ALSA controls: Playback Path (SPK/HP enum), DAC (0-255, 98% max).
Hotkey daemon: archr-hotkeys.py (evdev). VOL buttons adjust DAC 2%/step. MODE+VOL adjusts backlight 3%/step. HP jack triggers path switch. State persists in ~/.config/archr/.
U-Boot
| Original | Clone | |
|---|---|---|
| Source | bootloader/u-boot-rk3326/ | bootloader/u-boot-mainline/ |
| Version | BSP Rockchip | Mainline v2025.10 + ROCKNIX patches |
| Build | ./make.sh odroidgoa | ./build-uboot-clone.sh |
| Boot config | boot.ini | boot.scr (mkimage -T script) |
| Display | hwrev SARADC ch0 + DTB + DRM + logo.bmp | None |
| Defconfig | odroidgoa | rk3326-handheld_defconfig |
BSP source cannot boot clones even with identical compiler. Missing unpublished display patches.
Boot Splash
Initramfs /init binary, static aarch64, BMP data embedded via xxd -i. Appears at kernel +0.694s.
splash.bmp ImageMagick + Quantico font
splash_data.h xxd -i splash.bmp
archr-init.c compiled static, -I$TMPDIR
initramfs.img cpio + gzip, ~292 KBNo stdio.h in PID 1: fopen/opendir in static glibc crash silently. PID 1 crash = kernel panic with no output.
Pitfalls
These are non-obvious failure modes encountered during development.
pacman -S mesa destroys Panfrost. Overwrites GBM files from custom build. All Mesa .so must come from the same build. Recovery: restore-mesa26-gbm.sh.
U-Boot binary patching breaks boot. Rockchip SPL verifies CRC. Raw byte patches (e.g., bootdelay) cause rejection. Recompile or use serial saveenv.
init_kernel_dtb() halts forever. BSP U-Boot: if fatload + SPI + resource all fail to load DTB, board enters LED blink loop. Display DTB must exist on BOOT partition.
dd if=/dev/zero of=/dev/fb0 in ES wrapper. Blanked framebuffer on every boot. Four failed splash attempts before finding this one line.
PMIC pinctrl = kernel panic. rockchip,system-power-controller must not have pinctrl entries.
popen() costs 2-5 ms per call on ARM. ES was calling it 25x/sec for brightness. Direct sysfs read: 57 to 78 fps.
adc-keys uses closest-match, not threshold. Driver picks button with minimum voltage diff. Set values near measured, keyup-threshold to VREF (1.8V).