I make Linux boot on hardware that was never supposed to run it. The current victim: the AYANEO Pocket DS a clamshell, dual-screen handheld built on the Qualcomm QCS8550 (the embedded cousin of the Snapdragon 8 Gen 2) that ships with Android. It now runs Fedora aarch64 on a mainline-first kernel, and as of this summer it has a SteamOS-style image that boots straight into Big Picture.
This is not an Android container, not a chroot, not a vendor kernel with a distro stapled on. It’s Fedora on a kernel tracking mainline, with the device-specific drivers either patched in and clearly labelled, or on their way upstream.
What actually works #
- Both screens, both touchscreens the top OLED and the lower panel, each with its own touch controller, correctly rotated and routed.
- GPU acceleration Adreno 740, clocked to 1.0 GHz with a custom OPP table, on a patched Mesa (freedreno). This plus suspend/resume are the crown jewels; a regression there is a headline regression, and they’re protected accordingly.
- Suspend/resume. Yes, really, on a Qualcomm handheld.
- WiFi and Bluetooth (WCN7850), UFS + microSD, USB-C with DisplayPort alt-mode, stereo speakers, fan control across the SoC’s thermal zones, and the gamepad (the sticks/buttons arrive via an internal USB controller plus an MCU handled through InputPlumber mappings).
What doesn’t: the fingerprint sensor. That’s the honest, complete list of casualties right now.
Credit up front: the SM8550 device groundwork from ROCKNIX made this port possible. My job was turning that into a proper distro: real Fedora RPMs, real images, real CI no quirk-script pile.
The bug of the port: a touchscreen that froze the desktop #
If you only read one section, read this one.
Touching the top screen would freeze the whole desktop. Kernel log: geni_i2c: Bus arbitration lost, clock line undriveable, then a timeout resetting the controller’s state machine, then the touch driver giving up.
The top touchscreen (a Focaltech FT5426, mainline edt_ft5x06 driver) sits on an i2c bus that runs through the hinge. Its pin configuration is identical to the bottom screen’s perfectly-healthy bus so this isn’t a config problem, it’s physics: the hinge traces make the bus electrically marginal. It’s clean at idle and only falls over under the burst of traffic a touch generates. I ruled out clock speed (going slower was actually worse), regulators, and pin drive strength before accepting that the hardware is what it is.
So the fix is a driver patch that treats the bus like the flaky link it is:
- Shorter reads. The driver’s defaults for this chip fetch 10 touch points a 63-byte read on every interrupt, which is exactly the kind of long transaction that wedged the bus. Capped to 2 points, it’s a 15-byte read. Short transactions survive.
- Retries. The stock driver retried zero times; one transient error dropped the whole touch packet. Now: 4 retries with backoff.
- Recovery only when it’s real. The chip’s reset line is only toggled after a genuine freeze (>1 s with no successful read), rate-limited so ordinary bus stutter doesn’t cost you a 300 ms hitch.
- Sanity checks. Frames with impossible touch counts or out-of-range coordinates get dropped, which also cured the cursor occasionally teleporting past the touch point.
Result: from “touching the screen crashes the session” to ~98% smooth. It ships in the project kernel today, clearly labelled as the workaround it is.
Two more war stories, briefly #
Bluetooth shipped with no MAC address. bluetoothctl reported no controller at all, even though firmware load and HCI init completed fine. The WCN7850 reports an all-zero BD_ADDR, and the Bluetooth core deliberately refuses to register an address-less controller correct behavior, hostile symptom. The fix is a small boot service that programs a stable, locally-administered MAC derived from each device’s /etc/machine-id (per-device, so units don’t collide). It has to retry through the controller’s ~5-second early-boot setup window, and then Bluetooth just works.
A firmware update could silently kill WiFi. The kernel is built without firmware decompression, and Fedora ships the ath12k WiFi blobs xz-compressed so the port carries uncompressed copies, and a routine linux-firmware update could clobber them. Worse, the failure was delayed: the running chip keeps firmware in RAM, so WiFi died only on the next radio reset. The blobs now also live under /lib/firmware/updates/, which the kernel searches first and which no distro package touches. Landmine defused permanently.
There’s also a fun audio one the speakers were whisper-quiet because the smart amp’s analog PA was set to 12/17 in the ALSA UCM profile, and an override couldn’t win due to UCM’s include-ordering rules and an on-screen keyboard that lives on the bottom screen and types into the top one, which took XWayland, uinput injection, an InputPlumber ignore rule, a one-line C patch to Onboard, and a KWin “never take focus” rule to pull off. Dual-screen Linux keeps you humble.
The SteamOS-style image #
The part r/SBCGaming actually cares about: there’s now a steamos image profile alongside the KDE, KDE Mobile, GNOME, and Phosh ones.
- Boots directly into Steam Big Picture inside a gamescope session (the mmogr gamescope fork with Flip-DS dual-screen support).
- Native ARM64 Steam and Proton 11 ARM64 (Sildur’s build) are preseeded into the image first boot doesn’t download a gigabyte before showing you anything.
- Full KDE Plasma 6 desktop is one session-switch away (
steamos-session-select-style Gaming/Desktop toggle, with a “Return to Gaming Mode” launcher).
Honest status: beta. An early tester’s first-boot report turned into a four-bug fix chain (a filesystem-resize binary that was never actually shipped, a partition-grow step that silently aborted so downloads hit disk-full, a stale package pipeline, and a Steam bootstrap pinned to an old client snapshot forcing a broken self-update). All four are fixed at the root as of early July. Remaining known issues: the bottom screen is blank in Gaming Mode for now (the dual-screen companion tooling is KWin-based and only runs in desktop mode), and there’s one unverified report of a slow first boot I’m still chasing. I do think it is stable given that I am daily driving it myself.
Every profile rebuilds automatically in CI every week, so images never go stale against Fedora updates.
Upstream, because that’s the point #
The COPR kernel is the delivery vehicle, not the destination. Driver series for the top panel’s power tree the SGM3804 charge-pump regulator and SY7758 backlight have been submitted already by Neil Armstrong, and the panel driver for the display controller is co-authored with Teguh Sobirin and my friend Aaron Kling, since the same DDIC ships in the AYN Odin 2 Portal, Odin 3, and Thor. Fixing it once, upstream, means every one of those devices benefits that’s the whole model.
drm/panel: st7703: Add AYANEO Pocket DS Lower Panel Support – Has been merged to drm-misc kernel repository
Input: edt-ft5x06- ignore contacts with anout-of-range slot id – has been applied
Links #
- Docs, flashing guide, images: https://fedora-pocketds.azka.li/
- Source (kernel, packages, image builder): https://gitlab.com/linux-pocketds
- Packages: Fedora COPR
linux4switch/pocketds
Fair warning before you flash: the boot chain replaces the Android bootloader path with a signed loader, and the docs are the source of truth read them first, this is still an enthusiast port.
