Skip to content

Repository files navigation

Samsung Galaxy Tab S8+ (SM-X800) — mainline Linux / postmarketOS port

License Kernel UI GitHub last commit GitHub stars

Mainline Linux runs usably on the Galaxy Tab S8+ Wi-Fi (gts8pwifi, Qualcomm SM8450 "Waipio"): vanilla kernel 7.2, all 8 cores, a native KMS display driver (our S6TUUM1 panel driver — DSC, 120 Hz, real power management) on the 2800×1752 OLED, root on UFS, WiFi with ssh, Bluetooth, touchscreen, and the Book Cover Keyboard — you can log in at the panel and type on the real keyboard, or ssh in over WLAN with no cables at all.

No Galaxy Tab S8 port exists upstream — as far as we can tell this is the first.

kmscube rendering on the Adreno 730, native KMS display, Book Cover Keyboard

kmscube on FD730 (freedreno, OpenGL ES 3.2) — hardware GL through the native DPU/DSI/DSC pipeline, with the pogo Book Cover Keyboard doing the driving.

Status: it's a Linux tablet now. Boots through a quiet native display stack into KDE Plasma 6 (KWin Wayland, composited on the Adreno 730), with touchscreen, keyboard, WiFi, Bluetooth and speakers all live — or stay on the pure console, which is equally at home. The remaining gaps are the long tail (microphones, cameras, sensors).

Plasma 6 desktop on the Tab S8+

Component State
Boot (uniLoader → mainline kernel) ✅ working. uniLoader pinned with four patches: DTB relocation, the kernel command line from an embedded blob (/proc/cmdline ends in bootloader=uniloader), board registration, and aligned memcpy for the MMU-off CPU state ABL hands over (fixed the 2026-09-22 reset loop). Build and flash are one ordered make sequence. Story: docs/05
Display — native KMS console (msm DPU/DSI/DSC @ 2800×1752) ✅ working
CPU — all 8 cores ✅ working
UFS storage — root mounted, auto-resized ✅ working
Touchscreen (STM FTS1BA90A) ✅ working — our fts1ba90a driver, orientation measured on-device
Book Cover Keyboard (pogo STM32 @ i2c 0x2a) ✅ working — our stm32-pogo driver (keyboard, caps LED; touchpad supported but untested, the Slim cover has none)
WiFi (WCN6855, ath11k on PCIe0) ✅ working — NetworkManager autoconnects at boot; primary ssh path. Carries the upstream RX-corruption fix trilogy (bulk downloads used to wedge with msdu_done errors / silent drops)
Bluetooth (WCN6855 on uart20) ✅ controller up, address from efs, scan finds devices; pairing pending
USB-C port: Type-C, PD, roles (MAX77705 CCIC) ✅ working — our max77705-usbc driver speaks to the CCIC's PD firmware through its mailbox (ADR-003): plug a device and the tablet becomes host and switches VBUS on, unplug and VBUS goes off; plug a PC or charger and it becomes device and sink; a PD-passthrough dongle can swap roles live. Safety rules live in the driver: an opcode and register allowlist, fixed PDOs only, at most 9 V and 15 W, input limit lowered before any voltage increase (kernel r40). Story: ADR-003, PR #59
USB host (xhci) ✅ working — hot-plug with VBUS by attach: mice, keyboards, RTL8153 ethernet (firmware packaged), in either cable orientation
USB gadget (to a PC) ✅ working — plug into a computer and it enumerates as "Galaxy Tab S8+": NCM ethernet (the PC gets 172.16.42.2 by DHCP, ssh to 172.16.42.1), a serial login on /dev/ttyACM*, and MTP, so KDE's device notifier offers "Open with File Manager" on the tablet's ~/Shared folder (a dedicated folder: MTP has no authentication, so the home directory with its dot-files stays off the cable) (device r30)
Charging and battery ✅ working — upstream MAX77705 charger and gauge drivers (with our fixes): /sys/class/power_supply/max170xx_battery reports capacity, voltage, current, temperature and cycles; charging at 9 V PD from chargers and PC ports. Deliberately below stock (4.30 V float, 2.0 A) because mainline does not do stock's temperature-dependent charging; stock parity waits on a thermal guard (kernel r36). Story: ADR-003, PR #56
Power key, volume down (PMIC PON) ✅ working
Volume up (pm8350 gpio6, gpio-keys) 🟡 mapped and working on most boots — KEY_VOLUMEUP from the pm8350 GPIO line, active low with pull-up, as stock wires it. On some boots the PMIC latches two edges per press while the level never changes, so no event fires until the next reboot (issue #18; tools/volup-trap/ records the next occurrence)
reboot download from Linux 🟡 PON mode-download wired but ABL ignores it — likely cold reset clears the spare bits (downstream forces a warm reset first); under investigation
Native panel driver (S6TUUM1 DDIC) ✅ working — full native KMS: cold init (Anapass TCON-ready handshake), DSC @ 2800×1752, TE-synced 120 Hz, DPMS blank/unblank, brightness (11-bit DBV). Leaving the panel DPMS off hangs the tablet about a minute later with a silent reset, so idle blanking ships as console-blank (device r26): black frame after BLANK_MIN idle minutes with the panel powered, wake on any input; device r27 rescans /dev/input when the node count changes, so late and hot-plugged devices wake it too. Story: docs/08-native-display.md, device-facts/display-s6tuum1.md
S Pen (Wacom WEZ01 EMR digitizer) ✅ working — our wacom-wez01 driver; position + pressure + tool. SE14's FIFO is silicon-disabled (forces broken GPI DMA), so we bit-bang i2c on its pins via i2c-gpio. Firmware wez01_gts8p.bin (harvested). Polish: query/calibration + axis verify. Story: device-facts/wacom-wez01.md
GPU (Adreno 730) ✅ working — freedreno/Mesa FD730, OpenGL ES 3.2; Samsung-signed zap from the apnhlos partition (gts8pwifi-fw-extract), firmware rides in the initramfs (a7xx loads SQE at bind time)
Plasma Desktop 6 (KWin Wayland) ✅ working — full KDE 6.7 desktop, KWin composited on the Adreno, Plasma Login Manager autostart; one command on a fresh install: sudo gts8pwifi-setup plasma. Polish gaps: tear bands under fast motion (panel idles at ~24 Hz LFD), no runtime 120 Hz switching yet
Login experience ✅ quiet boot (loglevel=4), generated /etc/issue banner with live IP (agetty needs --issue-file on Alpine), UTF-8 locale, keyboard autorepeat (kernel r42)
Audio ✅ working — four CS35L45 amps on Primary MI2S from the ADSP (AudioReach), stereo playback through PulseAudio/UCM; volume capped (no speaker-protection DSP yet). Three DMICs through the VA macro, powered from L12C (found 2026-09-21 with a pad probe); stereo capture of the bottom and back mics through UCM. Story: docs/10-audio.md
Rear flash LED ✅ working — PM8350C flash module, two channels as one white LED at /sys/class/leds/white:flash (kernel r12). Torch: brightness 0..255 for 0..500 mA total, stock's level is 77 (150 mA). Flash: flash_brightness up to 1.5 A, hardware timeout up to 1280 ms, fired with flash_strobe; the timer ends the pulse and flash_fault then reads flash-timeout-exceeded, which is the normal end of a strobe
Cameras 🟡 all three sensors stream RAW10 at 30 fps, session after session — mainline CAMSS on SM8450, the Hi847 driver converted to device tree, a new Hi1337 driver with tables from the stock configuration, and a camcc fix that parks the camera RCGs on XO when idle (kernel r25). `tools/camtest.sh uw
Sensors (incl. auto-rotate) 🟡 accelerometer, light and magnetometer through the SLPI with hexagonrpcd (patched) and libssc, iio-sensor-proxy reports orientation and auto-rotate has what it needs (kernel r28, device r24, the served tree built from the tablet's own vendor partition at setup); gyroscope and calibration open. Story: docs/12-sensors.md, issue #33
Hall switches, thermistors ✅ both hall switches work, level and interrupt, as EV_SW on gpio-keys: cover on tlmm 169 at the left edge about midway, S Pen on tlmm 23 at the upper right corner of the back face, located with a magnet and gpiomon on 2026-09-22. The Book Cover Keyboard folio never brings a magnet to the cover sensor; tlmm 23 reads asserted while the folio is attached but off the pogo pins and while the pen is in the folio holder. AP and Wi-Fi thermistors on the pmk8350 ADC (kernel r26), gts8pwifi-therm prints stock-table temperatures. Story: docs/13-buttons-and-lid.md, issue #33
Lid, pen and power button (folio-state daemon, console-blank) ✅ working with nobody logged in. foliod fuses the pogo keyboard device, the two hall switches and a magnetometer sample through the SLPI into SW_LID and SW_PEN_INSERTED on a virtual input device; console-blank reads it (device r27): close the folio and the console goes dark in about 5 s, open it and it is back in about 3 s, the power button toggles the console with the lid open and does nothing closed, logind ignores the lid. Pen-forgotten logging is off by default because the pen in the folio holder is invisible to the sensors. Suspend and resume turned out to work (issue #49); lid to suspend is a future ADR amendment. Story: docs/13-buttons-and-lid.md, ADR-002, PR #48

btop on the console — 8 cores, WiFi, UTF-8, 120 Hz OLED

Daily-driver console: btop over UTF-8 fbcon — all 8 cores, WiFi, 95 GB root, half a watt of load average.

Getting a shell

Local: attach the Book Cover Keyboard and log in at the panel like any laptop.

Wireless: the device autoconnects to its saved WiFi network at boot (NetworkManager profile) and a bring-up service prints interface/MAC/IP/gateway to the panel whenever they change — read the address off the screen and ssh to it.

USB cable: plug the tablet into a computer. The computer gets 172.16.42.2 by DHCP; ssh user@172.16.42.1, or open the serial console on /dev/ttyACM0. The file manager sees the tablet over MTP (this capture predates the switch from the home directory to ~/Shared):

Dolphin browsing the tablet over MTP

Fallback: a USB-C ethernet dongle works the same way, and holding volume-down from initial power-on drops into the postmarketOS initramfs debug shell (on-screen keyboard via osk-sdl).

Should you try this?

If "mainline Linux with a real GPU on Samsung tablet hardware" makes you grin, genuinely: yes, come on in — the water's weird but warm. Read this first, though, because the door locks behind you:

  • Unlocking the bootloader permanently blows the Knox efuse. Warranty gone, Knox/Samsung Pay features dead forever — even if you return to stock Android. There is no un-blowing it.
  • Going back to stock is possible but not painless. Odin can reflash Samsung firmware (make restore-android documents our path), but expect friction, and Knox stays tripped regardless.
  • The unlock/root path has a firmware ceiling. Bootloader binary 9 or lower qualifies (the fifth character from the end of the build number, e.g. X800XXU9DYDC). Binary 9 covers One UI 7 and the first One UI 8 builds up to January 2026; binary A or B, shipped since February 2026, closes the door. Which units still qualify, and how to downgrade to One UI 7 first: docs/00-compatibility.md.
  • This is a development platform, not a product. No microphones, raw camera frames only, motion sensors through the SLPI with a patched daemon. What works, works genuinely well — native display, GPU, input, wireless — but you are signing up to be a porter, not a customer.

And a sincere off-ramp: if any of the above reads as risk rather than fun, Samsung DeX plus a Linux terminal/emulator app gets you a capable Linux environment with zero risk and zero soldered-shut doors. That is the sensible choice. This repo is the other one.

Start with docs/00 (does your tablet qualify), then docs/01 (unlock/root), then docs/05 (the boot recipe).

Why this is unusual

You cannot boot mainline Linux directly from Samsung's bootloader on this SoC. Samsung's ABL merges its own device-tree overlay fragments onto whatever DTB it selects, which corrupts a mainline device tree — the kernel then dies before any console exists, giving you a completely silent failure.

The fix is uniLoader, a secondary bootloader that embeds the kernel, DTB and ramdisk inside its own binary and masquerades as a kernel image. Samsung's ABL only ever sees "a kernel" and never touches our device tree. (lk2nd does not support SM8450.)

The full story — including the seven separate silent failures it took to get a console — is in docs/05-mainline-uniloader-boot.md. If you are porting another Samsung SM8450 device, read that first; it will save you a lot of blind reboots.

Layout

docs/                     The maintained story, in phase order
  00-compatibility.md       Which SM-X800 units can still be unlocked (binary counter)
  01-unlock-root-runbook.md Bootloader unlock + root
  05-mainline-uniloader-boot.md   ★ the working recipe + every bug and fix
  06-upstreaming.md         Conventions, pinning + patch model, contributing back
  07-input-and-wireless.md  Touch + keyboard driver ports, WiFi/BT bring-up
  08-native-display.md      Native KMS: DPU/DSC bring-up and the Anapass TCON
  09-firmware-harvest.md    Which blobs live where, and the extractor model
  10-audio.md               ADSP + AudioReach + four CS35L45 amps on MI2S
  11-camera.md              CAMSS raw path, Hi847 and Hi1337 sensors
  12-sensors.md             SLPI sensors, hall switches, thermistors
  13-buttons-and-lid.md     Buttons, hall switches, and the folio-state lid daemon
  discovery-notes/          Raw early-session notes, kept for provenance
                            (recon, the downstream dead end, the mainline pivot)
pmaports-overlay/         Our postmarketOS packages (the actual port)
  device/testing/linux-postmarketos-qcom-sm8450/   kernel pkg: DTS, config, DPU DSC
                                                   patches, and four drivers written
                                                   from Samsung's GPL downstream —
                                                   fts1ba90a.c (touch), stm32-pogo.c
                                                   (keyboard), max77705-otg.c (VBUS),
                                                   panel-samsung-s6tuum1.c (display)
  device/testing/device-samsung-gts8pwifi/         device pkg + deviceinfo
  uniloader-port/                                  our uniLoader port: board file,
                                                   defconfig, cmdline.in (the kernel
                                                   command line), patches 0001-0004
device-facts/             Non-proprietary device documentation
tools/                    Runbooks + helpers: mkpatch (patch workbench),
                          uniloader-fdt-harness (uniLoader's DTB patching
                          under qemu), post-flash procedure, hard-won gotchas
Makefile                  The build as an ordered sequence: check, deps, dumps,
                          harvest, rootfs, image, flash-all, install-tablet
                          (make help lists it)

Not in git (see .gitignore): pmb-work/, kernel-src/, reference/, root-build/, and all Samsung firmware (stock partition dumps, stock DTBs). Those are Samsung's copyrighted binaries and stay local.

Building

Requires pmbootstrap, odin4, android-tools (mkbootimg/unpack_bootimg/img2simg), and dtc.

First run only — point the vendored pmbootstrap at this repo and device (everything lives under the repo; nothing touches your home directory except pmbootstrap's own config file):

./pmb init      # work path: <this repo>/pmb-work
                # channel edge, device samsung-gts8pwifi (ours), UI console

The build is an ordered sequence. Each step checks what the previous one left behind and names the step to run when something is missing:

make check          # host tools, pmbootstrap init, dumps, harvest, apks; ends with
                    # what you are ready for (boot/install-tablet, or image once
                    # rootfs has produced root-build/combined.img)
make deps           # one-time: clone uniLoader (pinned), copy in the board port,
                    # apply patches 0001-0004, install the chroot toolchain
make dumps          # verify the stock partition dumps; ADB=1 pulls boot, apnhlos
                    # and super from a tablet rooted on stock (docs/01 step 8)
make harvest        # copy the proprietary blobs (GPU zap, sensor registry) out of the dumps
make rootfs         # pmb install; preserves the combined image, prints the UUIDs
make image          # uuids gate -> kernel -> device -> boot -> sparse userdata tar
make flash-all      # first install: boot + userdata in ONE odin session
make install-tablet # later kernels: dd boot.img + apk add over ssh, then reboot
make help           # the same list, plus every other target

Variants: make boot-debug builds a second boot image with pmos.debug-shell on the command line (its own boot-debug.img and tar, the normal artifacts stay); make kernel, make device and make boot run one stage of image; make flash-help picks the odin flavor for what you changed.

make rootfs prompts for the device user password unless you pass PASSWORD=... (the docs use throwaway credentials throughout — pick your own). DEVSUDO=1 additionally installs the -devsudo subpackage: passwordless sudo for the default user, for development images only.

uniLoader owns the kernel command line. The cmdline-blob step writes blob/cmdline from pmaports-overlay/uniloader-port/cmdline.in with the two rootfs UUIDs read from the vendor_boot header, then appends bootloader=uniloader and anything in BOOTARGS_EXTRA; uniLoader sets /chosen/bootargs from it at boot. The DTS still carries the same tokens for now, so make image starts with the uuids gate: the rootfs UUIDs must match the DTS or the build stops and prints the two lines to change. The uuids gate stays until the DTS copy is dropped (kernel pkgrel 29). A mismatch there was the most common cause of the initramfs debug shell while the DTS supplied the command line, and today the blob already carries the rootfs values.

make uniloader picks the kernel apk by the APKBUILD's pkgver-pkgrel, never the newest file, and records it in .stage/kernel-apk; install-tablet refuses when that record does not match the APKBUILD. The boot-image build runs stage-fw first (stages the harvested GPU zap into the build chroot's initramfs and hard-fails if it does not land) and ends by printing the numbered bring-up manifest.

Flashing gotchas

These cost us many cycles — see docs/05 §5:

  • The device must be in a freshly entered download mode. A session that has sat through boot attempts fails with FAIL! (Auth), and the "an error has occurred while updating the device software" screen is a "fake download mode": it enumerates as 04e8:685d and odin4 -l finds it, but it will not accept a flash. Entry choreography and recovery details: docs/05 §5.
  • userdata must be a sparse image (img2simg). A raw ext4 image fails at ~3% with Fail request receive 3.
  • userdata must hold the combined image, i.e. pmb install without --split. The pmOS initramfs needs both a pmOS_boot and a pmOS_root subpartition, and our real boot partition is occupied by uniLoader — so both have to live inside userdata. Flashing only the split -root.img leaves no pmOS_boot and stage-1 stalls forever in wait_boot_partition. See docs/05 §8b.
  • The "press power button to confirm unverified firmware boot" prompt times out on its own and the boot continues unattended; pressing Power only skips the wait.
  • A flash is two things: the boot image and the kernel apk. Kernel modules live in the rootfs, not in boot.img. dd of the new boot.img replaces kernel, DTB and initramfs only; /lib/modules is whatever kernel apk the rootfs has installed. A patch that changes a module (camss, r13) needs the matching apk add --allow-untrusted linux-postmarketos-qcom-sm8450-7.2-rN.apk on the tablet as well, or the old .ko stays and the new compatible never binds. make install-tablet does both and refuses on a pkgrel mismatch.
  • The UFS LUN order is not stable across boots. The boot partition was /dev/sda25 on one boot and /dev/sdb25 on the next. Always address /dev/disk/by-partlabel/boot, never a hardcoded sdX; the tell is cmp failing against every image at once.
  • Stage the recovery image before the first flash of a new bootloader. Keep a pmos_uniloader_boot.tar from a known-good build. make boot and make image rewrite root-build/pmos_uniloader_boot.tar and root-build/uniloader/boot.img in place, so copy the known-good pair aside under a dated or pkgrel-suffixed name before rebuilding, for example pmos_uniloader_boot-r28-good.tar. If the new one loops, enter download mode (power off, then Vol Up + Vol Down, plug USB) and odin4 -a that saved tar.
  • A camera register touched without its clock hangs the SoC. Skipping the CPAS fast AHB or the VFE core clock in a power-cycle bisect froze the tablet (no ping) the moment a VFE register or its interrupt handler ran. Recovery is the Vol Down
    • Power reset. Reading camcc (0xade0000) is safe; the camera blocks under TITAN_TOP are not while their domain or clock is off.
  • Do not poll /sys/kernel/debug/gpio. The listing walks every pin controller, including the LPASS island one at 0x3440000. A 5 Hz poll of it for a minute ended in a silent hang on 2026-09-22 (journal stops mid-session, no crash record); the link is a suspicion, not a proof, but /proc/interrupts and evtest give the same answers safely.
  • Flash multiple partitions in one odin4 invocation (-a and -u together, as make flash-all does) rather than calling odin twice — that is what caused the reboot between writes. --reboot is opt-in, and --redownload returns the device to download mode for the next round.

Only boot, vendor_boot, dtbo, vbmeta and userdata are ever written. Never flash bootloader or secure-world partitions (xbl, aop, tz, abl, pmic, …) — Samsung download mode is the only recovery floor on this device (EDL/9008 is not viable: it needs a Samsung-signed SM8450 Firehose loader that is not publicly available).

Credit

  • uniLoader by Ivaylo Ivanov — the piece that makes this possible.
  • sm8450-mainline — the kernel tree this port ran on until 2026-09, and still the source of the SM8450 config fragment.
  • sm8450-samsung-r0q.dts (Galaxy S22) — the skeleton this port started from.
  • postmarketOS.

License

Dual, following each part's upstream: GPL-2.0-only for kernel/uniLoader sources, MIT for packaging, docs, and tools — the per-directory table is in LICENSE.md. Samsung-proprietary content is never in this repo; extractors pull it from your own device.

Contributing

Issues and PRs welcome — especially device variant reports from the rest of the Tab S8 family (same SoC). House style: one variable per flash, patches via tools/mkpatch (never hand-written), evidence over theory — see docs/06-upstreaming.md for the conventions.

About

Mainline Linux / postmarketOS on the Galaxy Tab S8+ (SM-X800, SM8450): native display, Adreno GPU, KDE Plasma 6. First known Tab S8 mainline port.

Topics

Resources

Stars

24 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages