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

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.comSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent cf88ab48
......@@ -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
......
......@@ -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;
......
......@@ -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 (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;
}
if (!addr)
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;
}
sdw_dev = acpi_find_child_device(ACPI_COMPANION(dev), addr, 0);
if (!sdw_dev)
return -ENODEV;
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");
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment