drm/radeon: implement pci config reset for r6xx/7xx (v3)
authorAlex Deucher <alexander.deucher@amd.com>
Fri, 1 Nov 2013 23:01:36 +0000 (19:01 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Wed, 8 Jan 2014 23:42:22 +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.

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>
drivers/gpu/drm/radeon/r600.c
drivers/gpu/drm/radeon/r600d.h
drivers/gpu/drm/radeon/rv770.c
drivers/gpu/drm/radeon/rv770d.h

index bf0792c..ad99bae 100644 (file)
@@ -105,6 +105,7 @@ void r600_fini(struct radeon_device *rdev);
 void r600_irq_disable(struct radeon_device *rdev);
 static void r600_pcie_gen2_enable(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
@@ -1644,6 +1645,67 @@ static void r600_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask)
        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)
 {
        u32 reset_mask;
@@ -1653,10 +1715,17 @@ int r600_asic_reset(struct radeon_device *rdev)
        if (reset_mask)
                r600_set_bios_scratch_engine_hung(rdev, true);
 
+       /* try soft reset */
        r600_gpu_soft_reset(rdev, reset_mask);
 
        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)
                r600_set_bios_scratch_engine_hung(rdev, false);
 
index ebe3872..3fca4b9 100644 (file)
 #define RLC_UCODE_DATA                                    0x3f30
 
 #define SRBM_SOFT_RESET                                   0xe60
+#       define SOFT_RESET_BIF                             (1 << 1)
 #       define SOFT_RESET_DMA                             (1 << 12)
 #       define SOFT_RESET_RLC                             (1 << 13)
 #       define SOFT_RESET_UVD                             (1 << 18)
 #       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 CNTX_BUSY_INT_ENABLE                       (1 << 19)
 #       define CNTX_EMPTY_INT_ENABLE                      (1 << 20)
index 82e06e9..18e0288 100644 (file)
@@ -1123,6 +1123,35 @@ void r700_cp_fini(struct radeon_device *rdev)
        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
  */
index 1ae2771..3cf1e29 100644 (file)
 #define        CG_SPLL_FUNC_CNTL_2                             0x604
 #define                SCLK_MUX_SEL(x)                         ((x) << 0)
 #define                SCLK_MUX_SEL_MASK                       (0x1ff << 0)
+#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_STATUS                                  0x60c
+#define                SPLL_CHG_STATUS                         (1 << 1)
 
 #define        SPLL_CNTL_MODE                                  0x610
 #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                CLKF(x)                                 ((x) << 0)
 #define                CLKF_MASK                               (0x7f << 0)