[PATCH v3 0/2] ASoC: fix audio on the Microsoft Surface Pro 11 (Intel)

Sergey Lebedev posted 2 patches 3 weeks, 6 days ago
drivers/soundwire/dmi-quirks.c | 28 ++++++++++++++++++++++++++++
sound/soc/codecs/rt1320-sdw.c  |  2 +-
2 files changed, 29 insertions(+), 1 deletion(-)
[PATCH v3 0/2] ASoC: fix audio on the Microsoft Surface Pro 11 (Intel)
Posted by Sergey Lebedev 3 weeks, 6 days ago
The Microsoft Surface Pro 11 for Business (Intel, Lunar Lake) has no working
audio under Linux: the speakers are silent while every layer reports success.
These two patches fix it, and the machine then works with the stock
sof-soundwire UCM profile and the shipped topologies - no board quirk, no new
match entry, no local configuration of any kind.

Changes since v2: none to the code. v2 was sent in reply to the v1 series,
which Mark Brown asked me not to do because it buries the current patches in
an old thread and confuses tooling. He is right, and this is the same two
patches sent as their own thread. Sorry for the extra round.

  v1: https://lore.kernel.org/linux-sound/20260804225853.31585-1-lsa.uz@pm.me/
  v2: https://lore.kernel.org/linux-sound/20260830084500.6123-1-lsa.uz@pm.me/

Changes since v1: two of the three patches are replaced by a single DMI quirk,
which is what Bard Liao and Pierre-Louis Bossart asked for in review, and which
is both smaller and safer than what it replaces.

The board carries one physical RT1320 amplifier on SoundWire link 0 and
describes it twice:

  SWRA  _ADR 0x000030025D132000   SDCA class 0
  SWRB  _ADR 0x000030025D132001   SDCA class 1

Identical apart from the class id: same link, same manufacturer, part and
version, same unique id 0. The part reports class 1, so only SWRB ever
enumerates. SWRA stays UNATTACHED on every boot and on every firmware version
tested, including the November 2025 bundle, and the firmware is signed vendor
firmware we cannot have corrected at the source.

That ghost broke two things at once. It consumed an amplifier index, so the
real part was named "rt1320-2" and the stock UCM enabled switches on a device
that is not there; and its endpoints reached create_sdw_dailink(), which builds
DAI link names from link id and function type alone, so its SmartMic collided
with the real one and the card failed to register at all with -EEXIST.

v1 fixed those two symptoms in two places, each with its own way of noticing
the ghost. Removing the ghost at enumeration instead fixes both at once and
needs no runtime presence test:

  1/2 rt1320: the amplifier's preset never runs, because the driver waits for
      FUNCTION_NEEDS_INITIALIZATION and this part never sets it. rt712-sdca and
      rt722-sdca already handle this by also running the preset on the first
      hardware init; rt1320 is the odd one out. One line, unchanged from v1.

  2/2 dmi-quirks: remap the ghost _ADR to zero so sdw_acpi_find_slaves() never
      creates the peripheral, as ghost_realtek and global_ghost_adr already do.
      Matched on DMI_PRODUCT_SKU, not the product name, so a later batch with a
      different RT1320 version - and therefore a different _ADR - cannot be
      caught by a remap it was never verified against.

Testing. Surface Pro 11 for Business (Intel Core Ultra 7 268V). Verified on the
machine's own kernel, 7.0.0-30 (Ubuntu 26.04), with 2/2 backported to that
tree: its dmi-quirks.c predates ghost_realtek, but the table entry is identical
and the mechanism is unchanged - slave.c drops a peripheral whose overridden
_ADR is zero in both trees. 1/2 is byte-identical to v1's 1/3, which was built
and booted on 7.1.0-rc7.

  - /sys/bus/soundwire/devices/ shows only sdw:0:0:025d:1320:01; the class-0
    ghost is gone
  - amplifier named rt1320-1, controls "rt1320-1 OT23 L/R Switch"
  - card registers as sof-soundwire, 4 playback + 1 capture
  - no -EEXIST, no -61 link startup errors
  - speakers audible, internal microphone captures signal
  - stock alsa-ucm-conf and firmware-sof-signed, no local configuration
  - Secure Boot enabled with module signature enforcement, no rejections

Related work already on the list, so nobody reviews this twice. Amaan Lalani
sent a series for the same machine on 2026-08-28:

  [PATCH 0/2] ASoC: fix SoundWire enumeration on Surface Pro 11
  https://lore.kernel.org/linux-sound/BY5PR02MB63701A05A58EF6B4D6CAAC31A0AC2@BY5PR02MB6370.namprd02.prod.outlook.com/

In substance it is my v1 2/3 and 3/3: name-prefix reuse for _ADR entries that
differ only in class id, plus a runtime SDW_SLAVE_UNATTACHED test. The review
Bard and Pierre-Louis gave me therefore applies to it unchanged - it detects
the ghost at runtime rather than removing it at enumeration. Their version
hooks both the count and parse paths where mine hooked only parse, and carries
Fixes: tags, which is worth keeping if that approach is ever preferred.

There is also a body of downstream work for this machine in a linux-surface
fork (https://github.com/linux-surface/linux-surface/pull/1990), whose audio
fix takes the traditional shape of a DMI-gated machine entry. I wrote up the
comparison, including why the generic path appears to serve the microphone
better here, in a message on the v2 thread:

  https://lore.kernel.org/linux-sound/20260830122606.47028-1-lsa.uz@pm.me/

I have not run that branch on this device, so that part is their reports
against my measurements rather than one machine tested both ways. I have
offered to do it and will report the result.

One thing the review process turned up that is worth recording. The v1 cover
letter said the DAI link name collision was "no longer reachable on this
machine and we cannot demonstrate it". That was wrong: during v2 testing a boot
where the quirk did not take effect reproduced it exactly, and it is fatal.
create_sdw_dailink()'s naming scheme is still not unique in general. This series
does not address that - it removes the ghost before the naming code sees it -
and I am happy to send a separate patch if you would like it fixed.

checkpatch --strict is clean on both.

Sergey Lebedev (2):
  ASoC: rt1320: run the initialisation preset on the first hardware init
  soundwire: dmi-quirks: drop the ghost RT1320 on the Surface Pro 11
    (Intel)

 drivers/soundwire/dmi-quirks.c | 28 ++++++++++++++++++++++++++++
 sound/soc/codecs/rt1320-sdw.c  |  2 +-
 2 files changed, 29 insertions(+), 1 deletion(-)


base-commit: 7e9e0409cd57924c4099090879154300c07b8643
-- 
2.50.1 (Apple Git-155)
Re: [PATCH v3 0/2] ASoC: fix audio on the Microsoft Surface Pro 11 (Intel)
Posted by Sergey Lebedev 1 week, 5 days ago
For anyone finding this series later: it is finished, and not in the way the
subject line suggests.

1/2, the rt1320 preset fix, is in v7.2 and needs nothing further. It was
already upstream when this series went out.

2/2, the dmi-quirks change that drops the ghost RT1320, is superseded. It has
been resent on its own as

  [PATCH v4] soundwire: dmi-quirks: drop the ghost RT1320 on the Surface Pro 11 (Intel)
  https://lore.kernel.org/linux-sound/20260913210849.6446-1-lsa.uz@pm.me/

separately because it belongs to soundwire rather than ASoC, and because
carrying it as 2/2 of a series whose 1/2 has landed left it looking like part
of something already done.

Nothing here needs a reply. This note exists so the thread does not read as
open work.

Sergey
Re: [PATCH v3 0/2] ASoC: fix audio on the Microsoft Surface Pro 11 (Intel)
Posted by Sergey Lebedev 3 weeks, 6 days ago
Please do not apply 1/2. I cannot reproduce the condition it fixes, and I
would rather say so myself than have it found in review.

The patch rests on one claim: that this part never sets
FUNCTION_NEEDS_INITIALIZATION, so rt1320_io_init() never runs the vendor
preset and the amplifier is never programmed. Every func_status line I
recorded in July reads 0x41 - NEWLY_ATTACHED | FUNCTION_HAS_BEEN_RESET,
without BIT(5).

Re-tested tonight on the same machine, with the stock rt1320 driver and my
patch not loaded:

  rt1320-sdca sdw:0:0:025d:1320:01: rt1320_io_init amp func_status=0x61
  rt1320-sdca sdw:0:0:025d:1320:01: rt1320_vc_preset, RT1320_KR0_INT_READY=0x0
  rt1320-sdca sdw:0:0:025d:1320:01: rt1320_vc_preset, RT1320_KR0_INT_READY=0x1f

0x61 is 0x41 | BIT(5). The bit is set, the stock driver runs the preset, and
the patch is a no-op. Same reading in three configurations - with the ghost
_ADR removed, with a machine-entry approach that leaves it enumerated, and
fully stock - and on a genuine cold boot, not a reboot: the previous boot
ended in systemd-poweroff and an RTC alarm brought the machine back from S5.

The speakers work without the patch, and I checked that by measurement rather
than by reading logs, because silence with every layer reporting success is
the exact failure mode here. Playing a 1 kHz tone and recording the internal
microphone, the 1 kHz bin rises 185x over ambient with the patch absent, 610x
with it present. Both are unambiguously audible; the difference is room noise.

What I ruled out:

  - the gate is unchanged. if ((amp_func_status & FUNCTION_NEEDS_INITIALIZATION))
    is identical in v7.0 and v7.1-rc7, the tree this series targets
  - Ubuntu changed nothing relevant between 7.0.0-28 and 7.0.0-30: no rt1320,
    sdca, soundwire or sdw entry in the changelog
  - firmware predates the July readings. firmware-sof-signed went to 2025.12.2
    on 2026-07-27 and the Surface firmware bundle was applied 2026-07-28
  - the ghost is not involved: fully stock, it never reaches rt1320_io_init()
    at all, and the real device still reports 0x61

So I have no explanation for the change, and I am not going to invent one. If
someone knows how an SDCA part stops asserting that status bit between one
month and the next, I would like to hear it - that is worth more to the
subsystem than the patch was. I still have the hardware and will test whatever
is useful.

2/2 is unaffected and I would ask that it still be considered. I re-verified it
the same night by running fully stock:

  sysfs: cannot create duplicate filename '.../sof_sdw/SDW0-Capture-SmartMic'
  kobject_add_internal failed for SDW0-Capture-SmartMic with -EEXIST
  sof_sdw sof_sdw: probe with driver sof_sdw failed with error -12

aplay -l reports zero cards. Without the quirk this machine has no audio device
at all, so that patch is not an optimisation.

One more result from the same night, since it bears on the approach. I compared
this series against the downstream machine-entry patch that Surface Pro 11 users
run today, on one machine and one kernel, swapping only the audio modules. Both
end up with the same configuration - same three function topologies, 4 playback
+ 1 capture, rt1320-1, working microphone. The difference is what each costs:
the machine entry does not match at all unless class_id is added to
SDW_CODEC_ADR_MASK and to the peripheral comparison in soc-acpi.c, because
generic matching sees two peripherals for the one address it declares. That is
shared code for every SoundWire machine. Removing the ghost at enumeration needs
no such change.

Sorry for the noise on 1/2.

Thanks,
Sergey