Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions bin/omarchy-hw-qualcomm-soc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/bash

# omarchy:summary=Detect a Qualcomm SoC from the boot device tree.

tr '\0' '\n' </sys/firmware/devicetree/base/compatible 2>/dev/null | grep -q '^qcom,'
2 changes: 2 additions & 0 deletions default/pacman/mirrorlist-aarch64
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Arch Linux ARM publishes this endpoint with a $arch/$repo layout.
Server = http://mirror.archlinuxarm.org/$arch/$repo
30 changes: 30 additions & 0 deletions default/pacman/pacman-aarch64.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# See the pacman.conf(5) manpage for option and repository directives
# Arch Linux ARM provides the aarch64 repositories used below.

[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]
Include = /etc/pacman.d/mirrorlist

[extra]
Include = /etc/pacman.d/mirrorlist

[alarm]
Include = /etc/pacman.d/mirrorlist

[aur]
Include = /etc/pacman.d/mirrorlist
5 changes: 4 additions & 1 deletion etc/mkinitcpio.conf.d/thunderbolt_module.conf
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
MODULES+=(thunderbolt)
# linux-aarch64 does not provide the thunderbolt module.
if [[ $(uname -m) == x86_64 ]]; then
MODULES+=(thunderbolt)
fi
5 changes: 5 additions & 0 deletions install/hardware/all.sh
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,12 @@ 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/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"
Expand Down
40 changes: 40 additions & 0 deletions install/hardware/lenovo/start-yoga-slim7x-remoteprocs.sh
Original file line number Diff line number Diff line change
@@ -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
58 changes: 58 additions & 0 deletions install/hardware/lenovo/yoga-slim7x.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Lenovo Yoga Slim 7x (14Q8X9 / 83ED) board-specific setup.

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
yoga_slim7x_compatible=$(tr '\0' '\n' <"$compatible_path")
fi

if omarchy-hw-qualcomm-soc &&
{ grep -qi '^lenovo,yoga-slim7x$' <<<"$yoga_slim7x_compatible" ||
omarchy-hw-match 'Yoga Slim 7x' || omarchy-hw-match '83ED'; }; then
echo "Detected Lenovo Yoga Slim 7x, applying board-specific support..."

# The Yoga exposes its CPU performance domains through SCMI.
mkdir -p "$modules_load_dir"
echo "scmi-cpufreq" >"$modules_load_dir/yoga-slim7x.conf"

# 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 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

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
ConditionPathExists=!/etc/modprobe.d/qualcomm-adsp-nofw.conf

[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
51 changes: 51 additions & 0 deletions install/hardware/qualcomm/dtb-uki.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# 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

dtb_dir=${OMARCHY_QUALCOMM_DTB_DIR:-/boot/dtbs/qcom}
uki_config=${OMARCHY_QUALCOMM_UKI_CONFIG:-/etc/kernel/uki.conf}
dtbs=()
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 $dtb_dir; the UKI gets no .dtbauto sections" >&2
else
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."
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[*]}"
echo "$managed_end"
} >>"$uki_tmp"

mv -f "$uki_tmp" "$uki_config"
echo "Listed ${#dtbs[@]} device trees in $uki_config"
fi
fi
29 changes: 29 additions & 0 deletions install/hardware/qualcomm/firmware.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# 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

qcom-firmware-extract --install --no-rebuild

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
# 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.
# 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.
# Keep the DSP driver off until its signed firmware is installed.
blacklist qcom_q6v5_pas
CONF
else
rm -f "$modprobe_dir/qualcomm-adsp-nofw.conf"
fi
fi
13 changes: 13 additions & 0 deletions install/hardware/qualcomm/kernel-params.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# 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.
# 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
5 changes: 5 additions & 0 deletions install/hardware/vulkan.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
3 changes: 3 additions & 0 deletions install/omarchy-other.packages
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,6 @@ t2fanrd

# Framework 16
qmk-hid

# Qualcomm Snapdragon support packages
qcom-firmware-extract
19 changes: 15 additions & 4 deletions install/post-install/pacman.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
# 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
# Replace the installer's offline pacman configuration with online repositories.
if [[ $(uname -m) == aarch64 ]]; then
# 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

# Trust every installed keyring before the first signed sync.
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.
Expand Down
9 changes: 7 additions & 2 deletions install/user/mise-work.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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"
Expand Down
67 changes: 67 additions & 0 deletions test/shell.d/snapdragon-hardware-test.sh
Original file line number Diff line number Diff line change
@@ -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"
Loading