Unverified Commit 0386d765 authored by Vijendar Mukunda's avatar Vijendar Mukunda Committed by Mark Brown
Browse files

ASoC: amd: ps: refactor acp device configuration read logic



Refactor acp device configuration read logic and use common function
to scan SoundWire devices.

Signed-off-by: default avatarVijendar Mukunda <Vijendar.Mukunda@amd.com>
Link: https://msgid.link/r/20240214104014.1144668-1-Vijendar.Mukunda@amd.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent cf88ab48
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -132,9 +132,26 @@ config SND_SOC_AMD_RPL_ACP6x
          Say m if you have such a device.
          If unsure select "N".

config SND_SOC_AMD_SOUNDWIRE_LINK_BASELINE
	tristate
	select SOUNDWIRE_AMD if SND_SOC_AMD_SOUNDWIRE != n
	select SND_AMD_SOUNDWIRE_ACPI if ACPI

config SND_SOC_AMD_SOUNDWIRE
	tristate "Support for SoundWire based AMD platforms"
	default SND_SOC_AMD_SOUNDWIRE_LINK_BASELINE
	depends on SND_SOC_AMD_SOUNDWIRE_LINK_BASELINE
	depends on ACPI && SOUNDWIRE
	depends on !(SOUNDWIRE=m && SND_SOC_AMD_SOUNDWIRE_LINK_BASELINE=y)
	help
	  This adds support for SoundWire for AMD platforms.
	  Say Y if you want to enable SoundWire links with SOF.
	  If unsure select "N".

config SND_SOC_AMD_PS
        tristate "AMD Audio Coprocessor-v6.3 Pink Sardine support"
	select SND_AMD_ACP_CONFIG
	select SND_SOC_AMD_SOUNDWIRE_LINK_BASELINE
        depends on X86 && PCI && ACPI
        help
          This option enables Audio Coprocessor i.e ACP v6.3 support on
+11 −0
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@
 * Copyright (C) 2022, 2023 Advanced Micro Devices, Inc. All rights reserved.
 */

#include <linux/soundwire/sdw_amd.h>
#include <sound/acp63_chip_offset_byte.h>

#define ACP_DEVICE_ID 0x15E2
@@ -263,6 +264,11 @@ struct sdw_dma_ring_buf_reg {
 * @sdw0_dev_index: SoundWire Manager-0 platform device index
 * @sdw1_dev_index: SoundWire Manager-1 platform device index
 * @sdw_dma_dev_index: SoundWire DMA controller platform device index
 * @info: SoundWire AMD information found in ACPI tables
 * @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
 * @sdw0-dma_intr_stat: DMA interrupt status array for SoundWire manager-SW0 instance
 * @sdw_dma_intr_stat: DMA interrupt status array for SoundWire manager-SW1 instance
 * @acp_reset: flag set to true when bus reset is applied across all
@@ -282,6 +288,11 @@ struct acp63_dev_data {
	u16 sdw0_dev_index;
	u16 sdw1_dev_index;
	u16 sdw_dma_dev_index;
	struct sdw_amd_acpi_info info;
	bool is_sdw_dev;
	bool is_pdm_dev;
	bool is_pdm_config;
	bool is_sdw_config;
	u16 sdw0_dma_intr_stat[ACP63_SDW0_DMA_MAX_STREAMS];
	u16 sdw1_dma_intr_stat[ACP63_SDW1_DMA_MAX_STREAMS];
	bool acp_reset;
+50 −126
Original line number Diff line number Diff line
@@ -237,122 +237,51 @@ static irqreturn_t acp63_irq_handler(int irq, void *dev_id)
		return IRQ_NONE;
}

static int sdw_amd_scan_controller(struct device *dev)
#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 acp63_dev_data *acp_data;
	struct fwnode_handle *link;
	char name[32];
	u32 sdw_manager_bitmap;
	u8 count = 0;
	u32 acp_sdw_power_mode = 0;
	int index;
	int ret;

	acp_data = dev_get_drvdata(dev);
	/*
	 * Current implementation is based on MIPI DisCo 2.0 spec.
	 * Found controller, find links supported.
	 */
	ret = fwnode_property_read_u32_array((acp_data->sdw_fw_node), "mipi-sdw-manager-list",
					     &sdw_manager_bitmap, 1);
	if (!addr)
		return -ENODEV;

	if (ret) {
		dev_dbg(dev, "Failed to read mipi-sdw-manager-list: %d\n", ret);
		return -EINVAL;
	}
	count = hweight32(sdw_manager_bitmap);
	/* Check count is within bounds */
	if (count > AMD_SDW_MAX_MANAGERS) {
		dev_err(dev, "Manager count %d exceeds max %d\n", count, AMD_SDW_MAX_MANAGERS);
		return -EINVAL;
	}
	sdw_dev = acpi_find_child_device(ACPI_COMPANION(dev), addr, 0);
	if (!sdw_dev)
		return -ENODEV;

	if (!count) {
		dev_dbg(dev, "No SoundWire Managers detected\n");
		return -EINVAL;
	}
	dev_dbg(dev, "ACPI reports %d SoundWire Manager devices\n", count);
	acp_data->sdw_manager_count = count;
	for (index = 0; index < count; index++) {
		scnprintf(name, sizeof(name), "mipi-sdw-link-%d-subproperties", index);
		link = fwnode_get_named_child_node(acp_data->sdw_fw_node, name);
		if (!link) {
			dev_err(dev, "Manager node %s not found\n", name);
			return -EIO;
		}

		ret = fwnode_property_read_u32(link, "amd-sdw-power-mode", &acp_sdw_power_mode);
		if (ret)
			return ret;
		/*
		 * when SoundWire configuration is selected from acp pin config,
		 * based on manager instances count, acp init/de-init sequence should be
		 * executed as part of PM ops only when Bus reset is applied for the active
		 * SoundWire manager instances.
		 */
		if (acp_sdw_power_mode != AMD_SDW_POWER_OFF_MODE) {
			acp_data->acp_reset = false;
			return 0;
		}
	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_acp63_device_config(u32 config, struct pci_dev *pci, struct acp63_dev_data *acp_data)
static int get_acp63_device_config(struct pci_dev *pci, struct acp63_dev_data *acp_data)
{
	struct acpi_device *dmic_dev;
	struct acpi_device *sdw_dev;
	struct acpi_device *pdm_dev;
	const union acpi_object *obj;
	u32 config;
	bool is_dmic_dev = false;
	bool is_sdw_dev = false;
	int ret;

	dmic_dev = acpi_find_child_device(ACPI_COMPANION(&pci->dev), ACP63_DMIC_ADDR, 0);
	if (dmic_dev) {
		/* is_dmic_dev flag will be set when ACP PDM controller device exists */
		if (!acpi_dev_get_property(dmic_dev, "acp-audio-device-type",
					   ACPI_TYPE_INTEGER, &obj) &&
					   obj->integer.value == ACP_DMIC_DEV)
			is_dmic_dev = true;
	}

	sdw_dev = acpi_find_child_device(ACPI_COMPANION(&pci->dev), ACP63_SDW_ADDR, 0);
	if (sdw_dev) {
		acp_data->sdw_fw_node = acpi_fwnode_handle(sdw_dev);
		ret = sdw_amd_scan_controller(&pci->dev);
		/* is_sdw_dev flag will be set when SoundWire Manager device exists */
		if (!ret)
			is_sdw_dev = true;
	}
	if (!is_dmic_dev && !is_sdw_dev)
		return -ENODEV;
	dev_dbg(&pci->dev, "Audio Mode %d\n", config);
	config = readl(acp_data->acp63_base + ACP_PIN_CONFIG);
	switch (config) {
	case ACP_CONFIG_4:
	case ACP_CONFIG_5:
	case ACP_CONFIG_10:
	case ACP_CONFIG_11:
		if (is_dmic_dev) {
			acp_data->pdev_config = ACP63_PDM_DEV_CONFIG;
			acp_data->pdev_count = ACP63_PDM_MODE_DEVS;
		}
		acp_data->is_pdm_config = true;
		break;
	case ACP_CONFIG_2:
	case ACP_CONFIG_3:
		if (is_sdw_dev) {
			switch (acp_data->sdw_manager_count) {
			case 1:
				acp_data->pdev_config = ACP63_SDW_DEV_CONFIG;
				acp_data->pdev_count = ACP63_SDW0_MODE_DEVS;
				break;
			case 2:
				acp_data->pdev_config = ACP63_SDW_DEV_CONFIG;
				acp_data->pdev_count = ACP63_SDW0_SDW1_MODE_DEVS;
				break;
			default:
				return -EINVAL;
			}
		}
		acp_data->is_sdw_config = true;
		break;
	case ACP_CONFIG_6:
	case ACP_CONFIG_7:
@@ -360,39 +289,35 @@ static int get_acp63_device_config(u32 config, struct pci_dev *pci, struct acp63
	case ACP_CONFIG_8:
	case ACP_CONFIG_13:
	case ACP_CONFIG_14:
		if (is_dmic_dev && is_sdw_dev) {
			switch (acp_data->sdw_manager_count) {
			case 1:
				acp_data->pdev_config = ACP63_SDW_PDM_DEV_CONFIG;
				acp_data->pdev_count = ACP63_SDW0_PDM_MODE_DEVS;
				break;
			case 2:
				acp_data->pdev_config = ACP63_SDW_PDM_DEV_CONFIG;
				acp_data->pdev_count = ACP63_SDW0_SDW1_PDM_MODE_DEVS;
		acp_data->is_pdm_config = true;
		acp_data->is_sdw_config = true;
		break;
	default:
				return -EINVAL;
			}
		} else if (is_dmic_dev) {
			acp_data->pdev_config = ACP63_PDM_DEV_CONFIG;
			acp_data->pdev_count = ACP63_PDM_MODE_DEVS;
		} else if (is_sdw_dev) {
			switch (acp_data->sdw_manager_count) {
			case 1:
				acp_data->pdev_config = ACP63_SDW_DEV_CONFIG;
				acp_data->pdev_count = ACP63_SDW0_MODE_DEVS;
				break;
			case 2:
				acp_data->pdev_config = ACP63_SDW_DEV_CONFIG;
				acp_data->pdev_count = ACP63_SDW0_SDW1_MODE_DEVS;
		break;
			default:
				return -EINVAL;
	}

	if (acp_data->is_pdm_config) {
		pdm_dev = acpi_find_child_device(ACPI_COMPANION(&pci->dev), ACP63_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;
		}
		break;
	default:
		break;
	}

	if (acp_data->is_sdw_config) {
		ret = acp_scan_sdw_devices(&pci->dev, ACP63_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;
	if (!is_dmic_dev && !is_sdw_dev) {
		dev_dbg(&pci->dev, "No PDM or SoundWire manager devices found\n");
		return -ENODEV;
	}
	return 0;
}
@@ -576,7 +501,6 @@ static int snd_acp63_probe(struct pci_dev *pci,
	struct acp63_dev_data *adata;
	u32 addr;
	u32 irqflags, flag;
	int val;
	int ret;

	irqflags = IRQF_SHARED;
@@ -637,8 +561,7 @@ static int snd_acp63_probe(struct pci_dev *pci,
		dev_err(&pci->dev, "ACP PCI IRQ request failed\n");
		goto de_init;
	}
	val = readl(adata->acp63_base + ACP_PIN_CONFIG);
	ret = get_acp63_device_config(val, pci, adata);
	ret = get_acp63_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);
@@ -740,4 +663,5 @@ module_pci_driver(ps_acp63_driver);
MODULE_AUTHOR("Vijendar.Mukunda@amd.com");
MODULE_AUTHOR("Syed.SabaKareem@amd.com");
MODULE_DESCRIPTION("AMD ACP Pink Sardine PCI driver");
MODULE_IMPORT_NS(SND_AMD_SOUNDWIRE_ACPI);
MODULE_LICENSE("GPL v2");