[PATCH 04/21] ASoC: amd: acp70: add logic for scanning acp child devices

Vijendar Mukunda posted 21 patches 12 months ago
There is a newer version of this series
[PATCH 04/21] ASoC: amd: acp70: add logic for scanning acp child devices
Posted by Vijendar Mukunda 12 months ago
Based on acp pin configuration, add logic for scanning child devices
under acp pci device acpi scope.

Signed-off-by: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
---
 sound/soc/amd/acp70/acp70.h     |  43 +++++++++++++
 sound/soc/amd/acp70/pci-acp70.c | 103 ++++++++++++++++++++++++++++++++
 2 files changed, 146 insertions(+)

diff --git a/sound/soc/amd/acp70/acp70.h b/sound/soc/amd/acp70/acp70.h
index b6f0f75de91d..1b20de75876a 100644
--- a/sound/soc/amd/acp70/acp70.h
+++ b/sound/soc/amd/acp70/acp70.h
@@ -5,6 +5,7 @@
  * Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.
  */
 
+#include <linux/soundwire/sdw_amd.h>
 #include <sound/acp70_chip_offset_byte.h>
 
 #define ACP_DEVICE_ID		0x15E2
@@ -28,21 +29,63 @@
 #define ACP_EXT_INTR_STAT_CLEAR_MASK	0xFFFFFFFF
 #define ACP_ERROR_IRQ			BIT(29)
 
+#define ACP_DMIC_DEV			2
+#define ACP70_DMIC_ADDR			2
+#define ACP70_SDW_ADDR			5
+#define AMD_SDW_MAX_MANAGERS		2
+
+enum acp_config {
+	ACP_CONFIG_0 = 0,
+	ACP_CONFIG_1,
+	ACP_CONFIG_2,
+	ACP_CONFIG_3,
+	ACP_CONFIG_4,
+	ACP_CONFIG_5,
+	ACP_CONFIG_6,
+	ACP_CONFIG_7,
+	ACP_CONFIG_8,
+	ACP_CONFIG_9,
+	ACP_CONFIG_10,
+	ACP_CONFIG_11,
+	ACP_CONFIG_12,
+	ACP_CONFIG_13,
+	ACP_CONFIG_14,
+	ACP_CONFIG_15,
+	ACP_CONFIG_16,
+	ACP_CONFIG_17,
+	ACP_CONFIG_18,
+	ACP_CONFIG_19,
+	ACP_CONFIG_20,
+};
+
 /**
  * struct acp70_dev_data - acp pci driver context
  * @acp70_base: acp mmio base
  * @acp_lock: used to protect acp common registers
+ * @info: SoundWire AMD information found in ACPI tables
+ * @sdw: SoundWire context for all SoundWire manager instances
  * @addr: pci ioremap address
  * @reg_range: ACP reigister range
  * @acp_rev : ACP PCI revision id
+ * @is_sdw_dev: flag set to true when any SoundWire manager instances are available
+ * @is_pdm_dev: flag set to true when ACP PDM controller exists
+ * @is_pdm_config: flat set to true when PDM configuration is selected from BIOS
+ * @is_sdw_config: flag set to true when SDW configuration is selected from BIOS
  */
 
 struct acp70_dev_data {
 	void __iomem *acp70_base;
 	struct mutex acp_lock; /* protect shared registers */
+	struct sdw_amd_acpi_info info;
+	/* sdw context allocated by SoundWire driver */
+	struct sdw_amd_ctx *sdw;
 	u32 addr;
 	u32 reg_range;
 	u32 acp_rev;
+	bool is_sdw_dev;
+	bool is_pdm_dev;
+	bool is_pdm_config;
+	bool is_sdw_config;
 };
 
 int snd_amd_acp_find_config(struct pci_dev *pci);
diff --git a/sound/soc/amd/acp70/pci-acp70.c b/sound/soc/amd/acp70/pci-acp70.c
index a98407fa2cd2..d360dfc396ad 100644
--- a/sound/soc/amd/acp70/pci-acp70.c
+++ b/sound/soc/amd/acp70/pci-acp70.c
@@ -5,6 +5,8 @@
  * Copyright 2024 Advanced Micro Devices, Inc.
  */
 
+#include <linux/acpi.h>
+#include <linux/bitops.h>
 #include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/iopoll.h>
@@ -93,6 +95,99 @@ static int acp70_deinit(void __iomem *acp_base, struct device *dev)
 	return 0;
 }
 
+#if IS_ENABLED(CONFIG_SND_SOC_AMD_SOUNDWIRE)
+static int acp_scan_sdw_devices(struct device *dev, u64 addr)
+{
+	struct acpi_device *sdw_dev;
+	struct acp70_dev_data *acp_data;
+
+	acp_data = dev_get_drvdata(dev);
+	if (!addr)
+		return -ENODEV;
+
+	sdw_dev = acpi_find_child_device(ACPI_COMPANION(dev), addr, 0);
+	if (!sdw_dev) {
+		pr_err("%s No SoundWire devices found\n", __func__);
+		return -ENODEV;
+	}
+
+	acp_data->info.handle = sdw_dev->handle;
+	acp_data->info.count = AMD_SDW_MAX_MANAGERS;
+	return amd_sdw_scan_controller(&acp_data->info);
+}
+#else
+static int acp_scan_sdw_devices(struct device *dev, u64 addr)
+{
+	return 0;
+}
+#endif
+
+static int get_acp70_device_config(struct pci_dev *pci, struct acp70_dev_data *acp_data)
+{
+	struct acpi_device *pdm_dev;
+	const union acpi_object *obj;
+	u32 config;
+	int ret;
+	bool is_dmic_dev = false;
+	bool is_sdw_dev = false;
+
+	config = readl(acp_data->acp70_base + ACP_PIN_CONFIG);
+	dev_dbg(&pci->dev, "ACP_PIN_CONFIG:0x%x\n", config);
+	switch (config) {
+	case ACP_CONFIG_4:
+	case ACP_CONFIG_5:
+	case ACP_CONFIG_10:
+	case ACP_CONFIG_11:
+	case ACP_CONFIG_20:
+		acp_data->is_pdm_config = true;
+		break;
+	case ACP_CONFIG_2:
+	case ACP_CONFIG_3:
+	case ACP_CONFIG_16:
+		acp_data->is_sdw_config = true;
+		break;
+	case ACP_CONFIG_6:
+	case ACP_CONFIG_7:
+	case ACP_CONFIG_12:
+	case ACP_CONFIG_8:
+	case ACP_CONFIG_13:
+	case ACP_CONFIG_14:
+	case ACP_CONFIG_17:
+	case ACP_CONFIG_18:
+	case ACP_CONFIG_19:
+		acp_data->is_pdm_config = true;
+		acp_data->is_sdw_config = true;
+		break;
+	default:
+		break;
+	}
+
+	if (acp_data->is_pdm_config) {
+		pdm_dev = acpi_find_child_device(ACPI_COMPANION(&pci->dev), ACP70_DMIC_ADDR, 0);
+		if (pdm_dev) {
+			/* is_dmic_dev flag will be set when ACP PDM controller device exists */
+			if (!acpi_dev_get_property(pdm_dev, "acp-audio-device-type",
+						   ACPI_TYPE_INTEGER, &obj) &&
+						   obj->integer.value == ACP_DMIC_DEV)
+				is_dmic_dev = true;
+		}
+	}
+
+	if (acp_data->is_sdw_config) {
+		ret = acp_scan_sdw_devices(&pci->dev, ACP70_SDW_ADDR);
+		if (!ret && acp_data->info.link_mask)
+			is_sdw_dev = true;
+	}
+
+	acp_data->is_pdm_dev = is_dmic_dev;
+	acp_data->is_sdw_dev = is_sdw_dev;
+	dev_dbg(&pci->dev, "is_pdm_dev:%d is_sdw_dev:%d\n", is_dmic_dev, is_sdw_dev);
+	if (!is_dmic_dev && !is_sdw_dev) {
+		dev_dbg(&pci->dev, "No PDM or SoundWire manager devices found\n");
+		return -ENODEV;
+	}
+	return 0;
+}
 static int snd_acp70_probe(struct pci_dev *pci,
 			   const struct pci_device_id *pci_id)
 {
@@ -148,6 +243,13 @@ static int snd_acp70_probe(struct pci_dev *pci,
 	if (ret)
 		goto release_regions;
 
+	ret = get_acp70_device_config(pci, adata);
+	/* ACP PCI driver probe should be continued even PDM or SoundWire Devices are not found */
+	if (ret) {
+		dev_dbg(&pci->dev, "get acp device config failed:%d\n", ret);
+		goto skip_pdev_creation;
+	}
+skip_pdev_creation:
 	return 0;
 release_regions:
 	pci_release_regions(pci);
@@ -189,4 +291,5 @@ module_pci_driver(ps_acp70_driver);
 
 MODULE_AUTHOR("Vijendar.Mukunda@amd.com");
 MODULE_DESCRIPTION("AMD ACP7.0 PCI driver");
+MODULE_IMPORT_NS("SND_AMD_SOUNDWIRE_ACPI");
 MODULE_LICENSE("GPL");
-- 
2.34.1