drm/radeon: add support for vce 2.0 clock gating
authorAlex Deucher <alexander.deucher@amd.com>
Thu, 5 Sep 2013 19:14:28 +0000 (15:14 -0400)
committerChristian König <christian.koenig@amd.com>
Tue, 18 Feb 2014 15:11:44 +0000 (16:11 +0100)
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/radeon/cikd.h
drivers/gpu/drm/radeon/vce_v2_0.c

index ee16380ceba86795dd04756656d95ef213ac6ed4..213873270d5f6b705974aa57867f0dff47b7901a 100644 (file)
 #define VCE_RB_RPTR                    0x2018c
 #define VCE_RB_WPTR                    0x20190
 #define VCE_CLOCK_GATING_A             0x202f8
+#      define CGC_CLK_GATE_DLY_TIMER_MASK      (0xf << 0)
+#      define CGC_CLK_GATE_DLY_TIMER(x)        ((x) << 0)
+#      define CGC_CLK_GATER_OFF_DLY_TIMER_MASK (0xff << 4)
+#      define CGC_CLK_GATER_OFF_DLY_TIMER(x)   ((x) << 4)
+#      define CGC_UENC_WAIT_AWAKE      (1 << 18)
 #define VCE_CLOCK_GATING_B             0x202fc
+#define VCE_CGTT_CLK_OVERRIDE          0x207a0
 #define VCE_UENC_CLOCK_GATING          0x207bc
+#      define CLOCK_ON_DELAY_MASK      (0xf << 0)
+#      define CLOCK_ON_DELAY(x)        ((x) << 0)
+#      define CLOCK_OFF_DELAY_MASK     (0xff << 4)
+#      define CLOCK_OFF_DELAY(x)       ((x) << 4)
 #define VCE_UENC_REG_CLOCK_GATING      0x207c0
 #define VCE_SYS_INT_EN                 0x21300
 #      define VCE_SYS_INT_TRAP_INTERRUPT_EN    (1 << 3)
index 4911d1b00e3bd60a3e17cd28eb810e097b4c0a06..1ac7bb825a1b3bfecea601d76f8e33c2b8d581ff 100644 (file)
 #include "radeon_asic.h"
 #include "cikd.h"
 
+static void vce_v2_0_set_sw_cg(struct radeon_device *rdev, bool gated)
+{
+       u32 tmp;
+
+       if (gated) {
+               tmp = RREG32(VCE_CLOCK_GATING_B);
+               tmp |= 0xe70000;
+               WREG32(VCE_CLOCK_GATING_B, tmp);
+
+               tmp = RREG32(VCE_UENC_CLOCK_GATING);
+               tmp |= 0xff000000;
+               WREG32(VCE_UENC_CLOCK_GATING, tmp);
+
+               tmp = RREG32(VCE_UENC_REG_CLOCK_GATING);
+               tmp &= ~0x3fc;
+               WREG32(VCE_UENC_REG_CLOCK_GATING, tmp);
+
+               WREG32(VCE_CGTT_CLK_OVERRIDE, 0);
+    } else {
+               tmp = RREG32(VCE_CLOCK_GATING_B);
+               tmp |= 0xe7;
+               tmp &= ~0xe70000;
+               WREG32(VCE_CLOCK_GATING_B, tmp);
+
+               tmp = RREG32(VCE_UENC_CLOCK_GATING);
+               tmp |= 0x1fe000;
+               tmp &= ~0xff000000;
+               WREG32(VCE_UENC_CLOCK_GATING, tmp);
+
+               tmp = RREG32(VCE_UENC_REG_CLOCK_GATING);
+               tmp |= 0x3fc;
+               WREG32(VCE_UENC_REG_CLOCK_GATING, tmp);
+       }
+}
+
+static void vce_v2_0_set_dyn_cg(struct radeon_device *rdev, bool gated)
+{
+       u32 orig, tmp;
+
+       tmp = RREG32(VCE_CLOCK_GATING_B);
+       tmp &= ~0x00060006;
+       if (gated) {
+               tmp |= 0xe10000;
+       } else {
+               tmp |= 0xe1;
+               tmp &= ~0xe10000;
+       }
+       WREG32(VCE_CLOCK_GATING_B, tmp);
+
+       orig = tmp = RREG32(VCE_UENC_CLOCK_GATING);
+       tmp &= ~0x1fe000;
+       tmp &= ~0xff000000;
+       if (tmp != orig)
+               WREG32(VCE_UENC_CLOCK_GATING, tmp);
+
+       orig = tmp = RREG32(VCE_UENC_REG_CLOCK_GATING);
+       tmp &= ~0x3fc;
+       if (tmp != orig)
+               WREG32(VCE_UENC_REG_CLOCK_GATING, tmp);
+
+       if (gated)
+               WREG32(VCE_CGTT_CLK_OVERRIDE, 0);
+}
+
+static void vce_v2_0_disable_cg(struct radeon_device *rdev)
+{
+       WREG32(VCE_CGTT_CLK_OVERRIDE, 7);
+}
+
+void vce_v2_0_enable_mgcg(struct radeon_device *rdev, bool enable)
+{
+       bool sw_cg = false;
+
+       if (enable && (rdev->cg_flags & RADEON_CG_SUPPORT_VCE_MGCG)) {
+               if (sw_cg)
+                       vce_v2_0_set_sw_cg(rdev, true);
+               else
+                       vce_v2_0_set_dyn_cg(rdev, true);
+       } else {
+               vce_v2_0_disable_cg(rdev);
+
+               if (sw_cg)
+                       vce_v2_0_set_sw_cg(rdev, false);
+               else
+                       vce_v2_0_set_dyn_cg(rdev, false);
+       }
+}
+
+static void vce_v2_0_init_cg(struct radeon_device *rdev)
+{
+       u32 tmp;
+
+       tmp = RREG32(VCE_CLOCK_GATING_A);
+       tmp &= ~(CGC_CLK_GATE_DLY_TIMER_MASK | CGC_CLK_GATER_OFF_DLY_TIMER_MASK);
+       tmp |= (CGC_CLK_GATE_DLY_TIMER(0) | CGC_CLK_GATER_OFF_DLY_TIMER(4));
+       tmp |= CGC_UENC_WAIT_AWAKE;
+       WREG32(VCE_CLOCK_GATING_A, tmp);
+
+       tmp = RREG32(VCE_UENC_CLOCK_GATING);
+       tmp &= ~(CLOCK_ON_DELAY_MASK | CLOCK_OFF_DELAY_MASK);
+       tmp |= (CLOCK_ON_DELAY(0) | CLOCK_OFF_DELAY(4));
+       WREG32(VCE_UENC_CLOCK_GATING, tmp);
+
+       tmp = RREG32(VCE_CLOCK_GATING_B);
+       tmp |= 0x10;
+       tmp &= ~0x100000;
+       WREG32(VCE_CLOCK_GATING_B, tmp);
+}
+
 int vce_v2_0_resume(struct radeon_device *rdev)
 {
        uint64_t addr = rdev->vce.gpu_addr;
@@ -66,5 +175,7 @@ int vce_v2_0_resume(struct radeon_device *rdev)
        WREG32_P(VCE_SYS_INT_EN, VCE_SYS_INT_TRAP_INTERRUPT_EN,
                 ~VCE_SYS_INT_TRAP_INTERRUPT_EN);
 
+       vce_v2_0_init_cg(rdev);
+
        return 0;
 }