Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

35 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Ubuntu on Surface Pro 11 (Snapdragon X Elite)

KDE Plasma running on the Surface Pro 11 with the patched qcom-x1e kernel

This repository is an experimental Ubuntu bring-up kit for the Microsoft Surface Pro 11 with Snapdragon X Elite (X1E80100). It uses the Surface Laptop 7 Ubuntu work as a reference, and ports the Surface Pro 11-specific pieces from Dale Whinham’s Arch Linux work and, most importantly, Jens Glathe's continual kernel work: join the community.

The current verified target is:

Item Value
Device Microsoft Surface Pro, 11th Edition
SKU Surface_Pro_11th_Edition_2076
CPU Snapdragon(R) X 12-core X1E80100 @ 3.40 GHz
Firmware/UEFI 175.222.235, dated 2026-02-23
Internal disk Samsung MZ9L4512HBLU-00BMV-SAMSUNG, 476.9 GiB NVMe
Windows source checked Windows 11 Home Insider Preview build 29585

Warning: this is not an official Ubuntu, Microsoft, or linux-surface release. Keep Windows installed, keep a recovery USB nearby, and expect regressions.

Prerequisites

  • Surface Pro 11 with Snapdragon X Elite (X1E80100) — not Surface Laptop 7/Romulus or Intel Surface devices
  • Windows backup + BitLocker/Device Encryption recovery key (suspend or decrypt before partition work)
  • Secure Boot disabled in Surface UEFI
  • Windows recovery USB or another restore path
  • USB-C flash drive, 16 GB+ (write script erases the entire disk)
  • macOS build host with Docker Desktop, git, diskutil, sudo (20 GB free)
  • Temporary networking for post-install firmware (Wi-Fi doesn't work in the live session — use USB-C Ethernet, phone tethering, or a mounted Windows partition)
  • External USB keyboard recommended for installer recovery

Current Status

The Surface Pro 11 needs a custom device tree and firmware handling — a stock ARM64 Ubuntu ISO is not enough. See the dwhinham/linux-surface-pro-11 "What's working" list for the upstream Arch status.

Feature Status Notes
NVMe ✅ Working Installed Ubuntu boots from /dev/nvme0n1p5 with separate /boot and /boot/efi partitions after support setup.
Graphics ✅ Working Direct boot reaches the Ubuntu desktop. 3D acceleration for X1E SoCs only; X1P support is on its way from upstream.
Backlight ✅ Working Night Light and screen brightness controls work. Adjustable via /sys/class/backlight/dp_aux_backlight/brightness.
USB3 ⚠️ Partially USB-C ports are working, but the Surface Dock connector is presumably not.
USB4/Thunderbolt ❌ Not working No external display output when using the official USB4 dock.
USB-C display output ✅ Working Working as of 6.15-rc6 (for DP alt mode).
USB-C boot ✅ Working with --grub-mode direct The normal GRUB menu can display entries but input and timeout are unreliable. Use --grub-mode direct for the verified live-USB path.
Wi-Fi ✅ Working WCN7850/Qualcomm FastConnect 7800 binds to ath12k_wifi7_pci, loads firmware, scans, reconnects to a saved network after reboot, and passes traffic on patched git-fallback 7.0.0-22-qcom-x1e plus an rfkill-capable Denali DTB. Stock/upgraded 7.0.0-32-qcom-x1e remained hard-blocked. Uses a kernel hack to disable rfkill. Continue validating normal reboots, suspend/resume, and package upgrades.
Bluetooth ✅ Working Public address set via raw AF_BLUETOOTH socket C helper (tools/sp11-bt-set-addr.c) before bluetooth.service starts, avoiding the btmgmt D-state hang. Cold boot service succeeds at T+1s. Pairing, audio, and suspend/resume still need validation. See how-to-bring-up-bluetooth.
Audio — speakers ⚠️ Partially Sound card instantiates with generated topology from the CRD template. Both stereo speaker endpoints produce audio through a PipeWire manual sink with reordered audio.position labels. The 4-channel PCM is a transport layout, not four independently routable speakers. Music playback showed no audible regression with the 2.4 MHz DMIC kernel, but the manual sink is still required and speakers can sound distorted. See how-to-bring-up-audio and ADR-0036.
Audio — microphone ✅ Working with 2.4 MHz DMIC clock The corrected single-WSA-macro UCM profile exposes two-channel internal microphone capture, and Surface-specific unity gain avoids the shared +16 dB default clipping. Setting the Denali DMIC clock to 2.4 MHz eliminates the continuous feedback/static heard at 4.8 MHz and makes recorded speech dramatically clearer. Capture remains slightly tinny or thin. See ADR-0044 and ADR-0046.
Touchscreen ❌ Not working Kernel patches and DTB build and compile, but the kernel uses the EFI firmware DTB (Stubble) which has spi@a88000 as disabled, ignoring GRUB's devicetree directive. Requires a kernel rebuild with CONFIG_EFI_ARMSTUB_DTB_LOADER=y and dtb= cmdline — rebuild hangs at boot. See ADR-0041 for patch set structure, ADR-0042 for the full troubleshooting history, diagnostics, and remaining options.
Pen ❌ Not working Not working in live USB. Upstream Arch notes also list pen as not working.
Touchpad ✅ Working Type Cover touchpad works after the kernel loads i2c-hid-of and the gpio keys. Hot-plug may need re-binding.
Suspend/Resume ⚠️ Partially Lid suspend works with kernel 6.10+, but can fail to resume display.

Quick Start

The custom live-USB builder creates a small ARM64 GRUB boot shim, stores the Ubuntu Snapdragon X concept ISO on a Linux data partition, and injects the Surface Pro 11 device tree at boot. This avoids remastering the Ubuntu ISO.

1. Build the patched kernel (Docker, on macOS)

cd /path/to/linux-surface-pro-11-oe
mkdir -p build

# Default: Ubuntu concept kernel
./scripts/build-sp11-qcom-x1e-kernel-docker.sh \
  --source git --work-dir build/docker-sp11-qcom-x1e-kernel \
  --copy-to-payload --reset-source --jobs 4

# OR: SP11 v2 — Johan G.'s 7.1.3 tree with the 2.4 MHz DMIC default
./scripts/build-sp11-qcom-x1e-kernel-docker.sh \
  --source git \
  --git-url https://github.com/jglathe/linux_ms_dev_kit.git \
  --git-branch jg/ubuntu-qcom-x1e-7.1.3-jg-1 \
  --image ubuntu:26.04 \
  --patch-dirs "patches/jglathe-qcom-x1e-7.1.3 patches/sp11-qcom-x1e-7.1.3-v2" \
  --build-target "binary-indep binary-qcom-x1e" \
  --work-dir build/docker-sp11-qcom-x1e-kernel-jg-7.1.3-sp11-v2 \
  --linux-work-volume sp11-qcom-x1e-kernel-build-jg-7.1.3-sp11-v2 \
  --copy-to-payload \
  --reset-source \
  --jobs 4

--patch-dirs accepts a space-separated list; patches from each directory are applied in order. The binary-indep target is required because the ABI-specific headers package depends on linux-qcom-x1e-headers-<abi> (e.g. linux-qcom-x1e-headers-7.1.3-jg-1sp11v2).

If a new jg/ubuntu-qcom-x1e-7.1.3-jg-<n> tag fails check-config with N config options have been changed, regenerate the annotations patch before rerunning the build:

./scripts/regenerate-qcom-x1e-annotations.sh \
  --git-url https://github.com/jglathe/linux_ms_dev_kit.git \
  --git-branch "jg/ubuntu-qcom-x1e-7.1.3-jg-<n>" \
  --reset-source

The helper installs the source package's complete build dependencies, uses the same compiler and Rust probes as the package build, removes the stale annotations patch for the previous tag, and writes the replacement into patches/jglathe-qcom-x1e-7.1.3/. Verify the new filename, then rerun the original build command unchanged.

See the patched qcom-x1e kernel how-to for the full on-device build path and fallback-kernel safety model.

2. Build the USB image

./scripts/build-sp11-live-usb-image.sh \
  --iso https://people.canonical.com/~platform/images/ubuntu-concept/resolute-desktop-arm64+x1e.iso \
  --grub-mode direct \
  --work-dir build/work-direct-boot \
  --out build/sp11-ubuntu-live-direct.img \
  --validate

If auto DTB extraction fails, provide one explicitly via --dtb. An explicit DTB can come from a kernel package with SP11 support or from a local build of dwhinham/kernel-surface-pro-11. Do not substitute the Surface Laptop 7/Romulus DTB.

To build a live USB with KDE Plasma available by default, add --desktop kde. See ADR-0039.

3. Write the USB

diskutil list
diskutil info /dev/diskX  # verify it's the removable USB disk
./scripts/write-image-to-macos-disk.sh build/sp11-ubuntu-live-direct.img /dev/diskX

The script refuses to write unless the disk is external, removable, and USB.

4. Boot and install

  1. Disable Secure Boot in Surface UEFI.
  2. Boot from the USB.
  3. Install Ubuntu carefully (shrink Windows, create /, /boot, /boot/efi).
  4. At the end of the installer, choose continue testing and run the installed-system preparer before rebooting:
SP11DEV="$(blkid -L SP11DATA)"
SP11DATA="$(findmnt -rn -S "$SP11DEV" -o TARGET | head -n 1)"
[ -z "$SP11DATA" ] && { sudo mkdir -p /mnt/sp11data; sudo mount "$SP11DEV" /mnt/sp11data; SP11DATA=/mnt/sp11data; }
cd "$SP11DATA/support"
sudo ./scripts/prepare-sp11-installed-system.sh --target /target
sudo reboot

5. Post-install: firmware + kernel + bring-up

After the first installed boot, mount SP11DATA and run the finish script (downloads firmware, installs support helpers, reboots):

SP11DEV="$(blkid -L SP11DATA)"
SP11DATA="$(findmnt -rn -S "$SP11DEV" -o TARGET | head -n 1)"
[ -z "$SP11DATA" ] && { sudo mkdir -p /mnt/sp11data; sudo mount "$SP11DEV" /mnt/sp11data; SP11DATA=/mnt/sp11data; }
cd "$SP11DATA/support"
sudo ./scripts/finish-sp11-installed-system.sh --download --reboot

If networking is unavailable, mount the Windows partition and use Windows firmware instead: --windows-root "$WINROOT" (see the script --help).

Then install the patched kernel payload from the USB:

cd "$SP11DATA/support"
./scripts/build-sp11-qcom-x1e-kernel.sh --work-dir "$SP11DATA/payload/kernel-debs" --install-only
sudo reboot

Keep the previous qcom-x1e kernel as a GRUB fallback until the patched kernel has booted and Wi-Fi rfkill state has been validated.

For a direct local installation instead of the USB payload flow, place all four matching .deb packages in one directory and run the same helper against that directory. For example, with the 2.4 MHz DMIC packages downloaded to $HOME/Downloads:

cd /path/to/linux-surface-pro-11-oe
./scripts/build-sp11-qcom-x1e-kernel.sh \
  --work-dir "$HOME/Downloads" \
  --install-only
sudo reboot

For the standard v2 build, the directory must contain the matching image, modules, flavour-header, and common-header packages for 7.1.3-jg-1sp11v2. After reboot, verify the running kernel and authoritative Stubble-provided DMIC clock:

uname -r
od -An -tu4 -N4 --endian=big \
  /sys/firmware/devicetree/base/soc@0/codec@6d44000/qcom,dmic-sample-rate

Expected values are 7.1.3-jg-1sp11v2-qcom-x1e and 2400000.

Post-Install Bring-Up

Wi-Fi

The WCN7850 needs a patched kernel with rfkill disabled. The board.bin fallback is enough for the adapter to probe; the remaining blocker is the rfkill kernel/DTB path. See the patched qcom-x1e kernel how-to for the full diagnostic and build path.

Bluetooth

cd "$SP11DATA/support"
sudo ./scripts/troubleshoot-sp11-bluetooth.sh

If the diagnostic reports a 00:00:00:00:* address, get the real Bluetooth MAC from Windows (see how-to-bring-up-bluetooth) and configure it:

BT_MAC="<your-bluetooth-mac>"
sudo ./scripts/sp11-bluetooth-mac.sh --write-config "$BT_MAC"
gcc -Wall -Wextra -O2 -o tools/sp11-bt-set-addr tools/sp11-bt-set-addr.c
sudo ./scripts/sp11-bluetooth-mac.sh --install-systemd
sudo udevadm trigger --subsystem-match=bluetooth
sudo reboot

The installed unit runs before bluetooth.service, avoiding the cold-boot D-state hang. See ADR-0032.

Audio

cd "$SP11DATA/support"
sudo ./scripts/troubleshoot-sp11-audio.sh

If the topology file is missing, build and install it:

cd "$SP11DATA/support"
./scripts/sp11-audio-topology.sh
sudo ./scripts/sp11-audio-topology.sh --install
sudo ./scripts/sp11-fix-audio-boot-race.sh install
sudo reboot

Alternatively, download the audio topology and UCM v2 release. The corrected v2 UCM should be paired with the 7.1.3-jg-1 v2 kernel, which carries the 2.4 MHz DMIC clock required to eliminate the static observed with the earlier 4.8 MHz kernel.

See how-to-bring-up-audio and ADR-0035 for details.

KDE Plasma (Kubuntu-like Experience)

Kubuntu has no official ARM64 ISO. Two paths to a KDE Plasma desktop:

Option 1 (recommended): Post-install swap

cd "$SP11DATA/support"
sudo ./scripts/sp11-install-kde-desktop.sh
# Once confirmed, optionally remove GNOME:
sudo ./scripts/sp11-install-kde-desktop.sh --purge-gnome -y

Option 2 (experimental): Live USB with KDE

./scripts/build-sp11-live-usb-image.sh \
  --iso https://people.canonical.com/~platform/images/ubuntu-concept/resolute-desktop-arm64+x1e.iso \
  --desktop kde --grub-mode direct \
  --out build/sp11-ubuntu-live-direct-kde.img --validate

Both paths are desktop-layer changes only — they do not touch the SP11 kernel, DTB, firmware, audio, or Bluetooth bring-up. See ADR-0039.

Test Notes

Visual Evidence

How-To Guides

Decision Records

The major bring-up decisions are recorded in docs/adr/:

Windows Firmware

The verified Windows install contains the expected firmware inputs:

  • qcdxkmsuc8380.mbn
  • adsp_dtbs.elf
  • qcadsp8380.mbn
  • cdsp_dtbs.elf
  • qccdsp8380.mbn

These are extracted by scripts/finish-sp11-installed-system.sh either from the Windows partition (--windows-root) or downloaded from the Canonical firmware mirror (--download).

Useful Commands on Windows

Collect the Bluetooth MAC address from Windows (run PowerShell as Admin from a checkout of this repository):

powershell -NoProfile -ExecutionPolicy Bypass -File .\tools\collect-sp11-windows-bluetooth-address.ps1

Sources

This project is a synthesis of community bring-up work. The links below are kept as source credit and as an audit trail for future decisions.

Base projects and install flow:

Surface Pro 11 kernel and Wi-Fi rfkill:

Firmware, Bluetooth, and audio follow-up:

About

Ubuntu Linux ARM for Surface Pro 11 x1e80100 OLED

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages