diff options
author | Alex Deucher <alexander.deucher@amd.com> | 2013-11-15 16:35:55 -0500 |
---|---|---|
committer | Alex Deucher <alexander.deucher@amd.com> | 2014-01-08 18:42:24 -0500 |
commit | 4a5c8ea59f8360f354158fca039ee7fbef0fa4dd (patch) | |
tree | a3f90a21e8fc301d7e03d0145c853c0abd06c5ea /drivers/gpu/drm/radeon/si.c | |
parent | b5470b036e14d063655cc01d22ea5d727042860a (diff) |
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: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers/gpu/drm/radeon/si.c')
-rw-r--r-- | drivers/gpu/drm/radeon/si.c | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index c698e3fe007a..626163ef483d 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c | |||
@@ -80,6 +80,8 @@ extern void evergreen_print_gpu_status_regs(struct radeon_device *rdev); | |||
80 | extern bool evergreen_is_display_hung(struct radeon_device *rdev); | 80 | extern bool evergreen_is_display_hung(struct radeon_device *rdev); |
81 | static void si_enable_gui_idle_interrupt(struct radeon_device *rdev, | 81 | static void si_enable_gui_idle_interrupt(struct radeon_device *rdev, |
82 | bool enable); | 82 | bool enable); |
83 | static void si_init_pg(struct radeon_device *rdev); | ||
84 | static void si_init_cg(struct radeon_device *rdev); | ||
83 | static void si_fini_pg(struct radeon_device *rdev); | 85 | static void si_fini_pg(struct radeon_device *rdev); |
84 | static void si_fini_cg(struct radeon_device *rdev); | 86 | static void si_fini_cg(struct radeon_device *rdev); |
85 | static void si_rlc_stop(struct radeon_device *rdev); | 87 | 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) | |||
3722 | evergreen_print_gpu_status_regs(rdev); | 3724 | evergreen_print_gpu_status_regs(rdev); |
3723 | } | 3725 | } |
3724 | 3726 | ||
3727 | static void si_set_clk_bypass_mode(struct radeon_device *rdev) | ||
3728 | { | ||
3729 | u32 tmp, i; | ||
3730 | |||
3731 | tmp = RREG32(CG_SPLL_FUNC_CNTL); | ||
3732 | tmp |= SPLL_BYPASS_EN; | ||
3733 | WREG32(CG_SPLL_FUNC_CNTL, tmp); | ||
3734 | |||
3735 | tmp = RREG32(CG_SPLL_FUNC_CNTL_2); | ||
3736 | tmp |= SPLL_CTLREQ_CHG; | ||
3737 | WREG32(CG_SPLL_FUNC_CNTL_2, tmp); | ||
3738 | |||
3739 | for (i = 0; i < rdev->usec_timeout; i++) { | ||
3740 | if (RREG32(SPLL_STATUS) & SPLL_CHG_STATUS) | ||
3741 | break; | ||
3742 | udelay(1); | ||
3743 | } | ||
3744 | |||
3745 | tmp = RREG32(CG_SPLL_FUNC_CNTL_2); | ||
3746 | tmp &= ~(SPLL_CTLREQ_CHG | SCLK_MUX_UPDATE); | ||
3747 | WREG32(CG_SPLL_FUNC_CNTL_2, tmp); | ||
3748 | |||
3749 | tmp = RREG32(MPLL_CNTL_MODE); | ||
3750 | tmp &= ~MPLL_MCLK_SEL; | ||
3751 | WREG32(MPLL_CNTL_MODE, tmp); | ||
3752 | } | ||
3753 | |||
3754 | static void si_spll_powerdown(struct radeon_device *rdev) | ||
3755 | { | ||
3756 | u32 tmp; | ||
3757 | |||
3758 | tmp = RREG32(SPLL_CNTL_MODE); | ||
3759 | tmp |= SPLL_SW_DIR_CONTROL; | ||
3760 | WREG32(SPLL_CNTL_MODE, tmp); | ||
3761 | |||
3762 | tmp = RREG32(CG_SPLL_FUNC_CNTL); | ||
3763 | tmp |= SPLL_RESET; | ||
3764 | WREG32(CG_SPLL_FUNC_CNTL, tmp); | ||
3765 | |||
3766 | tmp = RREG32(CG_SPLL_FUNC_CNTL); | ||
3767 | tmp |= SPLL_SLEEP; | ||
3768 | WREG32(CG_SPLL_FUNC_CNTL, tmp); | ||
3769 | |||
3770 | tmp = RREG32(SPLL_CNTL_MODE); | ||
3771 | tmp &= ~SPLL_SW_DIR_CONTROL; | ||
3772 | WREG32(SPLL_CNTL_MODE, tmp); | ||
3773 | } | ||
3774 | |||
3775 | static void si_gpu_pci_config_reset(struct radeon_device *rdev) | ||
3776 | { | ||
3777 | struct evergreen_mc_save save; | ||
3778 | u32 tmp, i; | ||
3779 | |||
3780 | dev_info(rdev->dev, "GPU pci config reset\n"); | ||
3781 | |||
3782 | /* disable dpm? */ | ||
3783 | |||
3784 | /* disable cg/pg */ | ||
3785 | si_fini_pg(rdev); | ||
3786 | si_fini_cg(rdev); | ||
3787 | |||
3788 | /* Disable CP parsing/prefetching */ | ||
3789 | WREG32(CP_ME_CNTL, CP_ME_HALT | CP_PFP_HALT | CP_CE_HALT); | ||
3790 | /* dma0 */ | ||
3791 | tmp = RREG32(DMA_RB_CNTL + DMA0_REGISTER_OFFSET); | ||
3792 | tmp &= ~DMA_RB_ENABLE; | ||
3793 | WREG32(DMA_RB_CNTL + DMA0_REGISTER_OFFSET, tmp); | ||
3794 | /* dma1 */ | ||
3795 | tmp = RREG32(DMA_RB_CNTL + DMA1_REGISTER_OFFSET); | ||
3796 | tmp &= ~DMA_RB_ENABLE; | ||
3797 | WREG32(DMA_RB_CNTL + DMA1_REGISTER_OFFSET, tmp); | ||
3798 | /* XXX other engines? */ | ||
3799 | |||
3800 | /* halt the rlc, disable cp internal ints */ | ||
3801 | si_rlc_stop(rdev); | ||
3802 | |||
3803 | udelay(50); | ||
3804 | |||
3805 | /* disable mem access */ | ||
3806 | evergreen_mc_stop(rdev, &save); | ||
3807 | if (evergreen_mc_wait_for_idle(rdev)) { | ||
3808 | dev_warn(rdev->dev, "Wait for MC idle timed out !\n"); | ||
3809 | } | ||
3810 | |||
3811 | /* set mclk/sclk to bypass */ | ||
3812 | si_set_clk_bypass_mode(rdev); | ||
3813 | /* powerdown spll */ | ||
3814 | si_spll_powerdown(rdev); | ||
3815 | /* disable BM */ | ||
3816 | pci_clear_master(rdev->pdev); | ||
3817 | /* reset */ | ||
3818 | radeon_pci_config_reset(rdev); | ||
3819 | /* wait for asic to come out of reset */ | ||
3820 | for (i = 0; i < rdev->usec_timeout; i++) { | ||
3821 | if (RREG32(CONFIG_MEMSIZE) != 0xffffffff) | ||
3822 | break; | ||
3823 | udelay(1); | ||
3824 | } | ||
3825 | } | ||
3826 | |||
3725 | int si_asic_reset(struct radeon_device *rdev) | 3827 | int si_asic_reset(struct radeon_device *rdev) |
3726 | { | 3828 | { |
3727 | u32 reset_mask; | 3829 | u32 reset_mask; |
@@ -3731,10 +3833,17 @@ int si_asic_reset(struct radeon_device *rdev) | |||
3731 | if (reset_mask) | 3833 | if (reset_mask) |
3732 | r600_set_bios_scratch_engine_hung(rdev, true); | 3834 | r600_set_bios_scratch_engine_hung(rdev, true); |
3733 | 3835 | ||
3836 | /* try soft reset */ | ||
3734 | si_gpu_soft_reset(rdev, reset_mask); | 3837 | si_gpu_soft_reset(rdev, reset_mask); |
3735 | 3838 | ||
3736 | reset_mask = si_gpu_check_soft_reset(rdev); | 3839 | reset_mask = si_gpu_check_soft_reset(rdev); |
3737 | 3840 | ||
3841 | /* try pci config reset */ | ||
3842 | if (reset_mask && radeon_hard_reset) | ||
3843 | si_gpu_pci_config_reset(rdev); | ||
3844 | |||
3845 | reset_mask = si_gpu_check_soft_reset(rdev); | ||
3846 | |||
3738 | if (!reset_mask) | 3847 | if (!reset_mask) |
3739 | r600_set_bios_scratch_engine_hung(rdev, false); | 3848 | r600_set_bios_scratch_engine_hung(rdev, false); |
3740 | 3849 | ||