Add acp init and deinit functions for ACP7.0 platform. Signed-off-by: Vijendar Mukunda <Vijendar.Mukunda@xxxxxxx> --- sound/soc/amd/acp70/acp70.h | 15 ++++++ sound/soc/amd/acp70/pci-acp70.c | 92 +++++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+) diff --git a/sound/soc/amd/acp70/acp70.h b/sound/soc/amd/acp70/acp70.h index 28a46f0c2026..b6f0f75de91d 100644 --- a/sound/soc/amd/acp70/acp70.h +++ b/sound/soc/amd/acp70/acp70.h @@ -12,6 +12,21 @@ #define ACP70_REG_END 0x125C000 #define ACP70_PCI_REV 0x70 #define ACP71_PCI_REV 0x71 +#define ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK 0x00010001 +#define ACP_PGFSM_CNTL_POWER_ON_MASK 0x1F +#define ACP_PGFSM_CNTL_POWER_OFF_MASK 0 +#define ACP_PGFSM_STATUS_MASK 0xFF +#define ACP_POWERED_ON 0 +#define ACP_POWER_ON_IN_PROGRESS 1 +#define ACP_POWERED_OFF 2 +#define ACP_POWER_OFF_IN_PROGRESS 3 +#define DELAY_US 5 +#define ACP_COUNTER 20000 +/* time in ms for acp timeout */ +#define ACP_TIMEOUT 2000 + +#define ACP_EXT_INTR_STAT_CLEAR_MASK 0xFFFFFFFF +#define ACP_ERROR_IRQ BIT(29) /** * struct acp70_dev_data - acp pci driver context diff --git a/sound/soc/amd/acp70/pci-acp70.c b/sound/soc/amd/acp70/pci-acp70.c index 23e47f619bd7..a98407fa2cd2 100644 --- a/sound/soc/amd/acp70/pci-acp70.c +++ b/sound/soc/amd/acp70/pci-acp70.c @@ -5,13 +5,94 @@ * Copyright 2024 Advanced Micro Devices, Inc. */ +#include <linux/delay.h> #include <linux/io.h> +#include <linux/iopoll.h> #include <linux/module.h> #include <linux/pci.h> #include "../mach-config.h" #include "acp70.h" +static int acp70_power_on(void __iomem *acp_base) +{ + u32 val = 0; + + val = readl(acp_base + ACP_PGFSM_STATUS); + + if (!val) + return 0; + if (val & ACP_PGFSM_STATUS_MASK) + writel(ACP_PGFSM_CNTL_POWER_ON_MASK, acp_base + ACP_PGFSM_CONTROL); + + return readl_poll_timeout(acp_base + ACP_PGFSM_STATUS, val, !val, DELAY_US, ACP_TIMEOUT); +} + +static int acp70_reset(void __iomem *acp_base) +{ + u32 val; + int ret; + + writel(1, acp_base + ACP_SOFT_RESET); + + ret = readl_poll_timeout(acp_base + ACP_SOFT_RESET, val, + val & ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK, + DELAY_US, ACP_TIMEOUT); + if (ret) + return ret; + + writel(0, acp_base + ACP_SOFT_RESET); + + return readl_poll_timeout(acp_base + ACP_SOFT_RESET, val, !val, DELAY_US, ACP_TIMEOUT); +} + +static void acp70_enable_interrupts(void __iomem *acp_base) +{ + writel(1, acp_base + ACP_EXTERNAL_INTR_ENB); + writel(ACP_ERROR_IRQ, acp_base + ACP_EXTERNAL_INTR_CNTL); +} + +static void acp70_disable_interrupts(void __iomem *acp_base) +{ + writel(ACP_EXT_INTR_STAT_CLEAR_MASK, acp_base + ACP_EXTERNAL_INTR_STAT); + writel(0, acp_base + ACP_EXTERNAL_INTR_CNTL); + writel(0, acp_base + ACP_EXTERNAL_INTR_ENB); +} + +static int acp70_init(void __iomem *acp_base, struct device *dev) +{ + int ret; + + ret = acp70_power_on(acp_base); + if (ret) { + dev_err(dev, "ACP power on failed\n"); + return ret; + } + writel(0x01, acp_base + ACP_CONTROL); + ret = acp70_reset(acp_base); + if (ret) { + dev_err(dev, "ACP reset failed\n"); + return ret; + } + writel(0, acp_base + ACP_ZSC_DSP_CTRL); + acp70_enable_interrupts(acp_base); + return 0; +} + +static int acp70_deinit(void __iomem *acp_base, struct device *dev) +{ + int ret; + + acp70_disable_interrupts(acp_base); + ret = acp70_reset(acp_base); + if (ret) { + dev_err(dev, "ACP reset failed\n"); + return ret; + } + writel(0x01, acp_base + ACP_ZSC_DSP_CTRL); + return 0; +} + static int snd_acp70_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { @@ -63,6 +144,10 @@ static int snd_acp70_probe(struct pci_dev *pci, pci_set_master(pci); pci_set_drvdata(pci, adata); mutex_init(&adata->acp_lock); + ret = acp70_init(adata->acp70_base, &pci->dev); + if (ret) + goto release_regions; + return 0; release_regions: pci_release_regions(pci); @@ -74,6 +159,13 @@ static int snd_acp70_probe(struct pci_dev *pci, static void snd_acp70_remove(struct pci_dev *pci) { + struct acp70_dev_data *adata; + int ret; + + adata = pci_get_drvdata(pci); + ret = acp70_deinit(adata->acp70_base, &pci->dev); + if (ret) + dev_err(&pci->dev, "ACP de-init failed\n"); pci_release_regions(pci); pci_disable_device(pci); } -- 2.34.1