| /* |
| * Copyright 2008 Advanced Micro Devices, Inc. |
| * Copyright 2008 Red Hat Inc. |
| * Copyright 2009 Jerome Glisse. |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the "Software"), |
| * to deal in the Software without restriction, including without limitation |
| * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| * and/or sell copies of the Software, and to permit persons to whom the |
| * Software is furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice shall be included in |
| * all copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
| * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
| * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
| * OTHER DEALINGS IN THE SOFTWARE. |
| * |
| * Authors: Dave Airlie |
| * Alex Deucher |
| * Jerome Glisse |
| */ |
| #include "drmP.h" |
| #include "radeon_drm.h" |
| #include "radeon_reg.h" |
| #include "radeon.h" |
| #include "atom.h" |
| |
| /* 10 khz */ |
| uint32_t radeon_legacy_get_engine_clock(struct radeon_device *rdev) |
| { |
| struct radeon_pll *spll = &rdev->clock.spll; |
| uint32_t fb_div, ref_div, post_div, sclk; |
| |
| fb_div = RREG32_PLL(RADEON_M_SPLL_REF_FB_DIV); |
| fb_div = (fb_div >> RADEON_SPLL_FB_DIV_SHIFT) & RADEON_SPLL_FB_DIV_MASK; |
| fb_div <<= 1; |
| fb_div *= spll->reference_freq; |
| |
| ref_div = |
| RREG32_PLL(RADEON_M_SPLL_REF_FB_DIV) & RADEON_M_SPLL_REF_DIV_MASK; |
| |
| if (ref_div == 0) |
| return 0; |
| |
| sclk = fb_div / ref_div; |
| |
| post_div = RREG32_PLL(RADEON_SCLK_CNTL) & RADEON_SCLK_SRC_SEL_MASK; |
| if (post_div == 2) |
| sclk >>= 1; |
| else if (post_div == 3) |
| sclk >>= 2; |
| else if (post_div == 4) |
| sclk >>= 3; |
| |
| return sclk; |
| } |
| |
| /* 10 khz */ |
| uint32_t radeon_legacy_get_memory_clock(struct radeon_device *rdev) |
| { |
| struct radeon_pll *mpll = &rdev->clock.mpll; |
| uint32_t fb_div, ref_div, post_div, mclk; |
| |
| fb_div = RREG32_PLL(RADEON_M_SPLL_REF_FB_DIV); |
| fb_div = (fb_div >> RADEON_MPLL_FB_DIV_SHIFT) & RADEON_MPLL_FB_DIV_MASK; |
| fb_div <<= 1; |
| fb_div *= mpll->reference_freq; |
| |
| ref_div = |
| RREG32_PLL(RADEON_M_SPLL_REF_FB_DIV) & RADEON_M_SPLL_REF_DIV_MASK; |
| |
| if (ref_div == 0) |
| return 0; |
| |
| mclk = fb_div / ref_div; |
| |
| post_div = RREG32_PLL(RADEON_MCLK_CNTL) & 0x7; |
| if (post_div == 2) |
| mclk >>= 1; |
| else if (post_div == 3) |
| mclk >>= 2; |
| else if (post_div == 4) |
| mclk >>= 3; |
| |
| return mclk; |
| } |
| |
| #ifdef CONFIG_OF |
| /* |
| * Read XTAL (ref clock), SCLK and MCLK from Open Firmware device |
| * tree. Hopefully, ATI OF driver is kind enough to fill these |
| */ |
| static bool __devinit radeon_read_clocks_OF(struct drm_device *dev) |
| { |
| struct radeon_device *rdev = dev->dev_private; |
| struct device_node *dp = rdev->pdev->dev.of_node; |
| const u32 *val; |
| struct radeon_pll *p1pll = &rdev->clock.p1pll; |
| struct radeon_pll *p2pll = &rdev->clock.p2pll; |
| struct radeon_pll *spll = &rdev->clock.spll; |
| struct radeon_pll *mpll = &rdev->clock.mpll; |
| |
| if (dp == NULL) |
| return false; |
| val = of_get_property(dp, "ATY,RefCLK", NULL); |
| if (!val || !*val) { |
| printk(KERN_WARNING "radeonfb: No ATY,RefCLK property !\n"); |
| return false; |
| } |
| p1pll->reference_freq = p2pll->reference_freq = (*val) / 10; |
| p1pll->reference_div = RREG32_PLL(RADEON_PPLL_REF_DIV) & 0x3ff; |
| if (p1pll->reference_div < 2) |
| p1pll->reference_div = 12; |
| p2pll->reference_div = p1pll->reference_div; |
| |
| /* These aren't in the device-tree */ |
| if (rdev->family >= CHIP_R420) { |
| p1pll->pll_in_min = 100; |
| p1pll->pll_in_max = 1350; |
| p1pll->pll_out_min = 20000; |
| p1pll->pll_out_max = 50000; |
| p2pll->pll_in_min = 100; |
| p2pll->pll_in_max = 1350; |
| p2pll->pll_out_min = 20000; |
| p2pll->pll_out_max = 50000; |
| } else { |
| p1pll->pll_in_min = 40; |
| p1pll->pll_in_max = 500; |
| p1pll->pll_out_min = 12500; |
| p1pll->pll_out_max = 35000; |
| p2pll->pll_in_min = 40; |
| p2pll->pll_in_max = 500; |
| p2pll->pll_out_min = 12500; |
| p2pll->pll_out_max = 35000; |
| } |
| |
| spll->reference_freq = mpll->reference_freq = p1pll->reference_freq; |
| spll->reference_div = mpll->reference_div = |
| RREG32_PLL(RADEON_M_SPLL_REF_FB_DIV) & |
| RADEON_M_SPLL_REF_DIV_MASK; |
| |
| val = of_get_property(dp, "ATY,SCLK", NULL); |
| if (val && *val) |
| rdev->clock.default_sclk = (*val) / 10; |
| else |
| rdev->clock.default_sclk = |
| radeon_legacy_get_engine_clock(rdev); |
| |
| val = of_get_property(dp, "ATY,MCLK", NULL); |
| if (val && *val) |
| rdev->clock.default_mclk = (*val) / 10; |
| else |
| rdev->clock.default_mclk = |
| radeon_legacy_get_memory_clock(rdev); |
| |
| DRM_INFO("Using device-tree clock info\n"); |
| |
| return true; |
| } |
| #else |
| static bool __devinit radeon_read_clocks_OF(struct drm_device *dev) |
| { |
| return false; |
| } |
| #endif /* CONFIG_OF */ |
| |
| void radeon_get_clock_info(struct drm_device *dev) |
| { |
| struct radeon_device *rdev = dev->dev_private; |
| struct radeon_pll *p1pll = &rdev->clock.p1pll; |
| struct radeon_pll *p2pll = &rdev->clock.p2pll; |
| struct radeon_pll *dcpll = &rdev->clock.dcpll; |
| struct radeon_pll *spll = &rdev->clock.spll; |
| struct radeon_pll *mpll = &rdev->clock.mpll; |
| int ret; |
| |
| if (rdev->is_atom_bios) |
| ret = radeon_atom_get_clock_info(dev); |
| else |
| ret = radeon_combios_get_clock_info(dev); |
| if (!ret) |
| ret = radeon_read_clocks_OF(dev); |
| |
| if (ret) { |
| if (p1pll->reference_div < 2) { |
| if (!ASIC_IS_AVIVO(rdev)) { |
| u32 tmp = RREG32_PLL(RADEON_PPLL_REF_DIV); |
| if (ASIC_IS_R300(rdev)) |
| p1pll->reference_div = |
| (tmp & R300_PPLL_REF_DIV_ACC_MASK) >> R300_PPLL_REF_DIV_ACC_SHIFT; |
| else |
| p1pll->reference_div = tmp & RADEON_PPLL_REF_DIV_MASK; |
| if (p1pll->reference_div < 2) |
| p1pll->reference_div = 12; |
| } else |
| p1pll->reference_div = 12; |
| } |
| if (p2pll->reference_div < 2) |
| p2pll->reference_div = 12; |
| if (rdev->family < CHIP_RS600) { |
| if (spll->reference_div < 2) |
| spll->reference_div = |
| RREG32_PLL(RADEON_M_SPLL_REF_FB_DIV) & |
| RADEON_M_SPLL_REF_DIV_MASK; |
| } |
| if (mpll->reference_div < 2) |
| mpll->reference_div = spll->reference_div; |
| } else { |
| if (ASIC_IS_AVIVO(rdev)) { |
| /* TODO FALLBACK */ |
| } else { |
| DRM_INFO("Using generic clock info\n"); |
| |
| if (rdev->flags & RADEON_IS_IGP) { |
| p1pll->reference_freq = 1432; |
| p2pll->reference_freq = 1432; |
| spll->reference_freq = 1432; |
| mpll->reference_freq = 1432; |
| } else { |
| p1pll->reference_freq = 2700; |
| p2pll->reference_freq = 2700; |
| spll->reference_freq = 2700; |
| mpll->reference_freq = 2700; |
| } |
| p1pll->reference_div = |
| RREG32_PLL(RADEON_PPLL_REF_DIV) & 0x3ff; |
| if (p1pll->reference_div < 2) |
| p1pll->reference_div = 12; |
| p2pll->reference_div = p1pll->reference_div; |
| |
| if (rdev->family >= CHIP_R420) { |
| p1pll->pll_in_min = 100; |
| p1pll->pll_in_max = 1350; |
| p1pll->pll_out_min = 20000; |
| p1pll->pll_out_max = 50000; |
| p2pll->pll_in_min = 100; |
| p2pll->pll_in_max = 1350; |
| p2pll->pll_out_min = 20000; |
| p2pll->pll_out_max = 50000; |
| } else { |
| p1pll->pll_in_min = 40; |
| p1pll->pll_in_max = 500; |
| p1pll->pll_out_min = 12500; |
| p1pll->pll_out_max = 35000; |
| p2pll->pll_in_min = 40; |
| p2pll->pll_in_max = 500; |
| p2pll->pll_out_min = 12500; |
| p2pll->pll_out_max = 35000; |
| } |
| |
| spll->reference_div = |
| RREG32_PLL(RADEON_M_SPLL_REF_FB_DIV) & |
| RADEON_M_SPLL_REF_DIV_MASK; |
| mpll->reference_div = spll->reference_div; |
| rdev->clock.default_sclk = |
| radeon_legacy_get_engine_clock(rdev); |
| rdev->clock.default_mclk = |
| radeon_legacy_get_memory_clock(rdev); |
| } |
| } |
| |
| /* pixel clocks */ |
| if (ASIC_IS_AVIVO(rdev)) { |
| p1pll->min_post_div = 2; |
| p1pll->max_post_div = 0x7f; |
| p1pll->min_frac_feedback_div = 0; |
| p1pll->max_frac_feedback_div = 9; |
| p2pll->min_post_div = 2; |
| p2pll->max_post_div = 0x7f; |
| p2pll->min_frac_feedback_div = 0; |
| p2pll->max_frac_feedback_div = 9; |
| } else { |
| p1pll->min_post_div = 1; |
| p1pll->max_post_div = 16; |
| p1pll->min_frac_feedback_div = 0; |
| p1pll->max_frac_feedback_div = 0; |
| p2pll->min_post_div = 1; |
| p2pll->max_post_div = 12; |
| p2pll->min_frac_feedback_div = 0; |
| p2pll->max_frac_feedback_div = 0; |
| } |
| |
| /* dcpll is DCE4 only */ |
| dcpll->min_post_div = 2; |
| dcpll->max_post_div = 0x7f; |
| dcpll->min_frac_feedback_div = 0; |
| dcpll->max_frac_feedback_div = 9; |
| dcpll->min_ref_div = 2; |
| dcpll->max_ref_div = 0x3ff; |
| dcpll->min_feedback_div = 4; |
| dcpll->max_feedback_div = 0xfff; |
| dcpll->best_vco = 0; |
| |
| p1pll->min_ref_div = 2; |
| p1pll->max_ref_div = 0x3ff; |
| p1pll->min_feedback_div = 4; |
| p1pll->max_feedback_div = 0x7ff; |
| p1pll->best_vco = 0; |
| |
| p2pll->min_ref_div = 2; |
| p2pll->max_ref_div = 0x3ff; |
| p2pll->min_feedback_div = 4; |
| p2pll->max_feedback_div = 0x7ff; |
| p2pll->best_vco = 0; |
| |
| /* system clock */ |
| spll->min_post_div = 1; |
| spll->max_post_div = 1; |
| spll->min_ref_div = 2; |
| spll->max_ref_div = 0xff; |
| spll->min_feedback_div = 4; |
| spll->max_feedback_div = 0xff; |
| spll->best_vco = 0; |
| |
| /* memory clock */ |
| mpll->min_post_div = 1; |
| mpll->max_post_div = 1; |
| mpll->min_ref_div = 2; |
| mpll->max_ref_div = 0xff; |
| mpll->min_feedback_div = 4; |
| mpll->max_feedback_div = 0xff; |
| mpll->best_vco = 0; |
| |
| } |
| |
| /* 10 khz */ |
| static uint32_t calc_eng_mem_clock(struct radeon_device *rdev, |
| uint32_t req_clock, |
| int *fb_div, int *post_div) |
| { |
| struct radeon_pll *spll = &rdev->clock.spll; |
| int ref_div = spll->reference_div; |
| |
| if (!ref_div) |
| ref_div = |
| RREG32_PLL(RADEON_M_SPLL_REF_FB_DIV) & |
| RADEON_M_SPLL_REF_DIV_MASK; |
| |
| if (req_clock < 15000) { |
| *post_div = 8; |
| req_clock *= 8; |
| } else if (req_clock < 30000) { |
| *post_div = 4; |
| req_clock *= 4; |
| } else if (req_clock < 60000) { |
| *post_div = 2; |
| req_clock *= 2; |
| } else |
| *post_div = 1; |
| |
| req_clock *= ref_div; |
| req_clock += spll->reference_freq; |
| req_clock /= (2 * spll->reference_freq); |
| |
| *fb_div = req_clock & 0xff; |
| |
| req_clock = (req_clock & 0xffff) << 1; |
| req_clock *= spll->reference_freq; |
| req_clock /= ref_div; |
| req_clock /= *post_div; |
| |
| return req_clock; |
| } |
| |
| /* 10 khz */ |
| void radeon_legacy_set_engine_clock(struct radeon_device *rdev, |
| uint32_t eng_clock) |
| { |
| uint32_t tmp; |
| int fb_div, post_div; |
| |
| /* XXX: wait for idle */ |
| |
| eng_clock = calc_eng_mem_clock(rdev, eng_clock, &fb_div, &post_div); |
| |
| tmp = RREG32_PLL(RADEON_CLK_PIN_CNTL); |
| tmp &= ~RADEON_DONT_USE_XTALIN; |
| WREG32_PLL(RADEON_CLK_PIN_CNTL, tmp); |
| |
| tmp = RREG32_PLL(RADEON_SCLK_CNTL); |
| tmp &= ~RADEON_SCLK_SRC_SEL_MASK; |
| WREG32_PLL(RADEON_SCLK_CNTL, tmp); |
| |
| udelay(10); |
| |
| tmp = RREG32_PLL(RADEON_SPLL_CNTL); |
| tmp |= RADEON_SPLL_SLEEP; |
| WREG32_PLL(RADEON_SPLL_CNTL, tmp); |
| |
| udelay(2); |
| |
| tmp = RREG32_PLL(RADEON_SPLL_CNTL); |
| tmp |= RADEON_SPLL_RESET; |
| WREG32_PLL(RADEON_SPLL_CNTL, tmp); |
| |
| udelay(200); |
| |
| tmp = RREG32_PLL(RADEON_M_SPLL_REF_FB_DIV); |
| tmp &= ~(RADEON_SPLL_FB_DIV_MASK << RADEON_SPLL_FB_DIV_SHIFT); |
| tmp |= (fb_div & RADEON_SPLL_FB_DIV_MASK) << RADEON_SPLL_FB_DIV_SHIFT; |
| WREG32_PLL(RADEON_M_SPLL_REF_FB_DIV, tmp); |
| |
| /* XXX: verify on different asics */ |
| tmp = RREG32_PLL(RADEON_SPLL_CNTL); |
| tmp &= ~RADEON_SPLL_PVG_MASK; |
| if ((eng_clock * post_div) >= 90000) |
| tmp |= (0x7 << RADEON_SPLL_PVG_SHIFT); |
| else |
| tmp |= (0x4 << RADEON_SPLL_PVG_SHIFT); |
| WREG32_PLL(RADEON_SPLL_CNTL, tmp); |
| |
| tmp = RREG32_PLL(RADEON_SPLL_CNTL); |
| tmp &= ~RADEON_SPLL_SLEEP; |
| WREG32_PLL(RADEON_SPLL_CNTL, tmp); |
| |
| udelay(2); |
| |
| tmp = RREG32_PLL(RADEON_SPLL_CNTL); |
| tmp &= ~RADEON_SPLL_RESET; |
| WREG32_PLL(RADEON_SPLL_CNTL, tmp); |
| |
| udelay(200); |
| |
| tmp = RREG32_PLL(RADEON_SCLK_CNTL); |
| tmp &= ~RADEON_SCLK_SRC_SEL_MASK; |
| switch (post_div) { |
| case 1: |
| default: |
| tmp |= 1; |
| break; |
| case 2: |
| tmp |= 2; |
| break; |
| case 4: |
| tmp |= 3; |
| break; |
| case 8: |
| tmp |= 4; |
| break; |
| } |
| WREG32_PLL(RADEON_SCLK_CNTL, tmp); |
| |
| udelay(20); |
| |
| tmp = RREG32_PLL(RADEON_CLK_PIN_CNTL); |
| tmp |= RADEON_DONT_USE_XTALIN; |
| WREG32_PLL(RADEON_CLK_PIN_CNTL, tmp); |
| |
| udelay(10); |
| } |
| |
| void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enable) |
| { |
| uint32_t tmp; |
| |
| if (enable) { |
| if (rdev->flags & RADEON_SINGLE_CRTC) { |
| tmp = RREG32_PLL(RADEON_SCLK_CNTL); |
| if ((RREG32(RADEON_CONFIG_CNTL) & |
| RADEON_CFG_ATI_REV_ID_MASK) > |
| RADEON_CFG_ATI_REV_A13) { |
| tmp &= |
| ~(RADEON_SCLK_FORCE_CP | |
| RADEON_SCLK_FORCE_RB); |
| } |
| tmp &= |
| ~(RADEON_SCLK_FORCE_HDP | RADEON_SCLK_FORCE_DISP1 | |
| RADEON_SCLK_FORCE_TOP | RADEON_SCLK_FORCE_SE | |
| RADEON_SCLK_FORCE_IDCT | RADEON_SCLK_FORCE_RE | |
| RADEON_SCLK_FORCE_PB | RADEON_SCLK_FORCE_TAM | |
| RADEON_SCLK_FORCE_TDM); |
| WREG32_PLL(RADEON_SCLK_CNTL, tmp); |
| } else if (ASIC_IS_R300(rdev)) { |
| if ((rdev->family == CHIP_RS400) || |
| (rdev->family == CHIP_RS480)) { |
| tmp = RREG32_PLL(RADEON_SCLK_CNTL); |
| tmp &= |
| ~(RADEON_SCLK_FORCE_DISP2 | |
| RADEON_SCLK_FORCE_CP | |
| RADEON_SCLK_FORCE_HDP | |
| RADEON_SCLK_FORCE_DISP1 | |
| RADEON_SCLK_FORCE_TOP | |
| RADEON_SCLK_FORCE_E2 | R300_SCLK_FORCE_VAP |
| | RADEON_SCLK_FORCE_IDCT | |
| RADEON_SCLK_FORCE_VIP | R300_SCLK_FORCE_SR |
| | R300_SCLK_FORCE_PX | R300_SCLK_FORCE_TX |
| | R300_SCLK_FORCE_US | |
| RADEON_SCLK_FORCE_TV_SCLK | |
| R300_SCLK_FORCE_SU | |
| RADEON_SCLK_FORCE_OV0); |
| tmp |= RADEON_DYN_STOP_LAT_MASK; |
| tmp |= |
| RADEON_SCLK_FORCE_TOP | |
| RADEON_SCLK_FORCE_VIP; |
| WREG32_PLL(RADEON_SCLK_CNTL, tmp); |
| |
| tmp = RREG32_PLL(RADEON_SCLK_MORE_CNTL); |
| tmp &= ~RADEON_SCLK_MORE_FORCEON; |
| tmp |= RADEON_SCLK_MORE_MAX_DYN_STOP_LAT; |
| WREG32_PLL(RADEON_SCLK_MORE_CNTL, tmp); |
| |
| tmp = RREG32_PLL(RADEON_VCLK_ECP_CNTL); |
| tmp |= (RADEON_PIXCLK_ALWAYS_ONb | |
| RADEON_PIXCLK_DAC_ALWAYS_ONb); |
| WREG32_PLL(RADEON_VCLK_ECP_CNTL, tmp); |
| |
| tmp = RREG32_PLL(RADEON_PIXCLKS_CNTL); |
| tmp |= (RADEON_PIX2CLK_ALWAYS_ONb | |
| RADEON_PIX2CLK_DAC_ALWAYS_ONb | |
| RADEON_DISP_TVOUT_PIXCLK_TV_ALWAYS_ONb | |
| R300_DVOCLK_ALWAYS_ONb | |
| RADEON_PIXCLK_BLEND_ALWAYS_ONb | |
| RADEON_PIXCLK_GV_ALWAYS_ONb | |
| R300_PIXCLK_DVO_ALWAYS_ONb | |
| RADEON_PIXCLK_LVDS_ALWAYS_ONb | |
| RADEON_PIXCLK_TMDS_ALWAYS_ONb | |
| R300_PIXCLK_TRANS_ALWAYS_ONb | |
| R300_PIXCLK_TVO_ALWAYS_ONb | |
| R300_P2G2CLK_ALWAYS_ONb | |
| R300_P2G2CLK_DAC_ALWAYS_ONb); |
| WREG32_PLL(RADEON_PIXCLKS_CNTL, tmp); |
| } else if (rdev->family >= CHIP_RV350) { |
| tmp = RREG32_PLL(R300_SCLK_CNTL2); |
| tmp &= ~(R300_SCLK_FORCE_TCL | |
| R300_SCLK_FORCE_GA | |
| R300_SCLK_FORCE_CBA); |
| tmp |= (R300_SCLK_TCL_MAX_DYN_STOP_LAT | |
| R300_SCLK_GA_MAX_DYN_STOP_LAT | |
| R300_SCLK_CBA_MAX_DYN_STOP_LAT); |
| WREG32_PLL(R300_SCLK_CNTL2, tmp); |
| |
| tmp = RREG32_PLL(RADEON_SCLK_CNTL); |
| tmp &= |
| ~(RADEON_SCLK_FORCE_DISP2 | |
| RADEON_SCLK_FORCE_CP | |
| RADEON_SCLK_FORCE_HDP | |
| RADEON_SCLK_FORCE_DISP1 | |
| RADEON_SCLK_FORCE_TOP | |
| RADEON_SCLK_FORCE_E2 | R300_SCLK_FORCE_VAP |
| | RADEON_SCLK_FORCE_IDCT | |
| RADEON_SCLK_FORCE_VIP | R300_SCLK_FORCE_SR |
| | R300_SCLK_FORCE_PX | R300_SCLK_FORCE_TX |
| | R300_SCLK_FORCE_US | |
| RADEON_SCLK_FORCE_TV_SCLK | |
| R300_SCLK_FORCE_SU | |
| RADEON_SCLK_FORCE_OV0); |
| tmp |= RADEON_DYN_STOP_LAT_MASK; |
| WREG32_PLL(RADEON_SCLK_CNTL, tmp); |
| |
| tmp = RREG32_PLL(RADEON_SCLK_MORE_CNTL); |
| tmp &= ~RADEON_SCLK_MORE_FORCEON; |
| tmp |= RADEON_SCLK_MORE_MAX_DYN_STOP_LAT; |
| WREG32_PLL(RADEON_SCLK_MORE_CNTL, tmp); |
| |
| tmp = RREG32_PLL(RADEON_VCLK_ECP_CNTL); |
| tmp |= (RADEON_PIXCLK_ALWAYS_ONb | |
| RADEON_PIXCLK_DAC_ALWAYS_ONb); |
| WREG32_PLL(RADEON_VCLK_ECP_CNTL, tmp); |
| |
| tmp = RREG32_PLL(RADEON_PIXCLKS_CNTL); |
| tmp |= (RADEON_PIX2CLK_ALWAYS_ONb | |
| RADEON_PIX2CLK_DAC_ALWAYS_ONb | |
| RADEON_DISP_TVOUT_PIXCLK_TV_ALWAYS_ONb | |
| R300_DVOCLK_ALWAYS_ONb | |
| RADEON_PIXCLK_BLEND_ALWAYS_ONb | |
| RADEON_PIXCLK_GV_ALWAYS_ONb | |
| R300_PIXCLK_DVO_ALWAYS_ONb | |
| RADEON_PIXCLK_LVDS_ALWAYS_ONb | |
| RADEON_PIXCLK_TMDS_ALWAYS_ONb | |
| R300_PIXCLK_TRANS_ALWAYS_ONb | |
| R300_PIXCLK_TVO_ALWAYS_ONb | |
| R300_P2G2CLK_ALWAYS_ONb | |
| R300_P2G2CLK_DAC_ALWAYS_ONb); |
| WREG32_PLL(RADEON_PIXCLKS_CNTL, tmp); |
| |
| tmp = RREG32_PLL(RADEON_MCLK_MISC); |
| tmp |= (RADEON_MC_MCLK_DYN_ENABLE | |
| RADEON_IO_MCLK_DYN_ENABLE); |
| WREG32_PLL(RADEON_MCLK_MISC, tmp); |
| |
| tmp = RREG32_PLL(RADEON_MCLK_CNTL); |
| tmp |= (RADEON_FORCEON_MCLKA | |
| RADEON_FORCEON_MCLKB); |
| |
| tmp &= ~(RADEON_FORCEON_YCLKA | |
| RADEON_FORCEON_YCLKB | |
| RADEON_FORCEON_MC); |
| |
| /* Some releases of vbios have set DISABLE_MC_MCLKA |
| and DISABLE_MC_MCLKB bits in the vbios table. Setting these |
| bits will cause H/W hang when reading video memory with dynamic clocking |
| enabled. */ |
| if ((tmp & R300_DISABLE_MC_MCLKA) && |
| (tmp & R300_DISABLE_MC_MCLKB)) { |
| /* If both bits are set, then check the active channels */ |
| tmp = RREG32_PLL(RADEON_MCLK_CNTL); |
| if (rdev->mc.vram_width == 64) { |
| if (RREG32(RADEON_MEM_CNTL) & |
| R300_MEM_USE_CD_CH_ONLY) |
| tmp &= |
| ~R300_DISABLE_MC_MCLKB; |
| else |
| tmp &= |
| ~R300_DISABLE_MC_MCLKA; |
| } else { |
| tmp &= ~(R300_DISABLE_MC_MCLKA | |
| R300_DISABLE_MC_MCLKB); |
| } |
| } |
| |
| WREG32_PLL(RADEON_MCLK_CNTL, tmp); |
| } else { |
| tmp = RREG32_PLL(RADEON_SCLK_CNTL); |
| tmp &= ~(R300_SCLK_FORCE_VAP); |
| tmp |= RADEON_SCLK_FORCE_CP; |
| WREG32_PLL(RADEON_SCLK_CNTL, tmp); |
| udelay(15000); |
| |
| tmp = RREG32_PLL(R300_SCLK_CNTL2); |
| tmp &= ~(R300_SCLK_FORCE_TCL | |
| R300_SCLK_FORCE_GA | |
| R300_SCLK_FORCE_CBA); |
| WREG32_PLL(R300_SCLK_CNTL2, tmp); |
| } |
| } else { |
| tmp = RREG32_PLL(RADEON_CLK_PWRMGT_CNTL); |
| |
| tmp &= ~(RADEON_ACTIVE_HILO_LAT_MASK | |
| RADEON_DISP_DYN_STOP_LAT_MASK | |
| RADEON_DYN_STOP_MODE_MASK); |
| |
| tmp |= (RADEON_ENGIN_DYNCLK_MODE | |
| (0x01 << RADEON_ACTIVE_HILO_LAT_SHIFT)); |
| WREG32_PLL(RADEON_CLK_PWRMGT_CNTL, tmp); |
| udelay(15000); |
| |
| tmp = RREG32_PLL(RADEON_CLK_PIN_CNTL); |
| tmp |= RADEON_SCLK_DYN_START_CNTL; |
| WREG32_PLL(RADEON_CLK_PIN_CNTL, tmp); |
| udelay(15000); |
| |
| /* When DRI is enabled, setting DYN_STOP_LAT to zero can cause some R200 |
| to lockup randomly, leave them as set by BIOS. |
| */ |
| tmp = RREG32_PLL(RADEON_SCLK_CNTL); |
| /*tmp &= RADEON_SCLK_SRC_SEL_MASK; */ |
| tmp &= ~RADEON_SCLK_FORCEON_MASK; |
| |
| /*RAGE_6::A11 A12 A12N1 A13, RV250::A11 A12, R300 */ |
| if (((rdev->family == CHIP_RV250) && |
| ((RREG32(RADEON_CONFIG_CNTL) & |
| RADEON_CFG_ATI_REV_ID_MASK) < |
| RADEON_CFG_ATI_REV_A13)) |
| || ((rdev->family == CHIP_RV100) |
| && |
| ((RREG32(RADEON_CONFIG_CNTL) & |
| RADEON_CFG_ATI_REV_ID_MASK) <= |
| RADEON_CFG_ATI_REV_A13))) { |
| tmp |= RADEON_SCLK_FORCE_CP; |
| tmp |= RADEON_SCLK_FORCE_VIP; |
| } |
| |
| WREG32_PLL(RADEON_SCLK_CNTL, tmp); |
| |
| if ((rdev->family == CHIP_RV200) || |
| (rdev->family == CHIP_RV250) || |
| (rdev->family == CHIP_RV280)) { |
| tmp = RREG32_PLL(RADEON_SCLK_MORE_CNTL); |
| tmp &= ~RADEON_SCLK_MORE_FORCEON; |
| |
| /* RV200::A11 A12 RV250::A11 A12 */ |
| if (((rdev->family == CHIP_RV200) || |
| (rdev->family == CHIP_RV250)) && |
| ((RREG32(RADEON_CONFIG_CNTL) & |
| RADEON_CFG_ATI_REV_ID_MASK) < |
| RADEON_CFG_ATI_REV_A13)) { |
| tmp |= RADEON_SCLK_MORE_FORCEON; |
| } |
| WREG32_PLL(RADEON_SCLK_MORE_CNTL, tmp); |
| udelay(15000); |
| } |
| |
| /* RV200::A11 A12, RV250::A11 A12 */ |
| if (((rdev->family == CHIP_RV200) || |
| (rdev->family == CHIP_RV250)) && |
| ((RREG32(RADEON_CONFIG_CNTL) & |
| RADEON_CFG_ATI_REV_ID_MASK) < |
| RADEON_CFG_ATI_REV_A13)) { |
| tmp = RREG32_PLL(RADEON_PLL_PWRMGT_CNTL); |
| tmp |= RADEON_TCL_BYPASS_DISABLE; |
| WREG32_PLL(RADEON_PLL_PWRMGT_CNTL, tmp); |
| } |
| udelay(15000); |
| |
| /*enable dynamic mode for display clocks (PIXCLK and PIX2CLK) */ |
| tmp = RREG32_PLL(RADEON_PIXCLKS_CNTL); |
| tmp |= (RADEON_PIX2CLK_ALWAYS_ONb | |
| RADEON_PIX2CLK_DAC_ALWAYS_ONb | |
| RADEON_PIXCLK_BLEND_ALWAYS_ONb | |
| RADEON_PIXCLK_GV_ALWAYS_ONb | |
| RADEON_PIXCLK_DIG_TMDS_ALWAYS_ONb | |
| RADEON_PIXCLK_LVDS_ALWAYS_ONb | |
| RADEON_PIXCLK_TMDS_ALWAYS_ONb); |
| |
| WREG32_PLL(RADEON_PIXCLKS_CNTL, tmp); |
| udelay(15000); |
| |
| tmp = RREG32_PLL(RADEON_VCLK_ECP_CNTL); |
| tmp |= (RADEON_PIXCLK_ALWAYS_ONb | |
| RADEON_PIXCLK_DAC_ALWAYS_ONb); |
| |
| WREG32_PLL(RADEON_VCLK_ECP_CNTL, tmp); |
| udelay(15000); |
| } |
| } else { |
| /* Turn everything OFF (ForceON to everything) */ |
| if (rdev->flags & RADEON_SINGLE_CRTC) { |
| tmp = RREG32_PLL(RADEON_SCLK_CNTL); |
| tmp |= (RADEON_SCLK_FORCE_CP | RADEON_SCLK_FORCE_HDP | |
| RADEON_SCLK_FORCE_DISP1 | RADEON_SCLK_FORCE_TOP |
| | RADEON_SCLK_FORCE_E2 | RADEON_SCLK_FORCE_SE | |
| RADEON_SCLK_FORCE_IDCT | RADEON_SCLK_FORCE_VIP | |
| RADEON_SCLK_FORCE_RE | RADEON_SCLK_FORCE_PB | |
| RADEON_SCLK_FORCE_TAM | RADEON_SCLK_FORCE_TDM | |
| RADEON_SCLK_FORCE_RB); |
| WREG32_PLL(RADEON_SCLK_CNTL, tmp); |
| } else if ((rdev->family == CHIP_RS400) || |
| (rdev->family == CHIP_RS480)) { |
| tmp = RREG32_PLL(RADEON_SCLK_CNTL); |
| tmp |= (RADEON_SCLK_FORCE_DISP2 | RADEON_SCLK_FORCE_CP | |
| RADEON_SCLK_FORCE_HDP | RADEON_SCLK_FORCE_DISP1 |
| | RADEON_SCLK_FORCE_TOP | RADEON_SCLK_FORCE_E2 | |
| R300_SCLK_FORCE_VAP | RADEON_SCLK_FORCE_IDCT | |
| RADEON_SCLK_FORCE_VIP | R300_SCLK_FORCE_SR | |
| R300_SCLK_FORCE_PX | R300_SCLK_FORCE_TX | |
| R300_SCLK_FORCE_US | RADEON_SCLK_FORCE_TV_SCLK | |
| R300_SCLK_FORCE_SU | RADEON_SCLK_FORCE_OV0); |
| WREG32_PLL(RADEON_SCLK_CNTL, tmp); |
| |
| tmp = RREG32_PLL(RADEON_SCLK_MORE_CNTL); |
| tmp |= RADEON_SCLK_MORE_FORCEON; |
| WREG32_PLL(RADEON_SCLK_MORE_CNTL, tmp); |
| |
| tmp = RREG32_PLL(RADEON_VCLK_ECP_CNTL); |
| tmp &= ~(RADEON_PIXCLK_ALWAYS_ONb | |
| RADEON_PIXCLK_DAC_ALWAYS_ONb | |
| R300_DISP_DAC_PIXCLK_DAC_BLANK_OFF); |
| WREG32_PLL(RADEON_VCLK_ECP_CNTL, tmp); |
| |
| tmp = RREG32_PLL(RADEON_PIXCLKS_CNTL); |
| tmp &= ~(RADEON_PIX2CLK_ALWAYS_ONb | |
| RADEON_PIX2CLK_DAC_ALWAYS_ONb | |
| RADEON_DISP_TVOUT_PIXCLK_TV_ALWAYS_ONb | |
| R300_DVOCLK_ALWAYS_ONb | |
| RADEON_PIXCLK_BLEND_ALWAYS_ONb | |
| RADEON_PIXCLK_GV_ALWAYS_ONb | |
| R300_PIXCLK_DVO_ALWAYS_ONb | |
| RADEON_PIXCLK_LVDS_ALWAYS_ONb | |
| RADEON_PIXCLK_TMDS_ALWAYS_ONb | |
| R300_PIXCLK_TRANS_ALWAYS_ONb | |
| R300_PIXCLK_TVO_ALWAYS_ONb | |
| R300_P2G2CLK_ALWAYS_ONb | |
| R300_P2G2CLK_DAC_ALWAYS_ONb | |
| R300_DISP_DAC_PIXCLK_DAC2_BLANK_OFF); |
| WREG32_PLL(RADEON_PIXCLKS_CNTL, tmp); |
| } else if (rdev->family >= CHIP_RV350) { |
| /* for RV350/M10, no delays are required. */ |
| tmp = RREG32_PLL(R300_SCLK_CNTL2); |
| tmp |= (R300_SCLK_FORCE_TCL | |
| R300_SCLK_FORCE_GA | R300_SCLK_FORCE_CBA); |
| WREG32_PLL(R300_SCLK_CNTL2, tmp); |
| |
| tmp = RREG32_PLL(RADEON_SCLK_CNTL); |
| tmp |= (RADEON_SCLK_FORCE_DISP2 | RADEON_SCLK_FORCE_CP | |
| RADEON_SCLK_FORCE_HDP | RADEON_SCLK_FORCE_DISP1 |
| | RADEON_SCLK_FORCE_TOP | RADEON_SCLK_FORCE_E2 | |
| R300_SCLK_FORCE_VAP | RADEON_SCLK_FORCE_IDCT | |
| RADEON_SCLK_FORCE_VIP | R300_SCLK_FORCE_SR | |
| R300_SCLK_FORCE_PX | R300_SCLK_FORCE_TX | |
| R300_SCLK_FORCE_US | RADEON_SCLK_FORCE_TV_SCLK | |
| R300_SCLK_FORCE_SU | RADEON_SCLK_FORCE_OV0); |
| WREG32_PLL(RADEON_SCLK_CNTL, tmp); |
| |
| tmp = RREG32_PLL(RADEON_SCLK_MORE_CNTL); |
| tmp |= RADEON_SCLK_MORE_FORCEON; |
| WREG32_PLL(RADEON_SCLK_MORE_CNTL, tmp); |
| |
| tmp = RREG32_PLL(RADEON_MCLK_CNTL); |
| tmp |= (RADEON_FORCEON_MCLKA | |
| RADEON_FORCEON_MCLKB | |
| RADEON_FORCEON_YCLKA | |
| RADEON_FORCEON_YCLKB | RADEON_FORCEON_MC); |
| WREG32_PLL(RADEON_MCLK_CNTL, tmp); |
| |
| tmp = RREG32_PLL(RADEON_VCLK_ECP_CNTL); |
| tmp &= ~(RADEON_PIXCLK_ALWAYS_ONb | |
| RADEON_PIXCLK_DAC_ALWAYS_ONb | |
| R300_DISP_DAC_PIXCLK_DAC_BLANK_OFF); |
| WREG32_PLL(RADEON_VCLK_ECP_CNTL, tmp); |
| |
| tmp = RREG32_PLL(RADEON_PIXCLKS_CNTL); |
| tmp &= ~(RADEON_PIX2CLK_ALWAYS_ONb | |
| RADEON_PIX2CLK_DAC_ALWAYS_ONb | |
| RADEON_DISP_TVOUT_PIXCLK_TV_ALWAYS_ONb | |
| R300_DVOCLK_ALWAYS_ONb | |
| RADEON_PIXCLK_BLEND_ALWAYS_ONb | |
| RADEON_PIXCLK_GV_ALWAYS_ONb | |
| R300_PIXCLK_DVO_ALWAYS_ONb | |
| RADEON_PIXCLK_LVDS_ALWAYS_ONb | |
| RADEON_PIXCLK_TMDS_ALWAYS_ONb | |
| R300_PIXCLK_TRANS_ALWAYS_ONb | |
| R300_PIXCLK_TVO_ALWAYS_ONb | |
| R300_P2G2CLK_ALWAYS_ONb | |
| R300_P2G2CLK_DAC_ALWAYS_ONb | |
| R300_DISP_DAC_PIXCLK_DAC2_BLANK_OFF); |
| WREG32_PLL(RADEON_PIXCLKS_CNTL, tmp); |
| } else { |
| tmp = RREG32_PLL(RADEON_SCLK_CNTL); |
| tmp |= (RADEON_SCLK_FORCE_CP | RADEON_SCLK_FORCE_E2); |
| tmp |= RADEON_SCLK_FORCE_SE; |
| |
| if (rdev->flags & RADEON_SINGLE_CRTC) { |
| tmp |= (RADEON_SCLK_FORCE_RB | |
| RADEON_SCLK_FORCE_TDM | |
| RADEON_SCLK_FORCE_TAM | |
| RADEON_SCLK_FORCE_PB | |
| RADEON_SCLK_FORCE_RE | |
| RADEON_SCLK_FORCE_VIP | |
| RADEON_SCLK_FORCE_IDCT | |
| RADEON_SCLK_FORCE_TOP | |
| RADEON_SCLK_FORCE_DISP1 | |
| RADEON_SCLK_FORCE_DISP2 | |
| RADEON_SCLK_FORCE_HDP); |
| } else if ((rdev->family == CHIP_R300) || |
| (rdev->family == CHIP_R350)) { |
| tmp |= (RADEON_SCLK_FORCE_HDP | |
| RADEON_SCLK_FORCE_DISP1 | |
| RADEON_SCLK_FORCE_DISP2 | |
| RADEON_SCLK_FORCE_TOP | |
| RADEON_SCLK_FORCE_IDCT | |
| RADEON_SCLK_FORCE_VIP); |
| } |
| WREG32_PLL(RADEON_SCLK_CNTL, tmp); |
| |
| udelay(16000); |
| |
| if ((rdev->family == CHIP_R300) || |
| (rdev->family == CHIP_R350)) { |
| tmp = RREG32_PLL(R300_SCLK_CNTL2); |
| tmp |= (R300_SCLK_FORCE_TCL | |
| R300_SCLK_FORCE_GA | |
| R300_SCLK_FORCE_CBA); |
| WREG32_PLL(R300_SCLK_CNTL2, tmp); |
| udelay(16000); |
| } |
| |
| if (rdev->flags & RADEON_IS_IGP) { |
| tmp = RREG32_PLL(RADEON_MCLK_CNTL); |
| tmp &= ~(RADEON_FORCEON_MCLKA | |
| RADEON_FORCEON_YCLKA); |
| WREG32_PLL(RADEON_MCLK_CNTL, tmp); |
| udelay(16000); |
| } |
| |
| if ((rdev->family == CHIP_RV200) || |
| (rdev->family == CHIP_RV250) || |
| (rdev->family == CHIP_RV280)) { |
| tmp = RREG32_PLL(RADEON_SCLK_MORE_CNTL); |
| tmp |= RADEON_SCLK_MORE_FORCEON; |
| WREG32_PLL(RADEON_SCLK_MORE_CNTL, tmp); |
| udelay(16000); |
| } |
| |
| tmp = RREG32_PLL(RADEON_PIXCLKS_CNTL); |
| tmp &= ~(RADEON_PIX2CLK_ALWAYS_ONb | |
| RADEON_PIX2CLK_DAC_ALWAYS_ONb | |
| RADEON_PIXCLK_BLEND_ALWAYS_ONb | |
| RADEON_PIXCLK_GV_ALWAYS_ONb | |
| RADEON_PIXCLK_DIG_TMDS_ALWAYS_ONb | |
| RADEON_PIXCLK_LVDS_ALWAYS_ONb | |
| RADEON_PIXCLK_TMDS_ALWAYS_ONb); |
| |
| WREG32_PLL(RADEON_PIXCLKS_CNTL, tmp); |
| udelay(16000); |
| |
| tmp = RREG32_PLL(RADEON_VCLK_ECP_CNTL); |
| tmp &= ~(RADEON_PIXCLK_ALWAYS_ONb | |
| RADEON_PIXCLK_DAC_ALWAYS_ONb); |
| WREG32_PLL(RADEON_VCLK_ECP_CNTL, tmp); |
| } |
| } |
| } |
| |
| static void radeon_apply_clock_quirks(struct radeon_device *rdev) |
| { |
| uint32_t tmp; |
| |
| /* XXX make sure engine is idle */ |
| |
| if (rdev->family < CHIP_RS600) { |
| tmp = RREG32_PLL(RADEON_SCLK_CNTL); |
| if (ASIC_IS_R300(rdev) || ASIC_IS_RV100(rdev)) |
| tmp |= RADEON_SCLK_FORCE_CP | RADEON_SCLK_FORCE_VIP; |
| if ((rdev->family == CHIP_RV250) |
| || (rdev->family == CHIP_RV280)) |
| tmp |= |
| RADEON_SCLK_FORCE_DISP1 | RADEON_SCLK_FORCE_DISP2; |
| if ((rdev->family == CHIP_RV350) |
| || (rdev->family == CHIP_RV380)) |
| tmp |= R300_SCLK_FORCE_VAP; |
| if (rdev->family == CHIP_R420) |
| tmp |= R300_SCLK_FORCE_PX | R300_SCLK_FORCE_TX; |
| WREG32_PLL(RADEON_SCLK_CNTL, tmp); |
| } else if (rdev->family < CHIP_R600) { |
| tmp = RREG32_PLL(AVIVO_CP_DYN_CNTL); |
| tmp |= AVIVO_CP_FORCEON; |
| WREG32_PLL(AVIVO_CP_DYN_CNTL, tmp); |
| |
| tmp = RREG32_PLL(AVIVO_E2_DYN_CNTL); |
| tmp |= AVIVO_E2_FORCEON; |
| WREG32_PLL(AVIVO_E2_DYN_CNTL, tmp); |
| |
| tmp = RREG32_PLL(AVIVO_IDCT_DYN_CNTL); |
| tmp |= AVIVO_IDCT_FORCEON; |
| WREG32_PLL(AVIVO_IDCT_DYN_CNTL, tmp); |
| } |
| } |
| |
| int radeon_static_clocks_init(struct drm_device *dev) |
| { |
| struct radeon_device *rdev = dev->dev_private; |
| |
| /* XXX make sure engine is idle */ |
| |
| if (radeon_dynclks != -1) { |
| if (radeon_dynclks) { |
| if (rdev->asic->set_clock_gating) |
| radeon_set_clock_gating(rdev, 1); |
| } |
| } |
| radeon_apply_clock_quirks(rdev); |
| return 0; |
| } |