xf86-video-ati: Branch 'master' - 8 commits

Alex Deucher agd5f at kemper.freedesktop.org
Wed Apr 15 08:59:43 PDT 2009


 man/radeon.man        |   14 
 src/Makefile.am       |    2 
 src/radeon.h          |   43 ++-
 src/radeon_atombios.c |   57 +++
 src/radeon_atombios.h |   10 
 src/radeon_driver.c   |  427 ++---------------------------
 src/radeon_macros.h   |    3 
 src/radeon_pm.c       |  714 ++++++++++++++++++++++++++++++++++++++++++++++++++
 src/radeon_reg.h      |   30 ++
 9 files changed, 898 insertions(+), 402 deletions(-)

New commits:
commit 4b3a3785f7b06205eeec6ca6b8913ecc2b94bd1f
Author: Alex Deucher <alexdeucher at gmail.com>
Date:   Sat Apr 4 11:39:35 2009 -0400

    Unify ForceLowPowerMode and DynamicPM Options
    
    Force lower power mode and switch to a lower mode
    when idle.

diff --git a/src/radeon.h b/src/radeon.h
index c1ad2c3..7e84aeb 100644
--- a/src/radeon.h
+++ b/src/radeon.h
@@ -414,11 +414,30 @@ typedef enum {
 } RADEONCardType;
 
 typedef enum {
-	POWER_MODE_NONE,
-	POWER_MODE_STATIC,
-	POWER_MODE_DYNAMIC
+	POWER_DEFAULT,
+	POWER_LOW,
+	POWER_HIGH
+} RADEONPMType;
+
+typedef struct {
+    RADEONPMType type;
+    uint32_t sclk;
+    uint32_t mclk;
+    uint32_t pcie_lanes;
+    uint32_t flags;
 } RADEONPowerMode;
 
+typedef struct {
+    /* power modes */
+    int num_modes;
+    int current_mode;
+    RADEONPowerMode mode[3];
+
+    Bool     clock_gating_enabled;
+    Bool     dynamic_mode_enabled;
+    Bool     force_low_power_enabled;
+} RADEONPowerManagement;
+
 typedef struct _atomBiosHandle *atomBiosHandlePtr;
 
 typedef struct {
@@ -900,8 +919,7 @@ typedef struct {
     Bool              r4xx_atom;
 
     /* pm */
-    RADEONPowerMode   power_mode;
-    Bool              low_power_active;
+    RADEONPowerManagement pm;
 
 } RADEONInfoRec, *RADEONInfoPtr;
 
@@ -1083,10 +1101,11 @@ extern void RADEONRestoreMemMapRegisters(ScrnInfoPtr pScrn,
 					 RADEONSavePtr restore);
 
 /* radeon_pm.c */
-extern void RADEONSetClockGating(ScrnInfoPtr pScrn, Bool enable);
-extern void RADEONStaticLowPowerMode(ScrnInfoPtr pScrn, Bool enable);
+extern void RADEONPMInit(ScrnInfoPtr pScrn);
 extern void RADEONPMBlockHandler(ScrnInfoPtr pScrn);
-extern void RADEONDynamicLowPowerMode(ScrnInfoPtr pScrn, Bool enable);
+extern void RADEONPMEnterVT(ScrnInfoPtr pScrn);
+extern void RADEONPMLeaveVT(ScrnInfoPtr pScrn);
+extern void RADEONPMFini(ScrnInfoPtr pScrn);
 
 #ifdef USE_EXA
 /* radeon_exa.c */
diff --git a/src/radeon_atombios.c b/src/radeon_atombios.c
index f6fe961..e2348a4 100644
--- a/src/radeon_atombios.c
+++ b/src/radeon_atombios.c
@@ -572,7 +572,7 @@ atombios_static_pwrmgt_setup(ScrnInfoPtr pScrn, Bool enable)
 }
 
 int
-atombios_set_engine_clock(ScrnInfoPtr pScrn, int engclock)
+atombios_set_engine_clock(ScrnInfoPtr pScrn, uint32_t engclock)
 {
     RADEONInfoPtr info       = RADEONPTR(pScrn);
     SET_ENGINE_CLOCK_PS_ALLOCATION eng_clock_ps;
@@ -597,7 +597,7 @@ atombios_set_engine_clock(ScrnInfoPtr pScrn, int engclock)
 }
 
 int
-atombios_set_memory_clock(ScrnInfoPtr pScrn, int memclock)
+atombios_set_memory_clock(ScrnInfoPtr pScrn, uint32_t memclock)
 {
     RADEONInfoPtr info       = RADEONPTR(pScrn);
     SET_MEMORY_CLOCK_PS_ALLOCATION mem_clock_ps;
diff --git a/src/radeon_atombios.h b/src/radeon_atombios.h
index 69e27a3..b81cbbb 100644
--- a/src/radeon_atombios.h
+++ b/src/radeon_atombios.h
@@ -123,10 +123,10 @@ extern int
 atombios_static_pwrmgt_setup(ScrnInfoPtr pScrn, Bool enable);
 
 extern int
-atombios_set_engine_clock(ScrnInfoPtr pScrn, int engclock);
+atombios_set_engine_clock(ScrnInfoPtr pScrn, uint32_t engclock);
 
 extern int
-atombios_set_memory_clock(ScrnInfoPtr pScrn, int memclock);
+atombios_set_memory_clock(ScrnInfoPtr pScrn, uint32_t memclock);
 
 extern Bool
 RADEONGetATOMTVInfo(xf86OutputPtr output);
diff --git a/src/radeon_driver.c b/src/radeon_driver.c
index 8e70e65..105a9f3 100644
--- a/src/radeon_driver.c
+++ b/src/radeon_driver.c
@@ -3221,7 +3221,7 @@ static void RADEONBlockHandler(int i, pointer blockData,
     info->accel_state->engineMode = EXA_ENGINEMODE_UNKNOWN;
 #endif
 
-    if (info->power_mode == POWER_MODE_DYNAMIC)
+    if (info->pm.dynamic_mode_enabled)
 	RADEONPMBlockHandler(pScrn);
 }
 
@@ -3356,22 +3356,7 @@ Bool RADEONScreenInit(int scrnIndex, ScreenPtr pScreen,
     /* blank the outputs/crtcs */
     RADEONBlank(pScrn);
 
-    if (xf86ReturnOptValBool(info->Options, OPTION_CLOCK_GATING, FALSE))
-	RADEONSetClockGating(pScrn, TRUE);
-    else
-	RADEONSetClockGating(pScrn, FALSE);
-
-    info->power_mode = POWER_MODE_NONE;
-    if (xf86ReturnOptValBool(info->Options, OPTION_DYNAMIC_PM, FALSE)) {
-	info->power_mode = POWER_MODE_DYNAMIC;
-	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Dynamic Power Management Enabled\n");
-    } else
-	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Dynamic Power Management Disabled\n");
-
-    if (xf86ReturnOptValBool(info->Options, OPTION_FORCE_LOW_POWER, FALSE)) {
-	info->power_mode = POWER_MODE_STATIC;
-	RADEONStaticLowPowerMode(pScrn, TRUE);
-    }
+    RADEONPMInit(pScrn);
 
     if (info->allowColorTiling && (pScrn->virtualX > info->MaxSurfaceWidth)) {
 	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
@@ -5628,13 +5613,7 @@ Bool RADEONEnterVT(int scrnIndex, int flags)
     /* Makes sure the engine is idle before doing anything */
     RADEONWaitForIdleMMIO(pScrn);
 
-    if (xf86ReturnOptValBool(info->Options, OPTION_CLOCK_GATING, FALSE))
-	RADEONSetClockGating(pScrn, TRUE);
-    else
-	RADEONSetClockGating(pScrn, FALSE);
-
-    if (info->power_mode == POWER_MODE_STATIC)
-	RADEONStaticLowPowerMode(pScrn, TRUE);
+    RADEONPMEnterVT(pScrn);
 
     for (i = 0; i < config->num_crtc; i++)
 	radeon_crtc_modeset_ioctl(config->crtc[i], TRUE);
@@ -5773,6 +5752,8 @@ void RADEONLeaveVT(int scrnIndex, int flags)
 
     xf86_hide_cursors (pScrn);
 
+    RADEONPMLeaveVT(pScrn);
+
     RADEONRestore(pScrn);
 
     for (i = 0; i < config->num_crtc; i++)
@@ -5796,17 +5777,7 @@ static Bool RADEONCloseScreen(int scrnIndex, ScreenPtr pScreen)
     xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
 		   "RADEONCloseScreen\n");
 
-    switch (info->power_mode) {
-    case POWER_MODE_STATIC:
-	RADEONStaticLowPowerMode(pScrn, FALSE);
-	break;
-    case POWER_MODE_DYNAMIC:
-	RADEONDynamicLowPowerMode(pScrn, FALSE);
-	break;
-    case POWER_MODE_NONE:
-    default:
-	break;
-    }
+    RADEONPMFini(pScrn);
 
     /* Mark acceleration as stopped or we might try to access the engine at
      * wrong times, especially if we had DRI, after DRI has been stopped
diff --git a/src/radeon_pm.c b/src/radeon_pm.c
index 41b797a..2fcf45a 100644
--- a/src/radeon_pm.c
+++ b/src/radeon_pm.c
@@ -38,7 +38,7 @@
 #include "radeon_macros.h"
 #include "radeon_atombios.h"
 
-static int calc_div(int num, int den)
+static int calc_div(uint32_t num, uint32_t den)
 {
     int div = (num + (den / 2)) / den;
 
@@ -51,7 +51,7 @@ static int calc_div(int num, int den)
 
 /* 10 khz */
 static void
-RADEONSetEngineClock(ScrnInfoPtr pScrn, int eng_clock)
+RADEONSetEngineClock(ScrnInfoPtr pScrn, uint32_t eng_clock)
 {
     RADEONInfoPtr  info       = RADEONPTR(pScrn);
     RADEONPLLPtr pll = &info->pll;
@@ -75,7 +75,7 @@ RADEONSetEngineClock(ScrnInfoPtr pScrn, int eng_clock)
 
 /* 10 khz */
 static void
-RADEONSetMemoryClock(ScrnInfoPtr pScrn, int mem_clock)
+RADEONSetMemoryClock(ScrnInfoPtr pScrn, uint32_t mem_clock)
 {
     RADEONInfoPtr  info       = RADEONPTR(pScrn);
     RADEONPLLPtr pll = &info->pll;
@@ -551,7 +551,7 @@ RADEONSetPCIELanes(ScrnInfoPtr pScrn, int lanes)
 
 }
 
-void
+static void
 RADEONSetClockGating(ScrnInfoPtr pScrn, Bool enable)
 {
     RADEONInfoPtr  info       = RADEONPTR(pScrn);
@@ -575,48 +575,126 @@ RADEONSetClockGating(ScrnInfoPtr pScrn, Bool enable)
 	       enable ? "En" : "Dis");
 }
 
-void RADEONDynamicLowPowerMode(ScrnInfoPtr pScrn, Bool enable)
+static void RADEONSetStaticPowerMode(ScrnInfoPtr pScrn, RADEONPMType type)
 {
     RADEONInfoPtr  info       = RADEONPTR(pScrn);
-    int sclk = (int)info->sclk * 100; /* 10 khz */
+    int i;
+
+    for (i = 0; i < info->pm.num_modes; i++) {
+	if (info->pm.mode[i].type == type)
+	    break;
+    }
 
-    if (enable && info->low_power_active)
+    if (i == info->pm.num_modes)
 	return;
 
-    if (!enable && !info->low_power_active)
+    if (i == info->pm.current_mode)
 	return;
 
     RADEONWaitForIdleMMIO(pScrn);
 
-    if (enable) {
-	if (info->IsAtomBios)
-	    atombios_set_engine_clock(pScrn, sclk/4);
-	else
-	    RADEONSetEngineClock(pScrn, sclk/4);
+    if (info->IsAtomBios)
+	atombios_set_engine_clock(pScrn, info->pm.mode[i].sclk);
+    else
+	RADEONSetEngineClock(pScrn, info->pm.mode[i].sclk);
 
-	if (info->cardType == CARD_PCIE)
-	    RADEONSetPCIELanes(pScrn, 1);
+    if (info->cardType == CARD_PCIE)
+	RADEONSetPCIELanes(pScrn, info->pm.mode[i].pcie_lanes);
 
-	info->low_power_active = TRUE;
-    } else {
-	if (info->IsAtomBios)
-	    atombios_set_engine_clock(pScrn, sclk);
-	else
-	    RADEONSetEngineClock(pScrn, sclk);
+    info->pm.current_mode = i;
+
+    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Power Mode Switch\n");
+}
 
-	if (info->cardType == CARD_PCIE)
-	    RADEONSetPCIELanes(pScrn, 16);
 
-	info->low_power_active = FALSE;
+void RADEONPMInit(ScrnInfoPtr pScrn)
+{
+    RADEONInfoPtr  info       = RADEONPTR(pScrn);
+
+    if (xf86ReturnOptValBool(info->Options, OPTION_CLOCK_GATING, FALSE))
+	info->pm.clock_gating_enabled = TRUE;
+    else
+	info->pm.clock_gating_enabled = FALSE;
+
+    RADEONSetClockGating(pScrn, info->pm.clock_gating_enabled);
+
+    info->pm.mode[0].type = POWER_DEFAULT;
+    info->pm.mode[0].sclk = (uint32_t)info->sclk * 100; /* 10 khz */
+    info->pm.mode[0].mclk = (uint32_t)info->mclk * 100; /* 10 khz */
+    info->pm.mode[0].pcie_lanes = 16; /* XXX: read back current lane config */
+    info->pm.current_mode = 0;
+    info->pm.num_modes = 1;
+
+    if (xf86ReturnOptValBool(info->Options, OPTION_DYNAMIC_PM, FALSE)) {
+	info->pm.dynamic_mode_enabled = TRUE;
+	info->pm.mode[1].type = POWER_LOW;
+	info->pm.mode[1].sclk = info->pm.mode[0].sclk / 4;
+	info->pm.mode[1].mclk = info->pm.mode[0].mclk / 4;
+	info->pm.mode[1].pcie_lanes = 1;
+
+	info->pm.mode[2].type = POWER_HIGH;
+	info->pm.mode[2].sclk = info->pm.mode[0].sclk;
+	info->pm.mode[2].mclk = info->pm.mode[0].mclk;
+	info->pm.mode[2].pcie_lanes = 16;
+
+	info->pm.num_modes += 2;
+
+	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Dynamic Power Management Enabled\n");
+    } else {
+	info->pm.dynamic_mode_enabled = FALSE;
+	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Dynamic Power Management Disabled\n");
     }
 
-    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Low Power Mode %sabled\n",
-	       enable ? "En" : "Dis");
+    if (xf86ReturnOptValBool(info->Options, OPTION_FORCE_LOW_POWER, FALSE)) {
+	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Force Low Power Mode Enabled\n");
+	info->pm.force_low_power_enabled = TRUE;
+	if (info->pm.dynamic_mode_enabled) {
+	    info->pm.mode[2].type = POWER_HIGH;
+	    info->pm.mode[2].sclk = info->pm.mode[0].sclk / 2;
+	    info->pm.mode[2].mclk = info->pm.mode[0].mclk / 2;
+	    info->pm.mode[2].pcie_lanes = 2;
+	} else {
+	    info->pm.mode[1].type = POWER_HIGH;
+	    info->pm.mode[1].sclk = info->pm.mode[0].sclk / 2;
+	    info->pm.mode[1].mclk = info->pm.mode[0].mclk / 2;
+	    info->pm.mode[1].pcie_lanes = 2;
+	    info->pm.num_modes += 1;
+	}
+	RADEONSetStaticPowerMode(pScrn, POWER_HIGH);
+    } else
+	info->pm.force_low_power_enabled = FALSE;
+
 }
 
-void RADEONPMBlockHandler(ScrnInfoPtr pScrn)
+void RADEONPMEnterVT(ScrnInfoPtr pScrn)
+{
+    RADEONInfoPtr  info       = RADEONPTR(pScrn);
+
+    RADEONSetClockGating(pScrn, info->pm.clock_gating_enabled);
+    if (info->pm.force_low_power_enabled || info->pm.dynamic_mode_enabled)
+	RADEONSetStaticPowerMode(pScrn, POWER_HIGH);
+}
+
+void RADEONPMLeaveVT(ScrnInfoPtr pScrn)
+{
+    RADEONInfoPtr  info       = RADEONPTR(pScrn);
+
+    RADEONSetClockGating(pScrn, FALSE);
+    if (info->pm.force_low_power_enabled || info->pm.dynamic_mode_enabled)
+	RADEONSetStaticPowerMode(pScrn, POWER_DEFAULT);
+}
+
+void RADEONPMFini(ScrnInfoPtr pScrn)
 {
     RADEONInfoPtr info = RADEONPTR(pScrn);
+
+    RADEONSetClockGating(pScrn, FALSE);
+    if (info->pm.force_low_power_enabled || info->pm.dynamic_mode_enabled)
+	RADEONSetStaticPowerMode(pScrn, POWER_DEFAULT);
+}
+
+void RADEONPMBlockHandler(ScrnInfoPtr pScrn)
+{
     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
     int i;
 
@@ -628,40 +706,9 @@ void RADEONPMBlockHandler(ScrnInfoPtr pScrn)
 	    break;
     }
 
-    if (i == xf86_config->num_crtc) {
-	if (!info->low_power_active)
-	    RADEONDynamicLowPowerMode(pScrn, TRUE);
-    } else {
-	if (info->low_power_active)
-	    RADEONDynamicLowPowerMode(pScrn, FALSE);
-    }
+    if (i == xf86_config->num_crtc)
+	RADEONSetStaticPowerMode(pScrn, POWER_HIGH);
+    else
+	RADEONSetStaticPowerMode(pScrn, POWER_LOW);
 }
 
-void RADEONStaticLowPowerMode(ScrnInfoPtr pScrn, Bool enable)
-{
-    RADEONInfoPtr  info       = RADEONPTR(pScrn);
-    int sclk = (int)info->sclk * 100; /* 10 khz */
-
-    RADEONWaitForIdleMMIO(pScrn);
-
-    if (enable) {
-	if (info->IsAtomBios)
-	    atombios_set_engine_clock(pScrn, sclk/2);
-	else
-	    RADEONSetEngineClock(pScrn, sclk/2);
-
-	if (info->cardType == CARD_PCIE)
-	    RADEONSetPCIELanes(pScrn, 2);
-    } else {
-	if (info->IsAtomBios)
-	    atombios_set_engine_clock(pScrn, sclk);
-	else
-	    RADEONSetEngineClock(pScrn, sclk);
-
-	if (info->cardType == CARD_PCIE)
-	    RADEONSetPCIELanes(pScrn, 16);
-    }
-
-    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Static Low Power Mode %sabled\n",
-	       enable ? "En" : "Dis");
-}
commit 63cb57c5eb0d6bc083f54eb100cb972b0e7bca69
Author: Alex Deucher <alexdeucher at gmail.com>
Date:   Wed Apr 1 16:22:02 2009 -0400

    Add DynamicPM Option
    
    Dyanmically switch between power states. Switch to a low
    power state when the system is idle (DPMS off).

diff --git a/man/radeon.man b/man/radeon.man
index f616703..eb133c3 100644
--- a/man/radeon.man
+++ b/man/radeon.man
@@ -423,6 +423,10 @@ with this enabled.  The default is
 Enable a static low power mode.  This can help reduce heat and increase battery
 life by reducing power usage at the expense of performance. The default is
 .B off.
+.BI "Option \*qDynamicPM\*q \*q" boolean \*q
+Enable dynamic power mode switching.  This can help reduce heat and increase battery
+life by reducing power usage when the system is idle (DPMS active). The default is
+.B off.
 .TP
 .BI "Option \*qVGAAccess\*q \*q" boolean \*q
 Tell the driver if it can do legacy VGA IOs to the card. This is
diff --git a/src/radeon.h b/src/radeon.h
index 3a9130c..c1ad2c3 100644
--- a/src/radeon.h
+++ b/src/radeon.h
@@ -208,7 +208,8 @@ typedef enum {
     OPTION_EXA_VSYNC,
     OPTION_ATOM_TVOUT,
     OPTION_R4XX_ATOM,
-    OPTION_FORCE_LOW_POWER
+    OPTION_FORCE_LOW_POWER,
+    OPTION_DYNAMIC_PM
 } RADEONOpts;
 
 
@@ -412,6 +413,12 @@ typedef enum {
 	CARD_PCIE
 } RADEONCardType;
 
+typedef enum {
+	POWER_MODE_NONE,
+	POWER_MODE_STATIC,
+	POWER_MODE_DYNAMIC
+} RADEONPowerMode;
+
 typedef struct _atomBiosHandle *atomBiosHandlePtr;
 
 typedef struct {
@@ -893,7 +900,8 @@ typedef struct {
     Bool              r4xx_atom;
 
     /* pm */
-    Bool              low_power_mode;
+    RADEONPowerMode   power_mode;
+    Bool              low_power_active;
 
 } RADEONInfoRec, *RADEONInfoPtr;
 
@@ -1077,6 +1085,8 @@ extern void RADEONRestoreMemMapRegisters(ScrnInfoPtr pScrn,
 /* radeon_pm.c */
 extern void RADEONSetClockGating(ScrnInfoPtr pScrn, Bool enable);
 extern void RADEONStaticLowPowerMode(ScrnInfoPtr pScrn, Bool enable);
+extern void RADEONPMBlockHandler(ScrnInfoPtr pScrn);
+extern void RADEONDynamicLowPowerMode(ScrnInfoPtr pScrn, Bool enable);
 
 #ifdef USE_EXA
 /* radeon_exa.c */
diff --git a/src/radeon_driver.c b/src/radeon_driver.c
index 7c758f8..8e70e65 100644
--- a/src/radeon_driver.c
+++ b/src/radeon_driver.c
@@ -196,6 +196,7 @@ static const OptionInfoRec RADEONOptions[] = {
     { OPTION_ATOM_TVOUT,	"ATOMTVOut",	   OPTV_BOOLEAN, {0}, FALSE },
     { OPTION_R4XX_ATOM,	        "R4xxATOM",	   OPTV_BOOLEAN, {0}, FALSE },
     { OPTION_FORCE_LOW_POWER,	"ForceLowPowerMode", OPTV_BOOLEAN, {0}, FALSE },
+    { OPTION_DYNAMIC_PM,	"DynamicPM",       OPTV_BOOLEAN, {0}, FALSE },
     { -1,                    NULL,               OPTV_NONE,    {0}, FALSE }
 };
 
@@ -3219,6 +3220,9 @@ static void RADEONBlockHandler(int i, pointer blockData,
 #ifdef USE_EXA
     info->accel_state->engineMode = EXA_ENGINEMODE_UNKNOWN;
 #endif
+
+    if (info->power_mode == POWER_MODE_DYNAMIC)
+	RADEONPMBlockHandler(pScrn);
 }
 
 static void
@@ -3357,8 +3361,17 @@ Bool RADEONScreenInit(int scrnIndex, ScreenPtr pScreen,
     else
 	RADEONSetClockGating(pScrn, FALSE);
 
-    if (xf86ReturnOptValBool(info->Options, OPTION_FORCE_LOW_POWER, FALSE))
+    info->power_mode = POWER_MODE_NONE;
+    if (xf86ReturnOptValBool(info->Options, OPTION_DYNAMIC_PM, FALSE)) {
+	info->power_mode = POWER_MODE_DYNAMIC;
+	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Dynamic Power Management Enabled\n");
+    } else
+	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Dynamic Power Management Disabled\n");
+
+    if (xf86ReturnOptValBool(info->Options, OPTION_FORCE_LOW_POWER, FALSE)) {
+	info->power_mode = POWER_MODE_STATIC;
 	RADEONStaticLowPowerMode(pScrn, TRUE);
+    }
 
     if (info->allowColorTiling && (pScrn->virtualX > info->MaxSurfaceWidth)) {
 	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
@@ -5620,7 +5633,7 @@ Bool RADEONEnterVT(int scrnIndex, int flags)
     else
 	RADEONSetClockGating(pScrn, FALSE);
 
-    if (xf86ReturnOptValBool(info->Options, OPTION_FORCE_LOW_POWER, FALSE))
+    if (info->power_mode == POWER_MODE_STATIC)
 	RADEONStaticLowPowerMode(pScrn, TRUE);
 
     for (i = 0; i < config->num_crtc; i++)
@@ -5783,8 +5796,17 @@ static Bool RADEONCloseScreen(int scrnIndex, ScreenPtr pScreen)
     xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
 		   "RADEONCloseScreen\n");
 
-    if (xf86ReturnOptValBool(info->Options, OPTION_FORCE_LOW_POWER, FALSE))
+    switch (info->power_mode) {
+    case POWER_MODE_STATIC:
 	RADEONStaticLowPowerMode(pScrn, FALSE);
+	break;
+    case POWER_MODE_DYNAMIC:
+	RADEONDynamicLowPowerMode(pScrn, FALSE);
+	break;
+    case POWER_MODE_NONE:
+    default:
+	break;
+    }
 
     /* Mark acceleration as stopped or we might try to access the engine at
      * wrong times, especially if we had DRI, after DRI has been stopped
diff --git a/src/radeon_pm.c b/src/radeon_pm.c
index ac6b972..41b797a 100644
--- a/src/radeon_pm.c
+++ b/src/radeon_pm.c
@@ -575,6 +575,68 @@ RADEONSetClockGating(ScrnInfoPtr pScrn, Bool enable)
 	       enable ? "En" : "Dis");
 }
 
+void RADEONDynamicLowPowerMode(ScrnInfoPtr pScrn, Bool enable)
+{
+    RADEONInfoPtr  info       = RADEONPTR(pScrn);
+    int sclk = (int)info->sclk * 100; /* 10 khz */
+
+    if (enable && info->low_power_active)
+	return;
+
+    if (!enable && !info->low_power_active)
+	return;
+
+    RADEONWaitForIdleMMIO(pScrn);
+
+    if (enable) {
+	if (info->IsAtomBios)
+	    atombios_set_engine_clock(pScrn, sclk/4);
+	else
+	    RADEONSetEngineClock(pScrn, sclk/4);
+
+	if (info->cardType == CARD_PCIE)
+	    RADEONSetPCIELanes(pScrn, 1);
+
+	info->low_power_active = TRUE;
+    } else {
+	if (info->IsAtomBios)
+	    atombios_set_engine_clock(pScrn, sclk);
+	else
+	    RADEONSetEngineClock(pScrn, sclk);
+
+	if (info->cardType == CARD_PCIE)
+	    RADEONSetPCIELanes(pScrn, 16);
+
+	info->low_power_active = FALSE;
+    }
+
+    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Low Power Mode %sabled\n",
+	       enable ? "En" : "Dis");
+}
+
+void RADEONPMBlockHandler(ScrnInfoPtr pScrn)
+{
+    RADEONInfoPtr info = RADEONPTR(pScrn);
+    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+    int i;
+
+    for (i = 0; i < xf86_config->num_crtc; i++) {
+	xf86CrtcPtr crtc = xf86_config->crtc[i];
+	RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private;
+
+	if (radeon_crtc->enabled)
+	    break;
+    }
+
+    if (i == xf86_config->num_crtc) {
+	if (!info->low_power_active)
+	    RADEONDynamicLowPowerMode(pScrn, TRUE);
+    } else {
+	if (info->low_power_active)
+	    RADEONDynamicLowPowerMode(pScrn, FALSE);
+    }
+}
+
 void RADEONStaticLowPowerMode(ScrnInfoPtr pScrn, Bool enable)
 {
     RADEONInfoPtr  info       = RADEONPTR(pScrn);
@@ -590,8 +652,6 @@ void RADEONStaticLowPowerMode(ScrnInfoPtr pScrn, Bool enable)
 
 	if (info->cardType == CARD_PCIE)
 	    RADEONSetPCIELanes(pScrn, 2);
-
-	info->low_power_mode = TRUE;
     } else {
 	if (info->IsAtomBios)
 	    atombios_set_engine_clock(pScrn, sclk);
@@ -600,10 +660,8 @@ void RADEONStaticLowPowerMode(ScrnInfoPtr pScrn, Bool enable)
 
 	if (info->cardType == CARD_PCIE)
 	    RADEONSetPCIELanes(pScrn, 16);
-
-	info->low_power_mode = FALSE;
     }
 
-    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Low Power Mode %sabled\n",
+    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Static Low Power Mode %sabled\n",
 	       enable ? "En" : "Dis");
 }
commit a34a8b37afbea6ed4bf8ca42364195e174250c48
Author: Alex Deucher <alexdeucher at gmail.com>
Date:   Wed Apr 1 15:23:17 2009 -0400

    Set default low power PCIE lanes to 2
    
    1 lane seems to cause occasional corruption when
    blitting to/from gart memory.

diff --git a/src/radeon_pm.c b/src/radeon_pm.c
index d518998..ac6b972 100644
--- a/src/radeon_pm.c
+++ b/src/radeon_pm.c
@@ -589,7 +589,7 @@ void RADEONStaticLowPowerMode(ScrnInfoPtr pScrn, Bool enable)
 	    RADEONSetEngineClock(pScrn, sclk/2);
 
 	if (info->cardType == CARD_PCIE)
-	    RADEONSetPCIELanes(pScrn, 1);
+	    RADEONSetPCIELanes(pScrn, 2);
 
 	info->low_power_mode = TRUE;
     } else {
commit 1f0dc778dc25f4f85fedd73c55c847cab2c79fc5
Author: Alex Deucher <alexdeucher at gmail.com>
Date:   Wed Apr 1 15:12:27 2009 -0400

    Add support for setting the number PCIE lanes

diff --git a/src/radeon.h b/src/radeon.h
index 88de0e8..3a9130c 100644
--- a/src/radeon.h
+++ b/src/radeon.h
@@ -1060,9 +1060,11 @@ extern int RADEONMinBits(int val);
 extern unsigned RADEONINMC(ScrnInfoPtr pScrn, int addr);
 extern unsigned RADEONINPLL(ScrnInfoPtr pScrn, int addr);
 extern unsigned RADEONINPCIE(ScrnInfoPtr pScrn, int addr);
+extern unsigned R600INPCIE_PORT(ScrnInfoPtr pScrn, int addr);
 extern void RADEONOUTMC(ScrnInfoPtr pScrn, int addr, uint32_t data);
 extern void RADEONOUTPLL(ScrnInfoPtr pScrn, int addr, uint32_t data);
 extern void RADEONOUTPCIE(ScrnInfoPtr pScrn, int addr, uint32_t data);
+extern void R600OUTPCIE_PORT(ScrnInfoPtr pScrn, int addr, uint32_t data);
 extern void RADEONPllErrataAfterData(RADEONInfoPtr info);
 extern void RADEONPllErrataAfterIndex(RADEONInfoPtr info);
 extern void RADEONWaitForVerticalSync(ScrnInfoPtr pScrn);
diff --git a/src/radeon_driver.c b/src/radeon_driver.c
index ac1a151..7c758f8 100644
--- a/src/radeon_driver.c
+++ b/src/radeon_driver.c
@@ -690,6 +690,29 @@ void RADEONOUTPCIE(ScrnInfoPtr pScrn, int addr, uint32_t data)
     OUTREG(RADEON_PCIE_DATA, data);
 }
 
+/* Read PCIE PORT register */
+unsigned R600INPCIE_PORT(ScrnInfoPtr pScrn, int addr)
+{
+    RADEONInfoPtr  info       = RADEONPTR(pScrn);
+    unsigned char *RADEONMMIO = info->MMIO;
+    CARD32         data;
+
+    OUTREG(R600_PCIE_PORT_INDEX, addr & 0xff);
+    data = INREG(R600_PCIE_PORT_DATA);
+
+    return data;
+}
+
+/* Write PCIE PORT register */
+void R600OUTPCIE_PORT(ScrnInfoPtr pScrn, int addr, uint32_t data)
+{
+    RADEONInfoPtr  info       = RADEONPTR(pScrn);
+    unsigned char *RADEONMMIO = info->MMIO;
+
+    OUTREG(R600_PCIE_PORT_INDEX, ((addr) & 0xff));
+    OUTREG(R600_PCIE_PORT_DATA, data);
+}
+
 static Bool radeon_get_mc_idle(ScrnInfoPtr pScrn)
 {
     RADEONInfoPtr  info       = RADEONPTR(pScrn);
diff --git a/src/radeon_macros.h b/src/radeon_macros.h
index 19307c8..8575884 100644
--- a/src/radeon_macros.h
+++ b/src/radeon_macros.h
@@ -157,4 +157,7 @@ do {									\
 #define INPCIE(pScrn, addr) RADEONINPCIE(pScrn, addr)
 #define OUTPCIE(pScrn, addr, val) RADEONOUTPCIE(pScrn, addr, val)
 
+#define INPCIE_P(pScrn, addr) R600INPCIE_PORT(pScrn, addr)
+#define OUTPCIE_P(pScrn, addr, val) R600OUTPCIE_PORT(pScrn, addr, val)
+
 #endif
diff --git a/src/radeon_pm.c b/src/radeon_pm.c
index 86d739b..d518998 100644
--- a/src/radeon_pm.c
+++ b/src/radeon_pm.c
@@ -452,6 +452,105 @@ void RADEONForceSomeClocks(ScrnInfoPtr pScrn)
      OUTPLL(pScrn, RADEON_SCLK_CNTL, tmp);
 }
 
+static void
+RADEONSetPCIELanes(ScrnInfoPtr pScrn, int lanes)
+{
+    RADEONInfoPtr  info       = RADEONPTR(pScrn);
+    unsigned char *RADEONMMIO = info->MMIO;
+    uint32_t link_width_cntl, mask, target_reg;
+
+    if (info->IsIGP)
+	return;
+
+    RADEONWaitForIdleMMIO(pScrn);
+
+    switch (lanes) {
+    case 0:
+	mask = RADEON_PCIE_LC_LINK_WIDTH_X0;
+	break;
+    case 1:
+	mask = RADEON_PCIE_LC_LINK_WIDTH_X1;
+	break;
+    case 2:
+	mask = RADEON_PCIE_LC_LINK_WIDTH_X2;
+	break;
+    case 4:
+	mask = RADEON_PCIE_LC_LINK_WIDTH_X4;
+	break;
+    case 8:
+	mask = RADEON_PCIE_LC_LINK_WIDTH_X8;
+	break;
+    case 12:
+	mask = RADEON_PCIE_LC_LINK_WIDTH_X12;
+	break;
+    case 16:
+    default:
+	mask = RADEON_PCIE_LC_LINK_WIDTH_X16;
+	break;
+    }
+
+    if (info->ChipFamily >= CHIP_FAMILY_R600) {
+	link_width_cntl = INPCIE_P(pScrn, RADEON_PCIE_LC_LINK_WIDTH_CNTL);
+
+	if ((link_width_cntl & RADEON_PCIE_LC_LINK_WIDTH_RD_MASK) ==
+	    (mask << RADEON_PCIE_LC_LINK_WIDTH_RD_SHIFT))
+	    return;
+
+	link_width_cntl &= ~(RADEON_PCIE_LC_LINK_WIDTH_MASK |
+			     RADEON_PCIE_LC_RECONFIG_NOW |
+			     R600_PCIE_LC_RECONFIG_ARC_MISSING_ESCAPE |
+			     R600_PCIE_LC_SHORT_RECONFIG_EN |
+			     R600_PCIE_LC_RENEGOTIATE_EN);
+	link_width_cntl |= mask;
+
+#if 0
+	/* some northbridges can renegotiate the link rather than requiring
+	 * a complete re-config.
+	 * e.g., AMD 780/790 northbridges (pci ids: 0x5956, 0x5957, 0x5958, etc.)
+	 */
+	if (northbridge can renegotiate)
+	    link_width_cntl |= R600_PCIE_LC_RENEGOTIATE_EN;
+	else
+#endif
+	    link_width_cntl |= R600_PCIE_LC_RECONFIG_ARC_MISSING_ESCAPE;
+
+	OUTPCIE_P(pScrn, RADEON_PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl);
+	OUTPCIE_P(pScrn, RADEON_PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl | RADEON_PCIE_LC_RECONFIG_NOW);
+
+	if (info->ChipFamily >= CHIP_FAMILY_RV770)
+	    target_reg = R700_TARGET_AND_CURRENT_PROFILE_INDEX;
+	else
+	    target_reg = R600_TARGET_AND_CURRENT_PROFILE_INDEX;
+
+	/* wait for lane set to complete */
+	link_width_cntl = INREG(target_reg);
+	while (link_width_cntl == 0xffffffff)
+	    link_width_cntl = INREG(target_reg);
+
+    } else {
+	link_width_cntl = INPCIE(pScrn, RADEON_PCIE_LC_LINK_WIDTH_CNTL);
+
+	if ((link_width_cntl & RADEON_PCIE_LC_LINK_WIDTH_RD_MASK) ==
+	    (mask << RADEON_PCIE_LC_LINK_WIDTH_RD_SHIFT))
+	    return;
+
+	link_width_cntl &= ~(RADEON_PCIE_LC_LINK_WIDTH_MASK |
+			     RADEON_PCIE_LC_RECONFIG_NOW |
+			     RADEON_PCIE_LC_RECONFIG_LATER |
+			     RADEON_PCIE_LC_SHORT_RECONFIG_EN);
+	link_width_cntl |= mask;
+	OUTPCIE(pScrn, RADEON_PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl);
+	OUTPCIE(pScrn, RADEON_PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl | RADEON_PCIE_LC_RECONFIG_NOW);
+
+	/* wait for lane set to complete */
+	link_width_cntl = INPCIE(pScrn, RADEON_PCIE_LC_LINK_WIDTH_CNTL);
+	while (link_width_cntl == 0xffffffff)
+	    link_width_cntl = INPCIE(pScrn, RADEON_PCIE_LC_LINK_WIDTH_CNTL);
+
+    }
+
+}
+
 void
 RADEONSetClockGating(ScrnInfoPtr pScrn, Bool enable)
 {
@@ -489,6 +588,9 @@ void RADEONStaticLowPowerMode(ScrnInfoPtr pScrn, Bool enable)
 	else
 	    RADEONSetEngineClock(pScrn, sclk/2);
 
+	if (info->cardType == CARD_PCIE)
+	    RADEONSetPCIELanes(pScrn, 1);
+
 	info->low_power_mode = TRUE;
     } else {
 	if (info->IsAtomBios)
@@ -496,6 +598,9 @@ void RADEONStaticLowPowerMode(ScrnInfoPtr pScrn, Bool enable)
 	else
 	    RADEONSetEngineClock(pScrn, sclk);
 
+	if (info->cardType == CARD_PCIE)
+	    RADEONSetPCIELanes(pScrn, 16);
+
 	info->low_power_mode = FALSE;
     }
 
diff --git a/src/radeon_reg.h b/src/radeon_reg.h
index e8af027..e085353 100644
--- a/src/radeon_reg.h
+++ b/src/radeon_reg.h
@@ -276,6 +276,29 @@
 
 #define RADEON_PCIE_INDEX                   0x0030
 #define RADEON_PCIE_DATA                    0x0034
+#define R600_PCIE_PORT_INDEX                0x0038
+#define R600_PCIE_PORT_DATA                 0x003c
+/* PCIE_LC_LINK_WIDTH_CNTL is PCIE on r1xx-r5xx, PCIE_PORT on r6xx-r7xx */
+#define RADEON_PCIE_LC_LINK_WIDTH_CNTL      0xa2 /* PCIE */
+#       define RADEON_PCIE_LC_LINK_WIDTH_SHIFT     0
+#       define RADEON_PCIE_LC_LINK_WIDTH_MASK      0x7
+#       define RADEON_PCIE_LC_LINK_WIDTH_X0        0
+#       define RADEON_PCIE_LC_LINK_WIDTH_X1        1
+#       define RADEON_PCIE_LC_LINK_WIDTH_X2        2
+#       define RADEON_PCIE_LC_LINK_WIDTH_X4        3
+#       define RADEON_PCIE_LC_LINK_WIDTH_X8        4
+#       define RADEON_PCIE_LC_LINK_WIDTH_X12       5
+#       define RADEON_PCIE_LC_LINK_WIDTH_X16       6
+#       define RADEON_PCIE_LC_LINK_WIDTH_RD_SHIFT  4
+#       define RADEON_PCIE_LC_LINK_WIDTH_RD_MASK   0x70
+#       define R600_PCIE_LC_RECONFIG_ARC_MISSING_ESCAPE   (1 << 7)
+#       define RADEON_PCIE_LC_RECONFIG_NOW         (1 << 8)
+#       define RADEON_PCIE_LC_RECONFIG_LATER       (1 << 9)
+#       define RADEON_PCIE_LC_SHORT_RECONFIG_EN    (1 << 10)
+#       define R600_PCIE_LC_RENEGOTIATE_EN         (1 << 10)
+#       define R600_PCIE_LC_SHORT_RECONFIG_EN      (1 << 11)
+#define R600_TARGET_AND_CURRENT_PROFILE_INDEX      0x70c
+#define R700_TARGET_AND_CURRENT_PROFILE_INDEX      0x66c
 
 #define RADEON_CACHE_CNTL                   0x1724
 #define RADEON_CACHE_LINE                   0x0f0c /* PCI */
commit 7e10b6222e8f44a3ecc6aaea55a7a7680d133bb3
Author: Alex Deucher <alexdeucher at gmail.com>
Date:   Wed Apr 1 15:05:38 2009 -0400

    Add ForceLowPowerMode Option
    
    Force the chip to a low power mode at the expense
    of performance.

diff --git a/man/radeon.man b/man/radeon.man
index 9a7cf80..f616703 100644
--- a/man/radeon.man
+++ b/man/radeon.man
@@ -419,6 +419,11 @@ life by reducing power usage.  Some users report reduced 3D performance
 with this enabled.  The default is
 .B off.
 .TP
+.BI "Option \*qForceLowPowerMode\*q \*q" boolean \*q
+Enable a static low power mode.  This can help reduce heat and increase battery
+life by reducing power usage at the expense of performance. The default is
+.B off.
+.TP
 .BI "Option \*qVGAAccess\*q \*q" boolean \*q
 Tell the driver if it can do legacy VGA IOs to the card. This is
 necessary for properly resuming consoles when in VGA text mode, but
diff --git a/src/radeon.h b/src/radeon.h
index 60d56db..88de0e8 100644
--- a/src/radeon.h
+++ b/src/radeon.h
@@ -207,7 +207,8 @@ typedef enum {
     OPTION_INT10,
     OPTION_EXA_VSYNC,
     OPTION_ATOM_TVOUT,
-    OPTION_R4XX_ATOM
+    OPTION_R4XX_ATOM,
+    OPTION_FORCE_LOW_POWER
 } RADEONOpts;
 
 
@@ -891,6 +892,9 @@ typedef struct {
 
     Bool              r4xx_atom;
 
+    /* pm */
+    Bool              low_power_mode;
+
 } RADEONInfoRec, *RADEONInfoPtr;
 
 #define RADEONWaitForFifo(pScrn, entries)				\
@@ -1070,6 +1074,7 @@ extern void RADEONRestoreMemMapRegisters(ScrnInfoPtr pScrn,
 
 /* radeon_pm.c */
 extern void RADEONSetClockGating(ScrnInfoPtr pScrn, Bool enable);
+extern void RADEONStaticLowPowerMode(ScrnInfoPtr pScrn, Bool enable);
 
 #ifdef USE_EXA
 /* radeon_exa.c */
diff --git a/src/radeon_driver.c b/src/radeon_driver.c
index fe00dd7..ac1a151 100644
--- a/src/radeon_driver.c
+++ b/src/radeon_driver.c
@@ -195,6 +195,7 @@ static const OptionInfoRec RADEONOptions[] = {
     { OPTION_EXA_VSYNC,         "EXAVSync",        OPTV_BOOLEAN, {0}, FALSE },
     { OPTION_ATOM_TVOUT,	"ATOMTVOut",	   OPTV_BOOLEAN, {0}, FALSE },
     { OPTION_R4XX_ATOM,	        "R4xxATOM",	   OPTV_BOOLEAN, {0}, FALSE },
+    { OPTION_FORCE_LOW_POWER,	"ForceLowPowerMode", OPTV_BOOLEAN, {0}, FALSE },
     { -1,                    NULL,               OPTV_NONE,    {0}, FALSE }
 };
 
@@ -3333,6 +3334,9 @@ Bool RADEONScreenInit(int scrnIndex, ScreenPtr pScreen,
     else
 	RADEONSetClockGating(pScrn, FALSE);
 
+    if (xf86ReturnOptValBool(info->Options, OPTION_FORCE_LOW_POWER, FALSE))
+	RADEONStaticLowPowerMode(pScrn, TRUE);
+
     if (info->allowColorTiling && (pScrn->virtualX > info->MaxSurfaceWidth)) {
 	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
 		   "Color tiling not supported with virtual x resolutions larger than %d, disabling\n",
@@ -5593,6 +5597,9 @@ Bool RADEONEnterVT(int scrnIndex, int flags)
     else
 	RADEONSetClockGating(pScrn, FALSE);
 
+    if (xf86ReturnOptValBool(info->Options, OPTION_FORCE_LOW_POWER, FALSE))
+	RADEONStaticLowPowerMode(pScrn, TRUE);
+
     for (i = 0; i < config->num_crtc; i++)
 	radeon_crtc_modeset_ioctl(config->crtc[i], TRUE);
 
@@ -5753,6 +5760,9 @@ static Bool RADEONCloseScreen(int scrnIndex, ScreenPtr pScreen)
     xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
 		   "RADEONCloseScreen\n");
 
+    if (xf86ReturnOptValBool(info->Options, OPTION_FORCE_LOW_POWER, FALSE))
+	RADEONStaticLowPowerMode(pScrn, FALSE);
+
     /* Mark acceleration as stopped or we might try to access the engine at
      * wrong times, especially if we had DRI, after DRI has been stopped
      */
diff --git a/src/radeon_pm.c b/src/radeon_pm.c
index 89e1d8a..86d739b 100644
--- a/src/radeon_pm.c
+++ b/src/radeon_pm.c
@@ -476,3 +476,29 @@ RADEONSetClockGating(ScrnInfoPtr pScrn, Bool enable)
 	       enable ? "En" : "Dis");
 }
 
+void RADEONStaticLowPowerMode(ScrnInfoPtr pScrn, Bool enable)
+{
+    RADEONInfoPtr  info       = RADEONPTR(pScrn);
+    int sclk = (int)info->sclk * 100; /* 10 khz */
+
+    RADEONWaitForIdleMMIO(pScrn);
+
+    if (enable) {
+	if (info->IsAtomBios)
+	    atombios_set_engine_clock(pScrn, sclk/2);
+	else
+	    RADEONSetEngineClock(pScrn, sclk/2);
+
+	info->low_power_mode = TRUE;
+    } else {
+	if (info->IsAtomBios)
+	    atombios_set_engine_clock(pScrn, sclk);
+	else
+	    RADEONSetEngineClock(pScrn, sclk);
+
+	info->low_power_mode = FALSE;
+    }
+
+    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Low Power Mode %sabled\n",
+	       enable ? "En" : "Dis");
+}
commit 533d01a5933cd491bbc09cd463ea62475abf4bf2
Author: Alex Deucher <alexdeucher at gmail.com>
Date:   Tue Mar 31 17:24:29 2009 -0400

    radeon: Add functions to set sclk/mclk using atombios

diff --git a/src/radeon_atombios.c b/src/radeon_atombios.c
index e32f7ba..f6fe961 100644
--- a/src/radeon_atombios.c
+++ b/src/radeon_atombios.c
@@ -571,6 +571,59 @@ atombios_static_pwrmgt_setup(ScrnInfoPtr pScrn, Bool enable)
 
 }
 
+int
+atombios_set_engine_clock(ScrnInfoPtr pScrn, int engclock)
+{
+    RADEONInfoPtr info       = RADEONPTR(pScrn);
+    SET_ENGINE_CLOCK_PS_ALLOCATION eng_clock_ps;
+    AtomBiosArgRec data;
+    unsigned char *space;
+
+    RADEONWaitForIdleMMIO(pScrn);
+
+    eng_clock_ps.ulTargetEngineClock = engclock; /* 10 khz */
+
+    /*ErrorF("Attempting to set engine clock to: %d\n", engclock);*/
+    data.exec.index = GetIndexIntoMasterTable(COMMAND, SetEngineClock);
+    data.exec.dataSpace = (void *)&space;
+    data.exec.pspace = &eng_clock_ps;
+
+    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
+	/* ErrorF("Set engine clock success\n"); */
+	return ATOM_SUCCESS;
+    }
+    /* ErrorF("Set engine clock failed\n"); */
+    return ATOM_NOT_IMPLEMENTED;
+}
+
+int
+atombios_set_memory_clock(ScrnInfoPtr pScrn, int memclock)
+{
+    RADEONInfoPtr info       = RADEONPTR(pScrn);
+    SET_MEMORY_CLOCK_PS_ALLOCATION mem_clock_ps;
+    AtomBiosArgRec data;
+    unsigned char *space;
+
+    if (info->IsIGP)
+	return ATOM_SUCCESS;
+
+    RADEONWaitForIdleMMIO(pScrn);
+
+    mem_clock_ps.ulTargetMemoryClock = memclock; /* 10 khz */
+
+    /* ErrorF("Attempting to set mem clock to: %d\n", memclock); */
+    data.exec.index = GetIndexIntoMasterTable(COMMAND, SetMemoryClock);
+    data.exec.dataSpace = (void *)&space;
+    data.exec.pspace = &mem_clock_ps;
+
+    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
+	/* ErrorF("Set memory clock success\n"); */
+	return ATOM_SUCCESS;
+    }
+    /* ErrorF("Set memory clock failed\n"); */
+    return ATOM_NOT_IMPLEMENTED;
+}
+
 # endif
 
 static AtomBiosResult
diff --git a/src/radeon_atombios.h b/src/radeon_atombios.h
index 806df30..69e27a3 100644
--- a/src/radeon_atombios.h
+++ b/src/radeon_atombios.h
@@ -122,6 +122,12 @@ atombios_clk_gating_setup(ScrnInfoPtr pScrn, Bool enable);
 extern int
 atombios_static_pwrmgt_setup(ScrnInfoPtr pScrn, Bool enable);
 
+extern int
+atombios_set_engine_clock(ScrnInfoPtr pScrn, int engclock);
+
+extern int
+atombios_set_memory_clock(ScrnInfoPtr pScrn, int memclock);
+
 extern Bool
 RADEONGetATOMTVInfo(xf86OutputPtr output);
 
commit adb099409768e695b9928fa6aa5760f93dadd9af
Author: Alex Deucher <alexdeucher at gmail.com>
Date:   Tue Mar 31 17:13:11 2009 -0400

    radeon: Add functions to set sclk/mclk on r1xx-r4xx

diff --git a/src/radeon_pm.c b/src/radeon_pm.c
index 4f3f4c7..89e1d8a 100644
--- a/src/radeon_pm.c
+++ b/src/radeon_pm.c
@@ -38,6 +38,68 @@
 #include "radeon_macros.h"
 #include "radeon_atombios.h"
 
+static int calc_div(int num, int den)
+{
+    int div = (num + (den / 2)) / den;
+
+    if ((div < 2) || (div > 0xff))
+	return 0;
+    else
+	return div;
+
+}
+
+/* 10 khz */
+static void
+RADEONSetEngineClock(ScrnInfoPtr pScrn, int eng_clock)
+{
+    RADEONInfoPtr  info       = RADEONPTR(pScrn);
+    RADEONPLLPtr pll = &info->pll;
+    uint32_t ref_div, fb_div;
+    uint32_t m_spll_ref_fb_div;
+
+    RADEONWaitForIdleMMIO(pScrn);
+
+    m_spll_ref_fb_div = INPLL(pScrn, RADEON_M_SPLL_REF_FB_DIV);
+    ref_div = m_spll_ref_fb_div & RADEON_M_SPLL_REF_DIV_MASK;
+    fb_div = calc_div(eng_clock * ref_div, pll->reference_freq);
+
+    if (!fb_div)
+	return;
+
+    m_spll_ref_fb_div &= ~(RADEON_SPLL_FB_DIV_MASK << RADEON_SPLL_FB_DIV_SHIFT);
+    m_spll_ref_fb_div |= (fb_div & RADEON_SPLL_FB_DIV_MASK) << RADEON_SPLL_FB_DIV_SHIFT;
+    OUTPLL(pScrn, RADEON_M_SPLL_REF_FB_DIV, m_spll_ref_fb_div);
+    usleep(16000); /* Let the pll settle */
+}
+
+/* 10 khz */
+static void
+RADEONSetMemoryClock(ScrnInfoPtr pScrn, int mem_clock)
+{
+    RADEONInfoPtr  info       = RADEONPTR(pScrn);
+    RADEONPLLPtr pll = &info->pll;
+    uint32_t ref_div, fb_div;
+    uint32_t m_spll_ref_fb_div;
+
+    if (info->IsIGP)
+	return;
+
+    RADEONWaitForIdleMMIO(pScrn);
+
+    m_spll_ref_fb_div = INPLL(pScrn, RADEON_M_SPLL_REF_FB_DIV);
+    ref_div = m_spll_ref_fb_div & RADEON_M_SPLL_REF_DIV_MASK;
+    fb_div = calc_div(mem_clock * ref_div, pll->reference_freq);
+
+    if (!fb_div)
+	return;
+
+    m_spll_ref_fb_div &= ~(RADEON_MPLL_FB_DIV_MASK << RADEON_MPLL_FB_DIV_SHIFT);
+    m_spll_ref_fb_div |= (fb_div & RADEON_MPLL_FB_DIV_MASK) << RADEON_MPLL_FB_DIV_SHIFT;
+    OUTPLL(pScrn, RADEON_M_SPLL_REF_FB_DIV, m_spll_ref_fb_div);
+    usleep(16000); /* Let the pll settle */
+}
+
 static void LegacySetClockGating(ScrnInfoPtr pScrn, Bool enable)
 {
     RADEONInfoPtr  info       = RADEONPTR(pScrn);
diff --git a/src/radeon_reg.h b/src/radeon_reg.h
index d74a30a..e8af027 100644
--- a/src/radeon_reg.h
+++ b/src/radeon_reg.h
@@ -288,6 +288,13 @@
 #       define RADEON_PLL_WR_EN             (1 << 7)
 #       define RADEON_PLL_DIV_SEL           (3 << 8)
 #       define RADEON_PLL2_DIV_SEL_MASK     ~(3 << 8)
+#define RADEON_M_SPLL_REF_FB_DIV            0x000a
+#       define RADEON_M_SPLL_REF_DIV_MASK   0xff
+#       define RADEON_M_SPLL_REF_DIV_SHIFT  0
+#       define RADEON_MPLL_FB_DIV_MASK      0xff
+#       define RADEON_MPLL_FB_DIV_SHIFT     8
+#       define RADEON_SPLL_FB_DIV_MASK      0xff
+#       define RADEON_SPLL_FB_DIV_SHIFT     16
 #define RADEON_CLK_PWRMGT_CNTL              0x0014
 #       define RADEON_ENGIN_DYNCLK_MODE     (1 << 12)
 #       define RADEON_ACTIVE_HILO_LAT_MASK  (3 << 13)
commit 68e2a959ccc3d1a5d0731f1b55fdf1b2412635b2
Author: Alex Deucher <alexdeucher at gmail.com>
Date:   Tue Mar 31 17:02:45 2009 -0400

    Add unified ClockGating Option
    
    - replaces DynamicClocks Option as the name was misleading
    - unified interface for atom and com based bioses
    - fix up clock gating code for newer r3xx asics

diff --git a/man/radeon.man b/man/radeon.man
index 09239cf..9a7cf80 100644
--- a/man/radeon.man
+++ b/man/radeon.man
@@ -413,9 +413,8 @@ for CRT,
 .B RGB 
 for digital panels
 .TP
-.BI "Option \*qDynamicClocks\*q \*q" boolean \*q
-Enable dynamic clock scaling.  The on-chip clocks will scale dynamically
-based on usage. This can help reduce heat and increase battery
+.BI "Option \*qClockGating\*q \*q" boolean \*q
+Enable dynamic clock gating.  This can help reduce heat and increase battery
 life by reducing power usage.  Some users report reduced 3D performance
 with this enabled.  The default is
 .B off.
diff --git a/src/Makefile.am b/src/Makefile.am
index 7cc2a6f..1864f96 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -92,7 +92,7 @@ radeon_drv_la_SOURCES = \
 	radeon_driver.c radeon_video.c radeon_bios.c radeon_mm_i2c.c \
 	radeon_vip.c radeon_misc.c radeon_probe.c \
 	legacy_crtc.c legacy_output.c \
-	radeon_textured_video.c \
+	radeon_textured_video.c radeon_pm.c \
 	radeon_crtc.c radeon_output.c radeon_modes.c radeon_tv.c \
 	$(RADEON_ATOMBIOS_SOURCES) radeon_atombios.c radeon_atomwrapper.c \
 	$(RADEON_DRI_SRCS) $(RADEON_EXA_SOURCES) atombios_output.c atombios_crtc.c
diff --git a/src/radeon.h b/src/radeon.h
index d56d94d..60d56db 100644
--- a/src/radeon.h
+++ b/src/radeon.h
@@ -186,7 +186,7 @@ typedef enum {
     OPTION_SUBPIXEL_ORDER,
 #endif
     OPTION_SHOWCACHE,
-    OPTION_DYNAMIC_CLOCKS,
+    OPTION_CLOCK_GATING,
     OPTION_BIOS_HOTKEYS,
     OPTION_VGA_ACCESS,
     OPTION_REVERSE_DDC,
@@ -1068,6 +1068,9 @@ extern void RADEONInitMemMapRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save,
 extern void RADEONRestoreMemMapRegisters(ScrnInfoPtr pScrn,
 					 RADEONSavePtr restore);
 
+/* radeon_pm.c */
+extern void RADEONSetClockGating(ScrnInfoPtr pScrn, Bool enable);
+
 #ifdef USE_EXA
 /* radeon_exa.c */
 extern Bool RADEONSetupMemEXA(ScreenPtr pScreen);
diff --git a/src/radeon_atombios.c b/src/radeon_atombios.c
index a657fac..e32f7ba 100644
--- a/src/radeon_atombios.c
+++ b/src/radeon_atombios.c
@@ -524,7 +524,7 @@ rhdAtomASICInit(atomBiosHandlePtr handle)
 }
 
 int
-atombios_dyn_clk_setup(ScrnInfoPtr pScrn, int enable)
+atombios_clk_gating_setup(ScrnInfoPtr pScrn, Bool enable)
 {
     RADEONInfoPtr info       = RADEONPTR(pScrn);
     DYNAMIC_CLOCK_GATING_PS_ALLOCATION dynclk_data;
@@ -548,7 +548,7 @@ atombios_dyn_clk_setup(ScrnInfoPtr pScrn, int enable)
 }
 
 int
-atombios_static_pwrmgt_setup(ScrnInfoPtr pScrn, int enable)
+atombios_static_pwrmgt_setup(ScrnInfoPtr pScrn, Bool enable)
 {
     RADEONInfoPtr info       = RADEONPTR(pScrn);
     ENABLE_ASIC_STATIC_PWR_MGT_PS_ALLOCATION pwrmgt_data;
diff --git a/src/radeon_atombios.h b/src/radeon_atombios.h
index b9a5398..806df30 100644
--- a/src/radeon_atombios.h
+++ b/src/radeon_atombios.h
@@ -117,10 +117,10 @@ extern Bool
 RADEONGetATOMConnectorInfoFromBIOSConnectorTable (ScrnInfoPtr pScrn);
 
 extern int
-atombios_dyn_clk_setup(ScrnInfoPtr pScrn, int enable);
+atombios_clk_gating_setup(ScrnInfoPtr pScrn, Bool enable);
 
 extern int
-atombios_static_pwrmgt_setup(ScrnInfoPtr pScrn, int enable);
+atombios_static_pwrmgt_setup(ScrnInfoPtr pScrn, Bool enable);
 
 extern Bool
 RADEONGetATOMTVInfo(xf86OutputPtr output);
diff --git a/src/radeon_driver.c b/src/radeon_driver.c
index f1991e8..fe00dd7 100644
--- a/src/radeon_driver.c
+++ b/src/radeon_driver.c
@@ -118,8 +118,6 @@ static Bool RADEONCloseScreen(int scrnIndex, ScreenPtr pScreen);
 static Bool RADEONSaveScreen(ScreenPtr pScreen, int mode);
 static void RADEONSave(ScrnInfoPtr pScrn);
 
-static void RADEONSetDynamicClock(ScrnInfoPtr pScrn, int mode);
-static void RADEONForceSomeClocks(ScrnInfoPtr pScrn);
 static void RADEONSaveMemMapRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save);
 
 static void
@@ -176,7 +174,7 @@ static const OptionInfoRec RADEONOptions[] = {
     { OPTION_SUBPIXEL_ORDER, "SubPixelOrder",    OPTV_ANYSTR,  {0}, FALSE },
 #endif
     { OPTION_SHOWCACHE,      "ShowCache",        OPTV_BOOLEAN, {0}, FALSE },
-    { OPTION_DYNAMIC_CLOCKS, "DynamicClocks",    OPTV_BOOLEAN, {0}, FALSE },
+    { OPTION_CLOCK_GATING,   "ClockGating",      OPTV_BOOLEAN, {0}, FALSE },
     { OPTION_VGA_ACCESS,     "VGAAccess",        OPTV_BOOLEAN, {0}, TRUE  },
     { OPTION_REVERSE_DDC,    "ReverseDDC",       OPTV_BOOLEAN, {0}, FALSE },
     { OPTION_LVDS_PROBE_PLL, "LVDSProbePLL",     OPTV_BOOLEAN, {0}, FALSE },
@@ -3330,21 +3328,10 @@ Bool RADEONScreenInit(int scrnIndex, ScreenPtr pScreen,
     /* blank the outputs/crtcs */
     RADEONBlank(pScrn);
 
-    if (info->IsMobility && !IS_AVIVO_VARIANT) {
-	if (xf86ReturnOptValBool(info->Options, OPTION_DYNAMIC_CLOCKS, FALSE)) {
-	    RADEONSetDynamicClock(pScrn, 1);
-	} else {
-	    RADEONSetDynamicClock(pScrn, 0);
-	}
-    } else if (IS_AVIVO_VARIANT) {
-	if (xf86ReturnOptValBool(info->Options, OPTION_DYNAMIC_CLOCKS, FALSE)) {
-	    atombios_static_pwrmgt_setup(pScrn, 1);
-	    atombios_dyn_clk_setup(pScrn, 1);
-	}
-    }
-
-    if (IS_R300_VARIANT || IS_RV100_VARIANT)
-	RADEONForceSomeClocks(pScrn);
+    if (xf86ReturnOptValBool(info->Options, OPTION_CLOCK_GATING, FALSE))
+	RADEONSetClockGating(pScrn, TRUE);
+    else
+	RADEONSetClockGating(pScrn, FALSE);
 
     if (info->allowColorTiling && (pScrn->virtualX > info->MaxSurfaceWidth)) {
 	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
@@ -5601,21 +5588,10 @@ Bool RADEONEnterVT(int scrnIndex, int flags)
     /* Makes sure the engine is idle before doing anything */
     RADEONWaitForIdleMMIO(pScrn);
 
-    if (info->IsMobility && !IS_AVIVO_VARIANT) {
-	if (xf86ReturnOptValBool(info->Options, OPTION_DYNAMIC_CLOCKS, FALSE)) {
-	    RADEONSetDynamicClock(pScrn, 1);
-	} else {
-	    RADEONSetDynamicClock(pScrn, 0);
-	}
-    } else if (IS_AVIVO_VARIANT) {
-	if (xf86ReturnOptValBool(info->Options, OPTION_DYNAMIC_CLOCKS, FALSE)) {
-	    atombios_static_pwrmgt_setup(pScrn, 1);
-	    atombios_dyn_clk_setup(pScrn, 1);
-	}
-    }
-
-    if (IS_R300_VARIANT || IS_RV100_VARIANT)
-	RADEONForceSomeClocks(pScrn);
+    if (xf86ReturnOptValBool(info->Options, OPTION_CLOCK_GATING, FALSE))
+	RADEONSetClockGating(pScrn, TRUE);
+    else
+	RADEONSetClockGating(pScrn, FALSE);
 
     for (i = 0; i < config->num_crtc; i++)
 	radeon_crtc_modeset_ioctl(config->crtc[i], TRUE);
@@ -5874,362 +5850,3 @@ void RADEONFreeScreen(int scrnIndex, int flags)
 #endif
     RADEONFreeRec(pScrn);
 }
-
-static void RADEONForceSomeClocks(ScrnInfoPtr pScrn)
-{
-    /* It appears from r300 and rv100 may need some clocks forced-on */
-     uint32_t tmp;
-
-     tmp = INPLL(pScrn, RADEON_SCLK_CNTL);
-     tmp |= RADEON_SCLK_FORCE_CP | RADEON_SCLK_FORCE_VIP;
-     OUTPLL(pScrn, RADEON_SCLK_CNTL, tmp);
-}
-
-static void RADEONSetDynamicClock(ScrnInfoPtr pScrn, int mode)
-{
-    RADEONInfoPtr  info       = RADEONPTR(pScrn);
-    RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
-    unsigned char *RADEONMMIO = info->MMIO;
-    uint32_t tmp;
-    switch(mode) {
-        case 0: /* Turn everything OFF (ForceON to everything)*/
-            if ( !pRADEONEnt->HasCRTC2 ) {
-                tmp = INPLL(pScrn, 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);
-                OUTPLL(pScrn, RADEON_SCLK_CNTL, tmp);
-            } else if (info->ChipFamily == CHIP_FAMILY_RV350) {
-                /* for RV350/M10, no delays are required. */
-                tmp = INPLL(pScrn, R300_SCLK_CNTL2);
-                tmp |= (R300_SCLK_FORCE_TCL |
-                        R300_SCLK_FORCE_GA  |
-			R300_SCLK_FORCE_CBA);
-                OUTPLL(pScrn, R300_SCLK_CNTL2, tmp);
-
-                tmp = INPLL(pScrn, 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);
-                OUTPLL(pScrn, RADEON_SCLK_CNTL, tmp);
-
-                tmp = INPLL(pScrn, RADEON_SCLK_MORE_CNTL);
-                tmp |= RADEON_SCLK_MORE_FORCEON;
-                OUTPLL(pScrn, RADEON_SCLK_MORE_CNTL, tmp);
-
-                tmp = INPLL(pScrn, RADEON_MCLK_CNTL);
-                tmp |= (RADEON_FORCEON_MCLKA |
-                        RADEON_FORCEON_MCLKB |
-                        RADEON_FORCEON_YCLKA |
-			RADEON_FORCEON_YCLKB |
-                        RADEON_FORCEON_MC);
-                OUTPLL(pScrn, RADEON_MCLK_CNTL, tmp);
-
-                tmp = INPLL(pScrn, RADEON_VCLK_ECP_CNTL);
-                tmp &= ~(RADEON_PIXCLK_ALWAYS_ONb  | 
-                         RADEON_PIXCLK_DAC_ALWAYS_ONb | 
-			 R300_DISP_DAC_PIXCLK_DAC_BLANK_OFF); 
-                OUTPLL(pScrn, RADEON_VCLK_ECP_CNTL, tmp);
-
-                tmp = INPLL(pScrn, 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_ALWAYS_ONb           | 
-			 R300_DISP_DAC_PIXCLK_DAC2_BLANK_OFF); 
-                OUTPLL(pScrn, RADEON_PIXCLKS_CNTL, tmp);
-            }  else {
-                tmp = INPLL(pScrn, RADEON_SCLK_CNTL);
-                tmp |= (RADEON_SCLK_FORCE_CP | RADEON_SCLK_FORCE_E2);
-                tmp |= RADEON_SCLK_FORCE_SE;
-
-		if ( !pRADEONEnt->HasCRTC2 ) {
-                     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 ((info->ChipFamily == CHIP_FAMILY_R300) ||
-			   (info->ChipFamily == CHIP_FAMILY_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);
-		}
-                OUTPLL(pScrn, RADEON_SCLK_CNTL, tmp);
-            
-                usleep(16000);
-
-		if ((info->ChipFamily == CHIP_FAMILY_R300) ||
-		    (info->ChipFamily == CHIP_FAMILY_R350)) {
-                    tmp = INPLL(pScrn, R300_SCLK_CNTL2);
-                    tmp |= ( R300_SCLK_FORCE_TCL |
-			     R300_SCLK_FORCE_GA  |
-			     R300_SCLK_FORCE_CBA);
-                    OUTPLL(pScrn, R300_SCLK_CNTL2, tmp);
-		    usleep(16000);
-		}
-
-                if (info->IsIGP) {
-                    tmp = INPLL(pScrn, RADEON_MCLK_CNTL);
-                    tmp &= ~(RADEON_FORCEON_MCLKA |
-			     RADEON_FORCEON_YCLKA);
-                    OUTPLL(pScrn, RADEON_MCLK_CNTL, tmp);
-		    usleep(16000);
-		}
-  
-		if ((info->ChipFamily == CHIP_FAMILY_RV200) ||
-		    (info->ChipFamily == CHIP_FAMILY_RV250) ||
-		    (info->ChipFamily == CHIP_FAMILY_RV280)) {
-                    tmp = INPLL(pScrn, RADEON_SCLK_MORE_CNTL);
-		    tmp |= RADEON_SCLK_MORE_FORCEON;
-                    OUTPLL(pScrn, RADEON_SCLK_MORE_CNTL, tmp);
-		    usleep(16000);
-		}
-
-                tmp = INPLL(pScrn, 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);
-
-		OUTPLL(pScrn, RADEON_PIXCLKS_CNTL, tmp);
-		usleep(16000);
-
-                tmp = INPLL(pScrn, RADEON_VCLK_ECP_CNTL);
-                tmp &= ~(RADEON_PIXCLK_ALWAYS_ONb  |
-			 RADEON_PIXCLK_DAC_ALWAYS_ONb); 
-                OUTPLL(pScrn, RADEON_VCLK_ECP_CNTL, tmp);
-	    }
-	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Dynamic Clock Scaling Disabled\n");
-            break;
-        case 1:
-            if (!pRADEONEnt->HasCRTC2) {
-                tmp = INPLL(pScrn, RADEON_SCLK_CNTL);
-		if ((INREG(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);
-                OUTPLL(pScrn, RADEON_SCLK_CNTL, tmp);
-	    } else if ((info->ChipFamily == CHIP_FAMILY_R300) ||
-		       (info->ChipFamily == CHIP_FAMILY_R350) ||
-		       (info->ChipFamily == CHIP_FAMILY_RV350)) {
-		if (info->ChipFamily == CHIP_FAMILY_RV350) {
-		    tmp = INPLL(pScrn, 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);
-		    OUTPLL(pScrn, R300_SCLK_CNTL2, tmp);
-
-		    tmp = INPLL(pScrn, 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;
-		    OUTPLL(pScrn, RADEON_SCLK_CNTL, tmp);
-
-		    tmp = INPLL(pScrn, RADEON_SCLK_MORE_CNTL);
-		    tmp &= ~RADEON_SCLK_MORE_FORCEON;
-		    tmp |=  RADEON_SCLK_MORE_MAX_DYN_STOP_LAT;
-		    OUTPLL(pScrn, RADEON_SCLK_MORE_CNTL, tmp);
-
-		    tmp = INPLL(pScrn, RADEON_VCLK_ECP_CNTL);
-		    tmp |= (RADEON_PIXCLK_ALWAYS_ONb |
-			    RADEON_PIXCLK_DAC_ALWAYS_ONb);   
-		    OUTPLL(pScrn, RADEON_VCLK_ECP_CNTL, tmp);
-
-		    tmp = INPLL(pScrn, 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_ALWAYS_ONb);
-		    OUTPLL(pScrn, RADEON_PIXCLKS_CNTL, tmp);
-
-		    tmp = INPLL(pScrn, RADEON_MCLK_MISC);
-		    tmp |= (RADEON_MC_MCLK_DYN_ENABLE |
-			    RADEON_IO_MCLK_DYN_ENABLE);
-		    OUTPLL(pScrn, RADEON_MCLK_MISC, tmp);
-
-		    tmp = INPLL(pScrn, 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 = INPLL(pScrn, RADEON_MCLK_CNTL);
-			if (info->RamWidth == 64) {
-			    if (INREG(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);
-			}
-		    }
-
-		    OUTPLL(pScrn, RADEON_MCLK_CNTL, tmp);
-		} else {
-		    tmp = INPLL(pScrn, RADEON_SCLK_CNTL);
-		    tmp &= ~(R300_SCLK_FORCE_VAP);
-		    tmp |= RADEON_SCLK_FORCE_CP;
-		    OUTPLL(pScrn, RADEON_SCLK_CNTL, tmp);
-		    usleep(15000);
-
-		    tmp = INPLL(pScrn, R300_SCLK_CNTL2);
-		    tmp &= ~(R300_SCLK_FORCE_TCL |
-			     R300_SCLK_FORCE_GA  |
-			     R300_SCLK_FORCE_CBA);
-		    OUTPLL(pScrn, R300_SCLK_CNTL2, tmp);
-		}
-	    } else {
-                tmp = INPLL(pScrn, 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));
-                OUTPLL(pScrn, RADEON_CLK_PWRMGT_CNTL, tmp);
-		usleep(15000);
-
-                tmp = INPLL(pScrn, RADEON_CLK_PIN_CNTL);
-                tmp |= RADEON_SCLK_DYN_START_CNTL; 
-                OUTPLL(pScrn, RADEON_CLK_PIN_CNTL, tmp);
-		usleep(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 = INPLL(pScrn, 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 (((info->ChipFamily == CHIP_FAMILY_RV250) &&
-		     ((INREG(RADEON_CONFIG_CNTL) & RADEON_CFG_ATI_REV_ID_MASK) <
-		      RADEON_CFG_ATI_REV_A13)) || 
-		    ((info->ChipFamily == CHIP_FAMILY_RV100) &&
-		     ((INREG(RADEON_CONFIG_CNTL) & RADEON_CFG_ATI_REV_ID_MASK) <=
-		      RADEON_CFG_ATI_REV_A13))){
-                    tmp |= RADEON_SCLK_FORCE_CP;
-                    tmp |= RADEON_SCLK_FORCE_VIP;
-                }
-
-                OUTPLL(pScrn, RADEON_SCLK_CNTL, tmp);
-
-		if ((info->ChipFamily == CHIP_FAMILY_RV200) ||
-		    (info->ChipFamily == CHIP_FAMILY_RV250) ||
-		    (info->ChipFamily == CHIP_FAMILY_RV280)) {
-                    tmp = INPLL(pScrn, RADEON_SCLK_MORE_CNTL);
-                    tmp &= ~RADEON_SCLK_MORE_FORCEON;
-
-                    /* RV200::A11 A12 RV250::A11 A12 */
-		    if (((info->ChipFamily == CHIP_FAMILY_RV200) ||
-			 (info->ChipFamily == CHIP_FAMILY_RV250)) &&
-			((INREG(RADEON_CONFIG_CNTL) & RADEON_CFG_ATI_REV_ID_MASK) <
-			 RADEON_CFG_ATI_REV_A13)) {
-                        tmp |= RADEON_SCLK_MORE_FORCEON;
-		    }
-                    OUTPLL(pScrn, RADEON_SCLK_MORE_CNTL, tmp);
-		    usleep(15000);
-                }
-
-                /* RV200::A11 A12, RV250::A11 A12 */
-                if (((info->ChipFamily == CHIP_FAMILY_RV200) ||
-		     (info->ChipFamily == CHIP_FAMILY_RV250)) &&
-		    ((INREG(RADEON_CONFIG_CNTL) & RADEON_CFG_ATI_REV_ID_MASK) <
-		     RADEON_CFG_ATI_REV_A13)) {
-                    tmp = INPLL(pScrn, RADEON_PLL_PWRMGT_CNTL);
-                    tmp |= RADEON_TCL_BYPASS_DISABLE;
-                    OUTPLL(pScrn, RADEON_PLL_PWRMGT_CNTL, tmp);
-                }
-		usleep(15000);
-
-                /*enable dynamic mode for display clocks (PIXCLK and PIX2CLK)*/
-		tmp = INPLL(pScrn, 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);
-
-		OUTPLL(pScrn, RADEON_PIXCLKS_CNTL, tmp);
-		usleep(15000);
-
-		tmp = INPLL(pScrn, RADEON_VCLK_ECP_CNTL);
-		tmp |= (RADEON_PIXCLK_ALWAYS_ONb  |
-		        RADEON_PIXCLK_DAC_ALWAYS_ONb); 
-
-                OUTPLL(pScrn, RADEON_VCLK_ECP_CNTL, tmp);
-		usleep(15000);
-            }    
-	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Dynamic Clock Scaling Enabled\n");
-	    break;
-        default:
-	    break;
-    }
-}
diff --git a/src/radeon_pm.c b/src/radeon_pm.c
new file mode 100644
index 0000000..4f3f4c7
--- /dev/null
+++ b/src/radeon_pm.c
@@ -0,0 +1,416 @@
+/*
+ * Copyright 2009 Advanced Micro Devices, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * 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 on 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 (including the
+ * next paragraph) 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
+ * NON-INFRINGEMENT.  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.
+ *
+ * Author: Alex Deucher <alexander.deucher at amd.com>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+				/* Driver data structures */
+#include "radeon.h"
+#include "radeon_reg.h"
+#include "radeon_macros.h"
+#include "radeon_atombios.h"
+
+static void LegacySetClockGating(ScrnInfoPtr pScrn, Bool enable)
+{
+    RADEONInfoPtr  info       = RADEONPTR(pScrn);
+    RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
+    unsigned char *RADEONMMIO = info->MMIO;
+    uint32_t tmp;
+
+    if (enable) {
+	if (!pRADEONEnt->HasCRTC2) {
+	    tmp = INPLL(pScrn, RADEON_SCLK_CNTL);
+	    if ((INREG(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);
+	    OUTPLL(pScrn, RADEON_SCLK_CNTL, tmp);
+	} else if (IS_R300_VARIANT) {
+	    if (info->ChipFamily >= CHIP_FAMILY_RV350) {
+		tmp = INPLL(pScrn, 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);
+		OUTPLL(pScrn, R300_SCLK_CNTL2, tmp);
+
+		tmp = INPLL(pScrn, 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;
+		OUTPLL(pScrn, RADEON_SCLK_CNTL, tmp);
+
+		tmp = INPLL(pScrn, RADEON_SCLK_MORE_CNTL);
+		tmp &= ~RADEON_SCLK_MORE_FORCEON;
+		tmp |=  RADEON_SCLK_MORE_MAX_DYN_STOP_LAT;
+		OUTPLL(pScrn, RADEON_SCLK_MORE_CNTL, tmp);
+
+		tmp = INPLL(pScrn, RADEON_VCLK_ECP_CNTL);
+		tmp |= (RADEON_PIXCLK_ALWAYS_ONb |
+			RADEON_PIXCLK_DAC_ALWAYS_ONb);
+		OUTPLL(pScrn, RADEON_VCLK_ECP_CNTL, tmp);
+
+		tmp = INPLL(pScrn, 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_ALWAYS_ONb);
+		OUTPLL(pScrn, RADEON_PIXCLKS_CNTL, tmp);
+
+		tmp = INPLL(pScrn, RADEON_MCLK_MISC);
+		tmp |= (RADEON_MC_MCLK_DYN_ENABLE |
+			RADEON_IO_MCLK_DYN_ENABLE);
+		OUTPLL(pScrn, RADEON_MCLK_MISC, tmp);
+
+		tmp = INPLL(pScrn, 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 = INPLL(pScrn, RADEON_MCLK_CNTL);
+		    if (info->RamWidth == 64) {
+			if (INREG(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);
+		    }
+		}
+
+		OUTPLL(pScrn, RADEON_MCLK_CNTL, tmp);
+	    } else {
+		tmp = INPLL(pScrn, RADEON_SCLK_CNTL);
+		tmp &= ~(R300_SCLK_FORCE_VAP);
+		tmp |= RADEON_SCLK_FORCE_CP;
+		OUTPLL(pScrn, RADEON_SCLK_CNTL, tmp);
+		usleep(15000);
+
+		tmp = INPLL(pScrn, R300_SCLK_CNTL2);
+		tmp &= ~(R300_SCLK_FORCE_TCL |
+			 R300_SCLK_FORCE_GA  |
+			 R300_SCLK_FORCE_CBA);
+		OUTPLL(pScrn, R300_SCLK_CNTL2, tmp);
+	    }
+	} else {
+	    tmp = INPLL(pScrn, 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));
+	    OUTPLL(pScrn, RADEON_CLK_PWRMGT_CNTL, tmp);
+	    usleep(15000);
+
+	    tmp = INPLL(pScrn, RADEON_CLK_PIN_CNTL);
+	    tmp |= RADEON_SCLK_DYN_START_CNTL;
+	    OUTPLL(pScrn, RADEON_CLK_PIN_CNTL, tmp);
+	    usleep(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 = INPLL(pScrn, 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 (((info->ChipFamily == CHIP_FAMILY_RV250) &&
+		 ((INREG(RADEON_CONFIG_CNTL) & RADEON_CFG_ATI_REV_ID_MASK) <
+		  RADEON_CFG_ATI_REV_A13)) ||
+		((info->ChipFamily == CHIP_FAMILY_RV100) &&
+		 ((INREG(RADEON_CONFIG_CNTL) & RADEON_CFG_ATI_REV_ID_MASK) <=
+		  RADEON_CFG_ATI_REV_A13))) {
+		tmp |= RADEON_SCLK_FORCE_CP;
+		tmp |= RADEON_SCLK_FORCE_VIP;
+	    }
+
+	    OUTPLL(pScrn, RADEON_SCLK_CNTL, tmp);
+
+	    if ((info->ChipFamily == CHIP_FAMILY_RV200) ||
+		(info->ChipFamily == CHIP_FAMILY_RV250) ||
+		(info->ChipFamily == CHIP_FAMILY_RV280)) {
+		tmp = INPLL(pScrn, RADEON_SCLK_MORE_CNTL);
+		tmp &= ~RADEON_SCLK_MORE_FORCEON;
+
+		/* RV200::A11 A12 RV250::A11 A12 */
+		if (((info->ChipFamily == CHIP_FAMILY_RV200) ||
+		     (info->ChipFamily == CHIP_FAMILY_RV250)) &&
+		    ((INREG(RADEON_CONFIG_CNTL) & RADEON_CFG_ATI_REV_ID_MASK) <
+		     RADEON_CFG_ATI_REV_A13)) {
+		    tmp |= RADEON_SCLK_MORE_FORCEON;
+		}
+		OUTPLL(pScrn, RADEON_SCLK_MORE_CNTL, tmp);
+		usleep(15000);
+	    }
+
+	    /* RV200::A11 A12, RV250::A11 A12 */
+	    if (((info->ChipFamily == CHIP_FAMILY_RV200) ||
+		 (info->ChipFamily == CHIP_FAMILY_RV250)) &&
+		((INREG(RADEON_CONFIG_CNTL) & RADEON_CFG_ATI_REV_ID_MASK) <
+		 RADEON_CFG_ATI_REV_A13)) {
+		tmp = INPLL(pScrn, RADEON_PLL_PWRMGT_CNTL);
+		tmp |= RADEON_TCL_BYPASS_DISABLE;
+		OUTPLL(pScrn, RADEON_PLL_PWRMGT_CNTL, tmp);
+	    }
+	    usleep(15000);
+
+	    /*enable dynamic mode for display clocks (PIXCLK and PIX2CLK)*/
+	    tmp = INPLL(pScrn, 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);
+
+	    OUTPLL(pScrn, RADEON_PIXCLKS_CNTL, tmp);
+	    usleep(15000);
+
+	    tmp = INPLL(pScrn, RADEON_VCLK_ECP_CNTL);
+	    tmp |= (RADEON_PIXCLK_ALWAYS_ONb  |
+		    RADEON_PIXCLK_DAC_ALWAYS_ONb);
+
+	    OUTPLL(pScrn, RADEON_VCLK_ECP_CNTL, tmp);
+	    usleep(15000);
+	}
+    } else {
+	/* Turn everything OFF (ForceON to everything)*/
+	if ( !pRADEONEnt->HasCRTC2 ) {
+	    tmp = INPLL(pScrn, 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);
+	    OUTPLL(pScrn, RADEON_SCLK_CNTL, tmp);
+	} else if (info->ChipFamily >= CHIP_FAMILY_RV350) {
+	    /* for RV350/M10, no delays are required. */
+	    tmp = INPLL(pScrn, R300_SCLK_CNTL2);
+	    tmp |= (R300_SCLK_FORCE_TCL |
+		    R300_SCLK_FORCE_GA  |
+		    R300_SCLK_FORCE_CBA);
+	    OUTPLL(pScrn, R300_SCLK_CNTL2, tmp);
+
+	    tmp = INPLL(pScrn, 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);
+	    OUTPLL(pScrn, RADEON_SCLK_CNTL, tmp);
+
+	    tmp = INPLL(pScrn, RADEON_SCLK_MORE_CNTL);
+	    tmp |= RADEON_SCLK_MORE_FORCEON;
+	    OUTPLL(pScrn, RADEON_SCLK_MORE_CNTL, tmp);
+
+	    tmp = INPLL(pScrn, RADEON_MCLK_CNTL);
+	    tmp |= (RADEON_FORCEON_MCLKA |
+		    RADEON_FORCEON_MCLKB |
+		    RADEON_FORCEON_YCLKA |
+		    RADEON_FORCEON_YCLKB |
+		    RADEON_FORCEON_MC);
+	    OUTPLL(pScrn, RADEON_MCLK_CNTL, tmp);
+
+	    tmp = INPLL(pScrn, RADEON_VCLK_ECP_CNTL);
+	    tmp &= ~(RADEON_PIXCLK_ALWAYS_ONb  |
+		     RADEON_PIXCLK_DAC_ALWAYS_ONb |
+		     R300_DISP_DAC_PIXCLK_DAC_BLANK_OFF);
+	    OUTPLL(pScrn, RADEON_VCLK_ECP_CNTL, tmp);
+
+	    tmp = INPLL(pScrn, 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_ALWAYS_ONb           |
+		     R300_DISP_DAC_PIXCLK_DAC2_BLANK_OFF);
+	    OUTPLL(pScrn, RADEON_PIXCLKS_CNTL, tmp);
+	}  else {
+	    tmp = INPLL(pScrn, RADEON_SCLK_CNTL);
+	    tmp |= (RADEON_SCLK_FORCE_CP | RADEON_SCLK_FORCE_E2);
+	    tmp |= RADEON_SCLK_FORCE_SE;
+
+	    if ( !pRADEONEnt->HasCRTC2 ) {
+		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 ((info->ChipFamily == CHIP_FAMILY_R300) ||
+		       (info->ChipFamily == CHIP_FAMILY_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);
+	    }
+	    OUTPLL(pScrn, RADEON_SCLK_CNTL, tmp);
+
+	    usleep(16000);
+
+	    if ((info->ChipFamily == CHIP_FAMILY_R300) ||
+		(info->ChipFamily == CHIP_FAMILY_R350)) {
+		tmp = INPLL(pScrn, R300_SCLK_CNTL2);
+		tmp |= ( R300_SCLK_FORCE_TCL |
+			 R300_SCLK_FORCE_GA  |
+			 R300_SCLK_FORCE_CBA);
+		OUTPLL(pScrn, R300_SCLK_CNTL2, tmp);
+		usleep(16000);
+	    }
+
+	    if (info->IsIGP) {
+		tmp = INPLL(pScrn, RADEON_MCLK_CNTL);
+		tmp &= ~(RADEON_FORCEON_MCLKA |
+			 RADEON_FORCEON_YCLKA);
+		OUTPLL(pScrn, RADEON_MCLK_CNTL, tmp);
+		usleep(16000);
+	    }
+
+	    if ((info->ChipFamily == CHIP_FAMILY_RV200) ||
+		(info->ChipFamily == CHIP_FAMILY_RV250) ||
+		(info->ChipFamily == CHIP_FAMILY_RV280)) {
+		tmp = INPLL(pScrn, RADEON_SCLK_MORE_CNTL);
+		tmp |= RADEON_SCLK_MORE_FORCEON;
+		OUTPLL(pScrn, RADEON_SCLK_MORE_CNTL, tmp);
+		usleep(16000);
+	    }
+
+	    tmp = INPLL(pScrn, 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);
+
+	    OUTPLL(pScrn, RADEON_PIXCLKS_CNTL, tmp);
+	    usleep(16000);
+
+	    tmp = INPLL(pScrn, RADEON_VCLK_ECP_CNTL);
+	    tmp &= ~(RADEON_PIXCLK_ALWAYS_ONb  |
+		     RADEON_PIXCLK_DAC_ALWAYS_ONb);
+	    OUTPLL(pScrn, RADEON_VCLK_ECP_CNTL, tmp);
+	}
+    }
+}
+
+void RADEONForceSomeClocks(ScrnInfoPtr pScrn)
+{
+    /* It appears from r300 and rv100 may need some clocks forced-on */
+     uint32_t tmp;
+
+     tmp = INPLL(pScrn, RADEON_SCLK_CNTL);
+     tmp |= RADEON_SCLK_FORCE_CP | RADEON_SCLK_FORCE_VIP;
+     OUTPLL(pScrn, RADEON_SCLK_CNTL, tmp);
+}
+
+void
+RADEONSetClockGating(ScrnInfoPtr pScrn, Bool enable)
+{
+    RADEONInfoPtr  info       = RADEONPTR(pScrn);
+
+    RADEONWaitForIdleMMIO(pScrn);
+
+    if (info->ChipFamily >= CHIP_FAMILY_R600)
+	atombios_static_pwrmgt_setup(pScrn, enable);
+    else {
+	if (info->IsAtomBios) {
+	    atombios_static_pwrmgt_setup(pScrn, enable);
+	    atombios_clk_gating_setup(pScrn, enable);
+	} else if (info->IsMobility)
+	    LegacySetClockGating(pScrn, enable);
+
+	if (IS_R300_VARIANT || IS_RV100_VARIANT)
+	    RADEONForceSomeClocks(pScrn);
+    }
+
+    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Dynamic Clock Gating %sabled\n",
+	       enable ? "En" : "Dis");
+}
+


More information about the xorg-commit mailing list