Mainline Linux 7.1/7.2 on uConsole + Radxa CM5 — new panel working, sources published

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:

→ GitHub - tdeval/uconsole-radxa-cm5-mainline: WIP support for the Radxa CM5 module on the ClockWork µConsole with its post 2025 panel · GitHub

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) :white_check_mark:
LCD — TXW500170B0 (original) :warning: auto-detected, code path there, untested — please report
GPU — Mali-G610, panthor + Mesa panfrost :white_check_mark: glmark2 2270 fullscreen at native res
Wayland — sway, labwc :white_check_mark:
Internal keyboard + trackball :white_check_mark:
Ethernet, eMMC, microSD, USB :white_check_mark:
NVMe (HackerGadgets board) :white_check_mark: Gen2 x1, Samsung SM981
Battery charging :white_check_mark:
Poweroff / reboot :white_check_mark: (with the included shutdown hook)
HDMI :white_check_mark: under Wayland, hotplug included — :warning: console needs it connected at boot
Backlight brightness :warning: on/off only — dimming needs an OCP8178 driver port
Orange charge LED :cross_mark: dark (charging itself is fine)
WiFi USB dongle (RTW88 configs included); CM5 has no onboard radio
Audio :cross_mark: not attempted

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.

9 Likes

This is a very hardcore technical post, worthy of a thumbs up.:+1:

1 Like

That’s huge, thank you very much! :folded_hands::folded_hands::folded_hands::rocket:

1 Like

Nice work! Thx for the credit. I have an original panel - maybe i give it a try!

Regards

S

Thank you !
Without your work and Rex’s to support the uConsole, I wouldn’t have been able to go that far.

Yes, it would be nice to have your panel tested to clear this uncertainty. :wink:

My next work is on :

  • Supporting brightness control ( OCP8178, mostly done )
  • Charging feedback on the power LED

With that done, I think I’ll be a happy µConsole + Radxa CM5 user. :grin:

1 Like

Hey @TDeval, thank you so much for your effort.

I had AI (Claude Code) help for this and also for the structure of this post but i still wanted to share my experience.

Report: original panel (TXW500170B0) confirmed working, plus a few notes

[    0.057613] /dsi@fde30000: Fixed dependency cycle(s) with /dsi@fde30000/panel@0
[    0.057682] /dsi@fde30000/panel@0: Fixed dependency cycle(s) with /dsi@fde30000
[    0.311355] /dsi@fde30000: Fixed dependency cycle(s) with /dsi@fde30000/panel@0
[    0.312048] /dsi@fde30000/panel@0: Fixed dependency cycle(s) with /dsi@fde30000
[    0.497489] panel-cwu50 fde30000.dsi.0: GPIO probe: old panel (final check at prepare)
[    0.696520] panel-cwu50 fde30000.dsi.0: RDID: 00 00 00
[    0.696527] panel-cwu50 fde30000.dsi.0: panel: TXW500170B0 (original)
[    4.937163] panel-cwu50 fde30000.dsi.0: failed to exit sleep mode (-110)
[    8.107163] panel-cwu50 fde30000.dsi.0: Skipping unprepare of already unprepared panel
[    9.296514] panel-cwu50 fde30000.dsi.0: RDID: 93 00 00
[    9.296521] panel-cwu50 fde30000.dsi.0: panel: TXW500170B0 (original)

Setup: uConsole with the original TXW500170B0 panel, Radxa CM5 32 GB/256 GB, HackerGadgets CM5 adapter, tested with the RJ45/USB3 expansion board and the AIO v2. Debian on eMMC (Radxa’s Bookworm image, later upgraded in place to Trixie for Mesa 25/panthor), your 7.2.x DTS as the base (own kernel build from your script), with two additions patched into the DTB for the AIO: uart2 on uart2m0 for GPS and spi4 (spi4m2) with a spidev child for LoRa.

For the table:

  • LCD – TXW500170B0 (original): :white_check_mark: – the GPIO probe takes the old-panel path (GPIO probe: old panel); the first ID read returns RDID: 00 00 00 and the first enable times out (-110) as on the new panel, display-kick fixes it, the second attempt reads RDID: 93 00 00, and the picture is there. Boots fine warm and cold since.
  • NVMe: :white_check_mark: also with an Intel SSDPEKNU512GZH on the AIO v2 (Gen2 x1).
  • WiFi: :white_check_mark: RTL8812AU (2T2R with USB interface i had laying around) via mainline rtw88_8812au - needs CONFIG_RTW88_8812A=m and CONFIG_RTW88_8812AU=m added to your fragment; firmware rtw8812a_fw.bin is in linux-firmware.
  • GPS (AIO v2): :white_check_mark: by enabling uart2 (uart2m0, GPIO0_B5/B6) in the DTB → /dev/ttyS2, gpsd + chrony as time source.
  • RTL-SDR (AIO v2): :white_check_mark: - rtl_test clean, FM broadcast band received with rtl_power.
  • Poweroff / reboot: :white_check_mark: - warm reboot comes back with and without the shutdown hook for me; the reboots that failed for me early on turned out to be a nearly empty battery plus a high-resistance battery lead, not the hook.

Things that cost me time and might be worth a line in the README:

  1. If the panel stays at command interface is busy and the keyboard hub fails with -71, check the power supply before the DTS: in my case it was a nearly empty battery plus a high-resistance battery lead, and the symptoms were identical to a broken device tree. A cold power-up with the charger connected got me out of it; with a sound battery path, warm reboots have been fine since.
  2. The modules tarball extracts lib/ as a real directory; on a merged-/usr Debian tar -C / replaces the /lib symlink and the system won’t boot. --keep-directory-symlink or shipping usr/lib/modules avoids it.
  3. The uConsole doesn’t negotiate PD, so the charger must offer 5 V by default - my first PD charger delivered nothing (AXP reg 0x00 = 0), an Anker Prime works.
  4. voltage_min_design is read-only; voltage_min is the writable cutoff (I run 3.2 V). AXP reads occasionally return -6 on the bit-banged bus; not persistent.

AIO v2 caveats specific to the Radxa CM5, for anyone considering it: the RTC sits on the Pi’s I2C1 pins, and pin 3 is the AXP IRQ line on the uConsole mainboard (ClockworkPi’s schematic: PMU-IRQ GPIO2), so it can’t coexist with the PMU interrupt. LoRa (SX1262 on Pi SPI1) maps to spi4m2 for CLK/MOSI/CS, but MISO (pin 35) reads as floating - I’m verifying whether the module is powered or the pin isn’t routed on the CM5.

I will keep you updated.

2 Likes

Hey @alexg ,

Thanks a lot for your feedback.

Your input is really valuable, as there are some new test cases that I need to take into account.
Thanks for confirming the original LCD panel.
I’m glad you could make the AIO v2 board working. I will definitely order one as well. :wink:
Having RTL-SDR running is one of the points of this hardware, isn’t it ? :+1:

I will try to update my branch with your findings ASAP.
Sorry for the /lib f*ck-up, your advise is taken. I’ll adapt the tarball and README for the next build.

Hey @TDeval,

i was working on this for the last days and made some progress:

  • RTC: found working on I2C7; the “blocked by the AXP IRQ” claim was wrong
  • LoRa: not yet working, i need to figure out the pins on this board
  • Backlight: OCP8178 one-wire driver with 32 levels of brightness
  • Charge LED: one AXP register bit, now on while charging
  • Battery status: kernel patch - so Full is reported after termination; test pending (Still WIP)

I took the liberty to fork your repo, if you want you can have a look at what i added. Its a lot right now so i wanted to clean this stuff up and create a PR to your repo after everything is solid and clean.

2 Likes

Great news !

I will definitely look at your work ! :+1:

1 Like

Just got this up and running, everything seems to be working great as of now. will do some further testing, but i have an old screen and this is what my dmesg output is:

clockwork@radxa-cm5-rpi-cm4-io:~$ uname -r
7.1.13-dirty

clockwork@radxa-cm5-rpi-cm4-io:~$ dmesg | grep cwu50
[    0.460863] panel-cwu50 fde30000.dsi.0: GPIO probe: old panel (final check at prepare)
[    0.662829] panel-cwu50 fde30000.dsi.0: RDID: 00 00 00
[    0.662836] panel-cwu50 fde30000.dsi.0: panel: TXW500170B0 (original)
[    4.903509] panel-cwu50 fde30000.dsi.0: failed to exit sleep mode (-110)
[    9.266337] panel-cwu50 fde30000.dsi.0: Skipping unprepare of already unprepared panel
[    9.486756] panel-cwu50 fde30000.dsi.0: RDID: 93 00 00
[    9.487212] panel-cwu50 fde30000.dsi.0: panel: TXW500170B0 (original)