Эх сурвалжийг харах

drm/radeon: implement pci config reset for r6xx/7xx (v3)

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.

There's not much information still available on
r6xx, so r6xx is based on guess-work.

v2: put behind module parameter
v3: add IGP check

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Alex Deucher 11 жил өмнө
parent
commit
de9ae7447a

+ 69 - 0
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);
 void r600_irq_disable(struct radeon_device *rdev);
 static void r600_pcie_gen2_enable(struct radeon_device *rdev);
 static void r600_pcie_gen2_enable(struct radeon_device *rdev);
 extern int evergreen_rlc_resume(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
  * 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);
 	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)
 int r600_asic_reset(struct radeon_device *rdev)
 {
 {
 	u32 reset_mask;
 	u32 reset_mask;
@@ -1653,10 +1715,17 @@ int r600_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 */
 	r600_gpu_soft_reset(rdev, reset_mask);
 	r600_gpu_soft_reset(rdev, reset_mask);
 
 
 	reset_mask = r600_gpu_check_soft_reset(rdev);
 	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)
 	if (!reset_mask)
 		r600_set_bios_scratch_engine_hung(rdev, false);
 		r600_set_bios_scratch_engine_hung(rdev, false);
 
 

+ 7 - 0
drivers/gpu/drm/radeon/r600d.h

@@ -701,11 +701,18 @@
 #define RLC_UCODE_DATA                                    0x3f30
 #define RLC_UCODE_DATA                                    0x3f30
 
 
 #define SRBM_SOFT_RESET                                   0xe60
 #define SRBM_SOFT_RESET                                   0xe60
+#       define SOFT_RESET_BIF                             (1 << 1)
 #       define SOFT_RESET_DMA                             (1 << 12)
 #       define SOFT_RESET_DMA                             (1 << 12)
 #       define SOFT_RESET_RLC                             (1 << 13)
 #       define SOFT_RESET_RLC                             (1 << 13)
 #       define SOFT_RESET_UVD                             (1 << 18)
 #       define SOFT_RESET_UVD                             (1 << 18)
 #       define RV770_SOFT_RESET_DMA                       (1 << 20)
 #       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 CP_INT_CNTL                                       0xc124
 #       define CNTX_BUSY_INT_ENABLE                       (1 << 19)
 #       define CNTX_BUSY_INT_ENABLE                       (1 << 19)
 #       define CNTX_EMPTY_INT_ENABLE                      (1 << 20)
 #       define CNTX_EMPTY_INT_ENABLE                      (1 << 20)

+ 29 - 0
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);
 	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
  * Core functions
  */
  */

+ 7 - 0
drivers/gpu/drm/radeon/rv770d.h

@@ -100,14 +100,21 @@
 #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		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)
 #define		SPLL_DITHEN				(1 << 28)
 #define		SPLL_DITHEN				(1 << 28)
+#define	CG_SPLL_STATUS					0x60c
+#define		SPLL_CHG_STATUS				(1 << 1)
 
 
 #define	SPLL_CNTL_MODE					0x610
 #define	SPLL_CNTL_MODE					0x610
 #define		SPLL_DIV_SYNC				(1 << 5)
 #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	MPLL_AD_FUNC_CNTL				0x624
 #define		CLKF(x)					((x) << 0)
 #define		CLKF(x)					((x) << 0)
 #define		CLKF_MASK				(0x7f << 0)
 #define		CLKF_MASK				(0x7f << 0)