Clockwork uConsole · Volume 4

Boot, Firmware, SD, and eMMC

Multi-stage boot chains for Pi and Rockchip; EEPROM and U-Boot config; SD/eMMC/USB/NVMe/PXE; recovery and unbricking

Contents

SectionTopic
1About this Volume
2The Boot Problem
· 2.1Why staged loaders exist
· 2.2Pi vs Rockchip — same problem, different culture
· 2.3What “boot” means on the uConsole
3The Pi Boot Chain (CM4)
· 3.1Stage 0 — Boot ROM in the BCM2711
· 3.2Stage 1 — the SPI EEPROM
· 3.3Stage 2 — bootcode.bin
· 3.4Stage 3 — start4.elf (the GPU firmware)
· 3.5Stage 4 — Linux kernel and init
· 3.6The recovery path — USB MSD via rpiboot
4EEPROM Configuration
· 4.1What’s stored in the CM4 EEPROM
· 4.2rpi-eeprom-config walkthrough
· 4.3The BOOT_ORDER register
· 4.4Updating to the latest EEPROM
· 4.5Locking down EEPROM (write-protect)
5The Pi 5 / CM5 Boot Era
· 5.1What changed in stages 2 and 3
· 5.2NVMe boot, USB-3 MSD boot, network boot
· 5.3The CM5’s RTC story
· 5.4/boot/firmware/config.txt semantics
6The Rockchip Boot Chain (RK3588S2)
· 6.1Stage 0 — BootROM and BOOT_MODE straps
· 6.2Stage 1 — TPL (DRAM init)
· 6.3Stage 2 — SPL (U-Boot SPL)
· 6.4Stage 3 — U-Boot proper
· 6.5Stage 4 — Linux + initramfs
· 6.6fw_setenv — editing U-Boot environment from Linux
7SD Card Boot
· 7.1Partition layout
· 7.2SD card classes and what they mean
· 7.3The 256 GB ceiling and the SDXC spec
· 7.4Multi-OS / multi-boot strategies
· · 7.4.1One-OS-per-card
· · 7.4.2BerryBoot
· · 7.4.3PINN / NOOBS
· · 7.4.4Manual BOOT_ORDER switching
· · 7.4.5GPT + multi-rootfs
· 7.5SD-specific gotchas
8eMMC Boot
· 8.1eMMC partition layout (same scheme, different IO)
· 8.2USB-MSD flash via rpiboot
· 8.3rkdeveloptool flash for Rockchip eMMC
· 8.4Wear-leveling and lifetime
· 8.5Backup and restore
9USB Boot
· 9.1USB-MSD boot from a USB-C SSD
· 9.2The V3.14 USB-2 cap and the V3.14_V5 USB-3 path
· 9.3Choosing a USB enclosure that works for boot
10NVMe Boot Paths
· 10.1CM5 native NVMe (with the V3.14_V5 + AIO V2)
· 10.2CM4 NVMe via Mini PCIe + M.2 adapter
· 10.3NVMe over USB-C (CM4 fallback)
11Network Boot (PXE)
· 11.1dnsmasq + tftp server setup
· 11.2NFS-root configuration
· 11.3The lab use-case
12Recovery and Unbricking
· 12.1Symptom → fix matrix
· 12.2Pi recovery — rpiboot USB MSD
· 12.3Rockchip MaskROM mode
· 12.4Re-flashing a corrupt EEPROM
· 12.5SD-card resurrection
13Common config.txt and cmdline.txt Recipes
· 13.1config.txt — the uConsole essentials
· 13.2cmdline.txt — the kernel command line
· 13.3Common edits and what they do
14Vol 12 Cheatsheet Updates
15Resources
16Footnotes
17Index

1. About this Volume

This volume is what happens between the moment you press the power button and the moment your shell prompt appears. It is the most procedural-feeling volume of the series — there are checklists, command examples, and “if A then B else C” decision trees — but the procedures rest on a foundation of staged-bootloader theory that is worth the patience it takes to unpack.

Volume 3 stubbed out the boot path for each compute module class — Pi CM4, Pi CM5, and Radxa CM5 — and deferred the chain detail to here. This volume picks up that thread. We walk each stage of the Pi BCM27xx boot chain (with explicit attention to what changed between the CM4 era and the CM5 era), then walk the Rockchip RK3588S2 chain from BootROM through U-Boot, and then dig into the storage-attached side of boot — SD, eMMC, USB, NVMe, network. The closing chapters are the recovery / unbricking story (worth knowing before you brick something) and the cheat-sheet of common config.txt edits.

The reader is assumed to have read Volume 3 and is comfortable with terms like “Boot ROM,” “EEPROM,” “kernel image,” “device tree.” If those are new, skim the first chapter of bootlin.com/training/boot-time/ before continuing — it’s free and excellent.

A note on scope: we describe the Linux boot path. We do not describe Windows-on-ARM, Android, ChromeOS, or any other guest OS that could run on these modules. Those exist (the Pi 5 does run a Windows-on-ARM developer build), but they’re not the uConsole’s center of gravity, and adding them would double the volume without doubling the value.

2. The Boot Problem

Before the chains: what is a boot chain, and why are there always so many stages?

2.1 Why staged loaders exist

A modern ARM SoC powers up with no DRAM initialised, no clocks running at speed, no peripheral drivers loaded, and no filesystem — nothing more than a small block of immutable mask-ROM code at a fixed reset vector. That code’s only job is to decide what to load next from a small subset of supported sources (a serial ROM, an SD card’s first sector, a USB host endpoint), and then jump to the loaded image. The image then has to set up enough of the world (DRAM, clocks, the CPU’s cache hierarchy, an IO controller) to load the next stage. That stage does more setup, then loads the next, and so on. Each stage is responsible for making the next stage’s job easier.

The reasons there are typically four to five stages, not one or two:

  • Mask ROM is immutable. It can’t be updated to add new boot sources. It has to remain small (mask ROM is expensive in silicon area) and conservative (it can’t fail on hardware variations).
  • The first writable stage runs from on-die SRAM. SRAM is small (~64 KB to ~1 MB on these SoCs). The image that fits in SRAM has to do just enough to bring up DRAM, then load the next stage from somewhere bigger.
  • Subsequent stages run from DRAM but still without a kernel — these stages do peripheral init, secure-boot verification, sometimes memory-protection setup (TrustZone), and they hand off to a more general-purpose loader.
  • The general-purpose loader (U-Boot, GRUB on x86, the Pi’s start.elf) understands filesystems, displays a menu, lets the user pick what to boot, and parses configuration files.
  • The kernel is what users think of as “Linux.” It still has its own staging — uncompressing itself, mounting initramfs, running early init, then transitioning to the rootfs.

The engineering reason staged-loader complexity has won is that no single binary can be both “small enough to fit in mask ROM” and “smart enough to display a menu and parse a filesystem.” The staging spreads complexity across a chain where each stage operates within a budget the previous stage gave it.

2.2 Pi vs Rockchip — same problem, different culture

The Pi Foundation and Rockchip solve the same boot problem with different cultural priorities. The two are worth contrasting because the differences explain a lot of what feels weird about each.

ConcernPi (Broadcom) approachRockchip approach
GPU vs CPU as boot hostGPU boots first; CPU is started later by the GPU firmware.CPU boots first; the GPU is initialised much later.
First-stage codeClosed-source binary blob (bootcode.bin, start.elf).Open-source U-Boot SPL.
Boot config syntaxINI-style config.txt with Pi-specific keys.U-Boot environment variables (bootcmd, bootargs).
Bootloader update pathrpi-eeprom-update (fully managed).Manual flash with rkdeveloptool or dd.
Boot device orderingBOOT_ORDER register in EEPROM (one nibble per source).U-Boot’s boot_targets list.
DocumentationExcellent on Pi side (CC-BY); mostly Pi-Foundation-curated.Patchy; mix of vendor docs, Armbian wiki, forum threads.
Open-sourcenessMost stages closed; start.elf is a binary blob.Every stage is OSS (TPL/SPL/U-Boot all rebuildable from source).
Recovery modeUSB MSD with rpiboot — Pi appears as a mass-storage device.MaskROM mode with rkdeveloptool — Rockchip appears as a vendor recovery device.
Boot-source flexibilityUp to 8 sources in BOOT_ORDER (SD, USB, network, NVMe, RESTART).Defined per-board in U-Boot device tree; flexible but per-build.

The pithy summary: Pi optimises for “it just works”; Rockchip optimises for “it’s all open source”. Both work. Both have warts. The uConsole’s CM4/CM5 path is on the Pi side; the Radxa CM5 path is on the Rockchip side.

2.3 What “boot” means on the uConsole

Concretely, on a uConsole, “boot” is the sequence:

  1. You press the power button on the back of the case.
  2. The AXP228 PMIC runs its power-on sequence (Vol 2 §3.5) — DCDCs come up, ALDOs come up, PWROK asserts, RUN goes high on the CM connector.
  3. The compute module’s SoC reset releases. The mask ROM starts executing.
  4. The boot chain (Pi or Rockchip) runs through stages 1–4 above.
  5. Linux loads, mounts the rootfs, runs systemd, brings up the framebuffer driver for the JD9365DA-H3 display, brings up the keyboard MCU’s USB endpoint, brings up the audio path.
  6. You see the login prompt or desktop.

A uConsole boot from cold takes about 15–25 seconds depending on module + storage + OS. The visible time (from screen-comes-on to login-prompt) is shorter — most of the boot chain runs while the screen is still dark. We come back to “why is my boot so slow?” optimisation in Volume 11 (Performance).

3. The Pi Boot Chain (CM4)

The Pi CM4 runs the classic BCM27xx boot chain. This chapter walks each stage in detail. The stages and the artifacts each consumes/produces:

   ┌──────────────────┐
   │  Power-on reset  │
   └────────┬─────────┘


 ┌─────────────────────┐    Stage 0
 │  Boot ROM (BCM2711) │   (mask ROM, immutable)
 │  reads SPI EEPROM   │
 └────────┬────────────┘


 ┌─────────────────────┐    Stage 1
 │  EEPROM bootloader  │   (writable; updated via rpi-eeprom-update)
 │  decides boot src   │
 │  enumerates SD/USB/ │
 │  NVMe/network       │
 └────────┬────────────┘
          │ (chosen src)

 ┌─────────────────────┐    Stage 2
 │  bootcode.bin       │   (on /boot/, signed by Pi)
 │  GPU firmware init  │
 └────────┬────────────┘


 ┌─────────────────────┐    Stage 3
 │  start4.elf         │   (the GPU firmware proper)
 │  loads kernel.img,  │
 │  cmdline.txt,       │
 │  config.txt,        │
 │  device tree (.dtb),│
 │  overlays           │
 └────────┬────────────┘
          │ (kernel running)

 ┌─────────────────────┐    Stage 4
 │  Linux kernel boots │
 │  initramfs → init   │
 │  systemd → login    │
 └─────────────────────┘

3.1 Stage 0 — Boot ROM in the BCM2711

The first instructions executed after reset come from a small mask ROM inside the BCM2711.1 This ROM is unmodifiable — it’s wired into the silicon. Its job is small:

  1. Initialise basic clocks and the SPI controller.
  2. Read the first ~4 KB of the SPI EEPROM (CM4 has a 16 Mbit SPI flash on-module dedicated to the EEPROM bootloader).
  3. Verify the EEPROM image’s signature.
  4. Load the rest of the EEPROM bootloader into on-die SRAM.
  5. Jump to the EEPROM bootloader.

If the EEPROM is corrupt or signature-invalid, the Boot ROM falls back to a USB Device Mode — the CM4 enumerates as a USB mass-storage device on its USB-C port, and a host running rpiboot can then push a known-good EEPROM image into the SPI flash. This is the rpiboot recovery path covered in §3.6.

There is an interesting consequence of “Boot ROM lives in the SoC, EEPROM lives on the module”: a CM4’s boot ROM is the same as a Pi 4’s boot ROM, but the EEPROM contents differ between Pi 4 and CM4. The EEPROM image you’d flash to “fix” a brick has to be the CM4 variant.

3.2 Stage 1 — the SPI EEPROM

The EEPROM2 is a Winbond 16 Mbit (2 MB) SPI flash on the CM4 module — separate from the SoC’s mask ROM and separate from the eMMC. It contains:

  • The Stage 1 bootloader binary (signed).
  • The bootloader’s configuration (the famous BOOT_ORDER and friends).
  • A revision/version stamp.
  • Reserved space for future use.

Stage 1’s job is to enumerate the configured boot sources in BOOT_ORDER order, decide which has a valid Stage 2 image (bootcode.bin), and load it. The enumeration is non-trivial — Stage 1 is what brings up the SD controller for SD boot, the USB hub for USB MSD boot, the PCIe controller for NVMe boot (Pi 5 / CM5 only), and the Ethernet PHY for network boot.

The EEPROM bootloader is the most updated piece of firmware in the Pi ecosystem. New EEPROM releases ship every few months, fixing boot-source enumeration bugs, adding new boot sources, adjusting timeouts, and improving SD-card compatibility. rpi-eeprom-update is the management tool — see §4.4.

3.3 Stage 2 — bootcode.bin

This stage is Pi-Foundation-only — closed-source, signed, distributed only via Pi’s package repository. bootcode.bin is loaded from the boot partition (FAT32) of whatever boot device Stage 1 picked. Its job:

  • Initialise DRAM (memory training, calibration).
  • Initialise the GPU.
  • Load start4.elf (the GPU firmware proper, Stage 3) from the boot partition.
  • Hand off to start4.elf.

bootcode.bin is small (~50 KB). It exists in this position because start4.elf is too big to fit in SRAM and DRAM has to be brought up before start4.elf can be loaded.

On the CM5 / Pi 5, bootcode.bin is gone — Stage 2’s role is folded into the EEPROM bootloader. See §5.

3.4 Stage 3 — start4.elf (the GPU firmware)

start4.elf is the GPU firmware blob — it runs on the VideoCore VI (CM4) or VII (CM5) GPU, not on the ARM cores. The ARM cores remain in a held state until the GPU brings them up. This is unusual — most ARM systems boot from the CPU side and bring the GPU up later — but it is the Pi family’s distinctive choice and has been since the original Pi.

start4.elf does:

  1. Reads config.txt (we cover this in §13).
  2. Loads the device tree blob (.dtb) corresponding to the detected board.
  3. Applies device-tree overlays as instructed in config.txt.
  4. Reads cmdline.txt for kernel command-line parameters.
  5. Loads the Linux kernel image (kernel.img, or kernel8.img for 64-bit ARM).
  6. Sets up the ARM cores.
  7. Hands the kernel control of the system.

Variants of the GPU firmware include start.elf (legacy 32-bit), start4.elf (64-bit ARMv8), start_x.elf (extended hardware-codec features), and start_cd.elf (cut-down — minimal features for low-memory configs). The CM4 typically uses start4.elf.

Like bootcode.bin, start4.elf is closed-source and signed by Pi. The community has occasionally produced reverse-engineered alternatives (notably librerpi/rpi-open-firmware); none have reached production-quality on the CM4.

3.5 Stage 4 — Linux kernel and init

The kernel takes over from start4.elf. It:

  1. Runs early decompression (the kernel image is gzip- or xz-compressed).
  2. Sets up the per-CPU and per-core state.
  3. Mounts the initramfs (an in-memory rootfs) if configured.
  4. Calls init (typically /sbin/init, which on modern systems is systemd).
  5. systemd runs unit files in dependency order — early boot, mount fstab entries, start network, run user services, light up the display manager or login prompt.

The Pi’s kernel.img/kernel8.img is a Pi-built kernel that includes the Clockwork patches for the JD9365DA-H3 display and the GD32 keyboard MCU. The community Bookworm/Trixie images (Vol 5) bundle their own kernel image with the same patches applied to a more modern kernel base.

3.6 The recovery path — USB MSD via rpiboot

When the EEPROM is corrupt, when the eMMC is empty, or when you simply want to flash an image to eMMC without removing the module, you boot the CM4 into USB Device Mode and connect a host running rpiboot.3 The procedure:

  1. On the host (Linux/macOS): git clone https://github.com/raspberrypi/usbboot && cd usbboot && make && sudo ./rpiboot. Leave it running; it waits for a USB device.
  2. On the uConsole: Power off. Hold the nRPIBOOT GPIO low (jumper or short to GND) — on the CM4 carrier this is a labelled jumper on the V3.14 mainboard.
  3. Connect the uConsole’s USB-C port to the host. Apply power to the uConsole.
  4. The CM4 enumerates as a USB mass-storage device. The host’s rpiboot recognises it and presents the eMMC as /dev/sdX.
  5. Flash the image: sudo dd if=raspios.img of=/dev/sdX bs=4M status=progress conv=fsync. Or use rpi-imager (the official GUI flasher).
  6. Disconnect, remove the nRPIBOOT jumper, reboot. The CM4 now boots from the freshly-flashed eMMC.

This is the standard way to get a fresh image onto an eMMC CM4. There is no SD card slot path for eMMC modules — you need rpiboot (or you swap to a Lite + uSD module).

4. EEPROM Configuration

The EEPROM is the single most important piece of firmware on a CM4. This chapter is a hands-on reference for inspecting, editing, and updating it.

4.1 What’s stored in the CM4 EEPROM

A current Pi-EEPROM image (firmware ≥ 2024) contains, roughly:

RegionSizePurpose
Bootloader binary~256 KBThe Stage 1 code (signed by Pi)
Configuration data~16 KBINI-style key/value pairs (BOOT_ORDER, WAKE_ON_GPIO, etc.)
Public key~1 KBSignature verification key for bootcode.bin and start4.elf
Reserved / futurerest of 2 MBUnused

The configuration is what most users care about. It is editable by a tool (rpi-eeprom-config) without re-flashing the entire image — the tool patches just the configuration region and re-signs.

4.2 rpi-eeprom-config walkthrough

rpi-eeprom-config is shipped on every Pi OS / Bookworm / Trixie image. From a running uConsole (with sudo):

# View the current EEPROM config:
sudo rpi-eeprom-config

# Edit interactively in $EDITOR:
sudo rpi-eeprom-config --edit

# Apply a config from a file:
sudo rpi-eeprom-config --apply /path/to/boot.conf

--edit opens the config in your editor; on save, rpi-eeprom-config validates, writes a new EEPROM image to /var/lib/rpi-eeprom/firmware-default-pieeprom-2024-XX-XX.bin, and queues it for application on next reboot. The actual EEPROM flash happens in early boot before the kernel starts — there’s no live re-flash.

A typical CM4 config looks like:

[all]
BOOT_UART=0
WAKE_ON_GPIO=1
POWER_OFF_ON_HALT=1
BOOT_ORDER=0xf41
PSU_MAX_CURRENT=5000

We covered POWER_OFF_ON_HALT=1 in Volume 2 §14 (the PMIC-latch quirk fix). The other keys:

KeyPurpose
BOOT_UART1 = enable verbose boot messages on the UART (good for debugging hangs).
WAKE_ON_GPIO1 = wake from halt on GPIO toggle. Default for the uConsole power btn.
POWER_OFF_ON_HALT1 = on halt, drop power-rail (the AXP228 latch fix from Vol 2 §14).
BOOT_ORDERThe boot-source priority — see §4.3.
PSU_MAX_CURRENTTells firmware the max current supply can deliver (used for thermal mgmt).

4.3 The BOOT_ORDER register

BOOT_ORDER is a hex value where each nibble (4 bits) is a boot source. The bootloader reads nibbles right-to-left (least-significant first) and tries them in that order. A 0xf nibble means “restart this list” (loop forever).

Nibble values:

NibbleSourceMeaning
0x0(stop)Stop trying — drop into recovery.
0x1SD cardTry the SD card slot.
0x2Network bootTFTP/PXE.
0x3RPIBOOTUSB-MSD recovery mode (forces the device to wait for rpiboot).
0x4USB mass storageTry connected USB MSD devices.
0x5BCM-USB-MSDInternal USB-MSD enumeration (advanced — Pi 5 only).
0x6NVMeNVMe over PCIe (Pi 5 / CM5 only).
0xeStop and timeoutStop trying after a timeout. Useful for eventually entering recovery.
0xfRestartRepeat the list.

The default BOOT_ORDER=0xf41 reads as: Try SD (1), then USB (4), then RESTART (f) — i.e., loop forever between SD and USB. This is sensible defaults for most users.

Common variants for the uConsole:

LoadoutBOOT_ORDERReads as
Default (SD-first, fall back to USB, loop)0xf41SD → USB → restart
eMMC-first (CM4 with eMMC)0xf41(eMMC enumerates as SD-class to the loader)
USB-first (boot from external USB-C SSD)0xf14USB → SD → restart
Network-first (lab provisioning)0xf241Network → SD → USB → restart
NVMe-first (CM5 with NVMe via adapter)0xf416NVMe → USB → SD → restart
Force-recovery (always wait for rpiboot)0xf3RPIBOOT only — useful for “this CM4 is borked, factory reset it”

4.4 Updating to the latest EEPROM

EEPROM updates are routine and important. The Pi packages tracker shipd a new EEPROM every 1–3 months, fixing boot bugs and adding sources.

Inspect the current version:

$ vcgencmd bootloader_version
2024-12-15 (15)
copyright (c) 2012 Broadcom
version 2024-12-15
$ rpi-eeprom-update
*** UPDATE AVAILABLE ***
BOOTLOADER: update available
   CURRENT: 2024-12-15
    LATEST: 2025-04-08
   RELEASE: latest
   FIRMWARE: ...

Apply the update:

sudo rpi-eeprom-update -a
sudo reboot

The kernel writes the new EEPROM image during early boot. If something goes wrong (rare — the update has a built-in rollback), the bootloader falls back to the previous version automatically.

For a CM4 with a stale EEPROM (e.g., from a Lite + uSD that hasn’t been online), the manual flash via rpiboot is also an option:

# On the host:
cd ~/usbboot/recovery
git pull
sudo ./rpiboot
# (uConsole booted in nRPIBOOT mode, EEPROM gets re-flashed.)

4.5 Locking down EEPROM (write-protect)

For a deployed uConsole — say a ham-radio appliance left in a remote shack — you can write-protect the EEPROM:

  1. Set EEPROM_WP=1 in the EEPROM config.
  2. Pull the EEPROM_nWP GPIO low (mainboard test pad — see Vol 2 §5.1).

After this, rpi-eeprom-config --apply will refuse to write. To re-enable, raise EEPROM_nWP and clear the config flag.

Most users will never write-protect. The exception is appliance-style deployments where you want to prevent firmware-level tampering.

5. The Pi 5 / CM5 Boot Era

The Pi 5 (and therefore the CM5) brought significant changes to the boot story. Most are improvements; a few are migrations. This chapter is the diff.

5.1 What changed in stages 2 and 3

The Pi 5 and CM5 use the BCM2712. The BCM2712’s boot architecture is consolidated: the GPU does less, and the EEPROM does more.

StageCM4 (BCM2711)CM5 (BCM2712)
Stage 0ARM mask ROM in the SoCSame (different ROM image; same role)
Stage 1 EEPROMStage 1 only — picks boot sourceStages 1+2 — picks source AND inits DRAM
Stage 2bootcode.bin on the boot partitionRemoved. Folded into EEPROM.
Stage 3start4.elf on boot partitionstart.elf (a slimmer GPU firmware)
Stage 4Linux kernelSame

The practical effect is a simpler boot partition: bootcode.bin is no longer needed (its absence on a CM5 image won’t cause failure), and start.elf does less work because DRAM is already initialised. Boot times on the CM5 are typically 1–2 seconds faster than the CM4 for the same OS image, partly from this simplification.

5.2 NVMe boot, USB-3 MSD boot, network boot

The Pi 5 era EEPROM understands new boot sources:

  • NVMe boot0x6 nibble. Requires the device-tree blob to know about the NVMe controller, and the pcie-slot config in config.txt. On a CM5 in the uConsole, this requires the V3.14_V5 mainboard or the HackerGadgets adapter to wire the second PCIe lane to a Mini PCIe → M.2 adapter or to a CM5 NVMe board.
  • USB-3 MSD boot0x4 nibble (same as USB-2, but the bootloader now knows about USB-3). On the V3.14 mainboard, USB is capped at 2.0 even with a CM5 (Vol 7 §7.4.3); the V3.14_V5 + adapter unlocks USB-3.
  • Network boot improvements — faster TFTP, TLS-secured network boot for managed deployments (less relevant for the uConsole).

5.3 The CM5’s RTC story

The Pi 5 ships with a tiny coin-cell RTC backup on the carrier (not the module) — the Pi 5 Model B has a CR2032 socket. The CM5 does not have an on-module RTC. If you want time-keeping across power-off, you need an external RTC.

For the uConsole, the options are:

  • The HackerGadgets AIO V2 — has a PCF85063A + CR1220 RTC integrated (Vol 7 §7.4.3). Linux exposes it as /dev/rtc1.
  • A DS3231 or DS1307 RTC module on the I²C bus of the 40-pin header (DIY).
  • NTP at boot — if you have network connectivity at boot, set the time via chronyd or systemd-timesyncd. The default for most desktop loadouts.

If your loadout records timestamped data offline (RF captures with sample-time, packet-capture files, log files for forensics), invest in a hardware RTC. Otherwise NTP is fine.

5.4 /boot/firmware/config.txt semantics

A subtle change between CM4 and CM5: the path of the boot partition mount point. Before the Pi 5 era:

  • CM4 / Pi 4 / Pi 3: boot partition mounted at /boot/.

From the Pi 5 era onward:

  • CM5 / Pi 5 (Bookworm and later): boot partition mounted at /boot/firmware/.

If you’re following an old tutorial that says “edit /boot/config.txt”, on a CM5 / Bookworm-era image it’s /boot/firmware/config.txt. The legacy path may still resolve via a symlink on some images, but the canonical location is /boot/firmware/. We use the modern path in §13.

6. The Rockchip Boot Chain (RK3588S2)

If you’ve installed a Radxa CM5 in your uConsole (Volume 3 §5), this is your boot chain. It’s structurally similar to the Pi chain — staged loaders, each progressively smarter — but every stage is open-source U-Boot or U-Boot-derived code, and the toolchain is rkdeveloptool not rpiboot.

6.1 Stage 0 — BootROM and BOOT_MODE straps

The RK3588S2 has its own immutable mask ROM. It’s separate from the Pi’s, of course — different SoC, different ROM. The Rockchip BootROM4 does:

  1. Reads the BOOT_MODE strap pins to decide which storage to boot from. (On the Radxa CM5, these are tied to the carrier — for the uConsole, they’re on the mainboard’s CM connector and are pulled to favour eMMC if present, otherwise SD.)
  2. Reads the TPL (Tertiary Program Loader) image from the chosen boot device.
  3. Verifies the TPL signature against the OTP-stored public key.
  4. Loads TPL into the SoC’s on-die SRAM.
  5. Jumps to TPL.

If TPL fails or signature-invalid, the BootROM enters MaskROM mode — it enumerates as a USB device (vendor ID 0x2207, product depending on chip), and a host running rkdeveloptool can push a known-good image. This is the Rockchip equivalent of rpiboot (§12.3).

6.2 Stage 1 — TPL (DRAM init)

The TPL5 is a small (~16-32 KB) U-Boot derivative whose only job is to bring up DRAM. The DDR controller on the RK3588S2 needs careful sequenced initialisation, including memory training (calibration of timing margins). TPL does this:

  1. Configures the LPDDR4X PHY.
  2. Runs memory training (varies by speed bin and DRAM module).
  3. Tests the resulting margins.
  4. Transitions execution from SRAM to DRAM.
  5. Loads SPL into DRAM and jumps to it.

TPL is fully open source — every Rockchip module’s TPL is in the U-Boot tree. You can rebuild it with custom DRAM timings if you’re doing exotic things (LPDDR5 overclocking, low-power SDP). Most users never touch it.

6.3 Stage 2 — SPL (U-Boot SPL)

SPL (Secondary Program Loader) is U-Boot’s “small” build configuration. It runs from DRAM, has access to the storage controllers, and its job is to:

  1. Initialise basic peripherals (UART for console, the SD/eMMC controller for storage access).
  2. Read U-Boot proper from the SPL boot partition.
  3. Verify and load U-Boot.
  4. Jump to U-Boot.

SPL also handles the TrustZone setup if secure boot is enabled — establishing the secure world, installing TEE (Trusted Execution Environment, typically OP-TEE), then handing off to U-Boot in non-secure world.

6.4 Stage 3 — U-Boot proper

U-Boot proper6 is a much larger binary (~1-4 MB) with full filesystem support, a command-line interface, an environment editor, network stack, USB host stack, and the ability to:

  • Interactively select boot images via menu.
  • Edit boot variables (bootcmd, bootargs).
  • Probe storage devices and present their filesystems.
  • Boot Linux from any of: eMMC, SD, USB, NVMe, network (TFTP/NFS).
  • Apply device-tree overlays similar to Pi’s config.txt but in U-Boot syntax.

The default behaviour on a Radxa CM5 image is fully automatic — U-Boot reads its environment, runs bootcmd, which loads and boots Linux. To intervene, you connect a UART (Vol 11 covers this) and press a key during U-Boot countdown — you get the U-Boot CLI.

6.5 Stage 4 — Linux + initramfs

Same as the Pi side — kernel decompresses, initramfs runs, init (systemd) starts. The difference is the kernel’s device tree: the Rockchip kernel uses rk3588s2-uconsole.dtb (community-built), which describes the JD9365DA-H3 panel, the Mini PCIe slot, the audio path, the keyboard hub, etc. Volume 6 covers the device tree in detail.

6.6 fw_setenv — editing U-Boot environment from Linux

U-Boot’s environment is the equivalent of Pi’s EEPROM config. It lives in a dedicated flash region (defined in U-Boot’s build config — usually a partition called u-boot-env or uboot-env). Linux can read and write it via fw_setenv / fw_printenv:7

# View current environment:
sudo fw_printenv

# View one key:
sudo fw_printenv bootcmd

# Set a key:
sudo fw_setenv bootargs 'root=/dev/mmcblk1p2 rootwait'

# Remove a key:
sudo fw_setenv bootargs

The tool needs a config file at /etc/fw_env.config that tells it where the U-Boot env partition lives. A typical config:

# Device     Offset       Env. size
/dev/mtd0    0x0000       0x10000

Or for an env partition on the eMMC:

/dev/mmcblk0   0x3F8000    0x8000

Check your image’s config file before editing — getting this wrong wedges U-Boot.

Common edits for the uConsole:

VariableTypical valueWhat it does
bootcmdrun distro_bootcmdCalls the distro-defined boot script
bootargsconsole=ttyS2,1500000 root=/dev/mmcblk1p2 rw rootwaitKernel command line
boot_targetsmmc0 mmc1 nvme0 usb0 pxe dhcpOrder of boot sources
fdtfilerockchip/rk3588s2-uconsole.dtbWhich device tree to load
kernel_addr_r0x00280000DRAM address to load kernel into

7. SD Card Boot

Most uConsoles boot from SD. This chapter is the SD boot reference.

7.1 Partition layout

A standard Pi-OS / Bookworm SD layout is two partitions:

PartitionSizeFilesystemMount pointContents
mmcblk0p1256-512 MBFAT32/boot (legacy) or /boot/firmware (Pi 5 era)bootcode.bin, start4.elf, kernel*.img, config.txt, cmdline.txt, *.dtb, overlays/
mmcblk0p2restext4/Linux rootfs

The Rockchip layout for a Radxa CM5 image is more partitioned — typically 6-8 partitions for boot loaders, U-Boot env, kernel, dtb, rootfs, and recovery — but the Linux-visible layout when running is similar (mmcblk1p1 / mmcblk1p2).

7.2 SD card classes and what they mean

Modern SD cards advertise their performance with two speed-class systems that overlap confusingly:

Class labelMin sustained sequentialMin random 4K readUse case for the uConsole
Class 1010 MB/s sequential(not specified)Legacy; barely adequate
UHS-I10 MB/s(not specified)Mainstream
U110 MB/s(not specified)Marketing duplicate of UHS-I
U330 MB/s(not specified)Video-friendly
A110 MB/s1500 IOPS (~6 MB/s)“Apps” — usable for OS boot
A210 MB/s4000 IOPS (~16 MB/s)“Apps” tier — recommended for OS
V3030 MB/s(video bias)Video; fine for OS
V60 / V9060 / 90 MB/s(video bias)Video; overkill for OS

For the uConsole, A2 is the right choice. A1 is acceptable for one-shot loadouts; A2 makes the day-to-day experience meaningfully better because random 4K reads dominate package management, browser caches, and database queries.

Recommended specific cards (all available 2026):

  • Samsung Pro Plus (UHS-I, U3, A2) — well-priced, reliable.
  • SanDisk Extreme Pro (UHS-I, U3, A2) — the standard.
  • Kingston Canvas Go! Plus (UHS-I, U3, A2) — solid budget option.
  • Lexar Professional 1066x — fast, slightly pricier.

Avoid: anything marketed as “Class 10” only without an A1/A2 rating; un-branded cards from marketplaces (counterfeits are rampant); cards labelled “for camera” only — they may be V30 but A0 (no random-IO spec).

7.3 The 256 GB ceiling and the SDXC spec

There is a well-circulated community report that 256 GB is the maximum SD size the uConsole boots from.8 This deserves unpacking.

The SDXC standard supports cards up to 2 TB, and a current (2025+) Pi EEPROM bootloader can boot from any SDXC card the bootloader’s ROM understands. In practice:

  • Cards ≤ 256 GB: nearly always work.
  • Cards 256 GB to 1 TB: mostly work with a current EEPROM; older EEPROM versions may fail to enumerate.
  • Cards > 1 TB: often work but with caveats around format (must be FAT32 boot partition, which has a 32 GB max — needs special re-formatting tools); slow boot.

If your card “isn’t detected” by the bootloader, the most common fix is update the EEPROM (§4.4). The next most common fix is re-format the boot partition as FAT32 — Windows refuses to format >32 GB as FAT32 by default; use mkfs.vfat -F 32 from Linux/macOS or Rufus on Windows.

For the cheatsheet (Vol 12 §15): “SD card not detected” → “Update EEPROM, then verify boot partition is FAT32.”

7.4 Multi-OS / multi-boot strategies

Several approaches:

7.4.1 One-OS-per-card

The simplest. Buy 4-8 microSD cards, label each with the OS+loadout (Pi OS, Kali, Parrot, BlackArch, RetroPie, DragonOS), and swap as needed. The uConsole’s SD slot is accessible without case-opening.

7.4.2 BerryBoot

BerryBoot is a multi-boot manager for Pi systems. It puts a small bootloader on the boot partition, then a list of OS images on the rest of the card. At boot it presents a menu and chains into the chosen OS. Supports Pi OS, Ubuntu, RetroPie, OctoPi, and others. Useful if you want one card with several OSes.

Limits: not aware of CM5; some images don’t work cleanly. Maintained but not as actively as the OSes themselves.

7.4.3 PINN / NOOBS

The original Pi multi-installer. PINN (PINN Is Not NOOBS) is the maintained fork. Same idea as BerryBoot — single card, multiple OSes. Slightly more polished UI; same caveats.

7.4.4 Manual BOOT_ORDER switching

For two-OS setups: install one OS to eMMC and one to SD. Set BOOT_ORDER=0xf41 to prefer SD. Pop the SD in for “Loadout B,” remove for “Loadout A.”

7.4.5 GPT + multi-rootfs

Advanced. One large card with a single boot partition and multiple rootfs partitions. The boot kernel-cmdline picks the rootfs. Switch via cmdline.txt edits or via a tiny menu kernel. Used by some custom distros (Buildroot’s genimage, some Yocto recipes).

7.5 SD-specific gotchas

Some classics:

  • Counterfeit cards. A “1 TB” card from a marketplace may report 1 TB to the OS but actually only have 32 GB of flash, with the remainder lying. f3probe (Linux/macOS) detects this. Run it on every new card before trusting it.
  • Wear on the boot partition. The boot partition has heavy small-write traffic during normal operation. After a few years, the boot partition can become read-only or corrupted while the rootfs is fine. Keep a spare card.
  • Bus-speed mismatch. A UHS-I card in a UHS-I slot runs at full UHS-I speed; in a non-UHS slot it falls back to legacy speeds (much slower). The uConsole’s SD slot supports UHS-I.
  • Slow boot from a fresh card. First boot includes filesystem expansion (raspi-config does this on first boot), so the very first boot is slower than steady state. This is normal.

8. eMMC Boot

eMMC boots like SD but faster. This chapter is the eMMC reference.

8.1 eMMC partition layout (same scheme, different IO)

eMMC presents itself as /dev/mmcblk0 with the same FAT32 boot + ext4 root layout. The Linux kernel sees no functional difference; the bootloader sees a faster device.

8.2 USB-MSD flash via rpiboot

For Pi CM4 / CM5 with eMMC, rpiboot is the canonical tool for flashing the eMMC from a host. Procedure already covered in §3.6. Expanded version:

# On the host, install Pi image and tooling:
sudo apt install rpiboot rpi-imager  # Debian/Ubuntu
# Or build from source:
git clone https://github.com/raspberrypi/usbboot
cd usbboot
make

# Run rpiboot in a terminal, leave running:
sudo ./rpiboot
# (it now waits for a Pi MSD device.)

On the uConsole:

  1. Power off, batteries out.
  2. Locate the nRPIBOOT jumper on the V3.14 mainboard. It’s a small 2-pin header near the CM connector — the silkscreen is “NRPIBOOT” or “RPIBOOT”. Place a jumper across both pins, or short with a wire.
  3. Connect USB-C to the host.
  4. Apply power (insert batteries OR plug USB-C-to-host AND a charger into a separate USB-C splitter — the uConsole needs power on the charger port plus the data link to the host).
  5. The host’s rpiboot console message: RPi: Started up CM4, then RPi: Got message: GET_STORAGE_INFO. The eMMC enumerates as /dev/sdX on the host.
  6. Use rpi-imager (GUI) or dd (command line) to flash. Verify the device — lsblk to confirm /dev/sdX is the CM4’s eMMC, not your host’s drive.
  7. After flash completes, eject /dev/sdX, disconnect USB-C, remove the nRPIBOOT jumper, re-power.

8.3 rkdeveloptool flash for Rockchip eMMC

For Radxa CM5 + eMMC, the tool is rkdeveloptool:9

# Install dependencies and build:
sudo apt install libudev-dev libusb-1.0-0-dev autoconf automake pkg-config
git clone https://github.com/rockchip-linux/rkdeveloptool
cd rkdeveloptool
autoreconf -i && ./configure && make

# Put the uConsole in MaskROM mode (see §12.3 for trigger details).

# Verify connection:
sudo ./rkdeveloptool ld
# (should list "DevNo=1   Vid=0x2207, Pid=0x350b (or similar)")

# Download the bootloader:
sudo ./rkdeveloptool db rk3588_loader_v1.13.bin   # path to bootloader

# Flash the image:
sudo ./rkdeveloptool wl 0 uconsole-radxa.img

# Reset to boot:
sudo ./rkdeveloptool rd

The bootloader binary (rk3588_loader_v*.bin) needs to be downloaded from Rockchip’s vendor releases or Radxa’s wiki. The image (uconsole-radxa.img) is the same .img file you’d flash to an SD card.

8.4 Wear-leveling and lifetime

eMMC chips have a Flash Translation Layer (FTL) that handles wear-leveling automatically. Modern eMMC 5.1 chips are rated for 3,000-10,000 erase cycles per block with 100-1,000x effective lifetime improvement from wear-leveling. In typical OS use (writing logs, package updates, browser cache), an eMMC 5.1 should last 5-10 years.

What kills eMMC faster:

  • Excessive writes — running a database with no commit_interval tuning, building Docker images repeatedly, running fio benchmarks in a loop.
  • Sustained 100% disk activity — kernel compiles, big rsync jobs.
  • Power-loss during writes — eMMC is not journaled at the FTL level. A power-cut during a metadata write can cause filesystem corruption that wear-levels work around but doesn’t undo.

Mitigations:

  • Mount /var/log as tmpfs if logging is heavy.
  • Use fstrim weekly to maintain FTL performance: sudo systemctl enable --now fstrim.timer.
  • Move heavy-write workloads to an SD or USB SSD, leaving eMMC for the OS.

8.5 Backup and restore

Backing up an eMMC requires either rpiboot mode (so the host sees it as a block device) or a running Linux session (so you can dd the image to an external drive).

From a running uConsole with a USB drive mounted at /mnt/backup:

# Backup (block-level):
sudo dd if=/dev/mmcblk0 of=/mnt/backup/uconsole-emmc.img bs=4M status=progress

# Or compress on the fly:
sudo dd if=/dev/mmcblk0 bs=4M status=progress | xz -T0 > /mnt/backup/uconsole-emmc.img.xz

Restoring requires rpiboot (you can’t dd over the running rootfs):

# Boot uConsole into rpiboot mode (§3.6 step-by-step).
# On host with eMMC enumerated as /dev/sdX:
sudo dd if=/mnt/backup/uconsole-emmc.img of=/dev/sdX bs=4M status=progress conv=fsync

# Or for a compressed backup:
xzcat /mnt/backup/uconsole-emmc.img.xz | sudo dd of=/dev/sdX bs=4M status=progress conv=fsync

For Pi-specific incremental backups, rpi-clone is a friendly wrapper that handles partition resizing, checksum verification, and “boot from backup” testing.

9. USB Boot

USB boot is the path for users who want a single fast SSD as the rootfs. It’s simpler than PXE, faster than SD, and on the V3.14_V5 + CM5 combo, uses USB 3.0 for ~400 MB/s sequential reads.

9.1 USB-MSD boot from a USB-C SSD

Procedure on the Pi CM4/CM5 path:

  1. Prepare the USB SSD. Format with the same FAT32 boot + ext4 root layout as an SD or eMMC.
  2. Flash an OS image to the USB SSD using dd from a host or rpi-imager selecting the USB device.
  3. Update the EEPROM to a version supporting USB boot (any 2024+ EEPROM does).
  4. Set BOOT_ORDER appropriately (e.g., 0xf14 for “USB first, then SD, then loop”).
  5. Plug the USB SSD into the uConsole’s USB-A port (V3.14) or the V3.14_V5’s USB-C port.
  6. Reboot. The bootloader enumerates USB MSDs after SD; if the SSD has a valid boot partition, it boots from there.

9.2 The V3.14 USB-2 cap and the V3.14_V5 USB-3 path

On the V3.14 mainboard, every USB port goes through the GL850G hub which is USB 2.0 only. Even with a CM5 + USB-3-capable SSD, you get USB 2.0 throughput — about 35 MB/s sequential. This is faster than a typical microSD A1 but slower than a microSD A2.

On the V3.14_V5 mainboard with the HackerGadgets adapter and a CM5: one of the CM5’s USB-3 root hubs is exposed on the AIO V2’s USB-C port. That gives USB 3.0 throughput (~400 MB/s), which is much faster than any SD or eMMC option.

For the decision matrix: USB boot only beats SD/eMMC if you have V3.14_V5 + CM5 + a USB-3 SSD. On stock V3.14, USB boot is a convenience (easy hot-swap, large capacity) more than a speed choice.

9.3 Choosing a USB enclosure that works for boot

Not every USB-SSD enclosure boots reliably. Pi has an official compatibility list but it’s incomplete. Rules of thumb:

  • UAS (USB Attached SCSI) support is good for performance but historically buggy with some chipsets. Some chipsets (notably the JMS580) have a UAS-bug that causes the Pi bootloader to hang. The fix is to disable UAS via the usb-storage.quirks= kernel parameter:
    # In cmdline.txt:
    usb-storage.quirks=152d:0578:u
    (Where 152d:0578 is the vendor:product ID of the offending chipset; find via lsusb.)
  • Cheap “USB-3” enclosures sometimes lie about the chipset. Stick to known-good brands: Samsung T7, SanDisk Extreme Portable, Crucial X9.
  • External power: most USB-3 SSDs can run on bus power, but high-load operations (database commits, kernel compiles) draw spikes that can cause brownouts on the Pi’s USB rails. If you see “spurious” filesystem corruption after benchmark runs, try a powered hub or a USB-Y cable for extra power.

10. NVMe Boot Paths

NVMe is the fastest storage option. Here are the three paths on the uConsole, in order from “easiest” to “most exotic.”

10.1 CM5 native NVMe (with the V3.14_V5 + AIO V2)

This is the cleanest path:

  1. CM5 module installed in the uConsole.
  2. V3.14_V5 mainboard.
  3. HackerGadgets AIO V2 expansion card or a Mini PCIe → M.2 NVMe adapter.
  4. NVMe SSD installed on the adapter.
  5. EEPROM updated to support NVMe boot.
  6. BOOT_ORDER=0xf416 (NVMe-first).

Throughput: ~1 GB/s sequential, ~100 MB/s random 4K (limited by Mini PCIe PCIe Gen 3 ×1, not the NVMe device itself).

10.2 CM4 NVMe via Mini PCIe + M.2 adapter

Same physical setup as §10.1 but on a CM4. The CM4 has only PCIe Gen 2 ×1, so:

  • Throughput: ~500 MB/s sequential (Gen 2 bandwidth limit).
  • The CM4 EEPROM doesn’t natively support NVMe boot — you boot from SD/eMMC into a kernel with NVMe drivers, then pivot-root to the NVMe.

Because of the pivot-root requirement, this is more advanced. The Pi forum has working configs for this; search “CM4 NVMe boot pivot root.”

10.3 NVMe over USB-C (CM4 fallback)

Cheap and cheerful: USB-C-to-NVMe enclosures exist for $25-50, and the CM4 boots from USB-MSD natively. Throughput is capped at USB 2.0 (~35 MB/s on V3.14) or USB 3.0 (~400 MB/s on V3.14_V5). Less than full Mini-PCIe NVMe bandwidth, but a one-line setup with no PCIe-bridge complications.

11. Network Boot (PXE)

For a managed lab (multiple uConsoles to provision identically), network boot is much faster to deploy than flashing each card individually.

11.1 dnsmasq + tftp server setup

A simple dual-purpose dnsmasq setup serves both DHCP (with PXE options) and TFTP:

# On a Linux server in the lab network (192.168.10.0/24):
sudo apt install dnsmasq

# /etc/dnsmasq.conf:
interface=eth0
bind-interfaces

dhcp-range=192.168.10.100,192.168.10.200,24h

enable-tftp
tftp-root=/srv/tftp

# Pi-specific: tell DHCP clients to PXE-boot from this server
dhcp-option-force=66,192.168.10.1
dhcp-boot=bootcode.bin

# Restart:
sudo systemctl restart dnsmasq

Then in /srv/tftp/ put the Pi boot artefacts: bootcode.bin, start4.elf, the kernel, and the cmdline.txt pointing at an NFS rootfs.

11.2 NFS-root configuration

# On the server:
sudo apt install nfs-kernel-server
# /etc/exports:
/srv/nfs/uconsole-rootfs  192.168.10.0/24(rw,sync,no_root_squash,no_subtree_check)

sudo systemctl restart nfs-kernel-server

In the PXE’d /srv/tftp/cmdline.txt:

root=/dev/nfs nfsroot=192.168.10.1:/srv/nfs/uconsole-rootfs,vers=4,proto=tcp ip=dhcp rw rootwait

The uConsole boots, gets DHCP, fetches bootcode.bin over TFTP, fetches kernel via TFTP, kernel mounts NFS-root, runs init, login prompt appears.

11.3 The lab use-case

Why bother? Because:

  • Provisioning is centralised. Update /srv/nfs/uconsole-rootfs once; every PXE-booted uConsole reflects the change.
  • No per-device card management. No microSD cards to lose, no eMMCs to flash.
  • Uniform images for a class / cohort. Useful for teaching environments (a hardware-hacking class, a classroom of uConsoles for student CTFs).
  • Easy rollback. Snapshot the NFS rootfs; restore from snapshot if a class trashes the OS.

For a single-uConsole user, PXE is overkill. For five or more, it’s a productivity win.

12. Recovery and Unbricking

This chapter is the “I broke it” reference. Things to read before you brick something.

12.1 Symptom → fix matrix

SymptomLikely causeFirst-line fix
No power LED, no screenPMIC latch / cells flat / battery connector looseReseat battery board’s mainboard connector firmly. Charge.
Power LED on, screen blackEEPROM corrupt OR display driver not loadedrpiboot recovery (§3.6), then check start4.elf is valid.
Pi splash, then blackKernel panic (corrupt rootfs)Boot from a different SD; mount the failed card; check logs.
”Card not detected” at bootEEPROM doesn’t support card sizeUpdate EEPROM (§4.4). Also verify FAT32 boot partition.
Boots but kernel panic in initCorrupt initramfsRe-flash the boot partition.
Boots but no screenDSI driver missing in kernelVerify config.txt has dtoverlay= for the panel.
Boots but no keyboardUSB hub or GD32 firmware issuelsusb. If GL850G missing — mainboard hardware. If keyboard MCU missing — re-seat.
Boots but no audioALSA card numbering changedamixer. Check /usr/share/alsa/cards/. Reinstall ALSA.
Boots, then drops to emergency shellRootfs unmountableBoot a recovery card; fsck the original rootfs.
vcgencmd reports under-voltage detectedPSU not delivering 5V/3ACharge / use a better USB-C cable.
AIO V2 not detectedGPIO power-gating (the AIO V2 gotcha, Vol 7 §7.4.3)Pull the SDR/LoRa/GPS GPIO high per HackerGadgets setup guide.
Won’t boot at all after EEPROM updateBad EEPROM rollout (rare)rpiboot recovery, flash a known-good EEPROM image.
Radxa CM5 won’t boot (red LED only)Bad TPL or DRAM training failureHold MaskROM trigger, rkdeveloptool flash bootloader (§12.3).

12.2 Pi recovery — rpiboot USB MSD

Already covered in §3.6 / §8.2. Worth stating again: this is the canonical Pi recovery tool. It works as long as the Boot ROM in the BCM2711 / BCM2712 is intact (and that’s mask ROM — virtually impossible to corrupt). It can recover from corrupted EEPROM, corrupted eMMC, corrupted boot partition, even completely empty eMMC (factory-fresh CM4).

The only failure mode where rpiboot can’t save you is physical damage to the SoC or to the SPI EEPROM chip itself. Both are rare; both are not user-serviceable.

12.3 Rockchip MaskROM mode

For a Radxa CM5, the recovery equivalent is MaskROM mode:

  1. Power off the uConsole, batteries out.
  2. Locate the MaskROM trigger. On the Radxa CM5, this is a tiny solder pad labelled MASKROM or RK_MASKROM on the module itself — you short it to a nearby GND pad with tweezers or a piece of wire.
  3. Connect USB-C from the uConsole to a host running rkdeveloptool.
  4. Apply power. The SoC enters MaskROM mode (the BootROM enumerates as a USB device with VID 0x2207).
  5. Release the MASKROM short.
  6. On the host: sudo rkdeveloptool ld should show the device.
  7. From here, flash bootloader / image / rootfs as in §8.3.

This is fiddlier than Pi’s rpiboot because the trigger is a tiny solder pad rather than a labeled jumper. Don’t apply power with the MASKROM pad bridged for more than a few seconds — repeated entry into MaskROM mode is fine, but holding it bridged during normal boot can cause flash corruption.

12.4 Re-flashing a corrupt EEPROM

If the EEPROM update process was interrupted (power loss during rpi-eeprom-update):

  1. Boot into rpiboot mode (§3.6).
  2. On the host: cd ~/usbboot/recovery && sudo ./rpiboot.
  3. The recovery flow flashes a known-good EEPROM image (the latest released Pi EEPROM bundled with the rpiboot source tree).
  4. Reboot. Verify with vcgencmd bootloader_version.

12.5 SD-card resurrection

For a corrupted SD card:

# On a Linux host:
sudo dd if=/dev/sdX of=damaged.img bs=4M status=progress conv=noerror,sync
# (this gets as much data as possible from the card)

# Then either:
# (a) Mount the image read-only and copy data off:
sudo mount -o loop,ro damaged.img /mnt/recovery
# (or use kpartx to enumerate partitions if the card is partitioned)
sudo kpartx -av damaged.img
# (b) Flash the image to a fresh card and boot:
sudo dd if=damaged.img of=/dev/sdY bs=4M status=progress

Use e2fsck for ext4 partitions and fsck.vfat for the FAT32 boot partition. Not every card is recoverable — bad blocks at the wrong locations (boot sector, superblocks) can be terminal. Always have a backup.

13. Common config.txt and cmdline.txt Recipes

The two boot-config files you’ll edit most often. Both live in /boot/firmware/ (Pi 5 / CM5 / Bookworm) or /boot/ (CM4 / older).

13.1 config.txt — the uConsole essentials

A minimal, working config.txt for a Pi CM4 in the uConsole:

[all]
# Disable rainbow splash on boot (optional, faster cosmetic)
disable_splash=1

# JD9365DA-H3 LCD via DSI0 — applied by Clockwork kernel patch
dtoverlay=clockwork-uconsole-lcd

# 720p framebuffer
hdmi_force_hotplug=1
hdmi_group=2
hdmi_mode=87
hdmi_cvt=1280 720 60 6 0 0 0

# Audio over the OCP8178 amps via PWM (Vol 2 §7)
dtparam=audio=on

# Power management
dtoverlay=disable-bt   # disable BT if unused (saves ~150 mW)

# Mini PCIe slot — enable the PCIe controller
dtparam=pciex1

# 64-bit kernel (modern OSes default to this)
arm_64bit=1

For a CM5, change dtoverlay=clockwork-uconsole-lcd to dtoverlay=clockwork-uconsole-lcd-cm5 if the community image differentiates. Many community images auto-detect.

13.2 cmdline.txt — the kernel command line

A minimal, working cmdline.txt:

console=serial0,115200 console=tty1 root=PARTUUID=abc12345-02 rootfstype=ext4 rootwait fsck.repair=yes quiet splash plymouth.ignore-serial-consoles

Key parameters:

  • console=serial0,115200 — kernel messages on UART (debugging).
  • console=tty1 — kernel messages on the LCD (so you see boot).
  • root=PARTUUID=... — which partition is the rootfs (use blkid to find).
  • rootwait — wait for the rootfs device before mounting.
  • fsck.repair=yes — auto-repair on boot.
  • quiet splash — silence verbose boot.

13.3 Common edits and what they do

GoalEdit
Increase max CPU frequencyarm_freq=2000 in config.txt (Pi 5/CM5 only; risk of throttle/instability)
Force 1080p HDMI outputhdmi_mode=82 (1080p60)
Disable WiFi (lower power)dtoverlay=disable-wifi
Disable BT (lower power)dtoverlay=disable-bt
Verbose boot messagesRemove quiet splash from cmdline.txt
Boot into single-user mode (recovery)Add single to cmdline.txt
Boot to specific runlevelsystemd.unit=multi-user.target (no GUI)
Boot from external driveBOOT_ORDER=0xf14 in EEPROM
Disable serial console (free GPIO 14/15)Remove console=serial0,115200 from cmdline.txt; enable_uart=0
Enable I²C on GPIO 2/3 for the AIO V2 GPIO trickdtparam=i2c_arm=on
Read-only root for embedded/kiosk useAdd ro to cmdline.txt; configure overlayfs separately

14. Vol 12 Cheatsheet Updates

The following one-pagers should be added or updated in Vol 12:

  • §3 (Boot recipes): full BOOT_ORDER nibble decode table from §4.3.
  • §15 (Error → fix matrix): the symptom → fix table from §12.1.
  • §17 (config.txt one-liner reference): the table from §13.3.
  • §19 (Recovery commands):
    • sudo rpiboot + nRPIBOOT jumper for Pi recovery.
    • sudo rkdeveloptool ld for Rockchip detection.
    • sudo rpi-eeprom-update -a for EEPROM update.
    • sudo fw_setenv examples.

The cheatsheet entries should be one-page-printable, font-size 9 minimum.

15. Resources

SourceURL
Pi EEPROM bootloader documentationhttps://www.raspberrypi.com/documentation/computers/raspberry-pi.html#raspberry-pi-boot-eeprom
rpi-eeprom releaseshttps://github.com/raspberrypi/rpi-eeprom/releases
rpiboot (USB MSD recovery)https://github.com/raspberrypi/usbboot
rpi-imager (official flasher)https://www.raspberrypi.com/software/
Pi 4 boot flowhttps://www.raspberrypi.com/documentation/computers/raspberry-pi.html#raspberry-pi-boot-eeprom
Pi 5 boot flowhttps://www.raspberrypi.com/documentation/computers/raspberry-pi-5.html
Rockchip BootROM / boot-stage wikihttp://opensource.rock-chips.com/wiki_Boot_option
rkdeveloptool sourcehttps://github.com/rockchip-linux/rkdeveloptool
U-Boot upstreamhttps://github.com/u-boot/u-boot
libubootenv (modern fw_setenv)https://github.com/sbabic/libubootenv
BerryBoot (multi-OS for Pi)https://www.berryterminal.com/doku.php/berryboot
PINN multi-installerhttps://github.com/procount/pinn
f3probe (counterfeit-card detector)https://github.com/AltraMayor/f3
rpi-clonehttps://github.com/billw2/rpi-clone
Bootlin boot-time traininghttps://bootlin.com/training/boot-time/

16. Footnotes

(Footnotes are listed inline above; this section is a placeholder anchor for the index.)

17. Index

A — Active boot source — §4.3.

B — bootcmd (U-Boot) — §6.6. bootcode.bin — §3.3, §5.1. Boot ROM (BCM2711) — §3.1. BootROM (RK3588S2) — §6.1. Boot order — §4.3. Boot UART — §4.2. BOOT_MODE straps — §6.1. BOOT_ORDER register — §4.3. Backup (eMMC) — §8.5. BerryBoot — §7.4.2.

C — cmdline.txt — §13.2. config.txt — §13.1, §13.3. Counterfeit cards — §7.5. Cross-references (Vol 2 §14) — §4.2 (POWER_OFF_ON_HALT). console= — §13.2.

D — dnsmasq — §11.1. Device tree — §3.4, §6.5. dd (block-level backup) — §8.5. DRAM training — §6.2.

E — EEPROM (Pi) — §3.2, §4. eMMC — §8 (full chapter). enable_tftp (dnsmasq) — §11.1. e2fsck — §12.5.

F — f3probe — §7.5. fsck — §12.5. fstrim — §8.4. fw_printenv — §6.6. fw_setenv — §6.6. FAT32 boot partition — §7.1.

G — Geekbench (boot time) — §2.3 (cross-ref). GPU firmware (start4.elf) — §3.4.

H — Hex (BOOT_ORDER nibbles) — §4.3.

I — init (systemd) — §3.5. initramfs — §6.5. I²C (AIO V2 GPIO) — §13.3.

J — JMS580 (UAS quirks) — §9.3. JD9365DA-H3 — §13.1.

K — Kernel — §3.5, §6.5. Kernel command line — §13.2.

L — libubootenv — §6.6. Loadout (PXE) — §11.3. LPDDR4X — §6.2.

M — MaskROM mode (Rockchip) — §6.1, §12.3. Mini PCIe (NVMe boot) — §10.1, §10.2. mkfs.vfat — §7.3. Multi-OS — §7.4.

N — nRPIBOOT jumper — §3.6, §8.2. NFS-root — §11.2. NVMe — §10. Network boot — §11.

O — Open-source (Rockchip stages) — §6. OS choice (per card) — §7.4.

P — Partition layout — §7.1, §8.1. PINN — §7.4.3. PMIC latch (POWER_OFF_ON_HALT) — §4.2 (cross-ref Vol 2 §14). PXE — §11.

Q — Quiet boot (quiet splash) — §13.2.

R — Recovery (Pi rpiboot) — §3.6, §12.2. Recovery (Rockchip MaskROM) — §6.1, §12.3. rkdeveloptool — §6, §8.3, §12.3. rpi-eeprom-config — §4.2. rpi-eeprom-update — §4.4. rpi-clone — §8.5. rpiboot — §3.6, §12.2. Rockchip TPL — §6.2. Rockchip SPL — §6.3. Root NFS — §11.2.

S — SD card — §7. SDXC — §7.3. Single-user mode (recovery boot) — §13.3. Speeds (SD class) — §7.2. SPI EEPROM — §3.2. start4.elf — §3.4. Symptom → fix matrix — §12.1. systemd — §3.5.

T — TPL (Rockchip) — §6.2. tftp — §11.1.

U — UAS quirks — §9.3. U-Boot — §6.4. U-Boot SPL — §6.3. UHS-I (SD) — §7.2. USB-3 boot — §5.2, §9.2. USB-MSD recovery — §3.6. USB boot — §9.

V — vcgencmd bootloader_version — §4.4. V3.14_V5 — §9.2 (cross-ref Vol 2 §17). V3.14 USB-2 cap — §9.2.

W — Wear-leveling — §8.4. WiFi disable — §13.3. Write-protect (EEPROM) — §4.5.

X, Y, Z — None.

Footnotes

  1. The BCM2711 boot ROM is documented at the Pi developer pages: https://www.raspberrypi.com/documentation/computers/raspberry-pi.html#raspberry-pi-boot-eeprom. The ROM is the same across all BCM2711 SKUs (Pi 4 / Pi 400 / CM4).

  2. Pi EEPROM bootloader documentation: https://www.raspberrypi.com/documentation/computers/raspberry-pi.html#raspberry-pi-boot-eeprom. Source code: https://github.com/raspberrypi/rpi-eeprom. Releases page: https://github.com/raspberrypi/rpi-eeprom/releases.

  3. rpiboot source and documentation: https://github.com/raspberrypi/usbboot. rpiboot -d puts the device in boot-from-host mode; rpiboot without -d flashes the connected eMMC.

  4. Rockchip BootROM and boot-flow documentation: http://opensource.rock-chips.com/wiki_Boot_option. Detailed boot-stage explanation: https://opensource.rock-chips.com/wiki_System_Trust_Stack. The Armbian wiki has additional context: https://docs.armbian.com/Hardware_Allwinner_overview/.

  5. U-Boot’s Rockchip TPL/SPL implementation: https://github.com/u-boot/u-boot/tree/master/arch/arm/mach-rockchip. Each Rockchip platform has a TPL config in arch/arm/mach-rockchip/rk3588/.

  6. U-Boot upstream: https://github.com/u-boot/u-boot. Rockchip-specific board configs: https://github.com/u-boot/u-boot/tree/master/configs (search for rk3588).

  7. fw_setenv and fw_printenv are part of libubootenv (modern, clean) or u-boot-tools (older, still common). Documentation: https://github.com/sbabic/libubootenv.

  8. The 256 GB report: Talking Sasquach video at youtu.be/4vNxTOFThdg ~7:00. Cross-checked against the Pi bootloader documentation: https://www.raspberrypi.com/documentation/computers/raspberry-pi.html#raspberry-pi-boot-eeprom. The Pi 4 / CM4 EEPROM versions ≥ 2022-04-26 add support for cards up to the SDXC 2 TB max; older versions cap at 256 GB or 512 GB depending on SDXC controller initialisation. The uConsole-specific report likely reflects the EEPROM version on the affected unit at time of recording.

  9. rkdeveloptool source: https://github.com/rockchip-linux/rkdeveloptool. Build for Linux: sudo apt install libudev-dev libusb-1.0-0-dev pkg-config && git clone … && autoreconf -i && ./configure && make.