summaryrefslogtreecommitdiffstats
path: root/sound/soc/amd
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/amd')
-rw-r--r--sound/soc/amd/Kconfig17
-rw-r--r--sound/soc/amd/Makefile2
-rw-r--r--sound/soc/amd/acp/Kconfig7
-rw-r--r--sound/soc/amd/acp/Makefile2
-rw-r--r--sound/soc/amd/acp/acp-legacy-common.c96
-rw-r--r--sound/soc/amd/acp/acp-mach-common.c6
-rw-r--r--sound/soc/amd/acp/acp-pci.c9
-rw-r--r--sound/soc/amd/acp/acp-sof-mach.c12
-rw-r--r--sound/soc/amd/acp/amd-sdw-acpi.c62
-rw-r--r--sound/soc/amd/acp/amd.h10
-rw-r--r--sound/soc/amd/acp/chip_offset_byte.h1
-rw-r--r--sound/soc/amd/ps/Makefile2
-rw-r--r--sound/soc/amd/ps/acp63.h91
-rw-r--r--sound/soc/amd/ps/pci-ps.c565
-rw-r--r--sound/soc/amd/ps/ps-mach.c2
-rw-r--r--sound/soc/amd/ps/ps-pdm-dma.c2
-rw-r--r--sound/soc/amd/ps/ps-sdw-dma.c2
17 files changed, 512 insertions, 376 deletions
diff --git a/sound/soc/amd/Kconfig b/sound/soc/amd/Kconfig
index 273688c053..fa74635cee 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/Makefile b/sound/soc/amd/Makefile
index 82e1cf864a..ebbe49c2bb 100644
--- a/sound/soc/amd/Makefile
+++ b/sound/soc/amd/Makefile
@@ -15,7 +15,7 @@ obj-$(CONFIG_SND_SOC_AMD_RV_RT5682_MACH) += snd-soc-acp-rt5682-mach.o
obj-$(CONFIG_SND_SOC_AMD_RENOIR) += renoir/
obj-$(CONFIG_SND_SOC_AMD_ACP5x) += vangogh/
obj-$(CONFIG_SND_SOC_AMD_ACP6x) += yc/
-obj-$(CONFIG_SND_SOC_AMD_ACP_COMMON) += acp/
+obj-$(CONFIG_SND_AMD_ACP_CONFIG) += acp/
obj-$(CONFIG_SND_AMD_ACP_CONFIG) += snd-acp-config.o
obj-$(CONFIG_SND_SOC_AMD_RPL_ACP6x) += rpl/
obj-$(CONFIG_SND_SOC_AMD_PS) += ps/
diff --git a/sound/soc/amd/acp/Kconfig b/sound/soc/amd/acp/Kconfig
index 84c963241d..30590a23ad 100644
--- a/sound/soc/amd/acp/Kconfig
+++ b/sound/soc/amd/acp/Kconfig
@@ -116,3 +116,10 @@ config SND_SOC_AMD_SOF_MACH
This option enables SOF sound card support for ACP audio.
endif # SND_SOC_AMD_ACP_COMMON
+
+config SND_AMD_SOUNDWIRE_ACPI
+ tristate
+ depends on ACPI
+ help
+ This options enables ACPI helper functions for SoundWire
+ interface for AMD platforms.
diff --git a/sound/soc/amd/acp/Makefile b/sound/soc/amd/acp/Makefile
index ff5f7893b8..1fd581a2aa 100644
--- a/sound/soc/amd/acp/Makefile
+++ b/sound/soc/amd/acp/Makefile
@@ -10,6 +10,7 @@ snd-acp-i2s-objs := acp-i2s.o
snd-acp-pdm-objs := acp-pdm.o
snd-acp-legacy-common-objs := acp-legacy-common.o
snd-acp-pci-objs := acp-pci.o
+snd-amd-sdw-acpi-objs := amd-sdw-acpi.o
#platform specific driver
snd-acp-renoir-objs := acp-renoir.o
@@ -33,6 +34,7 @@ obj-$(CONFIG_SND_AMD_ASOC_REMBRANDT) += snd-acp-rembrandt.o
obj-$(CONFIG_SND_AMD_ASOC_ACP63) += snd-acp63.o
obj-$(CONFIG_SND_AMD_ASOC_ACP70) += snd-acp70.o
+obj-$(CONFIG_SND_AMD_SOUNDWIRE_ACPI) += snd-amd-sdw-acpi.o
obj-$(CONFIG_SND_SOC_AMD_MACH_COMMON) += snd-acp-mach.o
obj-$(CONFIG_SND_SOC_AMD_LEGACY_MACH) += snd-acp-legacy-mach.o
obj-$(CONFIG_SND_SOC_AMD_SOF_MACH) += snd-acp-sof-mach.o
diff --git a/sound/soc/amd/acp/acp-legacy-common.c b/sound/soc/amd/acp/acp-legacy-common.c
index b5aff3f230..3be7c6d55a 100644
--- a/sound/soc/amd/acp/acp-legacy-common.c
+++ b/sound/soc/amd/acp/acp-legacy-common.c
@@ -358,11 +358,25 @@ int smn_read(struct pci_dev *dev, u32 smn_addr)
}
EXPORT_SYMBOL_NS_GPL(smn_read, SND_SOC_ACP_COMMON);
-int check_acp_pdm(struct pci_dev *pci, struct acp_chip_info *chip)
+static void check_acp3x_config(struct acp_chip_info *chip)
{
- struct acpi_device *pdm_dev;
- const union acpi_object *obj;
- u32 pdm_addr, val;
+ u32 val;
+
+ val = readl(chip->base + ACP3X_PIN_CONFIG);
+ switch (val) {
+ case ACP_CONFIG_4:
+ chip->is_i2s_config = true;
+ chip->is_pdm_config = true;
+ break;
+ default:
+ chip->is_pdm_config = true;
+ break;
+ }
+}
+
+static void check_acp6x_config(struct acp_chip_info *chip)
+{
+ u32 val;
val = readl(chip->base + ACP_PIN_CONFIG);
switch (val) {
@@ -371,42 +385,94 @@ int check_acp_pdm(struct pci_dev *pci, struct acp_chip_info *chip)
case ACP_CONFIG_6:
case ACP_CONFIG_7:
case ACP_CONFIG_8:
- case ACP_CONFIG_10:
case ACP_CONFIG_11:
+ case ACP_CONFIG_14:
+ chip->is_pdm_config = true;
+ break;
+ case ACP_CONFIG_9:
+ chip->is_i2s_config = true;
+ break;
+ case ACP_CONFIG_10:
case ACP_CONFIG_12:
case ACP_CONFIG_13:
+ chip->is_i2s_config = true;
+ chip->is_pdm_config = true;
+ break;
+ default:
+ break;
+ }
+}
+
+static void check_acp70_config(struct acp_chip_info *chip)
+{
+ u32 val;
+
+ val = readl(chip->base + ACP_PIN_CONFIG);
+ switch (val) {
+ case ACP_CONFIG_4:
+ case ACP_CONFIG_5:
+ case ACP_CONFIG_6:
+ case ACP_CONFIG_7:
+ case ACP_CONFIG_8:
+ case ACP_CONFIG_11:
case ACP_CONFIG_14:
+ case ACP_CONFIG_17:
+ case ACP_CONFIG_18:
+ chip->is_pdm_config = true;
+ break;
+ case ACP_CONFIG_9:
+ chip->is_i2s_config = true;
+ break;
+ case ACP_CONFIG_10:
+ case ACP_CONFIG_12:
+ case ACP_CONFIG_13:
+ case ACP_CONFIG_19:
+ case ACP_CONFIG_20:
+ chip->is_i2s_config = true;
+ chip->is_pdm_config = true;
break;
default:
- return -EINVAL;
+ break;
}
+}
+
+void check_acp_config(struct pci_dev *pci, struct acp_chip_info *chip)
+{
+ struct acpi_device *pdm_dev;
+ const union acpi_object *obj;
+ u32 pdm_addr;
switch (chip->acp_rev) {
case ACP3X_DEV:
pdm_addr = ACP_RENOIR_PDM_ADDR;
+ check_acp3x_config(chip);
break;
case ACP6X_DEV:
pdm_addr = ACP_REMBRANDT_PDM_ADDR;
+ check_acp6x_config(chip);
break;
case ACP63_DEV:
pdm_addr = ACP63_PDM_ADDR;
+ check_acp6x_config(chip);
break;
case ACP70_DEV:
pdm_addr = ACP70_PDM_ADDR;
+ check_acp70_config(chip);
break;
default:
- return -EINVAL;
+ break;
}
- pdm_dev = acpi_find_child_device(ACPI_COMPANION(&pci->dev), pdm_addr, 0);
- if (pdm_dev) {
- if (!acpi_dev_get_property(pdm_dev, "acp-audio-device-type",
- ACPI_TYPE_INTEGER, &obj) &&
- obj->integer.value == pdm_addr)
- return 0;
+ if (chip->is_pdm_config) {
+ pdm_dev = acpi_find_child_device(ACPI_COMPANION(&pci->dev), pdm_addr, 0);
+ if (pdm_dev) {
+ if (!acpi_dev_get_property(pdm_dev, "acp-audio-device-type",
+ ACPI_TYPE_INTEGER, &obj) &&
+ obj->integer.value == pdm_addr)
+ chip->is_pdm_dev = true;
+ }
}
- return -ENODEV;
}
-EXPORT_SYMBOL_NS_GPL(check_acp_pdm, SND_SOC_ACP_COMMON);
+EXPORT_SYMBOL_NS_GPL(check_acp_config, SND_SOC_ACP_COMMON);
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/sound/soc/amd/acp/acp-mach-common.c b/sound/soc/amd/acp/acp-mach-common.c
index 504d1b8c4c..665a6ea0a2 100644
--- a/sound/soc/amd/acp/acp-mach-common.c
+++ b/sound/soc/amd/acp/acp-mach-common.c
@@ -828,8 +828,8 @@ static const struct snd_soc_ops acp_card_maxim_ops = {
};
SND_SOC_DAILINK_DEF(max98388,
- DAILINK_COMP_ARRAY(COMP_CODEC("i2c-ADS8388:00", "max98388-aif1"),
- COMP_CODEC("i2c-ADS8388:01", "max98388-aif1")));
+ DAILINK_COMP_ARRAY(COMP_CODEC("i2c-ADS8388:00", MAX98388_CODEC_DAI),
+ COMP_CODEC("i2c-ADS8388:01", MAX98388_CODEC_DAI)));
static const struct snd_kcontrol_new max98388_controls[] = {
SOC_DAPM_PIN_SWITCH("Left Spk"),
@@ -1280,7 +1280,7 @@ static const struct snd_soc_ops acp_8821_ops = {
SND_SOC_DAILINK_DEF(nau8821,
DAILINK_COMP_ARRAY(COMP_CODEC("i2c-NVTN2020:00",
- "nau8821-hifi")));
+ NAU8821_CODEC_DAI)));
/* Declare DMIC codec components */
SND_SOC_DAILINK_DEF(dmic_codec,
diff --git a/sound/soc/amd/acp/acp-pci.c b/sound/soc/amd/acp/acp-pci.c
index 5f35b90eab..ad320b29e8 100644
--- a/sound/soc/amd/acp/acp-pci.c
+++ b/sound/soc/amd/acp/acp-pci.c
@@ -100,7 +100,6 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id
ret = -EINVAL;
goto release_regions;
}
-
dmic_dev = platform_device_register_data(dev, "dmic-codec", PLATFORM_DEVID_NONE, NULL, 0);
if (IS_ERR(dmic_dev)) {
dev_err(dev, "failed to create DMIC device\n");
@@ -119,6 +118,10 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id
if (ret)
goto unregister_dmic_dev;
+ check_acp_config(pci, chip);
+ if (!chip->is_pdm_dev && !chip->is_i2s_config)
+ goto skip_pdev_creation;
+
res = devm_kcalloc(&pci->dev, num_res, sizeof(struct resource), GFP_KERNEL);
if (!res) {
ret = -ENOMEM;
@@ -136,10 +139,6 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id
}
}
- ret = check_acp_pdm(pci, chip);
- if (ret < 0)
- goto skip_pdev_creation;
-
chip->flag = flag;
memset(&pdevinfo, 0, sizeof(pdevinfo));
diff --git a/sound/soc/amd/acp/acp-sof-mach.c b/sound/soc/amd/acp/acp-sof-mach.c
index b86f65d420..fc59ea34e6 100644
--- a/sound/soc/amd/acp/acp-sof-mach.c
+++ b/sound/soc/amd/acp/acp-sof-mach.c
@@ -28,7 +28,6 @@ static struct acp_card_drvdata sof_rt5682_rt1019_data = {
.hs_codec_id = RT5682,
.amp_codec_id = RT1019,
.dmic_codec_id = DMIC,
- .tdm_mode = false,
};
static struct acp_card_drvdata sof_rt5682_max_data = {
@@ -38,7 +37,6 @@ static struct acp_card_drvdata sof_rt5682_max_data = {
.hs_codec_id = RT5682,
.amp_codec_id = MAX98360A,
.dmic_codec_id = DMIC,
- .tdm_mode = false,
};
static struct acp_card_drvdata sof_rt5682s_rt1019_data = {
@@ -49,7 +47,6 @@ static struct acp_card_drvdata sof_rt5682s_rt1019_data = {
.amp_codec_id = RT1019,
.dmic_codec_id = DMIC,
.platform = RENOIR,
- .tdm_mode = false,
};
static struct acp_card_drvdata sof_rt5682s_max_data = {
@@ -60,7 +57,6 @@ static struct acp_card_drvdata sof_rt5682s_max_data = {
.amp_codec_id = MAX98360A,
.dmic_codec_id = DMIC,
.platform = RENOIR,
- .tdm_mode = false,
};
static struct acp_card_drvdata sof_nau8825_data = {
@@ -72,7 +68,6 @@ static struct acp_card_drvdata sof_nau8825_data = {
.dmic_codec_id = DMIC,
.platform = REMBRANDT,
.soc_mclk = true,
- .tdm_mode = false,
};
static struct acp_card_drvdata sof_rt5682s_hs_rt1019_data = {
@@ -84,20 +79,15 @@ static struct acp_card_drvdata sof_rt5682s_hs_rt1019_data = {
.dmic_codec_id = DMIC,
.platform = REMBRANDT,
.soc_mclk = true,
- .tdm_mode = false,
};
static struct acp_card_drvdata sof_nau8821_max98388_data = {
.hs_cpu_id = I2S_SP,
.amp_cpu_id = I2S_HS,
.bt_cpu_id = I2S_BT,
- .dmic_cpu_id = NONE,
.hs_codec_id = NAU8821,
.amp_codec_id = MAX98388,
- .bt_codec_id = NONE,
- .dmic_codec_id = NONE,
.soc_mclk = true,
- .tdm_mode = false,
};
static int acp_sof_probe(struct platform_device *pdev)
@@ -180,7 +170,7 @@ static struct platform_driver acp_asoc_audio = {
module_platform_driver(acp_asoc_audio);
MODULE_IMPORT_NS(SND_SOC_AMD_MACH);
-MODULE_DESCRIPTION("ACP chrome SOF audio support");
+MODULE_DESCRIPTION("ACP SOF Machine Driver");
MODULE_ALIAS("platform:rt5682-rt1019");
MODULE_ALIAS("platform:rt5682-max");
MODULE_ALIAS("platform:rt5682s-max");
diff --git a/sound/soc/amd/acp/amd-sdw-acpi.c b/sound/soc/amd/acp/amd-sdw-acpi.c
new file mode 100644
index 0000000000..babd841d32
--- /dev/null
+++ b/sound/soc/amd/acp/amd-sdw-acpi.c
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+//
+// This file is provided under a dual BSD/GPLv2 license. When using or
+// redistributing this file, you may do so under either license.
+//
+// Copyright(c) 2023 Advanced Micro Devices, Inc. All rights reserved.
+//
+// Authors: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
+
+/*
+ * SDW AMD ACPI scan helper function
+ */
+
+#include <linux/acpi.h>
+#include <linux/bits.h>
+#include <linux/bitfield.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/export.h>
+#include <linux/fwnode.h>
+#include <linux/module.h>
+#include <linux/soundwire/sdw_amd.h>
+#include <linux/string.h>
+
+int amd_sdw_scan_controller(struct sdw_amd_acpi_info *info)
+{
+ struct acpi_device *adev = acpi_fetch_acpi_dev(info->handle);
+ u32 sdw_bitmap = 0;
+ u8 count = 0;
+ int ret;
+
+ if (!adev)
+ return -EINVAL;
+
+ /* Found controller, find links supported */
+ ret = fwnode_property_read_u32_array(acpi_fwnode_handle(adev),
+ "mipi-sdw-manager-list", &sdw_bitmap, 1);
+ if (ret) {
+ dev_err(&adev->dev,
+ "Failed to read mipi-sdw-manager-list: %d\n", ret);
+ return -EINVAL;
+ }
+ count = hweight32(sdw_bitmap);
+ /* Check count is within bounds */
+ if (count > info->count) {
+ dev_err(&adev->dev, "Manager count %d exceeds max %d\n",
+ count, info->count);
+ return -EINVAL;
+ }
+
+ if (!count) {
+ dev_dbg(&adev->dev, "No SoundWire Managers detected\n");
+ return -EINVAL;
+ }
+ dev_dbg(&adev->dev, "ACPI reports %d SoundWire Manager devices\n", count);
+ info->link_mask = sdw_bitmap;
+ return 0;
+}
+EXPORT_SYMBOL_NS(amd_sdw_scan_controller, SND_AMD_SOUNDWIRE_ACPI);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("AMD SoundWire ACPI helpers");
diff --git a/sound/soc/amd/acp/amd.h b/sound/soc/amd/acp/amd.h
index 5017e868f3..d75b4eb34d 100644
--- a/sound/soc/amd/acp/amd.h
+++ b/sound/soc/amd/acp/amd.h
@@ -138,6 +138,9 @@ struct acp_chip_info {
void __iomem *base; /* ACP memory PCI base */
struct platform_device *chip_pdev;
unsigned int flag; /* Distinguish b/w Legacy or Only PDM */
+ bool is_pdm_dev; /* flag set to true when ACP PDM controller exists */
+ bool is_pdm_config; /* flag set to true when PDM configuration is selected from BIOS */
+ bool is_i2s_config; /* flag set to true when I2S configuration is selected from BIOS */
};
struct acp_stream {
@@ -212,6 +215,11 @@ enum acp_config {
ACP_CONFIG_13,
ACP_CONFIG_14,
ACP_CONFIG_15,
+ ACP_CONFIG_16,
+ ACP_CONFIG_17,
+ ACP_CONFIG_18,
+ ACP_CONFIG_19,
+ ACP_CONFIG_20,
};
extern const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops;
@@ -240,7 +248,7 @@ void restore_acp_pdm_params(struct snd_pcm_substream *substream,
int restore_acp_i2s_params(struct snd_pcm_substream *substream,
struct acp_dev_data *adata, struct acp_stream *stream);
-int check_acp_pdm(struct pci_dev *pci, struct acp_chip_info *chip);
+void check_acp_config(struct pci_dev *pci, struct acp_chip_info *chip);
static inline u64 acp_get_byte_count(struct acp_dev_data *adata, int dai_id, int direction)
{
diff --git a/sound/soc/amd/acp/chip_offset_byte.h b/sound/soc/amd/acp/chip_offset_byte.h
index cfd6c4d075..18da734c0e 100644
--- a/sound/soc/amd/acp/chip_offset_byte.h
+++ b/sound/soc/amd/acp/chip_offset_byte.h
@@ -20,6 +20,7 @@
#define ACP_SOFT_RESET 0x1000
#define ACP_CONTROL 0x1004
#define ACP_PIN_CONFIG 0x1440
+#define ACP3X_PIN_CONFIG 0x1400
#define ACP_EXTERNAL_INTR_REG_ADDR(adata, offset, ctrl) \
(adata->acp_base + adata->rsrc->irq_reg_offset + offset + (ctrl * 0x04))
diff --git a/sound/soc/amd/ps/Makefile b/sound/soc/amd/ps/Makefile
index f2a5eaf2fa..b3c254886f 100644
--- a/sound/soc/amd/ps/Makefile
+++ b/sound/soc/amd/ps/Makefile
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0+
+# SPDX-License-Identifier: GPL-2.0-only
# Pink Sardine platform Support
snd-pci-ps-objs := pci-ps.o
snd-ps-pdm-dma-objs := ps-pdm-dma.o
diff --git a/sound/soc/amd/ps/acp63.h b/sound/soc/amd/ps/acp63.h
index 8b853b8d02..39208305dd 100644
--- a/sound/soc/amd/ps/acp63.h
+++ b/sound/soc/amd/ps/acp63.h
@@ -5,12 +5,12 @@
* 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
#define ACP63_REG_START 0x1240000
-#define ACP63_REG_END 0x1250200
-#define ACP63_DEVS 5
+#define ACP63_REG_END 0x125C000
#define ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK 0x00010001
#define ACP_PGFSM_CNTL_POWER_ON_MASK 1
@@ -55,32 +55,6 @@
#define ACP_DMIC_DEV 2
-/* ACP63_PDM_MODE_DEVS corresponds to platform devices count for ACP PDM configuration */
-#define ACP63_PDM_MODE_DEVS 3
-
-/*
- * ACP63_SDW0_MODE_DEVS corresponds to platform devices count for
- * SW0 SoundWire manager instance configuration
- */
-#define ACP63_SDW0_MODE_DEVS 2
-
-/*
- * ACP63_SDW0_SDW1_MODE_DEVS corresponds to platform devices count for SW0 + SW1 SoundWire manager
- * instances configuration
- */
-#define ACP63_SDW0_SDW1_MODE_DEVS 3
-
-/*
- * ACP63_SDW0_PDM_MODE_DEVS corresponds to platform devices count for SW0 manager
- * instance + ACP PDM controller configuration
- */
-#define ACP63_SDW0_PDM_MODE_DEVS 4
-
-/*
- * ACP63_SDW0_SDW1_PDM_MODE_DEVS corresponds to platform devices count for
- * SW0 + SW1 SoundWire manager instances + ACP PDM controller configuration
- */
-#define ACP63_SDW0_SDW1_PDM_MODE_DEVS 5
#define ACP63_DMIC_ADDR 2
#define ACP63_SDW_ADDR 5
#define AMD_SDW_MAX_MANAGERS 2
@@ -88,17 +62,6 @@
/* time in ms for acp timeout */
#define ACP_TIMEOUT 500
-/* ACP63_PDM_DEV_CONFIG corresponds to platform device configuration for ACP PDM controller */
-#define ACP63_PDM_DEV_CONFIG BIT(0)
-
-/* ACP63_SDW_DEV_CONFIG corresponds to platform device configuration for SDW manager instances */
-#define ACP63_SDW_DEV_CONFIG BIT(1)
-
-/*
- * ACP63_SDW_PDM_DEV_CONFIG corresponds to platform device configuration for ACP PDM + SoundWire
- * manager instance combination.
- */
-#define ACP63_SDW_PDM_DEV_CONFIG GENMASK(1, 0)
#define ACP_SDW0_STAT BIT(21)
#define ACP_SDW1_STAT BIT(2)
#define ACP_ERROR_IRQ BIT(29)
@@ -253,38 +216,46 @@ struct sdw_dma_ring_buf_reg {
* struct acp63_dev_data - acp pci driver context
* @acp63_base: acp mmio base
* @res: resource
- * @pdev: array of child platform device node structures
+ * @pdm_dev: ACP PDM controller platform device
+ * @dmic_codec: platform device for DMIC Codec
+ * sdw_dma_dev: platform device for SoundWire DMA controller
+ * @mach_dev: platform device for machine driver to support ACP PDM/SoundWire configuration
* @acp_lock: used to protect acp common registers
- * @sdw_fw_node: SoundWire controller fw node handle
- * @pdev_config: platform device configuration
- * @pdev_count: platform devices count
- * @pdm_dev_index: pdm platform device index
- * @sdw_manager_count: SoundWire manager instance count
- * @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
+ * @sdw: SoundWire context for all SoundWire manager instances
+ * @machine: ACPI machines for SoundWire interface
+ * @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
+ * @sdw_en_stat: flag set to true when any one of the SoundWire manager instance is enabled
+ * @addr: pci ioremap address
+ * @reg_range: ACP reigister range
* @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
- * the active SoundWire manager instances
*/
struct acp63_dev_data {
void __iomem *acp63_base;
struct resource *res;
- struct platform_device *pdev[ACP63_DEVS];
+ struct platform_device *pdm_dev;
+ struct platform_device *dmic_codec_dev;
+ struct platform_device *sdw_dma_dev;
+ struct platform_device *mach_dev;
struct mutex acp_lock; /* protect shared registers */
- struct fwnode_handle *sdw_fw_node;
- u16 pdev_config;
- u16 pdev_count;
- u16 pdm_dev_index;
- u8 sdw_manager_count;
- u16 sdw0_dev_index;
- u16 sdw1_dev_index;
- u16 sdw_dma_dev_index;
+ struct sdw_amd_acpi_info info;
+ /* sdw context allocated by SoundWire driver */
+ struct sdw_amd_ctx *sdw;
+ struct snd_soc_acpi_mach *machines;
+ bool is_sdw_dev;
+ bool is_pdm_dev;
+ bool is_pdm_config;
+ bool is_sdw_config;
+ bool sdw_en_stat;
+ u32 addr;
+ u32 reg_range;
u16 sdw0_dma_intr_stat[ACP63_SDW0_DMA_MAX_STREAMS];
u16 sdw1_dma_intr_stat[ACP63_SDW1_DMA_MAX_STREAMS];
- bool acp_reset;
};
int snd_amd_acp_find_config(struct pci_dev *pci);
diff --git a/sound/soc/amd/ps/pci-ps.c b/sound/soc/amd/ps/pci-ps.c
index 5927eef041..c72d666d51 100644
--- a/sound/soc/amd/ps/pci-ps.c
+++ b/sound/soc/amd/ps/pci-ps.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0+
+// SPDX-License-Identifier: GPL-2.0-only
/*
* AMD Pink Sardine ACP PCI Driver
*
@@ -17,6 +17,7 @@
#include <linux/pm_runtime.h>
#include <linux/iopoll.h>
#include <linux/soundwire/sdw_amd.h>
+#include "../mach-config.h"
#include "acp63.h"
@@ -104,10 +105,8 @@ static irqreturn_t acp63_irq_thread(int irq, void *context)
struct sdw_dma_dev_data *sdw_dma_data;
struct acp63_dev_data *adata = context;
u32 stream_index;
- u16 pdev_index;
- pdev_index = adata->sdw_dma_dev_index;
- sdw_dma_data = dev_get_drvdata(&adata->pdev[pdev_index]->dev);
+ sdw_dma_data = dev_get_drvdata(&adata->sdw_dma_dev->dev);
for (stream_index = 0; stream_index < ACP63_SDW0_DMA_MAX_STREAMS; stream_index++) {
if (adata->sdw0_dma_intr_stat[stream_index]) {
@@ -135,7 +134,6 @@ static irqreturn_t acp63_irq_handler(int irq, void *dev_id)
u32 stream_id = 0;
u16 irq_flag = 0;
u16 sdw_dma_irq_flag = 0;
- u16 pdev_index;
u16 index;
adata = dev_id;
@@ -149,8 +147,7 @@ static irqreturn_t acp63_irq_handler(int irq, void *dev_id)
ext_intr_stat = readl(adata->acp63_base + ACP_EXTERNAL_INTR_STAT);
if (ext_intr_stat & ACP_SDW0_STAT) {
writel(ACP_SDW0_STAT, adata->acp63_base + ACP_EXTERNAL_INTR_STAT);
- pdev_index = adata->sdw0_dev_index;
- amd_manager = dev_get_drvdata(&adata->pdev[pdev_index]->dev);
+ amd_manager = dev_get_drvdata(&adata->sdw->pdev[0]->dev);
if (amd_manager)
schedule_work(&amd_manager->amd_sdw_irq_thread);
irq_flag = 1;
@@ -159,8 +156,7 @@ static irqreturn_t acp63_irq_handler(int irq, void *dev_id)
ext_intr_stat1 = readl(adata->acp63_base + ACP_EXTERNAL_INTR_STAT1);
if (ext_intr_stat1 & ACP_SDW1_STAT) {
writel(ACP_SDW1_STAT, adata->acp63_base + ACP_EXTERNAL_INTR_STAT1);
- pdev_index = adata->sdw1_dev_index;
- amd_manager = dev_get_drvdata(&adata->pdev[pdev_index]->dev);
+ amd_manager = dev_get_drvdata(&adata->sdw->pdev[1]->dev);
if (amd_manager)
schedule_work(&amd_manager->amd_sdw_irq_thread);
irq_flag = 1;
@@ -176,8 +172,7 @@ static irqreturn_t acp63_irq_handler(int irq, void *dev_id)
}
if (ext_intr_stat & BIT(PDM_DMA_STAT)) {
- pdev_index = adata->pdm_dev_index;
- ps_pdm_data = dev_get_drvdata(&adata->pdev[pdev_index]->dev);
+ ps_pdm_data = dev_get_drvdata(&adata->pdm_dev->dev);
writel(BIT(PDM_DMA_STAT), adata->acp63_base + ACP_EXTERNAL_INTR_STAT);
if (ps_pdm_data->capture_stream)
snd_pcm_period_elapsed(ps_pdm_data->capture_stream);
@@ -237,122 +232,165 @@ 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;
+
+ acp_data = dev_get_drvdata(dev);
+ if (!addr)
+ return -ENODEV;
+
+ sdw_dev = acpi_find_child_device(ACPI_COMPANION(dev), addr, 0);
+ if (!sdw_dev)
+ 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);
+}
+
+static int amd_sdw_probe(struct device *dev)
+{
+ struct acp63_dev_data *acp_data;
+ struct sdw_amd_res sdw_res;
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);
+ memset(&sdw_res, 0, sizeof(sdw_res));
+ sdw_res.addr = acp_data->addr;
+ sdw_res.reg_range = acp_data->reg_range;
+ sdw_res.handle = acp_data->info.handle;
+ sdw_res.parent = dev;
+ sdw_res.dev = dev;
+ sdw_res.acp_lock = &acp_data->acp_lock;
+ sdw_res.count = acp_data->info.count;
+ sdw_res.mmio_base = acp_data->acp63_base;
+ sdw_res.link_mask = acp_data->info.link_mask;
+ ret = sdw_amd_probe(&sdw_res, &acp_data->sdw);
+ if (ret)
+ dev_err(dev, "error: SoundWire probe failed\n");
+ return ret;
+}
- 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 (!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;
+static int amd_sdw_exit(struct acp63_dev_data *acp_data)
+{
+ if (acp_data->sdw)
+ sdw_amd_exit(acp_data->sdw);
+ acp_data->sdw = NULL;
+
+ return 0;
+}
+
+static struct snd_soc_acpi_mach *acp63_sdw_machine_select(struct device *dev)
+{
+ struct snd_soc_acpi_mach *mach;
+ const struct snd_soc_acpi_link_adr *link;
+ struct acp63_dev_data *acp_data = dev_get_drvdata(dev);
+ int ret, i;
+
+ if (acp_data->info.count) {
+ ret = sdw_amd_get_slave_info(acp_data->sdw);
+ if (ret) {
+ dev_dbg(dev, "failed to read slave information\n");
+ return NULL;
+ }
+ for (mach = acp_data->machines; mach; mach++) {
+ if (!mach->links)
+ break;
+ link = mach->links;
+ for (i = 0; i < acp_data->info.count && link->num_adr; link++, i++) {
+ if (!snd_soc_acpi_sdw_link_slaves_found(dev, link,
+ acp_data->sdw->ids,
+ acp_data->sdw->num_slaves))
+ break;
+ }
+ if (i == acp_data->info.count || !link->num_adr)
+ break;
+ }
+ if (mach && mach->link_mask) {
+ mach->mach_params.links = mach->links;
+ mach->mach_params.link_mask = mach->link_mask;
+ return mach;
}
+ }
+ dev_dbg(dev, "No SoundWire machine driver found\n");
+ return NULL;
+}
+#else
+static int acp_scan_sdw_devices(struct device *dev, u64 addr)
+{
+ return 0;
+}
- 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;
+static int amd_sdw_probe(struct device *dev)
+{
+ return 0;
+}
+
+static int amd_sdw_exit(struct acp63_dev_data *acp_data)
+{
+ return 0;
+}
+
+static struct snd_soc_acpi_mach *acp63_sdw_machine_select(struct device *dev)
+{
+ return NULL;
+}
+#endif
+
+static int acp63_machine_register(struct device *dev)
+{
+ struct snd_soc_acpi_mach *mach;
+ struct acp63_dev_data *adata = dev_get_drvdata(dev);
+ int size;
+
+ if (adata->is_sdw_dev && adata->is_sdw_config) {
+ size = sizeof(*adata->machines);
+ mach = acp63_sdw_machine_select(dev);
+ if (mach) {
+ adata->mach_dev = platform_device_register_data(dev, mach->drv_name,
+ PLATFORM_DEVID_NONE, mach,
+ size);
+ if (IS_ERR(adata->mach_dev)) {
+ dev_err(dev,
+ "cannot register Machine device for SoundWire Interface\n");
+ return PTR_ERR(adata->mach_dev);
+ }
+ }
+
+ } else if (adata->is_pdm_dev && !adata->is_sdw_dev && adata->is_pdm_config) {
+ adata->mach_dev = platform_device_register_data(dev, "acp_ps_mach",
+ PLATFORM_DEVID_NONE, NULL, 0);
+ if (IS_ERR(adata->mach_dev)) {
+ dev_err(dev, "cannot register amd_ps_mach device\n");
+ return PTR_ERR(adata->mach_dev);
}
}
return 0;
}
-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 +398,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;
}
@@ -418,17 +452,13 @@ static void acp63_fill_platform_dev_info(struct platform_device_info *pdevinfo,
static int create_acp63_platform_devs(struct pci_dev *pci, struct acp63_dev_data *adata, u32 addr)
{
- struct acp_sdw_pdata *sdw_pdata;
- struct platform_device_info pdevinfo[ACP63_DEVS];
+ struct platform_device_info pdevinfo;
struct device *parent;
- int index;
int ret;
parent = &pci->dev;
- dev_dbg(&pci->dev,
- "%s pdev_config:0x%x pdev_count:0x%x\n", __func__, adata->pdev_config,
- adata->pdev_count);
- if (adata->pdev_config) {
+
+ if (adata->is_sdw_dev || adata->is_pdm_dev) {
adata->res = devm_kzalloc(&pci->dev, sizeof(struct resource), GFP_KERNEL);
if (!adata->res) {
ret = -ENOMEM;
@@ -440,130 +470,57 @@ static int create_acp63_platform_devs(struct pci_dev *pci, struct acp63_dev_data
memset(&pdevinfo, 0, sizeof(pdevinfo));
}
- switch (adata->pdev_config) {
- case ACP63_PDM_DEV_CONFIG:
- adata->pdm_dev_index = 0;
- acp63_fill_platform_dev_info(&pdevinfo[0], parent, NULL, "acp_ps_pdm_dma",
+ if (adata->is_pdm_dev && adata->is_pdm_config) {
+ acp63_fill_platform_dev_info(&pdevinfo, parent, NULL, "acp_ps_pdm_dma",
0, adata->res, 1, NULL, 0);
- acp63_fill_platform_dev_info(&pdevinfo[1], parent, NULL, "dmic-codec",
- 0, NULL, 0, NULL, 0);
- acp63_fill_platform_dev_info(&pdevinfo[2], parent, NULL, "acp_ps_mach",
- 0, NULL, 0, NULL, 0);
- break;
- case ACP63_SDW_DEV_CONFIG:
- if (adata->pdev_count == ACP63_SDW0_MODE_DEVS) {
- sdw_pdata = devm_kzalloc(&pci->dev, sizeof(struct acp_sdw_pdata),
- GFP_KERNEL);
- if (!sdw_pdata) {
- ret = -ENOMEM;
- goto de_init;
- }
- sdw_pdata->instance = 0;
- sdw_pdata->acp_sdw_lock = &adata->acp_lock;
- adata->sdw0_dev_index = 0;
- adata->sdw_dma_dev_index = 1;
- acp63_fill_platform_dev_info(&pdevinfo[0], parent, adata->sdw_fw_node,
- "amd_sdw_manager", 0, adata->res, 1,
- sdw_pdata, sizeof(struct acp_sdw_pdata));
- acp63_fill_platform_dev_info(&pdevinfo[1], parent, NULL, "amd_ps_sdw_dma",
- 0, adata->res, 1, NULL, 0);
- } else if (adata->pdev_count == ACP63_SDW0_SDW1_MODE_DEVS) {
- sdw_pdata = devm_kzalloc(&pci->dev, sizeof(struct acp_sdw_pdata) * 2,
- GFP_KERNEL);
- if (!sdw_pdata) {
- ret = -ENOMEM;
- goto de_init;
- }
-
- sdw_pdata[0].instance = 0;
- sdw_pdata[1].instance = 1;
- sdw_pdata[0].acp_sdw_lock = &adata->acp_lock;
- sdw_pdata[1].acp_sdw_lock = &adata->acp_lock;
- sdw_pdata->acp_sdw_lock = &adata->acp_lock;
- adata->sdw0_dev_index = 0;
- adata->sdw1_dev_index = 1;
- adata->sdw_dma_dev_index = 2;
- acp63_fill_platform_dev_info(&pdevinfo[0], parent, adata->sdw_fw_node,
- "amd_sdw_manager", 0, adata->res, 1,
- &sdw_pdata[0], sizeof(struct acp_sdw_pdata));
- acp63_fill_platform_dev_info(&pdevinfo[1], parent, adata->sdw_fw_node,
- "amd_sdw_manager", 1, adata->res, 1,
- &sdw_pdata[1], sizeof(struct acp_sdw_pdata));
- acp63_fill_platform_dev_info(&pdevinfo[2], parent, NULL, "amd_ps_sdw_dma",
- 0, adata->res, 1, NULL, 0);
+ adata->pdm_dev = platform_device_register_full(&pdevinfo);
+ if (IS_ERR(adata->pdm_dev)) {
+ dev_err(&pci->dev,
+ "cannot register %s device\n", pdevinfo.name);
+ ret = PTR_ERR(adata->pdm_dev);
+ goto de_init;
}
- break;
- case ACP63_SDW_PDM_DEV_CONFIG:
- if (adata->pdev_count == ACP63_SDW0_PDM_MODE_DEVS) {
- sdw_pdata = devm_kzalloc(&pci->dev, sizeof(struct acp_sdw_pdata),
- GFP_KERNEL);
- if (!sdw_pdata) {
- ret = -ENOMEM;
- goto de_init;
- }
-
- sdw_pdata->instance = 0;
- sdw_pdata->acp_sdw_lock = &adata->acp_lock;
- adata->pdm_dev_index = 0;
- adata->sdw0_dev_index = 1;
- adata->sdw_dma_dev_index = 2;
- acp63_fill_platform_dev_info(&pdevinfo[0], parent, NULL, "acp_ps_pdm_dma",
- 0, adata->res, 1, NULL, 0);
- acp63_fill_platform_dev_info(&pdevinfo[1], parent, adata->sdw_fw_node,
- "amd_sdw_manager", 0, adata->res, 1,
- sdw_pdata, sizeof(struct acp_sdw_pdata));
- acp63_fill_platform_dev_info(&pdevinfo[2], parent, NULL, "amd_ps_sdw_dma",
- 0, adata->res, 1, NULL, 0);
- acp63_fill_platform_dev_info(&pdevinfo[3], parent, NULL, "dmic-codec",
- 0, NULL, 0, NULL, 0);
- } else if (adata->pdev_count == ACP63_SDW0_SDW1_PDM_MODE_DEVS) {
- sdw_pdata = devm_kzalloc(&pci->dev, sizeof(struct acp_sdw_pdata) * 2,
- GFP_KERNEL);
- if (!sdw_pdata) {
- ret = -ENOMEM;
- goto de_init;
- }
- sdw_pdata[0].instance = 0;
- sdw_pdata[1].instance = 1;
- sdw_pdata[0].acp_sdw_lock = &adata->acp_lock;
- sdw_pdata[1].acp_sdw_lock = &adata->acp_lock;
- adata->pdm_dev_index = 0;
- adata->sdw0_dev_index = 1;
- adata->sdw1_dev_index = 2;
- adata->sdw_dma_dev_index = 3;
- acp63_fill_platform_dev_info(&pdevinfo[0], parent, NULL, "acp_ps_pdm_dma",
- 0, adata->res, 1, NULL, 0);
- acp63_fill_platform_dev_info(&pdevinfo[1], parent, adata->sdw_fw_node,
- "amd_sdw_manager", 0, adata->res, 1,
- &sdw_pdata[0], sizeof(struct acp_sdw_pdata));
- acp63_fill_platform_dev_info(&pdevinfo[2], parent, adata->sdw_fw_node,
- "amd_sdw_manager", 1, adata->res, 1,
- &sdw_pdata[1], sizeof(struct acp_sdw_pdata));
- acp63_fill_platform_dev_info(&pdevinfo[3], parent, NULL, "amd_ps_sdw_dma",
- 0, adata->res, 1, NULL, 0);
- acp63_fill_platform_dev_info(&pdevinfo[4], parent, NULL, "dmic-codec",
- 0, NULL, 0, NULL, 0);
+ memset(&pdevinfo, 0, sizeof(pdevinfo));
+ acp63_fill_platform_dev_info(&pdevinfo, parent, NULL, "dmic-codec",
+ 0, NULL, 0, NULL, 0);
+ adata->dmic_codec_dev = platform_device_register_full(&pdevinfo);
+ if (IS_ERR(adata->dmic_codec_dev)) {
+ dev_err(&pci->dev,
+ "cannot register %s device\n", pdevinfo.name);
+ ret = PTR_ERR(adata->dmic_codec_dev);
+ goto unregister_pdm_dev;
}
- break;
- default:
- dev_dbg(&pci->dev, "No PDM or SoundWire manager devices found\n");
- return 0;
}
+ if (adata->is_sdw_dev && adata->is_sdw_config) {
+ ret = amd_sdw_probe(&pci->dev);
+ if (ret) {
+ if (adata->is_pdm_dev)
+ goto unregister_dmic_codec_dev;
+ else
+ goto de_init;
+ }
+ memset(&pdevinfo, 0, sizeof(pdevinfo));
+ acp63_fill_platform_dev_info(&pdevinfo, parent, NULL, "amd_ps_sdw_dma",
+ 0, adata->res, 1, NULL, 0);
- for (index = 0; index < adata->pdev_count; index++) {
- adata->pdev[index] = platform_device_register_full(&pdevinfo[index]);
- if (IS_ERR(adata->pdev[index])) {
+ adata->sdw_dma_dev = platform_device_register_full(&pdevinfo);
+ if (IS_ERR(adata->sdw_dma_dev)) {
dev_err(&pci->dev,
- "cannot register %s device\n", pdevinfo[index].name);
- ret = PTR_ERR(adata->pdev[index]);
- goto unregister_devs;
+ "cannot register %s device\n", pdevinfo.name);
+ ret = PTR_ERR(adata->sdw_dma_dev);
+ if (adata->is_pdm_dev)
+ goto unregister_dmic_codec_dev;
+ else
+ goto de_init;
}
}
+
return 0;
-unregister_devs:
- for (--index; index >= 0; index--)
- platform_device_unregister(adata->pdev[index]);
+unregister_dmic_codec_dev:
+ platform_device_unregister(adata->dmic_codec_dev);
+unregister_pdm_dev:
+ platform_device_unregister(adata->pdm_dev);
de_init:
if (acp63_deinit(adata->acp63_base, &pci->dev))
dev_err(&pci->dev, "ACP de-init failed\n");
@@ -576,7 +533,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;
@@ -618,13 +574,8 @@ static int snd_acp63_probe(struct pci_dev *pci,
ret = -ENOMEM;
goto release_regions;
}
- /*
- * By default acp_reset flag is set to true. i.e acp_deinit() and acp_init()
- * will be invoked for all ACP configurations during suspend/resume callbacks.
- * This flag should be set to false only when SoundWire manager power mode
- * set to ClockStopMode.
- */
- adata->acp_reset = true;
+ adata->addr = addr;
+ adata->reg_range = ACP63_REG_END - ACP63_REG_START;
pci_set_master(pci);
pci_set_drvdata(pci, adata);
mutex_init(&adata->acp_lock);
@@ -637,8 +588,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);
@@ -649,6 +599,11 @@ static int snd_acp63_probe(struct pci_dev *pci,
dev_err(&pci->dev, "ACP platform devices creation failed\n");
goto de_init;
}
+ ret = acp63_machine_register(&pci->dev);
+ if (ret) {
+ dev_err(&pci->dev, "ACP machine register failed\n");
+ goto de_init;
+ }
skip_pdev_creation:
device_set_wakeup_enable(&pci->dev, true);
pm_runtime_set_autosuspend_delay(&pci->dev, ACP_SUSPEND_DELAY_MS);
@@ -667,47 +622,103 @@ disable_pci:
return ret;
}
+static bool check_acp_sdw_enable_status(struct acp63_dev_data *adata)
+{
+ u32 sdw0_en, sdw1_en;
+
+ sdw0_en = readl(adata->acp63_base + ACP_SW0_EN);
+ sdw1_en = readl(adata->acp63_base + ACP_SW1_EN);
+ return (sdw0_en || sdw1_en);
+}
+
+static void handle_acp63_sdw_pme_event(struct acp63_dev_data *adata)
+{
+ u32 val;
+
+ val = readl(adata->acp63_base + ACP_SW0_WAKE_EN);
+ if (val && adata->sdw->pdev[0])
+ pm_request_resume(&adata->sdw->pdev[0]->dev);
+
+ val = readl(adata->acp63_base + ACP_SW1_WAKE_EN);
+ if (val && adata->sdw->pdev[1])
+ pm_request_resume(&adata->sdw->pdev[1]->dev);
+}
+
static int __maybe_unused snd_acp63_suspend(struct device *dev)
{
struct acp63_dev_data *adata;
- int ret = 0;
+ int ret;
adata = dev_get_drvdata(dev);
- if (adata->acp_reset) {
- ret = acp63_deinit(adata->acp63_base, dev);
- if (ret)
- dev_err(dev, "ACP de-init failed\n");
+ if (adata->is_sdw_dev) {
+ adata->sdw_en_stat = check_acp_sdw_enable_status(adata);
+ if (adata->sdw_en_stat)
+ return 0;
}
+ ret = acp63_deinit(adata->acp63_base, dev);
+ if (ret)
+ dev_err(dev, "ACP de-init failed\n");
+
return ret;
}
-static int __maybe_unused snd_acp63_resume(struct device *dev)
+static int __maybe_unused snd_acp63_runtime_resume(struct device *dev)
{
struct acp63_dev_data *adata;
- int ret = 0;
+ int ret;
adata = dev_get_drvdata(dev);
- if (adata->acp_reset) {
- ret = acp63_init(adata->acp63_base, dev);
- if (ret)
- dev_err(dev, "ACP init failed\n");
+ if (adata->sdw_en_stat)
+ return 0;
+
+ ret = acp63_init(adata->acp63_base, dev);
+ if (ret) {
+ dev_err(dev, "ACP init failed\n");
+ return ret;
}
+
+ if (!adata->sdw_en_stat)
+ handle_acp63_sdw_pme_event(adata);
+ return 0;
+}
+
+static int __maybe_unused snd_acp63_resume(struct device *dev)
+{
+ struct acp63_dev_data *adata;
+ int ret;
+
+ adata = dev_get_drvdata(dev);
+ if (adata->sdw_en_stat)
+ return 0;
+
+ ret = acp63_init(adata->acp63_base, dev);
+ if (ret)
+ dev_err(dev, "ACP init failed\n");
+
return ret;
}
static const struct dev_pm_ops acp63_pm_ops = {
- SET_RUNTIME_PM_OPS(snd_acp63_suspend, snd_acp63_resume, NULL)
+ SET_RUNTIME_PM_OPS(snd_acp63_suspend, snd_acp63_runtime_resume, NULL)
SET_SYSTEM_SLEEP_PM_OPS(snd_acp63_suspend, snd_acp63_resume)
};
static void snd_acp63_remove(struct pci_dev *pci)
{
struct acp63_dev_data *adata;
- int ret, index;
+ int ret;
adata = pci_get_drvdata(pci);
- for (index = 0; index < adata->pdev_count; index++)
- platform_device_unregister(adata->pdev[index]);
+ if (adata->sdw) {
+ amd_sdw_exit(adata);
+ platform_device_unregister(adata->sdw_dma_dev);
+ }
+ if (adata->is_pdm_dev) {
+ platform_device_unregister(adata->pdm_dev);
+ platform_device_unregister(adata->dmic_codec_dev);
+ }
+ if (adata->mach_dev)
+ platform_device_unregister(adata->mach_dev);
ret = acp63_deinit(adata->acp63_base, &pci->dev);
if (ret)
dev_err(&pci->dev, "ACP de-init failed\n");
@@ -740,4 +751,6 @@ 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(SOUNDWIRE_AMD_INIT);
+MODULE_IMPORT_NS(SND_AMD_SOUNDWIRE_ACPI);
MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/amd/ps/ps-mach.c b/sound/soc/amd/ps/ps-mach.c
index 3ffbe4fdaf..e675b8f569 100644
--- a/sound/soc/amd/ps/ps-mach.c
+++ b/sound/soc/amd/ps/ps-mach.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0+
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Machine driver for AMD Pink Sardine platform using DMIC
*
diff --git a/sound/soc/amd/ps/ps-pdm-dma.c b/sound/soc/amd/ps/ps-pdm-dma.c
index d48f7c5af2..7bbacbab10 100644
--- a/sound/soc/amd/ps/ps-pdm-dma.c
+++ b/sound/soc/amd/ps/ps-pdm-dma.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0+
+// SPDX-License-Identifier: GPL-2.0-only
/*
* AMD ALSA SoC Pink Sardine PDM Driver
*
diff --git a/sound/soc/amd/ps/ps-sdw-dma.c b/sound/soc/amd/ps/ps-sdw-dma.c
index 9b59063798..66b800962f 100644
--- a/sound/soc/amd/ps/ps-sdw-dma.c
+++ b/sound/soc/amd/ps/ps-sdw-dma.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0+
+// SPDX-License-Identifier: GPL-2.0-only
/*
* AMD ALSA SoC Pink Sardine SoundWire DMA Driver
*