From 02f4f0ed21558845a71c5e481ae005905a71373e Mon Sep 17 00:00:00 2001 From: Naveen Manohar Date: Tue, 25 Aug 2026 22:22:08 +0530 Subject: [PATCH 1/2] ASoC: SOF: ipc4: handle PHRASE_DETECTED notification for WoV Add SOF_IPC4_NOTIFY_PHRASE_DETECTED notification handler, sent by DSP FW when a keyword is detected by WoV pipeline. Handler parses PCM list to find WoV capture PCM pcm_id 11, calls snd_pcm_period_elapsed() to unblock waiting capture stream. Change-Id: I45190d31847be31a22b490c2eaaf39d144164950 Signed-off-by: Naveen Manohar --- sound/soc/sof/Makefile | 2 +- sound/soc/sof/ipc4-wov.c | 49 ++++++++++++++++++++++++++++++++++++++++ sound/soc/sof/ipc4-wov.h | 13 +++++++++++ sound/soc/sof/ipc4.c | 4 ++++ 4 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 sound/soc/sof/ipc4-wov.c create mode 100644 sound/soc/sof/ipc4-wov.h diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile index 887abf70da3ba1..df97a86452b48a 100644 --- a/sound/soc/sof/Makefile +++ b/sound/soc/sof/Makefile @@ -12,7 +12,7 @@ snd-sof-$(CONFIG_SND_SOC_SOF_COMPRESS) += ipc3-compress.o endif ifneq ($(CONFIG_SND_SOC_SOF_IPC4),) snd-sof-y += ipc4.o ipc4-loader.o ipc4-topology.o ipc4-control.o ipc4-pcm.o\ - ipc4-mtrace.o ipc4-telemetry.o + ipc4-mtrace.o ipc4-telemetry.o ipc4-wov.o snd-sof-$(CONFIG_SND_SOC_SOF_COMPRESS) += ipc4-compress.o endif diff --git a/sound/soc/sof/ipc4-wov.c b/sound/soc/sof/ipc4-wov.c new file mode 100644 index 00000000000000..c973b13e7c1706 --- /dev/null +++ b/sound/soc/sof/ipc4-wov.c @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// Copyright(c) 2026 Intel Corporation + +#include +#include +#include +#include "sof-audio.h" +#include "ipc4-wov.h" + +/* IPC4 PHRASE_DETECTED primary/extension field layout */ +#define SOF_IPC4_PHRASE_WORD_ID_MASK GENMASK(31, 24) +#define SOF_IPC4_PHRASE_WORD_ID_SHIFT 24 +#define SOF_IPC4_PHRASE_SV_SCORE_MASK GENMASK(15, 0) + +/* PCM ID for WoV keyword detection capture stream */ +#define SOF_WOV_PCM_ID 11 + +void sof_ipc4_wov_phrase_detected(struct snd_sof_dev *sdev, + struct sof_ipc4_msg *ipc4_msg) +{ + struct snd_sof_pcm *spcm; + struct snd_pcm_substream *substream; + u32 word_id = (ipc4_msg->primary & SOF_IPC4_PHRASE_WORD_ID_MASK) + >> SOF_IPC4_PHRASE_WORD_ID_SHIFT; + u32 sv_score = ipc4_msg->extension & SOF_IPC4_PHRASE_SV_SCORE_MASK; + + dev_dbg(sdev->dev, "WoV: PHRASE_DETECTED word_id=%u sv_score=%u\n", + word_id, sv_score); + + list_for_each_entry(spcm, &sdev->pcm_list, list) { + if (spcm->pcm.pcm_id != SOF_WOV_PCM_ID) + continue; + + substream = spcm->stream[SNDRV_PCM_STREAM_CAPTURE].substream; + if (!substream || !substream->runtime) { + dev_warn(sdev->dev, "WoV: PCM %d not open\n", + SOF_WOV_PCM_ID); + return; + } + + pm_wakeup_event(sdev->dev, 2000); + snd_pcm_period_elapsed(substream); + return; + } + + dev_warn(sdev->dev, "WoV: PHRASE_DETECTED but PCM %d not found\n", + SOF_WOV_PCM_ID); +} diff --git a/sound/soc/sof/ipc4-wov.h b/sound/soc/sof/ipc4-wov.h new file mode 100644 index 00000000000000..fd071136f85cf9 --- /dev/null +++ b/sound/soc/sof/ipc4-wov.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ +/* Copyright(c) 2026 Intel Corporation */ + +#ifndef __SOF_IPC4_WOV_H +#define __SOF_IPC4_WOV_H + +#include "sof-priv.h" +#include "ipc4-priv.h" + +void sof_ipc4_wov_phrase_detected(struct snd_sof_dev *sdev, + struct sof_ipc4_msg *ipc4_msg); + +#endif /* __SOF_IPC4_WOV_H */ diff --git a/sound/soc/sof/ipc4.c b/sound/soc/sof/ipc4.c index bf3a122ee651e8..e6c2bb21116308 100644 --- a/sound/soc/sof/ipc4.c +++ b/sound/soc/sof/ipc4.c @@ -15,6 +15,7 @@ #include "sof-audio.h" #include "ipc4-fw-reg.h" #include "ipc4-priv.h" +#include "ipc4-wov.h" #include "ipc4-topology.h" #include "ipc4-telemetry.h" #include "ops.h" @@ -840,6 +841,9 @@ static void sof_ipc4_rx_msg(struct snd_sof_dev *sdev) case SOF_IPC4_NOTIFY_EXCEPTION_CAUGHT: snd_sof_dsp_panic(sdev, 0, true); break; + case SOF_IPC4_NOTIFY_PHRASE_DETECTED: + sof_ipc4_wov_phrase_detected(sdev, ipc4_msg); + break; case SOF_IPC4_NOTIFY_MODULE_NOTIFICATION: data_size = sizeof(struct sof_ipc4_notify_module_data); handler_func = sof_ipc4_module_notification_handler; From 54c39e09d7653a696586f01dbcd0f6e4e222b535 Mon Sep 17 00:00:00 2001 From: Naveen Manohar Date: Tue, 25 Aug 2026 22:35:33 +0530 Subject: [PATCH 2/2] ASoC: SOF: ipc4: notify WoV kcontrols on PHRASE_DETECTED When DSP reports keyword detection, notify topology-defined WoV kcontrols so that user space can poll for value changes. Checked for 2 kcontrols in loaded topology: - 'wov_trigger_id': RO enum reporting winner slot(0/1/2) - 'wov_event': control that user space polls via POLLPRI Change-Id: I8c8862f636904f5af519e86d5f9b09374c7316d6 Signed-off-by: Naveen Manohar --- sound/soc/sof/ipc4-wov.c | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/ipc4-wov.c b/sound/soc/sof/ipc4-wov.c index c973b13e7c1706..99273dc448c23a 100644 --- a/sound/soc/sof/ipc4-wov.c +++ b/sound/soc/sof/ipc4-wov.c @@ -16,6 +16,40 @@ /* PCM ID for WoV keyword detection capture stream */ #define SOF_WOV_PCM_ID 11 +/* kcontrol names as defined in the dmic-wov feature topology */ +#define SOF_WOV_KEYWORD_ID_CTL "wov_trigger_id" +#define SOF_WOV_EVENT_CTL "wov_event" + +/* + * kcontrol list for topology-defined WoV event/keyword-ID + * controls and trigger a user-space notification. + */ +static void sof_ipc4_wov_notify_kcontrols(struct snd_sof_dev *sdev) +{ + static const char * const wov_ctl_names[] = { + SOF_WOV_KEYWORD_ID_CTL, + SOF_WOV_EVENT_CTL, + }; + struct snd_sof_control *scontrol; + struct snd_kcontrol *kc; + int i; + + list_for_each_entry(scontrol, &sdev->kcontrol_list, list) { + for (i = 0; i < ARRAY_SIZE(wov_ctl_names); i++) { + if (strcmp(scontrol->name, wov_ctl_names[i])) + continue; + /* force firmware re-read on next .get */ + scontrol->comp_data_dirty = true; + kc = snd_soc_card_get_kcontrol(scontrol->scomp->card, + scontrol->name); + if (kc) + snd_ctl_notify_one(scontrol->scomp->card->snd_card, + SNDRV_CTL_EVENT_MASK_VALUE, + kc, 0); + } + } +} + void sof_ipc4_wov_phrase_detected(struct snd_sof_dev *sdev, struct sof_ipc4_msg *ipc4_msg) { @@ -28,6 +62,9 @@ void sof_ipc4_wov_phrase_detected(struct snd_sof_dev *sdev, dev_dbg(sdev->dev, "WoV: PHRASE_DETECTED word_id=%u sv_score=%u\n", word_id, sv_score); + pm_wakeup_event(sdev->dev, 2000); + sof_ipc4_wov_notify_kcontrols(sdev); + list_for_each_entry(spcm, &sdev->pcm_list, list) { if (spcm->pcm.pcm_id != SOF_WOV_PCM_ID) continue; @@ -39,7 +76,6 @@ void sof_ipc4_wov_phrase_detected(struct snd_sof_dev *sdev, return; } - pm_wakeup_event(sdev->dev, 2000); snd_pcm_period_elapsed(substream); return; }