[PATCH v2 6/8] ASoC: SOF: Intel: hda-mlink: Add support for mic privacy in VS SHIM registers

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]



New register has been introduced with PTL in the vendor specific SHIM
registers, outside of the IPs itself for microphone privacy status handling.

Via the PVCCS register the current microphone privacy status can be checked
and the interrupt generation on status change can be enabled/disabled.
The status change interrupt is routed to the owner of the interface
(DSP/host).

The PVCCS is provided for each sublink under the IP to make it possible to
control the interrupt generation per sublink.
On status change the MDSTSCHG bit needs to be cleared for all sublink of
the interface to be able to detect future changes in privacy.

The status bit (MDSTS) is volatile in all PVCCS register, it reflects the
current state of the GPIO signal.

Microphone privacy is a hardware feature (if enabled and configured that
way), the host has only passive, monitoring role.

The added functions are generic to be future proof if the mic privacy
support is extended beyond Soundwire and DMIC links.

Signed-off-by: Peter Ujfalusi <peter.ujfalusi@xxxxxxxxxxxxxxx>
Reviewed-by: Ranjani Sridharan <ranjani.sridharan@xxxxxxxxxxxxxxx>
Reviewed-by: Liam Girdwood <liam.r.girdwood@xxxxxxxxx>
Reviewed-by: Kai Vehmanen <kai.vehmanen@xxxxxxxxxxxxxxx>
---
 include/sound/hda-mlink.h       |  25 +++++++
 sound/soc/sof/intel/hda-mlink.c | 127 ++++++++++++++++++++++++++++++++
 2 files changed, 152 insertions(+)

diff --git a/include/sound/hda-mlink.h b/include/sound/hda-mlink.h
index 6774f4b9e5fc..4327317be6af 100644
--- a/include/sound/hda-mlink.h
+++ b/include/sound/hda-mlink.h
@@ -62,6 +62,12 @@ struct mutex *hdac_bus_eml_get_mutex(struct hdac_bus *bus, bool alt, int elid);
 
 int hdac_bus_eml_enable_offload(struct hdac_bus *bus, bool alt, int elid, bool enable);
 
+/* microphone privacy specific function supported by ACE3+ architecture */
+void hdac_bus_eml_set_mic_privacy_mask(struct hdac_bus *bus, bool alt, int elid,
+				       unsigned long mask);
+bool hdac_bus_eml_is_mic_privacy_changed(struct hdac_bus *bus, bool alt, int elid);
+bool hdac_bus_eml_get_mic_privacy_state(struct hdac_bus *bus, bool alt, int elid);
+
 #else
 
 static inline int
@@ -185,4 +191,23 @@ hdac_bus_eml_enable_offload(struct hdac_bus *bus, bool alt, int elid, bool enabl
 {
 	return 0;
 }
+
+static inline void
+hdac_bus_eml_set_mic_privacy_mask(struct hdac_bus *bus, bool alt, int elid,
+				  unsigned long mask)
+{
+}
+
+static inline bool
+hdac_bus_eml_is_mic_privacy_changed(struct hdac_bus *bus, bool alt, int elid)
+{
+	return false;
+}
+
+static inline bool
+hdac_bus_eml_get_mic_privacy_state(struct hdac_bus *bus, bool alt, int elid)
+{
+	return false;
+}
+
 #endif /* CONFIG_SND_SOC_SOF_HDA_MLINK */
diff --git a/sound/soc/sof/intel/hda-mlink.c b/sound/soc/sof/intel/hda-mlink.c
index fe627bcb0531..ce561fe52bd5 100644
--- a/sound/soc/sof/intel/hda-mlink.c
+++ b/sound/soc/sof/intel/hda-mlink.c
@@ -16,6 +16,7 @@
 
 #include <linux/bitfield.h>
 #include <linux/module.h>
+#include <linux/string_choices.h>
 
 #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_MLINK)
 
@@ -42,6 +43,7 @@
  * @shim_offset:	offset to SHIM register base
  * @ip_offset:		offset to IP register base
  * @shim_vs_offset:	offset to vendor-specific (VS) SHIM base
+ * @mic_privacy_mask:	bitmask of sublinks where mic privacy is applied
  */
 struct hdac_ext2_link {
 	struct hdac_ext_link hext_link;
@@ -65,6 +67,8 @@ struct hdac_ext2_link {
 	u32 shim_offset;
 	u32 ip_offset;
 	u32 shim_vs_offset;
+
+	unsigned long mic_privacy_mask;
 };
 
 #define hdac_ext_link_to_ext2(h) container_of(h, struct hdac_ext2_link, hext_link)
@@ -90,6 +94,13 @@ struct hdac_ext2_link {
 #define AZX_REG_INTEL_UAOL_IP_OFFSET			0x100
 #define AZX_REG_INTEL_UAOL_VS_SHIM_OFFSET		0xC00
 
+/* Microphone privacy */
+#define AZX_REG_INTEL_VS_SHIM_PVCCS			0x10
+#define AZX_REG_INTEL_VS_SHIM_PVCCS_MDSTSCHGIE		BIT(0)
+#define AZX_REG_INTEL_VS_SHIM_PVCCS_MDSTSCHG		BIT(8)
+#define AZX_REG_INTEL_VS_SHIM_PVCCS_MDSTS		BIT(9)
+#define AZX_REG_INTEL_VS_SHIM_PVCCS_FMDIS		BIT(10)
+
 /* HDAML section - this part follows sequences in the hardware specification,
  * including naming conventions and the use of the hdaml_ prefix.
  * The code is intentionally minimal with limited dependencies on frameworks or
@@ -696,6 +707,20 @@ static int hdac_bus_eml_power_up_base(struct hdac_bus *bus, bool alt, int elid,
 	}
 
 	ret = hdaml_link_init(hlink->ml_addr + AZX_REG_ML_LCTL, sublink);
+	if ((h2link->mic_privacy_mask & BIT(sublink)) && !ret) {
+		u16 __iomem *pvccs = h2link->base_ptr +
+				     h2link->shim_vs_offset +
+				     sublink * h2link->instance_offset +
+				     AZX_REG_INTEL_VS_SHIM_PVCCS;
+		u16 val = readw(pvccs);
+
+		writew(val | AZX_REG_INTEL_VS_SHIM_PVCCS_MDSTSCHGIE, pvccs);
+
+		if (val & AZX_REG_INTEL_VS_SHIM_PVCCS_MDSTS)
+			dev_dbg(bus->dev,
+				"sublink %d (%d:%d): Mic privacy is enabled\n",
+				sublink, alt, elid);
+	}
 
 skip_init:
 	if (eml_lock)
@@ -742,6 +767,16 @@ static int hdac_bus_eml_power_down_base(struct hdac_bus *bus, bool alt, int elid
 		if (--h2link->sublink_ref_count[sublink] > 0)
 			goto skip_shutdown;
 	}
+
+	if (h2link->mic_privacy_mask & BIT(sublink)) {
+		u16 __iomem *pvccs = h2link->base_ptr +
+				     h2link->shim_vs_offset +
+				     sublink * h2link->instance_offset +
+				     AZX_REG_INTEL_VS_SHIM_PVCCS;
+
+		writew(readw(pvccs) & ~AZX_REG_INTEL_VS_SHIM_PVCCS_MDSTSCHGIE, pvccs);
+	}
+
 	ret = hdaml_link_shutdown(hlink->ml_addr + AZX_REG_ML_LCTL, sublink);
 
 skip_shutdown:
@@ -987,6 +1022,98 @@ int hdac_bus_eml_enable_offload(struct hdac_bus *bus, bool alt, int elid, bool e
 }
 EXPORT_SYMBOL_NS(hdac_bus_eml_enable_offload, "SND_SOC_SOF_HDA_MLINK");
 
+void hdac_bus_eml_set_mic_privacy_mask(struct hdac_bus *bus, bool alt, int elid,
+				       unsigned long mask)
+{
+	struct hdac_ext2_link *h2link;
+
+	if (!mask)
+		return;
+
+	h2link = find_ext2_link(bus, alt, elid);
+	if (!h2link)
+		return;
+
+	if (__fls(mask) > h2link->slcount) {
+		dev_warn(bus->dev,
+			 "%s: invalid sublink mask for %d:%d, slcount %d: %#lx\n",
+			 __func__, alt, elid, h2link->slcount, mask);
+		return;
+	}
+
+	dev_dbg(bus->dev, "sublink mask for %d:%d, slcount %d: %#lx\n", alt,
+		elid, h2link->slcount, mask);
+
+	h2link->mic_privacy_mask = mask;
+}
+EXPORT_SYMBOL_NS(hdac_bus_eml_set_mic_privacy_mask, "SND_SOC_SOF_HDA_MLINK");
+
+bool hdac_bus_eml_is_mic_privacy_changed(struct hdac_bus *bus, bool alt, int elid)
+{
+	struct hdac_ext2_link *h2link;
+	bool changed = false;
+	u16 __iomem *pvccs;
+	int i;
+
+	h2link = find_ext2_link(bus, alt, elid);
+	if (!h2link)
+		return false;
+
+	/* The change in privacy state needs to be acked for each link */
+	for_each_set_bit(i, &h2link->mic_privacy_mask, h2link->slcount) {
+		u16 val;
+
+		if (h2link->sublink_ref_count[i] == 0)
+			continue;
+
+		pvccs = h2link->base_ptr +
+			h2link->shim_vs_offset +
+			i * h2link->instance_offset +
+			AZX_REG_INTEL_VS_SHIM_PVCCS;
+
+		val = readw(pvccs);
+		if (val & AZX_REG_INTEL_VS_SHIM_PVCCS_MDSTSCHG) {
+			writew(val, pvccs);
+			changed = true;
+		}
+	}
+
+	return changed;
+}
+EXPORT_SYMBOL_NS(hdac_bus_eml_is_mic_privacy_changed, "SND_SOC_SOF_HDA_MLINK");
+
+bool hdac_bus_eml_get_mic_privacy_state(struct hdac_bus *bus, bool alt, int elid)
+{
+	struct hdac_ext2_link *h2link;
+	u16 __iomem *pvccs;
+	bool state;
+	int i;
+
+	h2link = find_ext2_link(bus, alt, elid);
+	if (!h2link)
+		return false;
+
+	for_each_set_bit(i, &h2link->mic_privacy_mask, h2link->slcount) {
+		if (h2link->sublink_ref_count[i] == 0)
+			continue;
+
+		/* Return the privacy state from the first active link */
+		pvccs = h2link->base_ptr +
+			h2link->shim_vs_offset +
+			i * h2link->instance_offset +
+			AZX_REG_INTEL_VS_SHIM_PVCCS;
+
+		state = readw(pvccs) & AZX_REG_INTEL_VS_SHIM_PVCCS_MDSTS;
+		dev_dbg(bus->dev, "alt: %d, elid: %d: Mic privacy is %s\n", alt,
+			elid, str_enabled_disabled(state));
+
+		return state;
+	}
+
+	return false;
+}
+EXPORT_SYMBOL_NS(hdac_bus_eml_get_mic_privacy_state, "SND_SOC_SOF_HDA_MLINK");
+
 #endif
 
 MODULE_LICENSE("Dual BSD/GPL");
-- 
2.48.1





[Index of Archives]     [Pulseaudio]     [Linux Audio Users]     [ALSA Devel]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]

  Powered by Linux