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
This commit is contained in:
2026-07-28 12:02:19 +03:00
parent 9b28150c86
commit 7585c5f147
2 changed files with 163 additions and 46 deletions

View File

@@ -217,8 +217,10 @@ Whichever route, drop the result into `firmware/local/` and rebuild — see
## What the firmware does not fix
Installing all of it still leaves two things broken, both for reasons that are
not about firmware. Recorded here so nobody repeats the search.
Installing all of it still leaves two things not working out of the box, for
reasons that are not about firmware. Audio turns out to be a missing Fedora
kernel module and is fixable today; onboard WiFi remains genuinely broken.
Recorded here so nobody repeats the search.
### Onboard WiFi: everything is in place except a working modem
@@ -261,12 +263,14 @@ said to show around 40.
#### The modem fetches wlanmdsp over TFTP
This is the step that is easy to miss, and the reason `tqftpserv` exists.
`tqftpserv` serves from `/lib/firmware/`, and the modem asks it for the WLAN
firmware by path:
The modem asks it for the WLAN firmware by path — but where tqftpserv serves
from depends on the version, and the layout below (from aarch64-laptops) does
**not** work with Fedora's current build; see [The tqftpserv paths above are
version-dependent](#the-tqftpserv-paths-above-are-version-dependent). On
current Fedora:
```sh
sudo mkdir -p /lib/firmware/readonly/firmware/image
sudo cp wlanmdsp.mbn /lib/firmware/readonly/firmware/image/
sudo ln -sf updates/qcom/sdm850/LENOVO/81JL/wlanmdsp.mbn /lib/firmware/wlanmdsp.mbn
```
The modem also wants a writable area, and says so in the `tqftpserv` journal:
@@ -276,10 +280,13 @@ The modem also wants a writable area, and says so in the `tqftpserv` journal:
[TQFTP] WRQ: /readwrite/server_check.txt
```
On current Fedora that lives in `/tmp/tqftpserv` (recreate after each boot, or
add a tmpfiles.d entry):
```sh
sudo mkdir -p /lib/firmware/readwrite/ota_firewall
sudo touch /lib/firmware/readwrite/ota_firewall/ruleset
sudo chmod -R 0777 /lib/firmware/readwrite
sudo mkdir -p /tmp/tqftpserv/ota_firewall
sudo touch /tmp/tqftpserv/ota_firewall/ruleset
sudo chmod -R 0777 /tmp/tqftpserv
```
Watching `journalctl -u tqftpserv` while starting the modem is the best
@@ -315,26 +322,67 @@ made to load.
#### Firmware has been eliminated as the variable
The test that narrows it: both projects publish the modem trio, and their
copies differ — the modem pair matches on size but not checksum. Both were
installed on this machine, with `rmtfs` and `tqftpserv` running and `wlanmdsp`
in the TFTP path. Both produce the **identical** QLINK failure.
The nine driver versions under `Lenovo/YogaC630/` contain five distinct
modem-firmware builds — `200.0.1.0` through `200.0.4.0` share one 2018-vintage
pair (a different mpss size from all later builds, and the closest match to
this machine's 2018-10 manufacture date), `200.0.10.0`, `200.0.11.0`,
`200.0.14.0`/`200.0.16.0`, and `200.0.19.0` are the others, and
aarch64-laptops' copies differ again by checksum. Every one of them was booted
on this machine, with `rmtfs` and `tqftpserv` running. Every one produces the
**identical** QLINK failure, crashing about 0.4 s after mpss comes up.
That is worth stating carefully. It does not show either set to be wrong, and
it does not make one more trustworthy than the other — the aarch64-laptops
copies come from a setup whose support table ticks WiFi, but on a 2019 kernel,
and neither set has been shown to work here. What it does show is that changing
firmware does not change the outcome.
So neither the firmware nor its vintage is the variable. Nor is the kernel
version, at least not recently: Fedora's 6.12.15 (`kernel-core` from koji,
booted with the same device tree) produces the identical crash. The
aarch64-laptops setup that ticked WiFi ran a 2019 5.x branch, so a very old
regression is not excluded — but their issue #51 records modem crash/recovery
lockups on that setup too, so "WiFi worked" and "the modem crashed" may well
have coexisted, with `wlanmdsp` loading in the window before the first crash.
An earlier note in this project's history has the crash loop at roughly 42 s;
today it is ~3.4 s. If those cadences are both real, what changed — and
whether a long first window is enough for `wlfw` to appear — is an open
question.
So the difference is not the firmware, and not the userspace services. What
remains is the kernel: that setup ran `aarch64-laptops/linux` branch `gpu`,
circa 2019 on 5.x, against 7.1.5 here. Both ath10k patches it applied are long
upstream — the device tree carries `qcom,snoc-host-cap-8bit-quirk` from the
first of them. Six years of `qcom-q6v5-mss` churn sits between the two.
#### What QLINK is, and what the modem reads before dying
That points at a kernel regression rather than anything missing on disk.
Confirming it means bisecting or booting an older kernel, which nothing here
does yet.
QLINK is the SerDes link between the SoC and the SDR845 RF transceiver chip;
`rflm_qlnk.cpp` is the modem firmware's manager for it. "Stuck in start state
0x0" means the transceiver never answered — the signature of a chip that is
absent, unpowered, or misconfigured. This unit is an LTE SKU (SIM slot,
factory-label IMEI, modem worked under Windows), so the chip is present and
functional; under Windows, ACPI and the Qualcomm PEP handle subsystem power,
and under device-tree boot whatever they did for the RF front end has no
equivalent. That is a hypothesis, not a finding — the DSDT keeps its power
management in opaque PEP tables, so it could not be confirmed from the tables
alone.
`rmtfs -v` shows the modem's storage dialogue in the half-second before the
crash: it opens `modem_fs1`, `modem_fs2`, `modem_fsg` and `modem_fsc`
successfully, requests two partitions Linux's rmtfs has never heard of —
`modem_fsg_oem_1` and `modem_fsg_oem_2`, names that appear inside the mpss
image itself, with no provider found in any WOA-Project cabinet — allocates
its 2 MB buffer, reads a superblock's worth, and dies. On this machine
`modemst1`/`modemst2` carry valid `IMGEFS1`/`IMGEFS2` filesystems, while
**`fsg` and `fsc` are entirely blank**. Byte copies of all four live in
`firmware/local/nv-backup/` (gitignored), taken before any experimentation.
#### The tqftpserv paths above are version-dependent
The `/lib/firmware/readonly/firmware/image/` and `/lib/firmware/readwrite/`
layout described earlier matches the old aarch64-laptops tqftpserv. Fedora's
current build is different: `/readwrite/*` is served from `/tmp/tqftpserv`
(tmpfs — anything created there is gone on reboot), and
`/readonly/firmware/image/<file>` resolves through the normal firmware search
path, i.e. `/lib/firmware/<file>`. So `wlanmdsp.mbn` needs to be reachable as
`/lib/firmware/wlanmdsp.mbn` (a symlink to the copy under `updates/` works),
and the writable tree belongs under `/tmp/tqftpserv/`.
The full Windows-side TFTP tree can be reconstructed, and was: the driver
INFs are TFTP-mapping manifests, and `mcfg_subsys_ext850.inf` maps 159 modem
configuration files — carrier configs and, notably, `mcfg_hw` hardware RF
configs for the SDX20 — into `readonly/firmware/image/modem_pr/mcfg/...`.
Serving all of it changes nothing: the modem crashes before requesting any of
it.
Things that sound like they should help and do not:
@@ -343,14 +391,24 @@ Things that sound like they should help and do not:
- **`rmtfs` alone.** Necessary, not sufficient. Its "failed to update start
state" warnings are its optional remoteproc-control helper and are harmless.
- **The `_nm` variants.** See above.
- **Any published firmware version.** All five distinct builds fail
identically; see above.
- **The MCFG configuration tree.** Served in full over TFTP; the modem never
gets far enough to ask for it.
- **`clk_ignore_unused pd_ignore_unused`.** Already on the command line
(postmarketOS ships the same for this machine).
Untried, in rough order of promise: the other eight driver versions under
`Lenovo/YogaC630/` (this machine's UEFI is `9UCN33WW(V2.06)` from 2019, and the
newest package may not be the right vintage); `mcfg_subsys_ext850.cab`, which
holds modem configuration data; and building `board-2.bin` from the C630's own
`bdwlan.*` files rather than relying on Fedora's.
Untried, in rough order of promise: reporting upstream — the error string
appears nowhere public, and linux-arm-msm (Bjorn Andersson, Dmitry Baryshkov,
Steev Klimaszewski all have C630 history) is where the RF-power hypothesis
could be confirmed or killed; Lenovo's Digital Download Recovery Service image
for this serial, which would show the exact original driver set and whatever
provides `modem_fsg_oem_*` under Windows; building `board-2.bin` from the
C630's own `bdwlan.*` files (only relevant once the modem stays up); and the
5.x aarch64-laptops kernel itself, to test whether its crash cadence leaves a
usable window.
### Audio is a kernel driver problem
### Audio: Fedora does not build the speaker-amp driver
The ADSP runs, the audio services register, and the codec answers:
@@ -358,23 +416,77 @@ The ADSP runs, the audio services register, and the codec answers:
wcd934x-slim 217:250:1:0: WCD934x chip id major 0x108, minor 0x1
```
So SLIMbus, the ADSP and the hardware are all fine. What fails is one sub-device
of the codec:
So SLIMbus, the ADSP and the hardware are all fine. The trail of suspicion
used to end at this SoundWire message:
```
qcom-soundwire wcd934x-soundwire.12.auto: din-ports (2) mismatch with controller (6)
platform sound: deferred probe pending: msm-snd-sdm845: SLIM Playback: codec dai not found
```
The codec's SoundWire block declares two data-in ports where the controller
expects six, so it never probes, so the sound card has no codec DAI and never
appears. That is a mismatch inside the kernel, and needs a kernel or
device-tree change rather than any blob.
The first line is a red herring. Since kernel 6.18 (commit `9e53a66a2f2f`,
"soundwire: qcom: deprecate qcom,din/out-ports") it is a warning: the
device-tree value overrides the register value afterwards and the probe
continues.
The real blocker is the second line. The device tree's `SLIM Playback` link
names four codec DAIs: the WCD9340, the SoundWire master inside it, and the
two WSA881x speaker amplifiers hanging off that master. Fedora's aarch64
kernel has never set `CONFIG_SND_SOC_WSA881X` — while the newer siblings
WSA883X and WSA884X, which the ThinkPad X13s needs, are both `=m`. With no
amplifier driver the two SoundWire slaves never bind, the machine driver
cannot find its DAIs, and the card sits in deferred probe forever.
Building the one missing module proves it. `sound/soc/codecs/wsa881x.c` is a
single self-contained file; compiled against the running kernel
(`kernel-devel`, `gcc`, `make`, then `make -C /lib/modules/$(uname -r)/build
M=$PWD modules` with `obj-m += snd-soc-wsa881x.o` and `snd-soc-wsa881x-objs :=
wsa881x.o`), installed under `/lib/modules/$(uname -r)/extra/` and picked up
by `depmod -a`, it autoloads on the SoundWire modalias at boot and the
`Lenovo-YOGA-C630-13Q50` card registers, headphone-jack detection included.
The UCM profile has been in alsa-ucm-conf since 2020; `alsaucm` itself is in
`alsa-ucm-utils`, so on the minimal image:
```sh
alsaucm -c Lenovo-YOGA-C630-13Q50 set _verb HiFi set _enadev Speaker
speaker-test -D plughw:0,0 -c2 -t sine -f 440 -l 1
```
The `overflow error on RX port` and register-read `-16` messages logged when a
stream stops are noise, seen on working sdm845 devices too.
**PipeWire needs one more thing.** The ADSP front-end advertises S24_LE
(24-bit samples in 32-bit containers) and then garbles it: playback runs
without any error, consumes data at the right rate, and powers every DAPM
widget — a byte-for-byte identical `/sys/kernel/debug/asoc` widget dump
against a working stream — while producing ~-48 dB of near-silence,
consistent with the samples being bit-shifted inside the container. PipeWire
prefers the widest format a device offers, so every PipeWire client (mpv,
GNOME, `pw-play`) is inaudible while `aplay` and `speaker-test`, which
default to S16_LE, work perfectly. This cost most of a day: the failure is
per-format, invisible in every log, and easy to misattribute to routing,
suspend/resume or per-stream volumes, all of which look guilty and are not.
`overlay/etc/wireplumber/wireplumber.conf.d/51-c630-alsa.conf` pins the
built-in card to S16_LE, which fixes every client. The underlying q6asm
format bug is worth a report to alsa-devel.
Unrelated to the hardware, two pieces of routing politics are worth knowing
on a machine like this: PipeWire's RAOP discovery will happily make a
neighbour's AirPlay speaker the default sink, and a newly connected
Bluetooth device also takes over the default. If sound "does not work",
check `wpctl status` for where the default actually points before blaming
the drivers.
The durable fix is one line of Fedora kernel config — flipping
`CONFIG_SND_SOC_WSA881X` to `=m` for aarch64, an easy case given the in-tree
device tree requires it and both newer WSA drivers are already enabled. Until
that lands, the module has to be built out of tree per kernel.
One thing worth knowing if you go looking: `slim_qcom_ngd_ctrl` can probe before
the ADSP is ready and log `QMI wait timeout`. Reloading the module afterwards
gets the codec detected, which is how the chip ID above was obtained — but it
does not get past the SoundWire mismatch.
gets the codec detected, which is how the chip ID above was obtained. A series
of NGD probe-ordering fixes (Bjorn Andersson, mid-2026, Cc: stable) targets
exactly this class of race and should reach Fedora with the 7.2 rebase.
## Extracting them