drm/radeon: improve mc_stop/mc_resume on r5xx-r7xx
authorAlex Deucher <alexander.deucher@amd.com>
Wed, 12 Dec 2012 19:30:32 +0000 (14:30 -0500)
committerAlex Deucher <alexander.deucher@amd.com>
Wed, 12 Dec 2012 19:34:08 +0000 (14:34 -0500)
Along the same lines of what was done for evergreen+
in the last kernel.

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

index 2b960cb5c18a664a2ecf64b712bea3deeed06b63..909219b1bf805c0ad68849f54cc978c64209899e 100644 (file)
 #define R600_CONFIG_F0_BASE                                     0x542C
 #define R600_CONFIG_APER_SIZE                                   0x5430
 
+#define        R600_BIF_FB_EN                                          0x5490
+#define                R600_FB_READ_EN                                 (1 << 0)
+#define                R600_FB_WRITE_EN                                (1 << 1)
+
+#define R600_CITF_CNTL                                         0x200c
+#define                R600_BLACKOUT_MASK                              0x00000003
+
+#define R700_MC_CITF_CNTL                                      0x25c0
+
 #define R600_ROM_CNTL                              0x1600
 #       define R600_SCK_OVERWRITE                  (1 << 1)
 #       define R600_SCK_PRESCALE_CRYSTAL_CLK_SHIFT 28
index ae56673d24103662c6cb977d9d044da4a510ba18..c338931190a5d4c22a26ff4c4c24ce9d5ae2273b 100644 (file)
@@ -263,6 +263,7 @@ extern int rs690_mc_wait_for_idle(struct radeon_device *rdev);
 struct rv515_mc_save {
        u32 vga_render_control;
        u32 vga_hdp_control;
+       bool crtc_enabled[2];
 };
 
 int rv515_init(struct radeon_device *rdev);
index 785d09590b241d850972f1cbc0015889d5823bfd..2bb6d0e84b3d94361546d06705c5d3252b7126bf 100644 (file)
@@ -40,6 +40,12 @@ static int rv515_debugfs_ga_info_init(struct radeon_device *rdev);
 static void rv515_gpu_init(struct radeon_device *rdev);
 int rv515_mc_wait_for_idle(struct radeon_device *rdev);
 
+static const u32 crtc_offsets[2] =
+{
+       0,
+       AVIVO_D2CRTC_H_TOTAL - AVIVO_D1CRTC_H_TOTAL
+};
+
 void rv515_debugfs(struct radeon_device *rdev)
 {
        if (r100_debugfs_rbbm_init(rdev)) {
@@ -281,30 +287,114 @@ static int rv515_debugfs_ga_info_init(struct radeon_device *rdev)
 
 void rv515_mc_stop(struct radeon_device *rdev, struct rv515_mc_save *save)
 {
+       u32 crtc_enabled, tmp, frame_count, blackout;
+       int i, j;
+
        save->vga_render_control = RREG32(R_000300_VGA_RENDER_CONTROL);
        save->vga_hdp_control = RREG32(R_000328_VGA_HDP_CONTROL);
 
-       /* Stop all video */
-       WREG32(R_0068E8_D2CRTC_UPDATE_LOCK, 0);
+       /* disable VGA render */
        WREG32(R_000300_VGA_RENDER_CONTROL, 0);
-       WREG32(R_0060E8_D1CRTC_UPDATE_LOCK, 1);
-       WREG32(R_0068E8_D2CRTC_UPDATE_LOCK, 1);
-       WREG32(R_006080_D1CRTC_CONTROL, 0);
-       WREG32(R_006880_D2CRTC_CONTROL, 0);
-       WREG32(R_0060E8_D1CRTC_UPDATE_LOCK, 0);
-       WREG32(R_0068E8_D2CRTC_UPDATE_LOCK, 0);
-       WREG32(R_000330_D1VGA_CONTROL, 0);
-       WREG32(R_000338_D2VGA_CONTROL, 0);
+       /* blank the display controllers */
+       for (i = 0; i < rdev->num_crtc; i++) {
+               crtc_enabled = RREG32(AVIVO_D1CRTC_CONTROL + crtc_offsets[i]) & AVIVO_CRTC_EN;
+               if (crtc_enabled) {
+                       save->crtc_enabled[i] = true;
+                       tmp = RREG32(AVIVO_D1CRTC_CONTROL + crtc_offsets[i]);
+                       if (!(tmp & AVIVO_CRTC_DISP_READ_REQUEST_DISABLE)) {
+                               radeon_wait_for_vblank(rdev, i);
+                               tmp |= AVIVO_CRTC_DISP_READ_REQUEST_DISABLE;
+                               WREG32(AVIVO_D1CRTC_CONTROL + crtc_offsets[i], tmp);
+                       }
+                       /* wait for the next frame */
+                       frame_count = radeon_get_vblank_counter(rdev, i);
+                       for (j = 0; j < rdev->usec_timeout; j++) {
+                               if (radeon_get_vblank_counter(rdev, i) != frame_count)
+                                       break;
+                               udelay(1);
+                       }
+               } else {
+                       save->crtc_enabled[i] = false;
+               }
+       }
+
+       radeon_mc_wait_for_idle(rdev);
+
+       if (rdev->family >= CHIP_R600) {
+               if (rdev->family >= CHIP_RV770)
+                       blackout = RREG32(R700_MC_CITF_CNTL);
+               else
+                       blackout = RREG32(R600_CITF_CNTL);
+               if ((blackout & R600_BLACKOUT_MASK) != R600_BLACKOUT_MASK) {
+                       /* Block CPU access */
+                       WREG32(R600_BIF_FB_EN, 0);
+                       /* blackout the MC */
+                       blackout |= R600_BLACKOUT_MASK;
+                       if (rdev->family >= CHIP_RV770)
+                               WREG32(R700_MC_CITF_CNTL, blackout);
+                       else
+                               WREG32(R600_CITF_CNTL, blackout);
+               }
+       }
 }
 
 void rv515_mc_resume(struct radeon_device *rdev, struct rv515_mc_save *save)
 {
-       WREG32(R_006110_D1GRPH_PRIMARY_SURFACE_ADDRESS, rdev->mc.vram_start);
-       WREG32(R_006118_D1GRPH_SECONDARY_SURFACE_ADDRESS, rdev->mc.vram_start);
-       WREG32(R_006910_D2GRPH_PRIMARY_SURFACE_ADDRESS, rdev->mc.vram_start);
-       WREG32(R_006918_D2GRPH_SECONDARY_SURFACE_ADDRESS, rdev->mc.vram_start);
-       WREG32(R_000310_VGA_MEMORY_BASE_ADDRESS, rdev->mc.vram_start);
-       /* Unlock host access */
+       u32 tmp, frame_count;
+       int i, j;
+
+       /* update crtc base addresses */
+       for (i = 0; i < rdev->num_crtc; i++) {
+               if (rdev->family >= CHIP_RV770) {
+                       if (i == 1) {
+                               WREG32(R700_D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH,
+                                      upper_32_bits(rdev->mc.vram_start));
+                               WREG32(R700_D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH,
+                                      upper_32_bits(rdev->mc.vram_start));
+                       } else {
+                               WREG32(R700_D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH,
+                                      upper_32_bits(rdev->mc.vram_start));
+                               WREG32(R700_D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH,
+                                      upper_32_bits(rdev->mc.vram_start));
+                       }
+               }
+               WREG32(R_006110_D1GRPH_PRIMARY_SURFACE_ADDRESS + crtc_offsets[i],
+                      (u32)rdev->mc.vram_start);
+               WREG32(R_006118_D1GRPH_SECONDARY_SURFACE_ADDRESS + crtc_offsets[i],
+                      (u32)rdev->mc.vram_start);
+       }
+       WREG32(R_000310_VGA_MEMORY_BASE_ADDRESS, (u32)rdev->mc.vram_start);
+
+       if (rdev->family >= CHIP_R600) {
+               /* unblackout the MC */
+               if (rdev->family >= CHIP_RV770)
+                       tmp = RREG32(R700_MC_CITF_CNTL);
+               else
+                       tmp = RREG32(R600_CITF_CNTL);
+               tmp &= ~R600_BLACKOUT_MASK;
+               if (rdev->family >= CHIP_RV770)
+                       WREG32(R700_MC_CITF_CNTL, tmp);
+               else
+                       WREG32(R600_CITF_CNTL, tmp);
+               /* allow CPU access */
+               WREG32(R600_BIF_FB_EN, R600_FB_READ_EN | R600_FB_WRITE_EN);
+       }
+
+       for (i = 0; i < rdev->num_crtc; i++) {
+               if (save->crtc_enabled[i]) {
+                       tmp = RREG32(AVIVO_D1CRTC_CONTROL + crtc_offsets[i]);
+                       tmp &= ~AVIVO_CRTC_DISP_READ_REQUEST_DISABLE;
+                       WREG32(AVIVO_D1CRTC_CONTROL + crtc_offsets[i], tmp);
+                       /* wait for the next frame */
+                       frame_count = radeon_get_vblank_counter(rdev, i);
+                       for (j = 0; j < rdev->usec_timeout; j++) {
+                               if (radeon_get_vblank_counter(rdev, i) != frame_count)
+                                       break;
+                               udelay(1);
+                       }
+               }
+       }
+       /* Unlock vga access */
        WREG32(R_000328_VGA_HDP_CONTROL, save->vga_hdp_control);
        mdelay(1);
        WREG32(R_000300_VGA_RENDER_CONTROL, save->vga_render_control);