From 7ac7b2c58897e5716090e5ae117f89b336c4568b Mon Sep 17 00:00:00 2001 From: Gaggery Tsai Date: Thu, 23 Jul 2026 11:02:00 -0700 Subject: [PATCH 1/2] topology2: cavs: fix WoV pipeline routing The SoundWire topology cannot instantiate the existing WoV pipeline. It does not import the KPB or detector classes, and its DAI route names a widget that cannot exist because copier names use their stream name. Import the required classes and move the DAI-to-KPB route to dmic-wov. Fix the KPB output pin target, describe the host copier input formats, and set the 16 kHz PCM constraints so hw_params can select the mono detector path. Parameterize the KPB UUID, keeping the IPC3 default while allowing IPC4 targets to select kpb4. Signed-off-by: Gaggery Tsai --- tools/topology/topology2/cavs-sdw.conf | 4 ++ .../topology2/include/components/kpb.conf | 9 ++- .../include/pipelines/cavs/dai-kpb-be.conf | 8 +-- .../platform/intel/dmic-default.conf | 5 -- .../topology2/platform/intel/dmic-wov.conf | 62 +++++++++++++++---- 5 files changed, 62 insertions(+), 26 deletions(-) diff --git a/tools/topology/topology2/cavs-sdw.conf b/tools/topology/topology2/cavs-sdw.conf index 311e0376b333..23fa33880c17 100644 --- a/tools/topology/topology2/cavs-sdw.conf +++ b/tools/topology/topology2/cavs-sdw.conf @@ -35,6 +35,10 @@ + + + + diff --git a/tools/topology/topology2/include/components/kpb.conf b/tools/topology/topology2/include/components/kpb.conf index 03f7989be8ac..ffa73d01f567 100644 --- a/tools/topology/topology2/include/components/kpb.conf +++ b/tools/topology/topology2/include/components/kpb.conf @@ -12,6 +12,12 @@ # # Where N is the unique instance number for the kpb object within the same alsaconf node. +# Keep the IPC3 UUID as the default. IPC4 topologies must select kpb4 by +# overriding KPB_UUID in the top-level topology. +Define { + KPB_UUID "43:84:21:d8:f3:5f:4c:4a:b3:88:6c:fe:07:b9:56:2e" +} + Class.Widget."kpb" { # # Pipeline ID for the kpb object @@ -67,8 +73,7 @@ Class.Widget."kpb" { num_input_audio_formats 1 num_output_audio_formats 1 - #UUID: D8218443-5FF3-4A4C-B388-6CFE07B9562E - uuid "43:84:21:d8:f3:5f:4c:4a:b3:88:6c:fe:07:b9:56:2e" + uuid $KPB_UUID no_pm "true" cpc 720000 num_input_pins 1 diff --git a/tools/topology/topology2/include/pipelines/cavs/dai-kpb-be.conf b/tools/topology/topology2/include/pipelines/cavs/dai-kpb-be.conf index 91ca50a62bed..19ae0a70708e 100644 --- a/tools/topology/topology2/include/pipelines/cavs/dai-kpb-be.conf +++ b/tools/topology/topology2/include/pipelines/cavs/dai-kpb-be.conf @@ -125,12 +125,8 @@ Class.Pipeline."dai-kpb-be" { } } - Object.Base { - route."1" { - source "dai-copier.DMIC.$index.1" - sink "kpb.$index.1" - } - } + # DAI copier names contain the stream name instead of the pipeline + # index. The instantiating topology must provide the route to KPB. time_domain "timer" dynamic_pipeline 1 diff --git a/tools/topology/topology2/platform/intel/dmic-default.conf b/tools/topology/topology2/platform/intel/dmic-default.conf index 1bb96a45465b..0e7275774f7a 100644 --- a/tools/topology/topology2/platform/intel/dmic-default.conf +++ b/tools/topology/topology2/platform/intel/dmic-default.conf @@ -25,11 +25,6 @@ Define { DMIC1_HOST_PIPELINE_ID 18 DMIC1_DAI_PIPELINE_ID 19 WOV_PIPELINE_ID 20 - DMIC1_HOST_PIPELINE_SINK 'copier.host.18.1' - DMIC_WOV_DAI_PIPELINE_SRC 'dai-copier.DMIC.dmic16k.capture' - DMIC_WOV_DAI_PIPELINE_KPB 'kpb.19.1' - WOV_PIPELINE_SINK 'micsel.20.1' - WOV_PIPELINE_VIRTUAL 'virtual.detect_sink' INCLUDE_WOV 'false' # The UUID corresponds to the test detect component WOV_UUID '1f:d5:a8:eb:27:78:b5:47:82:ee:de:6e:77:43:af:67' diff --git a/tools/topology/topology2/platform/intel/dmic-wov.conf b/tools/topology/topology2/platform/intel/dmic-wov.conf index 0094941e0c74..4beb269ca606 100644 --- a/tools/topology/topology2/platform/intel/dmic-wov.conf +++ b/tools/topology/topology2/platform/intel/dmic-wov.conf @@ -9,9 +9,41 @@ Object.Pipeline { Object.Widget.host-copier.1 { stream_name $DMIC1_PCM_CAPS - pcm_id 11 - num_output_audio_formats 2 + pcm_id $DMIC1_PCM_ID + num_input_audio_formats 3 + num_output_audio_formats 3 + Object.Base.input_audio_format [ + { + in_rate 16000 + in_channels 1 + in_ch_cfg $CHANNEL_CONFIG_MONO + in_ch_map $CHANNEL_MAP_MONO + in_bit_depth 32 + in_valid_bit_depth 32 + } + { + in_rate 16000 + in_bit_depth 32 + in_valid_bit_depth 32 + } + { + in_rate 16000 + in_channels 4 + in_bit_depth 32 + in_valid_bit_depth 32 + in_ch_cfg $CHANNEL_CONFIG_3_POINT_1 + in_ch_map $CHANNEL_MAP_3_POINT_1 + } + ] Object.Base.output_audio_format [ + { + out_rate 16000 + out_channels 1 + out_ch_cfg $CHANNEL_CONFIG_MONO + out_ch_map $CHANNEL_MAP_MONO + out_bit_depth 32 + out_valid_bit_depth 32 + } { out_rate 16000 out_bit_depth 32 @@ -84,10 +116,10 @@ Object.Pipeline { Object.Widget.kpb.1 { Object.Base.output_pin_binding.1 { - output_pin_binding_name $WOV_PIPELINE_SINK + output_pin_binding_name "micsel.$WOV_PIPELINE_ID.1" } Object.Base.output_pin_binding.2 { - output_pin_binding_name $DMIC1_HOST_PIPELINE_SINK + output_pin_binding_name "host-copier.$DMIC1_PCM_ID.capture" } Object.Base.output_pin_binding.3 { output_pin_binding_name "NotConnected" @@ -111,23 +143,27 @@ Object.Pipeline { Object.Base.route [ { - source $DMIC_WOV_DAI_PIPELINE_KPB - sink "host-copier.11.capture" + source "dai-copier.DMIC.$DMIC1_NAME.capture" + sink "kpb.$DMIC1_DAI_PIPELINE_ID.1" + } + { + source "kpb.$DMIC1_DAI_PIPELINE_ID.1" + sink "host-copier.$DMIC1_PCM_ID.capture" } { - source $DMIC_WOV_DAI_PIPELINE_KPB - sink $WOV_PIPELINE_SINK + source "kpb.$DMIC1_DAI_PIPELINE_ID.1" + sink "micsel.$WOV_PIPELINE_ID.1" } { - source $WOV_PIPELINE_VIRTUAL - sink "host-copier.11.capture" + source "virtual.detect_sink" + sink "host-copier.$DMIC1_PCM_ID.capture" } ] Object.PCM.pcm [ { name "DMIC16k" - id 11 + id $DMIC1_PCM_ID direction "capture" capture_compatible_d0i3 true Object.Base.fe_dai.1 { @@ -136,10 +172,10 @@ Object.PCM.pcm [ Object.PCM.pcm_caps.1 { name $DMIC1_PCM_CAPS - # only 32-bit capture supported now formats 'S32_LE' - channels_min $NUM_DMICS + channels_min 1 channels_max $NUM_DMICS + rates '16000' rate_min 16000 rate_max 16000 } From 75b2660fde9bb93b481e7284983cfb9205fa400b Mon Sep 17 00:00:00 2001 From: Gaggery Tsai Date: Thu, 23 Jul 2026 11:02:00 -0700 Subject: [PATCH 2/2] topology2: cavs: configure WoV module formats Loadable detectors describe their audio frame and memory requirements in the module manifest. Fixed format values cannot instantiate modules that require a different sample width, frame size, or BSS allocation. Expose the pipeline and PCM formats, container and valid widths, frame bytes, instance pages, and control size as target overrides. Retain the existing 32-bit, one ms frame defaults. Enable TLV writes on wov_init so clients can update module large configuration data after the widget is instantiated. Signed-off-by: Gaggery Tsai --- tools/topology/topology2/README.md | 25 ++++++++++ .../topology2/include/components/wov.conf | 9 +++- .../include/pipelines/cavs/dai-kpb-be.conf | 16 +++--- .../include/pipelines/cavs/wov-detect.conf | 18 ++++--- .../platform/intel/dmic-default.conf | 7 +++ .../topology2/platform/intel/dmic-wov.conf | 49 ++++++++++--------- 6 files changed, 82 insertions(+), 42 deletions(-) diff --git a/tools/topology/topology2/README.md b/tools/topology/topology2/README.md index bea7ffcfdcde..15b57abd8143 100644 --- a/tools/topology/topology2/README.md +++ b/tools/topology/topology2/README.md @@ -252,6 +252,31 @@ default ID ranges for the same endpoint types. > `BT_PCM_ID` override variable to set the correct value when BT coexists with a speaker > amplifier (which also uses PCM ID 2 by default). +### Wake-on-voice parameters + +For a CAVS topology with PCH DMIC enabled and `PASSTHROUGH=false`, set +`INCLUDE_WOV=true` to add the DMIC1, KPB, detector, and drain PCM +pipelines. IPC4 targets must also override `KPB_UUID` with the `kpb4` +UUID registered by their firmware. The class default is the IPC3 KPB +UUID so existing IPC3 users are unchanged. + +The detector's module manifest determines its frame and memory settings. +Override these variables together when selecting a detector: + +| Variable | Default | Purpose | +|---|---:|---| +| `WOV_FORMAT` | `s32le` | Pipeline sample format | +| `WOV_PCM_FMT` | `S32_LE` | Drain PCM sample format | +| `WOV_BIT_DEPTH` | 32 | Audio container width | +| `WOV_VALID_BIT_DEPTH` | 32 | Valid sample width | +| `WOV_IBS` | 64 | Detector input frame bytes | +| `WOV_OBS` | 64 | Detector output frame bytes | +| `WOV_IS_PAGES` | 0 | Module instance memory pages | +| `WOV_CONTROL_MAX` | 4096 | Maximum bytes-control payload | + +The `wov_init` bytes control supports runtime TLV reads and writes. Increase +`WOV_CONTROL_MAX` only when a detector accepts a larger configuration. + **Intel HDA PCM IDs:** | Endpoint | Default PCM ID | Override Variable | diff --git a/tools/topology/topology2/include/components/wov.conf b/tools/topology/topology2/include/components/wov.conf index fccf2066be6e..15148833b235 100644 --- a/tools/topology/topology2/include/components/wov.conf +++ b/tools/topology/topology2/include/components/wov.conf @@ -14,6 +14,10 @@ # # Where N is the unique instance number for the wov object within the same alsaconf node. +Define { + WOV_CONTROL_MAX 4096 +} + Class.Widget."wov" { # # Pipeline ID for the wov object @@ -72,13 +76,14 @@ Class.Widget."wov" { name wov_init access [ tlv_read + tlv_write tlv_callback ] Object.Base.extops."extctl" { get 258 - put 0 + put 258 } - max 4096 + max $WOV_CONTROL_MAX Object.Base.data."1" { IncludeByKey.WOV_UUID { '1f:d5:a8:eb:27:78:b5:47:82:ee:de:6e:77:43:af:67' {bytes "0x53, 0x4f, 0x46, 0x34, 0x02, 0x00, 0x00, 0x00, diff --git a/tools/topology/topology2/include/pipelines/cavs/dai-kpb-be.conf b/tools/topology/topology2/include/pipelines/cavs/dai-kpb-be.conf index 19ae0a70708e..700082d9090b 100644 --- a/tools/topology/topology2/include/pipelines/cavs/dai-kpb-be.conf +++ b/tools/topology/topology2/include/pipelines/cavs/dai-kpb-be.conf @@ -89,14 +89,14 @@ Class.Pipeline."dai-kpb-be" { Object.Base.input_audio_format [ { in_rate 16000 - in_bit_depth 32 - in_valid_bit_depth 32 + in_bit_depth $WOV_BIT_DEPTH + in_valid_bit_depth $WOV_VALID_BIT_DEPTH } { in_rate 16000 in_channels 4 - in_bit_depth 32 - in_valid_bit_depth 32 + in_bit_depth $WOV_BIT_DEPTH + in_valid_bit_depth $WOV_VALID_BIT_DEPTH in_ch_cfg $CHANNEL_CONFIG_3_POINT_1 in_ch_map $CHANNEL_MAP_3_POINT_1 } @@ -105,14 +105,14 @@ Class.Pipeline."dai-kpb-be" { Object.Base.output_audio_format [ { out_rate 16000 - out_bit_depth 32 - out_valid_bit_depth 32 + out_bit_depth $WOV_BIT_DEPTH + out_valid_bit_depth $WOV_VALID_BIT_DEPTH } { out_rate 16000 out_channels 4 - out_bit_depth 32 - out_valid_bit_depth 32 + out_bit_depth $WOV_BIT_DEPTH + out_valid_bit_depth $WOV_VALID_BIT_DEPTH out_ch_cfg $CHANNEL_CONFIG_3_POINT_1 out_ch_map $CHANNEL_MAP_3_POINT_1 } diff --git a/tools/topology/topology2/include/pipelines/cavs/wov-detect.conf b/tools/topology/topology2/include/pipelines/cavs/wov-detect.conf index 0f4490525c83..da99f97a6569 100644 --- a/tools/topology/topology2/include/pipelines/cavs/wov-detect.conf +++ b/tools/topology/topology2/include/pipelines/cavs/wov-detect.conf @@ -64,8 +64,8 @@ Class.Pipeline."wov-detect" { in_channels 2 in_ch_map $CHANNEL_MAP_STEREO in_ch_cfg 1 - in_bit_depth 32 - in_valid_bit_depth 32 + in_bit_depth $WOV_BIT_DEPTH + in_valid_bit_depth $WOV_VALID_BIT_DEPTH } ] Object.Base.output_audio_format [ @@ -74,8 +74,8 @@ Class.Pipeline."wov-detect" { out_channels 1 out_ch_map $CHANNEL_MAP_MONO out_ch_cfg 0 - out_bit_depth 32 - out_valid_bit_depth 32 + out_bit_depth $WOV_BIT_DEPTH + out_valid_bit_depth $WOV_VALID_BIT_DEPTH } ] } @@ -89,16 +89,18 @@ Class.Pipeline."wov-detect" { in_channels 1 in_ch_cfg 0 in_ch_map $CHANNEL_MAP_MONO - in_bit_depth 32 - in_valid_bit_depth 32 + in_bit_depth $WOV_BIT_DEPTH + in_valid_bit_depth $WOV_VALID_BIT_DEPTH + ibs $WOV_IBS } ] Object.Base.output_audio_format [ { out_rate 16000 out_channels 1 - out_bit_depth 32 - out_valid_bit_depth 32 + out_bit_depth $WOV_BIT_DEPTH + out_valid_bit_depth $WOV_VALID_BIT_DEPTH + obs $WOV_OBS } ] } diff --git a/tools/topology/topology2/platform/intel/dmic-default.conf b/tools/topology/topology2/platform/intel/dmic-default.conf index 0e7275774f7a..9b2dc3456bf1 100644 --- a/tools/topology/topology2/platform/intel/dmic-default.conf +++ b/tools/topology/topology2/platform/intel/dmic-default.conf @@ -29,6 +29,13 @@ Define { # The UUID corresponds to the test detect component WOV_UUID '1f:d5:a8:eb:27:78:b5:47:82:ee:de:6e:77:43:af:67' WOV_CPC '360000' + WOV_FORMAT s32le + WOV_PCM_FMT 'S32_LE' + WOV_BIT_DEPTH 32 + WOV_VALID_BIT_DEPTH 32 + WOV_IBS 64 + WOV_OBS 64 + WOV_IS_PAGES 0 DMIC1_PCM_CAPS 'Passthrough Capture 18' DMIC_CORE_ID 0 PASSTHROUGH "false" diff --git a/tools/topology/topology2/platform/intel/dmic-wov.conf b/tools/topology/topology2/platform/intel/dmic-wov.conf index 4beb269ca606..1a00ad6381a3 100644 --- a/tools/topology/topology2/platform/intel/dmic-wov.conf +++ b/tools/topology/topology2/platform/intel/dmic-wov.conf @@ -1,7 +1,7 @@ Object.Pipeline { host-gateway-capture [ { - format $FORMAT + format $WOV_FORMAT rate 16000 rate_min 16000 rate_max 16000 @@ -18,19 +18,19 @@ Object.Pipeline { in_channels 1 in_ch_cfg $CHANNEL_CONFIG_MONO in_ch_map $CHANNEL_MAP_MONO - in_bit_depth 32 - in_valid_bit_depth 32 + in_bit_depth $WOV_BIT_DEPTH + in_valid_bit_depth $WOV_VALID_BIT_DEPTH } { in_rate 16000 - in_bit_depth 32 - in_valid_bit_depth 32 + in_bit_depth $WOV_BIT_DEPTH + in_valid_bit_depth $WOV_VALID_BIT_DEPTH } { in_rate 16000 in_channels 4 - in_bit_depth 32 - in_valid_bit_depth 32 + in_bit_depth $WOV_BIT_DEPTH + in_valid_bit_depth $WOV_VALID_BIT_DEPTH in_ch_cfg $CHANNEL_CONFIG_3_POINT_1 in_ch_map $CHANNEL_MAP_3_POINT_1 } @@ -41,19 +41,19 @@ Object.Pipeline { out_channels 1 out_ch_cfg $CHANNEL_CONFIG_MONO out_ch_map $CHANNEL_MAP_MONO - out_bit_depth 32 - out_valid_bit_depth 32 + out_bit_depth $WOV_BIT_DEPTH + out_valid_bit_depth $WOV_VALID_BIT_DEPTH } { out_rate 16000 - out_bit_depth 32 - out_valid_bit_depth 32 + out_bit_depth $WOV_BIT_DEPTH + out_valid_bit_depth $WOV_VALID_BIT_DEPTH } { out_rate 16000 out_channels 4 - out_bit_depth 32 - out_valid_bit_depth 32 + out_bit_depth $WOV_BIT_DEPTH + out_valid_bit_depth $WOV_VALID_BIT_DEPTH out_ch_cfg $CHANNEL_CONFIG_3_POINT_1 out_ch_map $CHANNEL_MAP_3_POINT_1 } @@ -65,7 +65,7 @@ Object.Pipeline { dai-kpb-be [ { direction "capture" - format $FORMAT + format $WOV_FORMAT rate 16000 rate_min 16000 rate_max 16000 @@ -84,14 +84,14 @@ Object.Pipeline { Object.Base.input_audio_format [ { in_rate 16000 - in_bit_depth 32 - in_valid_bit_depth 32 + in_bit_depth $WOV_BIT_DEPTH + in_valid_bit_depth $WOV_VALID_BIT_DEPTH } { in_rate 16000 in_channels 4 - in_bit_depth 32 - in_valid_bit_depth 32 + in_bit_depth $WOV_BIT_DEPTH + in_valid_bit_depth $WOV_VALID_BIT_DEPTH in_ch_cfg $CHANNEL_CONFIG_3_POINT_1 in_ch_map $CHANNEL_MAP_3_POINT_1 } @@ -100,14 +100,14 @@ Object.Pipeline { Object.Base.output_audio_format [ { out_rate 16000 - out_bit_depth 32 - out_valid_bit_depth 32 + out_bit_depth $WOV_BIT_DEPTH + out_valid_bit_depth $WOV_VALID_BIT_DEPTH } { out_rate 16000 out_channels 4 - out_bit_depth 32 - out_valid_bit_depth 32 + out_bit_depth $WOV_BIT_DEPTH + out_valid_bit_depth $WOV_VALID_BIT_DEPTH out_ch_cfg $CHANNEL_CONFIG_3_POINT_1 out_ch_map $CHANNEL_MAP_3_POINT_1 } @@ -131,11 +131,12 @@ Object.Pipeline { wov-detect [ { index $WOV_PIPELINE_ID - format s32le + format $WOV_FORMAT channels 2 Object.Widget.wov.1 { uuid $WOV_UUID cpc $WOV_CPC + is_pages $WOV_IS_PAGES } } ] @@ -172,7 +173,7 @@ Object.PCM.pcm [ Object.PCM.pcm_caps.1 { name $DMIC1_PCM_CAPS - formats 'S32_LE' + formats $WOV_PCM_FMT channels_min 1 channels_max $NUM_DMICS rates '16000'