Abstract
Les laptops Intel Meteor Lake (Lenovo Yoga Pro 9, Legion, etc.) souffrent d’instabilités audio sévères sous Linux avec la pile SOF + SoundWire + TAS2781. Après une analyse approfondie du stack (SOF, SoundWire, tas2781-hda, runtime PM, non-idempotence), la cause racine a été identifiée : l’initialisation du DSP du TAS2781 est non idempotente et dépend du chargement correct de son firmware.
Sur les distributions qui livrent le firmware en .zst (Arch Linux, CachyOS, Fedora Rawhide…), le driver tas2781-hda ne décompresse pas automatiquement le fichier → le DSP reste muet → son pourri (aigus seulement, pas de basses).
Solution définitive : forcer le mode HDA legacy (dsp_driver=1) + décompression permanente du firmware TAS2781. Stabilité 100 % dès le premier boot, même après mises à jour.
1. Introduction
Les plateformes Meteor Lake ont abandonné le vieux HDA au profit de SOF + SoundWire. Sur papier, c’est plus moderne, plus économe, plus puissant. En pratique, sous Linux, c’est souvent instable : coupures, son dégradé, besoin de plusieurs reboots, etc.
Cet article documente le problème sur un Lenovo Yoga Pro 9 16IMH9 et propose la solution qui marche à tous les coups.
2. Matériel et environnement
- Machine : Lenovo Yoga Pro 9 16IMH9 (Meteor Lake-P)
- Amplificateur : Texas Instruments TAS2781 (via SoundWire + I²C)
- Kernel : 6.12.68-2-cachyos-lts (et toutes les versions récentes concernées)
- Audio stack : ALSA + PipeWire
- Distribution : CachyOS (mais le bug existe aussi sur Arch, Fedora, etc.)
3. Analyse du problème (résumé des observations initiales)
- Le son devient aléatoirement dégradé (aigus seulement, basses mortes, distorsion).
- Un simple reboot ne suffit pas toujours → parfois 2 ou 3 reboots consécutifs sont nécessaires.
- Le mode SOF (dsp_driver=0) est instable.
- Le mode HDA legacy (dsp_driver=1) est parfaitement stable dès le premier boot.
- Le driver tas2781-hda se lie correctement (bound i2c-TIAS2781:00), mais le DSP du TAS2781 n’a parfois jamais reçu son firmware.
4. La cause racine sur Arch/CachyOS (découverte finale)
Sur CachyOS (et Arch), linux-firmware fournit les blobs TAS2781 compressés en .zst :
text
/lib/firmware/ti/audio/tas2781/TAS2XXX2326.bin.zst
Le driver snd_hda_scodec_tas2781_i2c demande exactement TAS2XXX2326.bin (sans .zst). Le firmware loader du noyau ne décompresse pas automatiquement ce fichier dans ce contexte précis → le DSP du TAS2781 reste sans configuration → son pourri.
C’est pourquoi le problème disparaissait parfois après plusieurs reboots (hasard du timing de décompression ou de re-probe).
5. Solution définitive (valable sur toutes les distros utilisant .zst)
5.1 Forcer le mode HDA legacy (stable à 100 %)
fish
sudo tee /etc/modprobe.d/disable-sof.conf <<EOF
options snd_intel_dspcfg dsp_driver=1
EOF
sudo reboot
5.2 Décompresser le firmware TAS2781 une bonne fois pour toutes
fish
sudo zstd -d /lib/firmware/ti/audio/tas2781/TAS2XXX2326.bin.zst \
-o /lib/firmware/TAS2XXX2326.bin
5.3 Rendre le fix permanent (même après pacman -Syu linux-firmware)
fish
# Script
sudo tee /usr/local/bin/fix-tas2781-firmware.fish <<'EOF'
#!/usr/bin/fish
set FW_SRC /lib/firmware/ti/audio/tas2781/TAS2XXX2326.bin.zst
set FW_DST /lib/firmware/TAS2XXX2326.bin
if test -f $FW_SRC; and not test -f $FW_DST
echo "Décompression TAS2781 firmware..."
sudo zstd -d $FW_SRC -o $FW_DST
echo "OK → $FW_DST créé"
else
echo "Firmware déjà OK"
end
EOF
sudo chmod +x /usr/local/bin/fix-tas2781-firmware.fish
fish
# Service systemd
sudo tee /etc/systemd/system/tas2781-firmware.service <<EOF
[Unit]
Description=Décompresse TAS2781 firmware (.zst → .bin)
After=multi-user.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/fix-tas2781-firmware.fish
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now tas2781-firmware.service
Après ça, même après une mise à jour du firmware, le son reste parfait au prochain boot.
6. Que faire pour quand même avoir SOF à jour ?
Le bug SOF/SoundWire/TAS2781 est toujours présent upstream (non-idempotence + gestion d’énergie). En attendant un vrai fix dans le noyau, le mode HDA legacy est la seule solution stable aujourd’hui.
Conclusion
Le problème n’était pas un bug de SOF en lui-même, mais une combinaison fatale :
- initialisation non idempotente du TAS2781
- firmware fourni en .zst sur Arch/CachyOS
- driver qui ne décompresse pas
Avec le mode HDA + le service de décompression, le son est maintenant parfaitement stable sur mon Yoga Pro 9, même après des dizaines de reboots/suspensions/mises à jour.
Merci à tous ceux qui ont signalé le même problème. Le workaround est maintenant documenté et reproductible.
Quand le son est mauvais :
ls /sys/bus/i2c/devices/ | grep TAS
Si i2c-TIAS2781:00 :
sudo sh -c ‘echo 1 > /sys/bus/i2c/devices/i2c-TIAS2781:00/delete_device’
sleep 2
sudo sh -c ‘echo TIAS2781 0x38 > /sys/bus/i2c/devices/i2c-*/new_device’
Si le son redevient normal immédiatement, c’est une preuve directe d’un bug de reset / init ampli.
(27/41) mise à jour de libavif [——————————————————————–] 100%
(28/41) mise à jour de libheif [——————————————————————–] 100%
(29/41) mise à jour de libwacom [——————————————————————–] 100%
(30/41) mise à jour de nanobind [——————————————————————–] 100%
(31/41) mise à jour de pipewire-alsa [——————————————————————–] 100%
(32/41) mise à jour de pipewire-pulse [——————————————————————–] 100%
(33/41) mise à jour de shiboken6 [——————————————————————–] 100%
(34/41) mise à jour de pyside6 [——————————————————————–] 100%
(35/41) mise à jour de python-cryptography [——————————————————————–] 100%
(36/41) mise à jour de python-gbinder [——————————————————————–] 100%
(37/41) mise à jour de python-internetarchive [——————————————————————–] 100%
(38/41) mise à jour de python-orjson [——————————————————————–] 100%
(39/41) mise à jour de python-psutil [——————————————————————–] 100%
(40/41) mise à jour de unrar [——————————————————————–] 100%
(41/41) mise à jour de vivaldi [——————————————————————–] 100%
:: Exécution des crochets (« hooks ») de post-transaction…
( 1/14) Creating system user accounts…
( 2/14) Creating temporary files…
/usr/lib/tmpfiles.d/systemd.conf:35: Duplicate line for path « /var/lib/systemd/coredump », ignoring.
( 3/14) Updating udev hardware database…
( 4/14) Applying kernel sysctl settings…
( 5/14) Reloading system manager configuration…
( 6/14) Reloading user manager configuration…
( 7/14) Restarting marked services…
( 8/14) Reloading device manager configuration…
( 9/14) Arming ConditionNeedsUpdate…
(10/14) Update Nvidia module in initcpio (for DRM KMS)
==> Building image from preset: /etc/mkinitcpio.d/linux-cachyos-lts.preset: ‘default’
==> Using default configuration file: ‘/etc/mkinitcpio.conf’
-> -k /boot/vmlinuz-linux-cachyos-lts -g /boot/initramfs-linux-cachyos-lts.img
==> Starting build: ‘6.12.68-2-cachyos-lts’
-> Running build hook: [base]
-> Running build hook: [udev]
-> Running build hook: [autodetect]
-> Running build hook: [microcode]
-> Running build hook: [kms]
-> Running build hook: [modconf]
-> Running build hook: [block]
-> Running build hook: [keyboard]
-> Running build hook: [keymap]
-> Running build hook: [consolefont]
==> WARNING: consolefont: no font found in configuration
-> Running build hook: [plymouth]
-> Running build hook: [filesystems]
==> Generating module dependencies
==> Creating zstd-compressed initcpio image: ‘/boot/initramfs-linux-cachyos-lts.img’
-> Early uncompressed CPIO image generation successful
==> Initcpio image generation successful
==> Building image from preset: /etc/mkinitcpio.d/linux-cachyos.preset: ‘default’
==> Using default configuration file: ‘/etc/mkinitcpio.conf’
-> -k /boot/vmlinuz-linux-cachyos -g /boot/initramfs-linux-cachyos.img
==> Starting build: ‘6.18.8-3-cachyos’
-> Running build hook: [base]
-> Running build hook: [udev]
-> Running build hook: [autodetect]
-> Running build hook: [microcode]
-> Running build hook: [kms]
-> Running build hook: [modconf]
-> Running build hook: [block]
-> Running build hook: [keyboard]
-> Running build hook: [keymap]
-> Running build hook: [consolefont]
==> WARNING: consolefont: no font found in configuration
-> Running build hook: [plymouth]
-> Running build hook: [filesystems]
==> Generating module dependencies
==> Creating zstd-compressed initcpio image: ‘/boot/initramfs-linux-cachyos.img’
-> Early uncompressed CPIO image generation successful
==> Initcpio image generation successful
(11/14) Compiling GSettings XML schema files…
(12/14) Updating icon theme caches…
(13/14) Checking which packages need to be rebuilt
foreign python-backports-zstd
(14/14) Updating the desktop file MIME type cache…
~ 1m 15s
❯
# Stop PipeWire pour libérer le device
systemctl –user stop pipewire pipewire-pulse wireplumber
# Décharge le driver TAS2781
sudo modprobe -r snd_hda_scodec_tas2781_i2c
# Attente
sleep 3
# Recharge le driver (il va re-lire le firmware et réinitialiser le DSP)
sudo modprobe snd_hda_scodec_tas2781_i2c
# Redémarre PipeWire
systemctl –user start pipewire pipewire-pulse wireplumber