freebsd-dev/sys/dev/drm2/radeon/radeon_clocks.c
Jean-Sébastien Pédron 455fa6518a drm: Update the device-independent code to match Linux 3.8.13
This update brings few features:
    o  Support for the setmaster/dropmaster ioctls. For instance, they
       are used to run multiple X servers simultaneously.
    o  Support for minor devices. The only user-visible change is a new
       entry in /dev/dri but it is useless at the moment. This is a
       first step to support render nodes [1].

The main benefit is to greatly reduce the diff with Linux (at the
expense of an unreadable commit diff). Hopefully, next upgrades will be
easier.

No updates were made to the drivers, beside adapting them to API
changes.

[1] https://en.wikipedia.org/wiki/Direct_Rendering_Manager#Render_nodes

Tested by:	Many people
MFC after:	1 month
Relnotes:	yes
2015-03-17 18:50:33 +00:00

918 lines
26 KiB
C

/*
* 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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <dev/drm2/drmP.h>
#include <dev/drm2/radeon/radeon_drm.h>
#include "radeon_reg.h"
#include "radeon.h"
#include "radeon_asic.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 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;
}
/* not sure what the max should be in all cases */
rdev->clock.max_pixel_clock = 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 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");
/* may need to be per card */
rdev->clock.max_pixel_clock = 35000;
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->pm.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);
mdelay(15);
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);
mdelay(15);
tmp = RREG32_PLL(RADEON_CLK_PIN_CNTL);
tmp |= RADEON_SCLK_DYN_START_CNTL;
WREG32_PLL(RADEON_CLK_PIN_CNTL, tmp);
mdelay(15);
/* 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);
mdelay(15);
}
/* 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);
}
mdelay(15);
/*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);
mdelay(15);
tmp = RREG32_PLL(RADEON_VCLK_ECP_CNTL);
tmp |= (RADEON_PIXCLK_ALWAYS_ONb |
RADEON_PIXCLK_DAC_ALWAYS_ONb);
WREG32_PLL(RADEON_VCLK_ECP_CNTL, tmp);
mdelay(15);
}
} 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);
mdelay(16);
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);
mdelay(16);
}
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);
mdelay(16);
}
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);
mdelay(16);
}
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);
mdelay(16);
tmp = RREG32_PLL(RADEON_VCLK_ECP_CNTL);
tmp &= ~(RADEON_PIXCLK_ALWAYS_ONb |
RADEON_PIXCLK_DAC_ALWAYS_ONb);
WREG32_PLL(RADEON_VCLK_ECP_CNTL, tmp);
}
}
}