From 471ec071e8c0b2693219c15827e22c5d1c8dc7ca Mon Sep 17 00:00:00 2001 From: Tomasz Leman Date: Fri, 23 May 2025 11:05:00 +0200 Subject: [PATCH] audio: mic_privacy: Fix feature functionality after D3 resume When resuming from D3 state, the microphone privacy feature wasn't properly restored, causing two critical issues: 1. The system didn't respond to privacy button inputs after D3 transitions 2. A short fade-out effect appeared in audio when privacy was enabled, causing test failures that expected complete silence This patch provides a comprehensive solution by: - Adding mic_privacy_manager_init() to resume_dais() to ensure proper re-initialization of the microphone privacy subsystem after D3 - Implementing mic_privacy_get_mic_disable_status() to correctly retrieve the current microphone disable status - Storing the mic_disable_status before entering D3 and comparing it after resume to detect changes during low power state - Enhancing mic_privacy_enable_dmic_irq() to immediately check for IRQ status after D3 transitions to catch events that occurred during suspended state - Explicitly resetting fade parameters (fade_in_out_bytes, gain parameters) to ensure immediate silence without fade artifacts when privacy is enabled - Adding proper error handling and validation to ensure the mic_priv structure is valid before access With these changes, the microphone privacy feature works correctly through power state transitions and properly mutes audio without fade artifacts when privacy is enabled after D3 resume. Signed-off-by: Tomasz Leman (cherry picked from commit aea81019855fda81692a7c917f95ed29ff82311f) Signed-off-by: Kai Vehmanen --- .../mic_privacy_manager_intel.c | 36 ++++++++++++++++- src/include/sof/audio/mic_privacy_manager.h | 1 + zephyr/lib/cpu.c | 39 +++++++++++++++++++ 3 files changed, 74 insertions(+), 2 deletions(-) diff --git a/src/audio/mic_privacy_manager/mic_privacy_manager_intel.c b/src/audio/mic_privacy_manager/mic_privacy_manager_intel.c index 94f4d6d44216..5120c2ab4b59 100644 --- a/src/audio/mic_privacy_manager/mic_privacy_manager_intel.c +++ b/src/audio/mic_privacy_manager/mic_privacy_manager_intel.c @@ -62,11 +62,29 @@ static void enable_fw_managed_irq(bool enable_irq) void mic_privacy_enable_dmic_irq(bool enable_irq) { + /* Only proceed if we have a valid device and API */ + if (!mic_priv_dev || !mic_privacy_api) { + LOG_ERR("mic_privacy device or API not initialized"); + return; + } + if (mic_privacy_api->get_policy() == MIC_PRIVACY_HW_MANAGED) { - if (enable_irq) + if (enable_irq) { mic_privacy_api->enable_dmic_irq(true, handle_dmic_irq); - else + + /* Check current status immediately to handle any transitions during D3 */ + if (mic_privacy_api->get_dmic_irq_status()) { + struct mic_privacy_settings settings; + uint32_t mic_disable_status = + mic_privacy_api->get_dmic_mic_disable_status(); + + mic_privacy_fill_settings(&settings, mic_disable_status); + mic_privacy_propagate_settings(&settings); + mic_privacy_api->clear_dmic_irq_status(); + } + } else { mic_privacy_api->enable_dmic_irq(false, NULL); + } } } @@ -235,3 +253,17 @@ void mic_privacy_process(struct comp_dev *dev, struct mic_privacy_data *mic_priv break; } } + +uint32_t mic_privacy_get_mic_disable_status(void) +{ + if (!mic_priv_dev) { + LOG_ERR("mic_privacy device not initialized"); + return 0; + } + + mic_privacy_api = (struct mic_privacy_api_funcs *)mic_priv_dev->api; + if (mic_privacy_api->get_policy() == MIC_PRIVACY_FW_MANAGED) + return mic_privacy_api->get_fw_managed_mic_disable_status(); + + return mic_privacy_api->get_dmic_mic_disable_status(); +} diff --git a/src/include/sof/audio/mic_privacy_manager.h b/src/include/sof/audio/mic_privacy_manager.h index 98fd81a85a42..61689343a37e 100644 --- a/src/include/sof/audio/mic_privacy_manager.h +++ b/src/include/sof/audio/mic_privacy_manager.h @@ -51,6 +51,7 @@ uint32_t mic_privacy_get_policy_register(void); void mic_privacy_propagate_settings(struct mic_privacy_settings *settings); uint32_t mic_privacy_get_dma_zeroing_wait_time(void); uint32_t mic_privacy_get_privacy_mask(void); +uint32_t mic_privacy_get_mic_disable_status(void); void mic_privacy_enable_dmic_irq(bool enable_irq); void mic_privacy_fill_settings(struct mic_privacy_settings *settings, uint32_t mic_disable_status); void mic_privacy_set_gtw_mic_state(struct mic_privacy_data *mic_priv_data, diff --git a/zephyr/lib/cpu.c b/zephyr/lib/cpu.c index 79946cc039f1..8141557e8987 100644 --- a/zephyr/lib/cpu.c +++ b/zephyr/lib/cpu.c @@ -11,6 +11,12 @@ */ #include +#if CONFIG_INTEL_ADSP_MIC_PRIVACY +#include +#ifdef CONFIG_ADSP_IMR_CONTEXT_SAVE +static uint32_t mic_disable_status; +#endif /* CONFIG_ADSP_IMR_CONTEXT_SAVE */ +#endif /* CONFIG_INTEL_ADSP_MIC_PRIVACY */ #include #include #include @@ -64,6 +70,7 @@ extern void *global_imr_ram_storage; * data integrity across D3 transitions, which is critical for SOF's operation * and currently outside the scope of Zephyr's device-level PM capabilities. */ + static void suspend_dais(void) { struct ipc_comp_dev *icd; @@ -79,6 +86,10 @@ static void suspend_dais(void) mod = comp_mod(icd->cd); cd = module_get_private_data(mod); +#if CONFIG_INTEL_ADSP_MIC_PRIVACY + if (cd->mic_priv) + mic_disable_status = mic_privacy_get_mic_disable_status(); +#endif dd = cd->dd[0]; if (dai_remove(dd->dai->dev) < 0) { tr_err(&zephyr_tr, "DAI suspend failed, type %d index %d", @@ -95,6 +106,11 @@ static void resume_dais(void) struct copier_data *cd; struct dai_data *dd; +#if CONFIG_INTEL_ADSP_MIC_PRIVACY + /* Re-initialize mic privacy manager first to ensure proper state before DAI resume */ + mic_privacy_manager_init(); +#endif + list_for_item(clist, &ipc_get()->comp_list) { icd = container_of(clist, struct ipc_comp_dev, list); if (icd->type != COMP_TYPE_COMPONENT || dev_comp_type(icd->cd) != SOF_COMP_DAI) @@ -107,6 +123,29 @@ static void resume_dais(void) tr_err(&zephyr_tr, "DAI resume failed, type %d index %d", dd->dai->type, dd->dai->index); } + +#if CONFIG_INTEL_ADSP_MIC_PRIVACY + if (cd->mic_priv) { + uint32_t current_mic_status = mic_privacy_get_mic_disable_status(); + + if (mic_disable_status != current_mic_status) { + tr_dbg(&zephyr_tr, "MIC privacy settings cheange after D3"); + struct mic_privacy_settings settings; + + /* Update privacy settings based on new state */ + mic_privacy_fill_settings(&settings, current_mic_status); + mic_privacy_propagate_settings(&settings); + /* Ensure we're starting from a clean state with no fade effects */ + if (cd->mic_priv->mic_privacy_state) { + /* Force immediate mute without fade effect */ + cd->mic_priv->mic_privacy_state = MIC_PRIV_MUTED; + cd->mic_priv->fade_in_out_bytes = 0; + cd->mic_priv->mic_priv_gain_params.gain_env = 0; + cd->mic_priv->mic_priv_gain_params.fade_in_sg_count = 0; + } + } + } +#endif } } #endif /* CONFIG_ADSP_IMR_CONTEXT_SAVE */