diff --git a/sound/soc/amd/Kconfig b/sound/soc/amd/Kconfig index 273688c05317..fa74635cee08 100644 --- a/sound/soc/amd/Kconfig +++ b/sound/soc/amd/Kconfig @@ -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 diff --git a/sound/soc/amd/ps/acp63.h b/sound/soc/amd/ps/acp63.h index 8b853b8d0219..123b9ade69d4 100644 --- a/sound/soc/amd/ps/acp63.h +++ b/sound/soc/amd/ps/acp63.h @@ -5,6 +5,7 @@ * Copyright (C) 2022, 2023 Advanced Micro Devices, Inc. All rights reserved. */ +#include #include #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; diff --git a/sound/soc/amd/ps/pci-ps.c b/sound/soc/amd/ps/pci-ps.c index 5927eef04170..c97e418a88ce 100644 --- a/sound/soc/amd/ps/pci-ps.c +++ b/sound/soc/amd/ps/pci-ps.c @@ -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,40 +289,36 @@ 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; - 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; - } - } + 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), 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; + } + } + + 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");