Commit bdaa6497 authored by Alex Deucher's avatar Alex Deucher Committed by Ben Hutchings

drm/radeon: properly handle mc_stop/mc_resume on evergreen+ (v2)

commit 62444b74 upstream.

- Stop the displays from accessing the FB
- Block CPU access
- Turn off MC client access

This should fix issues some users have seen, especially
with UEFI, when changing the MC FB location that result
in hangs or display corruption.

v2: fix crtc enabled check noticed by Luca Tettamanti
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
[bwh: Backported to 3.2:
 - Drop DCE6 cases
 - Call evergreen_mc_wait_for_idle() directly
 - Add dce4_wait_for_vblank() (commits 3ae19b75
   and 4a15903d) and call it directly
Signed-off-by: default avatarBen Hutchings <ben@decadent.org.uk>
parent 4dcbf47b
...@@ -37,6 +37,16 @@ ...@@ -37,6 +37,16 @@
#define EVERGREEN_PFP_UCODE_SIZE 1120 #define EVERGREEN_PFP_UCODE_SIZE 1120
#define EVERGREEN_PM4_UCODE_SIZE 1376 #define EVERGREEN_PM4_UCODE_SIZE 1376
static const u32 crtc_offsets[6] =
{
EVERGREEN_CRTC0_REGISTER_OFFSET,
EVERGREEN_CRTC1_REGISTER_OFFSET,
EVERGREEN_CRTC2_REGISTER_OFFSET,
EVERGREEN_CRTC3_REGISTER_OFFSET,
EVERGREEN_CRTC4_REGISTER_OFFSET,
EVERGREEN_CRTC5_REGISTER_OFFSET
};
static void evergreen_gpu_init(struct radeon_device *rdev); static void evergreen_gpu_init(struct radeon_device *rdev);
void evergreen_fini(struct radeon_device *rdev); void evergreen_fini(struct radeon_device *rdev);
void evergreen_pcie_gen2_enable(struct radeon_device *rdev); void evergreen_pcie_gen2_enable(struct radeon_device *rdev);
...@@ -66,6 +76,27 @@ void evergreen_fix_pci_max_read_req_size(struct radeon_device *rdev) ...@@ -66,6 +76,27 @@ void evergreen_fix_pci_max_read_req_size(struct radeon_device *rdev)
} }
} }
void dce4_wait_for_vblank(struct radeon_device *rdev, int crtc)
{
int i;
if (crtc >= rdev->num_crtc)
return;
if (RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[crtc]) & EVERGREEN_CRTC_MASTER_EN) {
for (i = 0; i < rdev->usec_timeout; i++) {
if (!(RREG32(EVERGREEN_CRTC_STATUS + crtc_offsets[crtc]) & EVERGREEN_CRTC_V_BLANK))
break;
udelay(1);
}
for (i = 0; i < rdev->usec_timeout; i++) {
if (RREG32(EVERGREEN_CRTC_STATUS + crtc_offsets[crtc]) & EVERGREEN_CRTC_V_BLANK)
break;
udelay(1);
}
}
}
void evergreen_pre_page_flip(struct radeon_device *rdev, int crtc) void evergreen_pre_page_flip(struct radeon_device *rdev, int crtc)
{ {
/* enable the pflip int */ /* enable the pflip int */
...@@ -1065,116 +1096,88 @@ void evergreen_agp_enable(struct radeon_device *rdev) ...@@ -1065,116 +1096,88 @@ void evergreen_agp_enable(struct radeon_device *rdev)
void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save) void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save)
{ {
u32 crtc_enabled, tmp, frame_count, blackout;
int i, j;
save->vga_render_control = RREG32(VGA_RENDER_CONTROL); save->vga_render_control = RREG32(VGA_RENDER_CONTROL);
save->vga_hdp_control = RREG32(VGA_HDP_CONTROL); save->vga_hdp_control = RREG32(VGA_HDP_CONTROL);
/* Stop all video */ /* disable VGA render */
WREG32(VGA_RENDER_CONTROL, 0); WREG32(VGA_RENDER_CONTROL, 0);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 1); /* blank the display controllers */
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 1); for (i = 0; i < rdev->num_crtc; i++) {
if (rdev->num_crtc >= 4) { crtc_enabled = RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i]) & EVERGREEN_CRTC_MASTER_EN;
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 1); if (crtc_enabled) {
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 1); save->crtc_enabled[i] = true;
} tmp = RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i]);
if (rdev->num_crtc >= 6) { if (!(tmp & EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE)) {
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 1); dce4_wait_for_vblank(rdev, i);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 1); tmp |= EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE;
} WREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i], tmp);
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) { /* wait for the next frame */
WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, 0); frame_count = radeon_get_vblank_counter(rdev, i);
WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, 0); for (j = 0; j < rdev->usec_timeout; j++) {
if (radeon_get_vblank_counter(rdev, i) != frame_count)
break;
udelay(1);
} }
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);
} }
WREG32(D1VGA_CONTROL, 0); evergreen_mc_wait_for_idle(rdev);
WREG32(D2VGA_CONTROL, 0);
if (rdev->num_crtc >= 4) { blackout = RREG32(MC_SHARED_BLACKOUT_CNTL);
WREG32(EVERGREEN_D3VGA_CONTROL, 0); if ((blackout & BLACKOUT_MODE_MASK) != 1) {
WREG32(EVERGREEN_D4VGA_CONTROL, 0); /* Block CPU access */
} WREG32(BIF_FB_EN, 0);
if (rdev->num_crtc >= 6) { /* blackout the MC */
WREG32(EVERGREEN_D5VGA_CONTROL, 0); blackout &= ~BLACKOUT_MODE_MASK;
WREG32(EVERGREEN_D6VGA_CONTROL, 0); WREG32(MC_SHARED_BLACKOUT_CNTL, blackout | 1);
} }
} }
void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save) void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save)
{ {
WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC0_REGISTER_OFFSET, u32 tmp, frame_count;
upper_32_bits(rdev->mc.vram_start)); int i, j;
WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC0_REGISTER_OFFSET,
upper_32_bits(rdev->mc.vram_start));
WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC0_REGISTER_OFFSET,
(u32)rdev->mc.vram_start);
WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC0_REGISTER_OFFSET,
(u32)rdev->mc.vram_start);
WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC1_REGISTER_OFFSET, /* update crtc base addresses */
for (i = 0; i < rdev->num_crtc; i++) {
WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + crtc_offsets[i],
upper_32_bits(rdev->mc.vram_start)); upper_32_bits(rdev->mc.vram_start));
WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC1_REGISTER_OFFSET, WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + crtc_offsets[i],
upper_32_bits(rdev->mc.vram_start)); upper_32_bits(rdev->mc.vram_start));
WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC1_REGISTER_OFFSET, WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + crtc_offsets[i],
(u32)rdev->mc.vram_start); (u32)rdev->mc.vram_start);
WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC1_REGISTER_OFFSET, WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + crtc_offsets[i],
(u32)rdev->mc.vram_start); (u32)rdev->mc.vram_start);
}
WREG32(EVERGREEN_VGA_MEMORY_BASE_ADDRESS_HIGH, upper_32_bits(rdev->mc.vram_start));
WREG32(EVERGREEN_VGA_MEMORY_BASE_ADDRESS, (u32)rdev->mc.vram_start);
if (rdev->num_crtc >= 4) { /* unblackout the MC */
WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC2_REGISTER_OFFSET, tmp = RREG32(MC_SHARED_BLACKOUT_CNTL);
upper_32_bits(rdev->mc.vram_start)); tmp &= ~BLACKOUT_MODE_MASK;
WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC2_REGISTER_OFFSET, WREG32(MC_SHARED_BLACKOUT_CNTL, tmp);
upper_32_bits(rdev->mc.vram_start)); /* allow CPU access */
WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC2_REGISTER_OFFSET, WREG32(BIF_FB_EN, FB_READ_EN | FB_WRITE_EN);
(u32)rdev->mc.vram_start);
WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC2_REGISTER_OFFSET,
(u32)rdev->mc.vram_start);
WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC3_REGISTER_OFFSET, for (i = 0; i < rdev->num_crtc; i++) {
upper_32_bits(rdev->mc.vram_start)); if (save->crtc_enabled) {
WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC3_REGISTER_OFFSET, tmp = RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i]);
upper_32_bits(rdev->mc.vram_start)); tmp &= ~EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE;
WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC3_REGISTER_OFFSET, WREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i], tmp);
(u32)rdev->mc.vram_start); /* wait for the next frame */
WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC3_REGISTER_OFFSET, frame_count = radeon_get_vblank_counter(rdev, i);
(u32)rdev->mc.vram_start); for (j = 0; j < rdev->usec_timeout; j++) {
if (radeon_get_vblank_counter(rdev, i) != frame_count)
break;
udelay(1);
} }
if (rdev->num_crtc >= 6) {
WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC4_REGISTER_OFFSET,
upper_32_bits(rdev->mc.vram_start));
WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC4_REGISTER_OFFSET,
upper_32_bits(rdev->mc.vram_start));
WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC4_REGISTER_OFFSET,
(u32)rdev->mc.vram_start);
WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC4_REGISTER_OFFSET,
(u32)rdev->mc.vram_start);
WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC5_REGISTER_OFFSET,
upper_32_bits(rdev->mc.vram_start));
WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC5_REGISTER_OFFSET,
upper_32_bits(rdev->mc.vram_start));
WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC5_REGISTER_OFFSET,
(u32)rdev->mc.vram_start);
WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC5_REGISTER_OFFSET,
(u32)rdev->mc.vram_start);
} }
}
WREG32(EVERGREEN_VGA_MEMORY_BASE_ADDRESS_HIGH, upper_32_bits(rdev->mc.vram_start)); /* Unlock vga access */
WREG32(EVERGREEN_VGA_MEMORY_BASE_ADDRESS, (u32)rdev->mc.vram_start);
/* Unlock host access */
WREG32(VGA_HDP_CONTROL, save->vga_hdp_control); WREG32(VGA_HDP_CONTROL, save->vga_hdp_control);
mdelay(1); mdelay(1);
WREG32(VGA_RENDER_CONTROL, save->vga_render_control); WREG32(VGA_RENDER_CONTROL, save->vga_render_control);
......
...@@ -210,7 +210,10 @@ ...@@ -210,7 +210,10 @@
#define EVERGREEN_CRTC_CONTROL 0x6e70 #define EVERGREEN_CRTC_CONTROL 0x6e70
# define EVERGREEN_CRTC_MASTER_EN (1 << 0) # define EVERGREEN_CRTC_MASTER_EN (1 << 0)
# define EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE (1 << 24) # define EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE (1 << 24)
#define EVERGREEN_CRTC_BLANK_CONTROL 0x6e74
# define EVERGREEN_CRTC_BLANK_DATA_EN (1 << 8)
#define EVERGREEN_CRTC_STATUS 0x6e8c #define EVERGREEN_CRTC_STATUS 0x6e8c
# define EVERGREEN_CRTC_V_BLANK (1 << 0)
#define EVERGREEN_CRTC_STATUS_POSITION 0x6e90 #define EVERGREEN_CRTC_STATUS_POSITION 0x6e90
#define EVERGREEN_MASTER_UPDATE_MODE 0x6ef8 #define EVERGREEN_MASTER_UPDATE_MODE 0x6ef8
#define EVERGREEN_CRTC_UPDATE_LOCK 0x6ed4 #define EVERGREEN_CRTC_UPDATE_LOCK 0x6ed4
......
...@@ -77,6 +77,10 @@ ...@@ -77,6 +77,10 @@
#define CONFIG_MEMSIZE 0x5428 #define CONFIG_MEMSIZE 0x5428
#define BIF_FB_EN 0x5490
#define FB_READ_EN (1 << 0)
#define FB_WRITE_EN (1 << 1)
#define CP_ME_CNTL 0x86D8 #define CP_ME_CNTL 0x86D8
#define CP_ME_HALT (1 << 28) #define CP_ME_HALT (1 << 28)
#define CP_PFP_HALT (1 << 26) #define CP_PFP_HALT (1 << 26)
...@@ -194,6 +198,9 @@ ...@@ -194,6 +198,9 @@
#define NOOFCHAN_MASK 0x00003000 #define NOOFCHAN_MASK 0x00003000
#define MC_SHARED_CHREMAP 0x2008 #define MC_SHARED_CHREMAP 0x2008
#define MC_SHARED_BLACKOUT_CNTL 0x20ac
#define BLACKOUT_MODE_MASK 0x00000007
#define MC_ARB_RAMCFG 0x2760 #define MC_ARB_RAMCFG 0x2760
#define NOOFBANK_SHIFT 0 #define NOOFBANK_SHIFT 0
#define NOOFBANK_MASK 0x00000003 #define NOOFBANK_MASK 0x00000003
......
...@@ -386,6 +386,7 @@ void r700_cp_fini(struct radeon_device *rdev); ...@@ -386,6 +386,7 @@ void r700_cp_fini(struct radeon_device *rdev);
struct evergreen_mc_save { struct evergreen_mc_save {
u32 vga_render_control; u32 vga_render_control;
u32 vga_hdp_control; u32 vga_hdp_control;
bool crtc_enabled[RADEON_MAX_CRTCS];
}; };
void evergreen_pcie_gart_tlb_flush(struct radeon_device *rdev); void evergreen_pcie_gart_tlb_flush(struct radeon_device *rdev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment