Mailinglist Archive: radeonhd (312 mails)

< Previous Next >
[radeonhd] [PATCH] ForceLowPowerMode
  • From: Yang Zhao <yang@xxxxxxxxxx>
  • Date: Fri, 17 Apr 2009 16:40:34 -0700
  • Message-id: <40a7b1aa0904171640n58231d4frd0610a891e8b636f@xxxxxxxxxxxxxx>
Hi all,

I've been sitting on some AtomBIOS based simple power management code
for a while. Since similar code has been deemed safe enough to push to
radeon, I figure I'd do the same for radeonhd.

The attached set of patches adds ForceLowPowerMode and
LowPowerModeEngineClock options. Set them in the Device section of
your xorg.conf as usual.

* ForceLowPowerMode statically sets the engine clock at initiation
time to a low value; defaults to (default_engine_clock / 2).
* If the above value isn't what you want, or breaks, specify a clock
value to use with LowPowerModeEngineClock. See Catalyst for the range
of what's considered safe by the OEM.

The wait-for-idle code for radeonhd is more fine grained and is not
actually exposed in its entirety, so the current RHDSetEngineClock()
and RHDSetMemoryClock() do not work reliably outside of init time.
This is why DPMS-driven downclocking was not implemented.

As always, play with clock values at your own discretion.

Cheers,
--
Yang Zhao
http://yangman.ca
From 01140fffec02f6aa84d8ad6316a3f42d3e6e993c Mon Sep 17 00:00:00 2001
From: Yang Zhao <yang@xxxxxxxxxx>
Date: Sat, 7 Mar 2009 13:05:44 -0800
Subject: [PATCH] AtomBIOS: add hooks to call memory and engine clock getters
and setters


Signed-off-by: Yang Zhao <yang@xxxxxxxxxx>
---
src/rhd_atombios.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++
src/rhd_atombios.h | 5 +++
2 files changed, 83 insertions(+), 0 deletions(-)

diff --git a/src/rhd_atombios.c b/src/rhd_atombios.c
index a285e48..c055c6c 100644
--- a/src/rhd_atombios.c
+++ b/src/rhd_atombios.c
@@ -126,6 +126,11 @@ atomSetRegisterListLocation(atomBiosHandlePtr handle,
AtomBiosRequestID func, At
static AtomBiosResult
atomRestoreRegisters(atomBiosHandlePtr handle, AtomBiosRequestID func,
AtomBiosArgPtr data);

+static AtomBiosResult
+rhdAtomSetClock(atomBiosHandlePtr handle, AtomBiosRequestID func,
AtomBiosArgPtr data);
+static AtomBiosResult
+rhdAtomGetClock(atomBiosHandlePtr handle, AtomBiosRequestID func,
AtomBiosArgPtr data);
+

enum msgDataFormat {
MSG_FORMAT_NONE,
@@ -270,6 +275,14 @@ struct atomBIOSRequests {
"Register List Location", MSG_FORMAT_NONE},
{ATOM_RESTORE_REGISTERS, atomRestoreRegisters,
"Restore Registers", MSG_FORMAT_NONE},
+ {GET_ENGINE_CLOCK, rhdAtomGetClock,
+ "Current Engine Clock", MSG_FORMAT_DEC},
+ {GET_MEMORY_CLOCK, rhdAtomGetClock,
+ "Current Memory Clock", MSG_FORMAT_DEC},
+ {SET_ENGINE_CLOCK, rhdAtomSetClock,
+ "Set Engine Clock", MSG_FORMAT_NONE},
+ {SET_MEMORY_CLOCK, rhdAtomSetClock,
+ "Set Memory Clock", MSG_FORMAT_NONE},
{FUNC_END, NULL,
NULL, MSG_FORMAT_NONE}
};
@@ -5099,6 +5112,71 @@ atomRestoreRegisters(atomBiosHandlePtr handle,
AtomBiosRequestID func, AtomBiosA
return ATOM_SUCCESS;
}

+static AtomBiosResult
+rhdAtomGetClock(atomBiosHandlePtr handle, AtomBiosRequestID func,
AtomBiosArgPtr data)
+{
+ AtomBiosArgRec idx;
+ GET_ENGINE_CLOCK_PARAMETERS eng_p;
+ GET_MEMORY_CLOCK_PARAMETERS mem_p;
+
+ RHDFUNC(handle);
+
+ idx.exec.dataSpace = NULL;
+
+ if (func == GET_ENGINE_CLOCK) {
+ idx.exec.index = GetIndexIntoMasterTable(COMMAND, GetEngineClock);
+ idx.exec.pspace = &eng_p;
+ } else if (func == GET_MEMORY_CLOCK) {
+ idx.exec.index = GetIndexIntoMasterTable(COMMAND, GetMemoryClock);
+ idx.exec.pspace = &mem_p;
+ } else
+ return ATOM_NOT_IMPLEMENTED;
+
+ if (RHDAtomBiosFunc(handle->scrnIndex, handle,
+ ATOMBIOS_EXEC, &idx) == ATOM_SUCCESS) {
+ data->val = (func == GET_ENGINE_CLOCK) ?
+ eng_p.ulReturnEngineClock :
+ mem_p.ulReturnMemoryClock;
+ data->val *= 10;
+ return ATOM_SUCCESS;
+ }
+
+ return ATOM_FAILED;
+}
+
+static AtomBiosResult
+rhdAtomSetClock(atomBiosHandlePtr handle, AtomBiosRequestID func,
AtomBiosArgPtr data)
+{
+ AtomBiosArgRec execData;
+ SET_ENGINE_CLOCK_PS_ALLOCATION eng_clock_ps;
+ SET_MEMORY_CLOCK_PS_ALLOCATION mem_clock_ps;
+
+ RHDFUNC(handle);
+ execData.exec.dataSpace = NULL;
+
+ if (func == SET_ENGINE_CLOCK) {
+ eng_clock_ps.ulTargetEngineClock = data->clockValue / 10;
+ execData.exec.index = GetIndexIntoMasterTable(COMMAND, SetEngineClock);
+ execData.exec.pspace = &eng_clock_ps;
+ xf86DrvMsg(handle->scrnIndex, X_INFO, "Attempting to set Engine Clock
to %lu\n", data->clockValue);
+ } else if (func == SET_MEMORY_CLOCK) {
+ mem_clock_ps.ulTargetMemoryClock = data->clockValue / 10;
+ execData.exec.index = GetIndexIntoMasterTable(COMMAND, SetMemoryClock);
+ execData.exec.pspace = &mem_clock_ps;
+ xf86DrvMsg(handle->scrnIndex, X_INFO, "Attempting to set Memory Clock
to %lu\n", data->clockValue);
+ } else
+ return ATOM_NOT_IMPLEMENTED;
+
+ if (RHDAtomBiosFunc(handle->scrnIndex, handle,
+ ATOMBIOS_EXEC, &execData) == ATOM_SUCCESS) {
+ return ATOM_SUCCESS;
+ }
+
+ xf86DrvMsg(handle->scrnIndex, X_WARNING, "Failed to set %s Clock\n",
+ (func == SET_ENGINE_CLOCK) ? "Engine" : "Memory");
+ return ATOM_FAILED;
+}
+
# ifdef ATOM_BIOS_PARSER

#define ALLOC_CNT 25
diff --git a/src/rhd_atombios.h b/src/rhd_atombios.h
index 56e4a39..c1b73c4 100644
--- a/src/rhd_atombios.h
+++ b/src/rhd_atombios.h
@@ -101,6 +101,10 @@ typedef enum _AtomBiosRequestID {
ATOM_GET_PCIE_LANES,
ATOM_SET_REGISTER_LIST_LOCATION,
ATOM_RESTORE_REGISTERS,
+ GET_ENGINE_CLOCK,
+ GET_MEMORY_CLOCK,
+ SET_ENGINE_CLOCK,
+ SET_MEMORY_CLOCK,
FUNC_END
} AtomBiosRequestID;

@@ -209,6 +213,7 @@ typedef union AtomBiosArg
AtomExecRec exec;
AtomFbRec fb;
enum RHD_TV_MODE tvMode;
+ unsigned long clockValue;
} AtomBiosArgRec, *AtomBiosArgPtr;

enum atomCrtc {
--
1.6.0.6

From 269bafd40c065cee2315ca718575c38f10bc384f Mon Sep 17 00:00:00 2001
From: Yang Zhao <yang@xxxxxxxxxx>
Date: Fri, 17 Apr 2009 15:13:58 -0700
Subject: [PATCH] PM: Add functions for get/setting engine and memory clocks


Signed-off-by: Yang Zhao <yang@xxxxxxxxxx>
---
src/Makefile.am | 2 +
src/rhd_pm.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/rhd_pm.h | 34 ++++++++++++++++++
3 files changed, 138 insertions(+), 0 deletions(-)
create mode 100644 src/rhd_pm.c
create mode 100644 src/rhd_pm.h

diff --git a/src/Makefile.am b/src/Makefile.am
index 7156d63..4c0ca86 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -76,6 +76,8 @@ radeonhd_drv_la_SOURCES = \
rhd_output.h \
rhd_pll.c \
rhd_pll.h \
+ rhd_pm.c \
+ rhd_pm.h \
rhd_randr.c \
rhd_randr.h \
rhd_regs.h \
diff --git a/src/rhd_pm.c b/src/rhd_pm.c
new file mode 100644
index 0000000..c3a5abf
--- /dev/null
+++ b/src/rhd_pm.c
@@ -0,0 +1,102 @@
+/*
+ * 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 ATI, VA LINUX SYSTEMS AND/OR
+ * THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/*
+ * Authors:
+ * Yang Zhao <yang@xxxxxxxxxx>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "xf86.h"
+
+#include "rhd.h"
+#include "rhd_pm.h"
+
+#include "rhd_atombios.h"
+
+unsigned long
+RHDGetEngineClock(RHDPtr rhdPtr) {
+#ifdef ATOM_BIOS
+ union AtomBiosArg data;
+ if (RHDAtomBiosFunc(rhdPtr->scrnIndex, rhdPtr->atomBIOS,
+ GET_ENGINE_CLOCK, &data) == ATOM_SUCCESS) {
+ return data.clockValue;
+ } else
+#endif
+ return 0;
+}
+
+unsigned long
+RHDGetDefaultEngineClock(RHDPtr rhdPtr) {
+#ifdef ATOM_BIOS
+ union AtomBiosArg data;
+ if (RHDAtomBiosFunc(rhdPtr->scrnIndex, rhdPtr->atomBIOS,
+ GET_DEFAULT_ENGINE_CLOCK, &data) == ATOM_SUCCESS) {
+ return data.clockValue;
+ } else
+#endif
+ return 0;
+}
+
+unsigned long
+RHDGetMemoryClock(RHDPtr rhdPtr) {
+#ifdef ATOM_BIOS
+ union AtomBiosArg data;
+ if (RHDAtomBiosFunc(rhdPtr->scrnIndex, rhdPtr->atomBIOS,
+ GET_MEMORY_CLOCK, &data) == ATOM_SUCCESS) {
+ return data.clockValue;
+ } else
+#endif
+ return 0;
+}
+
+Bool
+RHDSetEngineClock(RHDPtr rhdPtr, unsigned long clk) {
+#ifdef ATOM_BIOS
+ union AtomBiosArg data;
+
+ /* TODO: Idle first; find which idles are needed and expose them */
+ data.clockValue = clk;
+ return RHDAtomBiosFunc(rhdPtr->scrnIndex, rhdPtr->atomBIOS,
+ SET_ENGINE_CLOCK, &data) == ATOM_SUCCESS;
+#else
+ xf86DrvMsg(rhdPtr->scrnIndex, X_WARNING, "AtomBIOS required to set engine
clock\n");
+#endif
+}
+
+Bool
+RHDSetMemoryClock(RHDPtr rhdPtr, unsigned long clk) {
+#ifdef ATOM_BIOS
+ union AtomBiosArg data;
+
+ /* TODO: Idle first; find which idles are needed and expose them */
+ data.clockValue = clk;
+ return RHDAtomBiosFunc(rhdPtr->scrnIndex, rhdPtr->atomBIOS,
+ SET_MEMORY_CLOCK, &data) == ATOM_SUCCESS;
+#else
+ xf86DrvMsg(rhdPtr->scrnIndex, X_WARNING, "AtomBIOS required to set engine
clock\n");
+#endif
+}
diff --git a/src/rhd_pm.h b/src/rhd_pm.h
new file mode 100644
index 0000000..241f5e6
--- /dev/null
+++ b/src/rhd_pm.h
@@ -0,0 +1,34 @@
+/*
+ * 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 ATI, VA LINUX SYSTEMS AND/OR
+ * THEIR SUPPLIERS 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.
+ */
+
+#ifndef _RHD_PM_H
+# define _RHD_PM_H
+
+unsigned long RHDGetEngineClock(RHDPtr rhdPtr);
+unsigned long RHDGetDefaultEngineClock(RHDPtr rhdPtr);
+unsigned long RHDGetMemoryClock(RHDPtr rhdPtr);
+
+Bool RHDSetEngineClock(RHDPtr rhdPtr, unsigned long clk);
+Bool RHDSetMemoryClock(RHDPtr rhdPtr, unsigned long clk);
+
+#endif /* _RHD_PM_H */
--
1.6.0.6

From 218b7042dc7f419d47b3035bd1a2f99341bfc05b Mon Sep 17 00:00:00 2001
From: Yang Zhao <yang@xxxxxxxxxx>
Date: Fri, 17 Apr 2009 16:15:43 -0700
Subject: [PATCH] PM: Add ForceLowPowerMode and LowPowerModeEngineClock options

- LowPowerMode enables static low-power mode by setting engine clock.
- LowPowerModeEngineClock controls what the clock is set to, in Hz.
If unset, (default_engine_clock / 2) is used

Signed-off-by: Yang Zhao <yang@xxxxxxxxxx>
---
src/rhd.h | 2 ++
src/rhd_driver.c | 31 ++++++++++++++++++++++++++++++-
2 files changed, 32 insertions(+), 1 deletions(-)

diff --git a/src/rhd.h b/src/rhd.h
index a9932df..a4362aa 100644
--- a/src/rhd.h
+++ b/src/rhd.h
@@ -247,6 +247,8 @@ typedef struct RHDRec {
RHDOpt audio;
RHDOpt hdmi;
RHDOpt coherent;
+ RHDOpt lowPowerMode;
+ RHDOpt lowPowerModeEngineClock;
enum RHD_HPD_USAGE hpdUsage;
unsigned int FbMapSize;
pointer FbBase; /* map base of fb */
diff --git a/src/rhd_driver.c b/src/rhd_driver.c
index f849faa..ad51030 100644
--- a/src/rhd_driver.c
+++ b/src/rhd_driver.c
@@ -117,6 +117,7 @@
#include "rhd_randr.h"
#include "rhd_cs.h"
#include "rhd_audio.h"
+#include "rhd_pm.h"
#include "r5xx_accel.h"
#include "rhd_video.h"

@@ -252,7 +253,9 @@ typedef enum {
OPTION_UNVERIFIED_FEAT,
OPTION_AUDIO,
OPTION_HDMI,
- OPTION_COHERENT
+ OPTION_COHERENT,
+ OPTION_FORCE_LOW_POWER,
+ OPTION_LOW_POWER_CLOCK
} RHDOpts;

static const OptionInfoRec RHDOptions[] = {
@@ -282,6 +285,8 @@ static const OptionInfoRec RHDOptions[] = {
{ OPTION_AUDIO, "Audio", OPTV_BOOLEAN, {0},
FALSE },
{ OPTION_HDMI, "HDMI", OPTV_ANYSTR, {0},
FALSE },
{ OPTION_COHERENT, "COHERENT", OPTV_ANYSTR, {0},
FALSE },
+ { OPTION_FORCE_LOW_POWER, "ForceLowPowerMode", OPTV_BOOLEAN, {0},
FALSE },
+ { OPTION_LOW_POWER_CLOCK, "LowPowerModeEngineClock", OPTV_INTEGER,
{0}, FALSE },
{ -1, NULL, OPTV_NONE, {0}, FALSE }
};

@@ -1126,6 +1131,25 @@ RHDScreenInit(int scrnIndex, ScreenPtr pScreen, int
argc, char **argv)
fbPictureInit(pScreen, 0, 0);
xf86SetBlackWhitePixels(pScreen);

+ /* Static power management */
+ if (rhdPtr->lowPowerMode.val.bool) {
+ if (!rhdPtr->lowPowerModeEngineClock.val.integer) {
+ rhdPtr->lowPowerModeEngineClock.val.integer =
RHDGetDefaultEngineClock(rhdPtr) / 2;
+ }
+
+ if (rhdPtr->lowPowerModeEngineClock.val.integer) {
+ xf86DrvMsg(scrnIndex, X_INFO, "Force low power mode: engine clock
at %dHz\n",
+ rhdPtr->lowPowerModeEngineClock.val.integer);
+ RHDSetEngineClock(rhdPtr,
rhdPtr->lowPowerModeEngineClock.val.integer);
+
+ /* Induce logging of new engine clock */
+ RHDGetEngineClock(rhdPtr);
+ } else {
+ xf86DrvMsg(scrnIndex, X_WARNING,
+ "ForceLowPowerMode disabled: could not determine
default engine clock\n");
+ }
+ }
+
#ifdef USE_DRI
if (DriScreenInited)
rhdPtr->directRenderingEnabled = RHDDRIFinishScreenInit(pScreen);
@@ -2828,6 +2852,11 @@ rhdProcessOptions(ScrnInfoPtr pScrn)
&rhdPtr->hdmi, "none");
RhdGetOptValString(rhdPtr->Options, OPTION_COHERENT,
&rhdPtr->coherent, NULL);
+ RhdGetOptValBool (rhdPtr->Options, OPTION_FORCE_LOW_POWER,
+ &rhdPtr->lowPowerMode, FALSE);
+ RhdGetOptValInteger(rhdPtr->Options, OPTION_LOW_POWER_CLOCK,
+ &rhdPtr->lowPowerModeEngineClock, 0);
+
#ifdef ATOM_BIOS
rhdParseAtomBIOSUsage(pScrn);
#endif
--
1.6.0.6

< Previous Next >
Follow Ups