summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/radeon.h35
-rw-r--r--src/radeon_atombios.c4
-rw-r--r--src/radeon_atombios.h4
-rw-r--r--src/radeon_driver.c41
-rw-r--r--src/radeon_pm.c171
5 files changed, 146 insertions, 109 deletions
diff --git a/src/radeon.h b/src/radeon.h
index c1ad2c3e..7e84aebc 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 f6fe9615..e2348a43 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 69e27a34..b81cbbbd 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 8e70e654..105a9f39 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 41b797a8..2fcf45a4 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");
-}