Sbc Opi5p

Orange Pi 5 Plus (sbc-opi5p) Setup Guide

Complete installation and configuration guide for NixOS on the Orange Pi 5 Plus single board computer.


Hardware Overview

ComponentSpecification
SoCRockchip RK3588 (4x Cortex-A76 + 4x Cortex-A55)
GPUMali-G610 MP4 (Valhall architecture)
NPU6 TOPS (RKNN)
RAM8 GB LPDDR5
StorageNVMe (PCIe 3.0 x4), eMMC, microSD
Networking2x 2.5GbE (RTL8125B), WiFi 6E (option)
USB2x USB 3.0, 2x USB 2.0, 1x USB-C
Video2x HDMI 2.1 out, 1x HDMI in
OtherSPI flash (32 Mbit), 40-pin GPIO, fan header

What Works on NixOS

FeatureStatusNotes
CPU (8 cores)WorkingBig.LITTLE scheduling via mainline
GPU (Mali-G610)WorkingPanthor driver (Linux 6.10+)
NVMeWorkingPCIe 3.0 native support
eMMCWorkingStandard MMC subsystem
SD cardWorkingBoot medium for installation
2.5GbE (both ports)WorkingRealtek r8169 driver
USB 3.0WorkingxHCI native
USB-CPartialOne orientation only, no PD negotiation
HDMI outputWorkingVia DRM/KMS
WiFi 6EWorkingRequires armbian-firmware
NPU (RKNN)Not workingVendor-only rknpu driver, no mainline support
Hardware video decodePartialhantro/rkvdec2 improving, not full codec coverage

Architecture Decisions

Kernel: Vendor BSP vs Mainline

This configuration uses a vendor kernel (Linux 6.14 with Armbian patches) rather than mainline. The reasons:

AspectMainline (6.10+)Vendor (6.14 + Armbian patches)
CPU/GPU basicWorkingWorking
Mali-G610 (Panthor)Working (6.10+)Working
PCIe/NVMeWorkingWorking
WiFi/BT firmwareMay need extra patchesIncluded via Armbian defconfig
USB-CBuggyBetter Rockchip PHY support
Device tree qualityGood (upstream DTBs)Good (Armbian-maintained DTBs)
Kernel configGeneric ARM64Tuned for Rockchip64 boards
Security patchesFast (mainline)Slower (Armbian backports)

Trade-off: The vendor kernel provides better out-of-box hardware support (especially WiFi, USB-C, and Rockchip PHY drivers) at the cost of tracking a non-mainline tree. The Armbian project maintains the patches and defconfig, reducing maintenance burden.

The kernel is built from packages/rockchip-kernel/vendor.nix and applied via modules/profiles/hardware/cpu/rock.nix.

Boot Path: U-Boot vs edk2 UEFI

The RK3588 BootROM boot order is: SPI Flash > eMMC > SD Card > USB.

Two boot paths are available:

PathMechanismNixOS Bootloader
U-Boot (traditional)BootROM > TPL/SPL > U-Boot > extlinux.confboot.loader.generic-extlinux-compatible
edk2 UEFIBootROM > edk2-rk3588 UEFI > GRUB/systemd-bootboot.loader.systemd-boot or boot.loader.grub

This configuration uses edk2 UEFI flashed to SPI flash. Benefits:

  • Standard NixOS UEFI boot flow (same as x86_64)
  • systemd-boot or GRUB work natively
  • NVMe boot supported (PCIe 3.0)
  • No U-Boot-specific partition layout requirements
  • edk2-rk3588 has Platinum tier support for Orange Pi 5 Plus

Cross-Compilation Strategy

Building a full NixOS desktop system on the Orange Pi (8 GB RAM) is impractical:

FactorOrange Pi 5 PlusWorkstation (id3-eniac)
RAM8 GB32+ GB
Build speedSlow (ARM big.LITTLE)Fast (x86_64, many cores)
Swap pressureHigh (OOM risk)Minimal

Strategy: Build on the x86_64 workstation using binfmt QEMU emulation, then deploy to the Orange Pi. The storage.nix configuration enables this:

disko.imageBuilder = {
  enableBinfmt = true;  # Use QEMU binfmt for aarch64 builds on x86_64
  pkgs = hey.inputs.nixpkgs.legacyPackages.x86_64-linux;
};

Installation Flow Overview

┌─────────────────────────────────────────────────────────────────┐
│  Workstation (id3-eniac, x86_64 with binfmt)                    │
│                                                                 │
│  1. Build NixOS SD image (cross-compiled for aarch64-linux)     │
│  2. Flash to SD card                                            │
│  3. Download edk2 UEFI firmware                                 │
└─────────────────────────────────────────────────────────────────┘

                            ▼ SD card + edk2 firmware on USB
┌─────────────────────────────────────────────────────────────────┐
│  Orange Pi 5 Plus (first boot from SD)                          │
│                                                                 │
│  Stock/empty SPI → skips to SD → NixOS boots                    │
│  SSH server starts (your config has ssh.enable = true)           │
│  Flash edk2 to SPI while running from SD                        │
└─────────────────────────────────────────────────────────────────┘
                            │ SSH

┌─────────────────────────────────────────────────────────────────┐
│  Workstation (via SSH or nixos-anywhere)                        │
│                                                                 │
│  4. nixos-anywhere partitions NVMe via disko, installs NixOS    │
└─────────────────────────────────────────────────────────────────┘

                            ▼ Reboot (remove SD)
┌─────────────────────────────────────────────────────────────────┐
│  Orange Pi 5 Plus (final: edk2 UEFI → NVMe → NixOS)            │
└─────────────────────────────────────────────────────────────────┘

Key Concepts

SPI (Serial Peripheral Interface) — A 16 MB NOR flash chip on the board. The RK3588 SoC reads it first on boot. Stores the first-stage firmware (U-Boot or edk2 UEFI).

edk2 UEFI — A standard UEFI firmware for RK3588. Once flashed to SPI, it replaces the stock U-Boot and provides a familiar UEFI boot manager (same as your x86_64 PC). Supports NVMe boot natively.

Boot order — RK3588 BootROM tries: SPI → eMMC → SD → USB. If SPI is empty/blank, it falls through to SD. If SPI has edk2, edk2 takes over and presents a UEFI boot manager.

Cross-compilation — Your x86_64 workstation uses binfmt/QEMU to build aarch64-linux packages. The Orange Pi (8 GB RAM) cannot build a full desktop NixOS in reasonable time.

Prerequisites

  • Orange Pi 5 Plus with NVMe disk installed
  • microSD card (8 GB minimum)
  • Ethernet connection (WiFi not supported by nixos-anywhere)
  • USB drive (for edk2 firmware, optional — can also use scp)

Step 1: Build NixOS SD Card Image (on workstation)

# Via nix (preferred for SD card boot)
nix build .#nixosConfigurations.sbc-opi5p.config.formats.sd-aarch64

# Or via hey CLI (builds disko image — targets NVMe layout)
hey build disko-image --host sbc-opi5p

This cross-compiles your entire configuration.nix (Niri, VS Code, Emacs, SSH, etc.) for aarch64-linux using binfmt. Output: a compressed .img.xz in the Nix store.

Note: config.formats.sd-aarch64 produces an image with MBR partition table, FAT32 boot, ext4 root, and extlinux bootloader — optimized for SD card boot. hey build disko-image produces a GPT image matching your NVMe layout — better for flashing directly to NVMe.

Step 2: Flash to SD Card

# Decompress
xz -d result/sd-image/*.img.xz

# Flash (replace /dev/sdX with your SD card device!)
sudo dd if=*.img of=/dev/sdX bs=4M status=progress conv=fsync

Step 3: Download edk2 Firmware

On your workstation:

# Download edk2 UEFI firmware for Orange Pi 5 Plus
curl -LO https://github.com/edk2-porting/edk2-rk3588/releases/download/v1.1/orangepi-5plus_UEFI_Release_v1.1.img

# Copy to USB drive (FAT32 formatted) for transfer to Orange Pi
cp orangepi-5plus_UEFI_Release_v1.1.img /media/usb/

Step 4: First Boot (from SD card)

  1. Insert SD card into Orange Pi 5 Plus
  2. Connect Ethernet cable
  3. Power on
  4. What happens: RK3588 BootROM checks SPI (empty/stock), skips to SD, boots NixOS
  5. SSH starts automatically — your configuration.nix has modules.services.net.ssh.enable = true
  6. Find the IP: check your router’s DHCP leases, or nmap -sn 192.168.31.0/24

Step 5: Flash edk2 to SPI (from the running Orange Pi)

SSH into the Orange Pi, then:

# Copy edk2 firmware from USB drive
sudo cp /media/usb/orangepi-5plus_UEFI_Release_v1.1.img /tmp/

# Flash to SPI (the mtdblock0 device is the SPI NOR flash)
sudo dd if=/tmp/orangepi-5plus_UEFI_Release_v1.1.img of=/dev/mtdblock0 bs=4K

# Verify
sudo cat /proc/mtd  # Should show mtd0

Alternative: If /dev/mtdblock0 doesn’t exist (kernel lacks MTD support), use rkdeveloptool from your workstation via USB-C:

# On Orange Pi, enter maskrom mode (hold recovery button + power cycle)
# On workstation:
rkdeveloptool ld                    # Detect maskrom device
rkdeveloptool db rk3588_spl_loader.bin  # Load DRAM init
rkdeveloptool ef                    # Erase flash
rkdeveloptool wl 0 orangepi-5plus_UEFI_Release_v1.1.img  # Write
rkdeveloptool rd                    # Reboot

Step 6: Install to NVMe (from workstation)

# Using nixos-anywhere (recommended)
nix run github:nix-community/nixos-anywhere -- \
  --flake .#sbc-opi5p \
  root@<orange-pi-ip>

This will:

  1. SSH into the Orange Pi (still running from SD)
  2. Partition the NVMe disk per storage.nix (ESP + ext4 + swap)
  3. Install the full NixOS system closure (cross-built on workstation)
  4. Set up systemd-boot on the ESP
  5. Reboot

Step 7: Final Reboot

  1. Power off the Orange Pi
  2. Remove SD card
  3. Power on
  4. Boot flow: RK3588 → SPI (edk2 UEFI) → NVMe (systemd-boot) → NixOS
  5. Full system running: Niri, VS Code, Emacs, SSH, AdGuard, etc.

If you must build locally on the Orange Pi (e.g., no workstation available):

# Boot from SD (same as Step 2-4 above)
# Then install locally:
sudo nixos-install --flake .#sbc-opi5p

# Or use hey:
hey install --host sbc-opi5p

Warning: A full desktop build (Niri, VS Code, Emacs, etc.) on 8 GB ARM will likely take 2-4+ hours with heavy swapping. Consider reducing the configuration for local builds:

  • Disable VS Code, Emacs, and other large packages
  • Use a simpler desktop or headless configuration
  • Add swap on the SD card during build

Method 3: Remote Builder (Hybrid)

Configure the Orange Pi as a thin build target that delegates heavy compilation to your workstation:

# On the Orange Pi, configure the workstation as a remote builder:
# /etc/nix/machines:
ssh://alienzj@id3-eniac aarch64-linux /home/alienzj/.ssh/id_ed25519 8 1 big-parallel,kvm

# Then build normally:
hey sync --host sbc-opi5p

This sends build jobs to the x86_64 workstation (which uses binfmt to produce aarch64 outputs), keeping the Orange Pi cool and responsive.


Disk Layout

The disko configuration in hosts/sbc-opi5p/modules/storage.nix defines:

/dev/nvme0n1 (Lexar NM620 1TB)
  +-- ESP (2 GB, FAT32)     /boot     systemd-boot
  +-- nixos (~982 GB, ext4) /         root filesystem
  +-- encryptedSwap (10 MB) [swap]    random encryption
  +-- plainSwap (remaining) [swap]    discard + hibernate resume

Partition Details

PartitionLabelSizeFormatMountPurpose
ESPBOOT2 GBFAT32/bootsystemd-boot, initrd, kernel
Rootnixos~982 GBext4/Nix store, system, home
Swap 110 MBencryptedswapEmergency swap (encrypted)
Swap 2remainingplainswapPrimary swap (discard, resume)

Why ext4 instead of btrfs? The Orange Pi is a server/board role, not a workstation. ext4 is simpler, faster on ARM, and doesn’t need the snapshot/subvolume complexity of btrfs. Impermanence is disabled (persist.enable = false).

Changing the NVMe Device Path

The current config hardcodes the NVMe device by ID:

device = "/dev/disk/by-id/nvme-Lexar_SSD_NM620_1TB_PAA0694103795P111D";

If更换 NVMe disk, update this path. You can find the correct path with:

ls /dev/disk/by-id/nvme-*

Or use a more generic path:

device = "/dev/nvme0n1";  # Less stable across reboots

Kernel: Build, Test, Update, Maintain

Architecture

The kernel is built from packages/rockchip-kernel/vendor.nix. It combines:

ComponentSourcePurpose
Kernel sourcegit.kernel.org (mainline)Base Linux kernel
DefconfigArmbian linux-rockchip64-edge.configHardware-tuned kernel config
PatchesArmbian patch/kernel/archive/rockchip64-<ver>/Rockchip64 hardware fixes
Extra configstructuredExtraConfig in vendor.nixNVMe, USB-C, DM_CRYPT, etc.
Board DTBSelected by board parameterDevice tree for specific board

The board parameter (opi5plus, opi5, opi5b) selects the correct device tree blob.

Building the Kernel

Quick Build (cross-compile on x86_64 workstation)

# Build just the kernel (cross-compiled for aarch64-linux via binfmt)
nix build .#nixosConfigurations.sbc-opi5p.config.boot.kernelPackages.kernel

# Check the output
ls -la result/
# → vmlinuz (kernel image), dtbs/ (device trees), modules/

This uses your workstation’s binfmt/QEMU to cross-compile. Takes 20-40 minutes depending on CPU.

Build the Full System (includes kernel)

# Build the entire NixOS system closure
nix build .#nixosConfigurations.sbc-opi5p.config.system.build.toplevel

# Or just the SD card image (includes kernel + full system)
nix build .#nixosConfigurations.sbc-opi5p.config.formats.sd-aarch64
# Only if you have no workstation — expect 1-2+ hours with heavy swapping
hey sync --host sbc-opi5p

Testing the Kernel

# 1. Build SD card image with new kernel
nix build .#nixosConfigurations.sbc-opi5p.config.formats.sd-aarch64

# 2. Flash to SD card
xz -d result/sd-image/*.img.xz
sudo dd if=*.img of=/dev/sdX bs=4M status=progress conv=fsync

# 3. Boot Orange Pi from SD card
# 4. Verify kernel:
uname -r                    # Should show new version
dmesg | grep -i rockchip    # Check SoC initialization
dmesg | grep -i pcie        # Check NVMe detection
dmesg | grep -i mmc         # Check SD/eMMC
ls /dev/dri/                # Check GPU (card0, renderD128)
ip link                     # Check 2.5GbE interfaces

Option 2: Test in QEMU (limited — no real hardware)

# Build a VM image (uses virtio, not real RK3588 hardware)
hey build vm --host sbc-opi5p

# Run the VM
result/bin/run-sbc-opi5p-vm

Note: QEMU VMs use virtio devices, not real RK3588 hardware. This tests the NixOS configuration but NOT the kernel’s hardware support (GPU, NVMe PHY, WiFi, etc.).

Option 3: Verify Kernel Config

# Extract and inspect the kernel config
nix build .#nixosConfigurations.sbc-opi5p.config.boot.kernelPackages.kernel.configfile
zcat result/.config | grep -E "PANTHOR|PCIE_ROCKCHIP|MMC_DW|TYPEC|PHY_ROCKCHIP"

# Key options to verify:
# CONFIG_PANTHOR=y          (GPU driver)
# CONFIG_PCIE_ROCKCHIP_DW_HOST=y  (NVMe)
# CONFIG_MMC_DW=y           (eMMC)
# CONFIG_TYPEC=y            (USB-C)
# CONFIG_PHY_ROCKCHIP_NANENG_COMBO_PHY=y  (USB/DP PHY)

Updating the Kernel

Update to a New Linux Version (e.g., 7.1, 7.2)

When a new stable kernel is released and Armbian adds patches for it:

Step 1: Check Armbian support

# Check if Armbian has patches for the new version
# Visit: https://github.com/armbian/build/tree/main/patch/kernel/archive/
# Look for: rockchip64-<new-version>/

# Also check the defconfig still exists:
# https://github.com/armbian/build/blob/main/config/kernel/linux-rockchip64-edge.config

Step 2: Find the latest Armbian commit

# Get the latest commit from Armbian build repo
git ls-remote https://github.com/armbian/build HEAD
# Note the commit hash

Step 3: Update packages/rockchip-kernel/vendor.nix

# Change these three values:
version = "7.1";  # ← New Linux version

src = fetchurl {
  url = "https://git.kernel.org/torvalds/t/linux-${version}.tar.gz";
  hash = "sha256-XXXX";  # ← Will be updated by nix build error
};

armbianBuild = fetchFromGitHub {
  owner = "armbian";
  repo = "build";
  rev = "NEW_COMMIT_HASH";  # ← Latest Armbian commit
  hash = "sha256-XXXX";  # ← Will be updated by nix build error
  # ...
};

Step 4: Get correct hashes

Nix will tell you the correct hash when you build with a wrong one:

# Build and let nix tell you the correct hash
nix build .#nixosConfigurations.sbc-opi5p.config.boot.kernelPackages.kernel 2>&1 | grep "got:"

# Output example:
#   specified: sha256-XXXX=
#   got:       sha256-YYYY=  ← Use this hash

Step 5: Verify patches exist

# After nix fetches the Armbian source, check the patch directory exists
ls /nix/store/*-source/patch/kernel/archive/rockchip64-7.1/
# Should contain board-*.patch and general-*.patch files

Step 6: Build and test

# Build the kernel
nix build .#nixosConfigurations.sbc-opi5p.config.boot.kernelPackages.kernel

# Build SD image and test on hardware (see Testing section above)

Update Armbian Commit (same kernel version)

If Armbian updates patches for the same kernel version (e.g., bug fixes):

# Just update the rev and hash in vendor.nix
# Same process as above, skip the version change

Maintaining Extra Kernel Config

The structuredExtraConfig in vendor.nix adds options on top of the Armbian defconfig. When adding new hardware support:

structuredExtraConfig = with lib.kernel; {
  # Existing options...

  # Add new options here, e.g. for a new USB WiFi adapter:
  RTL8852BU = module;  # Realtek RTL8852BU WiFi
};

Finding the right option name:

# Search the kernel source
grep -r "CONFIG_.*OPTION_NAME" linux-7.0/
# Or use the kernel's menuconfig (requires building first)
nix develop .#nixosConfigurations.sbc-opi5p.config.boot.kernelPackages.kernel
make ARCH=arm64 menuconfig

Kernel Release Schedule

BranchUpdate FrequencyWhen to Update
Stable (7.0.x)Weekly patchesWhen security fixes land
Edge (7.1, 7.2…)Every 2-3 monthsWhen Armbian adds support
LTS (6.12, 6.18)Monthly patchesFor servers needing stability

Current setup: Tracks Armbian’s edge branch (latest stable kernel). This gives the best hardware support but requires periodic updates.

Recommended update cadence: Every 1-2 kernel releases (every 2-4 months), or when a critical security fix is released.

Version History

DateVersionArmbian CommitNotes
2026-04-297.073a3e49Upgraded from 6.14 (unmaintained)
2026-04-146.1484447a0eInitial vendor kernel

Device Tree

The device tree blob is selected by modules/profiles/hardware/cpu/rock.nix:

hardware.deviceTree = {
  name = "rockchip/rk3588-orangepi-5-plus.dtb";
  overlays = [];
};

This DTB is provided by the kernel build (Armbian defconfig includes it).

Firmware

Armbian firmware blobs (WiFi, Bluetooth, etc.) are provided by packages/armbian-firmware:

hardware.firmware = [ hey.packages.armbian-firmware ];

This includes firmware for:

  • Realtek RTL8852BE WiFi 6E
  • Bluetooth 5.2
  • Various Rockchip codec/PHY blobs

To update firmware:

# Update the armbian-firmware package
# Edit packages/armbian-firmware/default.nix
# Update rev and hash from https://github.com/armbian/firmware

Bootloader: edk2 UEFI

Why edk2 Instead of U-Boot?

AspectU-Bootedk2 UEFI
Boot methodextlinux.confGRUB/systemd-boot
NixOS integrationgeneric-extlinux-compatibleStandard UEFI loaders
NVMe bootRequires SPI U-BootNative UEFI support
systemd-bootNot supportedSupported
Secure BootNot supportedPossible (future)
Community supportGoodPlatinum for OPI5+

Flashing edk2 to SPI

Download from: https://github.com/edk2-porting/edk2-rk3588/releases

# From a running Linux system on the Orange Pi:
sudo flashcp -v orangepi-5-plus_*.img /dev/mtd0

# Or via rkdeveloptool (USB-C recovery mode):
# 1. Hold recovery button, connect USB-C, power on
# 2. Flash:
rkdeveloptool db rk3588_spl_loader_*.bin
rkdeveloptool write 0 orangepi-5-plus_*.img

Verifying edk2 Boot

After flashing, connect HDMI and power on. You should see the edk2 UEFI shell. From there:

  • NVMe disks are detected automatically
  • SD cards are detected automatically
  • Boot order: NVMe > SD > USB

Post-Installation

First Boot Verification

After installing to NVMe and rebooting:

# Check system is running from NVMe
mount | grep /  # Should show /dev/nvme0n1p2 on /

# Check kernel version
uname -r  # Should show 7.0.x

# Check GPU
ls /dev/dri/  # Should show card0, renderD128

# Check networking
ip addr  # Should show two 2.5GbE interfaces (eth0, eth1)

# Check NixOS generation
nixos-rebuild list-generations

Enabling the Desktop

The configuration includes Niri (Wayland compositor) with a DIY shell mode. To start:

# If greetd is configured, it starts automatically
# Otherwise, from TTY:
niri-session

Remote Access

SSH is enabled by default (modules.services.net.ssh.enable = true):

ssh alienzj@<orange-pi-ip>

Updating

From the Orange Pi:

# Pull latest flake inputs
hey pull

# Rebuild and switch
hey sync --host sbc-opi5p

Or remotely from your workstation:

# Build on workstation, copy closure, activate remotely
nixos-rebuild switch --flake .#sbc-opi5p --target-host alienzj@<orange-pi-ip> --use-substitutes

Troubleshooting

Orange Pi Doesn’t Boot from NVMe

  1. Verify edk2 is flashed to SPI: connect HDMI, check for UEFI shell
  2. Check NVMe detection: in edk2 shell, run map to list block devices
  3. Verify ESP has bootloader: mount NVMe ESP, check for EFI/BOOT/BOOTAA64.EFI

No WiFi

# Check firmware is loaded
dmesg | grep -i wifi
dmesg | grep -i rtl8852

# Check firmware path
ls /run/current-system/firmware/rtw89/

# If missing, verify armbian-firmware is in hardware.firmware
nix eval .#nixosConfigurations.sbc-opi5p.config.hardware.firmware

Build Fails with “platform mismatch”

You’re building on x86_64 without binfmt. Verify:

ls /run/binfmt/aarch64-linux  # Should exist
# If not, enable in your NixOS config:
# boot.binfmt.emulatedSystems = ["aarch64-linux"];

Build Fails with OOM on Orange Pi

The Orange Pi has only 8 GB RAM. Full desktop builds require 16+ GB. Solutions:

  1. Build on workstation (recommended)
  2. Add swap: sudo fallocate -l 8G /swapfile && sudo mkswap /swapfile && sudo swapon /swapfile
  3. Reduce configuration (disable VS Code, Emacs, browsers)

edk2 USB-C Limitations

edk2-rk3588 has limited USB-C support:

  • Only one orientation works (flip the cable if no display)
  • No USB PD negotiation (use a USB-C cable with fixed power)
  • USB-C is not recommended as a primary boot device

FilePurpose
hosts/sbc-opi5p/default.nixHost entry point
hosts/sbc-opi5p/modules/configuration.nixSystem configuration
hosts/sbc-opi5p/modules/storage.nixDisko disk layout
packages/rockchip-kernel/vendor.nixCustom kernel build
packages/armbian-firmware/default.nixWiFi/BT firmware
modules/profiles/hardware/cpu/rock.nixRockchip hardware profile
modules/profiles/role/board.nixBoard role profile
docs/storage-disko.mdDisko documentation