summaryrefslogtreecommitdiffstats
path: root/sound/soc/sof/amd
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/sof/amd')
-rw-r--r--sound/soc/sof/amd/Kconfig18
-rw-r--r--sound/soc/sof/amd/acp-common.c65
-rw-r--r--sound/soc/sof/amd/acp-dsp-offset.h10
-rw-r--r--sound/soc/sof/amd/acp-loader.c32
-rw-r--r--sound/soc/sof/amd/acp.c232
-rw-r--r--sound/soc/sof/amd/acp.h26
-rw-r--r--sound/soc/sof/amd/pci-acp63.c7
7 files changed, 360 insertions, 30 deletions
diff --git a/sound/soc/sof/amd/Kconfig b/sound/soc/sof/amd/Kconfig
index 19c5e27a193f..2729c6eb3feb 100644
--- a/sound/soc/sof/amd/Kconfig
+++ b/sound/soc/sof/amd/Kconfig
@@ -6,6 +6,7 @@
config SND_SOC_SOF_AMD_TOPLEVEL
tristate "SOF support for AMD audio DSPs"
+ depends on SOUNDWIRE_AMD || !SOUNDWIRE_AMD
depends on X86 || COMPILE_TEST
help
This adds support for Sound Open Firmware for AMD platforms.
@@ -60,10 +61,27 @@ config SND_SOC_SOF_ACP_PROBES
This option is not user-selectable but automatically handled by
'select' statements at a higher level
+config SND_SOC_SOF_AMD_SOUNDWIRE_LINK_BASELINE
+ tristate
+ select SND_AMD_SOUNDWIRE_ACPI if ACPI
+
+config SND_SOC_SOF_AMD_SOUNDWIRE
+ tristate "SOF support for SoundWire based AMD platforms"
+ default SND_SOC_SOF_AMD_SOUNDWIRE_LINK_BASELINE
+ depends on SND_SOC_SOF_AMD_SOUNDWIRE_LINK_BASELINE
+ depends on ACPI
+ depends on SOUNDWIRE_AMD
+ help
+ This adds support for SoundWire with Sound Open Firmware
+ for AMD platforms.
+ Say Y if you want to enable SoundWire links with SOF.
+ If unsure select "N".
+
config SND_SOC_SOF_AMD_ACP63
tristate "SOF support for ACP6.3 platform"
depends on SND_SOC_SOF_PCI
select SND_SOC_SOF_AMD_COMMON
+ select SND_SOC_SOF_AMD_SOUNDWIRE_LINK_BASELINE
help
Select this option for SOF support on
AMD ACP6.3 version based platforms.
diff --git a/sound/soc/sof/amd/acp-common.c b/sound/soc/sof/amd/acp-common.c
index 2d72c6d55dc8..0fc4e20ec673 100644
--- a/sound/soc/sof/amd/acp-common.c
+++ b/sound/soc/sof/amd/acp-common.c
@@ -118,16 +118,72 @@ void amd_sof_dump(struct snd_sof_dev *sdev, u32 flags)
&panic_info, stack, AMD_STACK_DUMP_SIZE);
}
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_AMD_SOUNDWIRE)
+static int amd_sof_sdw_get_slave_info(struct snd_sof_dev *sdev)
+{
+ struct acp_dev_data *acp_data = sdev->pdata->hw_pdata;
+
+ return sdw_amd_get_slave_info(acp_data->sdw);
+}
+
+static struct snd_soc_acpi_mach *amd_sof_sdw_machine_select(struct snd_sof_dev *sdev)
+{
+ struct snd_soc_acpi_mach *mach;
+ const struct snd_soc_acpi_link_adr *link;
+ struct acp_dev_data *acp_data = sdev->pdata->hw_pdata;
+ int ret, i;
+
+ if (acp_data->info.count) {
+ ret = amd_sof_sdw_get_slave_info(sdev);
+ if (ret) {
+ dev_info(sdev->dev, "failed to read slave information\n");
+ return NULL;
+ }
+ for (mach = sdev->pdata->desc->alt_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(sdev->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;
+ mach->mach_params.platform = dev_name(sdev->dev);
+ return mach;
+ }
+ }
+ dev_info(sdev->dev, "No SoundWire machine driver found\n");
+ return NULL;
+}
+
+#else
+static struct snd_soc_acpi_mach *amd_sof_sdw_machine_select(struct snd_sof_dev *sdev)
+{
+ return NULL;
+}
+#endif
+
struct snd_soc_acpi_mach *amd_sof_machine_select(struct snd_sof_dev *sdev)
{
struct snd_sof_pdata *sof_pdata = sdev->pdata;
const struct sof_dev_desc *desc = sof_pdata->desc;
- struct snd_soc_acpi_mach *mach;
+ struct snd_soc_acpi_mach *mach = NULL;
- mach = snd_soc_acpi_find_machine(desc->machines);
+ if (desc->machines)
+ mach = snd_soc_acpi_find_machine(desc->machines);
if (!mach) {
- dev_warn(sdev->dev, "No matching ASoC machine driver found\n");
- return NULL;
+ mach = amd_sof_sdw_machine_select(sdev);
+ if (!mach) {
+ dev_warn(sdev->dev, "No matching ASoC machine driver found\n");
+ return NULL;
+ }
}
sof_pdata->tplg_filename = mach->sof_tplg_filename;
@@ -204,5 +260,6 @@ EXPORT_SYMBOL_NS(sof_acp_common_ops, SND_SOC_SOF_AMD_COMMON);
MODULE_IMPORT_NS(SND_SOC_SOF_AMD_COMMON);
MODULE_IMPORT_NS(SND_SOC_SOF_XTENSA);
+MODULE_IMPORT_NS(SOUNDWIRE_AMD_INIT);
MODULE_DESCRIPTION("ACP SOF COMMON Driver");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/sound/soc/sof/amd/acp-dsp-offset.h b/sound/soc/sof/amd/acp-dsp-offset.h
index a913f1cc4c80..59afbe2e0f42 100644
--- a/sound/soc/sof/amd/acp-dsp-offset.h
+++ b/sound/soc/sof/amd/acp-dsp-offset.h
@@ -65,7 +65,10 @@
/* Registers from ACP_INTR block */
#define ACP3X_EXT_INTR_STAT 0x1808
#define ACP5X_EXT_INTR_STAT 0x1808
+#define ACP6X_EXTERNAL_INTR_ENB 0x1A00
+#define ACP6X_EXTERNAL_INTR_CNTL 0x1A04
#define ACP6X_EXT_INTR_STAT 0x1A0C
+#define ACP6X_EXT_INTR_STAT1 0x1A10
#define ACP3X_DSP_SW_INTR_BASE 0x1814
#define ACP5X_DSP_SW_INTR_BASE 0x1814
@@ -78,6 +81,10 @@
#define ACP5X_AXI2DAGB_SEM_0 0x1884
#define ACP6X_AXI2DAGB_SEM_0 0x1874
+/* ACP common registers to report errors related to I2S & SoundWire interfaces */
+#define ACP_SW0_I2S_ERROR_REASON 0x18B4
+#define ACP_SW1_I2S_ERROR_REASON 0x1A50
+
/* Registers from ACP_SHA block */
#define ACP_SHA_DSP_FW_QUALIFIER 0x1C70
#define ACP_SHA_DMA_CMD 0x1CB0
@@ -96,4 +103,7 @@
/* Cache window registers */
#define ACP_DSP0_CACHE_OFFSET0 0x0420
#define ACP_DSP0_CACHE_SIZE0 0x0424
+
+#define ACP_SW0_EN 0x3000
+#define ACP_SW1_EN 0x3C00
#endif
diff --git a/sound/soc/sof/amd/acp-loader.c b/sound/soc/sof/amd/acp-loader.c
index e05eb7a86dd4..d2d21478399e 100644
--- a/sound/soc/sof/amd/acp-loader.c
+++ b/sound/soc/sof/amd/acp-loader.c
@@ -267,29 +267,49 @@ int acp_sof_load_signed_firmware(struct snd_sof_dev *sdev)
{
struct snd_sof_pdata *plat_data = sdev->pdata;
struct acp_dev_data *adata = plat_data->hw_pdata;
+ const char *fw_filename;
int ret;
- ret = request_firmware(&sdev->basefw.fw, adata->fw_code_bin, sdev->dev);
+ fw_filename = kasprintf(GFP_KERNEL, "%s/%s",
+ plat_data->fw_filename_prefix,
+ adata->fw_code_bin);
+ if (!fw_filename)
+ return -ENOMEM;
+
+ ret = request_firmware(&sdev->basefw.fw, fw_filename, sdev->dev);
if (ret < 0) {
+ kfree(fw_filename);
dev_err(sdev->dev, "sof signed firmware code bin is missing\n");
return ret;
} else {
- dev_dbg(sdev->dev, "request_firmware %s successful\n", adata->fw_code_bin);
+ dev_dbg(sdev->dev, "request_firmware %s successful\n", fw_filename);
}
+ kfree(fw_filename);
+
ret = snd_sof_dsp_block_write(sdev, SOF_FW_BLK_TYPE_IRAM, 0,
- (void *)sdev->basefw.fw->data, sdev->basefw.fw->size);
+ (void *)sdev->basefw.fw->data,
+ sdev->basefw.fw->size);
+
+ fw_filename = kasprintf(GFP_KERNEL, "%s/%s",
+ plat_data->fw_filename_prefix,
+ adata->fw_data_bin);
+ if (!fw_filename)
+ return -ENOMEM;
- ret = request_firmware(&adata->fw_dbin, adata->fw_data_bin, sdev->dev);
+ ret = request_firmware(&adata->fw_dbin, fw_filename, sdev->dev);
if (ret < 0) {
+ kfree(fw_filename);
dev_err(sdev->dev, "sof signed firmware data bin is missing\n");
return ret;
} else {
- dev_dbg(sdev->dev, "request_firmware %s successful\n", adata->fw_data_bin);
+ dev_dbg(sdev->dev, "request_firmware %s successful\n", fw_filename);
}
+ kfree(fw_filename);
ret = snd_sof_dsp_block_write(sdev, SOF_FW_BLK_TYPE_DRAM, 0,
- (void *)adata->fw_dbin->data, adata->fw_dbin->size);
+ (void *)adata->fw_dbin->data,
+ adata->fw_dbin->size);
return ret;
}
EXPORT_SYMBOL_NS(acp_sof_load_signed_firmware, SND_SOC_SOF_AMD_COMMON);
diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c
index 07632ae6ccf5..9b3c26210db3 100644
--- a/sound/soc/sof/amd/acp.c
+++ b/sound/soc/sof/amd/acp.c
@@ -28,11 +28,10 @@ MODULE_PARM_DESC(enable_fw_debug, "Enable Firmware debug");
const struct dmi_system_id acp_sof_quirk_table[] = {
{
- /* Valve Jupiter device */
+ /* Steam Deck OLED device */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Valve"),
DMI_MATCH(DMI_PRODUCT_NAME, "Galileo"),
- DMI_MATCH(DMI_PRODUCT_FAMILY, "Sephiroth"),
},
.driver_data = (void *)SECURED_FIRMWARE,
},
@@ -374,10 +373,13 @@ static irqreturn_t acp_irq_thread(int irq, void *context)
static irqreturn_t acp_irq_handler(int irq, void *dev_id)
{
+ struct amd_sdw_manager *amd_manager;
struct snd_sof_dev *sdev = dev_id;
const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
+ struct acp_dev_data *adata = sdev->pdata->hw_pdata;
unsigned int base = desc->dsp_intr_base;
unsigned int val;
+ int irq_flag = 0;
val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET);
if (val & ACP_DSP_TO_HOST_IRQ) {
@@ -386,7 +388,38 @@ static irqreturn_t acp_irq_handler(int irq, void *dev_id)
return IRQ_WAKE_THREAD;
}
- return IRQ_NONE;
+ val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->ext_intr_stat);
+ if (val & ACP_SDW0_IRQ_MASK) {
+ amd_manager = dev_get_drvdata(&adata->sdw->pdev[0]->dev);
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat, ACP_SDW0_IRQ_MASK);
+ if (amd_manager)
+ schedule_work(&amd_manager->amd_sdw_irq_thread);
+ irq_flag = 1;
+ }
+
+ if (val & ACP_ERROR_IRQ_MASK) {
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat, ACP_ERROR_IRQ_MASK);
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, base + ACP_SW0_I2S_ERROR_REASON, 0);
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, base + ACP_SW1_I2S_ERROR_REASON, 0);
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, base + ACP_ERROR_STATUS, 0);
+ irq_flag = 1;
+ }
+
+ if (desc->ext_intr_stat1) {
+ val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->ext_intr_stat1);
+ if (val & ACP_SDW1_IRQ_MASK) {
+ amd_manager = dev_get_drvdata(&adata->sdw->pdev[1]->dev);
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat1,
+ ACP_SDW1_IRQ_MASK);
+ if (amd_manager)
+ schedule_work(&amd_manager->amd_sdw_irq_thread);
+ irq_flag = 1;
+ }
+ }
+ if (irq_flag)
+ return IRQ_HANDLED;
+ else
+ return IRQ_NONE;
}
static int acp_power_on(struct snd_sof_dev *sdev)
@@ -442,6 +475,33 @@ static int acp_reset(struct snd_sof_dev *sdev)
if (desc->ext_intr_enb)
snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_enb, 0x01);
+ if (desc->ext_intr_cntl)
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_cntl, ACP_ERROR_IRQ_MASK);
+ return ret;
+}
+
+static int acp_dsp_reset(struct snd_sof_dev *sdev)
+{
+ unsigned int val;
+ int ret;
+
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SOFT_RESET, ACP_DSP_ASSERT_RESET);
+
+ ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, ACP_SOFT_RESET, val,
+ val & ACP_DSP_SOFT_RESET_DONE_MASK,
+ ACP_REG_POLL_INTERVAL, ACP_REG_POLL_TIMEOUT_US);
+ if (ret < 0) {
+ dev_err(sdev->dev, "timeout asserting reset\n");
+ return ret;
+ }
+
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SOFT_RESET, ACP_DSP_RELEASE_RESET);
+
+ ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, ACP_SOFT_RESET, val, !val,
+ ACP_REG_POLL_INTERVAL, ACP_REG_POLL_TIMEOUT_US);
+ if (ret < 0)
+ dev_err(sdev->dev, "timeout in releasing reset\n");
+
return ret;
}
@@ -461,10 +521,34 @@ static int acp_init(struct snd_sof_dev *sdev)
return acp_reset(sdev);
}
+static bool check_acp_sdw_enable_status(struct snd_sof_dev *sdev)
+{
+ struct acp_dev_data *acp_data;
+ u32 sdw0_en, sdw1_en;
+
+ acp_data = sdev->pdata->hw_pdata;
+ if (!acp_data->sdw)
+ return false;
+
+ sdw0_en = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SW0_EN);
+ sdw1_en = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SW1_EN);
+ acp_data->sdw_en_stat = sdw0_en || sdw1_en;
+ return acp_data->sdw_en_stat;
+}
+
int amd_sof_acp_suspend(struct snd_sof_dev *sdev, u32 target_state)
{
int ret;
+ /* When acp_reset() function is invoked, it will apply ACP SOFT reset and
+ * DSP reset. ACP Soft reset sequence will cause all ACP IP registers will
+ * be reset to default values which will break the ClockStop Mode functionality.
+ * Add a condition check to apply DSP reset when SoundWire ClockStop mode
+ * is selected. For the rest of the scenarios, apply acp reset sequence.
+ */
+ if (check_acp_sdw_enable_status(sdev))
+ return acp_dsp_reset(sdev);
+
ret = acp_reset(sdev);
if (ret) {
dev_err(sdev->dev, "ACP Reset failed\n");
@@ -480,20 +564,100 @@ EXPORT_SYMBOL_NS(amd_sof_acp_suspend, SND_SOC_SOF_AMD_COMMON);
int amd_sof_acp_resume(struct snd_sof_dev *sdev)
{
int ret;
+ struct acp_dev_data *acp_data;
- ret = acp_init(sdev);
- if (ret) {
- dev_err(sdev->dev, "ACP Init failed\n");
- return ret;
+ acp_data = sdev->pdata->hw_pdata;
+ if (!acp_data->sdw_en_stat) {
+ ret = acp_init(sdev);
+ if (ret) {
+ dev_err(sdev->dev, "ACP Init failed\n");
+ return ret;
+ }
+ return acp_memory_init(sdev);
+ } else {
+ return acp_dsp_reset(sdev);
}
- return acp_memory_init(sdev);
}
EXPORT_SYMBOL_NS(amd_sof_acp_resume, SND_SOC_SOF_AMD_COMMON);
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_AMD_SOUNDWIRE)
+static int acp_sof_scan_sdw_devices(struct snd_sof_dev *sdev, u64 addr)
+{
+ struct acpi_device *sdw_dev;
+ struct acp_dev_data *acp_data;
+ const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
+
+ if (!addr)
+ return -ENODEV;
+
+ acp_data = sdev->pdata->hw_pdata;
+ sdw_dev = acpi_find_child_device(ACPI_COMPANION(sdev->dev), addr, 0);
+ if (!sdw_dev)
+ return -ENODEV;
+
+ acp_data->info.handle = sdw_dev->handle;
+ acp_data->info.count = desc->sdw_max_link_count;
+
+ return amd_sdw_scan_controller(&acp_data->info);
+}
+
+static int amd_sof_sdw_probe(struct snd_sof_dev *sdev)
+{
+ struct acp_dev_data *acp_data;
+ struct sdw_amd_res sdw_res;
+ int ret;
+
+ acp_data = sdev->pdata->hw_pdata;
+
+ 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 = sdev->dev;
+ sdw_res.dev = sdev->dev;
+ sdw_res.acp_lock = &acp_data->acp_lock;
+ sdw_res.count = acp_data->info.count;
+ sdw_res.link_mask = acp_data->info.link_mask;
+ sdw_res.mmio_base = sdev->bar[ACP_DSP_BAR];
+
+ ret = sdw_amd_probe(&sdw_res, &acp_data->sdw);
+ if (ret)
+ dev_err(sdev->dev, "SoundWire probe failed\n");
+ return ret;
+}
+
+static int amd_sof_sdw_exit(struct snd_sof_dev *sdev)
+{
+ struct acp_dev_data *acp_data;
+
+ acp_data = sdev->pdata->hw_pdata;
+ if (acp_data->sdw)
+ sdw_amd_exit(acp_data->sdw);
+ acp_data->sdw = NULL;
+
+ return 0;
+}
+
+#else
+static int acp_sof_scan_sdw_devices(struct snd_sof_dev *sdev, u64 addr)
+{
+ return 0;
+}
+
+static int amd_sof_sdw_probe(struct snd_sof_dev *sdev)
+{
+ return 0;
+}
+
+static int amd_sof_sdw_exit(struct snd_sof_dev *sdev)
+{
+ return 0;
+}
+#endif
+
int amd_sof_acp_probe(struct snd_sof_dev *sdev)
{
struct pci_dev *pci = to_pci_dev(sdev->dev);
- struct snd_sof_pdata *plat_data = sdev->pdata;
struct acp_dev_data *adata;
const struct sof_amd_acp_desc *chip;
const struct dmi_system_id *dmi_id;
@@ -526,7 +690,9 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev)
}
pci_set_master(pci);
-
+ adata->addr = addr;
+ adata->reg_range = chip->reg_end_addr - chip->reg_start_addr;
+ mutex_init(&adata->acp_lock);
sdev->pdata->hw_pdata = adata;
adata->smn_dev = pci_get_device(PCI_VENDOR_ID_AMD, chip->host_bridge_id, NULL);
if (!adata->smn_dev) {
@@ -548,6 +714,21 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev)
if (ret < 0)
goto free_ipc_irq;
+ /* scan SoundWire capabilities exposed by DSDT */
+ ret = acp_sof_scan_sdw_devices(sdev, chip->sdw_acpi_dev_addr);
+ if (ret < 0) {
+ dev_dbg(sdev->dev, "skipping SoundWire, not detected with ACPI scan\n");
+ goto skip_soundwire;
+ }
+ ret = amd_sof_sdw_probe(sdev);
+ if (ret < 0) {
+ dev_err(sdev->dev, "error: SoundWire probe error\n");
+ free_irq(sdev->ipc_irq, sdev);
+ pci_dev_put(adata->smn_dev);
+ return ret;
+ }
+
+skip_soundwire:
sdev->dsp_box.offset = 0;
sdev->dsp_box.size = BOX_SIZE_512;
@@ -560,17 +741,25 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev)
adata->signed_fw_image = false;
dmi_id = dmi_first_match(acp_sof_quirk_table);
if (dmi_id && dmi_id->driver_data) {
- adata->fw_code_bin = kasprintf(GFP_KERNEL, "%s/sof-%s-code.bin",
- plat_data->fw_filename_prefix,
- chip->name);
- adata->fw_data_bin = kasprintf(GFP_KERNEL, "%s/sof-%s-data.bin",
- plat_data->fw_filename_prefix,
- chip->name);
- adata->signed_fw_image = dmi_id->driver_data;
+ adata->fw_code_bin = devm_kasprintf(sdev->dev, GFP_KERNEL,
+ "sof-%s-code.bin",
+ chip->name);
+ if (!adata->fw_code_bin) {
+ ret = -ENOMEM;
+ goto free_ipc_irq;
+ }
- dev_dbg(sdev->dev, "fw_code_bin:%s, fw_data_bin:%s\n", adata->fw_code_bin,
- adata->fw_data_bin);
+ adata->fw_data_bin = devm_kasprintf(sdev->dev, GFP_KERNEL,
+ "sof-%s-data.bin",
+ chip->name);
+ if (!adata->fw_data_bin) {
+ ret = -ENOMEM;
+ goto free_ipc_irq;
+ }
+
+ adata->signed_fw_image = dmi_id->driver_data;
}
+
adata->enable_fw_debug = enable_fw_debug;
acp_memory_init(sdev);
@@ -595,6 +784,9 @@ void amd_sof_acp_remove(struct snd_sof_dev *sdev)
if (adata->smn_dev)
pci_dev_put(adata->smn_dev);
+ if (adata->sdw)
+ amd_sof_sdw_exit(sdev);
+
if (sdev->ipc_irq)
free_irq(sdev->ipc_irq, sdev);
@@ -606,4 +798,6 @@ void amd_sof_acp_remove(struct snd_sof_dev *sdev)
EXPORT_SYMBOL_NS(amd_sof_acp_remove, SND_SOC_SOF_AMD_COMMON);
MODULE_DESCRIPTION("AMD ACP sof driver");
+MODULE_IMPORT_NS(SOUNDWIRE_AMD_INIT);
+MODULE_IMPORT_NS(SND_AMD_SOUNDWIRE_ACPI);
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h
index c645aee216fd..947068da39b5 100644
--- a/sound/soc/sof/amd/acp.h
+++ b/sound/soc/sof/amd/acp.h
@@ -12,7 +12,7 @@
#define __SOF_AMD_ACP_H
#include <linux/dmi.h>
-
+#include <linux/soundwire/sdw_amd.h>
#include "../sof-priv.h"
#include "../sof-audio.h"
@@ -31,6 +31,9 @@
#define ACP_ASSERT_RESET 0x01
#define ACP_RELEASE_RESET 0x00
#define ACP_SOFT_RESET_DONE_MASK 0x00010001
+#define ACP_DSP_ASSERT_RESET 0x04
+#define ACP_DSP_RELEASE_RESET 0x00
+#define ACP_DSP_SOFT_RESET_DONE_MASK 0x00050004
#define ACP_DSP_INTR_EN_MASK 0x00000001
#define ACP3X_SRAM_PTE_OFFSET 0x02050000
@@ -93,8 +96,13 @@
#define PROBE_STATUS_BIT BIT(31)
#define ACP_FIRMWARE_SIGNATURE 0x100
+#define ACP_ERROR_IRQ_MASK BIT(29)
+#define ACP_SDW0_IRQ_MASK BIT(21)
+#define ACP_SDW1_IRQ_MASK BIT(2)
+#define SDW_ACPI_ADDR_ACP63 5
#define ACP_DEFAULT_SRAM_LENGTH 0x00080000
#define ACP_SRAM_PAGE_COUNT 128
+#define ACP6X_SDW_MAX_MANAGER_COUNT 2
enum clock_source {
ACP_CLOCK_96M = 0,
@@ -184,13 +192,19 @@ struct sof_amd_acp_desc {
unsigned int host_bridge_id;
u32 pgfsm_base;
u32 ext_intr_enb;
+ u32 ext_intr_cntl;
u32 ext_intr_stat;
+ u32 ext_intr_stat1;
u32 dsp_intr_base;
u32 sram_pte_offset;
u32 hw_semaphore_offset;
u32 acp_clkmux_sel;
u32 fusion_dsp_offset;
u32 probe_reg_offset;
+ u32 reg_start_addr;
+ u32 reg_end_addr;
+ u32 sdw_max_link_count;
+ u64 sdw_acpi_dev_addr;
};
/* Common device data struct for ACP devices */
@@ -199,6 +213,12 @@ struct acp_dev_data {
const struct firmware *fw_dbin;
/* DMIC device */
struct platform_device *dmic_dev;
+ /* mutex lock to protect ACP common registers access */
+ struct mutex acp_lock;
+ /* ACPI information stored between scan and probe steps */
+ struct sdw_amd_acpi_info info;
+ /* sdw context allocated by SoundWire driver */
+ struct sdw_amd_ctx *sdw;
unsigned int fw_bin_size;
unsigned int fw_data_bin_size;
unsigned int fw_sram_data_bin_size;
@@ -207,6 +227,9 @@ struct acp_dev_data {
const char *fw_sram_data_bin;
u32 fw_bin_page_count;
u32 fw_data_bin_page_count;
+ u32 addr;
+ u32 reg_range;
+ u32 blk_type;
dma_addr_t sha_dma_addr;
u8 *bin_buf;
dma_addr_t dma_addr;
@@ -222,6 +245,7 @@ struct acp_dev_data {
bool enable_fw_debug;
bool is_dram_in_use;
bool is_sram_in_use;
+ bool sdw_en_stat;
};
void memcpy_to_scratch(struct snd_sof_dev *sdev, u32 offset, unsigned int *src, size_t bytes);
diff --git a/sound/soc/sof/amd/pci-acp63.c b/sound/soc/sof/amd/pci-acp63.c
index bceb94ac80a9..eeaa12cceb23 100644
--- a/sound/soc/sof/amd/pci-acp63.c
+++ b/sound/soc/sof/amd/pci-acp63.c
@@ -31,12 +31,19 @@ static const struct sof_amd_acp_desc acp63_chip_info = {
.rev = 6,
.host_bridge_id = HOST_BRIDGE_ACP63,
.pgfsm_base = ACP6X_PGFSM_BASE,
+ .ext_intr_enb = ACP6X_EXTERNAL_INTR_ENB,
+ .ext_intr_cntl = ACP6X_EXTERNAL_INTR_CNTL,
.ext_intr_stat = ACP6X_EXT_INTR_STAT,
+ .ext_intr_stat1 = ACP6X_EXT_INTR_STAT1,
.dsp_intr_base = ACP6X_DSP_SW_INTR_BASE,
.sram_pte_offset = ACP6X_SRAM_PTE_OFFSET,
.hw_semaphore_offset = ACP6X_AXI2DAGB_SEM_0,
.fusion_dsp_offset = ACP6X_DSP_FUSION_RUNSTALL,
.probe_reg_offset = ACP6X_FUTURE_REG_ACLK_0,
+ .sdw_max_link_count = ACP6X_SDW_MAX_MANAGER_COUNT,
+ .sdw_acpi_dev_addr = SDW_ACPI_ADDR_ACP63,
+ .reg_start_addr = ACP6x_REG_START,
+ .reg_end_addr = ACP6x_REG_END,
};
static const struct sof_dev_desc acp63_desc = {