From 2dd49bce2d1e2b5614f931785aea4b462436e693 Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Thu, 3 Sep 2026 13:59:18 +0530 Subject: [PATCH 01/12] ASoC: SOF: amd: return -EINVAL for unknown PCI revision in acp7x suspend amd_sof_acp7x_suspend() is registered only for ACP7.B and ACP7.F platforms. If an unexpected PCI revision reaches the switch statement the default case previously fell through, leaving ACP_CONTROL with a stale value (enable=false) before writing ZSC_DSP_CTRL=1. Return -EINVAL instead to surface the programming error immediately. Fixes: 1c9646f3180e ("ASoC: SOF: amd: add system and runtime PM ops for ACP7x") Signed-off-by: Vijendar Mukunda --- sound/soc/sof/amd/acp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index f89ad86260b4ed..688df7acd2e21c 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -1197,7 +1197,8 @@ int amd_sof_acp7x_suspend(struct snd_sof_dev *sdev, u32 target_state) enable = true; break; default: - break; + dev_err(sdev->dev, "Unexpected PCI revision: 0x%x\n", acp_data->pci_rev); + return -EINVAL; } snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_CONTROL, enable); snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP7X_ZSC_DSP_CTRL, 1); From 6ff5434860bb2db32249feac8d2df83d314b77f5 Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Tue, 8 Sep 2026 18:19:22 +0530 Subject: [PATCH 02/12] ASoC: SOF: amd: fix amd_sof_acp_remove() teardown ordering Call free_irq() before amd_sof_sdw_exit() in amd_sof_acp_remove(). amd_sof_sdw_exit() sets adata->sdw to NULL; if an IRQ fires between that point and the subsequent free_irq(), acp_irq_handler() may dereference the now-NULL pdev[] pointer, causing a use-after-free. Fixes: d948218424bf ("ASoC: SOF: amd: add code for invoking soundwire manager helper functions") Signed-off-by: Vijendar Mukunda --- sound/soc/sof/amd/acp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index 688df7acd2e21c..e4cdb74c075db6 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -1048,12 +1048,12 @@ void amd_sof_acp_remove(struct snd_sof_dev *sdev) { struct acp_dev_data *adata = sdev->pdata->hw_pdata; - if (adata->sdw) - amd_sof_sdw_exit(sdev); - if (sdev->ipc_irq) free_irq(sdev->ipc_irq, sdev); + if (adata->sdw) + amd_sof_sdw_exit(sdev); + if (adata->dmic_dev) platform_device_unregister(adata->dmic_dev); From 97c71a62b0ba534fd8d34d2b0401f77b226b4b1f Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Wed, 9 Sep 2026 11:51:35 +0530 Subject: [PATCH 03/12] ASoC: SOF: amd: fix amd_sof_acp_probe() error unwind ordering Call amd_sof_sdw_exit() after free_irq() in the free_ipc_irq error label of amd_sof_acp_probe(). Without this, an IRQ that fires between sdw context teardown and free_irq() can dereference freed SoundWire resources. Fixes: d948218424bf ("ASoC: SOF: amd: add code for invoking soundwire manager helper functions") Signed-off-by: Vijendar Mukunda --- sound/soc/sof/amd/acp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index e4cdb74c075db6..5570f3d1348dd9 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -1038,6 +1038,8 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev) free_ipc_irq: free_irq(sdev->ipc_irq, sdev); + if (adata->sdw) + amd_sof_sdw_exit(sdev); unregister_dev: platform_device_unregister(adata->dmic_dev); return ret; From c87e1d77654636419f5233e8b27688e719a2c2bb Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Wed, 2 Sep 2026 18:32:51 +0530 Subject: [PATCH 04/12] ASoC: SOF: amd: add ACP7.B/7.F PDM controller scan and pdata propagation Add acp_sof_scan_pdm_devices() to read the acp-audio-ep-port ACPI _DSD property from the PDM child device on ACP7.B/7.F platforms. Value 4 selects PDM0 (ACP7X_PDM_DMIC0), value 5 selects PDM1 (ACP7X_PDM_DMIC1). Unrecognized values are reported via dev_warn(). The selected controller is stored in acp_dev_data.pdm_sel and propagated to the machine driver via mach->pdata in amd_sof_machine_select() so the machine driver probe can register the correct SOF DMIC DAI link. Signed-off-by: Vijendar Mukunda --- sound/soc/amd/acp/soc_amd_sdw_common.h | 13 +++++++++++ sound/soc/sof/amd/acp-common.c | 17 ++++++++++++++ sound/soc/sof/amd/acp.c | 31 ++++++++++++++++++++++++++ sound/soc/sof/amd/acp.h | 10 +++++++++ 4 files changed, 71 insertions(+) diff --git a/sound/soc/amd/acp/soc_amd_sdw_common.h b/sound/soc/amd/acp/soc_amd_sdw_common.h index 3930cc46fa5871..17e4e97fb3d1d6 100644 --- a/sound/soc/amd/acp/soc_amd_sdw_common.h +++ b/sound/soc/amd/acp/soc_amd_sdw_common.h @@ -23,6 +23,19 @@ #define ACP71_PCI_REV 0x71 #define ACP72_PCI_REV 0x72 +/** + * struct amd_pdm_pdata - platform data passed via mach->pdata to machine driver + * @pdm_sel: active PDM controller (ACP7X_PDM_DMIC0 or ACP7X_PDM_DMIC1), + * non-zero when a PDM controller was identified via ACPI _DSD + * + * Carries the PDM controller selection for ACP7.B/7.F platforms, derived + * from the acp-audio-ep-port ACPI _DSD property and passed via mach->pdata + * to the machine driver. + */ +struct amd_pdm_pdata { + unsigned int pdm_sel; +}; + #define SOC_JACK_JDSRC(quirk) ((quirk) & GENMASK(3, 0)) #define ASOC_SDW_FOUR_SPK BIT(4) #define ASOC_SDW_ACP_DMIC BIT(5) diff --git a/sound/soc/sof/amd/acp-common.c b/sound/soc/sof/amd/acp-common.c index df656cdc152773..33540f7c421b19 100644 --- a/sound/soc/sof/amd/acp-common.c +++ b/sound/soc/sof/amd/acp-common.c @@ -16,6 +16,7 @@ #include "acp.h" #include "acp-dsp-offset.h" #include +#include "../../amd/acp/soc_amd_sdw_common.h" /** * amd_sof_ipc_dump() - This function is called when IPC tx times out. @@ -177,6 +178,7 @@ struct snd_soc_acpi_mach *amd_sof_machine_select(struct snd_sof_dev *sdev) struct acp_dev_data *acp_data = sdev->pdata->hw_pdata; const struct sof_dev_desc *desc = sof_pdata->desc; struct snd_soc_acpi_mach *mach = NULL; + struct amd_pdm_pdata *pdm_pdata; if (desc->machines) mach = snd_soc_acpi_find_machine(desc->machines); @@ -188,7 +190,22 @@ struct snd_soc_acpi_mach *amd_sof_machine_select(struct snd_sof_dev *sdev) } } + mach = devm_kmemdup(sdev->dev, mach, sizeof(*mach), GFP_KERNEL); + if (!mach) { + dev_err(sdev->dev, "failed to allocate machine entry copy\n"); + return NULL; + } + mach->mach_params.subsystem_rev = acp_data->pci_rev; + + if (acp_data->pdm_sel) { + pdm_pdata = devm_kzalloc(sdev->dev, sizeof(*pdm_pdata), GFP_KERNEL); + if (!pdm_pdata) + return NULL; + pdm_pdata->pdm_sel = acp_data->pdm_sel; + mach->pdata = pdm_pdata; + } + sof_pdata->tplg_filename = mach->sof_tplg_filename; sof_pdata->fw_filename = mach->fw_filename; diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index 5570f3d1348dd9..37909f2d86a415 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -853,6 +853,31 @@ int amd_sof_acp_resume(struct snd_sof_dev *sdev) } EXPORT_SYMBOL_NS(amd_sof_acp_resume, "SND_SOC_SOF_AMD_COMMON"); +static void acp_sof_scan_pdm_devices(struct snd_sof_dev *sdev, + struct acpi_device *pdm_dev) +{ + struct acp_dev_data *acp_data = sdev->pdata->hw_pdata; + struct fwnode_handle *fwnode, *child; + u32 ep_port_val; + + fwnode = acpi_fwnode_handle(pdm_dev); + child = fwnode_get_next_child_node(fwnode, NULL); + if (!child) + return; + + if (!fwnode_property_read_u32(child, "acp-audio-ep-port", &ep_port_val)) { + if (ep_port_val == ACP_DEV_PORT_PDM) + acp_data->pdm_sel = ACP7X_PDM_DMIC0; + else if (ep_port_val == ACP_DEV_PORT_PDM2) + acp_data->pdm_sel = ACP7X_PDM_DMIC1; + else + dev_warn(sdev->dev, + "acp-audio-ep-port: unrecognized value %u\n", + ep_port_val); + } + fwnode_handle_put(child); +} + #if IS_ENABLED(CONFIG_SND_SOC_SOF_AMD_SOUNDWIRE) static int acp_sof_scan_sdw_devices(struct snd_sof_dev *sdev, u64 addr) { @@ -1070,6 +1095,7 @@ int amd_sof_acp7x_probe(struct snd_sof_dev *sdev) const struct sof_amd_acp_desc *chip; const union acpi_object *obj; struct acpi_device *adev; + struct acpi_device *pdm_dev; unsigned int addr; unsigned int irqflags; int ret; @@ -1123,6 +1149,11 @@ int amd_sof_acp7x_probe(struct snd_sof_dev *sdev) } if (adev) { + /* DMIC ACPI child address is 2 on ACP7x platforms */ + pdm_dev = acpi_find_child_device(adev, ACP7X_DMIC_ADDR, 0); + if (pdm_dev) + acp_sof_scan_pdm_devices(sdev, pdm_dev); + if (!acpi_dev_get_property(adev, "acp-sof-signed-firmware-image", ACPI_TYPE_INTEGER, &obj)) adata->acp_sof_signed_firmware_image = obj->integer.value; diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index 1cd9904c2908f2..0b0f15c7deef32 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -125,6 +125,14 @@ #define ACP_SRAM_PAGE_COUNT 128 #define ACP6X_SDW_MAX_MANAGER_COUNT 2 #define ACP70_SDW_MAX_MANAGER_COUNT ACP6X_SDW_MAX_MANAGER_COUNT +/* ACPI _DSD acp-audio-ep-port values for PDM controller selection */ +#define ACP_DEV_PORT_PDM 4 +#define ACP_DEV_PORT_PDM2 5 +/* ACPI child device address for the ACP7x PDM/DMIC device */ +#define ACP7X_DMIC_ADDR 2 +/* ACP7X PDM controller selection values for acp_dev_data.pdm_sel; 0 = not set */ +#define ACP7X_PDM_DMIC0 1 +#define ACP7X_PDM_DMIC1 2 #define ACP_DSP_MSG_SET 1 #define ACP_DSP_ACK_SET 1 @@ -279,6 +287,8 @@ struct acp_dev_data { bool acp70_sdw0_wake_event; /* acp70_sdw1_wake_event flag set to true when wake irq asserted for SW1 instance */ bool acp70_sdw1_wake_event; + /* PDM controller index selected from ACPI acp-audio-ep-port; passed to machine driver */ + unsigned int pdm_sel; unsigned int pci_rev; int acp_sof_signed_firmware_image; }; From b1e294a967af1b7a12076b6ef9d1f4fb264bebbe Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Wed, 9 Sep 2026 10:13:23 +0530 Subject: [PATCH 05/12] ASoC: SOF: amd: update SoundWire specific acp descriptor fields for ACP7.B/7.F Populate the SoundWire descriptor fields in acp7x_chip_info so the SOF core can locate and enumerate the four SoundWire managers on ACP7.B/7.F platforms. Signed-off-by: Vijendar Mukunda --- sound/soc/sof/amd/acp.h | 3 +++ sound/soc/sof/amd/pci-acp7x.c | 2 ++ 2 files changed, 5 insertions(+) diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index 0b0f15c7deef32..3e84558aaea9b8 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -128,6 +128,9 @@ /* ACPI _DSD acp-audio-ep-port values for PDM controller selection */ #define ACP_DEV_PORT_PDM 4 #define ACP_DEV_PORT_PDM2 5 +#define SDW_ACPI_ADDR_ACP7X SDW_ACPI_ADDR_ACP63 +#define ACP7X_SDW_MAX_MANAGER_COUNT 4 + /* ACPI child device address for the ACP7x PDM/DMIC device */ #define ACP7X_DMIC_ADDR 2 /* ACP7X PDM controller selection values for acp_dev_data.pdm_sel; 0 = not set */ diff --git a/sound/soc/sof/amd/pci-acp7x.c b/sound/soc/sof/amd/pci-acp7x.c index 532e1531379591..0594c1f3deb6bb 100644 --- a/sound/soc/sof/amd/pci-acp7x.c +++ b/sound/soc/sof/amd/pci-acp7x.c @@ -40,6 +40,8 @@ static const struct sof_amd_acp_desc acp7x_chip_info = { .fusion_dsp_offset = ACP7X_DSP_FUSION_RUNSTALL, .probe_reg_offset = ACP7X_FUTURE_REG_ACLK_0, .reg_start_addr = ACP7X_REG_START, + .sdw_max_link_count = ACP7X_SDW_MAX_MANAGER_COUNT, + .sdw_acpi_dev_addr = SDW_ACPI_ADDR_ACP7X, .reg_end_addr = ACP7X_REG_END, }; From 935b9e6d72ccf1f02df952b93f1bba4c53caa6fe Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Wed, 9 Sep 2026 10:19:13 +0530 Subject: [PATCH 06/12] ASoC: SOF: amd: enable SoundWire build for ACP7.B/7.F Select SND_SOC_SOF_AMD_SOUNDWIRE_LINK_BASELINE in Kconfig for SND_SOC_SOF_AMD_ACP7X so that the SoundWire stack is built when ACP7.B/7.F SOF support is enabled. Signed-off-by: Vijendar Mukunda --- sound/soc/sof/amd/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/sof/amd/Kconfig b/sound/soc/sof/amd/Kconfig index 903e7ec3b3ba41..d64f682cfbea68 100644 --- a/sound/soc/sof/amd/Kconfig +++ b/sound/soc/sof/amd/Kconfig @@ -109,6 +109,7 @@ config SND_SOC_SOF_AMD_ACP7X depends on SND_SOC_SOF_PCI depends on AMD_NODE select SND_SOC_SOF_AMD_COMMON + select SND_SOC_SOF_AMD_SOUNDWIRE_LINK_BASELINE help Select this option for SOF support on AMD ACP7.B and ACP7.F PCI revision based platforms. From 985727e9fc1e64c4f9299747391a4af878854204 Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Wed, 9 Sep 2026 10:15:52 +0530 Subject: [PATCH 07/12] ASoC: SOF: amd: wire SoundWire probe and remove into ACP7.B/7.F paths In amd_sof_acp7x_probe(), scan DSDT for SoundWire peripherals via acp_sof_scan_sdw_devices() and call amd_sof_sdw_probe() on success. In the error unwind, call free_irq() before amd_sof_sdw_exit() so the IRQ cannot fire after the SoundWire context is freed. In amd_sof_acp7x_remove(), call amd_sof_sdw_exit() after free_irq() to prevent a use-after-free: the IRQ handler dereferences pdev[] entries freed by amd_sof_sdw_exit(). Signed-off-by: Vijendar Mukunda --- sound/soc/sof/amd/acp.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index 37909f2d86a415..a900dbc1de20d5 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -1148,6 +1148,18 @@ int amd_sof_acp7x_probe(struct snd_sof_dev *sdev) goto unregister_dev; } + /* 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"); + goto free_ipc_irq; + } +skip_soundwire: if (adev) { /* DMIC ACPI child address is 2 on ACP7x platforms */ pdm_dev = acpi_find_child_device(adev, ACP7X_DMIC_ADDR, 0); @@ -1191,6 +1203,8 @@ int amd_sof_acp7x_probe(struct snd_sof_dev *sdev) free_ipc_irq: free_irq(sdev->ipc_irq, sdev); + if (adata->sdw) + amd_sof_sdw_exit(sdev); unregister_dev: platform_device_unregister(adata->dmic_dev); return ret; @@ -1204,6 +1218,9 @@ void amd_sof_acp7x_remove(struct snd_sof_dev *sdev) if (sdev->ipc_irq) free_irq(sdev->ipc_irq, sdev); + if (adata->sdw) + amd_sof_sdw_exit(sdev); + if (adata->dmic_dev) platform_device_unregister(adata->dmic_dev); From a60094cbe334f1c84090315a75a684115be11b17 Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Wed, 2 Sep 2026 18:34:45 +0530 Subject: [PATCH 08/12] ASoC: SOF: amd: add ACP7.B/7.F clock-stop detection in check_acp_sdw_enable_status Extend check_acp_sdw_enable_status() with a pci_rev switch so that ACP7.B/7.F, which has 4 SoundWire manager instances, reads all four SW_EN registers to determine whether any manager is in clock-stop mode. The existing two-manager read (ACP_SW0_EN, ACP_SW1_EN) is preserved for ACP63/ACP70/ACP71/ACP72 platforms. Signed-off-by: Vijendar Mukunda --- sound/soc/sof/amd/acp-dsp-offset.h | 2 ++ sound/soc/sof/amd/acp.c | 23 +++++++++++++++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/sound/soc/sof/amd/acp-dsp-offset.h b/sound/soc/sof/amd/acp-dsp-offset.h index bea1bd3afa70d2..74abbc834d71ca 100644 --- a/sound/soc/sof/amd/acp-dsp-offset.h +++ b/sound/soc/sof/amd/acp-dsp-offset.h @@ -156,5 +156,7 @@ #define ACP7X_IDMA_ERROR_MASK 0x1FF9FF #define ACP7X_ZSC_DSP_CTRL 0x001014 #define ACP7X_PME_EN ACP70_PME_EN +/* SW enable base for SDW0; manager N uses ACP7X_SW_EN + (N * 0x2000) */ +#define ACP7X_SW_EN 0x5200 #endif diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index a900dbc1de20d5..a4ca4f78e10609 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -779,15 +779,30 @@ static int acp_init(struct snd_sof_dev *sdev) static bool check_acp_sdw_enable_status(struct snd_sof_dev *sdev) { struct acp_dev_data *acp_data; - u32 sdw0_en, sdw1_en; + u32 sdw0_en, sdw1_en, sdw2_en, sdw3_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; + switch (acp_data->pci_rev) { + case ACP63_PCI_ID: + case ACP70_PCI_ID: + case ACP71_PCI_ID: + case ACP72_PCI_ID: + 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; + break; + case ACP7B_PCI_ID: + case ACP7F_PCI_ID: + sdw0_en = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP7X_SW_EN + (0 * 0x2000)); + sdw1_en = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP7X_SW_EN + (1 * 0x2000)); + sdw2_en = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP7X_SW_EN + (2 * 0x2000)); + sdw3_en = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP7X_SW_EN + (3 * 0x2000)); + acp_data->sdw_en_stat = sdw0_en || sdw1_en || sdw2_en || sdw3_en; + break; + } return acp_data->sdw_en_stat; } From 697985027d8f740dc6515df7cafcbb0b68f089fd Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Wed, 2 Sep 2026 20:23:10 +0530 Subject: [PATCH 09/12] ASoC: SOF: amd: add ACP7.B/7.F SoundWire IO IRQ handling ACP7.B/7.F exposes four SoundWire managers (SDW0-SDW3), each with dedicated interrupt, wake-enable, PME status and error registers. Add acp7x_irq_handler() to dispatch: - Per-manager data IRQs via sof_acp7x_handle_sdw_manager_irq() - Host-wake and PME events via sof_amd_check_and_handle_acp7x_sdw_wake_irq() which checks both sources independently per manager so simultaneous host-wake and PME events are not missed - Error conditions via sof_amd_acp7x_clear_sdw_err_regs() which writes back the updated error status to clear only the affected manager bit Signed-off-by: Vijendar Mukunda --- sound/soc/sof/amd/acp-dsp-offset.h | 15 +++ sound/soc/sof/amd/acp.c | 186 ++++++++++++++++++++++++++++- sound/soc/sof/amd/acp.h | 2 + sound/soc/sof/amd/acp7x.h | 37 ++++++ 4 files changed, 234 insertions(+), 6 deletions(-) create mode 100644 sound/soc/sof/amd/acp7x.h diff --git a/sound/soc/sof/amd/acp-dsp-offset.h b/sound/soc/sof/amd/acp-dsp-offset.h index 74abbc834d71ca..3984cd627db6df 100644 --- a/sound/soc/sof/amd/acp-dsp-offset.h +++ b/sound/soc/sof/amd/acp-dsp-offset.h @@ -159,4 +159,19 @@ /* SW enable base for SDW0; manager N uses ACP7X_SW_EN + (N * 0x2000) */ #define ACP7X_SW_EN 0x5200 +/* ACP7X SoundWire IO registers (non-gsync, up to 4 managers SW0-SW3) */ +#define ACP7X_EXTERNAL_SW_INTR_STAT 0x001A24 +#define ACP7X_SW_WAKE_EN 0x001458 +#define ACP7X_SW_PME_STS 0x001474 +#define ACP7X_SDW_STAT BIT(23) +#define ACP7X_ERROR_IRQ BIT(29) +#define ACP7X_SW_WAKE_EN_MASK BIT(0) +#define ACP7X_SW_HOST_WAKE_MASK BIT(22) +#define ACP7X_SDW_HOST_WAKE_STAT BIT(24) +#define ACP7X_SW_FIFO_ERROR_REASON 0x50C4 +#define ACP7X_SW_ERROR_REASON1 0x50CC +#define ACP7X_SW_ERROR_REASON2 0x50D4 +#define ACP7X_EXTERNAL_SDW_STAT BIT(16) +#define ACP7X_SW_ERR_STAT_MASK BIT(11) + #endif diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index a4ca4f78e10609..1e039aacff387d 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -22,11 +22,20 @@ #include "../ops.h" #include "acp.h" #include "acp-dsp-offset.h" +#include "../../amd/acp/soc_amd_sdw_common.h" +#include "acp7x.h" static bool enable_fw_debug; module_param(enable_fw_debug, bool, 0444); MODULE_PARM_DESC(enable_fw_debug, "Enable Firmware debug"); +static const u32 acp7x_sof_sdw_ext_stat[ACP7X_SDW_MAX_MANAGER_COUNT] = { + ACP7X_SDW_STAT << 0, + ACP7X_SDW_STAT << 1, + ACP7X_SDW_STAT << 2, + ACP7X_SDW_STAT << 3, +}; + static struct acp_quirk_entry quirk_valve_galileo = { .signed_fw_image = true, .skip_iram_dram_size_mod = true, @@ -581,30 +590,195 @@ static irqreturn_t acp_irq_handler(int irq, void *dev_id) return IRQ_NONE; } +/* ACP7X SoundWire IO data tables */ + +const struct sof_amd_acp7x_sdw_err_regs acp7x_sdw_err_regs[ACP7X_SDW_MAX_MANAGER_COUNT] = { + { ACP7X_SW_ERR_STAT_MASK << 0, + ACP7X_SW_FIFO_ERROR_REASON + (0 * 0x2000), + ACP7X_SW_ERROR_REASON1 + (0 * 0x2000), + ACP7X_SW_ERROR_REASON2 + (0 * 0x2000) }, + { ACP7X_SW_ERR_STAT_MASK << 1, + ACP7X_SW_FIFO_ERROR_REASON + (1 * 0x2000), + ACP7X_SW_ERROR_REASON1 + (1 * 0x2000), + ACP7X_SW_ERROR_REASON2 + (1 * 0x2000) }, + { ACP7X_SW_ERR_STAT_MASK << 2, + ACP7X_SW_FIFO_ERROR_REASON + (2 * 0x2000), + ACP7X_SW_ERROR_REASON1 + (2 * 0x2000), + ACP7X_SW_ERROR_REASON2 + (2 * 0x2000) }, + { ACP7X_SW_ERR_STAT_MASK << 3, + ACP7X_SW_FIFO_ERROR_REASON + (3 * 0x2000), + ACP7X_SW_ERROR_REASON1 + (3 * 0x2000), + ACP7X_SW_ERROR_REASON2 + (3 * 0x2000) }, +}; + +const struct acp7x_sdw_wake_src acp7x_sdw_wake_sources[] = { + { ACP7X_SDW_HOST_WAKE_STAT << 0, ACP7X_SW_PME_STS + (0 * 4), + ACP7X_SW_WAKE_EN_MASK << 0, 0 }, + { ACP7X_SDW_HOST_WAKE_STAT << 1, ACP7X_SW_PME_STS + (1 * 4), + ACP7X_SW_WAKE_EN_MASK << 1, 1 }, + { ACP7X_SDW_HOST_WAKE_STAT << 2, ACP7X_SW_PME_STS + (2 * 4), + ACP7X_SW_WAKE_EN_MASK << 2, 2 }, + { ACP7X_SDW_HOST_WAKE_STAT << 3, ACP7X_SW_PME_STS + (3 * 4), + ACP7X_SW_WAKE_EN_MASK << 3, 3 }, +}; + +/* ACP7X SoundWire IO interrupt and wake helpers */ + +static void sof_amd_acp7x_handle_one_sdw_err(struct snd_sof_dev *sdev, u32 *err_stat, + u32 acp_error_stat_reg, + const struct sof_amd_acp7x_sdw_err_regs *regs) +{ + if (!(*err_stat & regs->err_stat_mask)) + return; + + *err_stat &= ~regs->err_stat_mask; + snd_sof_dsp_write(sdev, ACP_DSP_BAR, acp_error_stat_reg, *err_stat); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, regs->fifo_err_reason, 0); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, regs->err_reason1, 0); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, regs->err_reason2, 0); +} + +/* Clears SoundWire error registers for all managers; runs in hard IRQ context. */ +static void sof_amd_acp7x_clear_sdw_err_regs(struct snd_sof_dev *sdev) +{ + const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); + u32 err_stat; + unsigned int instance; + + err_stat = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->acp_error_stat); + + for (instance = 0; instance < ACP7X_SDW_MAX_MANAGER_COUNT; instance++) + sof_amd_acp7x_handle_one_sdw_err(sdev, &err_stat, desc->acp_error_stat, + &acp7x_sdw_err_regs[instance]); +} + +static void sof_amd_handle_acp7x_sdw_wake_event(struct acp_dev_data *adata) +{ + struct amd_sdw_manager *amd_manager; + unsigned int instance; + + for (instance = 0; instance < ACP7X_SDW_MAX_MANAGER_COUNT; instance++) { + if (!adata->acp7x_sdw_wake_event[instance]) + continue; + if (!adata->sdw->pdev[instance]) + continue; + + amd_manager = dev_get_drvdata(&adata->sdw->pdev[instance]->dev); + if (amd_manager) + pm_request_resume(amd_manager->dev); + adata->acp7x_sdw_wake_event[instance] = false; + } +} + +static int sof_amd_check_and_handle_acp7x_sdw_wake_irq(struct snd_sof_dev *sdev) +{ + struct acp_dev_data *adata = sdev->pdata->hw_pdata; + const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); + u32 ext_intr_stat1, sdw_pme_stat, sdw_wake_en; + u32 i; + bool sdw_wake_irq = false; + + ext_intr_stat1 = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->ext_intr_stat1); + + for (i = 0; i < ARRAY_SIZE(acp7x_sdw_wake_sources); i++) { + const struct acp7x_sdw_wake_src *src = &acp7x_sdw_wake_sources[i]; + + bool woke = false; + + if (ext_intr_stat1 & src->host_stat_mask) { + snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat1, + src->host_stat_mask); + woke = true; + } + + sdw_pme_stat = snd_sof_dsp_read(sdev, ACP_DSP_BAR, src->pme_sts_reg); + if (sdw_pme_stat) { + sdw_wake_en = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP7X_SW_WAKE_EN); + sdw_wake_en &= ~src->wake_en_mask; + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP7X_SW_WAKE_EN, sdw_wake_en); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, src->pme_sts_reg, sdw_pme_stat); + woke = true; + } + + if (woke) { + adata->acp7x_sdw_wake_event[src->instance] = true; + sdw_wake_irq = true; + } + } + + if (sdw_wake_irq) { + sof_amd_handle_acp7x_sdw_wake_event(adata); + return WAKE_IRQ_HANDLED; + } + return WAKE_IRQ_NONE; +} + +static void sof_acp7x_handle_sdw_manager_irq(struct snd_sof_dev *sdev, + struct acp_dev_data *adata, + const struct sof_amd_acp_desc *desc, + unsigned int instance, + u32 ext_stat_mask) +{ + struct amd_sdw_manager *amd_manager; + unsigned int sdw_intr_stat; + u32 sw_intr_reg = ACP7X_EXTERNAL_SW_INTR_STAT + (instance * 4); + + snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat, ext_stat_mask); + sdw_intr_stat = snd_sof_dsp_read(sdev, ACP_DSP_BAR, sw_intr_reg); + if (sdw_intr_stat & ACP7X_EXTERNAL_SDW_STAT) { + snd_sof_dsp_write(sdev, ACP_DSP_BAR, sw_intr_reg, ACP7X_EXTERNAL_SDW_STAT); + if (!adata->sdw->pdev[instance]) + return; + amd_manager = dev_get_drvdata(&adata->sdw->pdev[instance]->dev); + if (amd_manager) + schedule_work(&amd_manager->amd_sdw_irq_thread); + } +} + static irqreturn_t acp7x_irq_handler(int irq, void *dev_id) { struct snd_sof_dev *sdev = dev_id; + struct acp_dev_data *adata = sdev->pdata->hw_pdata; const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); unsigned int base = desc->dsp_intr_base; unsigned int val; unsigned int ext_intr_stat; - int irq_flag = 0; + unsigned int instance; + int irq_flag = 0, wake_irq_flag = 0; + bool dsp_irq = false; val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET); if (val & ACP_DSP_TO_HOST_IRQ) { snd_sof_dsp_write(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET, ACP_DSP_TO_HOST_IRQ); - return IRQ_WAKE_THREAD; + dsp_irq = true; } ext_intr_stat = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->ext_intr_stat); - if (ext_intr_stat & 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, desc->acp_error_stat, 0); + + if (adata->sdw) { + for (instance = 0; instance < ACP7X_SDW_MAX_MANAGER_COUNT; instance++) { + if (ext_intr_stat & acp7x_sof_sdw_ext_stat[instance]) { + sof_acp7x_handle_sdw_manager_irq(sdev, adata, desc, instance, + acp7x_sof_sdw_ext_stat[instance]); + irq_flag = 1; + } + } + } + + if (adata->sdw) + wake_irq_flag = sof_amd_check_and_handle_acp7x_sdw_wake_irq(sdev); + + if (ext_intr_stat & ACP7X_ERROR_IRQ) { + snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat, ACP7X_ERROR_IRQ); + sof_amd_acp7x_clear_sdw_err_regs(sdev); irq_flag = 1; } - if (irq_flag) + if (dsp_irq) + return IRQ_WAKE_THREAD; + + if (irq_flag || wake_irq_flag) return IRQ_HANDLED; return IRQ_NONE; diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index 3e84558aaea9b8..9568e10093c007 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -290,6 +290,8 @@ struct acp_dev_data { bool acp70_sdw0_wake_event; /* acp70_sdw1_wake_event flag set to true when wake irq asserted for SW1 instance */ bool acp70_sdw1_wake_event; + /* per-manager wake event flags; indexed by SoundWire manager instance (0-3) */ + bool acp7x_sdw_wake_event[ACP7X_SDW_MAX_MANAGER_COUNT]; /* PDM controller index selected from ACPI acp-audio-ep-port; passed to machine driver */ unsigned int pdm_sel; unsigned int pci_rev; diff --git a/sound/soc/sof/amd/acp7x.h b/sound/soc/sof/amd/acp7x.h new file mode 100644 index 00000000000000..5151d8757c12d1 --- /dev/null +++ b/sound/soc/sof/amd/acp7x.h @@ -0,0 +1,37 @@ +/* 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) 2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Author: Vijendar Mukunda + */ + +#ifndef __SOF_AMD_ACP7X_H +#define __SOF_AMD_ACP7X_H + +/* Return values for sof_amd_check_and_handle_acp7x_sdw_wake_irq() */ +#define WAKE_IRQ_HANDLED 1 +#define WAKE_IRQ_NONE 0 + +/* ACP7X SoundWire IO structures */ + +struct sof_amd_acp7x_sdw_err_regs { + u32 err_stat_mask; + u32 fifo_err_reason; + u32 err_reason1; + u32 err_reason2; +}; + +struct acp7x_sdw_wake_src { + u32 host_stat_mask; + u32 pme_sts_reg; + u32 wake_en_mask; + u8 instance; +}; + +extern const struct sof_amd_acp7x_sdw_err_regs acp7x_sdw_err_regs[ACP7X_SDW_MAX_MANAGER_COUNT]; +extern const struct acp7x_sdw_wake_src acp7x_sdw_wake_sources[]; + +#endif /* __SOF_AMD_ACP7X_H */ From 1bd090a7f422336647a208b0a29abc1f2bac7a06 Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Wed, 2 Sep 2026 18:05:39 +0530 Subject: [PATCH 10/12] ASoC: SOF: amd: enable SoundWire host wake interrupt in acp_init During acp_init() for ACP7.B/7.F, read ACP7X_SW_WAKE_EN and enable the corresponding host-wake interrupt mask in ACP7X_EXTERNAL_INTR_CNTL1 only for managers that have wake-enable set (SW_WAKE_EN bit i enables ACP7X_SW_HOST_WAKE_MASK << i in INTR_CNTL1). This ensures only the active managers arm their host-wake interrupt when ACP enters D0. Signed-off-by: Vijendar Mukunda --- sound/soc/sof/amd/acp.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index 1e039aacff387d..10a226c6161480 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -902,6 +902,8 @@ static int acp_init(struct snd_sof_dev *sdev) const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); struct acp_dev_data *acp_data; unsigned int sdw0_wake_en, sdw1_wake_en; + u32 sdw_wake_en, intr_mask; + unsigned int i; int ret; /* power on */ @@ -945,6 +947,20 @@ static int acp_init(struct snd_sof_dev *sdev) snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP7X_PME_EN, 1); snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP7X_DSP0_IDMA_ERROR_MASK, ACP7X_IDMA_ERROR_MASK); + /* + * Enable host-wake interrupt per manager based on SW_WAKE_EN: + * SW_WAKE_EN bit i enables ACP7X_SW_HOST_WAKE_MASK << i in INTR_CNTL1. + */ + sdw_wake_en = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP7X_SW_WAKE_EN); + intr_mask = 0; + for (i = 0; i < ACP7X_SDW_MAX_MANAGER_COUNT; i++) { + if (sdw_wake_en & BIT(i)) + intr_mask |= ACP7X_SW_HOST_WAKE_MASK << i; + } + if (intr_mask) + snd_sof_dsp_update_bits(sdev, ACP_DSP_BAR, + ACP7X_EXTERNAL_INTR_CNTL1, + intr_mask, intr_mask); break; } return 0; From 22d9a14aed0db3b4c0608877147e8c3e60343197 Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Wed, 2 Sep 2026 18:06:17 +0530 Subject: [PATCH 11/12] ASoC: SOF: amd: add SoundWire PM ops for ACP7.B/7.F Add handle_amd_sof_acp7x_sdw_pme_event() to iterate over all four SoundWire managers on runtime PM resume, clear PME status and wake-enable bits (under acp_lock to prevent races with the IRQ path), and request runtime resume for each active manager. Extend amd_sof_acp7x_suspend() with a clock-stop fast path: when SoundWire managers are in clock-stop mode, write ZSC_DSP_CTRL=1 and call acp_dsp_reset() instead of the full acp_reset() to preserve SoundWire bus state. Extend amd_sof_acp7x_resume() with a matching clock-stop resume path that restores ZSC_DSP_CTRL and re-arms PME_EN. Introduce amd_sof_acp7x_suspend_runtime() and amd_sof_acp7x_resume_runtime() as separate runtime PM callbacks. The runtime resume path calls handle_amd_sof_acp7x_sdw_pme_event() after re-initialising hardware to clear any PME state that arrived during the suspend window. Signed-off-by: Vijendar Mukunda --- sound/soc/sof/amd/acp.c | 101 +++++++++++++++++++++++++++++++++------- sound/soc/sof/amd/acp.h | 1 + 2 files changed, 84 insertions(+), 18 deletions(-) diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index 10a226c6161480..5c8288e7ee63e9 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -1364,6 +1364,9 @@ int amd_sof_acp7x_probe(struct snd_sof_dev *sdev) dev_err(sdev->dev, "error: SoundWire probe error\n"); goto free_ipc_irq; } + if (adata->info.link_mask) + adata->is_sdw_dev = true; + skip_soundwire: if (adev) { /* DMIC ACPI child address is 2 on ACP7x platforms */ @@ -1433,6 +1436,41 @@ void amd_sof_acp7x_remove(struct snd_sof_dev *sdev) } EXPORT_SYMBOL_NS(amd_sof_acp7x_remove, "SND_SOC_SOF_AMD_COMMON"); +static void handle_amd_sof_acp7x_sdw_pme_event(struct snd_sof_dev *sdev) +{ + struct acp_dev_data *adata; + struct amd_sdw_manager *amd_manager; + u32 sdw_pme_stat, sdw_wake_en, pme_reg, wake_mask; + unsigned int instance; + + adata = sdev->pdata->hw_pdata; + if (!adata->sdw) + return; + + for (instance = 0; instance < ACP7X_SDW_MAX_MANAGER_COUNT; instance++) { + pme_reg = ACP7X_SW_PME_STS + (instance * 4); + wake_mask = ACP7X_SW_WAKE_EN_MASK << instance; + + sdw_pme_stat = snd_sof_dsp_read(sdev, ACP_DSP_BAR, pme_reg); + if (!sdw_pme_stat) + continue; + + mutex_lock(&adata->acp_lock); + sdw_wake_en = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP7X_SW_WAKE_EN); + sdw_wake_en &= ~wake_mask; + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP7X_SW_WAKE_EN, sdw_wake_en); + mutex_unlock(&adata->acp_lock); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, pme_reg, sdw_pme_stat); + + if (!adata->sdw->pdev[instance]) + continue; + + amd_manager = dev_get_drvdata(&adata->sdw->pdev[instance]->dev); + if (amd_manager) + pm_request_resume(amd_manager->dev); + } +} + int amd_sof_acp7x_suspend(struct snd_sof_dev *sdev, u32 target_state) { struct acp_dev_data *acp_data; @@ -1441,6 +1479,11 @@ int amd_sof_acp7x_suspend(struct snd_sof_dev *sdev, u32 target_state) acp_data = sdev->pdata->hw_pdata; + if (acp_data->is_sdw_dev && check_acp_sdw_enable_status(sdev)) { + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP7X_ZSC_DSP_CTRL, 1); + return acp_dsp_reset(sdev); + } + ret = acp_reset(sdev); if (ret) { dev_err(sdev->dev, "ACP Reset failed\n"); @@ -1462,13 +1505,25 @@ int amd_sof_acp7x_suspend(struct snd_sof_dev *sdev, u32 target_state) } EXPORT_SYMBOL_NS(amd_sof_acp7x_suspend, "SND_SOC_SOF_AMD_COMMON"); -int amd_sof_acp7x_resume(struct snd_sof_dev *sdev) +int amd_sof_acp7x_suspend_runtime(struct snd_sof_dev *sdev) +{ + return amd_sof_acp7x_suspend(sdev, 0); +} +EXPORT_SYMBOL_NS(amd_sof_acp7x_suspend_runtime, "SND_SOC_SOF_AMD_COMMON"); + +int amd_sof_acp7x_resume_runtime(struct snd_sof_dev *sdev) { struct acp_dev_data *acp_data; int ret; acp_data = sdev->pdata->hw_pdata; + if (acp_data->sdw_en_stat) { + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP7X_ZSC_DSP_CTRL, 0); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP7X_PME_EN, 1); + return acp_dsp_reset(sdev); + } + ret = acp_init(sdev); if (ret) { dev_err(sdev->dev, "ACP Init failed\n"); @@ -1480,30 +1535,40 @@ int amd_sof_acp7x_resume(struct snd_sof_dev *sdev) return ret; } - switch (acp_data->pci_rev) { - case ACP7B_PCI_ID: - case ACP7F_PCI_ID: - snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP7X_PME_EN, 1); - break; - default: - break; - } + if (acp_data->is_sdw_dev) + handle_amd_sof_acp7x_sdw_pme_event(sdev); return 0; } -EXPORT_SYMBOL_NS(amd_sof_acp7x_resume, "SND_SOC_SOF_AMD_COMMON"); +EXPORT_SYMBOL_NS(amd_sof_acp7x_resume_runtime, "SND_SOC_SOF_AMD_COMMON"); -int amd_sof_acp7x_suspend_runtime(struct snd_sof_dev *sdev) +int amd_sof_acp7x_resume(struct snd_sof_dev *sdev) { - return amd_sof_acp7x_suspend(sdev, 0); -} -EXPORT_SYMBOL_NS(amd_sof_acp7x_suspend_runtime, "SND_SOC_SOF_AMD_COMMON"); + struct acp_dev_data *acp_data; + int ret; -int amd_sof_acp7x_resume_runtime(struct snd_sof_dev *sdev) -{ - return amd_sof_acp7x_resume(sdev); + acp_data = sdev->pdata->hw_pdata; + + if (acp_data->sdw_en_stat) { + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP7X_ZSC_DSP_CTRL, 0); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP7X_PME_EN, 1); + return acp_dsp_reset(sdev); + } + + ret = acp_init(sdev); + if (ret) { + dev_err(sdev->dev, "ACP Init failed\n"); + return ret; + } + ret = acp_memory_init(sdev); + if (ret) { + dev_err(sdev->dev, "ACP Memory init failed\n"); + return ret; + } + + return 0; } -EXPORT_SYMBOL_NS(amd_sof_acp7x_resume_runtime, "SND_SOC_SOF_AMD_COMMON"); +EXPORT_SYMBOL_NS(amd_sof_acp7x_resume, "SND_SOC_SOF_AMD_COMMON"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("AMD ACP sof driver"); diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index 9568e10093c007..5a887959461a26 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -294,6 +294,7 @@ struct acp_dev_data { bool acp7x_sdw_wake_event[ACP7X_SDW_MAX_MANAGER_COUNT]; /* PDM controller index selected from ACPI acp-audio-ep-port; passed to machine driver */ unsigned int pdm_sel; + bool is_sdw_dev; unsigned int pci_rev; int acp_sof_signed_firmware_image; }; From bbfe903e7de9a5bf998cb933d033f4dc3e6925c2 Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Thu, 10 Sep 2026 21:14:38 +0530 Subject: [PATCH 12/12] ASoC: SOF: amd: Propagate PCI subsystem Vendor and Device IDs Extend the AMD SOF machine driver to propagate the PCI subsystem Vendor and Device IDs so that they may be subsequently used as an SSID. Store the subsystem IDs in acp_dev_data during probe (both amd_sof_acp_probe and amd_sof_acp7x_probe), and propagate them to mach_params in the SoundWire machine select path. Signed-off-by: Vijendar Mukunda --- sound/soc/sof/amd/acp-common.c | 6 ++++++ sound/soc/sof/amd/acp.c | 4 ++++ sound/soc/sof/amd/acp.h | 2 ++ 3 files changed, 12 insertions(+) diff --git a/sound/soc/sof/amd/acp-common.c b/sound/soc/sof/amd/acp-common.c index 33540f7c421b19..60e5c851c8743c 100644 --- a/sound/soc/sof/amd/acp-common.c +++ b/sound/soc/sof/amd/acp-common.c @@ -155,9 +155,15 @@ static struct snd_soc_acpi_mach *amd_sof_sdw_machine_select(struct snd_sof_dev * } if (mach && mach->link_mask) { mach->mach_params.subsystem_rev = acp_data->pci_rev; + mach->mach_params.subsystem_vendor = acp_data->subsystem_vendor; + mach->mach_params.subsystem_device = acp_data->subsystem_device; + mach->mach_params.subsystem_id_set = true; mach->mach_params.links = mach->links; mach->mach_params.link_mask = mach->link_mask; mach->mach_params.platform = dev_name(sdev->dev); + + dev_dbg(sdev->dev, "SSID %x%04x\n", mach->mach_params.subsystem_vendor, + mach->mach_params.subsystem_device); return mach; } } diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index 5c8288e7ee63e9..790af65be34a2f 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -1197,6 +1197,8 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev) adata->addr = addr; adata->reg_range = chip->reg_end_addr - chip->reg_start_addr; adata->pci_rev = pci->revision; + adata->subsystem_vendor = pci->subsystem_vendor; + adata->subsystem_device = pci->subsystem_device; mutex_init(&adata->acp_lock); sdev->pdata->hw_pdata = adata; @@ -1334,6 +1336,8 @@ int amd_sof_acp7x_probe(struct snd_sof_dev *sdev) adata->addr = addr; adata->reg_range = chip->reg_end_addr - chip->reg_start_addr; adata->pci_rev = pci->revision; + adata->subsystem_vendor = pci->subsystem_vendor; + adata->subsystem_device = pci->subsystem_device; mutex_init(&adata->acp_lock); sdev->pdata->hw_pdata = adata; diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index 5a887959461a26..ae194af70b2b7f 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -296,6 +296,8 @@ struct acp_dev_data { unsigned int pdm_sel; bool is_sdw_dev; unsigned int pci_rev; + u32 subsystem_vendor; + u32 subsystem_device; int acp_sof_signed_firmware_image; };