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