ASoC: SOF: amd: refactor acp driver pm ops
authorVijendar Mukunda <Vijendar.Mukunda@amd.com>
Mon, 29 Jan 2024 05:51:47 +0000 (11:21 +0530)
committerMark Brown <broonie@kernel.org>
Tue, 30 Jan 2024 16:06:43 +0000 (16:06 +0000)
Refactor acp driver pm ops to support SoundWire interface.

When SoundWire configuration is enabled, In case of ClockStopMode,
DSP soft reset should be applied and for rest of the scenarios
acp init/deinit sequence should be invoked.

Signed-off-by: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
Link: https://msgid.link/r/20240129055147.1493853-14-Vijendar.Mukunda@amd.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/sof/amd/acp-dsp-offset.h
sound/soc/sof/amd/acp.c
sound/soc/sof/amd/acp.h

index c1bdc028a61a42b36b2b327bec241ffa8e7d17bd..59afbe2e0f42059f6d84429bcb601c59d8af0566 100644 (file)
 /* 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
index 7a34faae9889b5c8c39894f9b1bfa2a10ef88f14..920fead2d93d50148bf7bcea9bed9517907cea99 100644 (file)
@@ -482,6 +482,31 @@ static int acp_reset(struct snd_sof_dev *sdev)
        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;
+}
+
 static int acp_init(struct snd_sof_dev *sdev)
 {
        int ret;
@@ -498,10 +523,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");
@@ -517,13 +566,19 @@ 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);
 
index e94713d7ff1d9f50551948383d839b23c3bbf9dd..947068da39b5350e0f14d05a47b3e4ba1630a7e0 100644 (file)
@@ -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
@@ -242,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);