Skip to content

dgshue/OpenWrt-RISC

Repository files navigation

OpenWrt for the Orange Pi RV2 (SpacemiT K1 / Ky X1, RISC-V)

A from-source, mainline-kernel OpenWrt target for the Orange Pi RV2 — the SpacemiT K1 ("Ky X1") SoC: 8-core RISC-V rv64gc, dual Gigabit Ethernet, microSD boot.

Upstream OpenWrt has no K1 target. This repo adds one (target/linux/spacemit) on top of OpenWrt main's Linux 6.18, carrying a small set of device-tree and driver backports so the board boots a clean, reproducible image we build ourselves — not a vendor blob.

Status: boots to a full OpenWrt userspace on real hardware. Kernel 6.18.37, dual-GbE via k1_emac, microSD rootfs (F2FS overlay), procd, and the LuCI web UI all come up. See STATUS.md for the running worklog.


Hardware

Board Orange Pi RV2
SoC SpacemiT K1 (a.k.a. Ky "X1"), 8× RISC-V rv64imafdcv, rv64gc userland
RAM 8 GB LPDDR4X
Ethernet 2× GbE — SpacemiT EMAC IP (k1_emac), Motorcomm RGMII PHY (no HW offload)
Storage microSD (root); eMMC pads; SPI-NOR holds U-Boot/OpenSBI
Console Serial UART0, ttyS0 @ 115200 (COM9 on the dev host)
Bootloader Vendor U-Boot 2022.10ky + OpenSBI, in SPI-NOR — flashing the SD does not touch it

The bootloader living in SPI-NOR is important: our SD image provides only a FAT boot partition (boot.scr + Image + dtb) and the rootfs. U-Boot loads boot.scr from the SD and bootis the kernel — mirroring the vendor flow.


What works / what doesn't

Working: SMP boot (8 cores), clock/reset (CCU), pinctrl, GPIO, I²C, SpacemiT P1 PMIC + regulators + RTC, microSD (high-speed), dual Gigabit Ethernet, onboard Wi-Fi (AP6256 / BCM43456 SDIO, STA mode validated), 8250 serial console, squashfs root + F2FS overlay, procd, LuCI web UI.

Not yet / caveats:

  • microSD runs in high-speed (3.3 V) mode only, not UHS — see patch 0003 and the MMC fix writeup. UHS needs two more driver commits backported.
  • USB / PCIe device-tree nodes are present (from the board backport) but not exercised/validated here.
  • Wi-Fi is validated in STA (client) mode — see patches 0004–0006 and the AP6256 bring-up writeup. brcmfmac has no 4-address (WDS) mode, so the radio can't be a transparent L2 bridge port; L2-bridging a wireless uplink needs relayd. Wireless-bridge mode is implemented and hardware-validated via relayd — both GbE ports are bridged and wired clients lease from the upstream router over the WiFi uplink; see Wireless bridge (relayd).
  • reboot behaviour on this board is quirky (OpenSBI SRST is a no-op on the vendor firmware) — a power cycle is the reliable reset.

Build from source

OpenWrt must not be built as root. Use a normal user on a Debian/Ubuntu-like host.

# 1. Build deps (Debian/Ubuntu)
sudo apt install build-essential clang flex bison g++ gawk gettext git \
  libncurses-dev libssl-dev python3 rsync unzip zlib1g-dev file wget swig time

# 2. OpenWrt main (pins Linux 6.18)
git clone https://git.openwrt.org/openwrt/openwrt.git
cd openwrt

# 3. Drop in this target
git clone https://github.com/dgshue/OpenWrt-RISC.git /tmp/rv2
cp -a /tmp/rv2/target/linux/spacemit target/linux/

# 4. Feeds
./scripts/feeds update -a
./scripts/feeds install -a

# 5. Select the target + build
make defconfig          # auto-selects spacemit / generic / xunlong_orangepi-rv2
make -j"$(nproc)"

Output lands in bin/targets/spacemit/generic/:

  • openwrt-spacemit-generic-xunlong_orangepi-rv2-squashfs-sdcard.img.gz (recommended)
  • openwrt-spacemit-generic-xunlong_orangepi-rv2-ext4-sdcard.img.gz

Adding the LuCI web UI (optional)

./scripts/feeds install luci
echo 'CONFIG_PACKAGE_luci=y'                     >> .config
echo 'CONFIG_PACKAGE_luci-theme-material=y'      >> .config   # optional themes
echo 'CONFIG_PACKAGE_luci-theme-openwrt-2020=y'  >> .config
make defconfig && make -j"$(nproc)"

Full router build (VPN, adblock/DNS, IPv6, SMB, …) (optional)

For a complete router/firewall image — WireGuard + OpenVPN, dnsmasq-full + adblock + https-dns-proxy, full IPv6, SQM, DDNS, ACME, monitoring, SMB, and diagnostics — append the package profile and rebuild:

cat /tmp/rv2/config/rv2-router.config >> .config   # from this repo
./scripts/feeds install -a
make defconfig && make -j"$(nproc)"

This profile also selects the onboard Wi-Fi packages (kmod-brcmfmac, BRCMFMAC_SDIO, wpad-mbedtls, iw); the AP6256 firmware, CLM blob and board NVRAM ship in the target base-files. See docs/wifi-ap6256.md for the bring-up story.

See docs/router-build.md for the full package list, the VPN-is-an-interface-protocol gotcha (LuCI has no standalone VPN app pages anymore), and the force-DNS / sinkhole recipe that closes the "my DNS filter misses half the queries" gap.


Flash & first boot

  1. Decompress and write the .img.gz to a quality microSD (balenaEtcher reads the gz directly and verifies). SD-card quality matters on this board — cheap/worn cards fail to init.
  2. Insert the card, connect serial (115200 8N1), power on. Watch for Starting kernel …Please press Enter to activate this console.
  3. Networking default (see caveat below): LAN comes up and the board is reachable; open http://<board-ip>/ for LuCI. No root password is set initially (set one in System → Administration or via passwd on the console before enabling SSH).

⚠️ Local LAN default: base-files/etc/uci-defaults/99-rv2-lan sets a static 192.168.1.250, points gateway/DNS at 192.168.1.1, and disables the LAN DHCP server (so the board is a well-behaved host on an existing network rather than a router at .1). This is tailored to the author's LAN — edit or delete that file to restore OpenWrt's standard 192.168.1.1 + DHCP behaviour before building your own image.


The target & patches

target/linux/spacemit/
├── Makefile                     # BOARD=spacemit, ARCH=riscv64, KERNEL_PATCHVER=6.18
├── config-6.18                  # K1 driver stack built-in (CCU clk, EMAC, sdhci, pinctrl, PMIC…)
├── generic/target.mk            # the 'generic' subtarget
├── image/                       # SD image recipe (MBR: FAT boot p1 + rootfs p2, boot.scr)
├── base-files/                  # 02_network (eth0=LAN/eth1=WAN), inittab, uci-defaults,
│                                #   brcm/ Wi-Fi firmware+NVRAM (see patch 0004)
└── patches-6.18/
    ├── 0001-…-backport-k1-board-enablement…      # board DTS (see below)
    ├── 0002-mmc-sdhci-of-k1-enable-pad-clock…    # the SD boot fix (see below)
    ├── 0003-…-sd-high-speed-only                 # constrain SD to high-speed
    ├── 0004-…-enable-ap6256-sdio-wifi            # Wi-Fi DTS node (see below)
    ├── 0005-…-fix-unaligned-HOST_CONTROL2-access # SDIO panic fix (see below)
    └── 0006-rtc-spacemit-p1-enable-…-32KOUT      # PMIC 32KOUT / Wi-Fi LPO (see below)

Patches

  • 0001 — board device-tree backport. OpenWrt's 6.18 ships only a minimal K1 DTS (RV2 = UART+LED). This replaces the K1 DTS trio (k1.dtsi, k1-pinctrl.dtsi, k1-orangepi-rv2.dts) with the mainline-master versions, wiring dual-GbE EMAC, microSD, USB, PCIe and the PMIC. The clock/reset dt-bindings header is byte-identical between 6.18 and master, and all three K1 boards compile clean against the 6.18 headers.

  • 0002 — sdhci-of-k1 pad-clock enable (backport of upstream f87b273e4b6d, 2026-05-11). This is the fix that makes the microSD work under Linux. The 6.18 driver never enables the SD pad clock, so the card receives no clock and card-init times out silently (mmc1: Failed to initialize … with no CRC/-110/voltage error). U-Boot reads the same card fine, which makes it a confusing failure. Full debugging story: docs/openwrt-sd-mmc-fix.md.

  • 0003 — microSD high-speed only. We backport 0002 but not the K1 UHS voltage-switch/tuning commits (00a97fc57c09, e9cb83c10071), so requesting UHS risks a failed 1.8 V switch during init. This drops sd-uhs-* and adds no-1-8-v for reliable 3.3 V high-speed operation. Remove it once those two commits are backported.

  • 0004 — AP6256 SDIO Wi-Fi device tree. Adds the K1 SDH1 host node (@ 0xd4280800, IRQ 100), the mmc2 pin group (GPIO_15..20), and the &sdhci1 board node with power sequencing (WL_REG_ON = GPIO 67) and the brcmfmac child. Key finding: vmmc-supply = <&pcie_vcc3v3>EXT_PWR_EN (GPIO 116) gates the shared EXT_3V3 buck feeding the module's VBAT, so the MMC core must power it before card init or the module is mute. Firmware/NVRAM ship in base-files/lib/firmware/brcm/.

  • 0005 — sdhci-of-k1: fix fatal unaligned HOST_CONTROL2 access (upstream-worthy). The K1 driver does a 32-bit RMW of the 16-bit SDHCI_HOST_CONTROL2 (offset 0x3E) → misaligned device load → RISC-V access fault → kernel panic in IRQ context. It's guarded by !MMC_CAP2_NO_SDIO, and every upstream K1 board marks its slots no-sdio, so our Wi-Fi slot is the first to hit it (100 % reproducible panic before, clean after). Fix: use sdhci_readw/writew.

  • 0006 — PMIC RTC: enable the 32 kHz crystal and 32KOUT. The SPM8821 RTC_CTRL powers up 0x00; mainline only toggles RTC_EN, so the PMIC 32KOUT pin stays dead — and it's the board's only 32.768 kHz source, feeding the AP6256 LPO. Without it brcmfmac fails with clock enable timeout. Fix enables crystal_en|out_32k_en|rtc_en|rtc_clk_sel at probe (also fixes the RTC).

Full Wi-Fi story, with the schematic power-rail reasoning and the panic trace: docs/wifi-ap6256.md.


Contributing

PRs to this repo are welcome — additional hardware bring-up (USB, PCIe, UHS SD), config cleanups, docs, and testing on real boards. See CONTRIBUTING.md for the full build/PR flow and how to report hardware-test results. Useful conventions:

  • Keep the target buildable against OpenWrt main and match OpenWrt's style for target files.
  • Kernel patches under patches-6.18/ should be minimal and, where possible, backports of merged mainline commits (cite the upstream hash in the patch header, as 0002 does).
  • Test on hardware over the serial console (115200); include the relevant boot-log lines in your PR.
  • Upstreaming changes to OpenWrt or the Linux kernel is coordinated by the maintainer — open an issue first.

Related sibling project (separate repo): a FreeBSD/OPNsense port of the same board, which is where much of the K1 hardware reverse-engineering (register maps, clock tree, board quirks) originated.


Credits & license

Maintainer: Daniel Shue (dgshue). Upstream K1 enablement is the work of the SpacemiT / Ky engineers and the mainline RISC-V community (device tree by Yangyu Chen & Hendrik Hamerlinck; the sdhci-of-k1 clock fix by Iker Pedrosa / Yixun Lan).

Target files and patches are licensed GPL-2.0-only (see LICENSE), matching OpenWrt and the Linux kernel they derive from. Backported patches retain their upstream authorship and license.

About

From-source, mainline-kernel OpenWrt target for the Orange Pi RV2 (SpacemiT K1 / Ky X1, RISC-V) — dual-GbE, boots to LuCI

Resources

License

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors