Mainline Linux 7.1/7.2 on uConsole + Radxa CM5 — new panel working, sources published
Short version: mainline kernel, no BSP tree, on a uConsole with a Radxa CM5 — including the new December-2025 LCD (TXW500170B0-BL) that the existing drivers render as garbage. Display, GPU-accelerated Wayland, internal keyboard/trackball, NVMe, ethernet, charging, clean poweroff. Everything needed to reproduce it is here:
I know a few people have got 7.1 booting recently, but as far as I can tell nobody’s published the sources — and having watched the threads where people are stuck, that seemed like the gap worth filling. Device tree, panel driver, kernel config fragment, build script, and a long troubleshooting doc are all in the repo.
Why mainline works now
RK3588s DSI support landed upstream in pieces during 2025 — the Samsung MIPI D/C-PHY driver around 6.15, then the DSI2 controller and its DT nodes in 6.16. By 7.1 the whole chain is present and stable, and rk3588s-radxa-cm5.dtsi is upstream too. So the only things missing for a uConsole are a panel driver and a board device tree.
What works
| LCD — TXW500170B0-BL (new) | |
| LCD — TXW500170B0 (original) | |
| GPU — Mali-G610, panthor + Mesa panfrost | |
| Wayland — sway, labwc | |
| Internal keyboard + trackball | |
| Ethernet, eMMC, microSD, USB | |
| NVMe (HackerGadgets board) | |
| Battery charging | |
| Poweroff / reboot | |
| HDMI | |
| Backlight brightness | |
| Orange charge LED | |
| WiFi | USB dongle (RTW88 configs included); CM5 has no onboard radio |
| Audio |
One workaround is required: the first DSI enable at boot wedges the controller and you get a grey screen. A one-shot systemd service that blanks/unblanks fb0 at boot fixes it completely. Details below — I think it’s a genuine mainline dw-mipi-dsi2 bug, not board-specific. It looks like this:
[ 1.406] panel-cwu50 fde30000.dsi.0: GPIO probe: new panel (final check at prepare)
[ 1.580] dw-mipi-dsi2 fde30000.dsi: command interface is busy
[ 1.580] dw-mipi-dsi2 fde30000.dsi: failed to write command header
...~4 seconds of that, once per init command...
[ 5.728] panel-cwu50 fde30000.dsi.0: failed to exit sleep mode (-110)
[15.100] panel-cwu50 fde30000.dsi.0: panel: TXW500170B0-BL (new) ← after the kick, fine
Tested on: uConsole (2026), Radxa CM5, HackerGadgets adapter + NVMe board, Arch Linux ARM, Mesa 26.1.4, panthor 1.8.0.
Dual display works properly under Wayland — each output at its own native resolution with its own transform, and HDMI hotplug is picked up mid-session:
DSI-1 720x1280 transform=90 → logical 1280x720
HDMI-A-1 1280x1024 transform=normal
The boot console is a different story: fbcon drives a single framebuffer cloned to both outputs and its rotation is global, so one of the two is always crooked, and it won’t re-probe a monitor plugged in after boot. Cosmetic — it’s only the boot console.
Also works on 7.2. I’ve since built and booted 7.2.0 from a clean linux-7.2.y checkout — same driver, same DTS, same Kconfig/Makefile one-liners, no changes at all, and the panel is detected identically. That portability is the whole argument for being on mainline rather than a vendor tree.
The five things that cost me the most time
Full write-up in docs/troubleshooting.md — these are the highlights.
1. Don’t put earlycon on the cmdline. It touches UART4’s registers before its clock is ungated and hard-hangs the boot: no output anywhere, static LED, nothing. Cost me a day of thinking the kernel was broken. console=ttyS4,1500000 on its own is fine.
2. root=UUID= doesn’t work without an initramfs. A bare kernel can’t resolve filesystem UUIDs — only /dev/..., PARTUUID=, PARTLABEL=. The vendor entries get away with it because they ship an initramfs.
3. “The kernel doesn’t boot” was the kernel booting fine. Mainline renames the NIC (end0) with a different MAC, so the DHCP server hands out a different IP. It was up, sshd was listening, I was knocking on the old address. If the status LED heartbeats and the ethernet link blinks, it’s alive — go look at your router’s lease table.
4. Reboot/poweroff hung until I disabled the PCIe SMMU. device_shutdown() freezes on arm-smmu-v3 fc900000.iommu: shutdown (MMU600 wired-IRQ erratum territory). &mmu600_pcie { status = "disabled"; } fixes it, and PCIe/NVMe works perfectly without it. Found via netconsole + initcall_debug, which prints each device’s name right before calling its shutdown callback — the last name in the stream is your culprit.
5. Panel revision detection is inverted from intuition. The reset GPIO is GPIO_ACTIVE_LOW, the new panel pulls RESX physically low, and gpiod_get_value() returns the logical level — so the new panel reads 1. I “fixed” this the wrong way round and spent a build cycle on a grey screen. Also: the RDID confirmation from the RPi driver doesn’t port — you get 93 00 00 on the Rockchip DSI2 read path, not 0x39.
Bonus, because it saved the whole project: you can read a failed boot’s log from your fallback kernel. journalctl --list-boots, then journalctl -b -1 -k. And if it won’t boot at all, pull the card and journalctl --root=/mnt -b -1 -k from another machine. No serial cable needed for most of this.
Serial console, if you do want one
The SoC’s default debug UART (uart2) routes to Mini-PCIe on this chassis and never reaches the GPIO header. UART4 with the m2 pinmux does:
| uConsole pin | Signal | Adapter |
|---|---|---|
| 23 | UART4 TX | RX |
| 19 | UART4 RX | TX |
| 25 | GND | GND |
1,500,000 baud, not 115200 — PL2303x and CH340 adapters can’t do it. CP2102N, FT232H or CH343P.
Deploying safely
Please install this alongside your working kernel as a second extlinux.conf entry and leave the old one intact. That’s how the whole thing was developed: BSP image as fallback, mainline as a second entry, iterating over SSH. If it doesn’t boot, put the card in another machine and change one line back.
Also worth knowing: there are three artifacts — Image, the DTB, and modules — and deploying a stale one fails silently. I lost an evening to “PCIe isn’t working” when I’d rebuilt the config but not redeployed the DTB. tr -d '\0' < /sys/firmware/devicetree/base/pcie@fe190000/status tells you what the kernel is actually running.
Credits
The panel init sequences are @ak-rex’s work from the ClockworkPi RPi tree — both the or@ak-rexginal and the new-panel variants, plus the GPIO-based revision detection. Without that driver none of this would exist; my part is the port to the mainline panel API, the device tree, and the integration@dev-null2019 The @dev-null2019 Radxa CM5 overlays were how I worked out the hardw@dev-null2019re mapping, and randomlinuxuser’s Arch image was the fallback system throughout.
Questions welcome. If you have the original (pre-2025) panel I’d particularly like to know whether auto-detection picks it up correctly — dmesg | grep cwu50 will say which sequence it chose.

