diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index bf0792cf0729..ad99bae2e85c 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -105,6 +105,7 @@ void r600_fini(struct radeon_device *rdev); void r600_irq_disable(struct radeon_device *rdev); static void r600_pcie_gen2_enable(struct radeon_device *rdev); extern int evergreen_rlc_resume(struct radeon_device *rdev); +extern void rv770_set_clk_bypass_mode(struct radeon_device *rdev); /** * r600_get_xclk - get the xclk @@ -1644,6 +1645,67 @@ static void r600_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask) r600_print_gpu_status_regs(rdev); } +static void r600_gpu_pci_config_reset(struct radeon_device *rdev) +{ + struct rv515_mc_save save; + u32 tmp, i; + + dev_info(rdev->dev, "GPU pci config reset\n"); + + /* disable dpm? */ + + /* Disable CP parsing/prefetching */ + if (rdev->family >= CHIP_RV770) + WREG32(R_0086D8_CP_ME_CNTL, S_0086D8_CP_ME_HALT(1) | S_0086D8_CP_PFP_HALT(1)); + else + WREG32(R_0086D8_CP_ME_CNTL, S_0086D8_CP_ME_HALT(1)); + + /* disable the RLC */ + WREG32(RLC_CNTL, 0); + + /* Disable DMA */ + tmp = RREG32(DMA_RB_CNTL); + tmp &= ~DMA_RB_ENABLE; + WREG32(DMA_RB_CNTL, tmp); + + mdelay(50); + + /* set mclk/sclk to bypass */ + if (rdev->family >= CHIP_RV770) + rv770_set_clk_bypass_mode(rdev); + /* disable BM */ + pci_clear_master(rdev->pdev); + /* disable mem access */ + rv515_mc_stop(rdev, &save); + if (r600_mc_wait_for_idle(rdev)) { + dev_warn(rdev->dev, "Wait for MC idle timedout !\n"); + } + + /* BIF reset workaround. Not sure if this is needed on 6xx */ + tmp = RREG32(BUS_CNTL); + tmp |= VGA_COHE_SPEC_TIMER_DIS; + WREG32(BUS_CNTL, tmp); + + tmp = RREG32(BIF_SCRATCH0); + + /* reset */ + radeon_pci_config_reset(rdev); + mdelay(1); + + /* BIF reset workaround. Not sure if this is needed on 6xx */ + tmp = SOFT_RESET_BIF; + WREG32(SRBM_SOFT_RESET, tmp); + mdelay(1); + WREG32(SRBM_SOFT_RESET, 0); + + /* 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 r600_asic_reset(struct radeon_device *rdev) { u32 reset_mask; @@ -1653,10 +1715,17 @@ int r600_asic_reset(struct radeon_device *rdev) if (reset_mask) r600_set_bios_scratch_engine_hung(rdev, true); + /* try soft reset */ r600_gpu_soft_reset(rdev, reset_mask); reset_mask = r600_gpu_check_soft_reset(rdev); + /* try pci config reset */ + if (reset_mask && radeon_hard_reset) + r600_gpu_pci_config_reset(rdev); + + reset_mask = r600_gpu_check_soft_reset(rdev); + if (!reset_mask) r600_set_bios_scratch_engine_hung(rdev, false); diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h index ebe38724a976..3fca4b9c65ad 100644 --- a/drivers/gpu/drm/radeon/r600d.h +++ b/drivers/gpu/drm/radeon/r600d.h @@ -701,11 +701,18 @@ #define RLC_UCODE_DATA 0x3f30 #define SRBM_SOFT_RESET 0xe60 +# define SOFT_RESET_BIF (1 << 1) # define SOFT_RESET_DMA (1 << 12) # define SOFT_RESET_RLC (1 << 13) # define SOFT_RESET_UVD (1 << 18) # define RV770_SOFT_RESET_DMA (1 << 20) +#define BIF_SCRATCH0 0x5438 + +#define BUS_CNTL 0x5420 +# define BIOS_ROM_DIS (1 << 1) +# define VGA_COHE_SPEC_TIMER_DIS (1 << 9) + #define CP_INT_CNTL 0xc124 # define CNTX_BUSY_INT_ENABLE (1 << 19) # define CNTX_EMPTY_INT_ENABLE (1 << 20) diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 82e06e9a76d2..18e02889ec7d 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -1123,6 +1123,35 @@ void r700_cp_fini(struct radeon_device *rdev) radeon_scratch_free(rdev, ring->rptr_save_reg); } +void rv770_set_clk_bypass_mode(struct radeon_device *rdev) +{ + u32 tmp, i; + + if (rdev->flags & RADEON_IS_IGP) + return; + + tmp = RREG32(CG_SPLL_FUNC_CNTL_2); + tmp &= SCLK_MUX_SEL_MASK; + tmp |= SCLK_MUX_SEL(1) | SCLK_MUX_UPDATE; + WREG32(CG_SPLL_FUNC_CNTL_2, tmp); + + for (i = 0; i < rdev->usec_timeout; i++) { + if (RREG32(CG_SPLL_STATUS) & SPLL_CHG_STATUS) + break; + udelay(1); + } + + tmp &= ~SCLK_MUX_UPDATE; + WREG32(CG_SPLL_FUNC_CNTL_2, tmp); + + tmp = RREG32(MPLL_CNTL_MODE); + if ((rdev->family == CHIP_RV710) || (rdev->family == CHIP_RV730)) + tmp &= ~RV730_MPLL_MCLK_SEL; + else + tmp &= ~MPLL_MCLK_SEL; + WREG32(MPLL_CNTL_MODE, tmp); +} + /* * Core functions */ diff --git a/drivers/gpu/drm/radeon/rv770d.h b/drivers/gpu/drm/radeon/rv770d.h index 1ae277152cc7..3cf1e2921545 100644 --- a/drivers/gpu/drm/radeon/rv770d.h +++ b/drivers/gpu/drm/radeon/rv770d.h @@ -100,14 +100,21 @@ #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 SPLL_CNTL_MODE 0x610 #define SPLL_DIV_SYNC (1 << 5) +#define MPLL_CNTL_MODE 0x61c +# define MPLL_MCLK_SEL (1 << 11) +# define RV730_MPLL_MCLK_SEL (1 << 25) + #define MPLL_AD_FUNC_CNTL 0x624 #define CLKF(x) ((x) << 0) #define CLKF_MASK (0x7f << 0)