Messages in this thread | | | Date | Mon, 17 Jan 2022 17:20:25 +0530 | Subject | Re: [PATCH v2 4/6] ASoC: amd: acp: Add ACP init()/deinit() callback for Renoir. | From | Ajit Kumar Pandey <> |
| |
On 1/14/2022 2:31 PM, Amadeusz Sławiński wrote: > [CAUTION: External Email] > > On 1/13/2022 5:33 PM, Ajit Kumar Pandey wrote: >> ACP hardware has PGFSM control registers that can be configured to >> power On/Off the ACP IP block. Add acp init()/de_init() callbacks >> in renoir platform driver probe()/remove() respectively to power >> on and off ACP IP block on ACP3X device. >> >> Signed-off-by: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com> >> --- >> sound/soc/amd/acp/acp-renoir.c | 170 +++++++++++++++++++++++++++ >> sound/soc/amd/acp/chip_offset_byte.h | 6 + >> 2 files changed, 176 insertions(+) >> >> diff --git a/sound/soc/amd/acp/acp-renoir.c >> b/sound/soc/amd/acp/acp-renoir.c >> index 770a57a0677b..a29f910f25d1 100644 >> --- a/sound/soc/amd/acp/acp-renoir.c >> +++ b/sound/soc/amd/acp/acp-renoir.c >> @@ -25,6 +25,19 @@ >> >> #define DRV_NAME "acp_asoc_renoir" >> >> +#define ACP_SOFT_RST_DONE_MASK 0x00010001 >> + >> +#define ACP_PWR_ON_MASK 0x01 >> +#define ACP_PWR_OFF_MASK 0x00 >> +#define ACP_PGFSM_STAT_MASK 0x03 >> +#define ACP_POWERED_ON 0x00 >> +#define ACP_PWR_ON_IN_PROGRESS 0x01 >> +#define ACP_POWERED_OFF 0x02 >> + >> + >> +#define ACP_ERROR_MASK 0x20000000 >> +#define ACP_EXT_INTR_STAT_CLEAR_MASK 0xFFFFFFFF >> + >> static struct snd_soc_acpi_codecs amp_rt1019 = { >> .num_codecs = 1, >> .codecs = {"10EC1019"} >> @@ -112,11 +125,154 @@ static struct snd_soc_dai_driver >> acp_renoir_dai[] = { >> }, >> }; >> >> +static int acp3x_power_on(void __iomem *base) >> +{ >> + u32 val; >> + int timeout = 0; >> + >> + val = readl(base + ACP_PGFSM_STATUS); >> + >> + if (val == ACP_POWERED_ON) >> + return 0; >> + >> + if ((val & ACP_PGFSM_STAT_MASK) != ACP_PWR_ON_IN_PROGRESS) >> + writel(ACP_PWR_ON_MASK, base + ACP_PGFSM_CONTROL); >> + >> + while (++timeout < 500) { >> + val = readl(base + ACP_PGFSM_STATUS); >> + if (!val) >> + return 0; >> + udelay(1); >> + } > > Can this while loop perhaps be replaced with readl_poll_timeout? > Similarly for cases below? > >> + >> + return -ETIMEDOUT; >> +} >> + >> +static int acp3x_power_off(void __iomem *base) >> +{ >> + u32 val; >> + int timeout = 0; >> + >> + writel(ACP_PWR_OFF_MASK, base + ACP_PGFSM_CONTROL); >> + >> + while (++timeout < 500) { >> + val = readl(base + ACP_PGFSM_STATUS); >> + if ((val & ACP_PGFSM_STAT_MASK) == ACP_POWERED_OFF) >> + return 0; >> + udelay(1); >> + } >> + >> + return -ETIMEDOUT; >> +} >> + >> +static int acp3x_reset(void __iomem *base) >> +{ >> + u32 val; >> + int timeout = 0; >> + >> + writel(1, base + ACP_SOFT_RESET); >> + >> + while (++timeout < 500) { >> + val = readl(base + ACP_SOFT_RESET); >> + if (val & ACP_SOFT_RST_DONE_MASK) >> + break; >> + cpu_relax(); >> + } >> + >> + writel(0, base + ACP_SOFT_RESET); >> + >> + timeout = 0; >> + while (++timeout < 500) { >> + val = readl(base + ACP_SOFT_RESET); >> + if (!val) >> + return 0; >> + cpu_relax(); >> + } >> + >> + return -ETIMEDOUT; >> +} >> + >> +static void acp3x_enable_interrupts(void __iomem *base) >> +{ >> + u32 ext_intr_ctrl; >> + >> + writel(0x01, base + ACP_EXTERNAL_INTR_ENB); >> + ext_intr_ctrl = readl(base + ACP_EXTERNAL_INTR_CNTL); >> + ext_intr_ctrl |= ACP_ERROR_MASK; >> + writel(ext_intr_ctrl, base + ACP_EXTERNAL_INTR_CNTL); >> +} >> + >> +static void acp3x_disable_interrupts(void __iomem *base) >> +{ >> + writel(ACP_EXT_INTR_STAT_CLEAR_MASK, base + >> ACP_EXTERNAL_INTR_STAT); >> + writel(0x00, base + ACP_EXTERNAL_INTR_ENB); >> +} >> + >> +static int rn_acp_init(void __iomem *base) >> +{ >> + int ret; >> + >> + /* power on */ >> + ret = acp3x_power_on(base); >> + if (ret) >> + return ret; >> + >> + writel(0x01, base + ACP_CONTROL); >> + >> + /* Reset */ >> + ret = acp3x_reset(base); >> + if (ret) >> + return ret; >> + >> + acp3x_enable_interrupts(base); >> + >> + return 0; >> +} >> + >> +static int rn_acp_deinit(void __iomem *base) >> +{ >> + int ret = 0; >> + >> + acp3x_disable_interrupts(base); >> + >> + /* Reset */ >> + ret = acp3x_reset(base); >> + if (ret) >> + return ret; >> + >> + writel(0x00, base + ACP_CONTROL); >> + >> + /* power off */ >> + ret = acp3x_power_off(base); >> + if (ret) >> + return ret; >> + >> + return 0; >> +} >> static int renoir_audio_probe(struct platform_device *pdev) >> { >> struct device *dev = &pdev->dev; >> + struct acp_chip_info *chip; >> struct acp_dev_data *adata; >> struct resource *res; >> + int ret; >> + >> + chip = dev_get_platdata(&pdev->dev); >> + if (!chip || !chip->base) { >> + dev_err(&pdev->dev, "ACP chip data is NULL\n"); >> + return -ENODEV; >> + } >> + >> + if (chip->acp_rev != ACP3X_DEV) { >> + dev_err(&pdev->dev, "Un-supported ACP Revision %d\n", >> chip->acp_rev); >> + return -ENODEV; >> + } >> + >> + ret = rn_acp_init(chip->base); >> + if (ret) { >> + dev_err(&pdev->dev, "ACP Init failed\n"); >> + return -EINVAL; >> + } >> >> adata = devm_kzalloc(dev, sizeof(struct acp_dev_data), GFP_KERNEL); >> if (!adata) >> @@ -155,6 +311,20 @@ static int renoir_audio_probe(struct >> platform_device *pdev) >> static int renoir_audio_remove(struct platform_device *pdev) >> { >> struct device *dev = &pdev->dev; >> + struct acp_chip_info *chip; >> + int ret; >> + >> + chip = dev_get_platdata(&pdev->dev); >> + if (!chip || !chip->base) { >> + dev_err(&pdev->dev, "ACP chip data is NULL\n"); >> + return -ENODEV; >> + } >> + >> + ret = rn_acp_deinit(chip->base); >> + if (ret) { >> + dev_err(&pdev->dev, "ACP de-init Failed\n"); >> + return -EINVAL; >> + } >> >> acp_platform_unregister(dev); >> return 0; >> diff --git a/sound/soc/amd/acp/chip_offset_byte.h >> b/sound/soc/amd/acp/chip_offset_byte.h >> index e38589a142e9..88f6fa597cd6 100644 >> --- a/sound/soc/amd/acp/chip_offset_byte.h >> +++ b/sound/soc/amd/acp/chip_offset_byte.h >> @@ -14,6 +14,12 @@ >> #define ACPAXI2AXI_ATU_CTRL 0xC40 >> #define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_5 0xC20 >> #define ACPAXI2AXI_ATU_BASE_ADDR_GRP_5 0xC24 >> + >> +#define ACP_PGFSM_CONTROL 0x141C >> +#define ACP_PGFSM_STATUS 0x1420 >> +#define ACP_SOFT_RESET 0x1000 >> +#define ACP_CONTROL 0x1004 >> + >> #define ACP_EXTERNAL_INTR_ENB 0x1800 >> #define ACP_EXTERNAL_INTR_CNTL 0x1804 >> #define ACP_EXTERNAL_INTR_STAT 0x1808 > ok will improvise this in next patch chain
| |