Commit Graph

22 Commits

Author SHA1 Message Date
7585c5f147 docs: audio root causes found; WiFi narrowed to the modem's own RF path
Audio: Fedora has never built CONFIG_SND_SOC_WSA881X, the speaker-amp
driver the in-tree DTS requires; with it built out of tree the card
registers and plays. The din-ports message is a harmless warning. Also
record the S24_LE format defect and the sink-stealing traps (AirPlay,
Bluetooth, phantom headphone jack) that masqueraded as broken audio.

WiFi: every published modem firmware build (five distinct across nine
WOA versions) and kernel 6.12 all fail identically at QLINK, the link to
the SDR845 RF transceiver. This unit is an LTE SKU with working modem
history under Windows, fsg/fsc are blank, and the modem asks rmtfs for
unknown fsg_oem partitions. Fedora's tqftpserv also serves different
paths than the old aarch64-laptops one — the earlier instructions here
were wrong for it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011XgGF5wfxLDAybVnNz6eNQ
2026-07-28 12:02:19 +03:00
9b28150c86 Pin the built-in card to S16_LE for PipeWire
The ADSP front-end advertises S24_LE and then garbles it: playback runs
without an error, consumes data at rate, powers every DAPM widget, and
produces ~-48 dB of near-silence. PipeWire prefers the widest advertised
format, so every PipeWire client was inaudible while aplay and
speaker-test, which default to S16_LE, worked. One wireplumber rule pins
the format until the q6asm handling is fixed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011XgGF5wfxLDAybVnNz6eNQ
2026-07-28 12:02:19 +03:00
0a82d2c2d7 Give Bluetooth its factory address from the DPP partition
The WCN3990 has no burned-in Bluetooth address, so the kernel registers
the controller unconfigured and bluetoothd never sees it. The factory
address is on the machine all along: QCOM/BT.PROVISION on the DPP
partition, a three-byte header followed by the six-byte address.
c630-bt-addr reads it and hands it to btmgmt before bluetooth.service
starts. Verified on hardware: controller configures, powers, scans, and
streams A2DP.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011XgGF5wfxLDAybVnNz6eNQ
2026-07-28 12:02:19 +03:00
8041c8b5f9 docs: document both firmware sources on equal terms
All checks were successful
build image / build (push) Successful in 1h51m36s
The repo named WOA-Project as a source and called its cabinets "the easiest
route", while aarch64-laptops appeared only as a place where files "have
circulated before" — despite it having actual .mbn files checked into its tree
and being where the WiFi trio used in today's testing came from. That ranking
was mine, not something the evidence supports.

Both are now documented with what each actually contains. They overlap and
neither is a superset:

WOA-Project is the only source of the two for qcdxkmsuc850.mbn, qcadsp850.mbn,
qccdsp850.mbn, qcslpi850.mbn, qcvss850.mbn and ipa_fws.elf, and publishes nine
versions whose cabinets differ. aarch64-laptops carries the modem/WLAN trio,
the bdwlan board data, a prebuilt board-2.bin and the script that makes it,
a630_gmu.bin, the machine's ACPI tables and a device tree — none of which
WOA-Project has, and it has none of the six above. Its wifi/firmware-5.bin is
an HTML error page rather than firmware, which is worth knowing before copying
it somewhere.

Also restate the modem result without implying a verdict on either source. Both
sets produce the identical QLINK failure here; that shows changing firmware does
not change the outcome, not that either set is wrong, and not that one is more
trustworthy than the other.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XWRjNJMistCy6ngXH5aJLS
2026-07-28 08:56:16 +03:00
b05c982a77 Write up the onboard WiFi investigation, and ship the services it needs
Some checks failed
build image / build (push) Has been cancelled
aarch64-laptops' support table ticks WiFi for this machine, so the path exists.
Following their WiFi README got considerably further and then stopped somewhere
useful to have documented.

Two of the four services they list are in the kernel now (pd-mapper, qrtr-ns).
The other two, rmtfs and tqftpserv, are packaged in Fedora and shipped
disabled — tqftpserv was not even installed. Both are now in base.pkgs and
enabled by stage2. Enabling them took qrtr-lookup from 19 registered services
to 25; a working setup is said to show around 40.

The step worth having written down: the modem does not read wlanmdsp.mbn from
/lib/firmware. It asks tqftpserv for it over TFTP, from
/lib/firmware/readonly/firmware/image/. Nothing reports this as an error —
ath10k_snoc binds, registers a QMI client, and waits forever for a service that
never registers. c630-firmware now places the file there, and creates the
writable area the modem asks tqftpserv for.

Where it stops: the modem boots and dies at "RF stuck in QLINK start state",
about every 42 seconds, never reaching the point of requesting wlanmdsp. Three
firmware pairings give three distinct failures, recorded in the doc — the _nm
"no modem" variants, which are the obvious idea and would skip cellular RF
entirely, turn out not to be signed for this device.

The result that narrows it: aarch64-laptops' own wifi directory carries the
qcdsp1v2850.mbn, qcdsp2850.mbn and wlanmdsp.mbn from the setup whose table ticks
WiFi. All three differ from the WOA-Project copies. Installed here with the
services running and wlanmdsp in the TFTP path, they produce the identical QLINK
failure — so it is neither the firmware nor the userspace. What is left is the
kernel: 5.x from 2019 there against 7.1.5 here, with both of their ath10k
patches long since upstream. That points at a regression, and confirming it
means a bisect rather than another file.

Also record what is untried: the other eight driver versions (this machine's
UEFI is from 2019 and the newest package may be the wrong vintage),
mcfg_subsys_ext850.cab, and building board-2.bin from the C630's own bdwlan.*
files.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XWRjNJMistCy6ngXH5aJLS
2026-07-28 08:52:08 +03:00
6ef4e251f2 docs: name WOA-Project rather than describing its contents
Some checks failed
build image / build (push) Has been cancelled
The repository name says 'Reference-Drivers'; that is its name, not a
characterisation of what is inside it, and using it as a descriptor implied
the thing I had already removed from the rest of the file.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XWRjNJMistCy6ngXH5aJLS
2026-07-28 08:25:40 +03:00
755031ac16 Remove the custom motd, and stop asserting a guess as the cause
Some checks failed
build image / build (push) Has been cancelled
Two problems, one of them mine twice over.

The motd is gone entirely. It had been wrong in a way that mattered — telling
anyone who logged in that onboard WiFi worked when it does not — and a login
banner is a bad place to keep claims that need revising every time we learn
something.

The worse issue is what it and the docs said about why the modem fails. I
inferred from the WOA-Project repository being named "Qualcomm-Reference-
Drivers" that its modem image was a generic reference build unsuited to this
machine's radio, and wrote that up as the explanation. That was a guess resting
on a repository name, and the naming is about redistribution rather than the
contents. Removed from both README and docs/firmware.md.

What is actually established stays: the modem boots, loads mpss, and dies at
"RF stuck in QLINK start state", roughly every 42 seconds. The cause is not
known. The machine has a SIM slot and its modem worked under Windows, so the
radio hardware is present — and the same cabinets supply the GPU, DSP and venus
firmware, all of which work, so whatever is wrong is specific to the modem.
The docs now say that and stop there.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XWRjNJMistCy6ngXH5aJLS
2026-07-28 08:25:26 +03:00
8fa461a41b docs: record what firmware fixed, and what it turns out not to fix
Some checks failed
build image / build (push) Has been cancelled
The motd was the worst of it — it told anyone logging in that "WiFi and
Bluetooth work with the firmware Fedora ships", which is precisely backwards for
the onboard adapter, and pointed at a Windows partition this machine no longer
has.

What the blobs did fix, verified: the GPU initialises, ADSP/CDSP/SLPI all run,
sensors appear as IIO devices, venus registers /dev/video0-3.

What they did not, and why, so nobody repeats the search:

Onboard WiFi is loaded by the modem — wlan*mdsp* is the WLAN Modem DSP — so
ath10k_snoc binds and then waits silently on a QMI service that never arrives.
The modem boots and dies at "RF stuck in QLINK start state", the RF front-end,
which is board-specific wiring in a way the SoC-level blobs are not. These are
Qualcomm *reference* drivers; good enough for the GPU and DSPs, evidently not
for this machine's radio. Three plausible fixes that do not work are recorded
too: rmtfs (correct to enable, does not help), the _nm firmware variants
(rejected at PBL), and unplugging the USB dongle (different bus entirely — it
was never competing).

Audio gets further than expected. The codec answers over SLIMbus with its chip
id, so hardware and ADSP are fine; what fails is the codec's SoundWire block
declaring two data-in ports where the controller expects six. That is a kernel
mismatch and needs a kernel change.

Also record the mesa caveat properly: the GPU works, but freedreno's EGL path
segfaults gnome-shell into a login loop, and LIBGL_ALWAYS_SOFTWARE does nothing
because mutter uses EGL. MESA_LOADER_DRIVER_OVERRIDE=kms_swrast is what works.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XWRjNJMistCy6ngXH5aJLS
2026-07-28 08:24:11 +03:00
18252b37f5 docs: the firmware is downloadable — WOA-Project reference drivers
All checks were successful
build image / build (push) Successful in 24m42s
The blobs turned out to be a public download rather than something to recover
from a lost backup. WOA-Project/Qualcomm-Reference-Drivers collects the
Windows-on-ARM driver cabinets by SoC, and three of them cover this machine
completely: qcdx850.cab has the zap shader and venus, qcipa850.cab has
ipa_fws.elf, and qcsubsys850.cab has the four DSP images plus WLANMDSP.MBN —
the WiFi firmware, which is not in the device tree's firmware-name list at all
and so was never on our list of things to look for.

Correct three claims elsewhere in the file that this disproves. `file` reports
these as ELF QUALCOMM DSP6 images, not as `data` — worth stating precisely,
since it is the quickest way to tell a real blob from a download that returned
an HTML error page. The sizes span 14KB to 60MB rather than "a few hundred KB
to a few MB". And the heading claiming they must come off the Windows partition
is no longer true of the easiest route.

Also narrow what c630-firmware puts in the initramfs. It globbed every .mbn in
the firmware directory, which would have pulled in the 60MB qcdsp2850.mbn and
inflated the initramfs roughly twentyfold. Only the GPU needs to be there —
msm_dpu probes at six seconds, while the initramfs is still root; the ADSP,
CDSP, SLPI, venus and modem all probe around forty seconds in and load from the
real root perfectly happily.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XWRjNJMistCy6ngXH5aJLS
2026-07-28 07:22:32 +03:00
1423366f30 docs: the missing firmware is sourceable, not lost
Some checks failed
build image / build (push) Has been cancelled
The Windows backups never turned up, which looked terminal. It is not, because
these blobs are signed per model rather than per machine — a copy from any
other Yoga C630 works.

The evidence is in linux-firmware itself, which already ships the exact
analogous set for the ThinkPad X13s under qcom/sc8280xp/LENOVO/21BX: the zap
shader, ADSP, CDSP, SLPI and venus firmware, one copy serving every unit of
that model. So redistribution is a licensing question rather than a technical
one, and qcom/sdm850/LENOVO/81JL/ has simply never been contributed. It will
not arrive in a linux-firmware update.

Record two routes: Lenovo's Digital Download Recovery Service, which builds a
Windows recovery image against a machine's serial for its owner and carries the
whole DriverStore; and other C630 owners, where these have circulated before.

Reconcile two earlier claims that this contradicts — that nobody can
redistribute them, and that a backup or surviving Windows partition were the
only routes. Both were wrong in the same way: they described this machine's
situation as though it were a property of the files.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XWRjNJMistCy6ngXH5aJLS
2026-07-28 06:58:29 +03:00
2457df7a37 docs: record what the GPU firmware trace actually proves
All checks were successful
build image / build (push) Successful in 53m10s
Tested on the machine. With the generic Adreno firmware reachable from the
initramfs and the model-signed blob absent, the GPU gets two files in and stops:

    loaded qcom/a630_sqe.fw from new location
    loaded qcom/a630_gmu.bin from new location
    *ERROR* Unable to load qcom/sdm850/LENOVO/81JL/qcdxkmsuc850.mbn
    *ERROR* gpu hw init failed: -2

That settles a question the docs had been hedging: the zap shader is a hard
requirement, not an optimisation, and the generic pieces are necessary but not
sufficient. Getting past sqe and gmu only to die at zap is about as clean a
demonstration as the hardware will give.

Two things fall out of the same trace and are worth writing down, because
nothing upstream documents them for this machine. The driver never falls back
to the installed sdm845/a630_zap.mbn — the device tree pins the model-specific
path — and a fallback would not help anyway, since the shader is signed against
this device's own secure-boot chain. And the display survives the failure
entirely: msm_dpu still binds the panel, so a dead GPU costs acceleration
rather than a picture, and a desktop runs on llvmpipe.

Also record why these files have to travel in the initramfs at all: msm_dpu
probes around six seconds in, while the initramfs is still root, and never
retries.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XWRjNJMistCy6ngXH5aJLS
2026-07-27 20:05:17 +03:00
3a2fc2a329 docs: record the clock trap, and confirm booting from internal storage
Some checks failed
build image / build (push) Has been cancelled
It boots from the internal drive with the stick removed — 18s to multi-user,
no failed units.

The first thing tried on it was `dnf install net-tools`, which failed with:

    Transaction failed: Rpm transaction failed.
      - systemd is needed by net-tools-2.0-0.77.20160912git.fc44.aarch64

systemd is obviously installed; the machine had just booted. The cause is the
clock. This machine's RTC cannot be set at all — ioctl(RTC_SET_TIME) returns
"No such device" — and reads 1970 every boot, so systemd advances it to its own
build date. That is close enough to look plausible and early enough that rpm
treats package signatures created after it as not yet valid, skips those
headers outright, and reports the packages as absent:

    Signature created at Sat Jul 25 18:33:30 2026 invalid: signature is not alive
    error: rpmdbNextIterator: skipping h# 282
    package systemd is not installed

chrony was already added to base.pkgs for the drift; it turns out to be load
bearing rather than a nicety, and it syncs within about five seconds of the
network appearing. Documented, because the symptom points nowhere near the
cause.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XWRjNJMistCy6ngXH5aJLS
2026-07-27 19:35:34 +03:00
f0b2d7846a Add install-to-disk.sh, and get the GPU firmware into the initramfs
Some checks failed
build image / build (push) Has been cancelled
Validated by running it on the machine, twice, and inspecting the result.

Two properties of this laptop rule out the obvious approach, and the script
exists mainly to encode them. Its internal UFS reports 4096-byte logical
sectors, so the image — built with 512-byte geometry — cannot be dd'd onto it;
the GPT header and every partition offset would land in the wrong place. And
there are no EFI runtime variables, so efibootmgr cannot register a boot entry
and GRUB has to sit at the removable-media path where the firmware looks
unprompted.

Three things the validation runs caught that review would not have:

rsync is not in the image. I had put it in the build container and never in
the package list, so the first run died at the copy. It now falls back to tar
(--xattrs-include='*', or SELinux labels are silently dropped and the result
does not boot), and rsync is in base.pkgs for the progress output.

Copying a live root makes tar exit non-zero — files change underneath it, and
this machine's clock is wrong besides, so every mtime looks like it is in the
future. With pipefail that aborted the install after the root filesystem and
before /boot, leaving a half-installed disk that looked plausible. Warning-level
exits are now tolerated and only a fatal exit 2 stops the run.

systemd-machine-id-setup keeps an existing valid id, and one had just been
copied off the stick, so the installed system was a clone. The file is removed
first now.

Also: msm_dpu probes ~6s in, while the initramfs is still root, and asks for
qcom/a630_sqe.fw before the real filesystem carrying it is reachable. It never
retries. Adding the Adreno firmware to the initramfs is a few tens of
kilobytes. c630-firmware does the same for the DSP blobs once they exist, since
dracut rejects install_items globs that match nothing.

chrony, because the RTC reads 1970 and nothing was correcting it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XWRjNJMistCy6ngXH5aJLS
2026-07-27 19:23:29 +03:00
482c5d9c9a Label the filesystem for SELinux at build time
All checks were successful
build image / build (push) Successful in 25m5s
The image booted. Kernel came up, the device tree loaded — UFS, display,
WiFi and IPA all probed as platform devices — framebuffer console came up, root
mounted off USB and systemd started. Then:

    systemd[1]: Unable to fix SELinux security context of /dev/tty..: Permission denied
    (x hundreds)
    systemd[1]: Too many messages being logged to kmsg, ignoring
    [!!!!!!] Failed to allocate manager object.

The filesystem had no SELinux labels. mke2fs -d carries security.* xattrs
across faithfully, but nothing had ever set them: the tree came from dnf, not
from a running SELinux system. I had relied on /.autorelabel, which cannot
work here — PID 1 dies long before anything acts on the flag.

Label the tree with setfiles instead, after the bind mounts are torn down (or
it would walk the builder's /proc) and before /boot is split out, so /boot's
files are labelled along with everything else. Verified in a privileged
container beforehand that security.selinux xattrs can actually be written
through a bind mount, rather than assuming it.

I had listed policycoreutils in the gongfoo build base for exactly this and
then never called setfiles. It is now also in stage2's fallback toolchain, so
the stock-Fedora path works too.

Ship permissive regardless. The labels make enforcing viable, but the failure
mode is unusually punishing — no login prompt, no shell, nothing to repair from
— and on a machine this awkward to reach that is not a default worth choosing.
SELINUX_MODE in config/device.env flips it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XWRjNJMistCy6ngXH5aJLS
2026-07-27 18:05:28 +03:00
2243166642 Boot fixes: drop the stock BLS entry, define load_video, set kernel cmdline
All checks were successful
build image / build (push) Successful in 23m57s
First boot on the hardware failed, returning to the GRUB menu with:

    can't find command 'load_video'
    file '/boot/vmlinuz-7.1.5-200.fc44.aarch64' not found
    you need to load the kernel first

The title in that message was the tell: "Fedora Linux (7.1.5-...) 44 (Forty
Four)" is Fedora's stock format, not ours. GRUB was booting an entry we did not
write. Confirmed by unpacking the published image and reading the boot
filesystem — /loader/entries held two files, and the one named after the
machine-id sorts before c630-*, so it won.

kernel-install wrote it during the dnf transaction, from inside the install
root where /boot is an ordinary directory rather than a partition. It was wrong
three ways: paths of /boot/vmlinuz-… that resolve nowhere once /boot is its own
filesystem; an empty options line, so no root= and no command line at all; and
no devicetree, so even had it loaded, the kernel would not have known what
machine it was on. Ours, sitting right beside it, was correct throughout.

So: delete any entry we did not write, and define load_video in grub.cfg —
blscfg emits menuentries that call it, and Fedora's generated config defines it
where a hand-written one must too.

Also write /etc/kernel/cmdline. That empty options line was not a build-time
quirk; it is what kernel-install produces when nothing tells it the command
line. The same gap would have bitten on the device at the first
`dnf update kernel`, writing an entry with no root= and no C630 quirks, and the
laptop would not have come back.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XWRjNJMistCy6ngXH5aJLS
2026-07-27 17:01:48 +03:00
a5f492d115 ci: upload artifacts with v3 — v4 cannot talk to Gitea
All checks were successful
build image / build (push) Successful in 24m3s
Build 18745 produced a working image (8.00 GiB compressed to 972 MiB in 44
seconds, checksum recorded) and then failed on the very last step:

    GHESNotSupportedError: @actions/artifact v2.0.0+, upload-artifact@v4+ and
    download-artifact@v4+ are not currently supported on GHES.

Gitea's artifact backend identifies as GHES, and the v2 artifact client behind
upload-artifact@v4 refuses GHES outright rather than falling back. I chose v4
on the assumption Gitea 1.25 supported it; it does not. v3 works.

Dropping compression-level with it — v3 has no such input, and the image is
already zstd so it would have been a no-op anyway.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XWRjNJMistCy6ngXH5aJLS
2026-07-27 15:26:58 +03:00
5ec2443261 Clear stale intermediates from the persistent work dir
Some checks failed
build image / build (push) Failing after 25m28s
Build 18744 died at "Building filesystems" with:

    mkfs.vfat: file /work/esp.img already exists

esp.img was left there by build 18700, which was cancelled during compression
and so never reached its end-of-build cleanup. Making $WORK persist so the
staged base could be reused made everything else in it persist as well, and
that turns out not to be inert: mkfs.vfat -C refuses to overwrite, and
`mv $ROOTFS/boot $WORK/boot` would have nested inside a surviving directory
rather than replacing it — a subtler failure that would have produced a /boot
filesystem containing a stray boot/ subdirectory.

Clear the work directory at the start of each run, keeping only the staged base
and its stamp, so the invariant is stated positively rather than depending on
the previous run having exited cleanly. Cleanup that only runs on success is
not cleanup.

Also record why 95-set-boot-entry.install exits 1 during the transaction, so
the next person to read a build log does not go hunting. It is a consequence of
suppressing initramfs generation, is confined to the build, and cannot occur on
the device.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XWRjNJMistCy6ngXH5aJLS
2026-07-27 14:59:15 +03:00
a9f18c9951 Cut ~60 minutes of emulated work out of the build
Some checks failed
build image / build (push) Failing after 44m21s
The first real run took 100 minutes. Roughly 60 of those were spent doing
things that either did not need doing or did not need doing under emulation.

dracut ran three times. The kernel's %posttrans runs kernel-install, which
builds an initramfs, and dracut-config-rescue makes it build a second, rescue
one — both before this build has written /etc/dracut.conf.d/10-c630.conf and
before /proc is bind-mounted, so both are wrong as well as expensive. stage2
then builds the real one. Setting initrd_generator=none in the install root for
the duration of the transaction suppresses both: 50-dracut.install and
51-dracut-rescue.install each bail when KERNEL_INSTALL_INITRD_GENERATOR is not
"dracut". Excluding dracut-config-rescue also spares the laptop a rescue
initramfs on every future kernel update, which on this hardware is not cheap.

That file must not ship. With it in place the machine would boot fine and then
fail to come back after its next kernel update — a bug that surfaces weeks
later looking nothing like an image problem. It is removed from the working
copy, and asserted absent again immediately before the root filesystem is
built.

Compression was running as an aarch64 binary under qemu-user for no reason;
zstd does not care what architecture it runs on. It now runs on the host when
the host has zstd, falling back to in-container otherwise so the build never
depends on it. Measured ~20 minutes against ~2.

Add BASE_RECIPE to the staged-base stamp. Excluding a weak dependency changes
what the base contains without changing the package list it hashes, so without
this the next build would happily reuse a stale base.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XWRjNJMistCy6ngXH5aJLS
2026-07-27 14:12:19 +03:00
3762f13d8b docs: correct the firmware split — graphics needs a Windows blob too
I had this wrong. The claim that accelerated graphics works on the firmware
Fedora ships does not survive contact with the device tree.

Fedora does package an sdm845/a630_zap.mbn, which is what led me astray, but
that is the generic Snapdragon 845 zap shader. The C630's node in
sdm850-lenovo-yoga-c630.dts names qcom/sdm850/LENOVO/81JL/qcdxkmsuc850.mbn
specifically — model-signed, present only in the machine's Windows partition.
Until it is supplied the display is unaccelerated.

Also add qcslpi850.mbn and qcvss850.mbn, which were missing entirely, and
attribute the sensor hub to slpi_pas rather than cdsp_pas. The list is now
every firmware-name property in the mainline device tree rather than a
recollection of forum posts, so it should be complete: eight files, not five.

WiFi and Bluetooth are unaffected — ath10k WCN3990 including wlanmdsp.mbn is
genuinely redistributable and genuinely shipped.

Add a section on locating the blobs on an old backup, for the case where
Windows is long gone from the machine.

Only comments changed in config/packages/base.pkgs, so the package set hashes
identically and the staged base stays valid.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XWRjNJMistCy6ngXH5aJLS
2026-07-27 12:51:01 +03:00
d168df0977 ci: build variants in a shell loop, not a dynamic matrix
Some checks failed
build image / build (push) Has been cancelled
The first run produced one job leg with an empty variant, and the build
rejected it. The prepare job was fine — it set variants=["minimal"] and the
output evaluated correctly — but Gitea's runner resolves strategy.matrix while
planning the workflow, before `needs` has produced anything, so
fromJSON(needs.prepare.outputs.variants) saw an empty string.

Dynamic matrices from needs outputs are not supported here. Drop the prepare
job and loop in shell instead: one job, no expression-engine dependency, and a
non-zero exit only after every requested variant has been attempted.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XWRjNJMistCy6ngXH5aJLS
2026-07-27 12:09:42 +03:00
4d1fd98683 Cache the expensive half of the build so iteration is cheap
Some checks failed
build image / prepare (push) Successful in 0s
build image / build (push) Failing after 29s
The dnf transaction is essentially the whole cost of a build — emulated rpm
scriptlets for 502 packages on minimal, 1929 on workstation. Everything after
it is minutes. Getting this laptop to boot will take several attempts at the
kernel command line and the dracut driver list, and paying for a reinstall each
time is not tenable.

Stage the post-dnf tree under <work>/base, keyed on a hash of the package
lists, release and variant, and copy it per build with --reflink=auto (a CoW
clone on btrfs). Config and overlay edits now reuse it; package list edits
invalidate it on their own, so --fresh is only needed to force the issue.

Keep downloaded rpms in a cachedir outside the install root, so even --fresh
re-runs the scriptlets without re-downloading. keepcache=0 was exactly the
wrong setting for a build meant to be run repeatedly.

Add --work so CI can put both outside the job workspace, which is wiped between
runs, and default the build container to the gongfoo aarch64 build base so the
assembly tooling is not installed under emulation every time. That image is a
speedup, not a dependency: fall back to stock Fedora when it is unreachable.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XWRjNJMistCy6ngXH5aJLS
2026-07-27 11:58:12 +03:00
280874f564 Build Fedora aarch64 images for the Lenovo Yoga C630
Assembles a ready-to-write disk image via Gitea Actions. Mainline has carried
sdm850-lenovo-yoga-c630.dts since 5.5 and Fedora ships it in kernel-core, so
unlike aarch64-laptops/build there is no kernel or GRUB to compile — what is
left is producing an image that boots on firmware which hands Linux no device
tree.

The build runs in an aarch64 container under qemu-user and builds filesystems
from directory trees with mke2fs -d and mcopy rather than mounting loop
devices, so it works on runners that will not hand out /dev/loop-control.

A kernel-install hook writes the devicetree line into each BLS entry; without
it the first `dnf update kernel` would produce an unbootable system.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XWRjNJMistCy6ngXH5aJLS
2026-07-27 11:24:53 +03:00