BPI-R4 Boot Chain Explained
The BPI-R4 follows the standard MediaTek boot chain. Understanding each stage tells you exactly where a boot failure occurs and what to fix.
- SPI-NAND / eMMC Boot ROM — hardwired in the SoC, loads BL2 from NAND or eMMC
- BL2 (TF-A) — initialises DRAM, loads BL31
- BL31 (ARM Trusted Firmware) — EL3 runtime, loads U-Boot
- U-Boot — reads boot config, loads kernel + DTB from the configured source
- Linux kernel — mounts rootfs from whatever device U-Boot passes via
root=
The boot media (where BL2 lives) and the rootfs (where Linux runs from) don't have to be on the same device. This is the key insight that enables fast NVMe root while keeping the bootloader on reliable NAND.
Why NVMe Root Matters
eMMC and NAND are fine for the bootloader and kernel, but running the full root filesystem on them wastes the BPI-R4's PCIe 3.0 ×2 NVMe slot. Concrete benefits:
| Metric | eMMC Root | NVMe Root |
|---|---|---|
| Sequential read | ~150 MB/s | ~1,500 MB/s |
| Random 4K IOPS (read) | ~5,000 | ~80,000 |
| Package install (opkg) | Seconds of stall | Near-instant |
| Log writes / SQLite ops | Wears eMMC over time | NVMe handles it easily |
If you're running a Banana Pi Pro or similar board and moved root to SATA, the principle is identical — see the move-root-to-SATA guide for the general approach. The BPI-R4 version substitutes NVMe for SATA. The BPI-R4 on Amazon is the board this guide is written for.
Configuring NAND Boot → NVMe Root
This setup keeps BL2, BL31, U-Boot, and the kernel on SPI-NAND (or eMMC), but points the root filesystem to the NVMe SSD.
Step 1: Prepare the NVMe SSD
Boot from SD or eMMC first (see the BPI-R4 setup guide for initial flashing), then:
# Confirm NVMe is visible
lsblk
# /dev/nvme0n1 should appear
# Partition: one large root partition
fdisk /dev/nvme0n1
# n → p → 1 → default start → default end → w
# Format as ext4 (or f2fs if preferred — see the filesystem guide)
mkfs.ext4 -L nvme-root /dev/nvme0n1p1
Step 2: Copy the root filesystem to NVMe
# Mount NVMe
mkdir -p /mnt/nvme
mount /dev/nvme0n1p1 /mnt/nvme
# Copy the entire rootfs (preserving permissions and links)
tar -C / --exclude='./mnt' --exclude='./proc' --exclude='./sys' \
--exclude='./dev' --exclude='./tmp' --exclude='./run' \
-cf - . | tar -C /mnt/nvme -xf -
# Create empty mount points
mkdir -p /mnt/nvme/{proc,sys,dev,tmp,run,mnt}
Step 3: Modify U-Boot to point root at NVMe
# Access U-Boot environment
fw_setenv bootargs 'console=ttyS0,115200 root=/dev/nvme0n1p1 rootfstype=ext4 rootwait'
# Verify
fw_printenv bootargs
fw_setenv is not available in your OpenWrt build, you must set the variable from the U-Boot prompt via serial console. Interrupt boot with any key and type: setenv bootargs 'console=ttyS0,115200 root=/dev/nvme0n1p1 rootfstype=ext4 rootwait' then saveenv.
# Reboot and verify
reboot
# After boot, confirm root is on NVMe
mount | grep nvme
df -h /
# Should show /dev/nvme0n1p1 mounted on /
SD Card Emergency Fallback
Keep a complete, bootable SD card image ready at all times. If the NVMe fails, the bootloader corrupts, or a sysupgrade goes wrong, this gets you back in minutes instead of hours.
Creating the fallback SD
# Flash a known-good OpenWrt image to a spare SD card
gunzip -c openwrt-*-bpi-r4-sdcard.img.gz | sudo dd of=/dev/sdX bs=4M status=progress conv=fsync
sync
Booting from SD when NAND boot fails
The BPI-R4 has boot select switches (check silk-screen labels near the SD slot). To force SD boot:
- Power off the board
- Set the boot DIP switches to SD mode (varies by revision — consult the LeMaker resources)
- Insert the fallback SD card
- Power on — BL2 loads from SD instead of NAND/eMMC
Re-flashing NAND from the SD fallback
# Once booted from SD, re-flash the NAND bootloader
mtd write /tmp/openwrt-*-bpi-r4-bl2.img BL2
mtd write /tmp/openwrt-*-bpi-r4-fip.img FIP
# Re-flash eMMC if that's where your main OS lives
dd if=/tmp/openwrt-*-bpi-r4-emmc.img of=/dev/mmcblk0 bs=4M status=progress conv=fsync
A/B Partition Scheme for Safer Upgrades
Instead of upgrading in place and hoping it works, maintain two root partitions on NVMe. Only one is active at a time. If the new version fails, switch back.
# Create two root partitions on NVMe
# Partition 1: 8 GB for rootfs A
# Partition 2: 8 GB for rootfs B
# Partition 3: remaining space for data
fdisk /dev/nvme0n1
# Create p1 (8G), p2 (8G), p3 (rest)
mkfs.ext4 -L root-A /dev/nvme0n1p1
mkfs.ext4 -L root-B /dev/nvme0n1p2
mkfs.ext4 -L data /dev/nvme0n1p3
Upgrade workflow
- Currently running from
root-A(/dev/nvme0n1p1) - Mount
root-Band unpack the new image there - Switch U-Boot to point at
root-B - Reboot and test
- If it works →
root-Bbecomes the active slot - If it fails → switch back to
root-Afrom U-Boot or SD fallback
# Switch to root-B
fw_setenv bootargs 'console=ttyS0,115200 root=/dev/nvme0n1p2 rootfstype=ext4 rootwait'
reboot
# If boot fails, serial console into U-Boot:
setenv bootargs 'console=ttyS0,115200 root=/dev/nvme0n1p1 rootfstype=ext4 rootwait'
saveenv
boot
sysupgrade with Partition Preservation
If you're using OpenWrt's standard overlay system (not the A/B scheme above), sysupgrade can preserve your configuration:
# Generate a backup of preserved files
sysupgrade -b /tmp/backup.tar.gz
# List what will be preserved
sysupgrade -l
# Run the upgrade (keeping settings)
sysupgrade -v /tmp/openwrt-*-sysupgrade.bin
# If you want a clean install instead:
sysupgrade -n /tmp/openwrt-*-sysupgrade.bin
/etc/sysupgrade.conf and the output of opkg list-installed are saved. Custom packages must be reinstalled after the upgrade — only configuration files survive.
After sysupgrade, verify NVMe root is still correctly configured:
# Check bootargs weren't reset
fw_printenv bootargs
mount | grep nvme
Brick Recovery via Serial and SD
A "bricked" BPI-R4 almost always means corrupt bootloader — the SoC itself is fine. Recovery requires a USB-to-serial adapter (3.3 V TTL) and a working SD card.
Full recovery procedure
- Connect serial adapter to the debug header (TX, RX, GND — not VCC)
- Open a terminal at 115200 baud:
screen /dev/ttyUSB0 115200 - Set boot switches to SD mode
- Insert the fallback SD card with a known-good OpenWrt image
- Power on — you should see BL2 loading from SD
- Once booted, re-flash the NAND/eMMC bootloaders
# From the SD-booted system, repair NAND:
mtd erase BL2
mtd write /tmp/openwrt-*-bpi-r4-bl2.img BL2
mtd erase FIP
mtd write /tmp/openwrt-*-bpi-r4-fip.img FIP
# Set boot switches back to NAND and reboot
reboot
bpi-r4. The image integrity guide has more on safe verification.
Boot Strategy Checklist
Before putting the BPI-R4 into production, verify each item:
- ☐ Bootloader (BL2 + U-Boot) is on NAND or eMMC — survives NVMe removal
- ☐ Root filesystem is on NVMe — fast and doesn't wear eMMC
- ☐
fw_printenv bootargsshowsroot=/dev/nvme0n1p1(or p2 for slot B) - ☐ Fallback SD card exists, is labelled, and boots successfully when switches are flipped
- ☐ You have a serial adapter and know the header pinout
- ☐ A/B partitions are set up (if using the dual-root scheme)
- ☐
/etc/sysupgrade.confincludes any custom files you need preserved - ☐ NVMe data partition is backed up to an external location periodically