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 <predlew...@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

_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

Reply via email to