[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