Skip to content

[CI TEST] audio, topology2: multi-slot Wake-on-Voice with PDM DMICs and D0i3 support - #11240

Draft
lgirdwood wants to merge 26 commits into
thesofproject:wcl-uaol-wov-002from
lgirdwood:wov-d0i3
Draft

lgirdwood wants to merge 26 commits into
thesofproject:wcl-uaol-wov-002from
lgirdwood:wov-d0i3

Conversation

@lgirdwood

Copy link
Copy Markdown
Member

Description

This PR introduces multi-slot Wake-on-Voice (WoV) with low-power D0i3 sleep/wake capability, hardware PDM DMIC input, and modular topology feature integration across Panther Lake (PTL), Wildcat Lake (WCL), and Tiger Lake (TGL).

Highlights

  1. Hardware PDM DMIC Wake-on-Voice:

    • Ensures WoV always connects to native 16 kHz 4-channel hardware PDM DMICs (dmic16k, DAI index 1) directly from the SoC PDM decimator, avoiding software resampling.
    • Co-exists with primary 48 kHz DMIC enhanced capture (dmic01) and external SoundWire microphones (Capture-SmartMic).
    • Generates and embeds complete ACPI NHLT tables with 48 kHz and 16 kHz hardware FIR/CIC filter coefficients in topology manifests.
  2. Multi-Slot WoV Pipeline Architecture:

    • ECNS DP Module (Pipeline 115): 20ms period, dual output pins (mono clean to KPB, stereo clean to PCM 10).
    • Keyphrase Buffer (Pipeline 116): 2000ms circular history buffer supporting multi-sink topology binding and drain streaming.
    • 3 Concurrent Detector Slots (Pipelines 111–113): Independent MFCC feature extraction + MicroWakeWord instances with 2 Hz scoring kcontrols.
    • WoV Arbiter (Pipeline 114): Multi-keyword arbitration, host notification on detection, and pre-roll drain triggering to PCM 11 (DMIC Multi-WOV).
  3. D0i3 Low-Power Sleep & Wake:

    • Flagged host copier on PCM 11 with capture_compatible_d0i3 1 to maintain low-power DSP SRAM retention across host S0ix sleep.
    • Added D0ix state notifier to IPC4 pipeline handler to manage COMP_STATE_PREPARE and suppress telemetry during D0i3.
    • Switched MicroWakeWord op resolver and interpreter to static storage to eliminate heap allocation leaks across sleep/wake cycles.
  4. Topology Integration & Modularity:

    • Added dmic-wov-feature.conf allowing multi-slot WoV to be included as a feature module into functional topologies (INCLUDE_WOV=multi).
    • Integrated and validated functional SoundWire topologies: sof-ptl-rt721-4ch-wov-multi, sof-ptl-rt722-4ch-wov-multi, and WCL equivalents.
    • Aligned WCL topologies with verified PTL topologies.
  5. Toolchain & Compiler Fixes:

    • Fixed Xtensa CALL8 out-of-range relocation in the libc shim by unifying .text section placement.
    • Conditionally compile ibuffer_allocator.cc to support both upstream TFLM and trees carrying Xtensa ICF vtable fixes.
    • Disabled USB Audio Offload (UAOL) by default to prevent interference during WoV validation.

Validation

  • Panther Lake Silicon (Aphid):
    • Verified 10/10 consecutive S0ix/D0i3 sleep/wake cycles with test_start and wov_blocking_read.
    • Verified multi-slot keyword detection and 2-second audio history drain.
    • Verified clean DMIC ECNS capture on PCM 10.
  • Topology Verification:
    • Compiled and verified topologies for PTL, WCL, and TGL via alsatplg.
    • Inspected binary structures to confirm BE DAI link IDs match kernel machine driver enumeration.

udaymb and others added 18 commits September 21, 2026 11:06
Fix the build issues related to
 - libc.a path update to use from xt-clang xtensa
 - comment ibuffer_allocater.cc entry as file does not exist
 - Add zephyr compiler options
 - Introduce assert_func

Signed-off-by: Naveen Manohar <naveen.m@intel.com>
Signed-off-by: Uday M Bhat <uday.m.bhat@intel.com>
PR thesofproject#11214 dropped ibuffer_allocator.cc from mww_tflm_lib on the grounds
that the file does not exist. That is true of the tflite-micro commit
pinned by scripts/tensorflow-clone.sh (e86d97b6), where IBufferAllocator
is a header-only pure-virtual interface, but not of trees carrying the
Xtensa ICF vtable-folding fix, which split IBufferAllocator's 13 virtuals
out of line into that .cc. On those trees the removal breaks the link
with ~14 undefined references under both toolchains:

  libmww_tflm_lib.a(micro_allocator.cc.obj):(.literal.
    _ZN6tflite16IBufferAllocatorC2ERKS0_+0x0):
    undefined reference to `vtable for tflite::IBufferAllocator'

Guard the source on the file's existence so both layouts build.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
ptl fails to link, on the branch base and with PR thesofproject#11214, under both
xt-clang and the Zephyr SDK:

  libmww_libc_shim.a(libm_math_sf_exp.c.o): sf_exp.c:(.text.expf+0x12):
    dangerous relocation: call8: call target out of range: __addsf3

The shim is assembled by `ar x`-ing prebuilt members out of the
toolchain's libc.a/libm.a. Those objects were compiled without
-mlongcalls, so their calls to the libgcc soft-float helpers are plain
CALL8 with a +/-512KB reach. Zephyr's Xtensa linker script places plain
`.text` (where libgcc lives) via `*(.literal .text)` at the front of the
.text output section and per-function `.text.*` via the later
`*(.literal.* .text.*)` rule at the back. Measured on wcl, which still
links: __addsf3 at 0xa003504c, expf at 0xa0091450 - 378KB apart. ptl's
.text is 651KB, so the two ends fall outside CALL8 range.

Rename the extracted members' .text.<fn>/.literal.<fn> back to plain
.text/.literal so they land in the same early cluster as libgcc. On ptl
this brings expf to 0xa00327bc and __addsf3 to 0xa0032d84, 1.5KB apart.
Order within a single `*(...)` wildcard follows input order, so each
object's .literal still precedes its .text and l32r reach is unaffected.

Verified: ptl links and boots on PTL silicon (aphid), topology
sof-ptl-dmic-wov-multi-4ch instantiates, DMIC ECNS capture records
cleanly and MWW runs inference on all three slots.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
tlv_value_set_uaol_caps() set link_count to the devicetree device count
unconditionally and indexed link_caps[] by device index, so a link whose
uaol_get_capabilities() call failed was still advertised to the host as a
present link with all-zero capabilities.

That matters now that the driver rejects the query when the host has not
set UAOLCTL.OFLEN: without this, a firmware that cannot read any link
still reports link_count = 1 with zeroed stream counts and FIFO sizes.

Count only the links that answered, pack them from index 0, and size the
TLV to match.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… on IPC4

kpb.c drives both a sel_sink (buf_id 0, the real-time feed to detectors)
and a host_sink (buf_id 1, the drain that bursts pre-roll to the host).
Declare two sink pins in kpb.toml so the drain path can be bound from
topology.

Additionally, under IPC4 pipeline state transitions and resets are
synchronous; returning -EBUSY on reset breaks the host teardown state
machine and causes widget free failures. Guard the deferred -EBUSY
drain check under #if !CONFIG_IPC_MAJOR_4.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
…in pipeline ops

Add NOTIFIER_ID_D0IX_STATE so components can track host S0iX/D0i3 entry
and exit transitions dispatched from ipc4_module_process_d0ix().

In ipc4_pipeline_prepare() and ipc4_pipeline_trigger(), add
COMP_STATE_PREPARE as a valid no-op state for RUNNING and RESET
transitions. When a pipeline has executed pipeline_prepare(), its state
is COMP_STATE_PREPARE; previously omitting it caused spurious
IPC4_INVALID_REQUEST (error 7) returns during stream restart and reset.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
…eaming

Send SOF_IPC4_NOTIFY_PHRASE_DETECTED to the host upon keyword detection
via notify_host_detect().

Update source buffer lookup to dynamically identify the KPB host sink
audio buffer, keep the sink silent while listening (WOV_ARB_NO_ACTIVE)
so the host PCM stays blocked in read() and allows platform D0i3 entry,
and periodically dispatch phrase detected notifications during audio
drain to keep the host reader fed.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
…ycle

Add CONFIG_COMP_MWW_FAKE_WAKE_MS test aid and app/wov-d0i3-fake-wake.conf
to synthesize keyword detections after a specified delay without a
physical microphone.

In mww_prepare(), arm the fake wake deadline so S0-only tests can trigger
directly, and fire the detection inline from mww_process().

Refactor mww_prepare() so model initialization runs once while stream
state and fake wake deadlines re-arm cleanly on every prepare even if
the module instance remains allocated.

Remove mww_notify_score(0) from mww_reset() to prevent host widget
lookup race conditions during teardown.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
…oV arbiter

Set period 1000 on custom capture pipeline classes so the timer domain
scheduler period reaches the firmware.

Configure KPB with 2 output pins:
- Pin 0 (sel_sink) real-time feed to detector slots via mixin.106.1
- Pin 1 (host_sink) drain route to wov-arbiter.104.1 pin 0

Configure WOV arbiter with 4 inputs (pin 0 KPB audio, pins 1-3 MWW
detector features) and 16-bit PCM output.

Set capture_compatible_d0i3 on the host copier widget to enable D0i3
stream compatibility under IPC4.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
…ncies

Document the multi-slot Wake-on-Voice test case with microWakeWord (MWW)
on Panther Lake (PTL):
- Update the topology architecture diagram with dual-sink KPB and 4-pin
  WOV arbiter connections.
- Document Linux kernel dependencies (branch wov-ipc4-d0i3 on
  lgirdwood/linux) and SOF firmware dependencies (branch wcl-uaol-wov-002
  on lgirdwood/sof).
- Provide build commands for firmware with the fake-wake overlay
  (CONFIG_COMP_MWW_FAKE_WAKE_MS=5000) and topology compilation.
- Include complete source code for the standalone blocking PCM read client
  (wov_blocking_read.c) and 20-run test suite (run_20_tests.sh).
- Document verified hardware test results (20/20 passes, zero IPC/ASoC
  errors).

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
…elemetry in D0i3

Track D0ix state transitions via NOTIFIER_ID_D0IX_STATE across all MWW
detector slots.

While in D0i3 (host sleeping in s2idle):
- Suppress mww_notify_score() ALSA enum kcontrol notifications so that
  intermediate probability score updates do not send IPCs that
  prematurely wake the host out of sleep.
- Re-arm the fake wake deadline (CONFIG_COMP_MWW_FAKE_WAKE_MS) from the
  time D0i3 is entered so that the configured timer duration elapses
  while the system is suspended.
- Disarm the fake wake timer when returning to D0i0.

Update topology README with the 5-run D0i3 sleep-and-wake validation
runbook and verified Panther Lake test results (5/5 passes, waking via
AudioDSP IRQ 193).

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
… TGL, and WCL

Add prebuilt topology binary files for the 4-channel native 16 kHz DMIC
multi-slot Wake-on-Voice use case:
- build/sof-ptl-dmic-wov-multi-4ch.tplg (Panther Lake)
- build/sof-tgl-dmic-wov-multi-4ch.tplg (Tiger Lake)
- build/sof-wcl-dmic-wov-multi-4ch.tplg (Wildcat Lake)

The Panther Lake binary matches the exact md5 (4f76c48bc0234062ae628ec12e5f8dd0)
tested and verified on Aphid hardware across S0 and D0i3 wake test suites.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
…ter to fix heap leak

TFLite Micro defines TF_LITE_REMOVE_VIRTUAL_DELETE on MicroMutableOpResolver,
which expands to a no-op 'void operator delete(void* p) {}'. Consequently,
calling 'delete inst->op_resolver' in MWW_Free() never returned the memory
to the heap, leaking ~600 bytes per slot on every stream open/close cycle.
Across multi-slot configurations (3 detector slots), repeated stream cycles
exhausted the DSP system heap, failing on run 10 with -ENOMEM in
MWW_InitOps() and returning -22 (IPC4_INVALID_REQUEST) to snd_pcm_start().

Eliminate heap allocations from MWW model initialization by allocating
both MwwOpResolver and MicroInterpreter in aligned static storage using
placement new and explicit destructor invocation.

Verified with 10 consecutive D0i3 sleep-and-wake test cycles on Panther Lake
hardware (Aphid), achieving 10/10 passes with zero errors.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
…ified PTL topology

Align tools/topology/topology2/dmic-wov-multi-wcl-4ch-manifest.conf to match
the verified Panther Lake topology manifest exactly, with the target platform
set to 'wcl'.

This brings the dual-sink KPB architecture (real-time detector feed on
sink 0, pre-roll burst drain on sink 1), 4-pin WOV arbiter routing, scheduler
period token, and D0i3 capture compatibility flags to Wildcat Lake.

Recompiled and updated build/sof-wcl-dmic-wov-multi-4ch.tplg (37636 bytes).

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
Disable UAOL on Intel ADSP targets in boards/intel_adsp/Kconfig.defconfig
(default n) and explicitly disable CONFIG_UAOL and CONFIG_DAI_INTEL_UAOL
in the wov-d0i3-fake-wake overlay.

Rebuilt firmware binaries for both Panther Lake (PTL) and Wildcat Lake (WCL),
and verified D0i3 sleep-and-wake on Aphid hardware (AudioDSP IRQ 193).

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
…MICs

Refactor multi-slot Wake-on-Voice (WoV) pipelines into a reusable feature module
that integrates with functional topologies (cavs-sdw, sof-hda-generic) and
can also be loaded as a standalone feature topology via snd_sof feature_topologies.

- Refactor platform/intel/dmic-wov-multi.conf to use non-colliding pipeline IDs
  (110-117), parameterized DMIC DAI bindings, and D0i3-compatible host copiers.
- Ensure WoV always utilizes hardware PDM DMICs (4 channels, 16kHz) for audio input.
- Add multi-slot WoV support to dmic-wov-feature.conf, including PDM DMIC DAI and
  DAPM virtual widgets required for standalone or overlay usage.
- Integrate multi-slot WoV into cavs-sdw.conf and sof-hda-generic.conf with WCL
  platform support and control class definitions.
- Add production CMake targets in tplg-targets-ace3.cmake and
  tplg-targets-hda-generic.cmake for PTL and WCL.
- Hardware verified on Aphid (PTL ACE 3.0):
  * 10 / 10 S0 WoV detection tests passed.
  * 10 / 10 D0i3 suspend/resume wake tests passed (IRQ 193).

Signed-off-by: Liam Girdwood <liam.r.girdwood@intel.com>
@lgirdwood lgirdwood changed the title audio, topology2: multi-slot Wake-on-Voice with PDM DMICs and D0i3 support [CI TEST] audio, topology2: multi-slot Wake-on-Voice with PDM DMICs and D0i3 support Sep 26, 2026
@lgirdwood

Copy link
Copy Markdown
Member Author

@naveen-manohar @harajend @bardliao @ujfalusi this is just for testing on the CI, it has a lot of patches not for upstream, just for debug. Will allow us to roll out WOV test alongside other WOV PR in flow.

…722 targets

Fix driver error "can't find host comp to bind pcm" when loading SoundWire
topologies with multi-slot WoV enabled.

- cavs-sdw.conf: Align DMIC0_PCM_CAPS to 'Gain Capture 10' so that host-copier.10.capture
  matches the stream capability name expected by PCM 10 ("DMIC ECNS Capture").
- dmic-wov-multi.conf: Define DMIC0_PCM_CAPS as "Gain Capture 10" to ensure consistent
  widget-to-PCM capability string binding across all parent topology templates.
- tplg-targets-ace3.cmake: Add production CMake targets for sof-wcl-rt721-4ch-wov-multi
  and sof-wcl-rt722-4ch-wov-multi.

Signed-off-by: Liam Girdwood <liam.r.girdwood@intel.com>
@naveen-manohar

Copy link
Copy Markdown
Contributor

Thanks @lgirdwood
seems drc can be removed
[ 12.990644] sof-audio-pci-intel-ptl 0000:00:1f.3: failed to find module info for widget drc.100.1 with UUID B36EE4DA-006F-47F9-A06D-FECBE2D8B6CE

…odules

Functional and feature topologies (such as SoundWire RT721/RT722 and DMIC
pipelines) require open audio processing components like DRC, TDFB,
Multiband DRC, Aria, and MUX.

Ensure these modules are enabled in both PTL and WCL board configurations
and module overlays so they are built into sof-ptl-openmodules.ri and
sof-wcl-openmodules.ri.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
… tables

Update embedded DMIC NHLT configuration tables in prebuilt multi-slot WoV
topology binaries:
- build/sof-ptl-dmic-wov-multi-4ch.tplg
- build/sof-tgl-dmic-wov-multi-4ch.tplg
- build/sof-wcl-dmic-wov-multi-4ch.tplg

The updated NHLT tables expand endpoint format capabilities to support
mono (1-channel), stereo (2-channel), and quad (4-channel) audio streams
in both 16-bit and 32-bit container depths at 16 kHz and 48 kHz.
This prevents ALSA copier bind failures (no matching blob) when capturing
mono or 16-bit streams from DMIC endpoints.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
Implement an on-demand synthetic wake trigger controlled via a volatile
kcontrol ('wovdebug_$index') per WoV slot instance:
- Setting the switch kcontrol to 1 enables and arms that instance's
  fake wake countdown timer.
- Once the stream is prepared/active and running in S0 or upon D0i3
  suspend, the countdown timer triggers keyword detection (KPB drain
  and arbiter notify).
- Upon firing, the firmware clears the kcontrol back to 0 and sends
  an IPC4 module notification event with the ALSA magic value so that
  the Linux kernel updates the control and notifies ALSA userspace.
- Define 'wovdebug_$index' mixer control in mww.conf and manifests.
- Recompile prebuilt WoV topologies.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
…gies

In alsatplg, mixing named object syntax (Object.PCM.pcm."10") with anonymous
array syntax (Object.PCM.pcm [ ... ]) causes alsatplg's internal array index
tracker to reset, resulting in subsequent Object.PCM.pcm array definitions
(Speaker, HDMI, Jack, Microphone) overwriting indices 0 and 1. This caused
the Speaker PCM (PCM ID 2) and others to be omitted from the compiled
SoundWire multi-slot WoV topologies.

- dmic-wov-multi.conf: Convert Object.PCM.pcm to standard anonymous array
  definitions for PCM 10 (DMIC ECNS Capture) and PCM 11 (DMIC Multi-WOV).
- dmic-generic.conf: Wrap default DMIC0 Object.PCM.pcm in IncludeByKey.INCLUDE_WOV
  so that multi-slot WoV topologies do not instantiate duplicate PCM 10.
- Recompile all SoundWire, HDA generic, and manifest multi-slot WoV topologies,
  restoring Speaker (PCM 2), Jack Out (PCM 0), Jack In (PCM 1), HDMI 1-3,
  and Microphone (PCM 4) alongside DMIC ECNS (PCM 10) and Multi-WOV (PCM 11).

Signed-off-by: Liam Girdwood <liam.r.girdwood@intel.com>
…CM 12 WoV mono

Fan out DMIC DAI capture pipeline (Pipeline 110) via mixin.110.1 (num_output_pins=2)
to ECNS mixout.115.1 and new Pipeline 118 (mixout.118.1 -> host-copier.10.capture).
Remap ECNS stereo capture to PCM 11 (Pipeline 117) and multi-slot WoV to PCM 12 (Pipeline 114).
Resolve duplicate target in tplg-targets-ace3.cmake.
…lsa utilities

Add blocking read test utilities for Wake-on-Voice gated capture validation:
- wov_blocking_read.c: ALSA-lib non-MMAP blocking read with no-period-wakeup
- wov_blocking_read_tinyalsa.c: tinyalsa blocking read using PCM_MMAP | PCM_NOIRQ
- Update Makefile with modular build targets
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants