/* * 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; if (!rdev->clock.default_sclk) rdev->clock.default_sclk = radeon_get_engine_clock(rdev); if ((!rdev->clock.default_mclk) && rdev->asic->get_memory_clock) rdev->clock.default_mclk = radeon_get_memory_clock(rdev); rdev->pm.current_sclk = rdev->clock.default_sclk; rdev->pm.current_mclk = rdev->clock.default_mclk; } /* 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; }