From a9cf761bad7ccae388c12b7fbf869e41cd18a93e Mon Sep 17 00:00:00 2001 From: Sean Date: Mon, 24 Aug 2026 20:04:35 +0800 Subject: [PATCH 01/15] Guard three x86-only assumptions so Omarchy can install on aarch64 Each of these is an unconditional assumption that only holds on x86_64. None is x86-specific in spirit, and each one blocks or breaks an ARM64 install. 1. etc/mkinitcpio.conf.d/thunderbolt_module.conf MODULES+=(thunderbolt) is unconditional, but Thunderbolt is x86-oriented hardware and the module is not built for every architecture -- Arch Linux ARM's aarch64 kernel has no `thunderbolt`. mkinitcpio treats an unresolvable MODULES entry as a hard error, so *every* initramfs build fails: ==> ERROR: module not found: `thunderbolt' That means no UKI, no boot entry, and an install that completes and then cannot boot. 2. install/post-install/pacman.sh This overwrites /etc/pacman.conf unconditionally. That config points [core]/[extra]/[multilib] at Omarchy's mirror of Arch, which is x86_64-only, and [omarchy] at pkgs.omarchy.org/stable/$arch, which 404s for aarch64. ([multilib] is 32-bit x86 libraries and exists on no ARM mirror at all.) Applying it on ARM leaves the installed system unable to update anything. 3. install/user/mise-work.sh Node publishes its builds as linux-x64 / linux-arm64, which does not match uname -m. The bundled-tarball lookup hardcodes linux-x64, so on ARM it finds nothing and the install aborts with "no bundled Node tarball". The sed that parses the version back out of the filename needs the same treatment. All three were found by installing Omarchy on aarch64 (Arch Linux ARM) and are fixed here the same way: derive from uname -m rather than assuming. --- etc/mkinitcpio.conf.d/thunderbolt_module.conf | 8 +++++++- install/post-install/pacman.sh | 10 ++++++++-- install/user/mise-work.sh | 9 +++++++-- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/etc/mkinitcpio.conf.d/thunderbolt_module.conf b/etc/mkinitcpio.conf.d/thunderbolt_module.conf index 9518f8b1201..2f145bb5534 100644 --- a/etc/mkinitcpio.conf.d/thunderbolt_module.conf +++ b/etc/mkinitcpio.conf.d/thunderbolt_module.conf @@ -1 +1,7 @@ -MODULES+=(thunderbolt) +# Thunderbolt is x86-oriented hardware and the module is not built for every +# architecture -- ALARM's aarch64 kernel has no `thunderbolt`. mkinitcpio treats +# an unresolvable MODULES entry as an error, which fails every initramfs build +# on such a system, so gate it rather than forcing it unconditionally. +if [[ $(uname -m) == x86_64 ]]; then + MODULES+=(thunderbolt) +fi diff --git a/install/post-install/pacman.sh b/install/post-install/pacman.sh index 23580b3c527..ebfed2b609c 100644 --- a/install/post-install/pacman.sh +++ b/install/post-install/pacman.sh @@ -1,7 +1,13 @@ # Configure pacman after package installation completes. Offline target package # installs use the live ISO's offline pacman.conf until this final restore. -cp -f "$OMARCHY_PATH/default/pacman/pacman-${OMARCHY_MIRROR:-stable}.conf" /etc/pacman.conf -cp -f "$OMARCHY_PATH/default/pacman/mirrorlist-${OMARCHY_MIRROR:-stable}" /etc/pacman.d/mirrorlist +# Omarchy's pacman.conf points [core]/[extra]/[multilib] at Omarchy's mirror of +# Arch (x86_64 only) and [omarchy] at pkgs.omarchy.org/$arch, which 404s for +# aarch64. Applying it on ARM leaves the installed system unable to update at +# all, so keep the working configuration there. +if [[ $(uname -m) == x86_64 ]]; then + cp -f "$OMARCHY_PATH/default/pacman/pacman-${OMARCHY_MIRROR:-stable}.conf" /etc/pacman.conf + cp -f "$OMARCHY_PATH/default/pacman/mirrorlist-${OMARCHY_MIRROR:-stable}" /etc/pacman.d/mirrorlist +fi # omarchy-settings skips this override until cups-browsed is actually present # to avoid pacman creating cups-browsed.conf.pacnew during ISO package install. diff --git a/install/user/mise-work.sh b/install/user/mise-work.sh index f77d5561e0e..17ea1e25df9 100644 --- a/install/user/mise-work.sh +++ b/install/user/mise-work.sh @@ -19,7 +19,12 @@ case ${OMARCHY_SETUP_CONTEXT:-runtime} in esac if [[ -n $NODE_PACKAGE_DIR ]]; then - NODE_TARBALL=$(find "$NODE_PACKAGE_DIR" -name "node-v*-linux-x64.tar.gz" -type f 2>/dev/null | head -n1) + # Node names its builds x64/arm64, not by uname + case "$(uname -m)" in + aarch64) _NODE_ARCH=arm64 ;; + *) _NODE_ARCH=x64 ;; + esac + NODE_TARBALL=$(find "$NODE_PACKAGE_DIR" -name "node-v*-linux-${_NODE_ARCH}.tar.gz" -type f 2>/dev/null | head -n1) if [[ -z $NODE_TARBALL ]]; then if [[ ${OMARCHY_SETUP_CONTEXT:-} == "provision-owner" ]]; then # A factory snapshot predating the bundled tarball may not have it staged. @@ -31,7 +36,7 @@ if [[ -n $NODE_PACKAGE_DIR ]]; then exit 1 fi else - NODE_VERSION=$(basename "$NODE_TARBALL" | sed 's/node-v\(.*\)-linux-x64.tar.gz/\1/') + NODE_VERSION=$(basename "$NODE_TARBALL" | sed "s/node-v\\(.*\\)-linux-${_NODE_ARCH}.tar.gz/\\1/") NODE_INSTALL_DIR="$HOME/.local/share/mise/installs/node/$NODE_VERSION" mkdir -p "$NODE_INSTALL_DIR" From ec595d9f96afcad8ccff7313bc1a5e75269518f7 Mon Sep 17 00:00:00 2001 From: Sean Date: Wed, 26 Aug 2026 16:25:42 +0800 Subject: [PATCH 02/15] Derive an aarch64 pacman.conf instead of skipping the restore The previous guard skipped the pacman.conf restore on aarch64 on the grounds that Omarchy's config points at x86-only repositories. But at that point the target still carries the live ISO's pacman.conf, which knows only the offline mirror, and that directory does not exist on the installed system. Skipping therefore left every aarch64 install unable to run pacman at all, which is the outcome the guard claimed to prevent. Derive the config from Omarchy's template instead: drop [multilib], keep [omarchy] (its $arch placeholder resolves correctly), add Arch Linux ARM's [alarm] and [aur] repositories, and leave the mirrorlist the distribution installed rather than replacing it with Omarchy's x86_64 mirror of Arch. The x86_64 path is unchanged. --- install/post-install/pacman.sh | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/install/post-install/pacman.sh b/install/post-install/pacman.sh index ebfed2b609c..dcf39563ce6 100644 --- a/install/post-install/pacman.sh +++ b/install/post-install/pacman.sh @@ -1,13 +1,31 @@ # Configure pacman after package installation completes. Offline target package # installs use the live ISO's offline pacman.conf until this final restore. -# Omarchy's pacman.conf points [core]/[extra]/[multilib] at Omarchy's mirror of -# Arch (x86_64 only) and [omarchy] at pkgs.omarchy.org/$arch, which 404s for -# aarch64. Applying it on ARM leaves the installed system unable to update at -# all, so keep the working configuration there. -if [[ $(uname -m) == x86_64 ]]; then - cp -f "$OMARCHY_PATH/default/pacman/pacman-${OMARCHY_MIRROR:-stable}.conf" /etc/pacman.conf - cp -f "$OMARCHY_PATH/default/pacman/mirrorlist-${OMARCHY_MIRROR:-stable}" /etc/pacman.d/mirrorlist -fi +case "$(uname -m)" in + aarch64) + # Omarchy's pacman.conf and mirrorlist describe an x86_64 Arch system: + # [multilib] is 32-bit x86 libraries and no ARM mirror carries it, and the + # mirrorlist points at Omarchy's mirror of Arch, which is x86_64 only. + # Arch Linux ARM also lays its tree out as $arch/$repo rather than Arch's + # $repo/os/$arch, so the mirrorlist cannot be reused with a different host. + # + # Derive the config from Omarchy's instead: drop [multilib], keep [omarchy] + # (its $arch placeholder resolves correctly), add Arch Linux ARM's own + # [alarm] and [aur] repositories, and leave the mirrorlist the distribution + # installed. Skipping this step is not an option: the live ISO's pacman.conf + # only knows the offline mirror, which does not exist on the installed system. + awk ' + /^\[multilib\]$/ { skip = 1; next } + /^\[/ { skip = 0 } + skip { next } + { print } + ' "$OMARCHY_PATH/default/pacman/pacman-${OMARCHY_MIRROR:-stable}.conf" >/etc/pacman.conf + printf '\n[alarm]\nInclude = /etc/pacman.d/mirrorlist\n\n[aur]\nInclude = /etc/pacman.d/mirrorlist\n' >>/etc/pacman.conf + ;; + *) + cp -f "$OMARCHY_PATH/default/pacman/pacman-${OMARCHY_MIRROR:-stable}.conf" /etc/pacman.conf + cp -f "$OMARCHY_PATH/default/pacman/mirrorlist-${OMARCHY_MIRROR:-stable}" /etc/pacman.d/mirrorlist + ;; +esac # omarchy-settings skips this override until cups-browsed is actually present # to avoid pacman creating cups-browsed.conf.pacnew during ISO package install. From 58b799cbb87e128407544b5a83620e2eb292fda2 Mon Sep 17 00:00:00 2001 From: Jimmy Van Veen Date: Tue, 25 Aug 2026 22:21:53 -0400 Subject: [PATCH 03/15] Carry the Windows-on-ARM device trees in every UKI on Qualcomm SoCs Snapdragon laptops boot with the device tree for their exact model and the firmware provides none. The live ISO already boots them with a systemd-stub UKI that carries every candidate tree as .dtbauto sections and picks one by SMBIOS hardware id; the installed system built its UKIs with no tree at all, so the first reboot after the install had nothing to boot. Add the omarchy-hw-qualcomm-soc probe (root device-tree compatible starts with qcom,) and a hardware leaf that lists the trees in /etc/kernel/uki.conf, which mkinitcpio hands to ukify for every UKI limine-mkinitcpio-hook builds. The list is a snapshot of /boot/dtbs/qcom taken when the leaf runs; the file header says so, and the enumeration retires when ukify accepts globs. --- bin/omarchy-hw-qualcomm-soc | 10 +++++++ install/hardware/all.sh | 3 ++ install/hardware/qualcomm/dtb-uki.sh | 42 ++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+) create mode 100755 bin/omarchy-hw-qualcomm-soc create mode 100644 install/hardware/qualcomm/dtb-uki.sh diff --git a/bin/omarchy-hw-qualcomm-soc b/bin/omarchy-hw-qualcomm-soc new file mode 100755 index 00000000000..a32865e5612 --- /dev/null +++ b/bin/omarchy-hw-qualcomm-soc @@ -0,0 +1,10 @@ +#!/bin/bash + +# omarchy:summary=Detect whether the computer runs on a Qualcomm SoC booted with its device tree (Snapdragon X and friends). + +# The Adreno GPU, the Wi-Fi and the rest of a Qualcomm SoC are platform devices, +# so neither lspci nor DMI can tell a Snapdragon laptop apart. The device tree +# can: every Qualcomm board's root node lists the SoC as a `qcom,` +# compatible, and it is there whenever the machine was booted with a device +# tree, which is how Omarchy boots Windows-on-ARM laptops. +tr '\0' '\n' /dev/null | grep -q '^qcom,' diff --git a/install/hardware/all.sh b/install/hardware/all.sh index 9b54d1c0192..c428e06acb6 100644 --- a/install/hardware/all.sh +++ b/install/hardware/all.sh @@ -41,6 +41,9 @@ run_logged "$OMARCHY_INSTALL/hardware/apple/fix-suspend-nvme.sh" run_logged "$OMARCHY_INSTALL/hardware/apple/fix-t2.sh" run_logged "$OMARCHY_INSTALL/hardware/apple/fix-brcmfmac-supplicant.sh" +run_logged "$OMARCHY_INSTALL/hardware/qualcomm/dtb-uki.sh" +run_logged "$OMARCHY_INSTALL/hardware/qualcomm/kernel-params.sh" + run_logged "$OMARCHY_INSTALL/hardware/lenovo/fix-yoga-pro7-bass-speakers.sh" run_logged "$OMARCHY_INSTALL/hardware/fix-bcm43xx.sh" diff --git a/install/hardware/qualcomm/dtb-uki.sh b/install/hardware/qualcomm/dtb-uki.sh new file mode 100644 index 00000000000..94d30f176d3 --- /dev/null +++ b/install/hardware/qualcomm/dtb-uki.sh @@ -0,0 +1,42 @@ +# Snapdragon laptops boot with the device tree that describes the exact model, +# and their Windows-on-ARM firmware provides none. A systemd-stub UKI can carry +# every candidate as a .dtbauto section and pick the right one at boot from the +# machine's SMBIOS hardware ids (the .hwids section ukify builds from systemd's +# tables). mkinitcpio hands ukify /etc/kernel/uki.conf when it exists, so listing +# the device trees there makes every UKI limine-mkinitcpio-hook builds pick its +# own tree, on this machine and after every kernel update. +# +# Limitation: DeviceTreeAuto= takes literal paths, not globs, so this is a +# snapshot of /boot/dtbs/qcom from when the leaf ran. A kernel update that adds +# a new board's tree needs `omarchy apply hardware` to refresh the list. Retire +# the enumeration when ukify accepts globs in DeviceTreeAuto=. +# +# Same prefixes as the Omarchy ISO's live UKI: Snapdragon X Elite/Plus (x1*), +# X2 (hamoa*, glymur*) and 8cx Gen 3 (sc8280xp*). The -el2 variants exist for +# running the kernel at EL2, which this firmware does not. + +if omarchy-hw-qualcomm-soc; then + omarchy-pkg-add systemd-ukify + + dtbs=() + for dtb in /boot/dtbs/qcom/x1*.dtb /boot/dtbs/qcom/hamoa*.dtb \ + /boot/dtbs/qcom/glymur*.dtb /boot/dtbs/qcom/sc8280xp*.dtb; do + if [[ -f $dtb && $dtb != *-el2.dtb ]]; then + dtbs+=("$dtb") + fi + done + + if ((${#dtbs[@]} == 0)); then + echo "No Windows-on-ARM device trees under /boot/dtbs/qcom; the UKI gets no .dtbauto sections" >&2 + else + mkdir -p /etc/kernel + { + echo "# Generated by Omarchy for Qualcomm Snapdragon devices (install/hardware/qualcomm/dtb-uki.sh)." + echo "# Device trees the systemd-stub picks from at boot by SMBIOS hardware id." + echo "# Rerun 'omarchy apply hardware' after a kernel update adds new boards." + echo "[UKI]" + echo "DeviceTreeAuto=${dtbs[*]}" + } >/etc/kernel/uki.conf + echo "Listed ${#dtbs[@]} device trees in /etc/kernel/uki.conf" + fi +fi From 71268d3da9e635dc1382b36c7fb95f26e021ed21 Mon Sep 17 00:00:00 2001 From: Jimmy Van Veen Date: Tue, 25 Aug 2026 22:21:54 -0400 Subject: [PATCH 04/15] Kernel parameters Snapdragon laptops need under Windows-on-ARM firmware The same set Fedora's Snapdragon images and the live ISO carry, as a limine-entry-tool drop-in so limine-update folds it into every entry, with each parameter's reason and retirement condition in the file. --- install/hardware/qualcomm/kernel-params.sh | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 install/hardware/qualcomm/kernel-params.sh diff --git a/install/hardware/qualcomm/kernel-params.sh b/install/hardware/qualcomm/kernel-params.sh new file mode 100644 index 00000000000..c9dad320ea5 --- /dev/null +++ b/install/hardware/qualcomm/kernel-params.sh @@ -0,0 +1,20 @@ +# Kernel parameters Snapdragon laptops need under their Windows-on-ARM firmware: +# the set Fedora's Snapdragon images and archiso carry, measured on the HP +# EliteBook Ultra G1q (X1E-78-100). Retire each one when the kernel no longer +# needs it; Fedora's images are the tell. + +DROP_IN="/etc/limine-entry-tool.d/qualcomm-snapdragon.conf" + +if omarchy-hw-qualcomm-soc; then + mkdir -p /etc/limine-entry-tool.d + cat >"$DROP_IN" <<'CONF' +# Generated by Omarchy for Qualcomm Snapdragon devices (install/hardware/qualcomm/kernel-params.sh) +# clk_ignore_unused pd_ignore_unused -- display and I/O drivers load from the +# initramfs after the kernel would otherwise switch their clocks and power +# domains off; the screen goes dark at 15 s without them. +# arm64.nopauth -- pointer authentication faults under this firmware. +# systemd.tpm2_wait=0 -- the firmware advertises a TPM2 Linux never gets; +# without this, a 90 s wait for /dev/tpmrm0 on every boot. +KERNEL_CMDLINE[default]+=" clk_ignore_unused pd_ignore_unused arm64.nopauth systemd.tpm2_wait=0" +CONF +fi From 7f79a0e4c22870d99efbcdb9bcd70037a9d5f5e9 Mon Sep 17 00:00:00 2001 From: Jimmy Van Veen Date: Tue, 25 Aug 2026 22:21:55 -0400 Subject: [PATCH 05/15] Install the Adreno Vulkan driver on Qualcomm SoCs Adreno GPUs are platform devices, so the lspci vendor scan in vulkan.sh never sees them; ask the SoC probe instead. --- install/hardware/vulkan.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/install/hardware/vulkan.sh b/install/hardware/vulkan.sh index a2447d46ffa..e13de205b8c 100644 --- a/install/hardware/vulkan.sh +++ b/install/hardware/vulkan.sh @@ -15,6 +15,11 @@ for vendor in "${!VULKAN_DRIVERS[@]}"; do fi done +# Adreno GPUs are platform devices, so lspci never sees them. +if omarchy-hw-qualcomm-soc; then + PACKAGES+=(vulkan-freedreno) +fi + if (( ${#PACKAGES[@]} > 0 )); then omarchy-pkg-add "${PACKAGES[@]}" fi From ba798d5ec81dc83ed121fa44de52913fd18bf032 Mon Sep 17 00:00:00 2001 From: Jimmy Van Veen Date: Wed, 26 Aug 2026 11:51:09 -0400 Subject: [PATCH 06/15] Qualcomm firmware package, and blacklist the audio DSP until its blobs exist Arch Linux ARM keeps the redistributable Qualcomm blobs in linux-firmware-qcom; the installed system had none of them. The vendor-signed DSP firmware comes later from the owner's Windows partition; until it is there the DSP driver's failing probe resets the USB-C mux, which drops a USB-C root disk and hangs the boot (seen on the HP EliteBook Ultra G1q). --- install/hardware/all.sh | 1 + install/hardware/qualcomm/firmware.sh | 29 +++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 install/hardware/qualcomm/firmware.sh diff --git a/install/hardware/all.sh b/install/hardware/all.sh index c428e06acb6..3f69ca9f713 100644 --- a/install/hardware/all.sh +++ b/install/hardware/all.sh @@ -43,6 +43,7 @@ run_logged "$OMARCHY_INSTALL/hardware/apple/fix-brcmfmac-supplicant.sh" run_logged "$OMARCHY_INSTALL/hardware/qualcomm/dtb-uki.sh" run_logged "$OMARCHY_INSTALL/hardware/qualcomm/kernel-params.sh" +run_logged "$OMARCHY_INSTALL/hardware/qualcomm/firmware.sh" run_logged "$OMARCHY_INSTALL/hardware/lenovo/fix-yoga-pro7-bass-speakers.sh" diff --git a/install/hardware/qualcomm/firmware.sh b/install/hardware/qualcomm/firmware.sh new file mode 100644 index 00000000000..9a85b9e0637 --- /dev/null +++ b/install/hardware/qualcomm/firmware.sh @@ -0,0 +1,29 @@ +# Firmware for the Qualcomm SoC. Arch Linux ARM splits the redistributable +# Qualcomm blobs out of linux-firmware into linux-firmware-qcom (Adreno GPU +# microcode, Wi-Fi/Bluetooth board data); without it the GPU and Wi-Fi never +# come up. The device-specific blobs signed by the laptop vendor (GPU zap +# shader, audio/compute DSP, WLAN/BT) are not redistributable and are +# extracted from the owner's Windows partition instead (qcom-firmware-extract). +# +# Until those signed blobs are present the audio DSP driver cannot load its +# firmware; its probe resets the USB-C mux while it fails, which drops a root +# disk attached over USB-C and hangs the boot. Keep it blacklisted while the +# DSP firmware is absent; the file is removed when the blobs are installed. + +if omarchy-hw-qualcomm-soc; then + omarchy-pkg-add linux-firmware-qcom + + mkdir -p /etc/modprobe.d + if compgen -G '/usr/lib/firmware/updates/qcom/*/adsp*' >/dev/null || + compgen -G '/usr/lib/firmware/qcom/*/*/adsp*' >/dev/null; then + rm -f /etc/modprobe.d/qualcomm-adsp-nofw.conf + else + cat >/etc/modprobe.d/qualcomm-adsp-nofw.conf <<'CONF' +# Generated by Omarchy for Qualcomm Snapdragon devices (install/hardware/qualcomm/firmware.sh) +# No signed audio-DSP firmware is installed yet; the driver's failing probe +# resets the USB-C mux and can take a USB-C root disk down with it. Removed +# by the same leaf once the firmware is present. +blacklist qcom_q6v5_pas +CONF + fi +fi From 90e9194e6277343e28b54359122f1bb152205205 Mon Sep 17 00:00:00 2001 From: Jimmy Van Veen Date: Wed, 26 Aug 2026 15:11:23 -0400 Subject: [PATCH 07/15] Copy the vendor-signed Qualcomm firmware from Windows during install install/hardware/qualcomm/firmware.sh installs qcom-firmware-extract next to linux-firmware-qcom and runs it in the target: the files the device tree names (GPU zap shader, audio and compute DSP images) are taken from the stage the ISO saved before the disk was written, or from a Windows partition still on disk, into /usr/lib/firmware/updates. The audio-DSP blacklist now follows what is actually missing (qcom-firmware-extract --list-missing) instead of a path glob, so it clears itself once the firmware is present. install/omarchy-other.packages lists qcom-firmware-extract (arch=any) so the offline mirror carries it. --- install/hardware/qualcomm/firmware.sh | 38 ++++++++++++++++----------- install/omarchy-other.packages | 3 +++ 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/install/hardware/qualcomm/firmware.sh b/install/hardware/qualcomm/firmware.sh index 9a85b9e0637..b196a768fc8 100644 --- a/install/hardware/qualcomm/firmware.sh +++ b/install/hardware/qualcomm/firmware.sh @@ -1,23 +1,29 @@ -# Firmware for the Qualcomm SoC. Arch Linux ARM splits the redistributable -# Qualcomm blobs out of linux-firmware into linux-firmware-qcom (Adreno GPU -# microcode, Wi-Fi/Bluetooth board data); without it the GPU and Wi-Fi never -# come up. The device-specific blobs signed by the laptop vendor (GPU zap -# shader, audio/compute DSP, WLAN/BT) are not redistributable and are -# extracted from the owner's Windows partition instead (qcom-firmware-extract). +# Firmware for the Qualcomm SoC. # -# Until those signed blobs are present the audio DSP driver cannot load its -# firmware; its probe resets the USB-C mux while it fails, which drops a root -# disk attached over USB-C and hangs the boot. Keep it blacklisted while the -# DSP firmware is absent; the file is removed when the blobs are installed. +# Arch Linux ARM splits the redistributable Qualcomm blobs out of +# linux-firmware into linux-firmware-qcom (Adreno GPU microcode, Wi-Fi and +# Bluetooth board data); without it the GPU and Wi-Fi never come up. +# +# The blobs signed by the laptop vendor (GPU zap shader, audio and compute DSP +# images) are not redistributable. qcom-firmware-extract copies the ones this +# machine's device tree names from the owner's own Windows installation: the +# ISO staged them before the disk was written, and a free-space install still +# has the Windows partition on disk. The installer builds the boot image once +# after every hardware leaf has run, so nothing is rebuilt here. +# +# Until the audio DSP firmware is present its driver cannot load; the failing +# probe resets the USB-C mux, which drops a root disk attached over USB-C and +# hangs the boot. Keep the driver blacklisted while that firmware is absent; +# the file is removed once the firmware is installed (re-run +# `sudo qcom-firmware-extract` after providing it). if omarchy-hw-qualcomm-soc; then - omarchy-pkg-add linux-firmware-qcom + omarchy-pkg-add linux-firmware-qcom qcom-firmware-extract + + qcom-firmware-extract --install --no-rebuild mkdir -p /etc/modprobe.d - if compgen -G '/usr/lib/firmware/updates/qcom/*/adsp*' >/dev/null || - compgen -G '/usr/lib/firmware/qcom/*/*/adsp*' >/dev/null; then - rm -f /etc/modprobe.d/qualcomm-adsp-nofw.conf - else + if qcom-firmware-extract --list-missing | grep -q 'adsp'; then cat >/etc/modprobe.d/qualcomm-adsp-nofw.conf <<'CONF' # Generated by Omarchy for Qualcomm Snapdragon devices (install/hardware/qualcomm/firmware.sh) # No signed audio-DSP firmware is installed yet; the driver's failing probe @@ -25,5 +31,7 @@ if omarchy-hw-qualcomm-soc; then # by the same leaf once the firmware is present. blacklist qcom_q6v5_pas CONF + else + rm -f /etc/modprobe.d/qualcomm-adsp-nofw.conf fi fi diff --git a/install/omarchy-other.packages b/install/omarchy-other.packages index e5d56d566fe..1a7be9fec7b 100644 --- a/install/omarchy-other.packages +++ b/install/omarchy-other.packages @@ -75,3 +75,6 @@ t2fanrd # Framework 16 qmk-hid + +# Qualcomm Snapdragon support packages +qcom-firmware-extract From 9a6dc239f6da7431e4746a8d528b4970805a2e65 Mon Sep 17 00:00:00 2001 From: Jimmy Van Veen Date: Wed, 26 Aug 2026 16:24:51 -0400 Subject: [PATCH 08/15] Keep the Qualcomm DSPs off when the root disk is on USB With real DSP firmware the Type-C port controller takes over the ports once the ADSP is up and resets them, which drops a root disk behind a USB-C port (G1q, external NVMe: cdsp up at 10.8 s, I/O errors and a read-only root at 22 s). Installs whose root disk reports TRAN=usb keep qcom_q6v5_pas blacklisted (no audio or battery reporting) until the kernel stops resetting connected ports; internal-disk installs are unchanged. --- install/hardware/qualcomm/firmware.sh | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/install/hardware/qualcomm/firmware.sh b/install/hardware/qualcomm/firmware.sh index b196a768fc8..317f5677164 100644 --- a/install/hardware/qualcomm/firmware.sh +++ b/install/hardware/qualcomm/firmware.sh @@ -23,7 +23,23 @@ if omarchy-hw-qualcomm-soc; then qcom-firmware-extract --install --no-rebuild mkdir -p /etc/modprobe.d - if qcom-firmware-extract --list-missing | grep -q 'adsp'; then + if lsblk -sno TRAN "$(findmnt -no SOURCE /)" 2>/dev/null | grep -q '^usb$'; then + # Root disk on USB. When the DSPs boot with real firmware the Type-C port + # controller (pmic_glink/UCSI) takes over the ports and resets them, which + # drops a root disk behind a USB-C port (observed on the HP EliteBook Ultra + # G1q, JimmayVV/omarchy-iso#27). Keep the DSPs off on such installs: no + # audio or battery reporting, but the system boots. RETIRE when the kernel + # stops resetting an already-connected port (#27). + cat >/etc/modprobe.d/qualcomm-adsp-nofw.conf <<'CONF' +# Generated by Omarchy for Qualcomm Snapdragon devices (install/hardware/qualcomm/firmware.sh) +# The root disk is attached over USB. Booting the DSPs hands the USB-C ports +# to the port controller, which resets them and drops the root disk. Keep the +# DSP driver off on this install (no audio or battery reporting) until the +# kernel stops resetting connected ports; delete this file after moving the +# system to an internal disk. +blacklist qcom_q6v5_pas +CONF + elif qcom-firmware-extract --list-missing | grep -q 'adsp'; then cat >/etc/modprobe.d/qualcomm-adsp-nofw.conf <<'CONF' # Generated by Omarchy for Qualcomm Snapdragon devices (install/hardware/qualcomm/firmware.sh) # No signed audio-DSP firmware is installed yet; the driver's failing probe From 96995451b6151812d4543e96e8f906a78d7e1b83 Mon Sep 17 00:00:00 2001 From: Jimmy Van Veen Date: Wed, 26 Aug 2026 19:35:12 -0400 Subject: [PATCH 09/15] Give an aarch64 install Arch Linux ARM's package sources The final pacman restore is skipped entirely on ARM, which leaves the installed system pointed at the live ISO's offline config -- a file:// repo under a bind mount that only exists during the install. The first thing a new aarch64 desktop does is fail: $ sudo pacman -Sy evtest failed retrieving file 'offline.db' from disk: Could not open file /var/cache/omarchy/mirror/offline/offline.db No pacman -S, no omarchy-update. The skip was right that Omarchy's channel configs cannot be applied on ARM -- [core]/[extra] come from Omarchy's mirror of Arch, which builds x86_64 only, [multilib] is 32-bit x86, and the Omarchy package repository serves no aarch64 tree -- but the configuration it keeps instead is the offline one, so it trades a broken config for no config. Restore Arch Linux ARM's repositories there instead: [core] [extra] [alarm] [aur], its stock set, through a mirrorlist of its own because ALARM serves $arch/$repo where Arch serves $repo/os/$arch. [options] is kept byte-identical to the x86_64 channel configs. [omarchy] is left out until that tree exists; including it would 404 on every sync, and Omarchy's own packages simply hold at the versions the ISO installed. Three further things the restore has to do that the x86_64 path does not: - Take archlinuxarm-keyring while the offline mirror is still the active source. Arch's `base` pulls in archlinux-keyring and nothing pulls in this one, and the repositories being written are unreachable during an offline install. - Write the mirrorlist unconditionally. The target's mirrorlist carries Omarchy's and Arch's x86_64 mirrors ahead of ALARM's, so a sync logs 404s from mirror.omarchy.org, mirror.rackspace.com and geo.mirror.pkgbuild.com before it finds anything. - Populate the keyring. The install leaves ALARM's build key untrusted on the target, so the first signed install fails with "Arch Linux ARM Build System is unknown trust". x86_64 keeps running the same two lines it ran before, and every other architecture keeps the behaviour it had before the skip was introduced. --- default/pacman/mirrorlist-aarch64 | 6 ++++ default/pacman/pacman-aarch64.conf | 53 ++++++++++++++++++++++++++++++ install/post-install/pacman.sh | 51 ++++++++++++++-------------- 3 files changed, 84 insertions(+), 26 deletions(-) create mode 100644 default/pacman/mirrorlist-aarch64 create mode 100644 default/pacman/pacman-aarch64.conf diff --git a/default/pacman/mirrorlist-aarch64 b/default/pacman/mirrorlist-aarch64 new file mode 100644 index 00000000000..3aebd0e77a3 --- /dev/null +++ b/default/pacman/mirrorlist-aarch64 @@ -0,0 +1,6 @@ +# Arch Linux ARM's geo-IP balanced mirror, as shipped by its own +# pacman-mirrorlist. Note the layout: ALARM serves $arch/$repo, where Arch (and +# so Omarchy's mirror of it) serves $repo/os/$arch, which is why the x86_64 +# mirrorlists cannot simply be repointed. HTTP is what ALARM publishes; package +# and database signatures are what integrity rests on either way. +Server = http://mirror.archlinuxarm.org/$arch/$repo diff --git a/default/pacman/pacman-aarch64.conf b/default/pacman/pacman-aarch64.conf new file mode 100644 index 00000000000..fd3ef87edff --- /dev/null +++ b/default/pacman/pacman-aarch64.conf @@ -0,0 +1,53 @@ +# See the pacman.conf(5) manpage for option and repository directives +# +# Package sources for an aarch64 install (see install/post-install/pacman.sh). +# Omarchy's pacman-.conf files describe an x86_64 machine: +# [core]/[extra]/[multilib] come from Omarchy's mirror of Arch, which builds +# x86_64 only, and [multilib] is 32-bit x86 libraries that exist on no ARM +# mirror at all. Arch Linux ARM supplies the equivalents here. +# +# [options] is kept byte-identical to the x86_64 channel configs so the two +# architectures behave the same; only the repository list differs. +# +# One file, not one per channel, because Arch Linux ARM has no channels and the +# only channel-varying section -- [omarchy] -- is absent below. Retire that +# when the Omarchy package repository serves aarch64: this then splits into +# pacman-{stable,rc,edge}-aarch64.conf exactly as the x86_64 files do. + +[options] +Color +ILoveCandy +VerbosePkgLists +HoldPkg = pacman glibc +Architecture = auto +CheckSpace +ParallelDownloads = 5 +DownloadUser = alpm + +# By default, pacman accepts packages signed by keys that its local keyring +# trusts (see pacman-key and its man page), as well as unsigned packages. +SigLevel = Required DatabaseOptional +LocalFileSigLevel = Optional + +# pacman searches repositories in the order defined here. +# +# [core] [extra] [alarm] [aur] is Arch Linux ARM's stock set. [alarm] carries +# its ARM-specific packages; [aur] carries its builds of AUR-origin packages, +# which on x86_64 Omarchy ships from [omarchy] instead. Deviating from the +# distribution default needs a reason, and there isn't one yet. +[core] +Include = /etc/pacman.d/mirrorlist + +[extra] +Include = /etc/pacman.d/mirrorlist + +[alarm] +Include = /etc/pacman.d/mirrorlist + +[aur] +Include = /etc/pacman.d/mirrorlist + +# [omarchy] is deliberately absent: the Omarchy package repository serves no +# aarch64 tree, so including it makes every pacman -Sy fail on a 404. Omarchy's +# own packages stay at the versions the ISO installed until that tree exists; +# everything else updates normally. Restore the section when it does. diff --git a/install/post-install/pacman.sh b/install/post-install/pacman.sh index dcf39563ce6..a98cd89b6c7 100644 --- a/install/post-install/pacman.sh +++ b/install/post-install/pacman.sh @@ -1,31 +1,30 @@ # Configure pacman after package installation completes. Offline target package # installs use the live ISO's offline pacman.conf until this final restore. -case "$(uname -m)" in - aarch64) - # Omarchy's pacman.conf and mirrorlist describe an x86_64 Arch system: - # [multilib] is 32-bit x86 libraries and no ARM mirror carries it, and the - # mirrorlist points at Omarchy's mirror of Arch, which is x86_64 only. - # Arch Linux ARM also lays its tree out as $arch/$repo rather than Arch's - # $repo/os/$arch, so the mirrorlist cannot be reused with a different host. - # - # Derive the config from Omarchy's instead: drop [multilib], keep [omarchy] - # (its $arch placeholder resolves correctly), add Arch Linux ARM's own - # [alarm] and [aur] repositories, and leave the mirrorlist the distribution - # installed. Skipping this step is not an option: the live ISO's pacman.conf - # only knows the offline mirror, which does not exist on the installed system. - awk ' - /^\[multilib\]$/ { skip = 1; next } - /^\[/ { skip = 0 } - skip { next } - { print } - ' "$OMARCHY_PATH/default/pacman/pacman-${OMARCHY_MIRROR:-stable}.conf" >/etc/pacman.conf - printf '\n[alarm]\nInclude = /etc/pacman.d/mirrorlist\n\n[aur]\nInclude = /etc/pacman.d/mirrorlist\n' >>/etc/pacman.conf - ;; - *) - cp -f "$OMARCHY_PATH/default/pacman/pacman-${OMARCHY_MIRROR:-stable}.conf" /etc/pacman.conf - cp -f "$OMARCHY_PATH/default/pacman/mirrorlist-${OMARCHY_MIRROR:-stable}" /etc/pacman.d/mirrorlist - ;; -esac +# Omarchy's channel configs describe an x86_64 machine, so aarch64 is restored +# to Arch Linux ARM's repositories instead; leaving the ISO's offline config in +# place there would end the install with no package sources at all. +if [[ $(uname -m) == aarch64 ]]; then + # Still on the offline pacman.conf at this point, which is the only reachable + # source during an offline install -- so take the keyring package now, before + # the repositories below replace it. Arch's `base` pulls in archlinux-keyring + # and nothing pulls in this one; the ISO carries it for exactly this step. + omarchy-pkg-add archlinuxarm-keyring + + cp -f "$OMARCHY_PATH/default/pacman/pacman-aarch64.conf" /etc/pacman.conf + cp -f "$OMARCHY_PATH/default/pacman/mirrorlist-aarch64" /etc/pacman.d/mirrorlist + + # Arch Linux ARM signs its repositories with its own key, and the install + # leaves that key untrusted on the target: the first signed sync fails with + # "Arch Linux ARM Build System is unknown trust". + # --init is a no-op on an initialised keyring, and --populate without an + # argument locally signs every keyring installed -- archlinux for the `any` + # packages Arch builds, archlinuxarm for the rest. + pacman-key --init + pacman-key --populate +else + cp -f "$OMARCHY_PATH/default/pacman/pacman-${OMARCHY_MIRROR:-stable}.conf" /etc/pacman.conf + cp -f "$OMARCHY_PATH/default/pacman/mirrorlist-${OMARCHY_MIRROR:-stable}" /etc/pacman.d/mirrorlist +fi # omarchy-settings skips this override until cups-browsed is actually present # to avoid pacman creating cups-browsed.conf.pacnew during ISO package install. From 05159a4a3897a1109a51f83f456c649b2598e326 Mon Sep 17 00:00:00 2001 From: Birk Skyum Date: Thu, 27 Aug 2026 22:29:04 +0200 Subject: [PATCH 10/15] Add Yoga Slim 7x board support --- install/hardware/all.sh | 1 + .../lenovo/start-yoga-slim7x-remoteprocs.sh | 40 +++++++++++++++++ install/hardware/lenovo/yoga-slim7x.sh | 44 +++++++++++++++++++ test/shell.d/yoga-slim7x-hardware-test.sh | 39 ++++++++++++++++ 4 files changed, 124 insertions(+) create mode 100644 install/hardware/lenovo/start-yoga-slim7x-remoteprocs.sh create mode 100644 install/hardware/lenovo/yoga-slim7x.sh create mode 100644 test/shell.d/yoga-slim7x-hardware-test.sh diff --git a/install/hardware/all.sh b/install/hardware/all.sh index 3f69ca9f713..7e47477fa74 100644 --- a/install/hardware/all.sh +++ b/install/hardware/all.sh @@ -46,6 +46,7 @@ run_logged "$OMARCHY_INSTALL/hardware/qualcomm/kernel-params.sh" run_logged "$OMARCHY_INSTALL/hardware/qualcomm/firmware.sh" run_logged "$OMARCHY_INSTALL/hardware/lenovo/fix-yoga-pro7-bass-speakers.sh" +run_logged "$OMARCHY_INSTALL/hardware/lenovo/yoga-slim7x.sh" run_logged "$OMARCHY_INSTALL/hardware/fix-bcm43xx.sh" run_logged "$OMARCHY_INSTALL/hardware/fix-surface-keyboard.sh" diff --git a/install/hardware/lenovo/start-yoga-slim7x-remoteprocs.sh b/install/hardware/lenovo/start-yoga-slim7x-remoteprocs.sh new file mode 100644 index 00000000000..ec7a5c94197 --- /dev/null +++ b/install/hardware/lenovo/start-yoga-slim7x-remoteprocs.sh @@ -0,0 +1,40 @@ +#!/bin/bash + +set -euo pipefail + +remoteproc_root=${OMARCHY_YOGA_REMOTEPROC_ROOT:-/sys/class/remoteproc} +attempts=${OMARCHY_YOGA_REMOTEPROC_ATTEMPTS:-30} +sleep_seconds=${OMARCHY_YOGA_REMOTEPROC_SLEEP:-1} + +for ((attempt = 1; attempt <= attempts; attempt++)); do + adsp_started=0 + shopt -s nullglob + + for state_file in "$remoteproc_root"/remoteproc*/state; do + remoteproc=${state_file%/state} + [[ -r $remoteproc/firmware && -r $state_file ]] || continue + + firmware=$(tr -d '\0\n' <"$remoteproc/firmware") + case "$firmware" in + *qcadsp*) kind=ADSP ;; + *qccdsp*) kind=CDSP ;; + *) continue ;; + esac + + if [[ $(<$state_file) == running ]]; then + echo "Yoga Slim 7x: $kind is already running" + [[ $kind == ADSP ]] && adsp_started=1 + elif [[ -w $state_file ]] && printf 'start\n' >"$state_file"; then + echo "Yoga Slim 7x: started $kind" + [[ $kind == ADSP ]] && adsp_started=1 + else + echo "Yoga Slim 7x: could not start $kind ($firmware)" >&2 + fi + done + + ((adsp_started)) && exit 0 + sleep "$sleep_seconds" +done + +echo "Yoga Slim 7x: audio DSP did not appear or could not be started" >&2 +exit 1 diff --git a/install/hardware/lenovo/yoga-slim7x.sh b/install/hardware/lenovo/yoga-slim7x.sh new file mode 100644 index 00000000000..aa55ddb4eeb --- /dev/null +++ b/install/hardware/lenovo/yoga-slim7x.sh @@ -0,0 +1,44 @@ +# Lenovo Yoga Slim 7x (14Q8X9 / 83ED) details that are not common to every +# Snapdragon laptop. Generic DTB, firmware, Vulkan and kernel-cmdline setup is +# handled by install/hardware/qualcomm/. + +yoga_slim7x_compatible="" +if [[ -r /sys/firmware/devicetree/base/compatible ]]; then + yoga_slim7x_compatible=$(tr '\0' '\n' /etc/modules-load.d/yoga-slim7x.conf + + # Its internal keyboard and touchpad are HID-over-I2C. Keep their OF + # transport in the initramfs so encrypted installs can accept a passphrase. + mkdir -p /etc/mkinitcpio.conf.d + cat >/etc/mkinitcpio.conf.d/yoga-slim7x-initramfs.conf <<'CONF' +MODULES+=(i2c-hid-of) +CONF + + # On this board the ADSP remains offline after its firmware is installed. + # Starting it enables the speakers and microphone. The helper also starts + # the CDSP when present, but only the audio DSP is required for success. + cat >/etc/systemd/system/yoga-slim7x-remoteprocs.service <<'UNIT' +[Unit] +Description=Start the Lenovo Yoga Slim 7x DSPs +Wants=systemd-udev-settle.service +After=systemd-udev-settle.service + +[Service] +Type=oneshot +ExecStart=/bin/bash /usr/share/omarchy/install/hardware/lenovo/start-yoga-slim7x-remoteprocs.sh +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target +UNIT + systemctl enable yoga-slim7x-remoteprocs.service +fi diff --git a/test/shell.d/yoga-slim7x-hardware-test.sh b/test/shell.d/yoga-slim7x-hardware-test.sh new file mode 100644 index 00000000000..8e0fb7fbde8 --- /dev/null +++ b/test/shell.d/yoga-slim7x-hardware-test.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +set -euo pipefail + +source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh" + +setup="$ROOT/install/hardware/lenovo/yoga-slim7x.sh" +starter="$ROOT/install/hardware/lenovo/start-yoga-slim7x-remoteprocs.sh" +scratch=$(mktemp -d) +trap 'rm -rf "$scratch"' EXIT + +bash -n "$setup" "$starter" || fail "Yoga Slim 7x hardware scripts have valid syntax" +grep -Fq 'MODULES+=(i2c-hid-of)' "$setup" || + fail "Yoga Slim 7x setup keeps the internal keyboard in the initramfs" +grep -Fq 'scmi-cpufreq' "$setup" || + fail "Yoga Slim 7x setup loads its SCMI CPU-frequency driver" + +remoteprocs="$scratch/remoteproc" +mkdir -p "$remoteprocs/remoteproc0" "$remoteprocs/remoteproc1" "$remoteprocs/remoteproc2" +printf 'qcom/x1e80100/LENOVO/83ED/qcadsp8380.mbn\n' >"$remoteprocs/remoteproc0/firmware" +printf 'offline\n' >"$remoteprocs/remoteproc0/state" +printf 'qcom/x1e80100/LENOVO/83ED/qccdsp8380.mbn\n' >"$remoteprocs/remoteproc1/firmware" +printf 'offline\n' >"$remoteprocs/remoteproc1/state" +printf 'unrelated.mbn\n' >"$remoteprocs/remoteproc2/firmware" +printf 'offline\n' >"$remoteprocs/remoteproc2/state" + +OMARCHY_YOGA_REMOTEPROC_ROOT="$remoteprocs" \ + OMARCHY_YOGA_REMOTEPROC_ATTEMPTS=1 \ + OMARCHY_YOGA_REMOTEPROC_SLEEP=0 \ + bash "$starter" + +[[ $(<"$remoteprocs/remoteproc0/state") == start ]] || + fail "Yoga Slim 7x helper starts the audio DSP by firmware identity" +[[ $(<"$remoteprocs/remoteproc1/state") == start ]] || + fail "Yoga Slim 7x helper starts the compute DSP by firmware identity" +[[ $(<"$remoteprocs/remoteproc2/state") == offline ]] || + fail "Yoga Slim 7x helper leaves unrelated remote processors alone" + +pass "Yoga Slim 7x adds only its board-specific keyboard, CPU and DSP setup" From 0eeb6f35de690d90bce2c688bbc4bce79e2f0f42 Mon Sep 17 00:00:00 2001 From: Birk Skyum Date: Fri, 28 Aug 2026 02:43:41 +0200 Subject: [PATCH 11/15] Address Snapdragon setup review feedback --- install/hardware/qualcomm/dtb-uki.sh | 35 ++++++++++--- install/hardware/qualcomm/firmware.sh | 13 +++-- test/shell.d/snapdragon-hardware-test.sh | 67 ++++++++++++++++++++++++ 3 files changed, 104 insertions(+), 11 deletions(-) create mode 100644 test/shell.d/snapdragon-hardware-test.sh diff --git a/install/hardware/qualcomm/dtb-uki.sh b/install/hardware/qualcomm/dtb-uki.sh index 94d30f176d3..ea83d7cb1f3 100644 --- a/install/hardware/qualcomm/dtb-uki.sh +++ b/install/hardware/qualcomm/dtb-uki.sh @@ -18,25 +18,48 @@ if omarchy-hw-qualcomm-soc; then omarchy-pkg-add systemd-ukify + dtb_dir=${OMARCHY_QUALCOMM_DTB_DIR:-/boot/dtbs/qcom} + uki_config=${OMARCHY_QUALCOMM_UKI_CONFIG:-/etc/kernel/uki.conf} dtbs=() - for dtb in /boot/dtbs/qcom/x1*.dtb /boot/dtbs/qcom/hamoa*.dtb \ - /boot/dtbs/qcom/glymur*.dtb /boot/dtbs/qcom/sc8280xp*.dtb; do + for dtb in "$dtb_dir"/x1*.dtb "$dtb_dir"/hamoa*.dtb \ + "$dtb_dir"/glymur*.dtb "$dtb_dir"/sc8280xp*.dtb; do if [[ -f $dtb && $dtb != *-el2.dtb ]]; then dtbs+=("$dtb") fi done if ((${#dtbs[@]} == 0)); then - echo "No Windows-on-ARM device trees under /boot/dtbs/qcom; the UKI gets no .dtbauto sections" >&2 + echo "No Windows-on-ARM device trees under $dtb_dir; the UKI gets no .dtbauto sections" >&2 else - mkdir -p /etc/kernel + managed_begin="# BEGIN OMARCHY QUALCOMM DEVICE TREES" + managed_end="# END OMARCHY QUALCOMM DEVICE TREES" + + mkdir -p "$(dirname "$uki_config")" + uki_tmp=$(mktemp "${uki_config}.XXXXXX") + + if [[ -f $uki_config ]]; then + cp -p "$uki_config" "$uki_tmp" + awk -v begin="$managed_begin" -v end="$managed_end" ' + $0 == begin { managed = 1; next } + managed && $0 == end { managed = 0; next } + !managed { print } + ' "$uki_config" >"$uki_tmp" + else + chmod 0644 "$uki_tmp" + fi + { + echo + echo "$managed_begin" echo "# Generated by Omarchy for Qualcomm Snapdragon devices (install/hardware/qualcomm/dtb-uki.sh)." echo "# Device trees the systemd-stub picks from at boot by SMBIOS hardware id." echo "# Rerun 'omarchy apply hardware' after a kernel update adds new boards." echo "[UKI]" echo "DeviceTreeAuto=${dtbs[*]}" - } >/etc/kernel/uki.conf - echo "Listed ${#dtbs[@]} device trees in /etc/kernel/uki.conf" + echo "$managed_end" + } >>"$uki_tmp" + + mv -f "$uki_tmp" "$uki_config" + echo "Listed ${#dtbs[@]} device trees in $uki_config" fi fi diff --git a/install/hardware/qualcomm/firmware.sh b/install/hardware/qualcomm/firmware.sh index 317f5677164..dbde1eefb80 100644 --- a/install/hardware/qualcomm/firmware.sh +++ b/install/hardware/qualcomm/firmware.sh @@ -22,15 +22,18 @@ if omarchy-hw-qualcomm-soc; then qcom-firmware-extract --install --no-rebuild - mkdir -p /etc/modprobe.d - if lsblk -sno TRAN "$(findmnt -no SOURCE /)" 2>/dev/null | grep -q '^usb$'; then + modprobe_dir=${OMARCHY_QUALCOMM_MODPROBE_DIR:-/etc/modprobe.d} + root_source=$(findmnt -no SOURCE --nofsroot / 2>/dev/null || true) + + mkdir -p "$modprobe_dir" + if [[ -n $root_source ]] && lsblk -sno TRAN "$root_source" 2>/dev/null | grep -q '^usb$'; then # Root disk on USB. When the DSPs boot with real firmware the Type-C port # controller (pmic_glink/UCSI) takes over the ports and resets them, which # drops a root disk behind a USB-C port (observed on the HP EliteBook Ultra # G1q, JimmayVV/omarchy-iso#27). Keep the DSPs off on such installs: no # audio or battery reporting, but the system boots. RETIRE when the kernel # stops resetting an already-connected port (#27). - cat >/etc/modprobe.d/qualcomm-adsp-nofw.conf <<'CONF' + cat >"$modprobe_dir/qualcomm-adsp-nofw.conf" <<'CONF' # Generated by Omarchy for Qualcomm Snapdragon devices (install/hardware/qualcomm/firmware.sh) # The root disk is attached over USB. Booting the DSPs hands the USB-C ports # to the port controller, which resets them and drops the root disk. Keep the @@ -40,7 +43,7 @@ if omarchy-hw-qualcomm-soc; then blacklist qcom_q6v5_pas CONF elif qcom-firmware-extract --list-missing | grep -q 'adsp'; then - cat >/etc/modprobe.d/qualcomm-adsp-nofw.conf <<'CONF' + cat >"$modprobe_dir/qualcomm-adsp-nofw.conf" <<'CONF' # Generated by Omarchy for Qualcomm Snapdragon devices (install/hardware/qualcomm/firmware.sh) # No signed audio-DSP firmware is installed yet; the driver's failing probe # resets the USB-C mux and can take a USB-C root disk down with it. Removed @@ -48,6 +51,6 @@ CONF blacklist qcom_q6v5_pas CONF else - rm -f /etc/modprobe.d/qualcomm-adsp-nofw.conf + rm -f "$modprobe_dir/qualcomm-adsp-nofw.conf" fi fi diff --git a/test/shell.d/snapdragon-hardware-test.sh b/test/shell.d/snapdragon-hardware-test.sh new file mode 100644 index 00000000000..f227825fd26 --- /dev/null +++ b/test/shell.d/snapdragon-hardware-test.sh @@ -0,0 +1,67 @@ +#!/bin/bash + +set -euo pipefail + +source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh" + +firmware_setup="$ROOT/install/hardware/qualcomm/firmware.sh" +dtb_setup="$ROOT/install/hardware/qualcomm/dtb-uki.sh" +scratch=$(mktemp -d) +trap 'rm -rf "$scratch"' EXIT + +bash -n "$firmware_setup" "$dtb_setup" || fail "Snapdragon hardware scripts have valid syntax" + +( + omarchy-hw-qualcomm-soc() { return 0; } + omarchy-pkg-add() { :; } + qcom-firmware-extract() { :; } + findmnt() { + [[ $* == "-no SOURCE --nofsroot /" ]] || fail "Snapdragon firmware setup strips the Btrfs subvolume suffix" + printf '/dev/mapper/root\n' + } + lsblk() { + [[ ${!#} == "/dev/mapper/root" ]] || fail "Snapdragon firmware setup passes a resolvable root device to lsblk" + printf 'usb\n' + } + + OMARCHY_QUALCOMM_MODPROBE_DIR="$scratch/modprobe.d" + source "$firmware_setup" +) + +[[ -f $scratch/modprobe.d/qualcomm-adsp-nofw.conf ]] || + fail "Snapdragon firmware setup protects a USB-backed root disk" + +mkdir -p "$scratch/dtbs" +: >"$scratch/dtbs/x1e80100-test.dtb" +: >"$scratch/dtbs/x1e80100-test-el2.dtb" +cat >"$scratch/uki.conf" <<'CONF' +[UKI] +SecureBootPrivateKey=/secure/db.key +PCRPrivateKey=/secure/pcr.key +CONF + +run_dtb_setup() ( + omarchy-hw-qualcomm-soc() { return 0; } + omarchy-pkg-add() { :; } + + OMARCHY_QUALCOMM_DTB_DIR="$scratch/dtbs" + OMARCHY_QUALCOMM_UKI_CONFIG="$scratch/uki.conf" + source "$dtb_setup" +) + +run_dtb_setup +run_dtb_setup + +grep -Fq 'SecureBootPrivateKey=/secure/db.key' "$scratch/uki.conf" || + fail "Snapdragon DTB setup preserves Secure Boot settings" +grep -Fq 'PCRPrivateKey=/secure/pcr.key' "$scratch/uki.conf" || + fail "Snapdragon DTB setup preserves PCR settings" +[[ $(grep -Fc '# BEGIN OMARCHY QUALCOMM DEVICE TREES' "$scratch/uki.conf") == 1 ]] || + fail "Snapdragon DTB setup keeps one managed UKI block" +grep -Fq "DeviceTreeAuto=$scratch/dtbs/x1e80100-test.dtb" "$scratch/uki.conf" || + fail "Snapdragon DTB setup lists the matching device tree" +if grep -Fq 'x1e80100-test-el2.dtb' "$scratch/uki.conf"; then + fail "Snapdragon DTB setup excludes EL2-only device trees" +fi + +pass "Snapdragon setup preserves UKI settings and detects USB root disks" From 3eeb4fbb26cf4143be2a39ba93ce87d9a8373bf9 Mon Sep 17 00:00:00 2001 From: Birk Skyum Date: Fri, 28 Aug 2026 12:52:46 +0200 Subject: [PATCH 12/15] Trim Snapdragon implementation comments --- bin/omarchy-hw-qualcomm-soc | 7 +--- default/pacman/mirrorlist-aarch64 | 6 +-- default/pacman/pacman-aarch64.conf | 25 +---------- etc/mkinitcpio.conf.d/thunderbolt_module.conf | 5 +-- install/hardware/qualcomm/dtb-uki.sh | 22 ++-------- install/hardware/qualcomm/firmware.sh | 41 ++++--------------- install/hardware/qualcomm/kernel-params.sh | 15 ++----- install/post-install/pacman.sh | 18 ++------ 8 files changed, 22 insertions(+), 117 deletions(-) diff --git a/bin/omarchy-hw-qualcomm-soc b/bin/omarchy-hw-qualcomm-soc index a32865e5612..c85c73b1e5e 100755 --- a/bin/omarchy-hw-qualcomm-soc +++ b/bin/omarchy-hw-qualcomm-soc @@ -1,10 +1,5 @@ #!/bin/bash -# omarchy:summary=Detect whether the computer runs on a Qualcomm SoC booted with its device tree (Snapdragon X and friends). +# omarchy:summary=Detect a Qualcomm SoC from the boot device tree. -# The Adreno GPU, the Wi-Fi and the rest of a Qualcomm SoC are platform devices, -# so neither lspci nor DMI can tell a Snapdragon laptop apart. The device tree -# can: every Qualcomm board's root node lists the SoC as a `qcom,` -# compatible, and it is there whenever the machine was booted with a device -# tree, which is how Omarchy boots Windows-on-ARM laptops. tr '\0' '\n' /dev/null | grep -q '^qcom,' diff --git a/default/pacman/mirrorlist-aarch64 b/default/pacman/mirrorlist-aarch64 index 3aebd0e77a3..c7185ed8f65 100644 --- a/default/pacman/mirrorlist-aarch64 +++ b/default/pacman/mirrorlist-aarch64 @@ -1,6 +1,2 @@ -# Arch Linux ARM's geo-IP balanced mirror, as shipped by its own -# pacman-mirrorlist. Note the layout: ALARM serves $arch/$repo, where Arch (and -# so Omarchy's mirror of it) serves $repo/os/$arch, which is why the x86_64 -# mirrorlists cannot simply be repointed. HTTP is what ALARM publishes; package -# and database signatures are what integrity rests on either way. +# Arch Linux ARM publishes this endpoint with a $arch/$repo layout. Server = http://mirror.archlinuxarm.org/$arch/$repo diff --git a/default/pacman/pacman-aarch64.conf b/default/pacman/pacman-aarch64.conf index fd3ef87edff..b11e10a47c7 100644 --- a/default/pacman/pacman-aarch64.conf +++ b/default/pacman/pacman-aarch64.conf @@ -1,18 +1,5 @@ # See the pacman.conf(5) manpage for option and repository directives -# -# Package sources for an aarch64 install (see install/post-install/pacman.sh). -# Omarchy's pacman-.conf files describe an x86_64 machine: -# [core]/[extra]/[multilib] come from Omarchy's mirror of Arch, which builds -# x86_64 only, and [multilib] is 32-bit x86 libraries that exist on no ARM -# mirror at all. Arch Linux ARM supplies the equivalents here. -# -# [options] is kept byte-identical to the x86_64 channel configs so the two -# architectures behave the same; only the repository list differs. -# -# One file, not one per channel, because Arch Linux ARM has no channels and the -# only channel-varying section -- [omarchy] -- is absent below. Retire that -# when the Omarchy package repository serves aarch64: this then splits into -# pacman-{stable,rc,edge}-aarch64.conf exactly as the x86_64 files do. +# Arch Linux ARM provides the aarch64 repositories used below. [options] Color @@ -30,11 +17,6 @@ SigLevel = Required DatabaseOptional LocalFileSigLevel = Optional # pacman searches repositories in the order defined here. -# -# [core] [extra] [alarm] [aur] is Arch Linux ARM's stock set. [alarm] carries -# its ARM-specific packages; [aur] carries its builds of AUR-origin packages, -# which on x86_64 Omarchy ships from [omarchy] instead. Deviating from the -# distribution default needs a reason, and there isn't one yet. [core] Include = /etc/pacman.d/mirrorlist @@ -46,8 +28,3 @@ Include = /etc/pacman.d/mirrorlist [aur] Include = /etc/pacman.d/mirrorlist - -# [omarchy] is deliberately absent: the Omarchy package repository serves no -# aarch64 tree, so including it makes every pacman -Sy fail on a 404. Omarchy's -# own packages stay at the versions the ISO installed until that tree exists; -# everything else updates normally. Restore the section when it does. diff --git a/etc/mkinitcpio.conf.d/thunderbolt_module.conf b/etc/mkinitcpio.conf.d/thunderbolt_module.conf index 2f145bb5534..eb0565bef59 100644 --- a/etc/mkinitcpio.conf.d/thunderbolt_module.conf +++ b/etc/mkinitcpio.conf.d/thunderbolt_module.conf @@ -1,7 +1,4 @@ -# Thunderbolt is x86-oriented hardware and the module is not built for every -# architecture -- ALARM's aarch64 kernel has no `thunderbolt`. mkinitcpio treats -# an unresolvable MODULES entry as an error, which fails every initramfs build -# on such a system, so gate it rather than forcing it unconditionally. +# linux-aarch64 does not provide the thunderbolt module. if [[ $(uname -m) == x86_64 ]]; then MODULES+=(thunderbolt) fi diff --git a/install/hardware/qualcomm/dtb-uki.sh b/install/hardware/qualcomm/dtb-uki.sh index ea83d7cb1f3..07bd8eb2005 100644 --- a/install/hardware/qualcomm/dtb-uki.sh +++ b/install/hardware/qualcomm/dtb-uki.sh @@ -1,19 +1,5 @@ -# Snapdragon laptops boot with the device tree that describes the exact model, -# and their Windows-on-ARM firmware provides none. A systemd-stub UKI can carry -# every candidate as a .dtbauto section and pick the right one at boot from the -# machine's SMBIOS hardware ids (the .hwids section ukify builds from systemd's -# tables). mkinitcpio hands ukify /etc/kernel/uki.conf when it exists, so listing -# the device trees there makes every UKI limine-mkinitcpio-hook builds pick its -# own tree, on this machine and after every kernel update. -# -# Limitation: DeviceTreeAuto= takes literal paths, not globs, so this is a -# snapshot of /boot/dtbs/qcom from when the leaf ran. A kernel update that adds -# a new board's tree needs `omarchy apply hardware` to refresh the list. Retire -# the enumeration when ukify accepts globs in DeviceTreeAuto=. -# -# Same prefixes as the Omarchy ISO's live UKI: Snapdragon X Elite/Plus (x1*), -# X2 (hamoa*, glymur*) and 8cx Gen 3 (sc8280xp*). The -el2 variants exist for -# running the kernel at EL2, which this firmware does not. +# Embed Qualcomm device trees so systemd-stub can select one from SMBIOS data. +# DeviceTreeAuto requires literal paths, so hardware setup refreshes the list. if omarchy-hw-qualcomm-soc; then omarchy-pkg-add systemd-ukify @@ -51,8 +37,8 @@ if omarchy-hw-qualcomm-soc; then { echo echo "$managed_begin" - echo "# Generated by Omarchy for Qualcomm Snapdragon devices (install/hardware/qualcomm/dtb-uki.sh)." - echo "# Device trees the systemd-stub picks from at boot by SMBIOS hardware id." + echo "# Generated by Omarchy for Qualcomm Snapdragon devices." + echo "# systemd-stub selects a device tree from SMBIOS data." echo "# Rerun 'omarchy apply hardware' after a kernel update adds new boards." echo "[UKI]" echo "DeviceTreeAuto=${dtbs[*]}" diff --git a/install/hardware/qualcomm/firmware.sh b/install/hardware/qualcomm/firmware.sh index dbde1eefb80..a25a0a5792d 100644 --- a/install/hardware/qualcomm/firmware.sh +++ b/install/hardware/qualcomm/firmware.sh @@ -1,21 +1,5 @@ -# Firmware for the Qualcomm SoC. -# -# Arch Linux ARM splits the redistributable Qualcomm blobs out of -# linux-firmware into linux-firmware-qcom (Adreno GPU microcode, Wi-Fi and -# Bluetooth board data); without it the GPU and Wi-Fi never come up. -# -# The blobs signed by the laptop vendor (GPU zap shader, audio and compute DSP -# images) are not redistributable. qcom-firmware-extract copies the ones this -# machine's device tree names from the owner's own Windows installation: the -# ISO staged them before the disk was written, and a free-space install still -# has the Windows partition on disk. The installer builds the boot image once -# after every hardware leaf has run, so nothing is rebuilt here. -# -# Until the audio DSP firmware is present its driver cannot load; the failing -# probe resets the USB-C mux, which drops a root disk attached over USB-C and -# hangs the boot. Keep the driver blacklisted while that firmware is absent; -# the file is removed once the firmware is installed (re-run -# `sudo qcom-firmware-extract` after providing it). +# Install packaged Qualcomm firmware and vendor-signed blobs extracted from Windows. +# Keep the DSP driver disabled when starting it could disconnect the root disk. if omarchy-hw-qualcomm-soc; then omarchy-pkg-add linux-firmware-qcom qcom-firmware-extract @@ -27,27 +11,16 @@ if omarchy-hw-qualcomm-soc; then mkdir -p "$modprobe_dir" if [[ -n $root_source ]] && lsblk -sno TRAN "$root_source" 2>/dev/null | grep -q '^usb$'; then - # Root disk on USB. When the DSPs boot with real firmware the Type-C port - # controller (pmic_glink/UCSI) takes over the ports and resets them, which - # drops a root disk behind a USB-C port (observed on the HP EliteBook Ultra - # G1q, JimmayVV/omarchy-iso#27). Keep the DSPs off on such installs: no - # audio or battery reporting, but the system boots. RETIRE when the kernel - # stops resetting an already-connected port (#27). + # Starting the DSPs resets USB-C, so keep them off when root is on USB. cat >"$modprobe_dir/qualcomm-adsp-nofw.conf" <<'CONF' -# Generated by Omarchy for Qualcomm Snapdragon devices (install/hardware/qualcomm/firmware.sh) -# The root disk is attached over USB. Booting the DSPs hands the USB-C ports -# to the port controller, which resets them and drops the root disk. Keep the -# DSP driver off on this install (no audio or battery reporting) until the -# kernel stops resetting connected ports; delete this file after moving the -# system to an internal disk. +# Generated by Omarchy for Qualcomm Snapdragon devices. +# Keep the DSP driver off while the root disk is attached over USB. blacklist qcom_q6v5_pas CONF elif qcom-firmware-extract --list-missing | grep -q 'adsp'; then cat >"$modprobe_dir/qualcomm-adsp-nofw.conf" <<'CONF' -# Generated by Omarchy for Qualcomm Snapdragon devices (install/hardware/qualcomm/firmware.sh) -# No signed audio-DSP firmware is installed yet; the driver's failing probe -# resets the USB-C mux and can take a USB-C root disk down with it. Removed -# by the same leaf once the firmware is present. +# Generated by Omarchy for Qualcomm Snapdragon devices. +# Keep the DSP driver off until its signed firmware is installed. blacklist qcom_q6v5_pas CONF else diff --git a/install/hardware/qualcomm/kernel-params.sh b/install/hardware/qualcomm/kernel-params.sh index c9dad320ea5..4536395f557 100644 --- a/install/hardware/qualcomm/kernel-params.sh +++ b/install/hardware/qualcomm/kernel-params.sh @@ -1,20 +1,13 @@ -# Kernel parameters Snapdragon laptops need under their Windows-on-ARM firmware: -# the set Fedora's Snapdragon images and archiso carry, measured on the HP -# EliteBook Ultra G1q (X1E-78-100). Retire each one when the kernel no longer -# needs it; Fedora's images are the tell. +# Add firmware workarounds required by current Snapdragon laptops. DROP_IN="/etc/limine-entry-tool.d/qualcomm-snapdragon.conf" if omarchy-hw-qualcomm-soc; then mkdir -p /etc/limine-entry-tool.d cat >"$DROP_IN" <<'CONF' -# Generated by Omarchy for Qualcomm Snapdragon devices (install/hardware/qualcomm/kernel-params.sh) -# clk_ignore_unused pd_ignore_unused -- display and I/O drivers load from the -# initramfs after the kernel would otherwise switch their clocks and power -# domains off; the screen goes dark at 15 s without them. -# arm64.nopauth -- pointer authentication faults under this firmware. -# systemd.tpm2_wait=0 -- the firmware advertises a TPM2 Linux never gets; -# without this, a 90 s wait for /dev/tpmrm0 on every boot. +# Generated by Omarchy for Qualcomm Snapdragon devices. +# Keep display and I/O resources enabled until their drivers load. +# Disable pointer authentication and waiting for an unavailable TPM. KERNEL_CMDLINE[default]+=" clk_ignore_unused pd_ignore_unused arm64.nopauth systemd.tpm2_wait=0" CONF fi diff --git a/install/post-install/pacman.sh b/install/post-install/pacman.sh index a98cd89b6c7..be3549d7c33 100644 --- a/install/post-install/pacman.sh +++ b/install/post-install/pacman.sh @@ -1,24 +1,12 @@ -# Configure pacman after package installation completes. Offline target package -# installs use the live ISO's offline pacman.conf until this final restore. -# Omarchy's channel configs describe an x86_64 machine, so aarch64 is restored -# to Arch Linux ARM's repositories instead; leaving the ISO's offline config in -# place there would end the install with no package sources at all. +# Replace the installer's offline pacman configuration with online repositories. if [[ $(uname -m) == aarch64 ]]; then - # Still on the offline pacman.conf at this point, which is the only reachable - # source during an offline install -- so take the keyring package now, before - # the repositories below replace it. Arch's `base` pulls in archlinux-keyring - # and nothing pulls in this one; the ISO carries it for exactly this step. + # Install the keyring before replacing the offline package source. omarchy-pkg-add archlinuxarm-keyring cp -f "$OMARCHY_PATH/default/pacman/pacman-aarch64.conf" /etc/pacman.conf cp -f "$OMARCHY_PATH/default/pacman/mirrorlist-aarch64" /etc/pacman.d/mirrorlist - # Arch Linux ARM signs its repositories with its own key, and the install - # leaves that key untrusted on the target: the first signed sync fails with - # "Arch Linux ARM Build System is unknown trust". - # --init is a no-op on an initialised keyring, and --populate without an - # argument locally signs every keyring installed -- archlinux for the `any` - # packages Arch builds, archlinuxarm for the rest. + # Trust every installed keyring before the first signed sync. pacman-key --init pacman-key --populate else From ba8d904acedb4ba5b1f6f01e0e9701c92f63598e Mon Sep 17 00:00:00 2001 From: Birk Skyum Date: Fri, 28 Aug 2026 12:54:18 +0200 Subject: [PATCH 13/15] Trim Yoga board setup comments --- install/hardware/lenovo/yoga-slim7x.sh | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/install/hardware/lenovo/yoga-slim7x.sh b/install/hardware/lenovo/yoga-slim7x.sh index aa55ddb4eeb..ca5243f3c8b 100644 --- a/install/hardware/lenovo/yoga-slim7x.sh +++ b/install/hardware/lenovo/yoga-slim7x.sh @@ -1,6 +1,4 @@ -# Lenovo Yoga Slim 7x (14Q8X9 / 83ED) details that are not common to every -# Snapdragon laptop. Generic DTB, firmware, Vulkan and kernel-cmdline setup is -# handled by install/hardware/qualcomm/. +# Lenovo Yoga Slim 7x (14Q8X9 / 83ED) board-specific setup. yoga_slim7x_compatible="" if [[ -r /sys/firmware/devicetree/base/compatible ]]; then @@ -23,9 +21,7 @@ if omarchy-hw-qualcomm-soc && MODULES+=(i2c-hid-of) CONF - # On this board the ADSP remains offline after its firmware is installed. - # Starting it enables the speakers and microphone. The helper also starts - # the CDSP when present, but only the audio DSP is required for success. + # Start the board's DSP remote processors after udev exposes them. cat >/etc/systemd/system/yoga-slim7x-remoteprocs.service <<'UNIT' [Unit] Description=Start the Lenovo Yoga Slim 7x DSPs From db3f5eef1d4a7866d3cc5341faebc7c4d4169a34 Mon Sep 17 00:00:00 2001 From: Birk Skyum Date: Fri, 28 Aug 2026 12:58:55 +0200 Subject: [PATCH 14/15] Skip Yoga DSP startup when disabled --- install/hardware/lenovo/yoga-slim7x.sh | 21 ++++++---- test/shell.d/yoga-slim7x-hardware-test.sh | 49 +++++++++++++++++++++-- 2 files changed, 60 insertions(+), 10 deletions(-) diff --git a/install/hardware/lenovo/yoga-slim7x.sh b/install/hardware/lenovo/yoga-slim7x.sh index ca5243f3c8b..d5c1a6ecb63 100644 --- a/install/hardware/lenovo/yoga-slim7x.sh +++ b/install/hardware/lenovo/yoga-slim7x.sh @@ -1,8 +1,13 @@ # Lenovo Yoga Slim 7x (14Q8X9 / 83ED) board-specific setup. yoga_slim7x_compatible="" -if [[ -r /sys/firmware/devicetree/base/compatible ]]; then - yoga_slim7x_compatible=$(tr '\0' '\n' /etc/modules-load.d/yoga-slim7x.conf + mkdir -p "$modules_load_dir" + echo "scmi-cpufreq" >"$modules_load_dir/yoga-slim7x.conf" # Its internal keyboard and touchpad are HID-over-I2C. Keep their OF # transport in the initramfs so encrypted installs can accept a passphrase. - mkdir -p /etc/mkinitcpio.conf.d - cat >/etc/mkinitcpio.conf.d/yoga-slim7x-initramfs.conf <<'CONF' + mkdir -p "$mkinitcpio_dir" + cat >"$mkinitcpio_dir/yoga-slim7x-initramfs.conf" <<'CONF' MODULES+=(i2c-hid-of) CONF # Start the board's DSP remote processors after udev exposes them. - cat >/etc/systemd/system/yoga-slim7x-remoteprocs.service <<'UNIT' + mkdir -p "$systemd_dir" + cat >"$systemd_dir/yoga-slim7x-remoteprocs.service" <<'UNIT' [Unit] Description=Start the Lenovo Yoga Slim 7x DSPs Wants=systemd-udev-settle.service After=systemd-udev-settle.service +ConditionPathExists=!/etc/modprobe.d/qualcomm-adsp-nofw.conf [Service] Type=oneshot diff --git a/test/shell.d/yoga-slim7x-hardware-test.sh b/test/shell.d/yoga-slim7x-hardware-test.sh index 8e0fb7fbde8..311a51d4e8e 100644 --- a/test/shell.d/yoga-slim7x-hardware-test.sh +++ b/test/shell.d/yoga-slim7x-hardware-test.sh @@ -10,10 +10,53 @@ scratch=$(mktemp -d) trap 'rm -rf "$scratch"' EXIT bash -n "$setup" "$starter" || fail "Yoga Slim 7x hardware scripts have valid syntax" -grep -Fq 'MODULES+=(i2c-hid-of)' "$setup" || - fail "Yoga Slim 7x setup keeps the internal keyboard in the initramfs" -grep -Fq 'scmi-cpufreq' "$setup" || + +matching="$scratch/matching" +mkdir -p "$matching" +printf 'qcom,x1e80100\0lenovo,yoga-slim7x\0' >"$matching/compatible" +( + omarchy-hw-qualcomm-soc() { return 0; } + omarchy-hw-match() { return 1; } + systemctl() { printf '%s\n' "$*" >>"$matching/systemctl.log"; } + + OMARCHY_YOGA_COMPATIBLE_PATH="$matching/compatible" \ + OMARCHY_YOGA_MODULES_LOAD_DIR="$matching/modules-load.d" \ + OMARCHY_YOGA_MKINITCPIO_DIR="$matching/mkinitcpio.conf.d" \ + OMARCHY_YOGA_SYSTEMD_DIR="$matching/systemd" \ + source "$setup" +) + +grep -Fxq 'scmi-cpufreq' "$matching/modules-load.d/yoga-slim7x.conf" || fail "Yoga Slim 7x setup loads its SCMI CPU-frequency driver" +grep -Fxq 'MODULES+=(i2c-hid-of)' "$matching/mkinitcpio.conf.d/yoga-slim7x-initramfs.conf" || + fail "Yoga Slim 7x setup keeps the internal keyboard in the initramfs" +grep -Fq 'ConditionPathExists=!/etc/modprobe.d/qualcomm-adsp-nofw.conf' \ + "$matching/systemd/yoga-slim7x-remoteprocs.service" || + fail "Yoga Slim 7x skips DSP startup when the generic firmware leaf blacklists it" +grep -Fxq 'enable yoga-slim7x-remoteprocs.service' "$matching/systemctl.log" || + fail "Yoga Slim 7x enables its remote processor service" + +nonmatching="$scratch/nonmatching" +mkdir -p "$nonmatching" +printf 'qcom,x1e80100\0hp,elitebook-ultra-g1q\0' >"$nonmatching/compatible" +( + omarchy-hw-qualcomm-soc() { return 0; } + omarchy-hw-match() { return 1; } + systemctl() { fail "nonmatching Qualcomm hardware does not enable Yoga services"; } + + OMARCHY_YOGA_COMPATIBLE_PATH="$nonmatching/compatible" \ + OMARCHY_YOGA_MODULES_LOAD_DIR="$nonmatching/modules-load.d" \ + OMARCHY_YOGA_MKINITCPIO_DIR="$nonmatching/mkinitcpio.conf.d" \ + OMARCHY_YOGA_SYSTEMD_DIR="$nonmatching/systemd" \ + source "$setup" +) + +[[ ! -e $nonmatching/modules-load.d/yoga-slim7x.conf ]] || + fail "nonmatching Qualcomm hardware does not get Yoga CPU setup" +[[ ! -e $nonmatching/mkinitcpio.conf.d/yoga-slim7x-initramfs.conf ]] || + fail "nonmatching Qualcomm hardware does not get Yoga initramfs setup" +[[ ! -e $nonmatching/systemd/yoga-slim7x-remoteprocs.service ]] || + fail "nonmatching Qualcomm hardware does not get Yoga services" remoteprocs="$scratch/remoteproc" mkdir -p "$remoteprocs/remoteproc0" "$remoteprocs/remoteproc1" "$remoteprocs/remoteproc2" From 27c5cd59c7c234e49984139179ba48525636f6d6 Mon Sep 17 00:00:00 2001 From: Birk Skyum Date: Fri, 28 Aug 2026 19:57:18 +0200 Subject: [PATCH 15/15] Initialize Yoga display before disk unlock --- install/hardware/lenovo/yoga-slim7x.sh | 23 +++++++++++++++++------ test/shell.d/yoga-slim7x-hardware-test.sh | 20 +++++++++++++++++--- 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/install/hardware/lenovo/yoga-slim7x.sh b/install/hardware/lenovo/yoga-slim7x.sh index d5c1a6ecb63..dede8968540 100644 --- a/install/hardware/lenovo/yoga-slim7x.sh +++ b/install/hardware/lenovo/yoga-slim7x.sh @@ -4,6 +4,7 @@ yoga_slim7x_compatible="" compatible_path=${OMARCHY_YOGA_COMPATIBLE_PATH:-/sys/firmware/devicetree/base/compatible} modules_load_dir=${OMARCHY_YOGA_MODULES_LOAD_DIR:-/etc/modules-load.d} mkinitcpio_dir=${OMARCHY_YOGA_MKINITCPIO_DIR:-/etc/mkinitcpio.conf.d} +limine_config_dir=${OMARCHY_YOGA_LIMINE_CONFIG_DIR:-/etc/limine-entry-tool.d} systemd_dir=${OMARCHY_YOGA_SYSTEMD_DIR:-/etc/systemd/system} if [[ -r $compatible_path ]]; then @@ -19,20 +20,30 @@ if omarchy-hw-qualcomm-soc && mkdir -p "$modules_load_dir" echo "scmi-cpufreq" >"$modules_load_dir/yoga-slim7x.conf" - # Its internal keyboard and touchpad are HID-over-I2C. Keep their OF - # transport in the initramfs so encrypted installs can accept a passphrase. + # Initialize the internal keyboard and display before disk unlock. mkdir -p "$mkinitcpio_dir" cat >"$mkinitcpio_dir/yoga-slim7x-initramfs.conf" <<'CONF' -MODULES+=(i2c-hid-of) +MODULES+=(i2c-hid-of qrtr ps883x pmic_glink_altmode) + +for firmware in \ + /usr/lib/firmware/qcom/gen70500_sqe.fw \ + /usr/lib/firmware/qcom/gen70500_gmu.bin \ + /usr/lib/firmware/qcom/x1e80100/LENOVO/83ED/qcdxkmsuc8380.mbn; do + [[ -f $firmware ]] && FILES+=("$firmware") +done +unset firmware CONF - # Start the board's DSP remote processors after udev exposes them. + mkdir -p "$limine_config_dir" + cat >"$limine_config_dir/yoga-slim7x.conf" <<'CONF' +KERNEL_CMDLINE[default]+=" initcall_blacklist=simpledrm_platform_driver_init" +CONF + + # Start the board's DSP remote processors. mkdir -p "$systemd_dir" cat >"$systemd_dir/yoga-slim7x-remoteprocs.service" <<'UNIT' [Unit] Description=Start the Lenovo Yoga Slim 7x DSPs -Wants=systemd-udev-settle.service -After=systemd-udev-settle.service ConditionPathExists=!/etc/modprobe.d/qualcomm-adsp-nofw.conf [Service] diff --git a/test/shell.d/yoga-slim7x-hardware-test.sh b/test/shell.d/yoga-slim7x-hardware-test.sh index 311a51d4e8e..66b5b340310 100644 --- a/test/shell.d/yoga-slim7x-hardware-test.sh +++ b/test/shell.d/yoga-slim7x-hardware-test.sh @@ -22,17 +22,28 @@ printf 'qcom,x1e80100\0lenovo,yoga-slim7x\0' >"$matching/compatible" OMARCHY_YOGA_COMPATIBLE_PATH="$matching/compatible" \ OMARCHY_YOGA_MODULES_LOAD_DIR="$matching/modules-load.d" \ OMARCHY_YOGA_MKINITCPIO_DIR="$matching/mkinitcpio.conf.d" \ + OMARCHY_YOGA_LIMINE_CONFIG_DIR="$matching/limine-entry-tool.d" \ OMARCHY_YOGA_SYSTEMD_DIR="$matching/systemd" \ source "$setup" ) grep -Fxq 'scmi-cpufreq' "$matching/modules-load.d/yoga-slim7x.conf" || fail "Yoga Slim 7x setup loads its SCMI CPU-frequency driver" -grep -Fxq 'MODULES+=(i2c-hid-of)' "$matching/mkinitcpio.conf.d/yoga-slim7x-initramfs.conf" || - fail "Yoga Slim 7x setup keeps the internal keyboard in the initramfs" +grep -Fxq 'MODULES+=(i2c-hid-of qrtr ps883x pmic_glink_altmode)' \ + "$matching/mkinitcpio.conf.d/yoga-slim7x-initramfs.conf" || + fail "Yoga Slim 7x setup initializes the keyboard and display in the initramfs" +grep -Fq '/usr/lib/firmware/qcom/gen70500_sqe.fw' \ + "$matching/mkinitcpio.conf.d/yoga-slim7x-initramfs.conf" || + fail "Yoga Slim 7x setup includes its display firmware in the initramfs" +grep -Fxq 'KERNEL_CMDLINE[default]+=" initcall_blacklist=simpledrm_platform_driver_init"' \ + "$matching/limine-entry-tool.d/yoga-slim7x.conf" || + fail "Yoga Slim 7x setup defers display ownership to the native driver" grep -Fq 'ConditionPathExists=!/etc/modprobe.d/qualcomm-adsp-nofw.conf' \ "$matching/systemd/yoga-slim7x-remoteprocs.service" || fail "Yoga Slim 7x skips DSP startup when the generic firmware leaf blacklists it" +if grep -Fq 'systemd-udev-settle.service' "$matching/systemd/yoga-slim7x-remoteprocs.service"; then + fail "Yoga Slim 7x DSP startup does not wait for all udev devices" +fi grep -Fxq 'enable yoga-slim7x-remoteprocs.service' "$matching/systemctl.log" || fail "Yoga Slim 7x enables its remote processor service" @@ -47,6 +58,7 @@ printf 'qcom,x1e80100\0hp,elitebook-ultra-g1q\0' >"$nonmatching/compatible" OMARCHY_YOGA_COMPATIBLE_PATH="$nonmatching/compatible" \ OMARCHY_YOGA_MODULES_LOAD_DIR="$nonmatching/modules-load.d" \ OMARCHY_YOGA_MKINITCPIO_DIR="$nonmatching/mkinitcpio.conf.d" \ + OMARCHY_YOGA_LIMINE_CONFIG_DIR="$nonmatching/limine-entry-tool.d" \ OMARCHY_YOGA_SYSTEMD_DIR="$nonmatching/systemd" \ source "$setup" ) @@ -55,6 +67,8 @@ printf 'qcom,x1e80100\0hp,elitebook-ultra-g1q\0' >"$nonmatching/compatible" fail "nonmatching Qualcomm hardware does not get Yoga CPU setup" [[ ! -e $nonmatching/mkinitcpio.conf.d/yoga-slim7x-initramfs.conf ]] || fail "nonmatching Qualcomm hardware does not get Yoga initramfs setup" +[[ ! -e $nonmatching/limine-entry-tool.d/yoga-slim7x.conf ]] || + fail "nonmatching Qualcomm hardware does not get Yoga boot parameters" [[ ! -e $nonmatching/systemd/yoga-slim7x-remoteprocs.service ]] || fail "nonmatching Qualcomm hardware does not get Yoga services" @@ -79,4 +93,4 @@ OMARCHY_YOGA_REMOTEPROC_ROOT="$remoteprocs" \ [[ $(<"$remoteprocs/remoteproc2/state") == offline ]] || fail "Yoga Slim 7x helper leaves unrelated remote processors alone" -pass "Yoga Slim 7x adds only its board-specific keyboard, CPU and DSP setup" +pass "Yoga Slim 7x adds only its board-specific keyboard, display, CPU and DSP setup"