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:
Родитель
b5470b036e
Коммит
4a5c8ea59f
|
@ -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);
|
||||
static void si_enable_gui_idle_interrupt(struct radeon_device *rdev,
|
||||
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_cg(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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
u32 reset_mask;
|
||||
|
@ -3731,10 +3833,17 @@ int si_asic_reset(struct radeon_device *rdev)
|
|||
if (reset_mask)
|
||||
r600_set_bios_scratch_engine_hung(rdev, true);
|
||||
|
||||
/* try soft reset */
|
||||
si_gpu_soft_reset(rdev, reset_mask);
|
||||
|
||||
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)
|
||||
r600_set_bios_scratch_engine_hung(rdev, false);
|
||||
|
||||
|
|
|
@ -94,6 +94,8 @@
|
|||
#define CG_SPLL_FUNC_CNTL_2 0x604
|
||||
#define SCLK_MUX_SEL(x) ((x) << 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 SPLL_FB_DIV(x) ((x) << 0)
|
||||
#define SPLL_FB_DIV_MASK (0x3ffffff << 0)
|
||||
|
@ -101,7 +103,10 @@
|
|||
#define SPLL_DITHEN (1 << 28)
|
||||
#define CG_SPLL_FUNC_CNTL_4 0x60c
|
||||
|
||||
#define SPLL_STATUS 0x614
|
||||
#define SPLL_CHG_STATUS (1 << 1)
|
||||
#define SPLL_CNTL_MODE 0x618
|
||||
#define SPLL_SW_DIR_CONTROL (1 << 0)
|
||||
# define SPLL_REFCLK_SEL(x) ((x) << 8)
|
||||
# define SPLL_REFCLK_SEL_MASK 0xFF00
|
||||
|
||||
|
@ -559,6 +564,8 @@
|
|||
# define MRDCK0_BYPASS (1 << 24)
|
||||
# define MRDCK1_BYPASS (1 << 25)
|
||||
|
||||
#define MPLL_CNTL_MODE 0x2bb0
|
||||
# define MPLL_MCLK_SEL (1 << 11)
|
||||
#define MPLL_FUNC_CNTL 0x2bb4
|
||||
#define BWCTRL(x) ((x) << 20)
|
||||
#define BWCTRL_MASK (0xff << 20)
|
||||
|
|
Загрузка…
Ссылка в новой задаче