drm/radeon: update rlc programming sequence on SI
authorAlex Deucher <alexander.deucher@amd.com>
Fri, 15 Feb 2013 21:49:59 +0000 (16:49 -0500)
committerAlex Deucher <alexander.deucher@amd.com>
Thu, 27 Jun 2013 23:16:29 +0000 (19:16 -0400)
This is required for certain power management features.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/radeon/si.c
drivers/gpu/drm/radeon/sid.h

index 9fd0bc379f361553e12e9543ffba85b18af65249..84ed3325a0d99f92b9e83edd5bf34cf447dd2b4b 100644 (file)
@@ -4418,14 +4418,93 @@ int si_rlc_init(struct radeon_device *rdev)
        return 0;
 }
 
+static void si_enable_gui_idle_interrupt(struct radeon_device *rdev,
+                                        bool enable)
+{
+       u32 tmp = RREG32(CP_INT_CNTL_RING0);
+       u32 mask;
+       int i;
+
+       if (enable)
+               tmp |= (CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE);
+       else
+               tmp &= ~(CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE);
+       WREG32(CP_INT_CNTL_RING0, tmp);
+
+       if (!enable) {
+               /* read a gfx register */
+               tmp = RREG32(DB_DEPTH_INFO);
+
+               mask = RLC_BUSY_STATUS | GFX_POWER_STATUS | GFX_CLOCK_STATUS | GFX_LS_STATUS;
+               for (i = 0; i < rdev->usec_timeout; i++) {
+                       if ((RREG32(RLC_STAT) & mask) == (GFX_CLOCK_STATUS | GFX_POWER_STATUS))
+                               break;
+                       udelay(1);
+               }
+       }
+}
+
+static void si_wait_for_rlc_serdes(struct radeon_device *rdev)
+{
+       int i;
+
+       for (i = 0; i < rdev->usec_timeout; i++) {
+               if (RREG32(RLC_SERDES_MASTER_BUSY_0) == 0)
+                       break;
+               udelay(1);
+       }
+
+       for (i = 0; i < rdev->usec_timeout; i++) {
+               if (RREG32(RLC_SERDES_MASTER_BUSY_1) == 0)
+                       break;
+               udelay(1);
+       }
+}
+
 static void si_rlc_stop(struct radeon_device *rdev)
 {
        WREG32(RLC_CNTL, 0);
+
+       si_enable_gui_idle_interrupt(rdev, false);
+
+       si_wait_for_rlc_serdes(rdev);
 }
 
 static void si_rlc_start(struct radeon_device *rdev)
 {
        WREG32(RLC_CNTL, RLC_ENABLE);
+
+       si_enable_gui_idle_interrupt(rdev, true);
+
+       udelay(50);
+}
+
+static bool si_lbpw_supported(struct radeon_device *rdev)
+{
+       u32 tmp;
+
+       /* Enable LBPW only for DDR3 */
+       tmp = RREG32(MC_SEQ_MISC0);
+       if ((tmp & 0xF0000000) == 0xB0000000)
+               return true;
+       return false;
+}
+
+static void si_enable_lbpw(struct radeon_device *rdev, bool enable)
+{
+       u32 tmp;
+
+       tmp = RREG32(RLC_LB_CNTL);
+       if (enable)
+               tmp |= LOAD_BALANCE_ENABLE;
+       else
+               tmp &= ~LOAD_BALANCE_ENABLE;
+       WREG32(RLC_LB_CNTL, tmp);
+
+       if (!enable) {
+               si_select_se_sh(rdev, 0xffffffff, 0xffffffff);
+               WREG32(SPI_LB_CU_MASK, 0x00ff);
+       }
 }
 
 static int si_rlc_resume(struct radeon_device *rdev)
@@ -4443,6 +4522,7 @@ static int si_rlc_resume(struct radeon_device *rdev)
        WREG32(RLC_LB_CNTL, 0);
        WREG32(RLC_LB_CNTR_MAX, 0xffffffff);
        WREG32(RLC_LB_CNTR_INIT, 0);
+       WREG32(RLC_LB_INIT_CU_MASK, 0xffffffff);
 
        WREG32(RLC_SAVE_AND_RESTORE_BASE, rdev->rlc.save_restore_gpu_addr >> 8);
        WREG32(RLC_CLEAR_STATE_RESTORE_BASE, rdev->rlc.clear_state_gpu_addr >> 8);
@@ -4457,6 +4537,8 @@ static int si_rlc_resume(struct radeon_device *rdev)
        }
        WREG32(RLC_UCODE_ADDR, 0);
 
+       si_enable_lbpw(rdev, si_lbpw_supported(rdev));
+
        si_rlc_start(rdev);
 
        return 0;
index 5f29d81d8db227a25e22e520beb9ae13843b570b..8786b6c93c67449294e1bd50a5ed891ea131903b 100644 (file)
 #define MC_IO_PAD_CNTL_D0                              0x29d0
 #define                MEM_FALL_OUT_CMD                        (1 << 8)
 
+#define MC_SEQ_MISC0                                           0x2a00
+
 #define MC_SEQ_IO_DEBUG_INDEX                          0x2a44
 #define MC_SEQ_IO_DEBUG_DATA                                   0x2a48
 
 #define                TCC_DISABLE_MASK                                0xFFFF0000
 #define                TCC_DISABLE_SHIFT                               16
 
+#define        SPI_LB_CU_MASK                                  0x9354
+
 #define        TA_CNTL_AUX                                     0x9508
 
 #define CC_RB_BACKEND_DISABLE                          0x98F4
 #define RLC_RL_BASE                                       0xC304
 #define RLC_RL_SIZE                                       0xC308
 #define RLC_LB_CNTL                                       0xC30C
+#       define LOAD_BALANCE_ENABLE                        (1 << 0)
 #define RLC_SAVE_AND_RESTORE_BASE                         0xC310
 #define RLC_LB_CNTR_MAX                                   0xC314
 #define RLC_LB_CNTR_INIT                                  0xC318
 #define RLC_CAPTURE_GPU_CLOCK_COUNT                       0xC340
 #define RLC_MC_CNTL                                       0xC344
 #define RLC_UCODE_CNTL                                    0xC348
+#define RLC_STAT                                          0xC34C
+#       define RLC_BUSY_STATUS                            (1 << 0)
+#       define GFX_POWER_STATUS                           (1 << 1)
+#       define GFX_CLOCK_STATUS                           (1 << 2)
+#       define GFX_LS_STATUS                              (1 << 3)
+
+#define RLC_LB_INIT_CU_MASK                               0xC41C
+
+#define RLC_SERDES_MASTER_BUSY_0                          0xC464
+#define RLC_SERDES_MASTER_BUSY_1                          0xC468
+
+#define DB_DEPTH_INFO                                   0x2803c
 
 #define PA_SC_RASTER_CONFIG                             0x28350
 #       define RASTER_CONFIG_RB_MAP_0                   0