drm/amd/amdgpu: Enabling ACP clock in hw_init (v2)
authorAkshu Agrawal <akshu.agrawal@amd.com>
Mon, 18 Sep 2017 06:56:07 +0000 (12:26 +0530)
committerAlex Deucher <alexander.deucher@amd.com>
Fri, 3 Nov 2017 19:44:46 +0000 (15:44 -0400)
Enabling of ACP in hw_init does away with requirement of order
of probe on designware_i2s and acp dma driver. designware_i2s
reads i2s registers and this use to fail if acp dma driver was not probed
prior to it.

BUG=:b:62103837
TEST=modprobe snd-soc-acp-pcm
modprobe snd-soc-acp-rt5645-mach
aplay -l
**** List of PLAYBACK Hardware Devices ****
card 0: acprt5650 [acprt5650], device 0: RT5645_AIF1 rt5645-aif1-0 []
  Subdevices: 1/1
    Subdevice #0: subdevice #0

v2: use proper device in dev_err to fix warnings (Alex)

Signed-off-by: Akshu Agrawal <akshu.agrawal@amd.com>
Reviewed-on: https://chromium-review.googlesource.com/670207
Reviewed-by: Jason Clinton <jclinton@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/676628
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c

index a52795d9b45852a371fed81a8f17a51d63bab120..023bfdb3e63f58dfd71c157cf663ac2b6220cd73 100644 (file)
 
 #include "acp_gfx_if.h"
 
-#define ACP_TILE_ON_MASK                0x03
-#define ACP_TILE_OFF_MASK               0x02
-#define ACP_TILE_ON_RETAIN_REG_MASK     0x1f
-#define ACP_TILE_OFF_RETAIN_REG_MASK    0x20
-
-#define ACP_TILE_P1_MASK                0x3e
-#define ACP_TILE_P2_MASK                0x3d
-#define ACP_TILE_DSP0_MASK              0x3b
-#define ACP_TILE_DSP1_MASK              0x37
-
-#define ACP_TILE_DSP2_MASK              0x2f
-
-#define ACP_DMA_REGS_END               0x146c0
-#define ACP_I2S_PLAY_REGS_START                0x14840
-#define ACP_I2S_PLAY_REGS_END          0x148b4
-#define ACP_I2S_CAP_REGS_START         0x148b8
-#define ACP_I2S_CAP_REGS_END           0x1496c
-
-#define ACP_I2S_COMP1_CAP_REG_OFFSET   0xac
-#define ACP_I2S_COMP2_CAP_REG_OFFSET   0xa8
-#define ACP_I2S_COMP1_PLAY_REG_OFFSET  0x6c
-#define ACP_I2S_COMP2_PLAY_REG_OFFSET  0x68
-
-#define mmACP_PGFSM_RETAIN_REG         0x51c9
-#define mmACP_PGFSM_CONFIG_REG         0x51ca
-#define mmACP_PGFSM_READ_REG_0         0x51cc
-
-#define mmACP_MEM_SHUT_DOWN_REQ_LO     0x51f8
-#define mmACP_MEM_SHUT_DOWN_REQ_HI     0x51f9
-#define mmACP_MEM_SHUT_DOWN_STS_LO     0x51fa
-#define mmACP_MEM_SHUT_DOWN_STS_HI     0x51fb
-
-#define ACP_TIMEOUT_LOOP               0x000000FF
-#define ACP_DEVS                       3
-#define ACP_SRC_ID                     162
+#define ACP_TILE_ON_MASK                       0x03
+#define ACP_TILE_OFF_MASK                      0x02
+#define ACP_TILE_ON_RETAIN_REG_MASK            0x1f
+#define ACP_TILE_OFF_RETAIN_REG_MASK           0x20
+
+#define ACP_TILE_P1_MASK                       0x3e
+#define ACP_TILE_P2_MASK                       0x3d
+#define ACP_TILE_DSP0_MASK                     0x3b
+#define ACP_TILE_DSP1_MASK                     0x37
+
+#define ACP_TILE_DSP2_MASK                     0x2f
+
+#define ACP_DMA_REGS_END                       0x146c0
+#define ACP_I2S_PLAY_REGS_START                        0x14840
+#define ACP_I2S_PLAY_REGS_END                  0x148b4
+#define ACP_I2S_CAP_REGS_START                 0x148b8
+#define ACP_I2S_CAP_REGS_END                   0x1496c
+
+#define ACP_I2S_COMP1_CAP_REG_OFFSET           0xac
+#define ACP_I2S_COMP2_CAP_REG_OFFSET           0xa8
+#define ACP_I2S_COMP1_PLAY_REG_OFFSET          0x6c
+#define ACP_I2S_COMP2_PLAY_REG_OFFSET          0x68
+
+#define mmACP_PGFSM_RETAIN_REG                 0x51c9
+#define mmACP_PGFSM_CONFIG_REG                 0x51ca
+#define mmACP_PGFSM_READ_REG_0                 0x51cc
+
+#define mmACP_MEM_SHUT_DOWN_REQ_LO             0x51f8
+#define mmACP_MEM_SHUT_DOWN_REQ_HI             0x51f9
+#define mmACP_MEM_SHUT_DOWN_STS_LO             0x51fa
+#define mmACP_MEM_SHUT_DOWN_STS_HI             0x51fb
+
+#define mmACP_CONTROL                          0x5131
+#define mmACP_STATUS                           0x5133
+#define mmACP_SOFT_RESET                       0x5134
+#define ACP_CONTROL__ClkEn_MASK                0x1
+#define ACP_SOFT_RESET__SoftResetAud_MASK      0x100
+#define ACP_SOFT_RESET__SoftResetAudDone_MASK  0x1000000
+#define ACP_CLOCK_EN_TIME_OUT_VALUE            0x000000FF
+#define ACP_SOFT_RESET_DONE_TIME_OUT_VALUE     0x000000FF
+
+#define ACP_TIMEOUT_LOOP                       0x000000FF
+#define ACP_DEVS                               3
+#define ACP_SRC_ID                             162
 
 enum {
        ACP_TILE_P1 = 0,
@@ -260,6 +269,8 @@ static int acp_hw_init(void *handle)
 {
        int r, i;
        uint64_t acp_base;
+       u32 val = 0;
+       u32 count = 0;
        struct device *dev;
        struct i2s_platform_data *i2s_pdata;
 
@@ -400,6 +411,46 @@ static int acp_hw_init(void *handle)
                }
        }
 
+       /* Assert Soft reset of ACP */
+       val = cgs_read_register(adev->acp.cgs_device, mmACP_SOFT_RESET);
+
+       val |= ACP_SOFT_RESET__SoftResetAud_MASK;
+       cgs_write_register(adev->acp.cgs_device, mmACP_SOFT_RESET, val);
+
+       count = ACP_SOFT_RESET_DONE_TIME_OUT_VALUE;
+       while (true) {
+               val = cgs_read_register(adev->acp.cgs_device, mmACP_SOFT_RESET);
+               if (ACP_SOFT_RESET__SoftResetAudDone_MASK ==
+                   (val & ACP_SOFT_RESET__SoftResetAudDone_MASK))
+                       break;
+               if (--count == 0) {
+                       dev_err(&adev->pdev->dev, "Failed to reset ACP\n");
+                       return -ETIMEDOUT;
+               }
+               udelay(100);
+       }
+       /* Enable clock to ACP and wait until the clock is enabled */
+       val = cgs_read_register(adev->acp.cgs_device, mmACP_CONTROL);
+       val = val | ACP_CONTROL__ClkEn_MASK;
+       cgs_write_register(adev->acp.cgs_device, mmACP_CONTROL, val);
+
+       count = ACP_CLOCK_EN_TIME_OUT_VALUE;
+
+       while (true) {
+               val = cgs_read_register(adev->acp.cgs_device, mmACP_STATUS);
+               if (val & (u32) 0x1)
+                       break;
+               if (--count == 0) {
+                       dev_err(&adev->pdev->dev, "Failed to reset ACP\n");
+                       return -ETIMEDOUT;
+               }
+               udelay(100);
+       }
+       /* Deassert the SOFT RESET flags */
+       val = cgs_read_register(adev->acp.cgs_device, mmACP_SOFT_RESET);
+       val &= ~ACP_SOFT_RESET__SoftResetAud_MASK;
+       cgs_write_register(adev->acp.cgs_device, mmACP_SOFT_RESET, val);
+
        return 0;
 }
 
@@ -412,6 +463,8 @@ static int acp_hw_init(void *handle)
 static int acp_hw_fini(void *handle)
 {
        int i, ret;
+       u32 val = 0;
+       u32 count = 0;
        struct device *dev;
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
@@ -419,6 +472,42 @@ static int acp_hw_fini(void *handle)
        if (!adev->acp.acp_cell)
                return 0;
 
+       /* Assert Soft reset of ACP */
+       val = cgs_read_register(adev->acp.cgs_device, mmACP_SOFT_RESET);
+
+       val |= ACP_SOFT_RESET__SoftResetAud_MASK;
+       cgs_write_register(adev->acp.cgs_device, mmACP_SOFT_RESET, val);
+
+       count = ACP_SOFT_RESET_DONE_TIME_OUT_VALUE;
+       while (true) {
+               val = cgs_read_register(adev->acp.cgs_device, mmACP_SOFT_RESET);
+               if (ACP_SOFT_RESET__SoftResetAudDone_MASK ==
+                   (val & ACP_SOFT_RESET__SoftResetAudDone_MASK))
+                       break;
+               if (--count == 0) {
+                       dev_err(&adev->pdev->dev, "Failed to reset ACP\n");
+                       return -ETIMEDOUT;
+               }
+               udelay(100);
+       }
+       /* Disable ACP clock */
+       val = cgs_read_register(adev->acp.cgs_device, mmACP_CONTROL);
+       val &= ~ACP_CONTROL__ClkEn_MASK;
+       cgs_write_register(adev->acp.cgs_device, mmACP_CONTROL, val);
+
+       count = ACP_CLOCK_EN_TIME_OUT_VALUE;
+
+       while (true) {
+               val = cgs_read_register(adev->acp.cgs_device, mmACP_STATUS);
+               if (val & (u32) 0x1)
+                       break;
+               if (--count == 0) {
+                       dev_err(&adev->pdev->dev, "Failed to reset ACP\n");
+                       return -ETIMEDOUT;
+               }
+               udelay(100);
+       }
+
        if (adev->acp.acp_genpd) {
                for (i = 0; i < ACP_DEVS ; i++) {
                        dev = get_mfd_cell_dev(adev->acp.acp_cell[i].name, i);