drm/radeon: implement pci config reset for SI (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: hide behind module parameter

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
Alex Deucher 2013-11-15 16:35:55 -05:00
parent b5470b036e
commit 4a5c8ea59f
2 changed files with 116 additions and 0 deletions

View File

@ -80,6 +80,8 @@ extern void evergreen_print_gpu_status_regs(struct radeon_device *rdev);
extern bool evergreen_is_display_hung(struct radeon_device *rdev); extern bool evergreen_is_display_hung(struct radeon_device *rdev);
static void si_enable_gui_idle_interrupt(struct radeon_device *rdev, static void si_enable_gui_idle_interrupt(struct radeon_device *rdev,
bool enable); bool enable);
static void si_init_pg(struct radeon_device *rdev);
static void si_init_cg(struct radeon_device *rdev);
static void si_fini_pg(struct radeon_device *rdev); static void si_fini_pg(struct radeon_device *rdev);
static void si_fini_cg(struct radeon_device *rdev); static void si_fini_cg(struct radeon_device *rdev);
static void si_rlc_stop(struct radeon_device *rdev); static void si_rlc_stop(struct radeon_device *rdev);
@ -3722,6 +3724,106 @@ static void si_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask)
evergreen_print_gpu_status_regs(rdev); evergreen_print_gpu_status_regs(rdev);
} }
static void si_set_clk_bypass_mode(struct radeon_device *rdev)
{
u32 tmp, i;
tmp = RREG32(CG_SPLL_FUNC_CNTL);
tmp |= SPLL_BYPASS_EN;
WREG32(CG_SPLL_FUNC_CNTL, tmp);
tmp = RREG32(CG_SPLL_FUNC_CNTL_2);
tmp |= SPLL_CTLREQ_CHG;
WREG32(CG_SPLL_FUNC_CNTL_2, tmp);
for (i = 0; i < rdev->usec_timeout; i++) {
if (RREG32(SPLL_STATUS) & SPLL_CHG_STATUS)
break;
udelay(1);
}
tmp = RREG32(CG_SPLL_FUNC_CNTL_2);
tmp &= ~(SPLL_CTLREQ_CHG | SCLK_MUX_UPDATE);
WREG32(CG_SPLL_FUNC_CNTL_2, tmp);
tmp = RREG32(MPLL_CNTL_MODE);
tmp &= ~MPLL_MCLK_SEL;
WREG32(MPLL_CNTL_MODE, tmp);
}
static void si_spll_powerdown(struct radeon_device *rdev)
{
u32 tmp;
tmp = RREG32(SPLL_CNTL_MODE);
tmp |= SPLL_SW_DIR_CONTROL;
WREG32(SPLL_CNTL_MODE, tmp);
tmp = RREG32(CG_SPLL_FUNC_CNTL);
tmp |= SPLL_RESET;
WREG32(CG_SPLL_FUNC_CNTL, tmp);
tmp = RREG32(CG_SPLL_FUNC_CNTL);
tmp |= SPLL_SLEEP;
WREG32(CG_SPLL_FUNC_CNTL, tmp);
tmp = RREG32(SPLL_CNTL_MODE);
tmp &= ~SPLL_SW_DIR_CONTROL;
WREG32(SPLL_CNTL_MODE, tmp);
}
static void si_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 cg/pg */
si_fini_pg(rdev);
si_fini_cg(rdev);
/* Disable CP parsing/prefetching */
WREG32(CP_ME_CNTL, CP_ME_HALT | CP_PFP_HALT | CP_CE_HALT);
/* dma0 */
tmp = RREG32(DMA_RB_CNTL + DMA0_REGISTER_OFFSET);
tmp &= ~DMA_RB_ENABLE;
WREG32(DMA_RB_CNTL + DMA0_REGISTER_OFFSET, tmp);
/* dma1 */
tmp = RREG32(DMA_RB_CNTL + DMA1_REGISTER_OFFSET);
tmp &= ~DMA_RB_ENABLE;
WREG32(DMA_RB_CNTL + DMA1_REGISTER_OFFSET, tmp);
/* XXX other engines? */
/* halt the rlc, disable cp internal ints */
si_rlc_stop(rdev);
udelay(50);
/* 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");
}
/* set mclk/sclk to bypass */
si_set_clk_bypass_mode(rdev);
/* powerdown spll */
si_spll_powerdown(rdev);
/* disable BM */
pci_clear_master(rdev->pdev);
/* 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 si_asic_reset(struct radeon_device *rdev) int si_asic_reset(struct radeon_device *rdev)
{ {
u32 reset_mask; u32 reset_mask;
@ -3731,10 +3833,17 @@ int si_asic_reset(struct radeon_device *rdev)
if (reset_mask) if (reset_mask)
r600_set_bios_scratch_engine_hung(rdev, true); r600_set_bios_scratch_engine_hung(rdev, true);
/* try soft reset */
si_gpu_soft_reset(rdev, reset_mask); si_gpu_soft_reset(rdev, reset_mask);
reset_mask = si_gpu_check_soft_reset(rdev); reset_mask = si_gpu_check_soft_reset(rdev);
/* try pci config reset */
if (reset_mask && radeon_hard_reset)
si_gpu_pci_config_reset(rdev);
reset_mask = si_gpu_check_soft_reset(rdev);
if (!reset_mask) if (!reset_mask)
r600_set_bios_scratch_engine_hung(rdev, false); r600_set_bios_scratch_engine_hung(rdev, false);

View File

@ -94,6 +94,8 @@
#define CG_SPLL_FUNC_CNTL_2 0x604 #define CG_SPLL_FUNC_CNTL_2 0x604
#define SCLK_MUX_SEL(x) ((x) << 0) #define SCLK_MUX_SEL(x) ((x) << 0)
#define SCLK_MUX_SEL_MASK (0x1ff << 0) #define SCLK_MUX_SEL_MASK (0x1ff << 0)
#define SPLL_CTLREQ_CHG (1 << 23)
#define SCLK_MUX_UPDATE (1 << 26)
#define CG_SPLL_FUNC_CNTL_3 0x608 #define CG_SPLL_FUNC_CNTL_3 0x608
#define SPLL_FB_DIV(x) ((x) << 0) #define SPLL_FB_DIV(x) ((x) << 0)
#define SPLL_FB_DIV_MASK (0x3ffffff << 0) #define SPLL_FB_DIV_MASK (0x3ffffff << 0)
@ -101,7 +103,10 @@
#define SPLL_DITHEN (1 << 28) #define SPLL_DITHEN (1 << 28)
#define CG_SPLL_FUNC_CNTL_4 0x60c #define CG_SPLL_FUNC_CNTL_4 0x60c
#define SPLL_STATUS 0x614
#define SPLL_CHG_STATUS (1 << 1)
#define SPLL_CNTL_MODE 0x618 #define SPLL_CNTL_MODE 0x618
#define SPLL_SW_DIR_CONTROL (1 << 0)
# define SPLL_REFCLK_SEL(x) ((x) << 8) # define SPLL_REFCLK_SEL(x) ((x) << 8)
# define SPLL_REFCLK_SEL_MASK 0xFF00 # define SPLL_REFCLK_SEL_MASK 0xFF00
@ -559,6 +564,8 @@
# define MRDCK0_BYPASS (1 << 24) # define MRDCK0_BYPASS (1 << 24)
# define MRDCK1_BYPASS (1 << 25) # define MRDCK1_BYPASS (1 << 25)
#define MPLL_CNTL_MODE 0x2bb0
# define MPLL_MCLK_SEL (1 << 11)
#define MPLL_FUNC_CNTL 0x2bb4 #define MPLL_FUNC_CNTL 0x2bb4
#define BWCTRL(x) ((x) << 20) #define BWCTRL(x) ((x) << 20)
#define BWCTRL_MASK (0xff << 20) #define BWCTRL_MASK (0xff << 20)