Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4a5c8ea5 authored by Alex Deucher's avatar Alex Deucher
Browse files

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: default avatarAlex Deucher <alexander.deucher@amd.com>
parent b5470b03
Loading
Loading
Loading
Loading
+109 −0
Original line number Diff line number Diff line
@@ -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);

+7 −0
Original line number Diff line number Diff line
@@ -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)