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:
192
docs/firmware.md
192
docs/firmware.md
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user