diff --git a/posix/include/sof/lib/dma.h b/posix/include/sof/lib/dma.h index ffae21574916..1ff90693926b 100644 --- a/posix/include/sof/lib/dma.h +++ b/posix/include/sof/lib/dma.h @@ -34,6 +34,7 @@ #endif struct comp_buffer; +struct comp_dev; /** \addtogroup sof_dma_drivers DMA Drivers * DMA Drivers API specification. @@ -550,7 +551,8 @@ int dma_buffer_copy_to(struct comp_buffer __sparse_cache *source, * conversion function. DMA buffer consume should be performed after the data has been copied * to all sinks. */ -int stream_copy_from_no_consume(struct comp_buffer __sparse_cache *source, +int stream_copy_from_no_consume(struct comp_dev *dev, + struct comp_buffer __sparse_cache *source, struct comp_buffer __sparse_cache *sink, dma_process_func process, uint32_t source_bytes, uint32_t chmap); diff --git a/src/audio/CMakeLists.txt b/src/audio/CMakeLists.txt index bd43559aaa80..0ef1083e3ae8 100644 --- a/src/audio/CMakeLists.txt +++ b/src/audio/CMakeLists.txt @@ -103,6 +103,9 @@ if(NOT CONFIG_COMP_MODULE_SHARED_LIBRARY_BUILD) if(CONFIG_COMP_VOLUME) add_subdirectory(volume) endif() + if(CONFIG_INTEL_ADSP_MIC_PRIVACY) + add_subdirectory(mic_privacy_manager) + endif() subdirs(pipeline) add_subdirectory(google) if(CONFIG_COMP_CHAIN_DMA) diff --git a/src/audio/base_fw_intel.c b/src/audio/base_fw_intel.c index 5c38d07960cc..85db72115764 100644 --- a/src/audio/base_fw_intel.c +++ b/src/audio/base_fw_intel.c @@ -28,6 +28,10 @@ #include #include "copier/copier_gain.h" +#if CONFIG_INTEL_ADSP_MIC_PRIVACY +#include +#endif + struct ipc4_modules_info { uint32_t modules_count; struct sof_man_module modules[0]; @@ -100,6 +104,18 @@ int basefw_vendor_hw_config(uint32_t *data_offset, char *data) tlv_value_uint32_set(tuple, IPC4_I2S_CAPS_HW_CFG, I2S_VER_30_PTL); #endif +#if CONFIG_INTEL_ADSP_MIC_PRIVACY + struct privacy_capabilities priv_caps; + + tuple = tlv_next(tuple); + + priv_caps.privacy_version = 1; + priv_caps.capabilities_length = 1; + priv_caps.capabilities[0] = mic_privacy_get_policy_register(); + + tlv_value_set(tuple, IPC4_INTEL_MIC_PRIVACY_CAPS_HW_CFG, sizeof(priv_caps), &priv_caps); +#endif + tuple = tlv_next(tuple); *data_offset = (int)((char *)tuple - data); @@ -335,6 +351,38 @@ static int basefw_set_fw_config(bool first_block, return 0; } +static int basefw_set_mic_priv_policy(bool first_block, + bool last_block, + uint32_t data_offset_or_size, + const char *data) +{ +#if CONFIG_INTEL_ADSP_MIC_PRIVACY + return 0; +#else + return IPC4_UNAVAILABLE; +#endif +} + +static int basefw_mic_priv_state_changed(bool first_block, + bool last_block, + uint32_t data_offset_or_size, + const char *data) +{ +#if CONFIG_INTEL_ADSP_MIC_PRIVACY + tr_info(&basefw_comp_tr, "state changed to %d", *data); + + uint32_t mic_disable_status = (uint32_t)(*data); + struct mic_privacy_settings settings; + + mic_privacy_fill_settings(&settings, mic_disable_status); + mic_privacy_propagate_settings(&settings); + + return 0; +#else + return IPC4_UNAVAILABLE; +#endif +} + int basefw_vendor_set_large_config(struct comp_dev *dev, uint32_t param_id, bool first_block, @@ -345,6 +393,10 @@ int basefw_vendor_set_large_config(struct comp_dev *dev, switch (param_id) { case IPC4_FW_CONFIG: return basefw_set_fw_config(first_block, last_block, data_offset, data); + case IPC4_SET_MIC_PRIVACY_FW_MANAGED_POLICY_MASK: + return basefw_set_mic_priv_policy(first_block, last_block, data_offset, data); + case IPC4_MIC_PRIVACY_HW_MANAGED_STATE_CHANGE: + return basefw_mic_priv_state_changed(first_block, last_block, data_offset, data); default: break; } diff --git a/src/audio/copier/copier.c b/src/audio/copier/copier.c index 0fe324cb78f3..560e3bce52a2 100644 --- a/src/audio/copier/copier.c +++ b/src/audio/copier/copier.c @@ -39,6 +39,9 @@ #include "host_copier.h" #include "dai_copier.h" #include "ipcgtw_copier.h" +#if CONFIG_INTEL_ADSP_MIC_PRIVACY +#include +#endif #if CONFIG_ZEPHYR_NATIVE_DRIVERS #include @@ -51,6 +54,79 @@ SOF_DEFINE_REG_UUID(copier); DECLARE_TR_CTX(copier_comp_tr, SOF_UUID(copier_uuid), LOG_LEVEL_INFO); +#if CONFIG_INTEL_ADSP_MIC_PRIVACY +static void mic_privacy_event(void *arg, enum notify_id type, void *data) +{ + struct mic_privacy_data *mic_priv_data = arg; + struct mic_privacy_settings *mic_privacy_settings = data; + + if (type == NOTIFIER_ID_MIC_PRIVACY_STATE_CHANGE) { + LOG_INF("mic_privacy_event, state1 = %d, state2 = %d ", + mic_privacy_settings->mic_privacy_state, mic_priv_data->mic_privacy_state); + + if (mic_privacy_settings->mic_privacy_state == MIC_PRIV_UNMUTED) { + if (mic_priv_data->mic_privacy_state == MIC_PRIV_MUTED) { + mic_priv_data->mic_privacy_state = MIC_PRIV_FADE_IN; + LOG_INF("mic_privacy_event switch to FADE_IN"); + } + } else { + /* In case when mute would be triggered before copier instantiation. */ + if (mic_priv_data->mic_privacy_state != MIC_PRIV_MUTED) { + mic_priv_data->mic_privacy_state = MIC_PRIV_FADE_OUT; + LOG_INF("mic_privacy_event switch to FADE_OUT"); + } + } + mic_priv_data->max_ramp_time_in_ms = (mic_privacy_settings->max_ramp_time * 1000) / + ADSP_RTC_FREQUENCY; + } +} + +static int mic_privacy_configure(struct comp_dev *dev, struct copier_data *cd) +{ + struct mic_privacy_data *mic_priv_data; + int ret; + + mic_priv_data = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, + sizeof(struct mic_privacy_data)); + if (!mic_priv_data) + return -ENOMEM; + + if (cd->gtw_type == ipc4_gtw_dmic) + mic_privacy_enable_dmic_irq(true); + + mic_priv_data->audio_freq = cd->config.base.audio_fmt.sampling_frequency; + + uint32_t zeroing_wait_time = (mic_privacy_get_dma_zeroing_wait_time() * 1000) / + ADSP_RTC_FREQUENCY; + + ret = copier_gain_set_params(dev, &mic_priv_data->mic_priv_gain_params, + zeroing_wait_time, SOF_DAI_INTEL_NONE); + if (ret != 0) { + rfree(mic_priv_data); + return ret; + } + + cd->mic_priv = mic_priv_data; + + ret = notifier_register(cd->mic_priv, NULL, NOTIFIER_ID_MIC_PRIVACY_STATE_CHANGE, + mic_privacy_event, 0); + if (ret != 0) + rfree(mic_priv_data); + + return ret; +} + +static void mic_privacy_free(struct copier_data *cd) +{ + if (cd->gtw_type == ipc4_gtw_dmic) + mic_privacy_enable_dmic_irq(false); + + notifier_unregister(cd->mic_priv, NULL, NOTIFIER_ID_MIC_PRIVACY_STATE_CHANGE); + + rfree(cd->mic_priv); +} +#endif + static int copier_init(struct processing_module *mod) { union ipc4_connector_node_id node_id; @@ -131,6 +207,16 @@ static int copier_init(struct processing_module *mod) comp_err(dev, "unable to create host"); goto error; } +#if CONFIG_INTEL_ADSP_MIC_PRIVACY + if (cd->direction == SOF_IPC_STREAM_CAPTURE && + node_id.f.dma_type == ipc4_hda_host_output_class) { + ret = mic_privacy_configure(dev, cd); + if (ret < 0) { + comp_err(dev, "unable to configure mic privacy"); + goto error; + } + } +#endif break; case ipc4_hda_link_output_class: case ipc4_hda_link_input_class: @@ -144,6 +230,15 @@ static int copier_init(struct processing_module *mod) comp_err(dev, "unable to create dai"); goto error; } +#if CONFIG_INTEL_ADSP_MIC_PRIVACY + if (cd->direction == SOF_IPC_STREAM_CAPTURE) { + ret = mic_privacy_configure(dev, cd); + if (ret < 0) { + comp_err(dev, "unable to configure mic privacy"); + goto error; + } + } +#endif break; #if CONFIG_IPC4_GATEWAY case ipc4_ipc_output_class: @@ -184,6 +279,10 @@ static int copier_free(struct processing_module *mod) struct copier_data *cd = module_get_private_data(mod); struct comp_dev *dev = mod->dev; +#if CONFIG_INTEL_ADSP_MIC_PRIVACY + mic_privacy_free(cd); +#endif + switch (dev->ipc_config.type) { case SOF_COMP_HOST: if (!cd->ipc_gtw) diff --git a/src/audio/copier/copier.h b/src/audio/copier/copier.h index 43c125134f07..4a6091d99dca 100644 --- a/src/audio/copier/copier.h +++ b/src/audio/copier/copier.h @@ -32,6 +32,10 @@ #include #include #include +#if CONFIG_INTEL_ADSP_MIC_PRIVACY +#include +#include +#endif static const uint32_t INVALID_QUEUE_ID = 0xFFFFFFFF; @@ -270,6 +274,9 @@ struct copier_data { uint32_t channels[IPC4_ALH_MAX_NUMBER_OF_GTW]; uint32_t chan_map[IPC4_ALH_MAX_NUMBER_OF_GTW]; struct ipcgtw_data *ipcgtw_data; +#if CONFIG_INTEL_ADSP_MIC_PRIVACY + struct mic_privacy_data *mic_priv; +#endif }; int apply_attenuation(struct comp_dev *dev, struct copier_data *cd, diff --git a/src/audio/copier/copier_dai.c b/src/audio/copier/copier_dai.c index 587a133ebd75..56cf02f112b0 100644 --- a/src/audio/copier/copier_dai.c +++ b/src/audio/copier/copier_dai.c @@ -229,7 +229,9 @@ static int copier_dai_init(struct comp_dev *dev, } cd->dd[index]->gain_data = gain_data; - ret = copier_gain_set_params(dev, cd->dd[index]); + ret = copier_gain_set_params(dev, cd->dd[index]->gain_data, + GAIN_DEFAULT_FADE_PERIOD, + cd->dd[index]->dai->type); if (ret < 0) { comp_err(dev, "Failed to set gain params!"); goto gain_free; diff --git a/src/audio/copier/copier_gain.c b/src/audio/copier/copier_gain.c index f7e2f24fdb8d..b48ccca0ab7f 100644 --- a/src/audio/copier/copier_gain.c +++ b/src/audio/copier/copier_gain.c @@ -15,20 +15,22 @@ LOG_MODULE_DECLARE(copier, CONFIG_SOF_LOG_LEVEL); -int copier_gain_set_params(struct comp_dev *dev, struct dai_data *dd) +int copier_gain_set_params(struct comp_dev *dev, + struct copier_gain_params *gain_params, + uint32_t fade_period, + enum sof_ipc_dai_type dai_type) { struct processing_module *mod = comp_mod(dev); struct copier_data *cd = module_get_private_data(mod); struct ipc4_base_module_cfg *ipc4_cfg = &cd->config.base; uint32_t sampling_freq = ipc4_cfg->audio_fmt.sampling_frequency; uint32_t frames = sampling_freq / dev->pipeline->period; - uint32_t fade_period = GAIN_DEFAULT_FADE_PERIOD; int ret; /* Set basic gain parameters */ - copier_gain_set_basic_params(dev, dd, ipc4_cfg); + copier_gain_set_basic_params(dev, gain_params, ipc4_cfg); - switch (dd->dai->type) { + switch (dai_type) { case SOF_DAI_INTEL_DMIC: { struct dmic_config_data *dmic_cfg = cd->gtw_cfg; @@ -43,18 +45,18 @@ int copier_gain_set_params(struct comp_dev *dev, struct dai_data *dd) /* Get fade period from DMIC blob */ fade_period = dmic_glb_cfg->ext_global_cfg.fade_in_period; /* Convert and assign silence and fade length values */ - dd->gain_data->silence_sg_length = + gain_params->silence_sg_length = frames * dmic_glb_cfg->ext_global_cfg.silence_period; - dd->gain_data->fade_sg_length = frames * fade_period; + gain_params->fade_sg_length = frames * fade_period; } break; default: - comp_info(dev, "Apply default fade period for dai type %d", dd->dai->type); + comp_info(dev, "Apply default fade period for dai type %d", dai_type); break; } /* Set fade parameters */ - ret = copier_gain_set_fade_params(dev, dd, ipc4_cfg, fade_period, frames); + ret = copier_gain_set_fade_params(dev, gain_params, ipc4_cfg, fade_period, frames); if (ret) comp_err(dev, "Failed to set fade params"); @@ -150,7 +152,10 @@ int copier_gain_dma_control(union ipc4_connector_node_id node, const char *confi break; } - ret = copier_set_gain(dev, cd->dd[0], gain_data); + struct ipc4_copier_module_cfg *copier_cfg = cd->dd[0]->dai_spec_config; + const int channels = copier_cfg->base.audio_fmt.channels_count; + + ret = copier_set_gain(dev, cd->dd[0]->gain_data, gain_data, channels); if (ret) comp_err(dev, "Gain DMA control: failed to set gain"); return ret; @@ -159,12 +164,9 @@ int copier_gain_dma_control(union ipc4_connector_node_id node, const char *confi return -ENODEV; } -int copier_set_gain(struct comp_dev *dev, struct dai_data *dd, - struct gain_dma_control_data *gain_data) +int copier_set_gain(struct comp_dev *dev, struct copier_gain_params *gain_params, + struct gain_dma_control_data *gain_data, int channels) { - struct copier_gain_params *gain_params = dd->gain_data; - struct ipc4_copier_module_cfg *copier_cfg = dd->dai_spec_config; - const int channels = copier_cfg->base.audio_fmt.channels_count; uint16_t static_gain[MAX_GAIN_COEFFS_CNT]; int ret; diff --git a/src/audio/copier/copier_gain.h b/src/audio/copier/copier_gain.h index 077a47f468c3..ec55ff999206 100644 --- a/src/audio/copier/copier_gain.h +++ b/src/audio/copier/copier_gain.h @@ -10,6 +10,7 @@ #include #include +#include #include #if SOF_USE_HIFI(3, COPIER) || SOF_USE_HIFI(4, COPIER) || SOF_USE_HIFI(5, COPIER) #include @@ -117,10 +118,13 @@ struct gain_dma_control_data { * the given device and DAI data. * * @param dev The pointer to the component device structure. - * @param dd The pointer to the DAI data structure. + * @param gain_params The pointer to gain params structure. + * @param fade_period The fade period in milliseconds. + * @param dai_type DAI type * @return 0 on success, negative error code on failure. */ -int copier_gain_set_params(struct comp_dev *dev, struct dai_data *dd); +int copier_gain_set_params(struct comp_dev *dev, struct copier_gain_params *gain_params, + uint32_t fade_period, enum sof_ipc_dai_type dai_type); /** * @brief Sets the basic gain parameters. @@ -129,10 +133,10 @@ int copier_gain_set_params(struct comp_dev *dev, struct dai_data *dd); * by the given device and DAI data. * * @param dev The pointer to the component device structure. - * @param dd The pointer to the DAI data structure. + * @param gain_params The pointer to gain params structure. * @param ipc4_cfg The pointer to the IPC4 base module config. */ -void copier_gain_set_basic_params(struct comp_dev *dev, struct dai_data *dd, +void copier_gain_set_basic_params(struct comp_dev *dev, struct copier_gain_params *gain_params, struct ipc4_base_module_cfg *ipc4_cfg); /** @@ -142,13 +146,13 @@ void copier_gain_set_basic_params(struct comp_dev *dev, struct dai_data *dd, * by the given device and DAI data. * * @param dev The pointer to the component device structure. - * @param dd The pointer to the DAI data structure. + * @param gain_params The pointer to gain params structure. * @param ipc4_cfg The pointer to the IPC4 base module config. * @param fade_period The fade period in milliseconds. * @param frames The number of frames to fade. * @return 0 on success, negative error code on failure. */ -int copier_gain_set_fade_params(struct comp_dev *dev, struct dai_data *dd, +int copier_gain_set_fade_params(struct comp_dev *dev, struct copier_gain_params *gain_params, struct ipc4_base_module_cfg *ipc4_cfg, uint32_t fade_period, uint32_t frames); @@ -209,12 +213,13 @@ enum copier_gain_state copier_gain_eval_state(struct copier_gain_params *gain_pa * Sets/modify gain for a copier module in runtime. * * @param dev The copier device structure. - * @param dd The DAI data structure. + * @param gain_params The pointer to the copier_gain_params structure. * @param gain_data The gain control data structure. + * @param channels Number of audio channels. * @return 0 on success, otherwise a negative error code. */ -int copier_set_gain(struct comp_dev *dev, struct dai_data *dd, - struct gain_dma_control_data *gain_data); +int copier_set_gain(struct comp_dev *dev, struct copier_gain_params *gain_params, + struct gain_dma_control_data *gain_data, int channels); /** * Checks for unity gain mode. diff --git a/src/audio/copier/copier_generic.c b/src/audio/copier/copier_generic.c index a4fc8ca6c9a1..bd0698cf3504 100644 --- a/src/audio/copier/copier_generic.c +++ b/src/audio/copier/copier_generic.c @@ -60,10 +60,9 @@ int apply_attenuation(struct comp_dev *dev, struct copier_data *cd, } } -void copier_gain_set_basic_params(struct comp_dev *dev, struct dai_data *dd, +void copier_gain_set_basic_params(struct comp_dev *dev, struct copier_gain_params *gain_params, struct ipc4_base_module_cfg *ipc4_cfg) { - struct copier_gain_params *gain_params = dd->gain_data; gain_params->channels_count = ipc4_cfg->audio_fmt.channels_count; @@ -71,11 +70,10 @@ void copier_gain_set_basic_params(struct comp_dev *dev, struct dai_data *dd, gain_params->gain_coeffs[i] = UNITY_GAIN_GENERIC; } -int copier_gain_set_fade_params(struct comp_dev *dev, struct dai_data *dd, +int copier_gain_set_fade_params(struct comp_dev *dev, struct copier_gain_params *gain_params, struct ipc4_base_module_cfg *ipc4_cfg, uint32_t fade_period, uint32_t frames) { - struct copier_gain_params *gain_params = dd->gain_data; uint16_t step_i64_to_i16; if (fade_period == GAIN_DEFAULT_FADE_PERIOD) { @@ -88,6 +86,8 @@ int copier_gain_set_fade_params(struct comp_dev *dev, struct dai_data *dd, /* Special case for GAIN_ZERO_TRANS_MS to support zero fade-in transition time */ gain_params->fade_sg_length = 0; return 0; + } else { + gain_params->fade_sg_length = frames * fade_period; } /* High precision step for fade-in calculation, keeps accurate precision */ diff --git a/src/audio/copier/copier_hifi.c b/src/audio/copier/copier_hifi.c index 0d0d454f2c41..7a2b2def8ed8 100644 --- a/src/audio/copier/copier_hifi.c +++ b/src/audio/copier/copier_hifi.c @@ -75,10 +75,9 @@ int apply_attenuation(struct comp_dev *dev, struct copier_data *cd, } } -void copier_gain_set_basic_params(struct comp_dev *dev, struct dai_data *dd, +void copier_gain_set_basic_params(struct comp_dev *dev, struct copier_gain_params *gain_params, struct ipc4_base_module_cfg *ipc4_cfg) { - struct copier_gain_params *gain_params = dd->gain_data; /* Set default gain coefficients */ for (int i = 0; i < ARRAY_SIZE(gain_params->gain_coeffs); ++i) @@ -91,11 +90,10 @@ void copier_gain_set_basic_params(struct comp_dev *dev, struct dai_data *dd, gain_params->channels_count = ipc4_cfg->audio_fmt.channels_count; } -int copier_gain_set_fade_params(struct comp_dev *dev, struct dai_data *dd, +int copier_gain_set_fade_params(struct comp_dev *dev, struct copier_gain_params *gain_params, struct ipc4_base_module_cfg *ipc4_cfg, uint32_t fade_period, uint32_t frames) { - struct copier_gain_params *gain_params = dd->gain_data; uint16_t init_gain[MAX_GAIN_COEFFS_CNT]; uint16_t step_i64_to_i16; ae_f16 step_f16; @@ -113,6 +111,8 @@ int copier_gain_set_fade_params(struct comp_dev *dev, struct dai_data *dd, /* Special case for GAIN_ZERO_TRANS_MS to support zero fade in transition time */ gain_params->fade_sg_length = 0; return 0; + } else { + gain_params->fade_sg_length = frames * fade_period; } /* High precision step for fade-in calculation, keeps accurate precision */ diff --git a/src/audio/copier/copier_host.c b/src/audio/copier/copier_host.c index b61af44bfe0e..53b6a2aed0d5 100644 --- a/src/audio/copier/copier_host.c +++ b/src/audio/copier/copier_host.c @@ -271,6 +271,10 @@ void copier_host_dma_cb(struct comp_dev *dev, size_t bytes) buffer_stream_writeback(cd->hd->local_buffer, bytes); } +#if CONFIG_INTEL_ADSP_MIC_PRIVACY + if (cd->mic_priv) + mic_privacy_process(dev, cd->mic_priv, cd->hd->local_buffer, bytes); +#endif } static void copier_notifier_cb(void *arg, enum notify_id type, void *data) diff --git a/src/audio/dai-zephyr.c b/src/audio/dai-zephyr.c index 5ca6db25ab10..37cf6131cb90 100644 --- a/src/audio/dai-zephyr.c +++ b/src/audio/dai-zephyr.c @@ -309,7 +309,7 @@ dai_dma_cb(struct dai_data *dd, struct comp_dev *dev, uint32_t bytes, if (sink_dev && sink_dev->state == COMP_STATE_ACTIVE && audio_buffer_hw_params_configured(&sink->audio_buffer)) { - ret = stream_copy_from_no_consume(dd->local_buffer, sink, + ret = stream_copy_from_no_consume(dev, dd->local_buffer, sink, converter[j], bytes, dd->chmap); } } @@ -322,7 +322,8 @@ dai_dma_cb(struct dai_data *dd, struct comp_dev *dev, uint32_t bytes, * The PCM converter functions used during DMA buffer copy can never fail, * so no need to check the return value of stream_copy_from_no_consume(). */ - ret = stream_copy_from_no_consume(dd->dma_buffer, dd->local_buffer, + + ret = stream_copy_from_no_consume(dev, dd->dma_buffer, dd->local_buffer, dd->process, bytes, dd->chmap); #if CONFIG_IPC_MAJOR_4 /* Apply gain to the local buffer */ @@ -369,7 +370,7 @@ dai_dma_cb(struct dai_data *dd, struct comp_dev *dev, uint32_t bytes, if (sink_dev && sink_dev->state == COMP_STATE_ACTIVE && audio_buffer_hw_params_configured(&sink->audio_buffer)) - ret = stream_copy_from_no_consume(dd->dma_buffer, + ret = stream_copy_from_no_consume(dev, dd->dma_buffer, sink, converter[j], bytes, dd->chmap); } diff --git a/src/audio/mic_privacy_manager/CMakeLists.txt b/src/audio/mic_privacy_manager/CMakeLists.txt new file mode 100644 index 000000000000..b4ae270f7669 --- /dev/null +++ b/src/audio/mic_privacy_manager/CMakeLists.txt @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: BSD-3-Clause + +add_local_sources(sof mic_privacy_manager_intel.c) diff --git a/src/audio/mic_privacy_manager/mic_privacy_manager_intel.c b/src/audio/mic_privacy_manager/mic_privacy_manager_intel.c new file mode 100644 index 000000000000..94f4d6d44216 --- /dev/null +++ b/src/audio/mic_privacy_manager/mic_privacy_manager_intel.c @@ -0,0 +1,237 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. All rights reserved. + +#include "sof/audio/mic_privacy_manager.h" + +#include +#include +#include +#include +#include +#include + +const struct device *mic_priv_dev; + +static struct mic_privacy_api_funcs *mic_privacy_api; +static enum mic_privacy_policy mic_privacy_policy; + +#define LOG_DOMAIN mic_priv + +LOG_MODULE_REGISTER(LOG_DOMAIN); + +void handle_dmic_irq(void const *self, int a, int b) +{ + LOG_DBG("mic_privacy DMIC IRQ"); + + if (mic_privacy_api->get_dmic_irq_status()) { + uint32_t mic_disable_status = mic_privacy_api->get_dmic_mic_disable_status(); + struct mic_privacy_settings settings; + + mic_privacy_fill_settings(&settings, mic_disable_status); + mic_privacy_propagate_settings(&settings); + mic_privacy_api->clear_dmic_irq_status(); + } +} + +void handle_fw_managed_irq(void const *dev) +{ + LOG_DBG("mic_privacy FW Managed IRQ"); + + uint32_t mic_disable_status = mic_privacy_api->get_fw_managed_mic_disable_status(); + struct mic_privacy_settings settings; + + mic_privacy_fill_settings(&settings, mic_disable_status); + mic_privacy_propagate_settings(&settings); + + if (mic_disable_status) + mic_privacy_api->set_fw_mic_disable_status(true); + else + mic_privacy_api->set_fw_mic_disable_status(false); + + mic_privacy_api->clear_fw_managed_irq(); +} + +static void enable_fw_managed_irq(bool enable_irq) +{ + if (enable_irq) + mic_privacy_api->enable_fw_managed_irq(true, handle_fw_managed_irq); + else + mic_privacy_api->enable_fw_managed_irq(false, NULL); +} + +void mic_privacy_enable_dmic_irq(bool enable_irq) +{ + if (mic_privacy_api->get_policy() == MIC_PRIVACY_HW_MANAGED) { + if (enable_irq) + mic_privacy_api->enable_dmic_irq(true, handle_dmic_irq); + else + mic_privacy_api->enable_dmic_irq(false, NULL); + } +} + +int mic_privacy_manager_init(void) +{ + mic_priv_dev = DEVICE_DT_GET(DT_NODELABEL(mic_privacy)); + + if (!mic_priv_dev) + return -EINVAL; + + mic_privacy_api = (struct mic_privacy_api_funcs *)mic_priv_dev->api; + mic_privacy_policy = mic_privacy_api->get_policy(); + + if (mic_privacy_policy == MIC_PRIVACY_FW_MANAGED) { + LOG_INF("mic_privacy init FW_MANAGED mode"); + mic_privacy_api->set_fw_managed_mode(true); + enable_fw_managed_irq(true); + } + + return 0; +} + +int mic_privacy_manager_get_policy(void) +{ + mic_privacy_api = (struct mic_privacy_api_funcs *)mic_priv_dev->api; + + return mic_privacy_api->get_policy(); +} + +uint32_t mic_privacy_get_policy_register(void) +{ + if (!mic_priv_dev) + return 0; + mic_privacy_api = (struct mic_privacy_api_funcs *)mic_priv_dev->api; + + return mic_privacy_api->get_privacy_policy_register_raw_value(); +} + +void mic_privacy_propagate_settings(struct mic_privacy_settings *settings) +{ + notifier_event(mic_priv_dev, NOTIFIER_ID_MIC_PRIVACY_STATE_CHANGE, + NOTIFIER_TARGET_CORE_ALL_MASK, settings, + sizeof(struct mic_privacy_settings)); +} + +uint32_t mic_privacy_get_dma_zeroing_wait_time(void) +{ + return (uint32_t)mic_privacy_api->get_dma_data_zeroing_wait_time(); +} + +uint32_t mic_privacy_get_privacy_mask(void) +{ + if (mic_privacy_policy == MIC_PRIVACY_HW_MANAGED) + return mic_privacy_api->get_dma_data_zeroing_link_select(); + + /* hardcoded for FW_MANAGED */ + return 0xFFFFFFFF; +} + +void mic_privacy_fill_settings(struct mic_privacy_settings *settings, uint32_t mic_disable_status) +{ + if (!settings) { + LOG_ERR("Invalid mic_privacy_settings pointer"); + return; + } + + settings->mic_privacy_mode = mic_privacy_policy; + settings->mic_privacy_state = mic_disable_status; + settings->privacy_mask_bits.value = mic_privacy_get_privacy_mask(); + settings->max_ramp_time = mic_privacy_get_dma_zeroing_wait_time(); + + LOG_DBG("mic_privacy_mode = %d, mic_disable_status = %d, \ + privacy_mask = %x, max_ramp_time_in_ms = %d", + settings->mic_privacy_mode, + settings->mic_privacy_state, + settings->privacy_mask_bits.value, + settings->max_ramp_time); +} + +void mic_privacy_set_gtw_mic_state(struct mic_privacy_data *mic_priv_data, + uint32_t mic_disable_status) +{ + if (mic_privacy_policy == MIC_PRIVACY_HW_MANAGED) { + if (mic_disable_status != 0) + mic_priv_data->mic_privacy_state = MIC_PRIV_MUTED; + else + mic_priv_data->mic_privacy_state = MIC_PRIV_UNMUTED; + } else if (mic_privacy_policy == MIC_PRIVACY_FW_MANAGED) { + if (mic_disable_status != 0) { + LOG_DBG("MUTED"); + mic_priv_data->mic_privacy_state = MIC_PRIV_MUTED; + mic_priv_data->dma_data_zeroing = true; + mic_privacy_api->set_fw_mic_disable_status(true); + } else { + LOG_DBG("UNMUTED"); + mic_priv_data->mic_privacy_state = MIC_PRIV_UNMUTED; + mic_priv_data->dma_data_zeroing = false; + mic_privacy_api->set_fw_mic_disable_status(false); + } + } +} + +void mic_privacy_update_gtw_mic_state(struct mic_privacy_data *mic_priv_data, + uint32_t hw_mic_disable_status) +{ + switch (mic_privacy_policy) { + case MIC_PRIVACY_HW_MANAGED: + mic_privacy_set_gtw_mic_state(mic_priv_data, hw_mic_disable_status); + break; + case MIC_PRIVACY_FW_MANAGED: + mic_privacy_set_gtw_mic_state(mic_priv_data, + mic_privacy_api->get_fw_managed_mic_disable_status()); + break; + default: + break; + } +} + +void mic_privacy_process(struct comp_dev *dev, struct mic_privacy_data *mic_priv, + struct comp_buffer *buffer, uint32_t copy_samples) +{ + uint32_t sg_size_in_bytes; + + sg_size_in_bytes = audio_stream_frame_bytes(&buffer->stream); + uint32_t one_ms_in_bytes = sg_size_in_bytes * (buffer->stream.runtime_stream_params.rate / 1000); + uint32_t copy_bytes = copy_samples * audio_stream_sample_bytes(&buffer->stream); + + switch (mic_priv->mic_privacy_state) { + case MIC_PRIV_UNMUTED: + break; + case MIC_PRIV_MUTED: + buffer_zero(buffer); + break; + case MIC_PRIV_FADE_IN: + if (mic_priv->fade_in_out_bytes == 0) { + /* start addition */ + mic_priv->mic_priv_gain_params.fade_in_sg_count = 0; + mic_priv->mic_priv_gain_params.gain_env = 0; + } + mic_priv->fade_in_out_bytes += copy_bytes; + if (mic_priv->fade_in_out_bytes > one_ms_in_bytes * mic_priv->max_ramp_time_in_ms) { + mic_priv->mic_privacy_state = MIC_PRIV_UNMUTED; + mic_priv->fade_in_out_bytes = 0; + } + + if (mic_priv->max_ramp_time_in_ms > 0) + copier_gain_input(dev, buffer, &mic_priv->mic_priv_gain_params, GAIN_ADD, copy_bytes); + break; + case MIC_PRIV_FADE_OUT: + if (mic_priv->fade_in_out_bytes == 0) { + /* start subtraction */ + mic_priv->mic_priv_gain_params.fade_in_sg_count = 0; + mic_priv->mic_priv_gain_params.gain_env = INT64_MAX; + } + mic_priv->fade_in_out_bytes += copy_bytes; + if (mic_priv->fade_in_out_bytes > one_ms_in_bytes * mic_priv->max_ramp_time_in_ms) { + mic_priv->mic_privacy_state = MIC_PRIV_MUTED; + mic_priv->fade_in_out_bytes = 0; + buffer_zero(buffer); + } + if (mic_priv->max_ramp_time_in_ms > 0) + copier_gain_input(dev, buffer, &mic_priv->mic_priv_gain_params, GAIN_SUBTRACT, copy_bytes); + break; + default: + LOG_ERR("invalid state %x", mic_priv->mic_privacy_state); + break; + } +} diff --git a/src/include/ipc4/base_fw.h b/src/include/ipc4/base_fw.h index ab98fad44160..25601b1209f0 100644 --- a/src/include/ipc4/base_fw.h +++ b/src/include/ipc4/base_fw.h @@ -288,6 +288,12 @@ enum ipc4_basefw_params { /* Use LARGE_CONFIG_SET to change SDW ownership */ IPC4_SDW_OWNERSHIP = 31, + + /* This command is used by SW to notify FW for changing state of Mic Privacy */ + IPC4_MIC_PRIVACY_HW_MANAGED_STATE_CHANGE = 35, + + /* Set policy mask for mic privacy in FW managed mode */ + IPC4_SET_MIC_PRIVACY_FW_MANAGED_POLICY_MASK = 36, }; enum ipc4_fw_config_params { @@ -399,7 +405,9 @@ enum ipc4_hw_config_params { /* Size of a single memory bank (EBB) in bytes */ IPC4_EBB_SIZE_BYTES_HW_CFG = 9, /* UAOL capabilities */ - IPC4_UAOL_CAPS_HW_CFG = 10 + IPC4_UAOL_CAPS_HW_CFG = 10, + /* Mic privacy capabilities */ + IPC4_INTEL_MIC_PRIVACY_CAPS_HW_CFG = 11 }; enum ipc4_memory_type { diff --git a/src/include/sof/audio/mic_privacy_manager.h b/src/include/sof/audio/mic_privacy_manager.h new file mode 100644 index 000000000000..98fd81a85a42 --- /dev/null +++ b/src/include/sof/audio/mic_privacy_manager.h @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2025 Intel Corporation. All rights reserved. + * + */ + +#ifndef ADSP_FW_MIC_PRIVACY_MANAGER_H +#define ADSP_FW_MIC_PRIVACY_MANAGER_H + +#include +#include +#include +#include "../audio/copier/copier_gain.h" + +#define ADSP_RTC_FREQUENCY 32768 + +struct mic_privacy_data { + enum ipc4_sampling_frequency audio_freq; + uint32_t mic_privacy_state; + bool dma_data_zeroing; + uint32_t fade_in_out_bytes; + uint32_t max_ramp_time_in_ms; + + struct copier_gain_params mic_priv_gain_params; +}; + +struct mic_privacy_settings { + enum mic_privacy_policy mic_privacy_mode; + /* 0-Mic Unmute, 1-Mic Mute */ + uint32_t mic_privacy_state; + uint32_t max_ramp_time; + union mic_privacy_mask privacy_mask_bits; +}; + +struct privacy_capabilities { + uint32_t privacy_version; + uint32_t capabilities_length; + uint32_t capabilities[1]; +}; + +enum mic_privacy_state { + MIC_PRIV_UNMUTED, + MIC_PRIV_FADE_IN, + MIC_PRIV_FADE_OUT, + MIC_PRIV_MUTED, +}; + +int mic_privacy_manager_init(void); +int mic_privacy_manager_get_policy(void); +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); +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, + uint32_t mic_disable_status); +void mic_privacy_update_gtw_mic_state(struct mic_privacy_data *mic_priv_data, + uint32_t hw_mic_disable_status); +void mic_privacy_process(struct comp_dev *dev, struct mic_privacy_data *mic_priv, + struct comp_buffer *buffer, uint32_t copy_samples); +void mic_privacy_gain_input(uint8_t *buff, uint32_t buff_size, uint32_t mic_priv_state, + const struct ipc4_audio_format *in_fmt); + +#endif /* ADSP_FW_MIC_PRIVACY_MANAGER_H */ diff --git a/src/include/sof/lib/notifier.h b/src/include/sof/lib/notifier.h index abf893281f70..060906655cb8 100644 --- a/src/include/sof/lib/notifier.h +++ b/src/include/sof/lib/notifier.h @@ -34,6 +34,7 @@ enum notify_id { NOTIFIER_ID_LL_POST_RUN, /* NULL */ NOTIFIER_ID_DMA_IRQ, /* struct dma_chan_data * */ NOTIFIER_ID_DAI_TRIGGER, /* struct dai_group * */ + NOTIFIER_ID_MIC_PRIVACY_STATE_CHANGE, /* struct mic_privacy_settings * */ NOTIFIER_ID_COUNT }; diff --git a/src/lib/dma.c b/src/lib/dma.c index 552c487cb296..afd7dac001ca 100644 --- a/src/lib/dma.c +++ b/src/lib/dma.c @@ -7,6 +7,10 @@ #include #include #include +#include +#if CONFIG_INTEL_ADSP_MIC_PRIVACY +#include +#endif #include #include #include @@ -20,6 +24,8 @@ #include #include #include +#include +#include "../audio/copier/copier.h" LOG_MODULE_REGISTER(dma, CONFIG_SOF_LOG_LEVEL); @@ -453,7 +459,8 @@ int dma_buffer_copy_to(struct comp_buffer *source, return ret; } -int stream_copy_from_no_consume(struct comp_buffer *source, struct comp_buffer *sink, +int stream_copy_from_no_consume(struct comp_dev *dev, struct comp_buffer *source, + struct comp_buffer *sink, dma_process_func process, uint32_t source_bytes, uint32_t chmap) { int source_channels = audio_stream_get_channels(&source->stream); @@ -501,6 +508,14 @@ int stream_copy_from_no_consume(struct comp_buffer *source, struct comp_buffer * /* process data */ ret = process(istream, 0, &sink->stream, 0, source_samples, chmap); +#if CONFIG_INTEL_ADSP_MIC_PRIVACY + struct processing_module *mod = comp_mod(dev); + struct copier_data *cd = module_get_private_data(mod); + + if (cd->mic_priv) + mic_privacy_process(dev, cd->mic_priv, sink, source_samples); +#endif + buffer_stream_writeback(sink, sink_bytes); comp_update_buffer_produce(sink, sink_bytes); diff --git a/src/platform/intel/ace/platform.c b/src/platform/intel/ace/platform.c index 9e88861d9a97..4af68f92af15 100644 --- a/src/platform/intel/ace/platform.c +++ b/src/platform/intel/ace/platform.c @@ -26,7 +26,9 @@ #include #include #include - +#if CONFIG_INTEL_ADSP_MIC_PRIVACY +#include "sof/audio/mic_privacy_manager.h" +#endif #include #include @@ -137,6 +139,13 @@ int platform_init(struct sof *sof) watchdog_init(); +#if CONFIG_INTEL_ADSP_MIC_PRIVACY + /* Init mic privacy manager */ + ret = mic_privacy_manager_init(); + if (ret < 0) + return ret; +#endif + /* show heap status */ heap_trace_all(1); diff --git a/west.yml b/west.yml index 7be1028f0985..9f60c7ca15f4 100644 --- a/west.yml +++ b/west.yml @@ -10,7 +10,7 @@ manifest: - name: thesofproject url-base: https://github.com/thesofproject - name: zephyrproject - url-base: https://github.com/zephyrproject-rtos + url-base: https://github.com/abonislawski # When upgrading projects here please run git log --oneline in the # project and if not too long then include the output in your commit @@ -43,7 +43,7 @@ manifest: - name: zephyr repo-path: zephyr - revision: fe29c40a9366b5ffdcdd2eac26023ce4502413b1 + revision: 02b5a4c6cc15ab3deaeb7e0be72ea327d8a8775d remote: zephyrproject # Import some projects listed in zephyr/west.yml@revision diff --git a/xtos/include/sof/lib/dma.h b/xtos/include/sof/lib/dma.h index 7cfd6cecdc2b..c11c6c75bd72 100644 --- a/xtos/include/sof/lib/dma.h +++ b/xtos/include/sof/lib/dma.h @@ -33,6 +33,7 @@ #endif struct comp_buffer; +struct comp_dev; /** \addtogroup sof_dma_drivers DMA Drivers * DMA Drivers API specification. @@ -544,9 +545,8 @@ int dma_buffer_copy_from(struct comp_buffer *source, * conversion function. DMA buffer consume should be performed after the data has been copied * to all sinks. */ -int stream_copy_from_no_consume(struct comp_buffer *source, - struct comp_buffer *sink, - dma_process_func process, +int stream_copy_from_no_consume(struct comp_dev *dev, struct comp_buffer *source, + struct comp_buffer *sink, dma_process_func process, uint32_t source_bytes, uint32_t chmap); /* copies data to DMA buffer using provided processing function */ diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt index 567c03e5e5df..382c3d7cec30 100644 --- a/zephyr/CMakeLists.txt +++ b/zephyr/CMakeLists.txt @@ -1214,6 +1214,10 @@ zephyr_library_sources_ifdef(CONFIG_SHELL sof_shell.c ) +zephyr_library_sources_ifdef(CONFIG_INTEL_ADSP_MIC_PRIVACY + ${SOF_AUDIO_PATH}/mic_privacy_manager/mic_privacy_manager_intel.c +) + zephyr_library_link_libraries(SOF) target_link_libraries(SOF INTERFACE zephyr_interface) diff --git a/zephyr/include/sof/lib/dma.h b/zephyr/include/sof/lib/dma.h index e5c68f9b31c9..adec97dc1a1e 100644 --- a/zephyr/include/sof/lib/dma.h +++ b/zephyr/include/sof/lib/dma.h @@ -33,6 +33,7 @@ #include struct comp_buffer; +struct comp_dev; /** \addtogroup sof_dma_drivers DMA Drivers * SOF DMA Drivers API specification (deprecated interface, to be @@ -316,7 +317,8 @@ int dma_buffer_copy_from(struct comp_buffer *source, * conversion function. DMA buffer consume should be performed after the data has been copied * to all sinks. */ -int stream_copy_from_no_consume(struct comp_buffer *source, +int stream_copy_from_no_consume(struct comp_dev *dev, + struct comp_buffer *source, struct comp_buffer *sink, dma_process_func process, uint32_t source_bytes, uint32_t chmap);