Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+112
+69
drivers/gpu/drm/radeon/r600.c
··· 105 105 void r600_irq_disable(struct radeon_device *rdev); 106 106 static void r600_pcie_gen2_enable(struct radeon_device *rdev); 107 107 extern int evergreen_rlc_resume(struct radeon_device *rdev); 108 + extern void rv770_set_clk_bypass_mode(struct radeon_device *rdev); 108 109 109 110 /** 110 111 * r600_get_xclk - get the xclk ··· 1645 1644 r600_print_gpu_status_regs(rdev); 1646 1645 } 1647 1646 1647 + static void r600_gpu_pci_config_reset(struct radeon_device *rdev) 1648 + { 1649 + struct rv515_mc_save save; 1650 + u32 tmp, i; 1651 + 1652 + dev_info(rdev->dev, "GPU pci config reset\n"); 1653 + 1654 + /* disable dpm? */ 1655 + 1656 + /* Disable CP parsing/prefetching */ 1657 + if (rdev->family >= CHIP_RV770) 1658 + WREG32(R_0086D8_CP_ME_CNTL, S_0086D8_CP_ME_HALT(1) | S_0086D8_CP_PFP_HALT(1)); 1659 + else 1660 + WREG32(R_0086D8_CP_ME_CNTL, S_0086D8_CP_ME_HALT(1)); 1661 + 1662 + /* disable the RLC */ 1663 + WREG32(RLC_CNTL, 0); 1664 + 1665 + /* Disable DMA */ 1666 + tmp = RREG32(DMA_RB_CNTL); 1667 + tmp &= ~DMA_RB_ENABLE; 1668 + WREG32(DMA_RB_CNTL, tmp); 1669 + 1670 + mdelay(50); 1671 + 1672 + /* set mclk/sclk to bypass */ 1673 + if (rdev->family >= CHIP_RV770) 1674 + rv770_set_clk_bypass_mode(rdev); 1675 + /* disable BM */ 1676 + pci_clear_master(rdev->pdev); 1677 + /* disable mem access */ 1678 + rv515_mc_stop(rdev, &save); 1679 + if (r600_mc_wait_for_idle(rdev)) { 1680 + dev_warn(rdev->dev, "Wait for MC idle timedout !\n"); 1681 + } 1682 + 1683 + /* BIF reset workaround. Not sure if this is needed on 6xx */ 1684 + tmp = RREG32(BUS_CNTL); 1685 + tmp |= VGA_COHE_SPEC_TIMER_DIS; 1686 + WREG32(BUS_CNTL, tmp); 1687 + 1688 + tmp = RREG32(BIF_SCRATCH0); 1689 + 1690 + /* reset */ 1691 + radeon_pci_config_reset(rdev); 1692 + mdelay(1); 1693 + 1694 + /* BIF reset workaround. Not sure if this is needed on 6xx */ 1695 + tmp = SOFT_RESET_BIF; 1696 + WREG32(SRBM_SOFT_RESET, tmp); 1697 + mdelay(1); 1698 + WREG32(SRBM_SOFT_RESET, 0); 1699 + 1700 + /* wait for asic to come out of reset */ 1701 + for (i = 0; i < rdev->usec_timeout; i++) { 1702 + if (RREG32(CONFIG_MEMSIZE) != 0xffffffff) 1703 + break; 1704 + udelay(1); 1705 + } 1706 + } 1707 + 1648 1708 int r600_asic_reset(struct radeon_device *rdev) 1649 1709 { 1650 1710 u32 reset_mask; ··· 1715 1653 if (reset_mask) 1716 1654 r600_set_bios_scratch_engine_hung(rdev, true); 1717 1655 1656 + /* try soft reset */ 1718 1657 r600_gpu_soft_reset(rdev, reset_mask); 1658 + 1659 + reset_mask = r600_gpu_check_soft_reset(rdev); 1660 + 1661 + /* try pci config reset */ 1662 + if (reset_mask && radeon_hard_reset) 1663 + r600_gpu_pci_config_reset(rdev); 1719 1664 1720 1665 reset_mask = r600_gpu_check_soft_reset(rdev); 1721 1666
+7
drivers/gpu/drm/radeon/r600d.h
··· 701 701 #define RLC_UCODE_DATA 0x3f30 702 702 703 703 #define SRBM_SOFT_RESET 0xe60 704 + # define SOFT_RESET_BIF (1 << 1) 704 705 # define SOFT_RESET_DMA (1 << 12) 705 706 # define SOFT_RESET_RLC (1 << 13) 706 707 # define SOFT_RESET_UVD (1 << 18) 707 708 # define RV770_SOFT_RESET_DMA (1 << 20) 709 + 710 + #define BIF_SCRATCH0 0x5438 711 + 712 + #define BUS_CNTL 0x5420 713 + # define BIOS_ROM_DIS (1 << 1) 714 + # define VGA_COHE_SPEC_TIMER_DIS (1 << 9) 708 715 709 716 #define CP_INT_CNTL 0xc124 710 717 # define CNTX_BUSY_INT_ENABLE (1 << 19)
+29
drivers/gpu/drm/radeon/rv770.c
··· 1123 1123 radeon_scratch_free(rdev, ring->rptr_save_reg); 1124 1124 } 1125 1125 1126 + void rv770_set_clk_bypass_mode(struct radeon_device *rdev) 1127 + { 1128 + u32 tmp, i; 1129 + 1130 + if (rdev->flags & RADEON_IS_IGP) 1131 + return; 1132 + 1133 + tmp = RREG32(CG_SPLL_FUNC_CNTL_2); 1134 + tmp &= SCLK_MUX_SEL_MASK; 1135 + tmp |= SCLK_MUX_SEL(1) | SCLK_MUX_UPDATE; 1136 + WREG32(CG_SPLL_FUNC_CNTL_2, tmp); 1137 + 1138 + for (i = 0; i < rdev->usec_timeout; i++) { 1139 + if (RREG32(CG_SPLL_STATUS) & SPLL_CHG_STATUS) 1140 + break; 1141 + udelay(1); 1142 + } 1143 + 1144 + tmp &= ~SCLK_MUX_UPDATE; 1145 + WREG32(CG_SPLL_FUNC_CNTL_2, tmp); 1146 + 1147 + tmp = RREG32(MPLL_CNTL_MODE); 1148 + if ((rdev->family == CHIP_RV710) || (rdev->family == CHIP_RV730)) 1149 + tmp &= ~RV730_MPLL_MCLK_SEL; 1150 + else 1151 + tmp &= ~MPLL_MCLK_SEL; 1152 + WREG32(MPLL_CNTL_MODE, tmp); 1153 + } 1154 + 1126 1155 /* 1127 1156 * Core functions 1128 1157 */
+7
drivers/gpu/drm/radeon/rv770d.h
··· 100 100 #define CG_SPLL_FUNC_CNTL_2 0x604 101 101 #define SCLK_MUX_SEL(x) ((x) << 0) 102 102 #define SCLK_MUX_SEL_MASK (0x1ff << 0) 103 + #define SCLK_MUX_UPDATE (1 << 26) 103 104 #define CG_SPLL_FUNC_CNTL_3 0x608 104 105 #define SPLL_FB_DIV(x) ((x) << 0) 105 106 #define SPLL_FB_DIV_MASK (0x3ffffff << 0) 106 107 #define SPLL_DITHEN (1 << 28) 108 + #define CG_SPLL_STATUS 0x60c 109 + #define SPLL_CHG_STATUS (1 << 1) 107 110 108 111 #define SPLL_CNTL_MODE 0x610 109 112 #define SPLL_DIV_SYNC (1 << 5) 113 + 114 + #define MPLL_CNTL_MODE 0x61c 115 + # define MPLL_MCLK_SEL (1 << 11) 116 + # define RV730_MPLL_MCLK_SEL (1 << 25) 110 117 111 118 #define MPLL_AD_FUNC_CNTL 0x624 112 119 #define CLKF(x) ((x) << 0)