Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ASoC: SOF: ipc4: Add support for Intel HW managed mic privacy messaging

ACE3 (Panther Lake) introduced support for microphone privacy feature which
can - in hardware - mute incoming audio data based on a state of a physical
switch.
The change in the privacy state is delivered through interface IP blocks
and can only be handled by the link owner.
In Intel platforms Soundwire is for example host owned, so the interrupt
can only be handled by the host.

Since the input stream is going to be muted by hardware, the host needs to
send a message to firmware about the change in privacy so it can execute a
fade out/in to enhance user experience.

The support for microphone privacy can be queried from the HW_CONFIG data
under the INTEL_MIC_PRIVACY_CAP tuple. This is Intel specific data, the
core will pass it to platform code if the intel_configure_mic_privacy()
callback is provided.

Platform code can call sof_ipc4_mic_privacy_state_change() to send the IPC
message to the firmware on state change.

Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Liam Girdwood <liam.r.girdwood@intel.com>
Reviewed-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
Link: https://patch.msgid.link/20250307112816.1495-6-peter.ujfalusi@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Peter Ujfalusi and committed by
Mark Brown
eea84a7f 8aeb7d2c

+69
+13
include/sound/sof/ipc4/header.h
··· 396 396 SOF_IPC4_FW_PARAM_MODULES_INFO_GET, 397 397 SOF_IPC4_FW_PARAM_LIBRARIES_INFO_GET = 16, 398 398 SOF_IPC4_FW_PARAM_SYSTEM_TIME = 20, 399 + SOF_IPC4_FW_PARAM_MIC_PRIVACY_STATE_CHANGE = 35, 399 400 }; 400 401 401 402 enum sof_ipc4_fw_config_params { ··· 446 445 /* core state: 0: put core_id to D3; 1: put core_id to D0 */ 447 446 uint32_t dx_mask; 448 447 } __packed __aligned(4); 448 + 449 + enum sof_ipc4_hw_config_params { 450 + SOF_IPC4_HW_CFG_INTEL_MIC_PRIVACY_CAPS = 11, 451 + }; 452 + 453 + #define SOF_IPC_INTEL_MIC_PRIVACY_VERSION_PTL 1 454 + 455 + struct sof_ipc4_intel_mic_privacy_cap { 456 + uint32_t version; 457 + uint32_t capabilities_length; 458 + uint32_t capabilities[]; 459 + } __packed; 449 460 450 461 /* Reply messages */ 451 462
+33
sound/soc/sof/ipc4-loader.c
··· 502 502 offset += sizeof(*tuple) + tuple->size; 503 503 } 504 504 505 + /* Get the hardware configuration */ 506 + msg.primary = SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG); 507 + msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); 508 + msg.primary |= SOF_IPC4_MOD_ID(SOF_IPC4_MOD_INIT_BASEFW_MOD_ID); 509 + msg.primary |= SOF_IPC4_MOD_INSTANCE(SOF_IPC4_MOD_INIT_BASEFW_INSTANCE_ID); 510 + msg.extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_FW_PARAM_HW_CONFIG_GET); 511 + 512 + msg.data_size = sdev->ipc->max_payload_size; 513 + 514 + ret = iops->set_get_data(sdev, &msg, msg.data_size, false); 515 + if (ret) 516 + goto out; 517 + 518 + offset = 0; 519 + while (offset < msg.data_size) { 520 + tuple = (struct sof_ipc4_tuple *)((u8 *)msg.data_ptr + offset); 521 + 522 + switch (tuple->type) { 523 + case SOF_IPC4_HW_CFG_INTEL_MIC_PRIVACY_CAPS: 524 + if (ipc4_data->intel_configure_mic_privacy) { 525 + struct sof_ipc4_intel_mic_privacy_cap *caps; 526 + 527 + caps = (struct sof_ipc4_intel_mic_privacy_cap *)tuple->value; 528 + ipc4_data->intel_configure_mic_privacy(sdev, caps); 529 + } 530 + break; 531 + default: 532 + break; 533 + } 534 + 535 + offset += sizeof(*tuple) + tuple->size; 536 + } 537 + 505 538 out: 506 539 kfree(msg.data_ptr); 507 540
+5
sound/soc/sof/ipc4-priv.h
··· 11 11 12 12 #include <linux/idr.h> 13 13 #include <sound/sof/ext_manifest4.h> 14 + #include <sound/sof/ipc4/header.h> 14 15 #include "sof-priv.h" 15 16 16 17 /* The DSP window indices are fixed */ ··· 90 89 91 90 int (*load_library)(struct snd_sof_dev *sdev, 92 91 struct sof_ipc4_fw_library *fw_lib, bool reload); 92 + void (*intel_configure_mic_privacy)(struct snd_sof_dev *sdev, 93 + struct sof_ipc4_intel_mic_privacy_cap *caps); 93 94 struct mutex pipeline_state_mutex; /* protect pipeline triggers, ref counts and states */ 94 95 }; 95 96 ··· 120 117 121 118 size_t sof_ipc4_find_debug_slot_offset_by_type(struct snd_sof_dev *sdev, 122 119 u32 slot_type); 120 + 121 + void sof_ipc4_mic_privacy_state_change(struct snd_sof_dev *sdev, bool state); 123 122 124 123 #endif
+18
sound/soc/sof/ipc4.c
··· 851 851 .pcm = &ipc4_pcm_ops, 852 852 .fw_tracing = &ipc4_mtrace_ops, 853 853 }; 854 + 855 + void sof_ipc4_mic_privacy_state_change(struct snd_sof_dev *sdev, bool state) 856 + { 857 + struct sof_ipc4_msg msg; 858 + u32 data = state; 859 + 860 + msg.primary = SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG); 861 + msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); 862 + msg.primary |= SOF_IPC4_MOD_ID(SOF_IPC4_MOD_INIT_BASEFW_MOD_ID); 863 + msg.primary |= SOF_IPC4_MOD_INSTANCE(SOF_IPC4_MOD_INIT_BASEFW_INSTANCE_ID); 864 + msg.extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_FW_PARAM_MIC_PRIVACY_STATE_CHANGE); 865 + 866 + msg.data_size = sizeof(data); 867 + msg.data_ptr = &data; 868 + 869 + sof_ipc4_set_get_data(sdev, &msg, msg.data_size, true); 870 + } 871 + EXPORT_SYMBOL(sof_ipc4_mic_privacy_state_change);