[PATCH] drm/radeon: cleanup and fix crtc while programming mc

j.glisse at gmail.com j.glisse at gmail.com
Thu Jul 26 16:24:48 PDT 2012


From: Jerome Glisse <jglisse at redhat.com>

When we change start address of vram for the GPU memory controller
we need to make sure that nothing in the GPU still use the old vram
address. This patch cleanup and fix crtc address.

However there is still someissue somewhere if we reenable the crtc
after updating the address at which they sancout. So to avoid any
issue disable crtc. Once we want to do flicker less transition
btw uefi and radeon we will probably want to revisit how we program
the GPU memory controller.

This probably fix :
https://bugs.freedesktop.org/show_bug.cgi?id=52467
https://bugs.freedesktop.org/show_bug.cgi?id=42373

Cc: <stable at vger.kernel.org>
Signed-off-by: Jerome Glisse <jglisse at redhat.com>
---
 drivers/gpu/drm/radeon/evergreen.c   |  178 ++++++++++++++++------------------
 drivers/gpu/drm/radeon/radeon_asic.h |   18 +++-
 2 files changed, 99 insertions(+), 97 deletions(-)

diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
index e585a3b..c6ede66 100644
--- a/drivers/gpu/drm/radeon/evergreen.c
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -1227,70 +1227,94 @@ void evergreen_agp_enable(struct radeon_device *rdev)
 	WREG32(VM_CONTEXT1_CNTL, 0);
 }
 
+static void evergreen_crtc_save(struct radeon_device *rdev, struct evergreen_mc_save *save, unsigned idx)
+{
+	save->crtc[idx].paddress = 0;
+	save->crtc[idx].saddress = 0;
+	save->crtc[idx].crtc_control = 0;
+
+	if (idx >= rdev->num_crtc) {
+		/* it seems accessing non existant crtc trigger high latency */
+		return;
+	}
+
+	save->crtc[idx].paddress = RREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + save->crtc[idx].offset);
+	save->crtc[idx].paddress |= ((uint64_t)RREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + save->crtc[idx].offset)) << 32ULL;
+	save->crtc[idx].saddress = RREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + save->crtc[idx].offset);
+	save->crtc[idx].saddress |= ((uint64_t)RREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + save->crtc[idx].offset)) << 32ULL;
+	save->crtc[idx].crtc_control = RREG32(EVERGREEN_CRTC_CONTROL + save->crtc[idx].offset);
+	/* We need to disable all crtc as for some reason crtc scanout
+	 * base address does not happen properly when changing the
+	 * mc vram start address. Don't remove this or you will break
+	 * things on uefi system.
+	 */
+	save->crtc[idx].crtc_control = 0;
+	save->crtc[idx].vga_control = RREG32(save->crtc[idx].vga_control_offset);
+
+	WREG32(EVERGREEN_CRTC_UPDATE_LOCK + save->crtc[idx].offset, 1);
+	WREG32(EVERGREEN_CRTC_CONTROL + save->crtc[idx].offset, 0);
+	WREG32(save->crtc[idx].vga_control_offset, 0);
+	WREG32(EVERGREEN_CRTC_UPDATE_LOCK + save->crtc[idx].offset, 0);
+}
+
 void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save)
 {
-	save->vga_control[0] = RREG32(D1VGA_CONTROL);
-	save->vga_control[1] = RREG32(D2VGA_CONTROL);
+	save->crtc[0].offset = EVERGREEN_CRTC0_REGISTER_OFFSET;
+	save->crtc[1].offset = EVERGREEN_CRTC1_REGISTER_OFFSET;
+	save->crtc[2].offset = EVERGREEN_CRTC2_REGISTER_OFFSET;
+	save->crtc[3].offset = EVERGREEN_CRTC3_REGISTER_OFFSET;
+	save->crtc[4].offset = EVERGREEN_CRTC4_REGISTER_OFFSET;
+	save->crtc[5].offset = EVERGREEN_CRTC5_REGISTER_OFFSET;
+	save->crtc[0].vga_control_offset = D1VGA_CONTROL;
+	save->crtc[1].vga_control_offset = D2VGA_CONTROL;
+	save->crtc[2].vga_control_offset = EVERGREEN_D3VGA_CONTROL;
+	save->crtc[3].vga_control_offset = EVERGREEN_D4VGA_CONTROL;
+	save->crtc[4].vga_control_offset = EVERGREEN_D5VGA_CONTROL;
+	save->crtc[5].vga_control_offset = EVERGREEN_D6VGA_CONTROL;
+
+	save->fb_address = (uint64_t)(RREG32(MC_VM_FB_LOCATION) & 0xffff) << 24ULL;
 	save->vga_render_control = RREG32(VGA_RENDER_CONTROL);
 	save->vga_hdp_control = RREG32(VGA_HDP_CONTROL);
-	save->crtc_control[0] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET);
-	save->crtc_control[1] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET);
-	if (rdev->num_crtc >= 4) {
-		save->vga_control[2] = RREG32(EVERGREEN_D3VGA_CONTROL);
-		save->vga_control[3] = RREG32(EVERGREEN_D4VGA_CONTROL);
-		save->crtc_control[2] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET);
-		save->crtc_control[3] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET);
-	}
-	if (rdev->num_crtc >= 6) {
-		save->vga_control[4] = RREG32(EVERGREEN_D5VGA_CONTROL);
-		save->vga_control[5] = RREG32(EVERGREEN_D6VGA_CONTROL);
-		save->crtc_control[4] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET);
-		save->crtc_control[5] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET);
-	}
 
 	/* Stop all video */
 	WREG32(VGA_RENDER_CONTROL, 0);
-	WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 1);
-	WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 1);
-	if (rdev->num_crtc >= 4) {
-		WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 1);
-		WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 1);
-	}
-	if (rdev->num_crtc >= 6) {
-		WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 1);
-		WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 1);
-	}
-	WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
-	WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
-	if (rdev->num_crtc >= 4) {
-		WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, 0);
-		WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, 0);
-	}
-	if (rdev->num_crtc >= 6) {
-		WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, 0);
-		WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, 0);
-	}
-	WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
-	WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
-	if (rdev->num_crtc >= 4) {
-		WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0);
-		WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0);
-	}
-	if (rdev->num_crtc >= 6) {
-		WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0);
-		WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0);
+	evergreen_crtc_save(rdev, save, 0);
+	evergreen_crtc_save(rdev, save, 1);
+	evergreen_crtc_save(rdev, save, 2);
+	evergreen_crtc_save(rdev, save, 3);
+	evergreen_crtc_save(rdev, save, 4);
+	evergreen_crtc_save(rdev, save, 5);
+}
+
+static void evergreen_crtc_restore(struct radeon_device *rdev, struct evergreen_mc_save *save, unsigned idx)
+{
+	if (idx >= rdev->num_crtc) {
+		/* it seems accessing non existant crtc trigger high latency */
+		return;
 	}
 
-	WREG32(D1VGA_CONTROL, 0);
-	WREG32(D2VGA_CONTROL, 0);
-	if (rdev->num_crtc >= 4) {
-		WREG32(EVERGREEN_D3VGA_CONTROL, 0);
-		WREG32(EVERGREEN_D4VGA_CONTROL, 0);
+	/* update new primary and secondary address */
+	if (save->crtc[idx].paddress) {
+		save->crtc[idx].paddress -= save->fb_address;
 	}
-	if (rdev->num_crtc >= 6) {
-		WREG32(EVERGREEN_D5VGA_CONTROL, 0);
-		WREG32(EVERGREEN_D6VGA_CONTROL, 0);
+	save->crtc[idx].paddress += rdev->mc.vram_start;
+	if (save->crtc[idx].saddress) {
+		save->crtc[idx].saddress -= save->fb_address;
 	}
+	save->crtc[idx].saddress += rdev->mc.vram_start;
+
+	WREG32(EVERGREEN_CRTC_UPDATE_LOCK + save->crtc[idx].offset, 1);
+	WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + save->crtc[idx].offset, lower_32_bits(save->crtc[idx].paddress));
+	WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + save->crtc[idx].offset, upper_32_bits(save->crtc[idx].paddress) & 0xff);
+	WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + save->crtc[idx].offset, lower_32_bits(save->crtc[idx].saddress));
+	WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + save->crtc[idx].offset, upper_32_bits(save->crtc[idx].saddress) & 0xff);
+	WREG32(EVERGREEN_CRTC_UPDATE_LOCK + save->crtc[idx].offset, 0);
+	WREG32(EVERGREEN_MASTER_UPDATE_MODE + save->crtc[idx].offset, 0);
+
+	WREG32(EVERGREEN_CRTC_UPDATE_LOCK + save->crtc[idx].offset, 1);
+	WREG32(save->crtc[idx].vga_control_offset, save->crtc[idx].vga_control);
+	WREG32(EVERGREEN_CRTC_CONTROL + save->crtc[idx].offset, save->crtc[idx].crtc_control | EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE);
+	WREG32(EVERGREEN_CRTC_UPDATE_LOCK + save->crtc[idx].offset, 0);
 }
 
 void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save)
@@ -1357,47 +1381,15 @@ void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *s
 	/* Unlock host access */
 	WREG32(VGA_HDP_CONTROL, save->vga_hdp_control);
 	mdelay(1);
+
 	/* Restore video state */
-	WREG32(D1VGA_CONTROL, save->vga_control[0]);
-	WREG32(D2VGA_CONTROL, save->vga_control[1]);
-	if (rdev->num_crtc >= 4) {
-		WREG32(EVERGREEN_D3VGA_CONTROL, save->vga_control[2]);
-		WREG32(EVERGREEN_D4VGA_CONTROL, save->vga_control[3]);
-	}
-	if (rdev->num_crtc >= 6) {
-		WREG32(EVERGREEN_D5VGA_CONTROL, save->vga_control[4]);
-		WREG32(EVERGREEN_D6VGA_CONTROL, save->vga_control[5]);
-	}
-	WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 1);
-	WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 1);
-	if (rdev->num_crtc >= 4) {
-		WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 1);
-		WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 1);
-	}
-	if (rdev->num_crtc >= 6) {
-		WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 1);
-		WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 1);
-	}
-	WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, save->crtc_control[0]);
-	WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, save->crtc_control[1]);
-	if (rdev->num_crtc >= 4) {
-		WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, save->crtc_control[2]);
-		WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, save->crtc_control[3]);
-	}
-	if (rdev->num_crtc >= 6) {
-		WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, save->crtc_control[4]);
-		WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, save->crtc_control[5]);
-	}
-	WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
-	WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
-	if (rdev->num_crtc >= 4) {
-		WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0);
-		WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0);
-	}
-	if (rdev->num_crtc >= 6) {
-		WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0);
-		WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0);
-	}
+	evergreen_crtc_restore(rdev, save, 0);
+	evergreen_crtc_restore(rdev, save, 1);
+	evergreen_crtc_restore(rdev, save, 2);
+	evergreen_crtc_restore(rdev, save, 3);
+	evergreen_crtc_restore(rdev, save, 4);
+	evergreen_crtc_restore(rdev, save, 5);
+
 	WREG32(VGA_RENDER_CONTROL, save->vga_render_control);
 }
 
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index f4af243..d450218 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -388,12 +388,22 @@ void r700_cp_fini(struct radeon_device *rdev);
 /*
  * evergreen
  */
+struct evergreen_crtc_save {
+	uint64_t			paddress;
+	uint64_t			saddress;
+	uint32_t			crtc_control;
+	uint32_t			vga_control;
+	uint32_t			offset;
+	uint32_t			vga_control_offset;
+};
+
 struct evergreen_mc_save {
-	u32 vga_control[6];
-	u32 vga_render_control;
-	u32 vga_hdp_control;
-	u32 crtc_control[6];
+	struct evergreen_crtc_save	crtc[RADEON_MAX_CRTCS];
+	uint64_t			fb_address;
+	uint32_t			vga_render_control;
+	uint32_t			vga_hdp_control;
 };
+
 void evergreen_pcie_gart_tlb_flush(struct radeon_device *rdev);
 int evergreen_init(struct radeon_device *rdev);
 void evergreen_fini(struct radeon_device *rdev);
-- 
1.7.10.4



More information about the dri-devel mailing list