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
325 lines
13 KiB
Markdown
325 lines
13 KiB
Markdown
# Firmware
|
|
|
|
The C630's firmware splits into two groups, and the split is about licensing,
|
|
not difficulty.
|
|
|
|
## What ships in the image
|
|
|
|
Qualcomm permits redistribution of these, so Fedora packages them and the build
|
|
installs them:
|
|
|
|
| Package | Files | Enables |
|
|
|---|---|---|
|
|
| `atheros-firmware` | `ath10k/WCN3990/hw1.0/{firmware-5.bin,board-2.bin,wlanmdsp.mbn}` | WiFi and Bluetooth |
|
|
| `qcom-firmware` | `qcom/a630_gmu.bin`, `qcom/a630_sqe.fw` | The generic half of the Adreno 630 — necessary but not sufficient |
|
|
|
|
Networking therefore works on a freshly written image. Graphics does not: see
|
|
below.
|
|
|
|
## What you have to supply
|
|
|
|
These are signed against per-model keys and Fedora does not ship them, so a
|
|
stock install has none of them. Nothing about them is unredistributable in
|
|
principle — the equivalent files for the
|
|
ThinkPad X13s *are* in linux-firmware — it is that nobody has obtained
|
|
permission for this model. See [If you have no
|
|
backup](#if-you-have-no-backup).
|
|
|
|
The list is not a guess: it is every `firmware-name` property in the mainline
|
|
device tree, `arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts`:
|
|
|
|
| File | Device tree node | Lost without it |
|
|
|---|---|---|
|
|
| `qcdxkmsuc850.mbn` | `gpu_zap_shader` | **Accelerated graphics** |
|
|
| `qcadsp850.mbn` | `adsp_pas` | Audio — speakers, microphone |
|
|
| `qcslpi850.mbn` | `slpi_pas` | Sensor hub — lid switch, accelerometer, auto-rotate |
|
|
| `qccdsp850.mbn` | `cdsp_pas` | Compute DSP offload |
|
|
| `qcvss850.mbn` | `venus` | Hardware video decode |
|
|
| `qcdsp1v2850.mbn` | `mss_pil` | Modem, stage 1 |
|
|
| `qcdsp2850.mbn` | `mss_pil` | Modem, stage 2 |
|
|
| `ipa_fws.elf` | `ipa` | IPA datapath, needed by the modem |
|
|
|
|
They belong under `/lib/firmware/updates/qcom/sdm850/LENOVO/81JL/`.
|
|
|
|
The GPU one is worth calling out, because it is easy to assume otherwise:
|
|
Fedora does ship an `sdm845/a630_zap.mbn`, but that is the generic
|
|
Snapdragon 845 zap shader and **not** what this device asks for. The C630's
|
|
device tree names `qcom/sdm850/LENOVO/81JL/qcdxkmsuc850.mbn` specifically, so
|
|
until you supply it you get an unaccelerated display.
|
|
|
|
Each file is independent, so a partial recovery is still worth having —
|
|
`qcdxkmsuc850.mbn` on its own buys you working graphics.
|
|
|
|
### Confirmed on the hardware
|
|
|
|
This is not inferred from the device tree. On a machine with the generic
|
|
Adreno firmware present and the model-signed blob absent, the GPU gets two
|
|
files in and then stops:
|
|
|
|
```
|
|
[drm:adreno_request_fw] loaded qcom/a630_sqe.fw from new location
|
|
[drm:adreno_request_fw] loaded qcom/a630_gmu.bin from new location
|
|
[drm:zap_shader_load_mdt] *ERROR* Unable to load qcom/sdm850/LENOVO/81JL/qcdxkmsuc850.mbn
|
|
[drm:adreno_load_gpu] *ERROR* gpu hw init failed: -2
|
|
```
|
|
|
|
So the generic pieces are necessary and not sufficient, and the zap shader is a
|
|
hard requirement rather than an optimisation. Two details follow from that
|
|
trace:
|
|
|
|
The driver never falls back to `sdm845/a630_zap.mbn`, even though the file is
|
|
installed — the device tree's `firmware-name` pins the model-specific path. Nor
|
|
would falling back help: the zap shader is signed against the device's own
|
|
secure-boot chain, and the Snapdragon 845 development board's copy will not
|
|
validate here.
|
|
|
|
The display keeps working throughout. `msm_dpu` binds the panel and the console
|
|
lands on `msmdrmfb` regardless, so a failed GPU costs you acceleration, not a
|
|
picture. A desktop still runs on llvmpipe — though `/dev/dri/renderD128` is
|
|
present even when `hw init` has failed, so mesa may try freedreno, fail, and
|
|
take the display manager down with it. `LIBGL_ALWAYS_SOFTWARE=1` in
|
|
`/etc/environment` avoids that.
|
|
|
|
### These have to be in the initramfs
|
|
|
|
`msm_dpu` probes about six seconds in, while the initramfs is still the root
|
|
filesystem, and does not retry. Firmware that only exists on the real root is
|
|
therefore invisible to it:
|
|
|
|
```
|
|
msm_dpu ae01000.display-controller: Direct firmware load for qcom/a630_sqe.fw failed with error -2
|
|
```
|
|
|
|
`overlay/etc/dracut.conf.d/10-c630.conf` puts the Adreno files in the initramfs
|
|
for this reason, and `c630-firmware` adds `qcdxkmsuc850.mbn` once it exists.
|
|
|
|
Only the GPU needs this. The ADSP, CDSP, SLPI, venus and modem all probe around
|
|
forty seconds in, well after the real root is mounted, and load from it
|
|
perfectly happily. That distinction is worth keeping: `qcdsp2850.mbn` alone is
|
|
60 MB, so sweeping the whole firmware directory into the initramfs would inflate
|
|
it roughly twentyfold for no benefit.
|
|
|
|
## Finding them on a backup
|
|
|
|
If Windows is long gone from the machine but you kept a copy of the files, one
|
|
search catches all eight, since seven share a suffix:
|
|
|
|
```sh
|
|
find /mnt/backup -type f \
|
|
\( -iname 'qc*850.mbn' -o -iname 'ipa_fws.elf' -o -iname 'bdwlan*.bin' \) \
|
|
-printf '%10s %p\n'
|
|
```
|
|
|
|
They originally lived in `C:\Windows\System32\DriverStore\FileRepository\`, in
|
|
directories named `qcdx850.inf_arm64_*` and `qcadsp*.inf_arm64_*`. If the loose
|
|
files turn up nothing, look for those directories wholesale:
|
|
|
|
```sh
|
|
find /mnt/backup -type d -iname 'qc*.inf_arm64_*'
|
|
```
|
|
|
|
Sizes range from 14 KB (`qcdxkmsuc850.mbn`) to 60 MB (`qcdsp2850.mbn`).
|
|
Despite the `.mbn` extension they are ELF images, and `file` should say so:
|
|
|
|
```
|
|
qcdxkmsuc850.mbn: ELF 32-bit LSB executable, QUALCOMM DSP6, version 1 (SYSV)
|
|
```
|
|
|
|
Anything reporting as text or HTML is a download that went wrong.
|
|
|
|
Lenovo does not appear to publish a driver package for the 81JL containing
|
|
these. If the backups turn up nothing, see [If you have no
|
|
backup](#if-you-have-no-backup) — the files are not tied to your individual
|
|
machine, so yours is not the only possible source.
|
|
|
|
## If you have no backup
|
|
|
|
Losing the Windows partition is not the end of it, because **these blobs are
|
|
signed per model, not per machine**. A copy from any other Yoga C630 works on
|
|
yours.
|
|
|
|
The evidence is in linux-firmware itself, which already ships the exact
|
|
analogous set for the ThinkPad X13s — one copy serving every unit of that
|
|
model:
|
|
|
|
```
|
|
qcom/sc8280xp/LENOVO/21BX/qcdxkmsuc8280.mbn zap shader
|
|
qcom/sc8280xp/LENOVO/21BX/qcadsp8280.mbn audio
|
|
qcom/sc8280xp/LENOVO/21BX/qccdsp8280.mbn compute DSP
|
|
qcom/sc8280xp/LENOVO/21BX/qcslpi8280.mbn sensors
|
|
qcom/sc8280xp/LENOVO/21BX/qcvss8280.mbn video
|
|
```
|
|
|
|
A one-to-one match with the C630's list, differing only in the model. So these
|
|
files are redistributable once Lenovo and Qualcomm permit it — it is a
|
|
licensing question, not a technical one.
|
|
|
|
`qcom/sdm850/LENOVO/81JL/` has simply never been contributed. Fedora ships no
|
|
sdm850 model firmware at all, so it will not turn up in a `linux-firmware`
|
|
update. Three routes, easiest first:
|
|
|
|
**The WOA-Project reference drivers.** <https://github.com/WOA-Project/Qualcomm-Reference-Drivers>
|
|
collects the Windows-on-ARM driver packages by SoC. The C630's are three
|
|
cabinet files, and between them they hold every file this machine asks for:
|
|
|
|
| Cabinet | Contains |
|
|
|---|---|
|
|
| `qcdx850.cab` | `qcdxkmsuc850.mbn` (zap shader), `qcvss850.mbn` (venus) |
|
|
| `qcipa850.cab` | `ipa_fws.elf` |
|
|
| `qcsubsys850.cab` | `qcadsp850.mbn`, `qccdsp850.mbn`, `qcslpi850.mbn`, `qcdsp1v2850.mbn`, `qcdsp2850.mbn`, and `WLANMDSP.MBN` |
|
|
|
|
That last one is a bonus — the WiFi firmware, which is not in the device tree's
|
|
`firmware-name` list but is what the onboard ath10k needs.
|
|
|
|
`cabextract` or `7z x` will open them:
|
|
|
|
```sh
|
|
for f in qcdx850.cab qcipa850.cab qcsubsys850.cab; do 7z x -o./extracted "$f"; done
|
|
find ./extracted -iname 'qc*850.mbn' -o -iname 'ipa_fws.elf' -o -iname 'WLANMDSP.MBN'
|
|
```
|
|
|
|
Ignore the `_nm` and `_CLS` variants; the device tree asks for the plain names.
|
|
Verify what you get with `file` — they should report as
|
|
`ELF 32-bit LSB executable, QUALCOMM DSP6`, not as text or HTML.
|
|
|
|
**Lenovo's Digital Download Recovery Service.** Lenovo builds a Windows
|
|
recovery image against a machine's serial number and lets the owner download
|
|
it. That image contains `Windows/System32/DriverStore/FileRepository`, and
|
|
therefore all eight files. Slower than the cabinets, but it is unambiguously
|
|
your own machine's firmware.
|
|
|
|
**Another C630 owner.** The aarch64-laptops project is where these have
|
|
circulated before, and any 81JL's copy is as good as your own.
|
|
|
|
Whichever route, drop the result into `firmware/local/` and rebuild — see
|
|
[Baking firmware into the image](#baking-firmware-into-the-image).
|
|
|
|
## 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.
|
|
|
|
### Onboard WiFi needs the modem, and the modem needs firmware nobody publishes
|
|
|
|
The name gives it away: **wlan*mdsp*** is the WLAN *Modem* DSP. On SDM845 the
|
|
WiFi firmware is loaded by the modem subsystem, so `ath10k_snoc` binds to
|
|
`18800000.wifi` and then sits silent, waiting on a QMI service that only appears
|
|
once the modem is up. It never logs an error, because from its point of view
|
|
nothing has gone wrong yet.
|
|
|
|
The modem itself boots and then dies:
|
|
|
|
```
|
|
qcom-q6v5-mss 4080000.remoteproc: MBA booted without debug policy, loading mpss
|
|
qcom-q6v5-mss 4080000.remoteproc: fatal error received:
|
|
RFLM@rflm_qlnk.cpp:1087 [3,3] RF stuck in QLINK start state: 0x0 after maximum
|
|
remoteproc remoteproc0: crash detected ... recovering
|
|
```
|
|
|
|
QLINK is the RF front-end interface, and RF front-end wiring is board-specific
|
|
in a way the DSP and GPU images are not. The WOA-Project cabinets are Qualcomm
|
|
*reference* drivers: good enough for the SoC-level blobs, evidently not for this
|
|
machine's radio. It restarts about every 42 seconds until stopped.
|
|
|
|
Things that sound like they should help and do not:
|
|
|
|
- **`rmtfs`.** The modem stores its NV and calibration on the `modemst1`,
|
|
`modemst2`, `fsg` and `fsc` partitions and reaches them through the `rmtfs`
|
|
daemon. Fedora packages it, and it is disabled by default. Enabling it is
|
|
correct and worth doing — `sudo systemctl enable --now rmtfs` — but the QLINK
|
|
failure persists with it running. Its "failed to update start state" warnings
|
|
are its optional remoteproc-control helper and are harmless.
|
|
- **The `_nm` firmware variants.** `qcdsp1v2850_nm.mbn` and `qcdsp2850_nm.mbn`
|
|
are the no-modem images, 5.7 MB against 60 MB, analogous to the `modem_nm.mbn`
|
|
Fedora ships for generic sdm845. They are rejected before they even run:
|
|
`PBL returned unexpected status`.
|
|
- **Unplugging the USB WiFi dongle.** Different bus, different driver, no
|
|
interaction. `ath10k_snoc` is waiting on the modem, not competing for a radio.
|
|
|
|
A USB dongle or USB tethering from a phone is the practical answer.
|
|
|
|
### Audio is a kernel driver problem
|
|
|
|
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:
|
|
|
|
```
|
|
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.
|
|
|
|
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.
|
|
|
|
## Extracting them
|
|
|
|
The image ships Fedora's `qcom-firmware-extract`. Run it once:
|
|
|
|
```sh
|
|
sudo c630-firmware
|
|
sudo reboot
|
|
```
|
|
|
|
That wraps `qcom-firmware-extract` and regenerates the initramfs afterwards,
|
|
which matters — the ADSP firmware has to be available before the root
|
|
filesystem is mounted, and `overlay/etc/dracut.conf.d/10-c630.conf` only takes
|
|
effect on a rebuild.
|
|
|
|
If it cannot find Windows, mount it yourself and point the tool at it:
|
|
|
|
```sh
|
|
lsblk -o NAME,SIZE,FSTYPE,LABEL # find the NTFS partition
|
|
sudo mkdir -p /mnt/windows
|
|
sudo mount /dev/sda4 /mnt/windows
|
|
sudo qcom-firmware-extract --windows-dir /mnt/windows
|
|
```
|
|
|
|
`qcom-firmware-extract` was written for the Snapdragon 8cx and X Elite laptops.
|
|
If it does not recognise the SDM850, copy the files by hand — they are in
|
|
`Windows/System32/DriverStore/FileRepository/` under a `qcdx*.inf_arm64_*`
|
|
directory:
|
|
|
|
```sh
|
|
sudo find /mnt/windows/Windows/System32/DriverStore/FileRepository \
|
|
-iname 'qc*850.mbn' -o -iname 'ipa_fws.elf' -o -iname 'qcdxkmsuc850.mbn'
|
|
|
|
sudo mkdir -p /lib/firmware/updates/qcom/sdm850/LENOVO/81JL
|
|
sudo cp <each file> /lib/firmware/updates/qcom/sdm850/LENOVO/81JL/
|
|
sudo dracut --force --regenerate-all
|
|
```
|
|
|
|
Check it took:
|
|
|
|
```sh
|
|
dmesg | grep -iE 'remoteproc|adsp|cdsp'
|
|
```
|
|
|
|
## Baking firmware into the image
|
|
|
|
If you would rather not repeat the extraction on every reinstall, drop the files
|
|
into `firmware/local/` in this repo, mirroring the `/usr/lib/firmware/updates/`
|
|
layout:
|
|
|
|
```
|
|
firmware/local/qcom/sdm850/LENOVO/81JL/qcadsp850.mbn
|
|
firmware/local/qcom/sdm850/LENOVO/81JL/qccdsp850.mbn
|
|
...
|
|
```
|
|
|
|
`build/stage2.sh` picks them up automatically. They are gitignored, and should
|
|
stay that way — this repository is public and the blobs are not yours to
|
|
publish.
|