From b585692fc937dc8f9d494078b5ffe2aafe31ec18 Mon Sep 17 00:00:00 2001 From: Ajit Kumar Pandey Date: Mon, 6 Jun 2022 16:02:08 -0500 Subject: [PATCH 1/5] ASoC: SOF: amd: Add SOF pm ops callback for Renoir Add SOF PM ops callback in renoir dsp ops to power off and on ACP IP block during system suspend and resume on Renoir platform. Signed-off-by: Ajit Kumar Pandey Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20220606210212.146626-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/acp-dsp-offset.h | 2 ++ sound/soc/sof/amd/acp.c | 36 ++++++++++++++++++++++++++++++ sound/soc/sof/amd/acp.h | 4 ++++ sound/soc/sof/amd/pci-rn.c | 4 ++++ sound/soc/sof/amd/renoir.c | 4 ++++ 5 files changed, 50 insertions(+) diff --git a/sound/soc/sof/amd/acp-dsp-offset.h b/sound/soc/sof/amd/acp-dsp-offset.h index 40fbf11facba..56cefd4a84fc 100644 --- a/sound/soc/sof/amd/acp-dsp-offset.h +++ b/sound/soc/sof/amd/acp-dsp-offset.h @@ -46,12 +46,14 @@ #define ACPAXI2AXI_ATU_BASE_ADDR_GRP_8 0xC3C #define ACPAXI2AXI_ATU_CTRL 0xC40 #define ACP_SOFT_RESET 0x1000 +#define ACP_CONTROL 0x1004 #define ACP_I2S_PIN_CONFIG 0x1400 /* Registers from ACP_PGFSM block */ #define ACP_PGFSM_CONTROL 0x141C #define ACP_PGFSM_STATUS 0x1420 +#define ACP_CLKMUX_SEL 0x1424 /* Registers from ACP_INTR block */ #define ACP_EXTERNAL_INTR_ENB 0x1800 diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index 0c272573df97..c40d2900dd36 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -413,10 +413,46 @@ static int acp_init(struct snd_sof_dev *sdev) dev_err(sdev->dev, "ACP power on failed\n"); return ret; } + + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_CONTROL, 0x01); /* Reset */ return acp_reset(sdev); } +int amd_sof_acp_suspend(struct snd_sof_dev *sdev, u32 target_state) +{ + int ret; + + ret = acp_reset(sdev); + if (ret) { + dev_err(sdev->dev, "ACP Reset failed\n"); + return ret; + } + + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_CONTROL, 0x00); + + return 0; +} +EXPORT_SYMBOL_NS(amd_sof_acp_suspend, SND_SOC_SOF_AMD_COMMON); + +int amd_sof_acp_resume(struct snd_sof_dev *sdev) +{ + int ret; + + ret = acp_init(sdev); + if (ret) { + dev_err(sdev->dev, "ACP Init failed\n"); + return ret; + } + + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_CLKMUX_SEL, 0x03); + + ret = acp_memory_init(sdev); + + return ret; +} +EXPORT_SYMBOL_NS(amd_sof_acp_resume, SND_SOC_SOF_AMD_COMMON); + int amd_sof_acp_probe(struct snd_sof_dev *sdev) { struct pci_dev *pci = to_pci_dev(sdev->dev); diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index 291b44c54bcc..4c42b8fd6abf 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -216,6 +216,10 @@ int acp_sof_trace_init(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab, struct sof_ipc_dma_trace_params_ext *dtrace_params); int acp_sof_trace_release(struct snd_sof_dev *sdev); +/* PM Callbacks */ +int amd_sof_acp_suspend(struct snd_sof_dev *sdev, u32 target_state); +int amd_sof_acp_resume(struct snd_sof_dev *sdev); + struct sof_amd_acp_desc { unsigned int host_bridge_id; }; diff --git a/sound/soc/sof/amd/pci-rn.c b/sound/soc/sof/amd/pci-rn.c index d5d9bcc2c997..3a7fed25a226 100644 --- a/sound/soc/sof/amd/pci-rn.c +++ b/sound/soc/sof/amd/pci-rn.c @@ -49,6 +49,7 @@ static const struct sof_amd_acp_desc renoir_chip_info = { static const struct sof_dev_desc renoir_desc = { .machines = snd_soc_acpi_amd_sof_machines, + .use_acpi_target_states = true, .resindex_lpe_base = 0, .resindex_pcicfg_base = -1, .resindex_imr_base = -1, @@ -166,6 +167,9 @@ static struct pci_driver snd_sof_pci_amd_rn_driver = { .id_table = rn_pci_ids, .probe = acp_pci_rn_probe, .remove = acp_pci_rn_remove, + .driver = { + .pm = &sof_pci_pm, + }, }; module_pci_driver(snd_sof_pci_amd_rn_driver); diff --git a/sound/soc/sof/amd/renoir.c b/sound/soc/sof/amd/renoir.c index 70190365328c..9261c8bc2236 100644 --- a/sound/soc/sof/amd/renoir.c +++ b/sound/soc/sof/amd/renoir.c @@ -173,6 +173,10 @@ struct snd_sof_dsp_ops sof_renoir_ops = { /* Trace Logger */ .trace_init = acp_sof_trace_init, .trace_release = acp_sof_trace_release, + + /* PM */ + .suspend = amd_sof_acp_suspend, + .resume = amd_sof_acp_resume, }; EXPORT_SYMBOL(sof_renoir_ops); From e53b20598f394e37951d6355f1c88ae01165b53f Mon Sep 17 00:00:00 2001 From: YC Hung Date: Mon, 6 Jun 2022 16:02:09 -0500 Subject: [PATCH 2/5] ASoC: SOF: mediatek: revise mt8195 clock sequence MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit clock enable : enable and set audio_h selection as 26M. Reviewed-by: Bard Liao Reviewed-by: Péter Ujfalusi Signed-off-by: YC Hung Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20220606210212.146626-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/mediatek/mt8195/mt8195-clk.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/sof/mediatek/mt8195/mt8195-clk.c b/sound/soc/sof/mediatek/mt8195/mt8195-clk.c index 6bcb4b9b00fb..9ef08e43aa38 100644 --- a/sound/soc/sof/mediatek/mt8195/mt8195-clk.c +++ b/sound/soc/sof/mediatek/mt8195/mt8195-clk.c @@ -132,6 +132,13 @@ static int adsp_default_clk_init(struct snd_sof_dev *sdev, bool enable) return ret; } + ret = clk_set_parent(priv->clk[CLK_TOP_AUDIO_H], + priv->clk[CLK_TOP_CLK26M]); + if (ret) { + dev_err(dev, "set audio_h_sel failed %d\n", ret); + return ret; + } + ret = adsp_enable_all_clock(sdev); if (ret) { dev_err(dev, "failed to adsp_enable_clock: %d\n", ret); From fd43dcbb859c85831a05e37287e1c5395f54aba8 Mon Sep 17 00:00:00 2001 From: YC Hung Date: Mon, 6 Jun 2022 16:02:10 -0500 Subject: [PATCH 3/5] ASoC: SOF: mediatek: Add shared_size for mediatek common chip information Add shared_size for mediatek common chip information which is used for audio and trace dma. Reviewed-by: Curtis Malainey Reviewed-by: Ranjani Sridharan Signed-off-by: YC Hung Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20220606210212.146626-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/mediatek/adsp_helper.h | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/sof/mediatek/adsp_helper.h b/sound/soc/sof/mediatek/adsp_helper.h index 4ab998756bbc..d41e904e6614 100644 --- a/sound/soc/sof/mediatek/adsp_helper.h +++ b/sound/soc/sof/mediatek/adsp_helper.h @@ -20,6 +20,7 @@ struct mtk_adsp_chip_info { u32 sramsize; u32 dramsize; u32 cfgregsize; + u32 shared_size; void __iomem *va_sram; /* corresponding to pa_sram */ void __iomem *va_dram; /* corresponding to pa_dram */ void __iomem *va_cfgreg; From 0bf4276cc7883d65e594926c1159d4c0712d02e7 Mon Sep 17 00:00:00 2001 From: YC Hung Date: Mon, 6 Jun 2022 16:02:11 -0500 Subject: [PATCH 4/5] ASoC: SOF: mediatek: mt8195 modify dram type as non-cache Modify dram as non-cache memory type to avoid wrong access between host and dsp side and get the size of shared dma from device tree. Reviewed-by: Curtis Malainey Reviewed-by: Ranjani Sridharan Signed-off-by: YC Hung Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20220606210212.146626-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/mediatek/mt8195/mt8195.c | 37 +++++++++++++++----------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.c b/sound/soc/sof/mediatek/mt8195/mt8195.c index 30111ab23bf5..64d1b5a4e31b 100644 --- a/sound/soc/sof/mediatek/mt8195/mt8195.c +++ b/sound/soc/sof/mediatek/mt8195/mt8195.c @@ -145,6 +145,14 @@ static int platform_parse_resource(struct platform_device *pdev, void *data) dev_dbg(dev, "DMA %pR\n", &res); + adsp->pa_shared_dram = (phys_addr_t)res.start; + adsp->shared_size = resource_size(&res); + if (adsp->pa_shared_dram & DRAM_REMAP_MASK) { + dev_err(dev, "adsp shared dma memory(%#x) is not 4K-aligned\n", + (u32)adsp->pa_shared_dram); + return -EINVAL; + } + ret = of_reserved_mem_device_init(dev); if (ret) { dev_err(dev, "of_reserved_mem_device_init failed\n"); @@ -273,23 +281,18 @@ static int adsp_shared_base_ioremap(struct platform_device *pdev, void *data) { struct device *dev = &pdev->dev; struct mtk_adsp_chip_info *adsp = data; - u32 shared_size; /* remap shared-dram base to be non-cachable */ - shared_size = TOTAL_SIZE_SHARED_DRAM_FROM_TAIL; - adsp->pa_shared_dram = adsp->pa_dram + adsp->dramsize - shared_size; - if (adsp->va_dram) { - adsp->shared_dram = adsp->va_dram + DSP_DRAM_SIZE - shared_size; - } else { - adsp->shared_dram = devm_ioremap(dev, adsp->pa_shared_dram, - shared_size); - if (!adsp->shared_dram) { - dev_err(dev, "ioremap failed for shared DRAM\n"); - return -ENOMEM; - } + adsp->shared_dram = devm_ioremap(dev, adsp->pa_shared_dram, + adsp->shared_size); + if (!adsp->shared_dram) { + dev_err(dev, "failed to ioremap base %pa size %#x\n", + adsp->shared_dram, adsp->shared_size); + return -ENOMEM; } + dev_dbg(dev, "shared-dram vbase=%p, phy addr :%pa, size=%#x\n", - adsp->shared_dram, &adsp->pa_shared_dram, shared_size); + adsp->shared_dram, &adsp->pa_shared_dram, adsp->shared_size); return 0; } @@ -361,9 +364,11 @@ static int mt8195_dsp_probe(struct snd_sof_dev *sdev) goto err_adsp_sram_power_off; } - sdev->bar[SOF_FW_BLK_TYPE_SRAM] = devm_ioremap_wc(sdev->dev, - priv->adsp->pa_dram, - priv->adsp->dramsize); + priv->adsp->va_sram = sdev->bar[SOF_FW_BLK_TYPE_IRAM]; + + sdev->bar[SOF_FW_BLK_TYPE_SRAM] = devm_ioremap(sdev->dev, + priv->adsp->pa_dram, + priv->adsp->dramsize); if (!sdev->bar[SOF_FW_BLK_TYPE_SRAM]) { dev_err(sdev->dev, "failed to ioremap base %pa size %#x\n", &priv->adsp->pa_dram, priv->adsp->dramsize); From 078f28fee5aa417169d8e8906815c684beddbe74 Mon Sep 17 00:00:00 2001 From: YC Hung Date: Mon, 6 Jun 2022 16:02:12 -0500 Subject: [PATCH 5/5] ASoC: SOF: mediatek: mt8195 suspend check dsp idle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit During suspend flow, sof_suspend will be called and the pm_ops->ctx_save callback notifies DSP of the upcoming power down. Upon receipt of the ctx_save IPC, the DSP will start the D3 transition. Before the DSP enter idle, an interrupt is generated to notify the host of the power state change. Since the host and DSP are two different processors, there could be a race condition, which can be avoided by polling with 1s timeout and 500us intervals Reviewed-by: Péter Ujfalusi Signed-off-by: YC Hung Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20220606210212.146626-6-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/mediatek/mt8195/mt8195.c | 13 +++++++++++++ sound/soc/sof/mediatek/mt8195/mt8195.h | 5 +++++ 2 files changed, 18 insertions(+) diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.c b/sound/soc/sof/mediatek/mt8195/mt8195.c index 64d1b5a4e31b..9c146015cd1b 100644 --- a/sound/soc/sof/mediatek/mt8195/mt8195.c +++ b/sound/soc/sof/mediatek/mt8195/mt8195.c @@ -443,6 +443,19 @@ static int mt8195_dsp_suspend(struct snd_sof_dev *sdev, u32 target_state) { struct platform_device *pdev = container_of(sdev->dev, struct platform_device, dev); int ret; + u32 reset_sw, dbg_pc; + + /* wait dsp enter idle, timeout is 1 second */ + ret = snd_sof_dsp_read_poll_timeout(sdev, DSP_REG_BAR, + DSP_RESET_SW, reset_sw, + ((reset_sw & ADSP_PWAIT) == ADSP_PWAIT), + SUSPEND_DSP_IDLE_POLL_INTERVAL_US, + SUSPEND_DSP_IDLE_TIMEOUT_US); + if (ret < 0) { + dbg_pc = snd_sof_dsp_read(sdev, DSP_REG_BAR, DSP_PDEBUGPC); + dev_warn(sdev->dev, "dsp not idle, powering off anyway : swrest %#x, pc %#x, ret %d\n", + reset_sw, dbg_pc, ret); + } /* stall and reset dsp */ sof_hifixdsp_shutdown(sdev); diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.h b/sound/soc/sof/mediatek/mt8195/mt8195.h index 929424182357..7ffd523f936c 100644 --- a/sound/soc/sof/mediatek/mt8195/mt8195.h +++ b/sound/soc/sof/mediatek/mt8195/mt8195.h @@ -34,6 +34,7 @@ struct snd_sof_dev; #define ADSP_DRESET_SW BIT(1) #define ADSP_RUNSTALL BIT(3) #define STATVECTOR_SEL BIT(4) +#define ADSP_PWAIT BIT(16) #define DSP_PFAULTBUS 0x0028 #define DSP_PFAULTINFO 0x002c #define DSP_GPR00 0x0030 @@ -153,6 +154,10 @@ struct snd_sof_dev; #define DRAM_REMAP_SHIFT 12 #define DRAM_REMAP_MASK (BIT(DRAM_REMAP_SHIFT) - 1) +/* suspend dsp idle check interval and timeout */ +#define SUSPEND_DSP_IDLE_TIMEOUT_US 1000000 /* timeout to wait dsp idle, 1 sec */ +#define SUSPEND_DSP_IDLE_POLL_INTERVAL_US 500 /* 0.5 msec */ + void sof_hifixdsp_boot_sequence(struct snd_sof_dev *sdev, u32 boot_addr); void sof_hifixdsp_shutdown(struct snd_sof_dev *sdev); #endif