Best Boot Strategy for BPI-R4: eMMC/NAND → NVMe with SD Fallback and Safer Upgrades (2026 Guide)

BPI-R4 boot strategy diagram showing eMMC NAND NVMe and SD card fallback paths with arrows

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.

  1. SPI-NAND / eMMC Boot ROM — hardwired in the SoC, loads BL2 from NAND or eMMC
  2. BL2 (TF-A) — initialises DRAM, loads BL31
  3. BL31 (ARM Trusted Firmware) — EL3 runtime, loads U-Boot
  4. U-Boot — reads boot config, loads kernel + DTB from the configured source
  5. 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.

Boot media priority: The MT7988A checks SPI-NAND first, then eMMC, then SD. If SPI-NAND has a valid BL2, the SD card is ignored unless you intervene via serial console or hardware boot switches.

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:

MetriceMMC RootNVMe Root
Sequential read~150 MB/s~1,500 MB/s
Random 4K IOPS (read)~5,000~80,000
Package install (opkg)Seconds of stallNear-instant
Log writes / SQLite opsWears eMMC over timeNVMe 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
Warning: If 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:

  1. Power off the board
  2. Set the boot DIP switches to SD mode (varies by revision — consult the LeMaker resources)
  3. Insert the fallback SD card
  4. Power on — BL2 loads from SD instead of NAND/eMMC
Tip: Label the fallback SD card with the date and OpenWrt version. Update it every time you do a major sysupgrade. An out-of-date fallback is better than no fallback, but keeping it current saves time.

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

  1. Currently running from root-A (/dev/nvme0n1p1)
  2. Mount root-B and unpack the new image there
  3. Switch U-Boot to point at root-B
  4. Reboot and test
  5. If it works → root-B becomes the active slot
  6. If it fails → switch back to root-A from 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
Warning: The A/B scheme doubles your root storage requirement but eliminates the "broken upgrade, no way back" scenario. On a 128 GB or 256 GB NVMe, the cost is negligible.

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
What sysupgrade preserves: Files listed in /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

  1. Connect serial adapter to the debug header (TX, RX, GND — not VCC)
  2. Open a terminal at 115200 baud: screen /dev/ttyUSB0 115200
  3. Set boot switches to SD mode
  4. Insert the fallback SD card with a known-good OpenWrt image
  5. Power on — you should see BL2 loading from SD
  6. 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
Warning: If you flash the wrong BL2 image (e.g., from a different board), the board will not boot from NAND at all. Always verify the image filename contains bpi-r4. The image integrity guide has more on safe verification.

Boot Strategy Checklist

Before putting the BPI-R4 into production, verify each item:

Tip: Test your recovery procedure before you need it. Deliberately boot from the SD fallback, verify it works, then switch back. Finding out your fallback SD is corrupted during an actual emergency is the worst possible time. For more on crash diagnosis when things go wrong at runtime, see the crash diagnosis guide.