Skip to content

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

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

lgirdwood wants to merge 83 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.

@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.

@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

…overy

Support building microWakeWord with external or dynamic toolchain configurations
where libc.a / libm.a archive layouts differ between Xtensa toolchain versions.
Specifically:
- Check for XTENSA_SYSTEM libc archive path when not found in standard Zephyr paths.
- Check libc archive member names to extract either Newlib (lib_a-*.o) or standard
  libc/libm members into the shim archive.
- Run mww_shim_flatten.py to flatten .text.* and .literal.* sections into .text
  and .literal to prevent CALL8 out-of-range relocation overflows.
- Enable -mlongcalls and -mtext-section-literals on Xtensa architecture builds.
- Conditionally include ibuffer_allocator.cc when present in the TFLM tree.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.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>
… 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>
Add NOTIFIER_ID_D0IX_STATE to notify registered DSP components when the host
changes the DSP D0 substate via SOF_IPC4_MOD_SET_D0IX.

Components such as microWakeWord that keep running while the host sleeps in
S0iX / D0i3 can use this event to adjust telemetry reporting or power
characteristics.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
When source or sink component is not a processing_module (such as a host
copier or non-module comp_dev), comp_mod() returns NULL.
Safely guard src_module_data and dst_module_data before accessing
mpd.in_buff_size and mpd.out_buff_size to prevent NULL pointer dereferences
when configuring DP ring buffers.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
Hostless internal pipelines (such as background keyword detection or
internal audio processing chains that feed an arbiter or buffer without
a host copier) do not have a host dev.

Allow ipc4_pipeline_prepare() and ipc4_pipeline_trigger() to operate
on pipelines where host is NULL by falling back to source_comp or
sink_comp. Furthermore, allow stopping pipelines that are currently in
COMP_STATE_PREPARE.

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

Improve the WoV Arbiter component:
- Host Notification: send IPC4 notification to host upon keyword detection
  and periodically during pre-roll buffer drain.
- Active Slot Reset: reset active_slot to WOV_ARB_NO_ACTIVE and notify host/kcontrols
  on stream stop, reset, and free. Also emit WOV_ARB_CMD_RESUME to unpause detectors.
- Drain Streaming: ensure the arbiter only produces data when an active slot is
  triggered, leaving the host PCM idle/blocked during low-power listening so the
  platform can enter D0i3.
- Update wov_arbiter README documentation.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
Adapt the ECNS module to support the dual-rate DMIC architecture:
- Input pin 0: 16 kHz stream from dmic16k (up to 320 frames per 20ms period).
  Extracts left channel to mono output pin 0 feeding KPB.
- Input pin 1: 48 kHz stream from dmic01 (up to 960 frames per 20ms period).
  Copies stereo 48 kHz output to pin 1 feeding Host Copier PCM 11.
- Operates in 20ms DP mode with independent buffer tracking per pin.
- Update ECNS header and README documentation.

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>
…er controls

Add power and testing enhancements to microWakeWord:
- D0i3 Power State: listen for NOTIFIER_ID_D0IX_STATE and suppress score
  telemetry notifications while the host is in D0i3 to prevent spurious
  wakeups.
- Test Trigger Controls: implement SOF_IPC4_SWITCH_CONTROL_PARAM_ID to expose
  a volatile 'wovdebug' switch kcontrol per slot. Setting this control arms
  a fake wake timer (MWW_FAKE_WAKE_DELAY_MS) that triggers a keyword detect
  event and automatically resets the control upon firing.
- Add CONFIG_MICROWAKEWORD_FAKE_WAKE and app/wov-d0i3-fake-wake.conf test overlay.

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).

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
…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>
…slot WoV pipelines

Implement the dual-rate DMIC topology architecture with multi-slot WoV:
- Provide dual PDM DAI endpoints:
  - dmic01 on PDM0: 48 kHz stereo 16-bit
  - dmic16k on PDM1: 16 kHz stereo 16-bit
- Connect dmic16k into ECNS (pin 0) and dmic01 into ECNS (pin 1).
- Connect ECNS output pin 0 (16k mono clean) to KPB and multi-slot WoV
  detectors (slots 0-2: OK Google, Alexa, Hey Jarvis), feeding WoV Arbiter
  and Host Copier PCM 12 (16 kHz mono WoV capture).
- Connect ECNS output pin 1 (48k stereo clean) to Host Copier PCM 11
  (48 kHz stereo capture).
- Remove deprecated raw PCM 10 host copier.
- Add volatile wovdebug switch controls and score enum controls per slot.
- Set capture_compatible_d0i3 to true on WoV PCMs.
- Update 4ch and multi manifests for PTL, WCL, and generic Intel platforms.

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

Integrate the multi-slot WoV pipelines and feature flags into SoundWire
and HDA topologies:
- Wire multi-slot WoV feature inclusion into cavs-sdw.conf, cavs-rt5682.conf,
  and sof-hda-generic.conf.
- Ensure Speaker and other primary PCMs are preserved when WoV features are
  instantiated.
- Add CMake topology build targets for Panther Lake (PTL) ACE 3.0, Wildcat Lake
  (WCL), and Tiger Lake (TGL) with multi-slot WoV SoundWire and HDA targets
  in production and development CMake files.

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

Provide prebuilt topology binary files for quick testing and hardware bring-up:
- build/sof-ptl-dmic-wov-multi-4ch.tplg
- build/sof-tgl-dmic-wov-multi-4ch.tplg
- build/sof-wcl-dmic-wov-multi-4ch.tplg

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
Add test utilities for verifying Wake-on-Voice capture pipelines:
- wov_blocking_read.c: alsa-lib utility that opens the WoV capture PCM
  in blocking read mode with SND_PCM_NO_IRQ_WAITEVENT or mmap to ensure
  the driver does not generate periodic IRQs during listening.
- wov_blocking_read_tinyalsa.c: TinyALSA version of the blocking reader.
- test_wov_no_irq.py: automated test runner validating WoV capture and wake
  across all slots in S0 and D0i3 (idle suspend) states.
- Makefile: build targets for wov_blocking_read and wov_blocking_read_tinyalsa.

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

Comprehensive documentation updates for multi-slot Wake-on-Voice and dual-rate DMIC:
- tools/topology/topology2/README.md:
  - Document complete pipeline architecture and DMIC routing diagrams.
  - Document dual-rate DMIC PDM DAI structure (dmic01 @ 48k, dmic16k @ 16k).
  - Document ECNS 20ms DP processing and pin mappings.
  - Document KPB circular buffering, pre-roll drain, and WoV Arbiter slot routing.
  - Document multi-slot WoV detector pipeline (OK Google, Alexa, Hey Jarvis).
  - Document PCM endpoints: PCM 11 (48k stereo clean), PCM 12 (16k mono WoV).
  - Add build steps with alsatplg and verification runbooks.
- doc/developer_guides/wov_ecns_integration_guide.md:
  - Update integration guide with dual-rate DMIC architecture and D0i3 verification.
- README.md:
  - Update top-level README with microWakeWord and WoV documentation references.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
lrgirdwo and others added 9 commits October 1, 2026 11:26
…ECNS, KPB, and host copier

Remove redundant mixin and mixout components between ECNS output pins
and downstream consumers:
- ECNS Output Pin 0 (16 kHz mono clean) connects directly to KPB
  (kpb.116.1 / kpb.106.1).
- ECNS Output Pin 1 (48 kHz stereo clean) connects directly to the
  Host Copier capture endpoint (host-copier.11.capture / host-copier.10.capture).
- Remove mixin.115.1, mixin.115.2, mixout.116.1, and mixout.117.1 from
  dmic-wov-multi.conf.
- Remove mixin.105.1, mixin.105.2, mixout.106.1, and mixout.107.1 from
  standalone 4ch manifests (PTL, WCL, TGL).
- Update prebuilt topology binaries and README topology diagrams and PCM tables.
- Validated on Aphid hardware across 10x S0 and 10x D0i3 WoV capture tests (20/20 PASS).

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

Synchronize Mermaid architecture diagrams to reflect direct widget routing:
- Add dedicated Dual-Rate DMIC & Multi-Slot WoV flowchart to tools/topology/topology2/README.md.
- Update src/audio/ecns/README.md, src/audio/wov_arbiter/README.md, and
  doc/developer_guides/wov_ecns_integration_guide.md to eliminate intermediate
  mixin.115.1/mixin.115.2 and mixout.116.1/mixout.117.1 widgets.
- Update src/audio/microwakeword/README.md to eliminate intermediate
  mixin.105.1/mixin.105.2 and mixout.106.1/mixout.107.1 widgets.
- Show direct ECNS Pin 0 connection to KPB and ECNS Pin 1 connection
  to Host Copier (PCM 11 / PCM 10).

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

Align standalone DMIC multi-slot Wake-on-Voice topology manifests (PTL, WCL,
and TGL) to embed the full 2-endpoint NHLT table matching production SoundWire
and platform topologies:
- Define Object.Dai.DMIC with both Endpoint 0 (dmic01 @ 48 kHz, id 6) and
  Endpoint 1 (dmic16k @ 16 kHz, id 7) with 4-channel active PDM0/PDM1 mics.
- Set Pipeline 100 DMIC_DAI_INDEX=1 and DMIC_NAME="dmic16k" so the 16 kHz
  capture copier matches Endpoint 1 in the topology-embedded NHLT table.
- Generates the exact 6,211-byte, 2-endpoint NHLT binary table on PTL and WCL
  matching production nhlt-sof-ptl-rt721-4ch.bin bit-for-bit
  (md5: e16dcb62d2b3bacc939b24a8a0a9d0f0).
- Generates matching 6,211-byte NHLT binary table on TGL with CAVS 2.5
  driver version 1.
- Update prebuilt topology binaries for PTL, WCL, and TGL in build/.
- Update tools/wov_capture/run_wov_10x.py to dynamically auto-detect DMIC
  Multi-WOV capture PCM device index and active slot debug kcontrol names.
- Update documentation in tools/topology/topology2/README.md.
- Validated on Aphid hardware across 10x S0 and 10x D0i3 WoV capture tests (20/20 PASS).

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

In IPC4, the Linux kernel assigns module instance IDs sequentially as
it traverses DAPM widgets. Because widgets are stored in a LIFO linked list
(list_add), the widgets in pipelines 101, 102, 103 are instantiated in
reverse order:
  - mww.103.1 -> instance 0
  - mww.102.1 -> instance 1
  - mww.101.1 -> instance 2

Previously, mww.c derived slot_id as (IPC4_INST_ID(dev->ipc_config.id) % 3),
which assigned slot 0 to mww.103.1 and slot 2 to mww.101.1. When the host
triggered wovdebug_101, the arbiter received slot 2 and set wov_active_slot
to 3 ('Slot 3'), inverting slots 1 and 3.

Align with detect_test.c by computing:
  cd->wov_slot_id = (uint8_t)(2 - (IPC4_INST_ID(dev->ipc_config.id) % 3));

This ensures:
  - wovdebug_101 (Pipeline 101) -> slot 0 -> wov_active_slot = 1 ('Slot 1')
  - wovdebug_102 (Pipeline 102) -> slot 1 -> wov_active_slot = 2 ('Slot 2')
  - wovdebug_103 (Pipeline 103) -> slot 2 -> wov_active_slot = 3 ('Slot 3')

Also update wov_blocking_read.c and run_wov_10x.py:
  - wov_blocking_read queries wov_active_slot upon receiving audio frames
    and asserts that triggered active_slot matches the expected slot.
  - run_wov_10x.py logs and validates trig_slot == slot for each iteration.
  - Validated on Aphid hardware across 10x S0 and 10x D0i3 runs (20/20 PASS).

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
Immediate logging runs every log call synchronously in the caller's
context, including the LL scheduler tick and DAI start. On ADL this
stalls the DMIC capture pipeline start: SET_PIPELINE_STATE(RUNNING)
times out and the DMIC GP-DMA overruns afterwards.

Drop CONFIG_LOG_MODE_IMMEDIATE and go back to the default deferred mode.

Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
CONFIG_ZEPHYR_DP_SCHEDULER can be enabled on cAVS, but only the ACE
platform_init() registered the DP scheduler. Creating a DP module on
cAVS then failed with "unable to bind scheduler to task (type 3)" and
module init returned -ENODEV.

Call scheduler_dp_init() after the LL scheduler is set up, as ACE does.

Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
The DP lock is taken by the LL thread on every tick in
scheduler_dp_ll_tick() and by each DP thread after every run. It was
a k_sem, which has no priority inheritance: when a DP thread holding
it was preempted by other DP threads, the cooperative high priority LL
thread blocked until the holder got CPU time again.

With several busy DP modules (3 MFCC + 3 MWW on cAVS 2.5) single LL
ticks took up to ~40 ms, overrunning the DMIC DMAs of unrelated
streams. With a k_mutex the holder inherits the LL priority: LL max
drops from ~1.5M to <30k timer cycles, with no LL overruns or DMA
xruns.

Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
In IPC4 a buffer gets its stream params from the consuming module at
bind time. Legacy comp_driver consumers don't do that, so a DP module
feeding one (e.g. MWW to the WoV arbiter) saw rate and frame size 0 on
its sink and module_adapter_calculate_dp_period() divided by zero.

Before calculating the DP period, apply the module's own stream params
to any sink buffer which has no rate yet.

Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
The dual-rate multi-slot WoV pipelines declare 2ch DMIC DAI copiers for
both dmic01 (48 kHz) and dmic16k (16 kHz). This matches the
dmic-wov-feature topology, which splits PDM0/PDM1 between the two DAIs,
but not dmic-generic.conf, where both DAIs enable all NUM_DMICS mics.
On 4-mic platforms (e.g. sof-adl-max98357a-rt5682-wov-multi) the NHLT
only carries 4ch DMIC blobs, so the kernel fails to start the ECNS
capture with:

  no matching blob for sample rate: 16000 sample width: 16 channels: 2

Add DMIC_WOV_DAI_CHANNELS (default 2) and set it to 4 in dmic-generic
when NUM_DMICS is 4. With 4 channels the DAI copiers take 4ch input and
keep the 2ch output, letting the copier remap the first two mics to
stereo for the ECNS, so the rest of the WoV graph is unchanged.

Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
singalsu and others added 30 commits October 7, 2026 18:48
…nces

Lowering the startup warmup threshold previously allowed the model to
evaluate detections on initial unprimed temporal buffer states during
pipeline start. This produced a false trigger at t = 1s on startup
transients before audio playback began.

Restore MWW_WARMUP_INFERENCES to 33 inferences (~1 sec) and restore
MWW_CONSECUTIVE_DETECTS_REQUIRED to 3 to align with training verification
and suppress startup false triggers.

Signed-off-by: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
mod_ipc_msg_w_ext_init() allocates the ipc_msg and its tx_data with
mod_zalloc(), which uses SOF_MEM_FLAG_USER only and thus returns
cached memory. Before the conversion the message was allocated with
SOF_MEM_FLAG_COHERENT.

msg->list is linked into the uncached ipc->msg_list by the module
(possibly on a secondary core or DP thread) and unlinked by the IPC
send worker on the primary core. With a cached msg the worker operates
on stale list pointers, list_item_del() fails to unlink the message
and the same notification is sent to the host over and over again.

Allocate the message and its payload with SOF_MEM_FLAG_COHERENT, as
it was done before.

Fixes: 97dd710 ("ipc: make IPC message allocation userspace-safe")
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
(cherry picked from commit a5cb815)
Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
The KPB real-time sink previously fed a mixin that lived in KPB's own
pipeline. Because kpb_copy() returns PPL_STATUS_PATH_STOP, the pipeline
walk ends at KPB and that downstream mixin was never scheduled, so the
detector slots only ever saw silence. Move the mixin fanout into its own
pipeline (118) which drains the KPB sel_sink buffer on its own
low-latency walk, the same way the WoV arbiter already consumes the KPB
host sink across pipelines.

Restrict the WoV capture PCMs to S16_LE. The detection path is 16-bit
end to end, and advertising S32_LE let the host negotiate a 32-bit chain
that ECNS pin0 cannot satisfy, which failed hw_params with an
unsupported-format error on ecns.115.1.

Enable the MFCC VAD in the PCAN config so the firmware populates the
per-hop energy and speech flag that MicroWakeWord gates on, while
keeping DTX and control notifications disabled so every hop is still
emitted and no kcontrol notification flood can break D0i3.

Pull in module-copier.conf in the feature and manifest files so the
standalone WoV topology builds resolve the module.

Signed-off-by: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
Demote the per-hop PCAN diagnostic from info to debug level so it no
longer floods the trace logger during active capture.

Signed-off-by: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
Synchronous draining reschedules the drain task on a tight 500 us EDF
loop that can starve the other low-latency work on the WoV core and
stall the scheduler. Disable it so draining runs on the normal cadence.

Signed-off-by: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
Add low-rate, silence-gated diagnostics that survive the trace logger
during active capture: a per-hop "MWW DBG" line with the VAD, energy and
feature range, an inference probability line, and a per-slot summary
printed at reset. The per-hop trace is gated on the VAD speech flag (plus
a clear feature-floor crossing) rather than the raw feature level, which
the DMIC noise floor almost always exceeded and so flooded the logger.
The probability is printed at 0.01% resolution with the window VAD mask
so the model output during the keyword is visible rather than truncated
to zero.

Lower the consecutive-detection requirement from three to two to make
the detector react within the test capture window.

Signed-off-by: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
The pin format, per-channel peak scan, per-copy and reset-summary traces
were bring-up scaffolding to chase the WoV capture path. The module is
working now, so drop the diagnostics and their accumulators. Functional
draining and the test-signal path are unchanged.

Signed-off-by: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
The per-copy arbiter trace ran at info level and added to the capture
log flood. Demote it to debug.

Signed-off-by: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
Select CONFIG_ECNS_KPB_MONO_AVG_ALL so the ECNS mono downmix that feeds
the keyword detectors averages all four PDM channels instead of a single
mic pair, which avoids keying detection off a weak microphone.

Enlarge the Zephyr log and mtrace cache buffers to 32 KiB so the
per-hop WoV diagnostics are not dropped during active capture.

Signed-off-by: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
Extend the MWW mtrace plot script to parse the current per-hop DBG
records and render the feature flow and detection curves.

Signed-off-by: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
Replace pipeline 118's mixin fanout with a three-output module-copier.
Replace detector mixouts with LL module-copiers ahead of the DP
MFCC/MWW paths. This avoids mixin underrun notification flooding,
which prevents the system from suspending. Update KPB's pin binding
for the new fanout widget.

Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
…copy

wov_arb_copy() resent SOF_IPC4_NOTIFY_PHRASE_DETECTED every 10ms (rate
limited, but still continuous) for as long as a slot stayed active, i.e. for
the entire remaining lifetime of the host PCM stream. This flooded the IPC
mailbox and host dmesg (hundreds of notifications per capture) even though
the notification has no functional purpose there: only a substream that
actually opted into SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP depends on it to
call snd_sof_pcm_period_elapsed(); a normal interrupt-driven capture is
already woken by its regular hw pointer updates and ignores it.

Drop the periodic resend and the last_notify_time throttle state it needed.
PHRASE_DETECTED is now sent exactly once per detection, from
arb_on_detect(), matching its role as a one-shot wake rather than a
substitute for the host's own period-elapsed mechanism.

Verified on DUT: arecord + wovdebug_111 trigger now produces exactly one
notification (2 dmesg lines) instead of ~600 over a 5s capture, and the
no-period-wakeup test tool (wov_blocking_read_tinyalsa) still unblocks
immediately on trigger.

Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
The tinyalsa reader arms wovdebug_* before pcm_readi(). With
start_threshold=1, tinyalsa may defer starting the PCM until that
read, allowing the fake detection to race ahead of the host
pipeline. Start the PCM explicitly before arming the control.

PCM_NOIRQ is not needed for MMAP capture and makes tinyalsa wake
on timed polls instead of normal period notifications. Drop it
so the reader can wait for period wakeups.

On the DUT, wovdebug_111 returned all 4000 frames with normal
period wakeups in 0.258s.

Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
The alsa-lib capture tool opens the PCM in nonblocking mode and
calls snd_pcm_wait() after EAGAIN. With no-period-wakeup set,
it has neither regular period notifications nor a timed check of
the hardware pointer. The wait times out even after a WoV trigger
has made audio available.

Leave period wakeups enabled so PCM readiness wakes the read loop.
On the DUT, wovdebug_111 captured all 4000 frames in S0 and
8000 frames after a six-second idle delay.

Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
inst->op_resolver is declared MwwOpResolver* (a MicroMutableOpResolver<14>
typedef), but was destroyed via the base-class destructor name
~MicroOpResolver(). GCC accepts naming a base class in an unqualified
pseudo-destructor call as an extension; Cadence's xt-clang (Clang 10.0.1)
enforces the standard rule that the name must match the pointer's own
declared type, and rejects the mismatch as an error. Name the destructor
after the actual declared type instead.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Add a dedicated West submanifest submanifests/tflm.yml declaring the TFLM
runtime and required ML companion projects (tflite-micro, flatbuffers,
nnlib-hifi4, gemmlowp, and ruy) so that west update manages them natively.
Update scripts/tensorflow-clone.sh to track thesofproject/tflite-micro at
the pinned commit.

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

Support topologies where ECNS has a single 16 kHz producer (pin0 fallback)
and align pin format definitions with 32-bit container configurations.
Fix audio frame consumption accounting to track the maximum produced
frames across pins, and guard sink lookup in module_adapter_prepare.

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

Remove embedded NHLT binary preprocessing from the rt721 and rt722 multi-wov
topologies, delegating endpoint discovery and configuration to the machine
BIOS ACPI NHLT table.

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

Add retry logic for control setting in wov_blocking_read, support ESTRPIPE
stream recovery, and update run_wov_10x.py process handling and timeouts.
Add PTL Intel debug key signature mapping to sof_ri_info.py.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
When the volatile 'wovdebug' switch kcontrol is activated via ALSA mixer,
arm a 5000 ms timer (configurable via CONFIG_COMP_MWW_FAKE_WAKE_MS) instead
of firing keyword detection immediately.

The timer counts down during active audio processing in mww_process()
and fires synthetic detection and KPB history draining upon expiration,
resetting the ALSA control back to 0. Re-arm the timer upon D0i3 power state
transition or prepare if armed to ensure the full delay elapses.

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

Point the tflite-micro project at upstream tensorflow/tflite-micro
(e86d97b6237f88ab5925c0b41e3e3589a1560d86) instead of the thesofproject
fork, since west now natively manages all five TFLM dependencies via
submanifests/tflm.yml. scripts/tensorflow-clone.sh duplicated this same
REPOS/COMMIT_ID pinning outside of west and had drifted out of sync with
it; nothing in the tree invoked it, so remove it and repoint the one
stale comment referencing it.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
No need for decimals in MWW probability value. The integer percent
is enough accurate for debug.

Signed-off-by: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
Add a built-in 100 Hz second-order highpass filter with +20 dB gain at
16 kHz to the ECNS component for the Pin 0 detection path to KPB.
The coefficients are initialized using a static coefficient blob and
run via iir_df1 on the downmixed mono signal before quantizing to 16-bit.

Filtering the single downmixed mono channel inside ECNS rather than
filtering all microphone channels upstream significantly reduces
computational overhead on the detection path.

Signed-off-by: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
Remove eqiir.119.1 from pipeline 119 and bind the dmic16k DAI copier
directly to ECNS input pin 0. Highpass filtering with +20 dB gain is
now handled internally inside ECNS on the downmixed mono signal for
the KPB detection path.

Drop the unused eqiir class include from dmic-wov-feature.conf and
update the pipeline routing.

Signed-off-by: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
ECNS already depends on IPC_MAJOR_4 in Kconfig and relies on IPC4
structures for buffer formats, queues, and configuration handling.

Drop the unused non-IPC4 conditional blocks in ecns_params and
ecns_prepare to simplify the component implementation.

Signed-off-by: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
Refactor the oversized ecns_copy() function by splitting its top-level
processing paths into dedicated helper functions:
- ecns_process_kpb(): handles Pin 0 16 kHz stream downmixing, built-in
  highpass filtering, and KPB mono buffer output.
- ecns_process_host(): handles Pin 1 48 kHz (or fallback) channel
  mapping and host capture buffer output.
- ecns_consume_sources(): manages buffer consumption and idle draining
  for active and inactive source inputs.

Signed-off-by: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
Calling audio_stream_wrap() on every processed audio sample or frame
imposes a significant MCPS overhead in data processing copy loops.

Refactor the processing helper loops to compute the number of frames
until the next circular buffer boundary using
audio_stream_frames_without_wrap(). Process contiguous chunks in the
inner loop with plain pointer arithmetic and wrap the stream pointers
only when reaching buffer boundaries.

Signed-off-by: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
Add CONFIG_ECNS_TEST_SIGNAL to gate the test signal generator on the
ECNS clean mono output pin (Pin 0 to KPB), defaulting to 'n'.

When disabled, avoid compiling the test signal generator helpers and
runtime checks, and emit a warning trace in ecns_set_large_config() if
an attempt is made to enable the test signal via ALSA control.

Signed-off-by: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
Commit 32af3fe introduced CONFIG_ECNS_TEST_SIGNAL to gate the ECNS
test signal generator with 'default n'.

Explicitly select CONFIG_ECNS_TEST_SIGNAL=y in intel_adsp_ace30_ptl.conf
and intel_adsp_ace30_wcl.conf so hardware Wake-on-Voice test signal
generation on the ECNS mono output to KPB remains enabled for continuous
integration and automated validation suites.

Also select MATH_IIR alongside MATH_IIR_DF1 in COMP_ECNS to ensure its
dependency is met.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
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.

5 participants