drm/radeon: implement pci config reset for SI (v2)
authorAlex Deucher <alexander.deucher@amd.com>
Fri, 15 Nov 2013 21:35:55 +0000 (16:35 -0500)
committerAlex Deucher <alexander.deucher@amd.com>
Wed, 8 Jan 2014 23:42:24 +0000 (18:42 -0500)
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>
drivers/gpu/drm/radeon/si.c
drivers/gpu/drm/radeon/sid.h

index c698e3fe007a2b4f090131d40a26b806c81c0e71..626163ef483dd10567d1de42ba3d1fcb817bcbfa 100644 (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);
 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);
 
index b322acc48097f632a0fa1ac3204facc3287912f5..caa3e61a38c25b587537933850317ac5d89e10bf 100644 (file)
@@ -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)
 #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
 
 #       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)