[RFC 3/7] drm/amdgpu/gmc6: don't use vram location programmed by the vbios

Piotr Redlewski predlewski at gmail.com
Wed Nov 8 22:38:35 UTC 2017


On SI chips, fb location programmed by the vbios (40-bit address) is out of
reach of the UVD memory controller, which supports only 32-bits.

This partially reverts following commits:
commit e4f6b39e8bcd ("drm/amdgpu: remove *_mc_access from display funcs")
commit 71086a3e8470 ("drm/amdgpu/gmc6: drop fb location programming")
commit ba3a5b83dd9b ("drm/amdgpu/gmc6: use the vram location programmed by the vbios")

Signed-off-by: Piotr Redlewski <predlewski at gmail.com>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h |   6 ++
 drivers/gpu/drm/amd/amdgpu/dce_v6_0.c    | 114 ++++++++++++++++++++++++++++++-
 drivers/gpu/drm/amd/amdgpu/dce_v6_0.h    |   5 ++
 drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c    |  40 ++++++++---
 4 files changed, 155 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
index 4069a3b2f55f..0bd916bd4c08 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
@@ -262,6 +262,12 @@ struct amdgpu_audio {
 	int num_pins;
 };
 
+struct amdgpu_mode_mc_save {
+	u32 vga_render_control;
+	u32 vga_hdp_control;
+	bool crtc_enabled[AMDGPU_MAX_CRTCS];
+};
+
 struct amdgpu_display_funcs {
 	/* display watermarks */
 	void (*bandwidth_update)(struct amdgpu_device *adev);
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c
index bd2c4f727df6..b9549806abc1 100644
--- a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c
@@ -393,8 +393,118 @@ static u32 dce_v6_0_hpd_get_gpio_reg(struct amdgpu_device *adev)
 	return mmDC_GPIO_HPD_A;
 }
 
-static void dce_v6_0_set_vga_render_state(struct amdgpu_device *adev,
-					  bool render)
+static u32 evergreen_get_vblank_counter(struct amdgpu_device *adev, int crtc)
+{
+	if (crtc >= adev->mode_info.num_crtc)
+		return 0;
+	else
+		return RREG32(mmCRTC_STATUS_FRAME_COUNT + crtc_offsets[crtc]);
+}
+
+void dce_v6_0_stop_mc_access(struct amdgpu_device *adev,
+			     struct amdgpu_mode_mc_save *save)
+{
+	u32 crtc_enabled, tmp, frame_count;
+	int i, j;
+
+	save->vga_render_control = RREG32(mmVGA_RENDER_CONTROL);
+	save->vga_hdp_control = RREG32(mmVGA_HDP_CONTROL);
+
+	/* disable VGA render */
+	WREG32(mmVGA_RENDER_CONTROL, 0);
+
+	/* blank the display controllers */
+	for (i = 0; i < adev->mode_info.num_crtc; i++) {
+		crtc_enabled = RREG32(mmCRTC_CONTROL + crtc_offsets[i]) & CRTC_CONTROL__CRTC_MASTER_EN_MASK;
+		if (crtc_enabled) {
+			save->crtc_enabled[i] = true;
+			tmp = RREG32(mmCRTC_BLANK_CONTROL + crtc_offsets[i]);
+
+			if (!(tmp & CRTC_BLANK_CONTROL__CRTC_BLANK_DATA_EN_MASK)) {
+				dce_v6_0_vblank_wait(adev, i);
+				WREG32(mmCRTC_UPDATE_LOCK + crtc_offsets[i], 1);
+				tmp |= CRTC_BLANK_CONTROL__CRTC_BLANK_DATA_EN_MASK;
+				WREG32(mmCRTC_BLANK_CONTROL + crtc_offsets[i], tmp);
+				WREG32(mmCRTC_UPDATE_LOCK + crtc_offsets[i], 0);
+			}
+			/* wait for the next frame */
+			frame_count = evergreen_get_vblank_counter(adev, i);
+			for (j = 0; j < adev->usec_timeout; j++) {
+				if (evergreen_get_vblank_counter(adev, i) != frame_count)
+					break;
+				udelay(1);
+			}
+
+			/* XXX this is a hack to avoid strange behavior with EFI on certain systems */
+			WREG32(mmCRTC_UPDATE_LOCK + crtc_offsets[i], 1);
+			tmp = RREG32(mmCRTC_CONTROL + crtc_offsets[i]);
+			tmp &= ~CRTC_CONTROL__CRTC_MASTER_EN_MASK;
+			WREG32(mmCRTC_CONTROL + crtc_offsets[i], tmp);
+			WREG32(mmCRTC_UPDATE_LOCK + crtc_offsets[i], 0);
+			save->crtc_enabled[i] = false;
+			/* ***** */
+		} else {
+			save->crtc_enabled[i] = false;
+		}
+	}
+}
+
+void dce_v6_0_resume_mc_access(struct amdgpu_device *adev,
+			       struct amdgpu_mode_mc_save *save)
+{
+	u32 tmp;
+	int i, j;
+
+	/* update crtc base addresses */
+	for (i = 0; i < adev->mode_info.num_crtc; i++) {
+		WREG32(mmGRPH_PRIMARY_SURFACE_ADDRESS_HIGH + crtc_offsets[i],
+		       upper_32_bits(adev->mc.vram_start));
+		WREG32(mmGRPH_SECONDARY_SURFACE_ADDRESS_HIGH + crtc_offsets[i],
+		       upper_32_bits(adev->mc.vram_start));
+		WREG32(mmGRPH_PRIMARY_SURFACE_ADDRESS + crtc_offsets[i],
+		       (u32)adev->mc.vram_start);
+		WREG32(mmGRPH_SECONDARY_SURFACE_ADDRESS + crtc_offsets[i],
+		       (u32)adev->mc.vram_start);
+	}
+
+	WREG32(mmVGA_MEMORY_BASE_ADDRESS_HIGH, upper_32_bits(adev->mc.vram_start));
+	WREG32(mmVGA_MEMORY_BASE_ADDRESS, (u32)adev->mc.vram_start);
+
+	/* unlock regs and wait for update */
+	for (i = 0; i < adev->mode_info.num_crtc; i++) {
+		if (save->crtc_enabled[i]) {
+			tmp = RREG32(mmMASTER_UPDATE_MODE + crtc_offsets[i]);
+			if ((tmp & 0x7) != 0) {
+				tmp &= ~0x7;
+				WREG32(mmMASTER_UPDATE_MODE + crtc_offsets[i], tmp);
+			}
+			tmp = RREG32(mmGRPH_UPDATE + crtc_offsets[i]);
+			if (tmp & GRPH_UPDATE__GRPH_UPDATE_LOCK_MASK) {
+				tmp &= ~GRPH_UPDATE__GRPH_UPDATE_LOCK_MASK;
+				WREG32(mmGRPH_UPDATE + crtc_offsets[i], tmp);
+			}
+			tmp = RREG32(mmMASTER_UPDATE_LOCK + crtc_offsets[i]);
+			if (tmp & 1) {
+				tmp &= ~1;
+				WREG32(mmMASTER_UPDATE_LOCK + crtc_offsets[i], tmp);
+			}
+			for (j = 0; j < adev->usec_timeout; j++) {
+				tmp = RREG32(mmGRPH_UPDATE + crtc_offsets[i]);
+				if ((tmp & GRPH_UPDATE__GRPH_SURFACE_UPDATE_PENDING_MASK) == 0)
+					break;
+				udelay(1);
+			}
+		}
+	}
+
+	/* Unlock vga access */
+	WREG32(mmVGA_HDP_CONTROL, save->vga_hdp_control);
+	mdelay(1);
+	WREG32(mmVGA_RENDER_CONTROL, save->vga_render_control);
+
+}
+
+void dce_v6_0_set_vga_render_state(struct amdgpu_device *adev, bool render)
 {
 	if (!render)
 		WREG32(mmVGA_RENDER_CONTROL,
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.h b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.h
index 7b546b596de1..35134523f53d 100644
--- a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.h
+++ b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.h
@@ -28,5 +28,10 @@ extern const struct amdgpu_ip_block_version dce_v6_0_ip_block;
 extern const struct amdgpu_ip_block_version dce_v6_4_ip_block;
 
 void dce_v6_0_disable_dce(struct amdgpu_device *adev);
+void dce_v6_0_stop_mc_access(struct amdgpu_device *adev,
+			     struct amdgpu_mode_mc_save *save);
+void dce_v6_0_resume_mc_access(struct amdgpu_device *adev,
+			       struct amdgpu_mode_mc_save *save);
+void dce_v6_0_set_vga_render_state(struct amdgpu_device *adev, bool render);
 
 #endif
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c
index d2a43db22cff..3f891f22af93 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c
@@ -24,6 +24,7 @@
 #include <drm/drmP.h>
 #include "amdgpu.h"
 #include "gmc_v6_0.h"
+#include "dce_v6_0.h"
 #include "amdgpu_ucode.h"
 
 #include "bif/bif_3_0_d.h"
@@ -66,10 +67,14 @@ static const u32 crtc_offsets[6] =
 	SI_CRTC5_REGISTER_OFFSET
 };
 
-static void gmc_v6_0_mc_stop(struct amdgpu_device *adev)
+static void gmc_v6_0_mc_stop(struct amdgpu_device *adev,
+			     struct amdgpu_mode_mc_save *save)
 {
 	u32 blackout;
 
+	if (adev->mode_info.num_crtc)
+		dce_v6_0_stop_mc_access(adev, save);
+
 	gmc_v6_0_wait_for_idle((void *)adev);
 
 	blackout = RREG32(mmMC_SHARED_BLACKOUT_CNTL);
@@ -86,7 +91,8 @@ static void gmc_v6_0_mc_stop(struct amdgpu_device *adev)
 
 }
 
-static void gmc_v6_0_mc_resume(struct amdgpu_device *adev)
+static void gmc_v6_0_mc_resume(struct amdgpu_device *adev,
+			       struct amdgpu_mode_mc_save *save)
 {
 	u32 tmp;
 
@@ -98,6 +104,9 @@ static void gmc_v6_0_mc_resume(struct amdgpu_device *adev)
 	tmp = REG_SET_FIELD(0, BIF_FB_EN, FB_READ_EN, 1);
 	tmp = REG_SET_FIELD(tmp, BIF_FB_EN, FB_WRITE_EN, 1);
 	WREG32(mmBIF_FB_EN, tmp);
+
+	if (adev->mode_info.num_crtc)
+		dce_v6_0_resume_mc_access(adev, save);
 }
 
 static int gmc_v6_0_init_microcode(struct amdgpu_device *adev)
@@ -219,20 +228,19 @@ static int gmc_v6_0_mc_load_microcode(struct amdgpu_device *adev)
 static void gmc_v6_0_vram_gtt_location(struct amdgpu_device *adev,
 				       struct amdgpu_mc *mc)
 {
-	u64 base = RREG32(mmMC_VM_FB_LOCATION) & 0xFFFF;
-	base <<= 24;
-
 	if (mc->mc_vram_size > 0xFFC0000000ULL) {
 		dev_warn(adev->dev, "limiting VRAM\n");
 		mc->real_vram_size = 0xFFC0000000ULL;
 		mc->mc_vram_size = 0xFFC0000000ULL;
 	}
-	amdgpu_vram_location(adev, &adev->mc, base);
+	amdgpu_vram_location(adev, &adev->mc, 0);
 	amdgpu_gart_location(adev, mc);
 }
 
 static void gmc_v6_0_mc_program(struct amdgpu_device *adev)
 {
+	struct amdgpu_mode_mc_save save;
+	u32 tmp;
 	int i, j;
 
 	/* Initialize HDP */
@@ -245,6 +253,11 @@ static void gmc_v6_0_mc_program(struct amdgpu_device *adev)
 	}
 	WREG32(mmHDP_REG_COHERENCY_FLUSH_CNTL, 0);
 
+	if (adev->mode_info.num_crtc)
+		dce_v6_0_set_vga_render_state(adev, false);
+
+	gmc_v6_0_mc_stop(adev, &save);
+
 	if (gmc_v6_0_wait_for_idle((void *)adev)) {
 		dev_warn(adev->dev, "Wait for MC idle timedout !\n");
 	}
@@ -269,6 +282,15 @@ static void gmc_v6_0_mc_program(struct amdgpu_device *adev)
 	       adev->mc.vram_end >> 12);
 	WREG32(mmMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR,
 	       adev->vram_scratch.gpu_addr >> 12);
+
+	tmp = ((adev->mc.vram_end >> 24) & 0xFFFF) << 16;
+	tmp |= ((adev->mc.vram_start >> 24) & 0xFFFF);
+	WREG32(mmMC_VM_FB_LOCATION, tmp);
+	/* XXX double check these! */
+	WREG32(mmHDP_NONSURFACE_BASE, (adev->mc.vram_start >> 8));
+	WREG32(mmHDP_NONSURFACE_INFO, (2 << 7) | (1 << 30));
+	WREG32(mmHDP_NONSURFACE_SIZE, 0x3FFFFFFF);
+
 	WREG32(mmMC_VM_AGP_BASE, 0);
 	WREG32(mmMC_VM_AGP_TOP, 0x0FFFFFFF);
 	WREG32(mmMC_VM_AGP_BOT, 0x0FFFFFFF);
@@ -276,6 +298,7 @@ static void gmc_v6_0_mc_program(struct amdgpu_device *adev)
 	if (gmc_v6_0_wait_for_idle((void *)adev)) {
 		dev_warn(adev->dev, "Wait for MC idle timedout !\n");
 	}
+	gmc_v6_0_mc_resume(adev, &save);
 }
 
 static int gmc_v6_0_mc_init(struct amdgpu_device *adev)
@@ -997,6 +1020,7 @@ static int gmc_v6_0_wait_for_idle(void *handle)
 static int gmc_v6_0_soft_reset(void *handle)
 {
 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+	struct amdgpu_mode_mc_save save;
 	u32 srbm_soft_reset = 0;
 	u32 tmp = RREG32(mmSRBM_STATUS);
 
@@ -1012,7 +1036,7 @@ static int gmc_v6_0_soft_reset(void *handle)
 	}
 
 	if (srbm_soft_reset) {
-		gmc_v6_0_mc_stop(adev);
+		gmc_v6_0_mc_stop(adev, &save);
 		if (gmc_v6_0_wait_for_idle(adev)) {
 			dev_warn(adev->dev, "Wait for GMC idle timed out !\n");
 		}
@@ -1032,7 +1056,7 @@ static int gmc_v6_0_soft_reset(void *handle)
 
 		udelay(50);
 
-		gmc_v6_0_mc_resume(adev);
+		gmc_v6_0_mc_resume(adev, &save);
 		udelay(50);
 	}
 
-- 
2.15.0



More information about the amd-gfx mailing list