Out of the box the ProArt PX13 plays audio fine over HDMI but the internal speakers are completely silent — PipeWire only ever shows a generic “Dummy Output” sink. Getting real, persistent sound out of this laptop turned out to require fixing three independent bugs stacked on top of each other: a missing calibration firmware blob, a missing ALSA UCM profile (plus a broken UCM control reference), and a SoundWire/ACP controller that doesn’t survive boot or suspend/resume cleanly.

This post walks through the actual root cause of each layer and the fix that was applied for each one. All of the code, configs, systemd units and calibration firmware are published at github.com/brainchillz/asus-proart-px13-linux-speaker-fix.

The starting symptom

aplay -l and wpctl status showed two cards:

card 0: HDMI (Generic HD-Audio)        -> works fine
card 1: amd-soundwire (rt721-sdca codec + 2x TAS2783 smart amp) -> speakers, no sound

PipeWire’s default sink was a synthetic “Dummy Output” — the telltale sign that PipeWire’s ALSA card profile (ACP) couldn’t find any usable playback device on card 1 at all.

Bug #1: Missing TAS2783 calibration firmware

Root cause

The internal speakers are driven by two TI TAS2783 SoundWire “smart amp” chips. Smart amps like this don’t just amplify — they run a DSP model of the speaker (impedance, thermal limits, excursion protection) that has to be calibrated per laptop chassis. The kernel’s slave-tas2783 SoundWire driver loads this calibration data as a firmware blob, and it derives the filename from the PCI subsystem ID, the SoundWire link number, and the slave’s bus address:

<subsystem-id>-<sdw-link>-<sdw-addr>.bin

# For this laptop (ASUS subsystem ID 0x1714, SoundWire link 1,
# slave addresses 0x8 and 0xB):
1714-1-8.bin
1714-1-B.bin

linux-firmware (as of mid-2026) only ships TAS2783 calibration blobs for a handful of HP/Dell subsystem IDs (8E86, 8E87, 8EF5, 8EF6, etc.). There is no ASUS 1714 blob upstream at all. The result, visible in journalctl -k -b 0 | grep -i tas2783:

slave-tas2783 sdw:0:1:0102:0000:01:8: Direct firmware load for 1714-1-8.bin failed with error -2
slave-tas2783 sdw:0:1:0102:0000:01:8: Failed to read fw binary 1714-1-8.bin
slave-tas2783 sdw:0:1:0102:0000:01:8: error playback without fw download
slave-tas2783 sdw:0:1:0102:0000:01:8: ASoC error (-22): at snd_soc_dai_hw_params() on tas2783-codec
 SDW1-PIN1-PLAYBACK-SmartAmp: ASoC error (-22): at __soc_pcm_hw_params() on SDW1-PIN1-PLAYBACK-SmartAmp

Without the calibration blob, the amp’s DSP never finishes initializing, so hw_params() on the SmartAmp playback DAI fails outright (-22 EINVAL) and the amp never produces audio. This is entirely independent of ALSA mixer levels, mute state, or PipeWire configuration — the amp simply refuses to play anything.

The fix

The calibration blobs do exist, just not in linux-firmware — they ship inside ASUS’s official Windows “TI SmartAMP” driver package for this laptop model. The package is an InstallAware self-extracting EXE (not Inno Setup, so innoextract doesn’t work on it). The blobs were recovered by running the installer under wine64 and snapshotting its self-extraction temp directory:

Firmwares/1714-1-0x8.bin  ->  1714-1-8.bin
Firmwares/1714-1-0xB.bin  ->  1714-1-B.bin

The fix script installs each blob to both of the paths the kernel driver looks in (the generic firmware search path and the TAS2783-specific subdirectory):

/lib/firmware/1714-1-8.bin
/lib/firmware/1714-1-B.bin
/lib/firmware/ti/audio/tas2783/1714-1-8.bin
/lib/firmware/ti/audio/tas2783/1714-1-B.bin

From fix-px13-audio.sh:

echo "==> Installing TAS2783 calibration firmware..."
sudo install -m 644 "$SCRIPT_DIR/firmware/1714-1-8.bin" /lib/firmware/1714-1-8.bin
sudo install -m 644 "$SCRIPT_DIR/firmware/1714-1-B.bin" /lib/firmware/1714-1-B.bin
sudo install -d -m 755 /lib/firmware/ti/audio/tas2783
sudo install -m 644 "$SCRIPT_DIR/firmware/1714-1-8.bin" /lib/firmware/ti/audio/tas2783/1714-1-8.bin
sudo install -m 644 "$SCRIPT_DIR/firmware/1714-1-B.bin" /lib/firmware/ti/audio/tas2783/1714-1-B.bin
Note on provenance / licensing

These blobs are TI/ASUS proprietary calibration data extracted from ASUS’s own Windows driver package for this exact model. The fix repo is intentionally private about the binaries and they are not redistributed publicly — only the scripts and configs that consume them.

After installing the firmware and re-binding the slave-tas2783 driver (echo <dev> > /sys/bus/soundwire/drivers/slave-tas2783/{unbind,bind}), the “Direct firmware load … failed” / “error playback without fw download” messages disappeared. Bug #1 fixed — but the speakers still produced no sound, because of bug #2.

Bug #2: No ALSA UCM “Speaker” device, and a broken control reference

Even with the firmware loading cleanly and raw ALSA playback to hw:1,2 (the TAS2783 SmartAmp PCM) working, PipeWire still only exposed “Dummy Output”. This turned out to be two separate UCM (Use Case Manager) bugs.

2a. Root cause: no upstream UCM profile for tas2783

PipeWire’s ALSA Card Profile (ACP) module decides what sinks/sources to expose for a card by reading its UCM2 configuration (/usr/share/alsa/ucm2/...). For SOF SoundWire cards, the generic profile at conf.d/amd-soundwire/amd-soundwire.conf / sof-soundwire/HiFi.conf derives which devices exist by parsing the kernel’s alsa.components string for this card, which for this machine is:

 cfg-amp:2 hs:rt721

HiFi.conf only adds a "Speaker" SectionDevice if it finds a spk:<codec> token in that string via its SpeakerCodec DefineRegex. This machine’s components string has cfg-amp:2 (two amps) but no spk: token — and even if it did, there is no tas2783.conf codec profile anywhere in upstream alsa-ucm-conf, for any machine. So SpeakerCodec1 resolves to empty, no Speaker device is ever defined, and PipeWire’s ACP only ever sees the rt721 codec’s “Headphones” and “Headset Microphone” devices — never the internal speaker amp.

2a. Fix: a local tas2783 UCM profile + a card-specific override

Two new UCM files were added (neither is part of any package, so a future alsa-ucm-conf upgrade that overwrites /usr/share/alsa/ucm2 could remove them). First, /usr/share/alsa/ucm2/sof-soundwire/tas2783.conf — a minimal Speaker device pointing at PCM device 2 (the SmartAmp playback PCM, confirmed working via aplay -D hw:1,2):

# Speaker device for the TI TAS2783 SoundWire smart amp, used on
# (at least) the ASUS ProArt PX13 (HN7306, Strix Halo). Upstream
# alsa-ucm-conf has no codec profile for tas2783 yet, so this is a
# minimal local addition. PCM device 2 is the SmartAmp playback
# device exposed by the snd_acp_sdw_legacy_mach machine driver.

SectionDevice."Speaker" {
	Comment "Speaker"

	Value {
		PlaybackPriority 100
		PlaybackPCM "hw:${CardId},2"
		PlaybackChannels 2
	}
}

Second, a card-long-name-specific override at /usr/share/alsa/ucm2/conf.d/amd-soundwire/ASUSTeKCOMPUTERINC.-ProArtPX13HN7306EAC-1.0-HN7306EAC.conf. This file takes priority over the generic amd-soundwire.conf for this exact card long-name. It’s a full copy of the generic file with one line appended after all the existing multi-codec If blocks, so it doesn’t disturb the working rt721 headset/mic logic, but still forces the Speaker device in:

# --- Local addition for this machine ---
# alsa.components for this card ("cfg-amp:2 hs:rt721") does not include
# a " spk:<codec>" token, so SpeakerCodec1 above resolves to "" and the
# generic sof-soundwire HiFi profile never adds a "Speaker" device. This
# machine has a TAS2783 SoundWire smart amp on PCM device 2 (confirmed
# via `aplay -D hw:1,2`). Force-select our local tas2783.conf, which adds
# a minimal "Speaker" SectionDevice. This override is applied after the
# multi-codec If blocks above so it doesn't disturb the rt721 headset
# handling.
Define.SpeakerCodec1 "tas2783"

After installing these and restarting PipeWire/WirePlumber, a new sink “Audio Coprocessor Speaker” appeared… but speaker-test against it produced no audible sound, exit code 0, no errors. That led to bug 2b.

2b. Root cause: disdevall chokes on a “Headphone Switch” control that doesn’t exist

Investigation with strace on alsaucm -c amd-soundwire set _verb HiFi showed it failing outright:

ALSA lib main.c:843:(execute_sequence) [error.ucm] unable to execute cset 'name='Headphone Switch' off'
ALSA lib main.c:2863:(set_verb_user) [error.ucm] failed to initialize new use case: HiFi
alsaucm: error failed to set _verb=HiFi: No such file or directory

The chain of causes here is subtle:

So disdevall tries to run a cset against a non-existent control, that single cset failure aborts the entire set _verb HiFi call, and PipeWire/ACP — unable to activate the HiFi UCM verb at all — silently falls back to its generic, built-in “stereo-fallback” profile. That profile plays to hw:1 (the raw card default, i.e. the rt721 codec path), not hw:1,2 (the TAS2783 SmartAmp). Hence: speaker-test runs cleanly and reports success, but the audio goes to a PCM the smart amp never sees — silence.

Two approaches that did NOT work

Left here because they’re instructive about how UCM resolves includes: Adding a SectionDevice."Headphones" override directly in the card-specific conf.d file → error: "unknown master file field SectionDevice"SectionDevice is only valid inside a UseCase file, not a master conf.d file. Defining Define.MultiCodec1 "rt721-px13" to redirect HiFi.conf’s multicodec include to a forked rt721-px13.conf → had no effect. ${var:MultiCodec1} is resolved once at DefineRegex-evaluation time and isn’t retroactively changed by a later Define. statement; strace confirmed the original rt721.conf was still the file opened.

2b. Fix: patch rt721.conf directly

The fix that actually worked was to directly patch /usr/share/alsa/ucm2/sof-soundwire/rt721.conf and empty out SectionDevice."Headphones"’s Enable/DisableSequence blocks (leaving its Value — routing, jack control, priority — untouched):

SectionDevice."Headphones" {
	Comment	"Headphones"

	# --- Local change for ASUS ProArt PX13 (HN7306) ---
	# This rt721-sdca codec/driver does not expose a "Headphone Switch"
	# control (only "rt721 FU05/FU06 Playback Volume", no mute switches -
	# see `amixer -c1 controls`). HiFi.conf's SectionVerb EnableSequence
	# runs "disdevall" (disable all devices) on verb activation, so the
	# missing control made `alsaucm set _verb HiFi` fail entirely, which
	# made PipeWire/ACP fall back to "stereo-fallback" instead of using
	# the local "Speaker" device (see tas2783.conf). Emptied below;
	# Value/routing unchanged. If a future alsa-ucm-conf update overwrites
	# this file and speakers go silent again, re-apply this change.
	EnableSequence [
	]

	DisableSequence [
	]

	Value {
	      PlaybackPriority 200
	      PlaybackPCM "hw:${CardId}"
	      JackControl "Headphone Jack"
	}
}

With this patch, alsaucm -c amd-soundwire set _verb HiFi exits 0. After restarting PipeWire/WirePlumber, wpctl status showed all three expected devices for the first time:

Sinks:
  "Audio Coprocessor Speaker"     (id 58)
  "Audio Coprocessor Headphones"  (id 59, default - higher PlaybackPriority)
Sources:
  "Audio Coprocessor Headset Microphone" (id 60)

speaker-test -D pipewire -c 2 -t sine -f 440 -l 1 against the Speaker sink was audibly confirmed working. Bugs #1 and #2 fixed — but only for this boot.

Bug #3: The ACP/SoundWire controller doesn’t survive boot or resume

Everything above gets the speakers working for the boot they’re applied on. But two persistence problems remained:

  1. On cold boot, the TAS2783 firmware download for SoundWire slave 01:b intermittently fails with an SDW bus timeout (FW download failed: -110), even though the firmware file is present and correct.
  2. On s2idle suspend/resume, the entire amd-soundwire ALSA card (card 1) disappears — not just the amps — and never comes back on its own.

3a. Cold-boot -110 firmware download timeout

With the firmware files in place, a cold boot’s journalctl -k -b 0 sometimes showed (for slave 01:b only):

soundwire sdw-master-0-1: trf on Slave 1 failed:-110 write addr 8088 count 32632
slave-tas2783 sdw:0:1:0102:0000:01:b: FW download failed: -110
slave-tas2783 sdw:0:1:0102:0000:01:b: fw with no files
slave-tas2783 sdw:0:1:0102:0000:01:b: error playback without fw download
slave-tas2783 sdw:0:1:0102:0000:01:b: ASoC error (-22): at snd_soc_dai_hw_params() on tas2783-codec

-110 is ETIMEDOUT — a SoundWire bus write (the firmware download itself) timed out for slave 01:b during early boot. This is a timing/race issue in the SDW bus initialization, distinct from the missing-file problem in Bug #1 (the file is found and read; the transfer to the device times out). Re-running the same unbind/bind cycle from Bug #1 after boot reliably clears it.

3b. Resume root cause: the whole ACP/SoundWire controller dies on s2idle resume

This was the hardest of the three. After a suspend/resume cycle, audio reverted to “Dummy Output” with zero tas2783/SDW kernel messages on resume at all. /proc/asound/cards showed only the HDMI card — card 1 (amd-soundwire) was gone entirely. An earlier attempt at a fix used a systemd-sleep “post” hook that tried to unbind/rebind the individual slave-tas2783 SoundWire devices (the same trick from Bug #1/3a). That approach hung for ~90 seconds on every resume: unbinding a SoundWire slave blocks indefinitely when the parent bus controller itself is dead, which is exactly the post-resume state.

3b. Fix attempt 1: reset at the PCI level (right idea, wrong hook)

If the whole controller is dead, the fix is to reset the whole controller: unbind/rebind the parent AMD ACP PCI device, 0000:c4:00.5 (driver snd_pci_ps), rather than poking individual SoundWire slaves. This tears down and re-probes both SoundWire managers, both TAS2783 amps (re-downloading their calibration firmware fresh), and the rt721 codec — recreating card 1 from scratch, like a cold boot. Verified live against a genuinely broken post-resume state, this worked: card 1 reappeared and “Audio Coprocessor Speaker” came back as the default sink.

However, when wired up as the same kind of systemd-sleep “post” hook, it still hung — this time the PCI unbind blocked for ~90s before being killed, leaving the ACP device unbound and the card gone entirely. Same failure mode, one level up: any unbind/bind of this hardware done from inside the frozen systemd-sleep “post” hook blocks, because it runs while user.slice is frozen and the bus/PM state is still in its broken just-resumed condition.

3b. Fix attempt 2 (final): a post-resume systemd service, not a sleep hook

The working fix moves the PCI reset out of the systemd-sleep hook entirely and into a normal oneshot service ordered after the sleep targets complete — i.e. it runs once the system has fully resumed and user.slice has thawed, in system.slice, which is never frozen:

[Unit]
Description=PX13 audio fix after resume (reset AMD ACP/SoundWire, refresh PipeWire)
# Run AFTER the system has fully resumed AND thawed user.slice. The reset
# (PCI unbind/bind of the ACP) HANGS if attempted from inside the
# systemd-sleep "post" hook (it runs while the device PM/bus is still in the
# broken just-resumed state and user.slice is frozen - the unbind blocks for
# ~90s and gets killed, leaving the card gone). Ordering after the sleep
# targets means this runs once the resume is complete and the session is
# thawed, where the reset works reliably.
After=suspend.target hibernate.target hybrid-sleep.target suspend-then-hibernate.target

[Service]
Type=oneshot
# Small settle delay so the just-resumed ACP device PM has finished before
# we unbind/bind it.
ExecStartPre=/bin/sleep 3
ExecStart=/usr/local/sbin/px13-audio-fix.sh

[Install]
WantedBy=suspend.target hibernate.target hybrid-sleep.target suspend-then-hibernate.target

The actual reset script, px13-audio-fix.sh, does the PCI unbind/bind (wrapped in timeout 30 as defensive belt-and-braces), waits for the amd-soundwire card to reappear in /proc/asound/cards, then refreshes PipeWire/WirePlumber:

PCI_DEV="0000:c4:00.5"
PCI_DRV="/sys/bus/pci/drivers/snd_pci_ps"
CARD_MATCH="amd-soundwire"

pci_write() { timeout 30 sh -c "echo '$1' > '$2'" 2>/dev/null; }

if [ ! -d "$PCI_DRV" ]; then
  log "snd_pci_ps driver not present, cannot reset - skipping"
elif [ ! -e "$PCI_DRV/$PCI_DEV" ]; then
  log "PCI $PCI_DEV not currently bound to snd_pci_ps - attempting bind only"
  pci_write "$PCI_DEV" "$PCI_DRV/bind" || log "bind failed/timed out"
else
  log "unbinding PCI $PCI_DEV"
  pci_write "$PCI_DEV" "$PCI_DRV/unbind" || log "unbind failed/timed out"
  sleep 2
  log "binding PCI $PCI_DEV"
  pci_write "$PCI_DEV" "$PCI_DRV/bind" || log "bind failed/timed out"
fi

# --- Wait for the amd-soundwire card to reappear -----------------------------
for _ in $(seq 1 40); do
  if grep -q "$CARD_MATCH" /proc/asound/cards 2>/dev/null; then
    log "amd-soundwire card is present"
    break
  fi
  sleep 0.25
done

The same script also runs at boot (via px13-audio-rebind.service, After=sound.target), which covers Bug 3a’s intermittent -110 timeout for slave 01:b, since the PCI-level reset re-downloads firmware to both amps from scratch.

Frozen-session safety

One more subtlety: px13-audio-fix.sh is shared between the boot service (runs in a normal, unfrozen session) and the resume service (runs after thaw, also normally unfrozen — but defensively checked anyway). Before calling systemctl --user restart for each logged-in user, it checks that user’s cgroup freezer state and skips the PipeWire restart if the session is still frozen, since a systemctl --user call against a frozen session would itself hang:

for uid in $(loginctl list-users --no-legend | awk '{print $1}'); do
  runtime_dir="/run/user/$uid"
  user_name="$(id -nu "$uid" 2>/dev/null)" || continue
  [ -d "$runtime_dir" ] || continue

  events="/sys/fs/cgroup/user.slice/user-${uid}.slice/cgroup.events"
  if [ -r "$events" ] && grep -q "^frozen 1$" "$events" 2>/dev/null; then
    log "uid $uid ($user_name) session frozen - skipping pipewire restart" \
        "(udev will re-enumerate on thaw)"
    continue
  fi

  log "restarting pipewire for uid $uid ($user_name)"
  sudo -u "$user_name" XDG_RUNTIME_DIR="$runtime_dir" \
    systemctl --user restart wireplumber pipewire pipewire-pulse 2>/dev/null \
    || log "pipewire restart for uid $uid failed"
done

Putting it all together

The final, verified-working setup installs:

ComponentPathPurpose
Calibration firmware/lib/firmware/1714-1-{8,B}.bin (+ ti/audio/tas2783/)Lets the TAS2783 amps initialize (Bug #1)
UCM Speaker profile/usr/share/alsa/ucm2/sof-soundwire/tas2783.conf + card overrideExposes the internal speaker to PipeWire (Bug #2a)
rt721.conf patch/usr/share/alsa/ucm2/sof-soundwire/rt721.confRemoves the unsupported Headphone Switch cset so the HiFi verb activates (Bug #2b)
px13-audio-fix.sh/usr/local/sbin/Resets the ACP controller (PCI unbind/bind of 0000:c4:00.5) and refreshes PipeWire (Bug #3)
px13-audio-rebind.service/etc/systemd/system/Runs the reset at boot, After=sound.target (Bug #3a)
px13-audio-resume.service/etc/systemd/system/Runs the reset after resume, ordered after the sleep targets (Bug #3b)

After running the install script, the verification commands are:

journalctl -k -b 0 | grep -i tas2783      # no firmware load errors
wpctl status                              # shows "Audio Coprocessor Speaker"
speaker-test -D pipewire -c 2 -t sine -f 440

A reboot and a suspend/resume cycle were both confirmed to keep the speakers working with no manual intervention.

What would make this unnecessary upstream

Each of the three bugs has a natural upstream home:

Until then, the full set of firmware, UCM configs, scripts and systemd units described above is available at github.com/brainchillz/asus-proart-px13-linux-speaker-fix.