drm/radeon: add set_uvd_clocks callback for r6xx v4

v2: wake up PLL, set [VD]CLK_SRC, cleanup code
v3: handle RV670,RV635,RV620 as well
v4: merge rv6xx and rs780/rs880 code, fix ref divider mask

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Christian König <christian.koenig@amd.com>
This commit is contained in:
Alex Deucher 2012-11-28 16:55:21 -05:00
parent a8fba64ab0
commit 4a956a70a8
2 changed files with 114 additions and 0 deletions

View file

@ -122,6 +122,94 @@ u32 r600_get_xclk(struct radeon_device *rdev)
int r600_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk)
{
unsigned fb_div = 0, ref_div, vclk_div = 0, dclk_div = 0;
int r;
/* bypass vclk and dclk with bclk */
WREG32_P(CG_UPLL_FUNC_CNTL_2,
VCLK_SRC_SEL(1) | DCLK_SRC_SEL(1),
~(VCLK_SRC_SEL_MASK | DCLK_SRC_SEL_MASK));
/* assert BYPASS_EN, deassert UPLL_RESET, UPLL_SLEEP and UPLL_CTLREQ */
WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_BYPASS_EN_MASK, ~(
UPLL_RESET_MASK | UPLL_SLEEP_MASK | UPLL_CTLREQ_MASK));
if (rdev->family >= CHIP_RS780)
WREG32_P(GFX_MACRO_BYPASS_CNTL, UPLL_BYPASS_CNTL,
~UPLL_BYPASS_CNTL);
if (!vclk || !dclk) {
/* keep the Bypass mode, put PLL to sleep */
WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_SLEEP_MASK, ~UPLL_SLEEP_MASK);
return 0;
}
if (rdev->clock.spll.reference_freq == 10000)
ref_div = 34;
else
ref_div = 4;
r = radeon_uvd_calc_upll_dividers(rdev, vclk, dclk, 50000, 160000,
ref_div + 1, 0xFFF, 2, 30, ~0,
&fb_div, &vclk_div, &dclk_div);
if (r)
return r;
if (rdev->family >= CHIP_RV670 && rdev->family < CHIP_RS780)
fb_div >>= 1;
else
fb_div |= 1;
r = radeon_uvd_send_upll_ctlreq(rdev, CG_UPLL_FUNC_CNTL);
if (r)
return r;
/* assert PLL_RESET */
WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_RESET_MASK, ~UPLL_RESET_MASK);
/* For RS780 we have to choose ref clk */
if (rdev->family >= CHIP_RS780)
WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_REFCLK_SRC_SEL_MASK,
~UPLL_REFCLK_SRC_SEL_MASK);
/* set the required fb, ref and post divder values */
WREG32_P(CG_UPLL_FUNC_CNTL,
UPLL_FB_DIV(fb_div) |
UPLL_REF_DIV(ref_div),
~(UPLL_FB_DIV_MASK | UPLL_REF_DIV_MASK));
WREG32_P(CG_UPLL_FUNC_CNTL_2,
UPLL_SW_HILEN(vclk_div >> 1) |
UPLL_SW_LOLEN((vclk_div >> 1) + (vclk_div & 1)) |
UPLL_SW_HILEN2(dclk_div >> 1) |
UPLL_SW_LOLEN2((dclk_div >> 1) + (dclk_div & 1)) |
UPLL_DIVEN_MASK | UPLL_DIVEN2_MASK,
~UPLL_SW_MASK);
/* give the PLL some time to settle */
mdelay(15);
/* deassert PLL_RESET */
WREG32_P(CG_UPLL_FUNC_CNTL, 0, ~UPLL_RESET_MASK);
mdelay(15);
/* deassert BYPASS EN */
WREG32_P(CG_UPLL_FUNC_CNTL, 0, ~UPLL_BYPASS_EN_MASK);
if (rdev->family >= CHIP_RS780)
WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~UPLL_BYPASS_CNTL);
r = radeon_uvd_send_upll_ctlreq(rdev, CG_UPLL_FUNC_CNTL);
if (r)
return r;
/* switch VCLK and DCLK selection */
WREG32_P(CG_UPLL_FUNC_CNTL_2,
VCLK_SRC_SEL(2) | DCLK_SRC_SEL(2),
~(VCLK_SRC_SEL_MASK | DCLK_SRC_SEL_MASK));
mdelay(100);
return 0;
}