Different from ordinary stoney,For Stoney Fanless,
smu firmware do not poweron/off acp tiles, so need to
poweron/off acp in driver.

Partially revert
'commit f766dd23e5ce ("drm/amdgpu/acp: Powrgate acp via smu")'

Signed-off-by: Rex Zhu <rex....@amd.com>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c | 118 +++++++++++++++++++++++++++++---
 drivers/gpu/drm/amd/amdgpu/amdgpu_acp.h |   4 ++
 2 files changed, 114 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c
index 8bf3a98..f673c99 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c
@@ -91,6 +91,8 @@ enum {
        ACP_TILE_DSP1,
        ACP_TILE_DSP2,
 };
+static int acp_set_powergating_state(void *handle,
+                                    enum amd_powergating_state state);
 
 static int acp_sw_init(void *handle)
 {
@@ -135,8 +137,7 @@ static int acp_poweroff(struct generic_pm_domain *genpd)
         * 2. power off the acp tiles
         * 3. check and enter ulv state
         */
-               if (adev->powerplay.pp_funcs->set_powergating_by_smu)
-                       amdgpu_dpm_set_powergating_by_smu(adev, 
AMD_IP_BLOCK_TYPE_ACP, true);
+               acp_set_powergating_state(adev, AMD_PG_STATE_GATE);
        }
        return 0;
 }
@@ -155,8 +156,7 @@ static int acp_poweron(struct generic_pm_domain *genpd)
         * 2. turn on acp clock
         * 3. power on acp tiles
         */
-               if (adev->powerplay.pp_funcs->set_powergating_by_smu)
-                       amdgpu_dpm_set_powergating_by_smu(adev, 
AMD_IP_BLOCK_TYPE_ACP, false);
+               acp_set_powergating_state(adev, AMD_PG_STATE_UNGATE);
        }
        return 0;
 }
@@ -201,7 +201,7 @@ static int acp_hw_init(void *handle)
                            ip_block->version->major, ip_block->version->minor);
        /* -ENODEV means board uses AZ rather than ACP */
        if (r == -ENODEV) {
-               amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, 
true);
+               acp_set_powergating_state(adev, AMD_PG_STATE_GATE);
                return 0;
        } else if (r) {
                return r;
@@ -407,7 +407,7 @@ static int acp_hw_fini(void *handle)
 
        /* return early if no ACP */
        if (!adev->acp.acp_genpd) {
-               amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, 
false);
+               acp_set_powergating_state(adev, AMD_PG_STATE_UNGATE);
                return 0;
        }
 
@@ -469,7 +469,7 @@ static int acp_suspend(void *handle)
 
        /* power up on suspend */
        if (!adev->acp.acp_cell)
-               amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, 
false);
+               acp_set_powergating_state(adev, AMD_PG_STATE_UNGATE);
        return 0;
 }
 
@@ -479,7 +479,7 @@ static int acp_resume(void *handle)
 
        /* power down again on resume */
        if (!adev->acp.acp_cell)
-               amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, 
true);
+               acp_set_powergating_state(adev, AMD_PG_STATE_GATE);
        return 0;
 }
 
@@ -509,15 +509,117 @@ static int acp_set_clockgating_state(void *handle,
        return 0;
 }
 
+/* power off a tile/block within ACP */
+static int acp_suspend_tile(struct amdgpu_device *adev, int tile)
+{
+       u32 val = 0;
+       u32 count = 0;
+
+       if ((tile  < ACP_TILE_P1) || (tile > ACP_TILE_DSP2)) {
+               pr_err("Invalid ACP tile : %d to suspend\n", tile);
+               return -1;
+       }
+
+       val = RREG32(mmACP_PGFSM_READ_REG_0 + tile);
+       val &= ACP_TILE_ON_MASK;
+
+       if (val == 0x0) {
+               val = RREG32(mmACP_PGFSM_RETAIN_REG);
+               val = val | (1 << tile);
+               WREG32(mmACP_PGFSM_RETAIN_REG, val);
+               WREG32(mmACP_PGFSM_CONFIG_REG,
+                                       0x500 + tile);
+
+               count = ACP_TIMEOUT_LOOP;
+               while (true) {
+                       val = RREG32(mmACP_PGFSM_READ_REG_0 + tile);
+                       val = val & ACP_TILE_ON_MASK;
+                       if (val == ACP_TILE_OFF_MASK)
+                               break;
+                       if (--count == 0) {
+                               pr_err("Timeout reading ACP PGFSM status\n");
+                               return -ETIMEDOUT;
+                       }
+                       udelay(100);
+               }
+
+               val = RREG32(mmACP_PGFSM_RETAIN_REG);
+
+               val |= ACP_TILE_OFF_RETAIN_REG_MASK;
+               WREG32(mmACP_PGFSM_RETAIN_REG, val);
+       }
+       return 0;
+}
+
+/* power on a tile/block within ACP */
+static int acp_resume_tile(struct amdgpu_device *adev, int tile)
+{
+       u32 val = 0;
+       u32 count = 0;
+
+       if ((tile < ACP_TILE_P1) || (tile > ACP_TILE_DSP2)) {
+               pr_err("Invalid ACP tile to resume\n");
+               return -1;
+       }
+
+       val = RREG32(mmACP_PGFSM_READ_REG_0 + tile);
+       val = val & ACP_TILE_ON_MASK;
+
+       if (val != 0x0) {
+               WREG32(mmACP_PGFSM_CONFIG_REG,
+                                       0x600 + tile);
+               count = ACP_TIMEOUT_LOOP;
+               while (true) {
+                       val = RREG32(mmACP_PGFSM_READ_REG_0 + tile);
+                       val = val & ACP_TILE_ON_MASK;
+                       if (val == 0x0)
+                               break;
+                       if (--count == 0) {
+                               pr_err("Timeout reading ACP PGFSM status\n");
+                               return -ETIMEDOUT;
+                       }
+                       udelay(100);
+               }
+               val = RREG32(mmACP_PGFSM_RETAIN_REG);
+               if (tile == ACP_TILE_P1)
+                       val = val & (ACP_TILE_P1_MASK);
+               else if (tile == ACP_TILE_P2)
+                       val = val & (ACP_TILE_P2_MASK);
+
+               WREG32(mmACP_PGFSM_RETAIN_REG, val);
+       }
+       return 0;
+}
+
 static int acp_set_powergating_state(void *handle,
                                     enum amd_powergating_state state)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
        bool enable = state == AMD_PG_STATE_GATE ? true : false;
+       int i, ret;
+
+       if (!enable && IS_ST_KICKER(adev)) {
+               for (i = 0; i < 2; i++) {
+                       /* do not power up DSPs which are not going to be used 
*/
+                       ret = acp_resume_tile(adev, ACP_TILE_P1 + i);
+                       if (ret) {
+                               pr_err("ACP tile %d resume failed\n", i);
+                               break;
+                       }
+               }
+       }
 
        if (adev->powerplay.pp_funcs->set_powergating_by_smu)
                amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, 
enable);
 
+       if (enable && IS_ST_KICKER(adev)) {
+               for (i = 0; i < 5; i++) {
+                       ret = acp_suspend_tile(adev, ACP_TILE_P1 + i);
+                       if (ret)
+                               pr_err("ACP tile %d suspend failed\n", i);
+               }
+       }
+
        return 0;
 }
 
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.h
index a288ce2..fcb2e7d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.h
@@ -39,4 +39,8 @@ struct amdgpu_acp {
 
 extern const struct amdgpu_ip_block_version acp_ip_block;
 
+#define IS_ST_KICKER(dev)  ((dev)->asic_type == CHIP_STONEY && \
+                          (((dev)->pm.fw_version & 0xff00) == 0x2100 || \
+                           ((dev)->pm.fw_version & 0xff00) == 0x1A00))
+
 #endif /* __AMDGPU_ACP_H__ */
-- 
1.9.1

_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

Reply via email to