El kernel ya traía el driver (SND_SOC_SOF_TIGERLAKE); faltaban los blobs, y sin ellos SOF carga y falla: en el laptop no hay sonido aunque ALSA esté. Mismo patrón que i915 con su DMC/GuC — driver desde fuente, firmware pineado por contenido, porque Intel no libera el código y la soberanía build-from-source no aplica a datos fijos. Tres piezas, cada una por un motivo distinto: - `sof-tgl.ri` + `sof-tgl-h.ri`: el firmware del DSP. Se copian LOS DOS porque el driver elige según el SKU y no quiero hornear la suposición. **`cp -L` es obligatorio**: en linux-firmware son SYMLINKS a `intel-signed/`, y un symlink relativo copiado a otro árbol apunta a la nada. Verificado: los tres quedan ficheros reales (525K/447K/95K). - `sof-tgl.ldc`: el diccionario de logs del DSP. No es opcional en la práctica — el driver lo pide al inicializar y sin él el firmware arranca SIN TRAZA, o sea que el día que algo falle no hay por dónde mirar. - 47 topologías (`sof-hda-generic-*`, `sof-tgl-*`): describen el grafo de audio. El driver pide UNA por nombre derivado de la máquina, y no se puede saber cuál sin el hardware delante. Copiar de más cuesta megas; copiar de menos cuesta un viaje físico al laptop para descubrir qué nombre pidió. ~3 MB en total. Si no hay SOF en el origen, AVISA y NO falla: el audio del laptop se pierde pero la imagen sigue booteando y en QEMU suena por HDA legacy — fallar bloquearía builds que no necesitan SOF. Verificado que no hay regresión: con los blobs en la imagen, el audio de la VM sigue funcionando por la ruta HDA (48. HDA Intel [alsa], sink y source reales) y cero page-flips fallidos. **El camino SOF en sí queda SIN VALIDAR hasta el próximo viaje al metal** — en QEMU no se ejerce, y eso está escrito en la receta del kernel en vez de dado por bueno. De paso, la cabecera del script deja de mentir: se llama «firmware» y no «wifi» porque copia las TRES familias de blobs que el metal necesita (iwlwifi, i915, SOF). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
103 lines
5.2 KiB
Bash
Executable File
103 lines
5.2 KiB
Bash
Executable File
#!/usr/bin/env sh
|
|
# metal-firmware.sh — inyecta el firmware del WiFi AX201 (y reg.db) en /lib/firmware de un rootfs.
|
|
#
|
|
# El firmware de iwlwifi son BLOBS binarios NO compilables desde fuente (Intel no libera el código); la
|
|
# soberanía de hammer (build-from-source) no aplica acá — son datos fijos como el microcódigo de la CPU.
|
|
# Se fijan por contenido (igual que un tarball pinned): se copian de un linux-firmware ya presente y se
|
|
# descomprimen a .ucode plano (el kernel metal NO habilita FW_LOADER_COMPRESS, así evitamos esa dep).
|
|
#
|
|
# Target: Intel Wi-Fi 6 AX201 [8086:a0f0] en TigerLake ⇒ familias QuZ-a0-hr-b0 + cc-a0 (el driver elige
|
|
# la API más alta que soporta) + regulatory.db(+.p7s) que cfg80211 verifica con la clave built-in.
|
|
#
|
|
# Copia además el firmware de i915 (DMC/GuC/HuC) y el de SOF (el DSP de audio de TigerLake). El nombre
|
|
# del script dice «firmware» y no «wifi» a propósito: son las tres familias de blobs que el metal
|
|
# necesita y ninguna se construye desde fuente.
|
|
#
|
|
# Uso: scripts/metal-firmware.sh <rootfs-dir>
|
|
# Vars: FWSRC dir origen del firmware (default /lib/firmware del host)
|
|
#
|
|
# TODO(soberanía): reemplazar FWSRC=host por un pin a un commit de linux-firmware (recipe fetch+extract).
|
|
set -eu
|
|
|
|
DST="${1:?uso: metal-firmware.sh <rootfs-dir>}"
|
|
FWSRC="${FWSRC:-/lib/firmware}"
|
|
OUT="$DST/lib/firmware"
|
|
mkdir -p "$OUT"
|
|
|
|
# patrones de firmware que el AX201 puede pedir (ambas familias, todas las API presentes)
|
|
PATTERNS="iwlwifi-QuZ-a0-hr-b0-*.ucode iwlwifi-cc-a0-*.ucode"
|
|
n=0
|
|
for pat in $PATTERNS; do
|
|
for src in "$FWSRC"/$pat "$FWSRC"/$pat.zst "$FWSRC"/$pat.xz; do
|
|
[ -e "$src" ] || continue
|
|
base=$(basename "$src")
|
|
case "$base" in
|
|
*.zst) dst="$OUT/${base%.zst}"; zstd -q -d -f -o "$dst" "$src" ;;
|
|
*.xz) dst="$OUT/${base%.xz}"; xz -dc "$src" > "$dst" ;;
|
|
*) dst="$OUT/$base"; cp "$src" "$dst" ;;
|
|
esac
|
|
n=$((n+1))
|
|
done
|
|
done
|
|
|
|
# regulatory db (texto firmado; cfg80211 lo carga vía firmware loader y verifica .p7s con clave built-in)
|
|
for f in regulatory.db regulatory.db.p7s; do
|
|
if [ -e "$FWSRC/$f" ]; then cp "$FWSRC/$f" "$OUT/$f"; n=$((n+1)); fi
|
|
done
|
|
|
|
# i915 (panel/GPU TigerLake): DMC (enciende el display tras ExitBootServices) + GuC/HuC. El driver pide
|
|
# versiones EXACTAS por nombre; copiamos TODAS las tgl_* (1.3M) para que encuentre la que su versión usa.
|
|
mkdir -p "$OUT/i915"
|
|
for src in "$FWSRC"/i915/tgl_*.bin "$FWSRC"/i915/tgl_*.bin.zst; do
|
|
[ -e "$src" ] || continue
|
|
base=$(basename "$src")
|
|
case "$base" in
|
|
*.zst) zstd -q -d -f -o "$OUT/i915/${base%.zst}" "$src" ;;
|
|
*.xz) xz -dc "$src" > "$OUT/i915/${base%.xz}" ;;
|
|
*) cp "$src" "$OUT/i915/$base" ;;
|
|
esac
|
|
n=$((n+1))
|
|
done
|
|
|
|
# SOF (Sound Open Firmware) para TigerLake. Intel movió el audio de TGL al DSP: el kernel trae el
|
|
# driver (`SND_SOC_SOF_TIGERLAKE`, encendido en linux-metal) pero **sin estos blobs carga y falla**, y en
|
|
# el laptop no hay sonido aunque ALSA esté. En QEMU no importa: ahí manda la ruta HDA legacy.
|
|
# Es el mismo patrón que i915 con su DMC/GuC — driver de fuente, firmware pineado por contenido.
|
|
#
|
|
# Tres piezas, y las tres hacen falta por motivos distintos:
|
|
# · sof-tgl.ri / sof-tgl-h.ri el firmware del DSP (LP y H). Se copian los DOS porque el driver
|
|
# elige según el SKU y no queremos hornear la suposición. **`cp -L`**: en linux-firmware son
|
|
# SYMLINKS a `intel-signed/`, y un symlink relativo copiado a otro árbol apunta a la nada.
|
|
# · sof-tgl.ldc el diccionario de logs del DSP. No es opcional en la práctica: el driver lo pide al
|
|
# inicializar y, si falta, el firmware arranca sin traza — o sea que el día que algo falle no hay
|
|
# por dónde mirar. 95 KB.
|
|
# · sof-tplg/*.tplg las TOPOLOGÍAS: describen el grafo de audio (qué DAI, cuántos canales, qué
|
|
# códec). El driver pide UNA por nombre, derivado de la máquina, y no se puede saber cuál sin el
|
|
# hardware delante. Se copian las `sof-hda-generic-*` (el caso HDA sobre SOF, que es el del target)
|
|
# y las `sof-tgl-*` — ~2 MB en total. Copiar de más cuesta megas; copiar de menos cuesta un viaje
|
|
# físico al laptop para descubrir qué nombre pidió.
|
|
mkdir -p "$OUT/intel/sof" "$OUT/intel/sof-tplg"
|
|
for src in "$FWSRC"/intel/sof/sof-tgl.ri "$FWSRC"/intel/sof/sof-tgl-h.ri "$FWSRC"/intel/sof/sof-tgl.ldc; do
|
|
[ -e "$src" ] || continue
|
|
cp -L "$src" "$OUT/intel/sof/$(basename "$src")"
|
|
n=$((n+1))
|
|
done
|
|
for src in "$FWSRC"/intel/sof-tplg/sof-hda-generic-*.tplg "$FWSRC"/intel/sof-tplg/sof-tgl-*.tplg; do
|
|
[ -e "$src" ] || continue
|
|
cp -L "$src" "$OUT/intel/sof-tplg/$(basename "$src")"
|
|
n=$((n+1))
|
|
done
|
|
sof_ri=$(ls "$OUT"/intel/sof/*.ri 2>/dev/null | wc -l)
|
|
sof_tplg=$(ls "$OUT"/intel/sof-tplg/*.tplg 2>/dev/null | wc -l)
|
|
if [ "$sof_ri" -eq 0 ]; then
|
|
# Aviso y NO error: el audio del laptop se pierde, pero la imagen sigue booteando y en QEMU suena por
|
|
# HDA legacy. Fallar acá bloquearía builds que no necesitan SOF.
|
|
echo "metal-firmware: ⚠ SIN firmware SOF en $FWSRC/intel/sof — el laptop TigerLake no tendrá audio" >&2
|
|
else
|
|
echo "metal-firmware: SOF = $sof_ri .ri + $sof_tplg topologías"
|
|
fi
|
|
|
|
[ "$n" -gt 0 ] || { echo "metal-firmware: NO encontré firmware AX201 en $FWSRC" >&2; exit 1; }
|
|
echo "metal-firmware: $n blobs → $OUT"
|
|
ls "$OUT" | sed 's/^/ /'
|