From: Christian K?nig <christian.koe...@amd.com>

Just power down the PLL when we get a VCLK or DCLK of zero.
Enabling the bypass mode early should also allow us to
switch UVD clocks on the fly.

Signed-off-by: Christian K?nig <christian.koenig at amd.com>
---
 drivers/gpu/drm/radeon/evergreen.c |   22 ++++++++++++++--------
 drivers/gpu/drm/radeon/rv770.c     |   20 +++++++++++++-------
 drivers/gpu/drm/radeon/si.c        |   22 ++++++++++++++--------
 3 files changed, 41 insertions(+), 23 deletions(-)

diff --git a/drivers/gpu/drm/radeon/evergreen.c 
b/drivers/gpu/drm/radeon/evergreen.c
index 124c193..facfa84 100644
--- a/drivers/gpu/drm/radeon/evergreen.c
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -189,6 +189,20 @@ int evergreen_set_uvd_clocks(struct radeon_device *rdev, 
u32 vclk, u32 dclk)
        unsigned vco_freq;
        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));
+
+       /* put PLL in bypass mode */
+       WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_BYPASS_EN_MASK, ~UPLL_BYPASS_EN_MASK);
+
+       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;
+       }
+
        /* loop through vco from low to high */
        for (vco_freq = 125000; vco_freq <= 250000; vco_freq += 100) {
                unsigned fb_div = vco_freq / rdev->clock.spll.reference_freq * 
16384;
@@ -236,14 +250,6 @@ int evergreen_set_uvd_clocks(struct radeon_device *rdev, 
u32 vclk, u32 dclk)

        mdelay(1);

-       /* 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));
-
-       /* put PLL in bypass mode */
-       WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_BYPASS_EN_MASK, ~UPLL_BYPASS_EN_MASK);
-
        r = evergreen_uvd_send_upll_ctlreq(rdev);
        if (r)
                return r;
diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c
index 777f537..59065ba 100644
--- a/drivers/gpu/drm/radeon/rv770.c
+++ b/drivers/gpu/drm/radeon/rv770.c
@@ -100,6 +100,17 @@ int rv770_set_uvd_clocks(struct radeon_device *rdev, u32 
vclk, u32 dclk)
        if (rdev->family == CHIP_RV740)
                return evergreen_set_uvd_clocks(rdev, vclk, dclk);

+       /* 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));
+
+       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;
+       }
+
        /* loop through vco from low to high */
        vco_min = max(max(vco_min, vclk), dclk);
        for (vco_freq = vco_min; vco_freq <= vco_max; vco_freq += 500) {
@@ -139,16 +150,11 @@ int rv770_set_uvd_clocks(struct radeon_device *rdev, u32 
vclk, u32 dclk)
                }
        }

-       /* 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));
-
        /* set UPLL_FB_DIV to 0x50000 */
        WREG32_P(CG_UPLL_FUNC_CNTL_3, UPLL_FB_DIV(0x50000), ~UPLL_FB_DIV_MASK);

-       /* deassert UPLL_RESET */
-       WREG32_P(CG_UPLL_FUNC_CNTL, 0, ~UPLL_RESET_MASK);
+       /* deassert UPLL_RESET and UPLL_SLEEP */
+       WREG32_P(CG_UPLL_FUNC_CNTL, 0, ~(UPLL_RESET_MASK | UPLL_SLEEP_MASK));

        /* assert BYPASS EN and FB_DIV[0] <- ??? why? */
        WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_BYPASS_EN_MASK, ~UPLL_BYPASS_EN_MASK);
diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c
index aa2c555..b7d78f2 100644
--- a/drivers/gpu/drm/radeon/si.c
+++ b/drivers/gpu/drm/radeon/si.c
@@ -4680,6 +4680,20 @@ int si_set_uvd_clocks(struct radeon_device *rdev, u32 
vclk, u32 dclk)
        unsigned vco_freq;
        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));
+
+       /* put PLL in bypass mode */
+       WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_BYPASS_EN_MASK, ~UPLL_BYPASS_EN_MASK);
+
+       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;
+       }
+
        /* loop through vco from low to high */
        for (vco_freq = 125000; vco_freq <= 250000; vco_freq += 100) {
                unsigned fb_div = vco_freq / rdev->clock.spll.reference_freq * 
16384;
@@ -4730,14 +4744,6 @@ int si_set_uvd_clocks(struct radeon_device *rdev, u32 
vclk, u32 dclk)

        mdelay(1);

-       /* 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));
-
-       /* put PLL in bypass mode */
-       WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_BYPASS_EN_MASK, ~UPLL_BYPASS_EN_MASK);
-
        r = si_uvd_send_upll_ctlreq(rdev);
        if (r)
                return r;
-- 
1.7.10.4

Reply via email to