From b5470b036e14d063655cc01d22ea5d727042860a Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 1 Nov 2013 16:25:10 -0400 Subject: [PATCH] drm/radeon: implement pci config reset for evergreen/cayman (v2) pci config reset is a low level reset that resets the entire chip from the bus interface. It can be more reliable if soft reset fails. v2: put behind module parameter Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/evergreen.c | 50 +++++++++++++++++++++++++++++ drivers/gpu/drm/radeon/evergreend.h | 4 +++ drivers/gpu/drm/radeon/ni.c | 7 ++-- 3 files changed, 59 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 21d975007037..4116d0279596 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -146,6 +146,7 @@ extern u32 si_get_csb_size(struct radeon_device *rdev); extern void si_get_csb_buffer(struct radeon_device *rdev, volatile u32 *buffer); extern u32 cik_get_csb_size(struct radeon_device *rdev); extern void cik_get_csb_buffer(struct radeon_device *rdev, volatile u32 *buffer); +extern void rv770_set_clk_bypass_mode(struct radeon_device *rdev); static const u32 evergreen_golden_registers[] = { @@ -3867,6 +3868,48 @@ static void evergreen_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask) evergreen_print_gpu_status_regs(rdev); } +void evergreen_gpu_pci_config_reset(struct radeon_device *rdev) +{ + struct evergreen_mc_save save; + u32 tmp, i; + + dev_info(rdev->dev, "GPU pci config reset\n"); + + /* disable dpm? */ + + /* Disable CP parsing/prefetching */ + WREG32(CP_ME_CNTL, CP_ME_HALT | CP_PFP_HALT); + udelay(50); + /* Disable DMA */ + tmp = RREG32(DMA_RB_CNTL); + tmp &= ~DMA_RB_ENABLE; + WREG32(DMA_RB_CNTL, tmp); + /* XXX other engines? */ + + /* halt the rlc */ + r600_rlc_stop(rdev); + + udelay(50); + + /* set mclk/sclk to bypass */ + rv770_set_clk_bypass_mode(rdev); + /* disable BM */ + pci_clear_master(rdev->pdev); + /* disable mem access */ + evergreen_mc_stop(rdev, &save); + if (evergreen_mc_wait_for_idle(rdev)) { + dev_warn(rdev->dev, "Wait for MC idle timed out !\n"); + } + /* reset */ + radeon_pci_config_reset(rdev); + /* wait for asic to come out of reset */ + for (i = 0; i < rdev->usec_timeout; i++) { + if (RREG32(CONFIG_MEMSIZE) != 0xffffffff) + break; + udelay(1); + } +} + int evergreen_asic_reset(struct radeon_device *rdev) { u32 reset_mask; @@ -3876,10 +3919,17 @@ int evergreen_asic_reset(struct radeon_device *rdev) if (reset_mask) r600_set_bios_scratch_engine_hung(rdev, true); + /* try soft reset */ evergreen_gpu_soft_reset(rdev, reset_mask); reset_mask = evergreen_gpu_check_soft_reset(rdev); + /* try pci config reset */ + if (reset_mask && radeon_hard_reset) + evergreen_gpu_pci_config_reset(rdev); + + reset_mask = evergreen_gpu_check_soft_reset(rdev); + if (!reset_mask) r600_set_bios_scratch_engine_hung(rdev, false); diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h index 17f990798992..f9c7963b3ee6 100644 --- a/drivers/gpu/drm/radeon/evergreend.h +++ b/drivers/gpu/drm/radeon/evergreend.h @@ -82,12 +82,16 @@ #define CG_SPLL_FUNC_CNTL_2 0x604 #define SCLK_MUX_SEL(x) ((x) << 0) #define SCLK_MUX_SEL_MASK (0x1ff << 0) +#define SCLK_MUX_UPDATE (1 << 26) #define CG_SPLL_FUNC_CNTL_3 0x608 #define SPLL_FB_DIV(x) ((x) << 0) #define SPLL_FB_DIV_MASK (0x3ffffff << 0) #define SPLL_DITHEN (1 << 28) +#define CG_SPLL_STATUS 0x60c +#define SPLL_CHG_STATUS (1 << 1) #define MPLL_CNTL_MODE 0x61c +# define MPLL_MCLK_SEL (1 << 11) # define SS_SSEN (1 << 24) # define SS_DSMODE_EN (1 << 25) diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index 05a900945613..9f11a55962b5 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -174,6 +174,7 @@ extern void evergreen_pcie_gen2_enable(struct radeon_device *rdev); extern void evergreen_program_aspm(struct radeon_device *rdev); extern void sumo_rlc_fini(struct radeon_device *rdev); extern int sumo_rlc_init(struct radeon_device *rdev); +extern void evergreen_gpu_pci_config_reset(struct radeon_device *rdev); /* Firmware Names */ MODULE_FIRMWARE("radeon/BARTS_pfp.bin"); @@ -1878,8 +1879,10 @@ int cayman_asic_reset(struct radeon_device *rdev) reset_mask = cayman_gpu_check_soft_reset(rdev); - if (!reset_mask) - r600_set_bios_scratch_engine_hung(rdev, false); + if (reset_mask) + evergreen_gpu_pci_config_reset(rdev); + + r600_set_bios_scratch_engine_hung(rdev, false); return 0; } -- 2.20.1