* [PATCH 0/9] drm/radeon/kms: update pm code
@ 2010-05-07 21:16 Alex Deucher
2010-05-07 21:16 ` [PATCH 1/9] drm/radeon/kms: enable misc pm power state features on r5xx, rs6xx Alex Deucher
` (3 more replies)
0 siblings, 4 replies; 19+ messages in thread
From: Alex Deucher @ 2010-05-07 21:16 UTC (permalink / raw)
To: airlied, dri-devel; +Cc: mjg59
This set of patches applies on top of the code in drm-radeon-testing.
I've been testing this code pretty hard this week and it's been solid.
In addition to some fixes on top of what's in d-r-t, it also reworks
the pm code to support two basic methods:
1. "dynpm"
2. "profile"
You can select the methods via sysfs. Echo "dynpm" or "profile" to
/sys/class/drm/card-0/device/power_method.
The "dynpm" method dynamically changes the clocks based on the number of pending
fences, so performance is ramped up when running GPU intensive apps, and
ramped down when the GPU is idle. The reclocking is attemped during
vertical blanking periods, but due to the timing of the reclocking
functions, doesn't not always complete in the blanking period, which can
lead to flicker in the display. Due to this, dynpm only works when a single
head is active.
The "profile" method exposes 4 profiles that can be selected from:
1. "default"
2. "auto"
3. "low"
4. "high"
Select the profile by echoing the selected profile to
/sys/class/drm/card-0/device/power_profile.
"default" uses the default clocks and does not change the power state. This is
the default behavior.
"auto" selects between low and high power states based on the whether the system
is on battery power or not. Even lower power states are selected when the monitors
are in the dpms off state.
"low" forces the gpu to be in the low power state all the time. Even lower power
states are selected when the monitors are in the dpms off state.
"high" forces the gpu to be in the high power state all the time. Even lower power
states are selected when the monitors are in the dpms off state.
The "profile" method is not as agressive as "dynpm," but is currently much more
stable and flicker free and works with multiple heads active.
The default power management method is "profile" using the "default" profile.
The default should eventaully be changed to "profile" "auto".
For upstream, we may want to squash some of these. I'm open to suggestions.
Everthing that's been added since drm-linus?
Alex
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH 1/9] drm/radeon/kms: enable misc pm power state features on r5xx, rs6xx
2010-05-07 21:16 [PATCH 0/9] drm/radeon/kms: update pm code Alex Deucher
@ 2010-05-07 21:16 ` Alex Deucher
2010-05-07 21:16 ` [PATCH 2/9] drm/radeon/kms: enable misc pm power state features on r1xx-r4xx Alex Deucher
2010-05-07 21:23 ` [PATCH 0/9] drm/radeon/kms: update pm code Matthew Garrett
` (2 subsequent siblings)
3 siblings, 1 reply; 19+ messages in thread
From: Alex Deucher @ 2010-05-07 21:16 UTC (permalink / raw)
To: airlied, dri-devel; +Cc: mjg59
voltage drop, dynamic voltage, dynamic sclk, pcie lane adjust, etc,
Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
---
drivers/gpu/drm/radeon/rs600.c | 14 ++++++++++----
drivers/gpu/drm/radeon/rs600d.h | 2 ++
2 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c
index c3890b7..8e0c460 100644
--- a/drivers/gpu/drm/radeon/rs600.c
+++ b/drivers/gpu/drm/radeon/rs600.c
@@ -48,12 +48,11 @@ int rs600_mc_wait_for_idle(struct radeon_device *rdev);
void rs600_pm_misc(struct radeon_device *rdev)
{
-#if 0
int requested_index = rdev->pm.requested_power_state_index;
struct radeon_power_state *ps = &rdev->pm.power_state[requested_index];
struct radeon_voltage *voltage = &ps->clock_info[0].voltage;
u32 tmp, dyn_pwrmgt_sclk_length, dyn_sclk_vol_cntl;
- u32 hdp_dyn_cntl, mc_host_dyn_cntl;
+ u32 hdp_dyn_cntl, /*mc_host_dyn_cntl,*/ dyn_backbias_cntl;
if ((voltage->type == VOLTAGE_GPIO) && (voltage->gpio.valid)) {
if (ps->misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) {
@@ -112,13 +111,21 @@ void rs600_pm_misc(struct radeon_device *rdev)
else
hdp_dyn_cntl |= HDP_FORCEON;
WREG32_PLL(HDP_DYN_CNTL, hdp_dyn_cntl);
-
+#if 0
+ /* mc_host_dyn seems to cause hangs from time to time */
mc_host_dyn_cntl = RREG32_PLL(MC_HOST_DYN_CNTL);
if (ps->misc & ATOM_PM_MISCINFO_DYNAMIC_MC_HOST_BLOCK_EN)
mc_host_dyn_cntl &= ~MC_HOST_FORCEON;
else
mc_host_dyn_cntl |= MC_HOST_FORCEON;
WREG32_PLL(MC_HOST_DYN_CNTL, mc_host_dyn_cntl);
+#endif
+ dyn_backbias_cntl = RREG32_PLL(DYN_BACKBIAS_CNTL);
+ if (ps->misc & ATOM_PM_MISCINFO2_DYNAMIC_BACK_BIAS_EN)
+ dyn_backbias_cntl |= IO_CG_BACKBIAS_EN;
+ else
+ dyn_backbias_cntl &= ~IO_CG_BACKBIAS_EN;
+ WREG32_PLL(DYN_BACKBIAS_CNTL, dyn_backbias_cntl);
/* set pcie lanes */
if ((rdev->flags & RADEON_IS_PCIE) &&
@@ -130,7 +137,6 @@ void rs600_pm_misc(struct radeon_device *rdev)
ps->pcie_lanes);
DRM_INFO("Setting: p: %d\n", ps->pcie_lanes);
}
-#endif
}
void rs600_pm_prepare(struct radeon_device *rdev)
diff --git a/drivers/gpu/drm/radeon/rs600d.h b/drivers/gpu/drm/radeon/rs600d.h
index 8f62434..a27c13a 100644
--- a/drivers/gpu/drm/radeon/rs600d.h
+++ b/drivers/gpu/drm/radeon/rs600d.h
@@ -655,6 +655,8 @@
#define HDP_FORCEON (1 << 0)
#define MC_HOST_DYN_CNTL 0x1e
#define MC_HOST_FORCEON (1 << 0)
+#define DYN_BACKBIAS_CNTL 0x29
+#define IO_CG_BACKBIAS_EN (1 << 0)
/* mmreg */
#define DOUT_POWER_MANAGEMENT_CNTL 0x7ee0
--
1.5.6.3
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH 2/9] drm/radeon/kms: enable misc pm power state features on r1xx-r4xx
2010-05-07 21:16 ` [PATCH 1/9] drm/radeon/kms: enable misc pm power state features on r5xx, rs6xx Alex Deucher
@ 2010-05-07 21:16 ` Alex Deucher
2010-05-07 21:16 ` [PATCH 3/9] drm/radeon/kms: re-enable gui idle interrupts on r6xx+ Alex Deucher
0 siblings, 1 reply; 19+ messages in thread
From: Alex Deucher @ 2010-05-07 21:16 UTC (permalink / raw)
To: airlied, dri-devel; +Cc: mjg59
voltage drop, dynamic voltage, dynamic sclk, pcie lane adjust, etc,
Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
---
drivers/gpu/drm/radeon/r100.c | 2 --
1 files changed, 0 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
index 493b9b4..14b7541 100644
--- a/drivers/gpu/drm/radeon/r100.c
+++ b/drivers/gpu/drm/radeon/r100.c
@@ -220,7 +220,6 @@ void r100_set_power_state(struct radeon_device *rdev, bool static_switch)
void r100_pm_misc(struct radeon_device *rdev)
{
-#if 0
int requested_index = rdev->pm.requested_power_state_index;
struct radeon_power_state *ps = &rdev->pm.power_state[requested_index];
struct radeon_voltage *voltage = &ps->clock_info[0].voltage;
@@ -308,7 +307,6 @@ void r100_pm_misc(struct radeon_device *rdev)
ps->pcie_lanes);
DRM_INFO("Setting: p: %d\n", ps->pcie_lanes);
}
-#endif
}
void r100_pm_prepare(struct radeon_device *rdev)
--
1.5.6.3
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH 3/9] drm/radeon/kms: re-enable gui idle interrupts on r6xx+
2010-05-07 21:16 ` [PATCH 2/9] drm/radeon/kms: enable misc pm power state features on r1xx-r4xx Alex Deucher
@ 2010-05-07 21:16 ` Alex Deucher
2010-05-07 21:16 ` [PATCH 4/9] radeon: Split out ring locking and allocation Alex Deucher
0 siblings, 1 reply; 19+ messages in thread
From: Alex Deucher @ 2010-05-07 21:16 UTC (permalink / raw)
To: airlied, dri-devel; +Cc: mjg59
Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
---
drivers/gpu/drm/radeon/radeon_pm.c | 24 +++++++++++++-----------
1 files changed, 13 insertions(+), 11 deletions(-)
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
index 2eb675e..bded834 100644
--- a/drivers/gpu/drm/radeon/radeon_pm.c
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
@@ -64,17 +64,19 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev, int static_switch)
mutex_lock(&rdev->ddev->struct_mutex);
mutex_lock(&rdev->vram_mutex);
mutex_lock(&rdev->cp.mutex);
-#if 0
- /* wait for GPU idle */
- rdev->pm.gui_idle = false;
- rdev->irq.gui_idle = true;
- radeon_irq_set(rdev);
- wait_event_interruptible_timeout(
- rdev->irq.idle_queue, rdev->pm.gui_idle,
- msecs_to_jiffies(RADEON_WAIT_IDLE_TIMEOUT));
- rdev->irq.gui_idle = false;
- radeon_irq_set(rdev);
-#endif
+
+ /* gui idle int has issues on older chips it seems */
+ if (rdev->family >= CHIP_R600) {
+ /* wait for GPU idle */
+ rdev->pm.gui_idle = false;
+ rdev->irq.gui_idle = true;
+ radeon_irq_set(rdev);
+ wait_event_interruptible_timeout(
+ rdev->irq.idle_queue, rdev->pm.gui_idle,
+ msecs_to_jiffies(RADEON_WAIT_IDLE_TIMEOUT));
+ rdev->irq.gui_idle = false;
+ radeon_irq_set(rdev);
+ }
radeon_unmap_vram_bos(rdev);
if (!static_switch) {
--
1.5.6.3
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH 4/9] radeon: Split out ring locking and allocation
2010-05-07 21:16 ` [PATCH 3/9] drm/radeon/kms: re-enable gui idle interrupts on r6xx+ Alex Deucher
@ 2010-05-07 21:16 ` Alex Deucher
2010-05-07 21:16 ` [PATCH 5/9] radeon: Use fences to gate entry to reclocking on <r600 Alex Deucher
0 siblings, 1 reply; 19+ messages in thread
From: Alex Deucher @ 2010-05-07 21:16 UTC (permalink / raw)
To: airlied, dri-devel; +Cc: mjg59, Matthew Garrett
From: Matthew Garrett <mjg@redhat.com>
We need to handle the ring while we've already locked it, so split out
the allocation and commit functions in order to allow them to be used.
Signed-off-by: Matthew Garrett <mjg@redhat.com>
---
drivers/gpu/drm/radeon/radeon.h | 2 ++
drivers/gpu/drm/radeon/radeon_ring.c | 27 +++++++++++++++++++++------
2 files changed, 23 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 93ac88e..e39e2b4 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -471,7 +471,9 @@ int radeon_ib_test(struct radeon_device *rdev);
extern void radeon_ib_bogus_add(struct radeon_device *rdev, struct radeon_ib *ib);
/* Ring access between begin & end cannot sleep */
void radeon_ring_free_size(struct radeon_device *rdev);
+int radeon_ring_alloc(struct radeon_device *rdev, unsigned ndw);
int radeon_ring_lock(struct radeon_device *rdev, unsigned ndw);
+void radeon_ring_commit(struct radeon_device *rdev);
void radeon_ring_unlock_commit(struct radeon_device *rdev);
void radeon_ring_unlock_undo(struct radeon_device *rdev);
int radeon_ring_test(struct radeon_device *rdev);
diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c
index f6e1e8d..6cc4259 100644
--- a/drivers/gpu/drm/radeon/radeon_ring.c
+++ b/drivers/gpu/drm/radeon/radeon_ring.c
@@ -258,31 +258,41 @@ void radeon_ring_free_size(struct radeon_device *rdev)
}
}
-int radeon_ring_lock(struct radeon_device *rdev, unsigned ndw)
+int radeon_ring_alloc(struct radeon_device *rdev, unsigned ndw)
{
int r;
/* Align requested size with padding so unlock_commit can
* pad safely */
ndw = (ndw + rdev->cp.align_mask) & ~rdev->cp.align_mask;
- mutex_lock(&rdev->cp.mutex);
while (ndw > (rdev->cp.ring_free_dw - 1)) {
radeon_ring_free_size(rdev);
if (ndw < rdev->cp.ring_free_dw) {
break;
}
r = radeon_fence_wait_next(rdev);
- if (r) {
- mutex_unlock(&rdev->cp.mutex);
+ if (r)
return r;
- }
}
rdev->cp.count_dw = ndw;
rdev->cp.wptr_old = rdev->cp.wptr;
return 0;
}
-void radeon_ring_unlock_commit(struct radeon_device *rdev)
+int radeon_ring_lock(struct radeon_device *rdev, unsigned ndw)
+{
+ int r;
+
+ mutex_lock(&rdev->cp.mutex);
+ r = radeon_ring_alloc(rdev, ndw);
+ if (r) {
+ mutex_unlock(&rdev->cp.mutex);
+ return r;
+ }
+ return 0;
+}
+
+void radeon_ring_commit(struct radeon_device *rdev)
{
unsigned count_dw_pad;
unsigned i;
@@ -295,6 +305,11 @@ void radeon_ring_unlock_commit(struct radeon_device *rdev)
}
DRM_MEMORYBARRIER();
radeon_cp_commit(rdev);
+}
+
+void radeon_ring_unlock_commit(struct radeon_device *rdev)
+{
+ radeon_ring_commit(rdev);
mutex_unlock(&rdev->cp.mutex);
}
--
1.5.6.3
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH 5/9] radeon: Use fences to gate entry to reclocking on <r600
2010-05-07 21:16 ` [PATCH 4/9] radeon: Split out ring locking and allocation Alex Deucher
@ 2010-05-07 21:16 ` Alex Deucher
2010-05-07 21:16 ` [PATCH 6/9] drm/radeon/kms: fix lock ordering in ring, ib handling Alex Deucher
0 siblings, 1 reply; 19+ messages in thread
From: Alex Deucher @ 2010-05-07 21:16 UTC (permalink / raw)
To: airlied, dri-devel; +Cc: mjg59, Matthew Garrett
From: Matthew Garrett <mjg@redhat.com>
GUI idle interrupts don't seem to work terribly well on r500 and earlier,
so let's use a fence instead.
Signed-off-by: Matthew Garrett <mjg@redhat.com>
---
drivers/gpu/drm/radeon/radeon_pm.c | 8 ++++++++
1 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
index bded834..1ee7fc9 100644
--- a/drivers/gpu/drm/radeon/radeon_pm.c
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
@@ -76,6 +76,14 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev, int static_switch)
msecs_to_jiffies(RADEON_WAIT_IDLE_TIMEOUT));
rdev->irq.gui_idle = false;
radeon_irq_set(rdev);
+ } else {
+ struct radeon_fence *fence;
+ radeon_ring_alloc(rdev, 64);
+ radeon_fence_create(rdev, &fence);
+ radeon_fence_emit(rdev, fence);
+ radeon_ring_commit(rdev);
+ radeon_fence_wait(fence, false);
+ radeon_fence_unref(&fence);
}
radeon_unmap_vram_bos(rdev);
--
1.5.6.3
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH 6/9] drm/radeon/kms: fix lock ordering in ring, ib handling
2010-05-07 21:16 ` [PATCH 5/9] radeon: Use fences to gate entry to reclocking on <r600 Alex Deucher
@ 2010-05-07 21:16 ` Alex Deucher
2010-05-07 21:16 ` [PATCH 7/9] drm/radeon/kms/pm: add support for no display power states Alex Deucher
0 siblings, 1 reply; 19+ messages in thread
From: Alex Deucher @ 2010-05-07 21:16 UTC (permalink / raw)
To: airlied, dri-devel; +Cc: mjg59
Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
---
drivers/gpu/drm/radeon/radeon_ring.c | 39 +++++++++++++++++++--------------
1 files changed, 22 insertions(+), 17 deletions(-)
diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c
index 6cc4259..261e98a 100644
--- a/drivers/gpu/drm/radeon/radeon_ring.c
+++ b/drivers/gpu/drm/radeon/radeon_ring.c
@@ -219,24 +219,26 @@ int radeon_ib_pool_init(struct radeon_device *rdev)
void radeon_ib_pool_fini(struct radeon_device *rdev)
{
int r;
+ struct radeon_bo *robj;
if (!rdev->ib_pool.ready) {
return;
}
mutex_lock(&rdev->ib_pool.mutex);
radeon_ib_bogus_cleanup(rdev);
+ robj = rdev->ib_pool.robj;
+ rdev->ib_pool.robj = NULL;
+ mutex_unlock(&rdev->ib_pool.mutex);
- if (rdev->ib_pool.robj) {
- r = radeon_bo_reserve(rdev->ib_pool.robj, false);
+ if (robj) {
+ r = radeon_bo_reserve(robj, false);
if (likely(r == 0)) {
- radeon_bo_kunmap(rdev->ib_pool.robj);
- radeon_bo_unpin(rdev->ib_pool.robj);
- radeon_bo_unreserve(rdev->ib_pool.robj);
+ radeon_bo_kunmap(robj);
+ radeon_bo_unpin(robj);
+ radeon_bo_unreserve(robj);
}
- radeon_bo_unref(&rdev->ib_pool.robj);
- rdev->ib_pool.robj = NULL;
+ radeon_bo_unref(&robj);
}
- mutex_unlock(&rdev->ib_pool.mutex);
}
@@ -359,20 +361,23 @@ int radeon_ring_init(struct radeon_device *rdev, unsigned ring_size)
void radeon_ring_fini(struct radeon_device *rdev)
{
int r;
+ struct radeon_bo *ring_obj;
mutex_lock(&rdev->cp.mutex);
- if (rdev->cp.ring_obj) {
- r = radeon_bo_reserve(rdev->cp.ring_obj, false);
+ ring_obj = rdev->cp.ring_obj;
+ rdev->cp.ring = NULL;
+ rdev->cp.ring_obj = NULL;
+ mutex_unlock(&rdev->cp.mutex);
+
+ if (ring_obj) {
+ r = radeon_bo_reserve(ring_obj, false);
if (likely(r == 0)) {
- radeon_bo_kunmap(rdev->cp.ring_obj);
- radeon_bo_unpin(rdev->cp.ring_obj);
- radeon_bo_unreserve(rdev->cp.ring_obj);
+ radeon_bo_kunmap(ring_obj);
+ radeon_bo_unpin(ring_obj);
+ radeon_bo_unreserve(ring_obj);
}
- radeon_bo_unref(&rdev->cp.ring_obj);
- rdev->cp.ring = NULL;
- rdev->cp.ring_obj = NULL;
+ radeon_bo_unref(&ring_obj);
}
- mutex_unlock(&rdev->cp.mutex);
}
--
1.5.6.3
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH 7/9] drm/radeon/kms/pm: add support for no display power states
2010-05-07 21:16 ` [PATCH 6/9] drm/radeon/kms: fix lock ordering in ring, ib handling Alex Deucher
@ 2010-05-07 21:16 ` Alex Deucher
2010-05-07 21:16 ` [PATCH 8/9] drm/radeon/kms/pm: rework power management Alex Deucher
0 siblings, 1 reply; 19+ messages in thread
From: Alex Deucher @ 2010-05-07 21:16 UTC (permalink / raw)
To: airlied, dri-devel; +Cc: mjg59
The lowest power states often cause display problems, so only enable
them when all displays are off.
Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
---
drivers/gpu/drm/radeon/atombios_crtc.c | 9 +++---
drivers/gpu/drm/radeon/r100.c | 12 ++++++--
drivers/gpu/drm/radeon/r600.c | 20 ++++++++++++--
drivers/gpu/drm/radeon/radeon.h | 7 +++-
drivers/gpu/drm/radeon/radeon_atombios.c | 37 ++++++++++++++++++--------
drivers/gpu/drm/radeon/radeon_combios.c | 2 +-
drivers/gpu/drm/radeon/radeon_legacy_crtc.c | 9 +++---
drivers/gpu/drm/radeon/radeon_pm.c | 38 ++++++++++++++++++--------
8 files changed, 94 insertions(+), 40 deletions(-)
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c
index 4151ad8..03dd6c4 100644
--- a/drivers/gpu/drm/radeon/atombios_crtc.c
+++ b/drivers/gpu/drm/radeon/atombios_crtc.c
@@ -245,13 +245,15 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode)
switch (mode) {
case DRM_MODE_DPMS_ON:
+ radeon_crtc->enabled = true;
+ /* adjust pm to dpms changes BEFORE enabling crtcs */
+ radeon_pm_compute_clocks(rdev);
atombios_enable_crtc(crtc, ATOM_ENABLE);
if (ASIC_IS_DCE3(rdev))
atombios_enable_crtc_memreq(crtc, ATOM_ENABLE);
atombios_blank_crtc(crtc, ATOM_DISABLE);
drm_vblank_post_modeset(dev, radeon_crtc->crtc_id);
radeon_crtc_load_lut(crtc);
- radeon_crtc->enabled = true;
break;
case DRM_MODE_DPMS_STANDBY:
case DRM_MODE_DPMS_SUSPEND:
@@ -262,11 +264,10 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode)
atombios_enable_crtc_memreq(crtc, ATOM_DISABLE);
atombios_enable_crtc(crtc, ATOM_DISABLE);
radeon_crtc->enabled = false;
+ /* adjust pm to dpms changes AFTER disabling crtcs */
+ radeon_pm_compute_clocks(rdev);
break;
}
-
- /* adjust pm to dpms change */
- radeon_pm_compute_clocks(rdev);
}
static void
diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
index 14b7541..4161a35 100644
--- a/drivers/gpu/drm/radeon/r100.c
+++ b/drivers/gpu/drm/radeon/r100.c
@@ -87,7 +87,7 @@ void r100_get_power_state(struct radeon_device *rdev,
} else {
if (rdev->pm.active_crtc_count > 1) {
for (i = 0; i < rdev->pm.num_power_states; i++) {
- if (rdev->pm.power_state[i].flags & RADEON_PM_SINGLE_DISPLAY_ONLY)
+ if (rdev->pm.power_state[i].flags & RADEON_PM_STATE_SINGLE_DISPLAY_ONLY)
continue;
else if (i >= rdev->pm.current_power_state_index) {
rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index;
@@ -101,6 +101,12 @@ void r100_get_power_state(struct radeon_device *rdev,
rdev->pm.requested_power_state_index =
rdev->pm.current_power_state_index - 1;
}
+ /* don't use the power state if crtcs are active and no display flag is set */
+ if ((rdev->pm.active_crtc_count > 0) &&
+ (rdev->pm.power_state[rdev->pm.requested_power_state_index].clock_info[0].flags &
+ RADEON_PM_MODE_NO_DISPLAY)) {
+ rdev->pm.requested_power_state_index++;
+ }
break;
case PM_ACTION_UPCLOCK:
if (rdev->pm.current_power_state_index == (rdev->pm.num_power_states - 1)) {
@@ -109,7 +115,7 @@ void r100_get_power_state(struct radeon_device *rdev,
} else {
if (rdev->pm.active_crtc_count > 1) {
for (i = (rdev->pm.num_power_states - 1); i >= 0; i--) {
- if (rdev->pm.power_state[i].flags & RADEON_PM_SINGLE_DISPLAY_ONLY)
+ if (rdev->pm.power_state[i].flags & RADEON_PM_STATE_SINGLE_DISPLAY_ONLY)
continue;
else if (i <= rdev->pm.current_power_state_index) {
rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index;
@@ -215,7 +221,7 @@ void r100_set_power_state(struct radeon_device *rdev, bool static_switch)
rdev->pm.current_power_state_index = rdev->pm.requested_power_state_index;
rdev->pm.current_clock_mode_index = rdev->pm.requested_clock_mode_index;
} else
- DRM_INFO("GUI not idle!!!\n");
+ DRM_INFO("pm: GUI not idle!!!\n");
}
void r100_pm_misc(struct radeon_device *rdev)
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index 75c825c..08a328c 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -120,7 +120,7 @@ void r600_get_power_state(struct radeon_device *rdev,
} else {
if (rdev->pm.active_crtc_count > 1) {
for (i = 0; i < rdev->pm.num_power_states; i++) {
- if (rdev->pm.power_state[i].flags & RADEON_PM_SINGLE_DISPLAY_ONLY)
+ if (rdev->pm.power_state[i].flags & RADEON_PM_STATE_SINGLE_DISPLAY_ONLY)
continue;
else if (i >= rdev->pm.current_power_state_index) {
rdev->pm.requested_power_state_index =
@@ -136,6 +136,13 @@ void r600_get_power_state(struct radeon_device *rdev,
rdev->pm.current_power_state_index - 1;
}
rdev->pm.requested_clock_mode_index = 0;
+ /* don't use the power state if crtcs are active and no display flag is set */
+ if ((rdev->pm.active_crtc_count > 0) &&
+ (rdev->pm.power_state[rdev->pm.requested_power_state_index].
+ clock_info[rdev->pm.requested_clock_mode_index].flags &
+ RADEON_PM_MODE_NO_DISPLAY)) {
+ rdev->pm.requested_power_state_index++;
+ }
break;
case PM_ACTION_UPCLOCK:
if (rdev->pm.current_power_state_index == (rdev->pm.num_power_states - 1)) {
@@ -144,7 +151,7 @@ void r600_get_power_state(struct radeon_device *rdev,
} else {
if (rdev->pm.active_crtc_count > 1) {
for (i = (rdev->pm.num_power_states - 1); i >= 0; i--) {
- if (rdev->pm.power_state[i].flags & RADEON_PM_SINGLE_DISPLAY_ONLY)
+ if (rdev->pm.power_state[i].flags & RADEON_PM_STATE_SINGLE_DISPLAY_ONLY)
continue;
else if (i <= rdev->pm.current_power_state_index) {
rdev->pm.requested_power_state_index =
@@ -179,7 +186,7 @@ void r600_get_power_state(struct radeon_device *rdev,
rdev->pm.requested_power_state_index = -1;
/* start at 1 as we don't want the default mode */
for (i = 1; i < rdev->pm.num_power_states; i++) {
- if (rdev->pm.power_state[i].flags & RADEON_PM_SINGLE_DISPLAY_ONLY)
+ if (rdev->pm.power_state[i].flags & RADEON_PM_STATE_SINGLE_DISPLAY_ONLY)
continue;
else if ((rdev->pm.power_state[i].type == POWER_STATE_TYPE_PERFORMANCE) ||
(rdev->pm.power_state[i].type == POWER_STATE_TYPE_BATTERY)) {
@@ -210,6 +217,13 @@ void r600_get_power_state(struct radeon_device *rdev,
rdev->pm.requested_clock_mode_index = 0;
rdev->pm.can_downclock = false;
}
+ /* don't use the power state if crtcs are active and no display flag is set */
+ if ((rdev->pm.active_crtc_count > 0) &&
+ (rdev->pm.power_state[rdev->pm.requested_power_state_index].
+ clock_info[rdev->pm.requested_clock_mode_index].flags &
+ RADEON_PM_MODE_NO_DISPLAY)) {
+ rdev->pm.requested_clock_mode_index++;
+ }
break;
case PM_ACTION_UPCLOCK:
if (rdev->pm.requested_power_state_index == rdev->pm.current_power_state_index) {
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index e39e2b4..480a83f 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -658,6 +658,9 @@ struct radeon_voltage {
u32 voltage;
};
+/* clock mode flags */
+#define RADEON_PM_MODE_NO_DISPLAY (1 << 0)
+
struct radeon_pm_clock_info {
/* memory clock */
u32 mclk;
@@ -665,12 +668,12 @@ struct radeon_pm_clock_info {
u32 sclk;
/* voltage info */
struct radeon_voltage voltage;
- /* standardized clock flags - not sure we'll need these */
+ /* standardized clock flags */
u32 flags;
};
/* state flags */
-#define RADEON_PM_SINGLE_DISPLAY_ONLY (1 << 0)
+#define RADEON_PM_STATE_SINGLE_DISPLAY_ONLY (1 << 0)
struct radeon_power_state {
enum radeon_pm_state_type type;
diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c
index 7968d61..78e53d1 100644
--- a/drivers/gpu/drm/radeon/radeon_atombios.c
+++ b/drivers/gpu/drm/radeon/radeon_atombios.c
@@ -1549,7 +1549,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id =
power_info->info.asPowerPlayInfo[i].ucVoltageDropIndex;
}
- rdev->pm.power_state[state_index].flags = RADEON_PM_SINGLE_DISPLAY_ONLY;
+ rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
rdev->pm.power_state[state_index].misc = misc;
/* order matters! */
if (misc & ATOM_PM_MISCINFO_POWER_SAVING_MODE)
@@ -1568,7 +1568,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_PERFORMANCE;
rdev->pm.power_state[state_index].flags &=
- ~RADEON_PM_SINGLE_DISPLAY_ONLY;
+ ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
}
if (misc & ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE) {
rdev->pm.power_state[state_index].type =
@@ -1577,7 +1577,10 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
rdev->pm.power_state[state_index].default_clock_mode =
&rdev->pm.power_state[state_index].clock_info[0];
rdev->pm.power_state[state_index].flags &=
- ~RADEON_PM_SINGLE_DISPLAY_ONLY;
+ ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
+ } else if (state_index == 0) {
+ rdev->pm.power_state[state_index].clock_info[0].flags |=
+ RADEON_PM_MODE_NO_DISPLAY;
}
state_index++;
break;
@@ -1613,7 +1616,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id =
power_info->info_2.asPowerPlayInfo[i].ucVoltageDropIndex;
}
- rdev->pm.power_state[state_index].flags = RADEON_PM_SINGLE_DISPLAY_ONLY;
+ rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
rdev->pm.power_state[state_index].misc = misc;
rdev->pm.power_state[state_index].misc2 = misc2;
/* order matters! */
@@ -1633,14 +1636,14 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_PERFORMANCE;
rdev->pm.power_state[state_index].flags &=
- ~RADEON_PM_SINGLE_DISPLAY_ONLY;
+ ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
}
if (misc2 & ATOM_PM_MISCINFO2_SYSTEM_AC_LITE_MODE)
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_BALANCED;
if (misc2 & ATOM_PM_MISCINFO2_MULTI_DISPLAY_SUPPORT)
rdev->pm.power_state[state_index].flags &=
- ~RADEON_PM_SINGLE_DISPLAY_ONLY;
+ ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
if (misc & ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE) {
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_DEFAULT;
@@ -1648,7 +1651,10 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
rdev->pm.power_state[state_index].default_clock_mode =
&rdev->pm.power_state[state_index].clock_info[0];
rdev->pm.power_state[state_index].flags &=
- ~RADEON_PM_SINGLE_DISPLAY_ONLY;
+ ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
+ } else if (state_index == 0) {
+ rdev->pm.power_state[state_index].clock_info[0].flags |=
+ RADEON_PM_MODE_NO_DISPLAY;
}
state_index++;
break;
@@ -1690,7 +1696,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
power_info->info_3.asPowerPlayInfo[i].ucVDDCI_VoltageDropIndex;
}
}
- rdev->pm.power_state[state_index].flags = RADEON_PM_SINGLE_DISPLAY_ONLY;
+ rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
rdev->pm.power_state[state_index].misc = misc;
rdev->pm.power_state[state_index].misc2 = misc2;
/* order matters! */
@@ -1710,7 +1716,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_PERFORMANCE;
rdev->pm.power_state[state_index].flags &=
- ~RADEON_PM_SINGLE_DISPLAY_ONLY;
+ ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
}
if (misc2 & ATOM_PM_MISCINFO2_SYSTEM_AC_LITE_MODE)
rdev->pm.power_state[state_index].type =
@@ -1721,6 +1727,9 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
rdev->pm.default_power_state_index = state_index;
rdev->pm.power_state[state_index].default_clock_mode =
&rdev->pm.power_state[state_index].clock_info[0];
+ } else if (state_index == 0) {
+ rdev->pm.power_state[state_index].clock_info[0].flags |=
+ RADEON_PM_MODE_NO_DISPLAY;
}
state_index++;
break;
@@ -1734,7 +1743,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
rdev->pm.power_state[state_index - 1].default_clock_mode =
&rdev->pm.power_state[state_index - 1].clock_info[0];
rdev->pm.power_state[state_index].flags &=
- ~RADEON_PM_SINGLE_DISPLAY_ONLY;
+ ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
rdev->pm.power_state[state_index].misc = 0;
rdev->pm.power_state[state_index].misc2 = 0;
}
@@ -1881,7 +1890,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
rdev->pm.power_state[state_index].flags = 0;
if (misc & ATOM_PPLIB_SINGLE_DISPLAY_ONLY)
rdev->pm.power_state[state_index].flags |=
- RADEON_PM_SINGLE_DISPLAY_ONLY;
+ RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
if (misc2 & ATOM_PPLIB_CLASSIFICATION_BOOT) {
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_DEFAULT;
@@ -1892,6 +1901,12 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
state_index++;
}
}
+ /* if multiple clock modes, mark the lowest as no display */
+ for (i = 0; i < state_index; i++) {
+ if (rdev->pm.power_state[i].num_clock_modes > 1)
+ rdev->pm.power_state[i].clock_info[0].flags |=
+ RADEON_PM_MODE_NO_DISPLAY;
+ }
/* first mode is usually default */
if (rdev->pm.default_power_state_index == -1) {
rdev->pm.power_state[0].type =
diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c
index b0d58a7..ea34ec5 100644
--- a/drivers/gpu/drm/radeon/radeon_combios.c
+++ b/drivers/gpu/drm/radeon/radeon_combios.c
@@ -2435,7 +2435,7 @@ void radeon_combios_get_power_modes(struct radeon_device *rdev)
if (rev > 6)
rdev->pm.power_state[state_index].pcie_lanes =
RBIOS8(offset + 0x5 + 0x10);
- rdev->pm.power_state[state_index].flags = RADEON_PM_SINGLE_DISPLAY_ONLY;
+ rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
state_index++;
} else {
/* XXX figure out some good default low power mode for mobility cards w/out power tables */
diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
index 7701d42..e1e5255 100644
--- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
+++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
@@ -314,6 +314,9 @@ void radeon_crtc_dpms(struct drm_crtc *crtc, int mode)
switch (mode) {
case DRM_MODE_DPMS_ON:
+ radeon_crtc->enabled = true;
+ /* adjust pm to dpms changes BEFORE enabling crtcs */
+ radeon_pm_compute_clocks(rdev);
if (radeon_crtc->crtc_id)
WREG32_P(RADEON_CRTC2_GEN_CNTL, RADEON_CRTC2_EN, ~(RADEON_CRTC2_EN | mask));
else {
@@ -323,7 +326,6 @@ void radeon_crtc_dpms(struct drm_crtc *crtc, int mode)
}
drm_vblank_post_modeset(dev, radeon_crtc->crtc_id);
radeon_crtc_load_lut(crtc);
- radeon_crtc->enabled = true;
break;
case DRM_MODE_DPMS_STANDBY:
case DRM_MODE_DPMS_SUSPEND:
@@ -337,11 +339,10 @@ void radeon_crtc_dpms(struct drm_crtc *crtc, int mode)
WREG32_P(RADEON_CRTC_EXT_CNTL, mask, ~mask);
}
radeon_crtc->enabled = false;
+ /* adjust pm to dpms changes AFTER disabling crtcs */
+ radeon_pm_compute_clocks(rdev);
break;
}
-
- /* adjust pm to dpms change */
- radeon_pm_compute_clocks(rdev);
}
int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y,
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
index 1ee7fc9..0dfa508 100644
--- a/drivers/gpu/drm/radeon/radeon_pm.c
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
@@ -58,7 +58,7 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev, int static_switch)
{
int i;
- if (!static_switch)
+ if (rdev->pm.state != PM_STATE_DISABLED)
radeon_get_power_state(rdev, rdev->pm.planned_action);
mutex_lock(&rdev->ddev->struct_mutex);
@@ -147,8 +147,11 @@ static ssize_t radeon_set_power_state_static(struct device *dev,
mutex_lock(&rdev->pm.mutex);
if ((ps >= 0) && (ps < rdev->pm.num_power_states) &&
(cm >= 0) && (cm < rdev->pm.power_state[ps].num_clock_modes)) {
- if ((rdev->pm.active_crtc_count > 1) &&
- (rdev->pm.power_state[ps].flags & RADEON_PM_SINGLE_DISPLAY_ONLY)) {
+ if ((rdev->pm.active_crtc_count > 0) &&
+ (rdev->pm.power_state[ps].clock_info[cm].flags & RADEON_PM_MODE_NO_DISPLAY)) {
+ DRM_ERROR("Invalid power state for display: %d.%d\n", ps, cm);
+ } else if ((rdev->pm.active_crtc_count > 1) &&
+ (rdev->pm.power_state[ps].flags & RADEON_PM_STATE_SINGLE_DISPLAY_ONLY)) {
DRM_ERROR("Invalid power state for multi-head: %d.%d\n", ps, cm);
} else {
/* disable dynpm */
@@ -248,7 +251,7 @@ static void radeon_print_power_mode_info(struct radeon_device *rdev)
is_default ? "(default)" : "");
if ((rdev->flags & RADEON_IS_PCIE) && !(rdev->flags & RADEON_IS_IGP))
DRM_INFO("\t%d PCIE Lanes\n", rdev->pm.power_state[i].pcie_lanes);
- if (rdev->pm.power_state[i].flags & RADEON_PM_SINGLE_DISPLAY_ONLY)
+ if (rdev->pm.power_state[i].flags & RADEON_PM_STATE_SINGLE_DISPLAY_ONLY)
DRM_INFO("\tSingle display only\n");
DRM_INFO("\t%d Clock Mode(s)\n", rdev->pm.power_state[i].num_clock_modes);
for (j = 0; j < rdev->pm.power_state[i].num_clock_modes; j++) {
@@ -261,6 +264,8 @@ static void radeon_print_power_mode_info(struct radeon_device *rdev)
j,
rdev->pm.power_state[i].clock_info[j].sclk * 10,
rdev->pm.power_state[i].clock_info[j].mclk * 10);
+ if (rdev->pm.power_state[i].clock_info[j].flags & RADEON_PM_MODE_NO_DISPLAY)
+ DRM_INFO("\t\tNo display only\n");
}
}
}
@@ -318,7 +323,7 @@ void radeon_pm_fini(struct radeon_device *rdev)
/* reset default clocks */
rdev->pm.state = PM_STATE_DISABLED;
rdev->pm.planned_action = PM_ACTION_DEFAULT;
- radeon_pm_set_clocks(rdev, false);
+ radeon_pm_set_clocks(rdev, true);
} else if ((rdev->pm.current_power_state_index !=
rdev->pm.default_power_state_index) ||
(rdev->pm.current_clock_mode_index != 0)) {
@@ -342,9 +347,6 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev)
struct drm_crtc *crtc;
struct radeon_crtc *radeon_crtc;
- if (rdev->pm.state == PM_STATE_DISABLED)
- return;
-
mutex_lock(&rdev->pm.mutex);
rdev->pm.active_crtcs = 0;
@@ -358,13 +360,22 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev)
}
}
+ if (rdev->pm.state == PM_STATE_DISABLED) {
+ mutex_unlock(&rdev->pm.mutex);
+ return;
+ }
+
+ /* Note, radeon_pm_set_clocks is called with static_switch set
+ * to true since we always want to statically set the clocks,
+ * not wait for vbl.
+ */
if (rdev->pm.active_crtc_count > 1) {
if (rdev->pm.state == PM_STATE_ACTIVE) {
cancel_delayed_work(&rdev->pm.idle_work);
rdev->pm.state = PM_STATE_PAUSED;
- rdev->pm.planned_action = PM_ACTION_UPCLOCK;
- radeon_pm_set_clocks(rdev, false);
+ rdev->pm.planned_action = PM_ACTION_DEFAULT;
+ radeon_pm_set_clocks(rdev, true);
DRM_DEBUG("radeon: dynamic power management deactivated\n");
}
@@ -374,7 +385,7 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev)
if (rdev->pm.state == PM_STATE_MINIMUM) {
rdev->pm.state = PM_STATE_ACTIVE;
rdev->pm.planned_action = PM_ACTION_UPCLOCK;
- radeon_pm_set_clocks(rdev, false);
+ radeon_pm_set_clocks(rdev, true);
queue_delayed_work(rdev->wq, &rdev->pm.idle_work,
msecs_to_jiffies(RADEON_IDLE_LOOP_MS));
@@ -390,7 +401,7 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev)
rdev->pm.state = PM_STATE_MINIMUM;
rdev->pm.planned_action = PM_ACTION_MINIMUM;
- radeon_pm_set_clocks(rdev, false);
+ radeon_pm_set_clocks(rdev, true);
}
}
@@ -526,6 +537,9 @@ static void radeon_pm_idle_work_handler(struct work_struct *work)
}
}
+ /* Note, radeon_pm_set_clocks is called with static_switch set
+ * to false since we want to wait for vbl to avoid flicker.
+ */
if (rdev->pm.planned_action != PM_ACTION_NONE &&
jiffies > rdev->pm.action_timeout) {
radeon_pm_set_clocks(rdev, false);
--
1.5.6.3
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH 8/9] drm/radeon/kms/pm: rework power management
2010-05-07 21:16 ` [PATCH 7/9] drm/radeon/kms/pm: add support for no display power states Alex Deucher
@ 2010-05-07 21:16 ` Alex Deucher
2010-05-07 21:16 ` [PATCH 9/9] drm/radeon/kms/pm: make pm spam debug only Alex Deucher
0 siblings, 1 reply; 19+ messages in thread
From: Alex Deucher @ 2010-05-07 21:16 UTC (permalink / raw)
To: airlied, dri-devel; +Cc: mjg59
- Separate dynpm and profile based power management methods. You can select the pm method
by echoing the selected method ("dynpm" or "profile") to power_method in sysfs.
- Expose basic 4 profile in profile method
"default" - default clocks
"auto" - select between low and high based on ac/dc state
"low" - DC, low power mode
"high" - AC, performance mode
The current base profile is "default", but it should switched to "auto" once we've tested
on more systems. Switching the state is a matter of echoing the requested profile to
power_profile in sysfs. The lowest power states are selected automatically when dpms turns
the monitors off in all states but default.
- Remove dynamic fence-based reclocking for the moment. We can revisit this later once we
have basic pm in.
- Move pm init/fini to modesetting path. pm is tightly coupled with display state. Make sure
display side is initialized before pm.
- Add pm suspend/resume functions to make sure pm state is properly reinitialized on resume.
- Remove dynpm module option. It's now selectable via sysfs.
Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
---
drivers/gpu/drm/radeon/Kconfig | 1 +
drivers/gpu/drm/radeon/evergreen.c | 3 -
drivers/gpu/drm/radeon/r100.c | 128 ++-----
drivers/gpu/drm/radeon/r300.c | 3 -
drivers/gpu/drm/radeon/r420.c | 32 ++-
drivers/gpu/drm/radeon/r520.c | 2 -
drivers/gpu/drm/radeon/r600.c | 332 ++++++++++++-----
drivers/gpu/drm/radeon/radeon.h | 87 +++--
drivers/gpu/drm/radeon/radeon_asic.c | 56 ++--
drivers/gpu/drm/radeon/radeon_asic.h | 12 +-
drivers/gpu/drm/radeon/radeon_device.c | 2 +
drivers/gpu/drm/radeon/radeon_display.c | 4 +
drivers/gpu/drm/radeon/radeon_drv.c | 4 -
drivers/gpu/drm/radeon/radeon_pm.c | 628 +++++++++++++++++++------------
drivers/gpu/drm/radeon/rs400.c | 3 -
drivers/gpu/drm/radeon/rs600.c | 3 -
drivers/gpu/drm/radeon/rs690.c | 3 -
drivers/gpu/drm/radeon/rv515.c | 3 -
drivers/gpu/drm/radeon/rv770.c | 3 -
19 files changed, 790 insertions(+), 519 deletions(-)
diff --git a/drivers/gpu/drm/radeon/Kconfig b/drivers/gpu/drm/radeon/Kconfig
index 1c02d23..80c5b3e 100644
--- a/drivers/gpu/drm/radeon/Kconfig
+++ b/drivers/gpu/drm/radeon/Kconfig
@@ -1,6 +1,7 @@
config DRM_RADEON_KMS
bool "Enable modesetting on radeon by default - NEW DRIVER"
depends on DRM_RADEON
+ depends on POWER_SUPPLY
help
Choose this option if you want kernel modesetting enabled by default.
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
index 8d86d05..8c8e4d3 100644
--- a/drivers/gpu/drm/radeon/evergreen.c
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -2115,8 +2115,6 @@ int evergreen_init(struct radeon_device *rdev)
r = radeon_clocks_init(rdev);
if (r)
return r;
- /* Initialize power management */
- radeon_pm_init(rdev);
/* Fence driver */
r = radeon_fence_driver_init(rdev);
if (r)
@@ -2178,7 +2176,6 @@ int evergreen_init(struct radeon_device *rdev)
void evergreen_fini(struct radeon_device *rdev)
{
- radeon_pm_fini(rdev);
/*r600_blit_fini(rdev);*/
r700_cp_fini(rdev);
r600_wb_fini(rdev);
diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
index 4161a35..4c5d21b 100644
--- a/drivers/gpu/drm/radeon/r100.c
+++ b/drivers/gpu/drm/radeon/r100.c
@@ -68,22 +68,21 @@ MODULE_FIRMWARE(FIRMWARE_R520);
* r100,rv100,rs100,rv200,rs200,r200,rv250,rs300,rv280
*/
-void r100_get_power_state(struct radeon_device *rdev,
- enum radeon_pm_action action)
+void r100_pm_get_dynpm_state(struct radeon_device *rdev)
{
int i;
- rdev->pm.can_upclock = true;
- rdev->pm.can_downclock = true;
+ rdev->pm.dynpm_can_upclock = true;
+ rdev->pm.dynpm_can_downclock = true;
- switch (action) {
- case PM_ACTION_MINIMUM:
+ switch (rdev->pm.dynpm_planned_action) {
+ case DYNPM_ACTION_MINIMUM:
rdev->pm.requested_power_state_index = 0;
- rdev->pm.can_downclock = false;
+ rdev->pm.dynpm_can_downclock = false;
break;
- case PM_ACTION_DOWNCLOCK:
+ case DYNPM_ACTION_DOWNCLOCK:
if (rdev->pm.current_power_state_index == 0) {
rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index;
- rdev->pm.can_downclock = false;
+ rdev->pm.dynpm_can_downclock = false;
} else {
if (rdev->pm.active_crtc_count > 1) {
for (i = 0; i < rdev->pm.num_power_states; i++) {
@@ -108,10 +107,10 @@ void r100_get_power_state(struct radeon_device *rdev,
rdev->pm.requested_power_state_index++;
}
break;
- case PM_ACTION_UPCLOCK:
+ case DYNPM_ACTION_UPCLOCK:
if (rdev->pm.current_power_state_index == (rdev->pm.num_power_states - 1)) {
rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index;
- rdev->pm.can_upclock = false;
+ rdev->pm.dynpm_can_upclock = false;
} else {
if (rdev->pm.active_crtc_count > 1) {
for (i = (rdev->pm.num_power_states - 1); i >= 0; i--) {
@@ -130,11 +129,11 @@ void r100_get_power_state(struct radeon_device *rdev,
rdev->pm.current_power_state_index + 1;
}
break;
- case PM_ACTION_DEFAULT:
+ case DYNPM_ACTION_DEFAULT:
rdev->pm.requested_power_state_index = rdev->pm.default_power_state_index;
- rdev->pm.can_upclock = false;
+ rdev->pm.dynpm_can_upclock = false;
break;
- case PM_ACTION_NONE:
+ case DYNPM_ACTION_NONE:
default:
DRM_ERROR("Requested mode for not defined action\n");
return;
@@ -151,77 +150,33 @@ void r100_get_power_state(struct radeon_device *rdev,
pcie_lanes);
}
-void r100_set_power_state(struct radeon_device *rdev, bool static_switch)
-{
- u32 sclk, mclk;
-
- if (rdev->pm.current_power_state_index == rdev->pm.requested_power_state_index)
- return;
-
- if (radeon_gui_idle(rdev)) {
-
- sclk = rdev->pm.power_state[rdev->pm.requested_power_state_index].
- clock_info[rdev->pm.requested_clock_mode_index].sclk;
- if (sclk > rdev->clock.default_sclk)
- sclk = rdev->clock.default_sclk;
-
- mclk = rdev->pm.power_state[rdev->pm.requested_power_state_index].
- clock_info[rdev->pm.requested_clock_mode_index].mclk;
- if (mclk > rdev->clock.default_mclk)
- mclk = rdev->clock.default_mclk;
- /* don't change the mclk with multiple crtcs */
- if (rdev->pm.active_crtc_count > 1)
- mclk = rdev->clock.default_mclk;
-
- /* voltage, pcie lanes, etc.*/
- radeon_pm_misc(rdev);
-
- if (static_switch) {
- radeon_pm_prepare(rdev);
- /* set engine clock */
- if (sclk != rdev->pm.current_sclk) {
- radeon_set_engine_clock(rdev, sclk);
- rdev->pm.current_sclk = sclk;
- DRM_INFO("Setting: e: %d\n", sclk);
- }
- /* set memory clock */
- if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) {
- radeon_set_memory_clock(rdev, mclk);
- rdev->pm.current_mclk = mclk;
- DRM_INFO("Setting: m: %d\n", mclk);
- }
- radeon_pm_finish(rdev);
- } else {
- radeon_sync_with_vblank(rdev);
-
- if (!radeon_pm_in_vbl(rdev))
- return;
-
- radeon_pm_prepare(rdev);
- /* set engine clock */
- if (sclk != rdev->pm.current_sclk) {
- radeon_pm_debug_check_in_vbl(rdev, false);
- radeon_set_engine_clock(rdev, sclk);
- radeon_pm_debug_check_in_vbl(rdev, true);
- rdev->pm.current_sclk = sclk;
- DRM_INFO("Setting: e: %d\n", sclk);
- }
-
- /* set memory clock */
- if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) {
- radeon_pm_debug_check_in_vbl(rdev, false);
- radeon_set_memory_clock(rdev, mclk);
- radeon_pm_debug_check_in_vbl(rdev, true);
- rdev->pm.current_mclk = mclk;
- DRM_INFO("Setting: m: %d\n", mclk);
- }
- radeon_pm_finish(rdev);
- }
-
- rdev->pm.current_power_state_index = rdev->pm.requested_power_state_index;
- rdev->pm.current_clock_mode_index = rdev->pm.requested_clock_mode_index;
- } else
- DRM_INFO("pm: GUI not idle!!!\n");
+void r100_pm_init_profile(struct radeon_device *rdev)
+{
+ /* default */
+ rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index;
+ rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index;
+ rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 0;
+ /* low sh */
+ rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 0;
+ /* high sh */
+ rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index;
+ rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 0;
+ /* low mh */
+ rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index;
+ rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 0;
+ /* high mh */
+ rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index;
+ rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 0;
}
void r100_pm_misc(struct radeon_device *rdev)
@@ -3815,7 +3770,6 @@ int r100_suspend(struct radeon_device *rdev)
void r100_fini(struct radeon_device *rdev)
{
- radeon_pm_fini(rdev);
r100_cp_fini(rdev);
r100_wb_fini(rdev);
r100_ib_fini(rdev);
@@ -3871,8 +3825,6 @@ int r100_init(struct radeon_device *rdev)
r100_errata(rdev);
/* Initialize clocks */
radeon_get_clock_info(rdev->ddev);
- /* Initialize power management */
- radeon_pm_init(rdev);
/* initialize AGP */
if (rdev->flags & RADEON_IS_AGP) {
r = radeon_agp_init(rdev);
diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c
index 5d622cb..5c54db5 100644
--- a/drivers/gpu/drm/radeon/r300.c
+++ b/drivers/gpu/drm/radeon/r300.c
@@ -1345,7 +1345,6 @@ int r300_suspend(struct radeon_device *rdev)
void r300_fini(struct radeon_device *rdev)
{
- radeon_pm_fini(rdev);
r100_cp_fini(rdev);
r100_wb_fini(rdev);
r100_ib_fini(rdev);
@@ -1401,8 +1400,6 @@ int r300_init(struct radeon_device *rdev)
r300_errata(rdev);
/* Initialize clocks */
radeon_get_clock_info(rdev->ddev);
- /* Initialize power management */
- radeon_pm_init(rdev);
/* initialize AGP */
if (rdev->flags & RADEON_IS_AGP) {
r = radeon_agp_init(rdev);
diff --git a/drivers/gpu/drm/radeon/r420.c b/drivers/gpu/drm/radeon/r420.c
index 3759d83..87c0e38 100644
--- a/drivers/gpu/drm/radeon/r420.c
+++ b/drivers/gpu/drm/radeon/r420.c
@@ -36,6 +36,35 @@
#include "r420d.h"
#include "r420_reg_safe.h"
+void r420_pm_init_profile(struct radeon_device *rdev)
+{
+ /* default */
+ rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index;
+ rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index;
+ rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 0;
+ /* low sh */
+ rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = 1;
+ rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 0;
+ /* high sh */
+ rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index;
+ rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 0;
+ /* low mh */
+ rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index;
+ rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 0;
+ /* high mh */
+ rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index;
+ rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 0;
+}
+
static void r420_set_reg_safe(struct radeon_device *rdev)
{
rdev->config.r300.reg_safe_bm = r420_reg_safe_bm;
@@ -268,7 +297,6 @@ int r420_suspend(struct radeon_device *rdev)
void r420_fini(struct radeon_device *rdev)
{
- radeon_pm_fini(rdev);
r100_cp_fini(rdev);
r100_wb_fini(rdev);
r100_ib_fini(rdev);
@@ -328,8 +356,6 @@ int r420_init(struct radeon_device *rdev)
/* Initialize clocks */
radeon_get_clock_info(rdev->ddev);
- /* Initialize power management */
- radeon_pm_init(rdev);
/* initialize AGP */
if (rdev->flags & RADEON_IS_AGP) {
r = radeon_agp_init(rdev);
diff --git a/drivers/gpu/drm/radeon/r520.c b/drivers/gpu/drm/radeon/r520.c
index 870111e..34330df 100644
--- a/drivers/gpu/drm/radeon/r520.c
+++ b/drivers/gpu/drm/radeon/r520.c
@@ -261,8 +261,6 @@ int r520_init(struct radeon_device *rdev)
}
/* Initialize clocks */
radeon_get_clock_info(rdev->ddev);
- /* Initialize power management */
- radeon_pm_init(rdev);
/* initialize AGP */
if (rdev->flags & RADEON_IS_AGP) {
r = radeon_agp_init(rdev);
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index 08a328c..618d76d 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -92,13 +92,12 @@ void r600_gpu_init(struct radeon_device *rdev);
void r600_fini(struct radeon_device *rdev);
void r600_irq_disable(struct radeon_device *rdev);
-void r600_get_power_state(struct radeon_device *rdev,
- enum radeon_pm_action action)
+void r600_pm_get_dynpm_state(struct radeon_device *rdev)
{
int i;
- rdev->pm.can_upclock = true;
- rdev->pm.can_downclock = true;
+ rdev->pm.dynpm_can_upclock = true;
+ rdev->pm.dynpm_can_downclock = true;
/* power state array is low to high, default is first */
if ((rdev->flags & RADEON_IS_IGP) || (rdev->family == CHIP_R600)) {
@@ -107,16 +106,16 @@ void r600_get_power_state(struct radeon_device *rdev,
if (rdev->pm.num_power_states > 2)
min_power_state_index = 1;
- switch (action) {
- case PM_ACTION_MINIMUM:
+ switch (rdev->pm.dynpm_planned_action) {
+ case DYNPM_ACTION_MINIMUM:
rdev->pm.requested_power_state_index = min_power_state_index;
rdev->pm.requested_clock_mode_index = 0;
- rdev->pm.can_downclock = false;
+ rdev->pm.dynpm_can_downclock = false;
break;
- case PM_ACTION_DOWNCLOCK:
+ case DYNPM_ACTION_DOWNCLOCK:
if (rdev->pm.current_power_state_index == min_power_state_index) {
rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index;
- rdev->pm.can_downclock = false;
+ rdev->pm.dynpm_can_downclock = false;
} else {
if (rdev->pm.active_crtc_count > 1) {
for (i = 0; i < rdev->pm.num_power_states; i++) {
@@ -144,10 +143,10 @@ void r600_get_power_state(struct radeon_device *rdev,
rdev->pm.requested_power_state_index++;
}
break;
- case PM_ACTION_UPCLOCK:
+ case DYNPM_ACTION_UPCLOCK:
if (rdev->pm.current_power_state_index == (rdev->pm.num_power_states - 1)) {
rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index;
- rdev->pm.can_upclock = false;
+ rdev->pm.dynpm_can_upclock = false;
} else {
if (rdev->pm.active_crtc_count > 1) {
for (i = (rdev->pm.num_power_states - 1); i >= 0; i--) {
@@ -168,12 +167,12 @@ void r600_get_power_state(struct radeon_device *rdev,
}
rdev->pm.requested_clock_mode_index = 0;
break;
- case PM_ACTION_DEFAULT:
+ case DYNPM_ACTION_DEFAULT:
rdev->pm.requested_power_state_index = rdev->pm.default_power_state_index;
rdev->pm.requested_clock_mode_index = 0;
- rdev->pm.can_upclock = false;
+ rdev->pm.dynpm_can_upclock = false;
break;
- case PM_ACTION_NONE:
+ case DYNPM_ACTION_NONE:
default:
DRM_ERROR("Requested mode for not defined action\n");
return;
@@ -200,22 +199,22 @@ void r600_get_power_state(struct radeon_device *rdev,
} else
rdev->pm.requested_power_state_index = 1;
- switch (action) {
- case PM_ACTION_MINIMUM:
+ switch (rdev->pm.dynpm_planned_action) {
+ case DYNPM_ACTION_MINIMUM:
rdev->pm.requested_clock_mode_index = 0;
- rdev->pm.can_downclock = false;
+ rdev->pm.dynpm_can_downclock = false;
break;
- case PM_ACTION_DOWNCLOCK:
+ case DYNPM_ACTION_DOWNCLOCK:
if (rdev->pm.requested_power_state_index == rdev->pm.current_power_state_index) {
if (rdev->pm.current_clock_mode_index == 0) {
rdev->pm.requested_clock_mode_index = 0;
- rdev->pm.can_downclock = false;
+ rdev->pm.dynpm_can_downclock = false;
} else
rdev->pm.requested_clock_mode_index =
rdev->pm.current_clock_mode_index - 1;
} else {
rdev->pm.requested_clock_mode_index = 0;
- rdev->pm.can_downclock = false;
+ rdev->pm.dynpm_can_downclock = false;
}
/* don't use the power state if crtcs are active and no display flag is set */
if ((rdev->pm.active_crtc_count > 0) &&
@@ -225,27 +224,27 @@ void r600_get_power_state(struct radeon_device *rdev,
rdev->pm.requested_clock_mode_index++;
}
break;
- case PM_ACTION_UPCLOCK:
+ case DYNPM_ACTION_UPCLOCK:
if (rdev->pm.requested_power_state_index == rdev->pm.current_power_state_index) {
if (rdev->pm.current_clock_mode_index ==
(rdev->pm.power_state[rdev->pm.requested_power_state_index].num_clock_modes - 1)) {
rdev->pm.requested_clock_mode_index = rdev->pm.current_clock_mode_index;
- rdev->pm.can_upclock = false;
+ rdev->pm.dynpm_can_upclock = false;
} else
rdev->pm.requested_clock_mode_index =
rdev->pm.current_clock_mode_index + 1;
} else {
rdev->pm.requested_clock_mode_index =
rdev->pm.power_state[rdev->pm.requested_power_state_index].num_clock_modes - 1;
- rdev->pm.can_upclock = false;
+ rdev->pm.dynpm_can_upclock = false;
}
break;
- case PM_ACTION_DEFAULT:
+ case DYNPM_ACTION_DEFAULT:
rdev->pm.requested_power_state_index = rdev->pm.default_power_state_index;
rdev->pm.requested_clock_mode_index = 0;
- rdev->pm.can_upclock = false;
+ rdev->pm.dynpm_can_upclock = false;
break;
- case PM_ACTION_NONE:
+ case DYNPM_ACTION_NONE:
default:
DRM_ERROR("Requested mode for not defined action\n");
return;
@@ -261,73 +260,225 @@ void r600_get_power_state(struct radeon_device *rdev,
pcie_lanes);
}
-void r600_set_power_state(struct radeon_device *rdev, bool static_switch)
+static int r600_pm_get_type_index(struct radeon_device *rdev,
+ enum radeon_pm_state_type ps_type,
+ int instance)
{
- u32 sclk, mclk;
-
- if ((rdev->pm.requested_clock_mode_index == rdev->pm.current_clock_mode_index) &&
- (rdev->pm.requested_power_state_index == rdev->pm.current_power_state_index))
- return;
-
- if (radeon_gui_idle(rdev)) {
- sclk = rdev->pm.power_state[rdev->pm.requested_power_state_index].
- clock_info[rdev->pm.requested_clock_mode_index].sclk;
- if (sclk > rdev->clock.default_sclk)
- sclk = rdev->clock.default_sclk;
-
- mclk = rdev->pm.power_state[rdev->pm.requested_power_state_index].
- clock_info[rdev->pm.requested_clock_mode_index].mclk;
- if (mclk > rdev->clock.default_mclk)
- mclk = rdev->clock.default_mclk;
-
- /* voltage, pcie lanes, etc.*/
- radeon_pm_misc(rdev);
+ int i;
+ int found_instance = -1;
- if (static_switch) {
- radeon_pm_prepare(rdev);
- /* set engine clock */
- if (sclk != rdev->pm.current_sclk) {
- radeon_set_engine_clock(rdev, sclk);
- rdev->pm.current_sclk = sclk;
- DRM_INFO("Setting: e: %d\n", sclk);
- }
- /* set memory clock */
- if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) {
- radeon_set_memory_clock(rdev, mclk);
- rdev->pm.current_mclk = mclk;
- DRM_INFO("Setting: m: %d\n", mclk);
- }
- radeon_pm_finish(rdev);
+ for (i = 0; i < rdev->pm.num_power_states; i++) {
+ if (rdev->pm.power_state[i].type == ps_type) {
+ found_instance++;
+ if (found_instance == instance)
+ return i;
+ }
+ }
+ /* return default if no match */
+ return rdev->pm.default_power_state_index;
+}
+
+void rs780_pm_init_profile(struct radeon_device *rdev)
+{
+ if (rdev->pm.num_power_states == 2) {
+ /* default */
+ rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index;
+ rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index;
+ rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 0;
+ /* low sh */
+ rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 0;
+ /* high sh */
+ rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = 1;
+ rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 0;
+ /* low mh */
+ rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 0;
+ /* high mh */
+ rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = 1;
+ rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 0;
+ } else if (rdev->pm.num_power_states == 3) {
+ /* default */
+ rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index;
+ rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index;
+ rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 0;
+ /* low sh */
+ rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = 1;
+ rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = 1;
+ rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 0;
+ /* high sh */
+ rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = 1;
+ rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = 2;
+ rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 0;
+ /* low mh */
+ rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = 1;
+ rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = 1;
+ rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 0;
+ /* high mh */
+ rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = 1;
+ rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = 2;
+ rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 0;
+ } else {
+ /* default */
+ rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index;
+ rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index;
+ rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 0;
+ /* low sh */
+ rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = 2;
+ rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = 2;
+ rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 0;
+ /* high sh */
+ rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = 2;
+ rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = 3;
+ rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 0;
+ /* low mh */
+ rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = 2;
+ rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 0;
+ /* high mh */
+ rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = 2;
+ rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = 3;
+ rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 0;
+ }
+}
+
+void r600_pm_init_profile(struct radeon_device *rdev)
+{
+ if (rdev->family == CHIP_R600) {
+ /* XXX */
+ /* default */
+ rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index;
+ rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index;
+ rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 2;
+ /* low sh */
+ rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index;
+ rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index;
+ rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 2;
+ /* high sh */
+ rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index;
+ rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index;
+ rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 2;
+ /* low mh */
+ rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index;
+ rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index;
+ rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 2;
+ /* high mh */
+ rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index;
+ rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index;
+ rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 2;
+ } else if (rdev->flags & RADEON_IS_MOBILITY) {
+ /* default */
+ rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index;
+ rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index;
+ rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 2;
+ /* low sh */
+ rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx =
+ r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 0);
+ rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx =
+ r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 0);
+ rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 2;
+ /* high sh */
+ rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx =
+ r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0);
+ rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx =
+ r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0);
+ rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 2;
+ /* low mh */
+ rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx =
+ r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 1);
+ rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx =
+ r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 1);
+ rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 2;
+ /* high mh */
+ rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx =
+ r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 1);
+ rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx =
+ r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 1);
+ rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 2;
+ } else {
+ if (rdev->pm.num_power_states < 4) {
+ /* default */
+ rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index;
+ rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index;
+ rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 2;
+ /* low sh */
+ rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index;
+ rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index;
+ rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 2;
+ /* high sh */
+ rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index;
+ rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index;
+ rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 2;
+ /* low mh */
+ rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index;
+ rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index;
+ rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 2;
+ /* high mh */
+ rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index;
+ rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index;
+ rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 2;
} else {
- radeon_sync_with_vblank(rdev);
-
- if (!radeon_pm_in_vbl(rdev))
- return;
-
- radeon_pm_prepare(rdev);
- if (sclk != rdev->pm.current_sclk) {
- radeon_pm_debug_check_in_vbl(rdev, false);
- radeon_set_engine_clock(rdev, sclk);
- radeon_pm_debug_check_in_vbl(rdev, true);
- rdev->pm.current_sclk = sclk;
- DRM_INFO("Setting: e: %d\n", sclk);
- }
-
- /* set memory clock */
- if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) {
- radeon_pm_debug_check_in_vbl(rdev, false);
- radeon_set_memory_clock(rdev, mclk);
- radeon_pm_debug_check_in_vbl(rdev, true);
- rdev->pm.current_mclk = mclk;
- DRM_INFO("Setting: m: %d\n", mclk);
- }
- radeon_pm_finish(rdev);
+ /* default */
+ rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index;
+ rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index;
+ rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 2;
+ /* low sh */
+ rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = 1;
+ rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = 1;
+ rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 2;
+ /* high sh */
+ rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = 1;
+ rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = 1;
+ rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 2;
+ /* low mh */
+ rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = 3;
+ rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = 3;
+ rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 2;
+ /* high mh */
+ rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = 3;
+ rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = 3;
+ rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0;
+ rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 2;
}
-
- rdev->pm.current_power_state_index = rdev->pm.requested_power_state_index;
- rdev->pm.current_clock_mode_index = rdev->pm.requested_clock_mode_index;
- } else
- DRM_INFO("GUI not idle!!!\n");
+ }
}
void r600_pm_misc(struct radeon_device *rdev)
@@ -2320,8 +2471,6 @@ int r600_init(struct radeon_device *rdev)
r = radeon_clocks_init(rdev);
if (r)
return r;
- /* Initialize power management */
- radeon_pm_init(rdev);
/* Fence driver */
r = radeon_fence_driver_init(rdev);
if (r)
@@ -2386,7 +2535,6 @@ int r600_init(struct radeon_device *rdev)
void r600_fini(struct radeon_device *rdev)
{
- radeon_pm_fini(rdev);
r600_audio_fini(rdev);
r600_blit_fini(rdev);
r600_cp_fini(rdev);
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 480a83f..5c9ce2b 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -89,7 +89,6 @@ extern int radeon_testing;
extern int radeon_connector_table;
extern int radeon_tv;
extern int radeon_new_pll;
-extern int radeon_dynpm;
extern int radeon_audio;
extern int radeon_disp_priority;
extern int radeon_hw_i2c;
@@ -173,11 +172,10 @@ struct radeon_clock {
int radeon_pm_init(struct radeon_device *rdev);
void radeon_pm_fini(struct radeon_device *rdev);
void radeon_pm_compute_clocks(struct radeon_device *rdev);
+void radeon_pm_suspend(struct radeon_device *rdev);
+void radeon_pm_resume(struct radeon_device *rdev);
void radeon_combios_get_power_modes(struct radeon_device *rdev);
void radeon_atombios_get_power_modes(struct radeon_device *rdev);
-bool radeon_pm_in_vbl(struct radeon_device *rdev);
-bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish);
-void radeon_sync_with_vblank(struct radeon_device *rdev);
/*
* Fences.
@@ -608,18 +606,24 @@ struct radeon_wb {
* Equation between gpu/memory clock and available bandwidth is hw dependent
* (type of memory, bus size, efficiency, ...)
*/
-enum radeon_pm_state {
- PM_STATE_DISABLED,
- PM_STATE_MINIMUM,
- PM_STATE_PAUSED,
- PM_STATE_ACTIVE
+
+enum radeon_pm_method {
+ PM_METHOD_PROFILE,
+ PM_METHOD_DYNPM,
+};
+
+enum radeon_dynpm_state {
+ DYNPM_STATE_DISABLED,
+ DYNPM_STATE_MINIMUM,
+ DYNPM_STATE_PAUSED,
+ DYNPM_STATE_ACTIVE
};
-enum radeon_pm_action {
- PM_ACTION_NONE,
- PM_ACTION_MINIMUM,
- PM_ACTION_DOWNCLOCK,
- PM_ACTION_UPCLOCK,
- PM_ACTION_DEFAULT
+enum radeon_dynpm_action {
+ DYNPM_ACTION_NONE,
+ DYNPM_ACTION_MINIMUM,
+ DYNPM_ACTION_DOWNCLOCK,
+ DYNPM_ACTION_UPCLOCK,
+ DYNPM_ACTION_DEFAULT
};
enum radeon_voltage_type {
@@ -637,11 +641,25 @@ enum radeon_pm_state_type {
POWER_STATE_TYPE_PERFORMANCE,
};
-enum radeon_pm_clock_mode_type {
- POWER_MODE_TYPE_DEFAULT,
- POWER_MODE_TYPE_LOW,
- POWER_MODE_TYPE_MID,
- POWER_MODE_TYPE_HIGH,
+enum radeon_pm_profile_type {
+ PM_PROFILE_DEFAULT,
+ PM_PROFILE_AUTO,
+ PM_PROFILE_LOW,
+ PM_PROFILE_HIGH,
+};
+
+#define PM_PROFILE_DEFAULT_IDX 0
+#define PM_PROFILE_LOW_SH_IDX 1
+#define PM_PROFILE_HIGH_SH_IDX 2
+#define PM_PROFILE_LOW_MH_IDX 3
+#define PM_PROFILE_HIGH_MH_IDX 4
+#define PM_PROFILE_MAX 5
+
+struct radeon_pm_profile {
+ int dpms_off_ps_idx;
+ int dpms_on_ps_idx;
+ int dpms_off_cm_idx;
+ int dpms_on_cm_idx;
};
struct radeon_voltage {
@@ -696,12 +714,6 @@ struct radeon_power_state {
struct radeon_pm {
struct mutex mutex;
- struct delayed_work idle_work;
- enum radeon_pm_state state;
- enum radeon_pm_action planned_action;
- unsigned long action_timeout;
- bool can_upclock;
- bool can_downclock;
u32 active_crtcs;
int active_crtc_count;
int req_vblank;
@@ -731,6 +743,19 @@ struct radeon_pm {
u32 current_sclk;
u32 current_mclk;
struct radeon_i2c_chan *i2c_bus;
+ /* selected pm method */
+ enum radeon_pm_method pm_method;
+ /* dynpm power management */
+ struct delayed_work dynpm_idle_work;
+ enum radeon_dynpm_state dynpm_state;
+ enum radeon_dynpm_action dynpm_planned_action;
+ unsigned long dynpm_action_timeout;
+ bool dynpm_can_upclock;
+ bool dynpm_can_downclock;
+ /* profile-based power management */
+ enum radeon_pm_profile_type profile;
+ int profile_index;
+ struct radeon_pm_profile profiles[PM_PROFILE_MAX];
};
@@ -819,11 +844,12 @@ struct radeon_asic {
*/
void (*ioctl_wait_idle)(struct radeon_device *rdev, struct radeon_bo *bo);
bool (*gui_idle)(struct radeon_device *rdev);
- void (*get_power_state)(struct radeon_device *rdev, enum radeon_pm_action action);
- void (*set_power_state)(struct radeon_device *rdev, bool static_switch);
+ /* power management */
void (*pm_misc)(struct radeon_device *rdev);
void (*pm_prepare)(struct radeon_device *rdev);
void (*pm_finish)(struct radeon_device *rdev);
+ void (*pm_init_profile)(struct radeon_device *rdev);
+ void (*pm_get_dynpm_state)(struct radeon_device *rdev);
};
/*
@@ -1041,6 +1067,7 @@ struct radeon_device {
uint8_t audio_category_code;
bool powered_down;
+ struct notifier_block acpi_nb;
};
int radeon_device_init(struct radeon_device *rdev,
@@ -1232,11 +1259,11 @@ static inline void radeon_ring_write(struct radeon_device *rdev, uint32_t v)
#define radeon_hpd_sense(rdev, hpd) (rdev)->asic->hpd_sense((rdev), (hpd))
#define radeon_hpd_set_polarity(rdev, hpd) (rdev)->asic->hpd_set_polarity((rdev), (hpd))
#define radeon_gui_idle(rdev) (rdev)->asic->gui_idle((rdev))
-#define radeon_get_power_state(rdev, a) (rdev)->asic->get_power_state((rdev), (a))
-#define radeon_set_power_state(rdev, s) (rdev)->asic->set_power_state((rdev), (s))
#define radeon_pm_misc(rdev) (rdev)->asic->pm_misc((rdev))
#define radeon_pm_prepare(rdev) (rdev)->asic->pm_prepare((rdev))
#define radeon_pm_finish(rdev) (rdev)->asic->pm_finish((rdev))
+#define radeon_pm_init_profile(rdev) (rdev)->asic->pm_init_profile((rdev))
+#define radeon_pm_get_dynpm_state(rdev) (rdev)->asic->pm_get_dynpm_state((rdev))
/* Common functions */
/* AGP */
diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c
index 1e6f17b..e57df08 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.c
+++ b/drivers/gpu/drm/radeon/radeon_asic.c
@@ -166,11 +166,11 @@ static struct radeon_asic r100_asic = {
.hpd_set_polarity = &r100_hpd_set_polarity,
.ioctl_wait_idle = NULL,
.gui_idle = &r100_gui_idle,
- .get_power_state = &r100_get_power_state,
- .set_power_state = &r100_set_power_state,
.pm_misc = &r100_pm_misc,
.pm_prepare = &r100_pm_prepare,
.pm_finish = &r100_pm_finish,
+ .pm_init_profile = &r100_pm_init_profile,
+ .pm_get_dynpm_state = &r100_pm_get_dynpm_state,
};
static struct radeon_asic r200_asic = {
@@ -210,11 +210,11 @@ static struct radeon_asic r200_asic = {
.hpd_set_polarity = &r100_hpd_set_polarity,
.ioctl_wait_idle = NULL,
.gui_idle = &r100_gui_idle,
- .get_power_state = &r100_get_power_state,
- .set_power_state = &r100_set_power_state,
.pm_misc = &r100_pm_misc,
.pm_prepare = &r100_pm_prepare,
.pm_finish = &r100_pm_finish,
+ .pm_init_profile = &r100_pm_init_profile,
+ .pm_get_dynpm_state = &r100_pm_get_dynpm_state,
};
static struct radeon_asic r300_asic = {
@@ -255,11 +255,11 @@ static struct radeon_asic r300_asic = {
.hpd_set_polarity = &r100_hpd_set_polarity,
.ioctl_wait_idle = NULL,
.gui_idle = &r100_gui_idle,
- .get_power_state = &r100_get_power_state,
- .set_power_state = &r100_set_power_state,
.pm_misc = &r100_pm_misc,
.pm_prepare = &r100_pm_prepare,
.pm_finish = &r100_pm_finish,
+ .pm_init_profile = &r100_pm_init_profile,
+ .pm_get_dynpm_state = &r100_pm_get_dynpm_state,
};
static struct radeon_asic r300_asic_pcie = {
@@ -299,11 +299,11 @@ static struct radeon_asic r300_asic_pcie = {
.hpd_set_polarity = &r100_hpd_set_polarity,
.ioctl_wait_idle = NULL,
.gui_idle = &r100_gui_idle,
- .get_power_state = &r100_get_power_state,
- .set_power_state = &r100_set_power_state,
.pm_misc = &r100_pm_misc,
.pm_prepare = &r100_pm_prepare,
.pm_finish = &r100_pm_finish,
+ .pm_init_profile = &r100_pm_init_profile,
+ .pm_get_dynpm_state = &r100_pm_get_dynpm_state,
};
static struct radeon_asic r420_asic = {
@@ -344,11 +344,11 @@ static struct radeon_asic r420_asic = {
.hpd_set_polarity = &r100_hpd_set_polarity,
.ioctl_wait_idle = NULL,
.gui_idle = &r100_gui_idle,
- .get_power_state = &r100_get_power_state,
- .set_power_state = &r100_set_power_state,
.pm_misc = &r100_pm_misc,
.pm_prepare = &r100_pm_prepare,
.pm_finish = &r100_pm_finish,
+ .pm_init_profile = &r420_pm_init_profile,
+ .pm_get_dynpm_state = &r100_pm_get_dynpm_state,
};
static struct radeon_asic rs400_asic = {
@@ -389,11 +389,11 @@ static struct radeon_asic rs400_asic = {
.hpd_set_polarity = &r100_hpd_set_polarity,
.ioctl_wait_idle = NULL,
.gui_idle = &r100_gui_idle,
- .get_power_state = &r100_get_power_state,
- .set_power_state = &r100_set_power_state,
.pm_misc = &r100_pm_misc,
.pm_prepare = &r100_pm_prepare,
.pm_finish = &r100_pm_finish,
+ .pm_init_profile = &r100_pm_init_profile,
+ .pm_get_dynpm_state = &r100_pm_get_dynpm_state,
};
static struct radeon_asic rs600_asic = {
@@ -434,11 +434,11 @@ static struct radeon_asic rs600_asic = {
.hpd_set_polarity = &rs600_hpd_set_polarity,
.ioctl_wait_idle = NULL,
.gui_idle = &r100_gui_idle,
- .get_power_state = &r100_get_power_state,
- .set_power_state = &r100_set_power_state,
.pm_misc = &rs600_pm_misc,
.pm_prepare = &rs600_pm_prepare,
.pm_finish = &rs600_pm_finish,
+ .pm_init_profile = &r420_pm_init_profile,
+ .pm_get_dynpm_state = &r100_pm_get_dynpm_state,
};
static struct radeon_asic rs690_asic = {
@@ -479,11 +479,11 @@ static struct radeon_asic rs690_asic = {
.hpd_set_polarity = &rs600_hpd_set_polarity,
.ioctl_wait_idle = NULL,
.gui_idle = &r100_gui_idle,
- .get_power_state = &r100_get_power_state,
- .set_power_state = &r100_set_power_state,
.pm_misc = &rs600_pm_misc,
.pm_prepare = &rs600_pm_prepare,
.pm_finish = &rs600_pm_finish,
+ .pm_init_profile = &r420_pm_init_profile,
+ .pm_get_dynpm_state = &r100_pm_get_dynpm_state,
};
static struct radeon_asic rv515_asic = {
@@ -524,11 +524,11 @@ static struct radeon_asic rv515_asic = {
.hpd_set_polarity = &rs600_hpd_set_polarity,
.ioctl_wait_idle = NULL,
.gui_idle = &r100_gui_idle,
- .get_power_state = &r100_get_power_state,
- .set_power_state = &r100_set_power_state,
.pm_misc = &rs600_pm_misc,
.pm_prepare = &rs600_pm_prepare,
.pm_finish = &rs600_pm_finish,
+ .pm_init_profile = &r420_pm_init_profile,
+ .pm_get_dynpm_state = &r100_pm_get_dynpm_state,
};
static struct radeon_asic r520_asic = {
@@ -569,11 +569,11 @@ static struct radeon_asic r520_asic = {
.hpd_set_polarity = &rs600_hpd_set_polarity,
.ioctl_wait_idle = NULL,
.gui_idle = &r100_gui_idle,
- .get_power_state = &r100_get_power_state,
- .set_power_state = &r100_set_power_state,
.pm_misc = &rs600_pm_misc,
.pm_prepare = &rs600_pm_prepare,
.pm_finish = &rs600_pm_finish,
+ .pm_init_profile = &r420_pm_init_profile,
+ .pm_get_dynpm_state = &r100_pm_get_dynpm_state,
};
static struct radeon_asic r600_asic = {
@@ -613,11 +613,11 @@ static struct radeon_asic r600_asic = {
.hpd_set_polarity = &r600_hpd_set_polarity,
.ioctl_wait_idle = r600_ioctl_wait_idle,
.gui_idle = &r600_gui_idle,
- .get_power_state = &r600_get_power_state,
- .set_power_state = &r600_set_power_state,
.pm_misc = &r600_pm_misc,
.pm_prepare = &rs600_pm_prepare,
.pm_finish = &rs600_pm_finish,
+ .pm_init_profile = &r600_pm_init_profile,
+ .pm_get_dynpm_state = &r600_pm_get_dynpm_state,
};
static struct radeon_asic rs780_asic = {
@@ -657,11 +657,11 @@ static struct radeon_asic rs780_asic = {
.hpd_set_polarity = &r600_hpd_set_polarity,
.ioctl_wait_idle = r600_ioctl_wait_idle,
.gui_idle = &r600_gui_idle,
- .get_power_state = &r600_get_power_state,
- .set_power_state = &r600_set_power_state,
.pm_misc = &r600_pm_misc,
.pm_prepare = &rs600_pm_prepare,
.pm_finish = &rs600_pm_finish,
+ .pm_init_profile = &rs780_pm_init_profile,
+ .pm_get_dynpm_state = &r600_pm_get_dynpm_state,
};
static struct radeon_asic rv770_asic = {
@@ -701,11 +701,11 @@ static struct radeon_asic rv770_asic = {
.hpd_set_polarity = &r600_hpd_set_polarity,
.ioctl_wait_idle = r600_ioctl_wait_idle,
.gui_idle = &r600_gui_idle,
- .get_power_state = &r600_get_power_state,
- .set_power_state = &r600_set_power_state,
.pm_misc = &rv770_pm_misc,
.pm_prepare = &rs600_pm_prepare,
.pm_finish = &rs600_pm_finish,
+ .pm_init_profile = &r600_pm_init_profile,
+ .pm_get_dynpm_state = &r600_pm_get_dynpm_state,
};
static struct radeon_asic evergreen_asic = {
@@ -743,11 +743,11 @@ static struct radeon_asic evergreen_asic = {
.hpd_sense = &evergreen_hpd_sense,
.hpd_set_polarity = &evergreen_hpd_set_polarity,
.gui_idle = &r600_gui_idle,
- .get_power_state = &r600_get_power_state,
- .set_power_state = &r600_set_power_state,
.pm_misc = &evergreen_pm_misc,
.pm_prepare = &evergreen_pm_prepare,
.pm_finish = &evergreen_pm_finish,
+ .pm_init_profile = &r600_pm_init_profile,
+ .pm_get_dynpm_state = &r600_pm_get_dynpm_state,
};
int radeon_asic_init(struct radeon_device *rdev)
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index 8a12786..5c40a3d 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -127,12 +127,11 @@ void r100_enable_bm(struct radeon_device *rdev);
void r100_set_common_regs(struct radeon_device *rdev);
void r100_bm_disable(struct radeon_device *rdev);
extern bool r100_gui_idle(struct radeon_device *rdev);
-extern void r100_set_power_state(struct radeon_device *rdev, bool static_switch);
-extern void r100_get_power_state(struct radeon_device *rdev,
- enum radeon_pm_action action);
extern void r100_pm_misc(struct radeon_device *rdev);
extern void r100_pm_prepare(struct radeon_device *rdev);
extern void r100_pm_finish(struct radeon_device *rdev);
+extern void r100_pm_init_profile(struct radeon_device *rdev);
+extern void r100_pm_get_dynpm_state(struct radeon_device *rdev);
/*
* r200,rv250,rs300,rv280
@@ -170,6 +169,7 @@ extern int r420_init(struct radeon_device *rdev);
extern void r420_fini(struct radeon_device *rdev);
extern int r420_suspend(struct radeon_device *rdev);
extern int r420_resume(struct radeon_device *rdev);
+extern void r420_pm_init_profile(struct radeon_device *rdev);
/*
* rs400,rs480
@@ -281,10 +281,10 @@ void r600_hpd_set_polarity(struct radeon_device *rdev,
enum radeon_hpd_id hpd);
extern void r600_ioctl_wait_idle(struct radeon_device *rdev, struct radeon_bo *bo);
extern bool r600_gui_idle(struct radeon_device *rdev);
-extern void r600_set_power_state(struct radeon_device *rdev, bool static_switch);
-extern void r600_get_power_state(struct radeon_device *rdev,
- enum radeon_pm_action action);
extern void r600_pm_misc(struct radeon_device *rdev);
+extern void r600_pm_init_profile(struct radeon_device *rdev);
+extern void rs780_pm_init_profile(struct radeon_device *rdev);
+extern void r600_pm_get_dynpm_state(struct radeon_device *rdev);
/*
* rv770,rv730,rv710,rv740
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
index e249da8..a20b612 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -748,6 +748,7 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state)
radeon_save_bios_scratch_regs(rdev);
+ radeon_pm_suspend(rdev);
radeon_suspend(rdev);
radeon_hpd_fini(rdev);
/* evict remaining vram memory */
@@ -783,6 +784,7 @@ int radeon_resume_kms(struct drm_device *dev)
/* resume AGP if in use */
radeon_agp_resume(rdev);
radeon_resume(rdev);
+ radeon_pm_resume(rdev);
radeon_restore_bios_scratch_regs(rdev);
radeon_fbdev_set_suspend(rdev, 0);
release_console_sem();
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index 25d20bc..bd44f88 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -1030,6 +1030,9 @@ int radeon_modeset_init(struct radeon_device *rdev)
/* initialize hpd */
radeon_hpd_init(rdev);
+ /* Initialize power management */
+ radeon_pm_init(rdev);
+
radeon_fbdev_init(rdev);
return 0;
}
@@ -1038,6 +1041,7 @@ void radeon_modeset_fini(struct radeon_device *rdev)
{
radeon_fbdev_fini(rdev);
kfree(rdev->mode_info.bios_hardcoded_edid);
+ radeon_pm_fini(rdev);
if (rdev->mode_info.mode_config_initialized) {
radeon_hpd_fini(rdev);
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c
index 4b05563..ff7baad 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -91,7 +91,6 @@ int radeon_testing = 0;
int radeon_connector_table = 0;
int radeon_tv = 1;
int radeon_new_pll = -1;
-int radeon_dynpm = -1;
int radeon_audio = 1;
int radeon_disp_priority = 0;
int radeon_hw_i2c = 0;
@@ -132,9 +131,6 @@ module_param_named(tv, radeon_tv, int, 0444);
MODULE_PARM_DESC(new_pll, "Select new PLL code");
module_param_named(new_pll, radeon_new_pll, int, 0444);
-MODULE_PARM_DESC(dynpm, "Disable/Enable dynamic power management (1 = enable)");
-module_param_named(dynpm, radeon_dynpm, int, 0444);
-
MODULE_PARM_DESC(audio, "Audio enable (0 = disable)");
module_param_named(audio, radeon_audio, int, 0444);
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
index 0dfa508..1827317 100644
--- a/drivers/gpu/drm/radeon/radeon_pm.c
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
@@ -23,14 +23,98 @@
#include "drmP.h"
#include "radeon.h"
#include "avivod.h"
+#ifdef CONFIG_ACPI
+#include <linux/acpi.h>
+#endif
+#include <linux/power_supply.h>
#define RADEON_IDLE_LOOP_MS 100
#define RADEON_RECLOCK_DELAY_MS 200
#define RADEON_WAIT_VBLANK_TIMEOUT 200
#define RADEON_WAIT_IDLE_TIMEOUT 200
-static void radeon_pm_idle_work_handler(struct work_struct *work);
+static void radeon_dynpm_idle_work_handler(struct work_struct *work);
static int radeon_debugfs_pm_init(struct radeon_device *rdev);
+static bool radeon_pm_in_vbl(struct radeon_device *rdev);
+static bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish);
+static void radeon_pm_update_profile(struct radeon_device *rdev);
+static void radeon_pm_set_clocks(struct radeon_device *rdev);
+
+#define ACPI_AC_CLASS "ac_adapter"
+
+#ifdef CONFIG_ACPI
+static int radeon_acpi_event(struct notifier_block *nb,
+ unsigned long val,
+ void *data)
+{
+ struct radeon_device *rdev = container_of(nb, struct radeon_device, acpi_nb);
+ struct acpi_bus_event *entry = (struct acpi_bus_event *)data;
+
+ if (strcmp(entry->device_class, ACPI_AC_CLASS) == 0) {
+ if (power_supply_is_system_supplied() > 0)
+ DRM_INFO("pm: AC\n");
+ else
+ DRM_INFO("pm: DC\n");
+
+ if (rdev->pm.pm_method == PM_METHOD_PROFILE) {
+ if (rdev->pm.profile == PM_PROFILE_AUTO) {
+ mutex_lock(&rdev->pm.mutex);
+ radeon_pm_update_profile(rdev);
+ radeon_pm_set_clocks(rdev);
+ mutex_unlock(&rdev->pm.mutex);
+ }
+ }
+ }
+
+ return NOTIFY_OK;
+}
+#endif
+
+static void radeon_pm_update_profile(struct radeon_device *rdev)
+{
+ switch (rdev->pm.profile) {
+ case PM_PROFILE_DEFAULT:
+ rdev->pm.profile_index = PM_PROFILE_DEFAULT_IDX;
+ break;
+ case PM_PROFILE_AUTO:
+ if (power_supply_is_system_supplied() > 0) {
+ if (rdev->pm.active_crtc_count > 1)
+ rdev->pm.profile_index = PM_PROFILE_HIGH_MH_IDX;
+ else
+ rdev->pm.profile_index = PM_PROFILE_HIGH_SH_IDX;
+ } else {
+ if (rdev->pm.active_crtc_count > 1)
+ rdev->pm.profile_index = PM_PROFILE_LOW_MH_IDX;
+ else
+ rdev->pm.profile_index = PM_PROFILE_LOW_SH_IDX;
+ }
+ break;
+ case PM_PROFILE_LOW:
+ if (rdev->pm.active_crtc_count > 1)
+ rdev->pm.profile_index = PM_PROFILE_LOW_MH_IDX;
+ else
+ rdev->pm.profile_index = PM_PROFILE_LOW_SH_IDX;
+ break;
+ case PM_PROFILE_HIGH:
+ if (rdev->pm.active_crtc_count > 1)
+ rdev->pm.profile_index = PM_PROFILE_HIGH_MH_IDX;
+ else
+ rdev->pm.profile_index = PM_PROFILE_HIGH_SH_IDX;
+ break;
+ }
+
+ if (rdev->pm.active_crtc_count == 0) {
+ rdev->pm.requested_power_state_index =
+ rdev->pm.profiles[rdev->pm.profile_index].dpms_off_ps_idx;
+ rdev->pm.requested_clock_mode_index =
+ rdev->pm.profiles[rdev->pm.profile_index].dpms_off_cm_idx;
+ } else {
+ rdev->pm.requested_power_state_index =
+ rdev->pm.profiles[rdev->pm.profile_index].dpms_on_ps_idx;
+ rdev->pm.requested_clock_mode_index =
+ rdev->pm.profiles[rdev->pm.profile_index].dpms_on_cm_idx;
+ }
+}
static void radeon_unmap_vram_bos(struct radeon_device *rdev)
{
@@ -54,12 +138,93 @@ static void radeon_unmap_vram_bos(struct radeon_device *rdev)
ttm_bo_unmap_virtual(&rdev->r600_blit.shader_obj->tbo);
}
-static void radeon_pm_set_clocks(struct radeon_device *rdev, int static_switch)
+static void radeon_sync_with_vblank(struct radeon_device *rdev)
{
- int i;
+ if (rdev->pm.active_crtcs) {
+ rdev->pm.vblank_sync = false;
+ wait_event_timeout(
+ rdev->irq.vblank_queue, rdev->pm.vblank_sync,
+ msecs_to_jiffies(RADEON_WAIT_VBLANK_TIMEOUT));
+ }
+}
+
+static void radeon_set_power_state(struct radeon_device *rdev)
+{
+ u32 sclk, mclk;
+
+ if ((rdev->pm.requested_clock_mode_index == rdev->pm.current_clock_mode_index) &&
+ (rdev->pm.requested_power_state_index == rdev->pm.current_power_state_index))
+ return;
+
+ if (radeon_gui_idle(rdev)) {
+ sclk = rdev->pm.power_state[rdev->pm.requested_power_state_index].
+ clock_info[rdev->pm.requested_clock_mode_index].sclk;
+ if (sclk > rdev->clock.default_sclk)
+ sclk = rdev->clock.default_sclk;
+
+ mclk = rdev->pm.power_state[rdev->pm.requested_power_state_index].
+ clock_info[rdev->pm.requested_clock_mode_index].mclk;
+ if (mclk > rdev->clock.default_mclk)
+ mclk = rdev->clock.default_mclk;
+
+ /* voltage, pcie lanes, etc.*/
+ radeon_pm_misc(rdev);
+
+ if (rdev->pm.pm_method == PM_METHOD_DYNPM) {
+ radeon_sync_with_vblank(rdev);
+
+ if (!radeon_pm_in_vbl(rdev))
+ return;
+
+ radeon_pm_prepare(rdev);
+ /* set engine clock */
+ if (sclk != rdev->pm.current_sclk) {
+ radeon_pm_debug_check_in_vbl(rdev, false);
+ radeon_set_engine_clock(rdev, sclk);
+ radeon_pm_debug_check_in_vbl(rdev, true);
+ rdev->pm.current_sclk = sclk;
+ DRM_INFO("Setting: e: %d\n", sclk);
+ }
+
+ /* set memory clock */
+ if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) {
+ radeon_pm_debug_check_in_vbl(rdev, false);
+ radeon_set_memory_clock(rdev, mclk);
+ radeon_pm_debug_check_in_vbl(rdev, true);
+ rdev->pm.current_mclk = mclk;
+ DRM_INFO("Setting: m: %d\n", mclk);
+ }
+ radeon_pm_finish(rdev);
+ } else {
+ /* set engine clock */
+ if (sclk != rdev->pm.current_sclk) {
+ radeon_sync_with_vblank(rdev);
+ radeon_pm_prepare(rdev);
+ radeon_set_engine_clock(rdev, sclk);
+ radeon_pm_finish(rdev);
+ rdev->pm.current_sclk = sclk;
+ DRM_INFO("Setting: e: %d\n", sclk);
+ }
+ /* set memory clock */
+ if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) {
+ radeon_sync_with_vblank(rdev);
+ radeon_pm_prepare(rdev);
+ radeon_set_memory_clock(rdev, mclk);
+ radeon_pm_finish(rdev);
+ rdev->pm.current_mclk = mclk;
+ DRM_INFO("Setting: m: %d\n", mclk);
+ }
+ }
- if (rdev->pm.state != PM_STATE_DISABLED)
- radeon_get_power_state(rdev, rdev->pm.planned_action);
+ rdev->pm.current_power_state_index = rdev->pm.requested_power_state_index;
+ rdev->pm.current_clock_mode_index = rdev->pm.requested_clock_mode_index;
+ } else
+ DRM_INFO("pm: GUI not idle!!!\n");
+}
+
+static void radeon_pm_set_clocks(struct radeon_device *rdev)
+{
+ int i;
mutex_lock(&rdev->ddev->struct_mutex);
mutex_lock(&rdev->vram_mutex);
@@ -67,27 +232,31 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev, int static_switch)
/* gui idle int has issues on older chips it seems */
if (rdev->family >= CHIP_R600) {
- /* wait for GPU idle */
- rdev->pm.gui_idle = false;
- rdev->irq.gui_idle = true;
- radeon_irq_set(rdev);
- wait_event_interruptible_timeout(
- rdev->irq.idle_queue, rdev->pm.gui_idle,
- msecs_to_jiffies(RADEON_WAIT_IDLE_TIMEOUT));
- rdev->irq.gui_idle = false;
- radeon_irq_set(rdev);
+ if (rdev->irq.installed) {
+ /* wait for GPU idle */
+ rdev->pm.gui_idle = false;
+ rdev->irq.gui_idle = true;
+ radeon_irq_set(rdev);
+ wait_event_interruptible_timeout(
+ rdev->irq.idle_queue, rdev->pm.gui_idle,
+ msecs_to_jiffies(RADEON_WAIT_IDLE_TIMEOUT));
+ rdev->irq.gui_idle = false;
+ radeon_irq_set(rdev);
+ }
} else {
- struct radeon_fence *fence;
- radeon_ring_alloc(rdev, 64);
- radeon_fence_create(rdev, &fence);
- radeon_fence_emit(rdev, fence);
- radeon_ring_commit(rdev);
- radeon_fence_wait(fence, false);
- radeon_fence_unref(&fence);
+ if (rdev->cp.ready) {
+ struct radeon_fence *fence;
+ radeon_ring_alloc(rdev, 64);
+ radeon_fence_create(rdev, &fence);
+ radeon_fence_emit(rdev, fence);
+ radeon_ring_commit(rdev);
+ radeon_fence_wait(fence, false);
+ radeon_fence_unref(&fence);
+ }
}
radeon_unmap_vram_bos(rdev);
- if (!static_switch) {
+ if (rdev->irq.installed) {
for (i = 0; i < rdev->num_crtc; i++) {
if (rdev->pm.active_crtcs & (1 << i)) {
rdev->pm.req_vblank |= (1 << i);
@@ -96,9 +265,9 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev, int static_switch)
}
}
- radeon_set_power_state(rdev, static_switch);
+ radeon_set_power_state(rdev);
- if (!static_switch) {
+ if (rdev->irq.installed) {
for (i = 0; i < rdev->num_crtc; i++) {
if (rdev->pm.req_vblank & (1 << i)) {
rdev->pm.req_vblank &= ~(1 << i);
@@ -112,230 +281,195 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev, int static_switch)
if (rdev->pm.active_crtc_count)
radeon_bandwidth_update(rdev);
- rdev->pm.planned_action = PM_ACTION_NONE;
+ rdev->pm.dynpm_planned_action = DYNPM_ACTION_NONE;
mutex_unlock(&rdev->cp.mutex);
mutex_unlock(&rdev->vram_mutex);
mutex_unlock(&rdev->ddev->struct_mutex);
}
-static ssize_t radeon_get_power_state_static(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t radeon_get_pm_profile(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
struct radeon_device *rdev = ddev->dev_private;
+ int cp = rdev->pm.profile;
- return snprintf(buf, PAGE_SIZE, "%d.%d\n", rdev->pm.current_power_state_index,
- rdev->pm.current_clock_mode_index);
+ return snprintf(buf, PAGE_SIZE, "%s\n",
+ (cp == PM_PROFILE_AUTO) ? "auto" :
+ (cp == PM_PROFILE_LOW) ? "low" :
+ (cp == PM_PROFILE_HIGH) ? "high" : "default");
}
-static ssize_t radeon_set_power_state_static(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t count)
+static ssize_t radeon_set_pm_profile(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
{
struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
struct radeon_device *rdev = ddev->dev_private;
- int ps, cm;
-
- if (sscanf(buf, "%u.%u", &ps, &cm) != 2) {
- DRM_ERROR("Invalid power state!\n");
- return count;
- }
mutex_lock(&rdev->pm.mutex);
- if ((ps >= 0) && (ps < rdev->pm.num_power_states) &&
- (cm >= 0) && (cm < rdev->pm.power_state[ps].num_clock_modes)) {
- if ((rdev->pm.active_crtc_count > 0) &&
- (rdev->pm.power_state[ps].clock_info[cm].flags & RADEON_PM_MODE_NO_DISPLAY)) {
- DRM_ERROR("Invalid power state for display: %d.%d\n", ps, cm);
- } else if ((rdev->pm.active_crtc_count > 1) &&
- (rdev->pm.power_state[ps].flags & RADEON_PM_STATE_SINGLE_DISPLAY_ONLY)) {
- DRM_ERROR("Invalid power state for multi-head: %d.%d\n", ps, cm);
- } else {
- /* disable dynpm */
- rdev->pm.state = PM_STATE_DISABLED;
- rdev->pm.planned_action = PM_ACTION_NONE;
- rdev->pm.requested_power_state_index = ps;
- rdev->pm.requested_clock_mode_index = cm;
- radeon_pm_set_clocks(rdev, true);
+ if (rdev->pm.pm_method == PM_METHOD_PROFILE) {
+ if (strncmp("default", buf, strlen("default")) == 0)
+ rdev->pm.profile = PM_PROFILE_DEFAULT;
+ else if (strncmp("auto", buf, strlen("auto")) == 0)
+ rdev->pm.profile = PM_PROFILE_AUTO;
+ else if (strncmp("low", buf, strlen("low")) == 0)
+ rdev->pm.profile = PM_PROFILE_LOW;
+ else if (strncmp("high", buf, strlen("high")) == 0)
+ rdev->pm.profile = PM_PROFILE_HIGH;
+ else {
+ DRM_ERROR("invalid power profile!\n");
+ goto fail;
}
- } else
- DRM_ERROR("Invalid power state: %d.%d\n\n", ps, cm);
+ radeon_pm_update_profile(rdev);
+ radeon_pm_set_clocks(rdev);
+ }
+fail:
mutex_unlock(&rdev->pm.mutex);
return count;
}
-static ssize_t radeon_get_dynpm(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t radeon_get_pm_method(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
struct radeon_device *rdev = ddev->dev_private;
+ int pm = rdev->pm.pm_method;
return snprintf(buf, PAGE_SIZE, "%s\n",
- (rdev->pm.state == PM_STATE_DISABLED) ? "disabled" : "enabled");
+ (pm == PM_METHOD_DYNPM) ? "dynpm" : "profile");
}
-static ssize_t radeon_set_dynpm(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t count)
+static ssize_t radeon_set_pm_method(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
{
struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
struct radeon_device *rdev = ddev->dev_private;
- int tmp = simple_strtoul(buf, NULL, 10);
- if (tmp == 0) {
- /* update power mode info */
- radeon_pm_compute_clocks(rdev);
- /* disable dynpm */
+
+ if (strncmp("dynpm", buf, strlen("dynpm")) == 0) {
mutex_lock(&rdev->pm.mutex);
- rdev->pm.state = PM_STATE_DISABLED;
- rdev->pm.planned_action = PM_ACTION_NONE;
+ rdev->pm.pm_method = PM_METHOD_DYNPM;
+ rdev->pm.dynpm_state = DYNPM_STATE_PAUSED;
+ rdev->pm.dynpm_planned_action = DYNPM_ACTION_DEFAULT;
mutex_unlock(&rdev->pm.mutex);
- DRM_INFO("radeon: dynamic power management disabled\n");
- } else if (tmp == 1) {
- if (rdev->pm.num_power_states > 1) {
- /* enable dynpm */
- mutex_lock(&rdev->pm.mutex);
- rdev->pm.state = PM_STATE_PAUSED;
- rdev->pm.planned_action = PM_ACTION_DEFAULT;
- radeon_get_power_state(rdev, rdev->pm.planned_action);
- mutex_unlock(&rdev->pm.mutex);
- /* update power mode info */
- radeon_pm_compute_clocks(rdev);
- DRM_INFO("radeon: dynamic power management enabled\n");
- } else
- DRM_ERROR("dynpm not valid on this system\n");
- } else
- DRM_ERROR("Invalid setting: %d\n", tmp);
-
+ } else if (strncmp("profile", buf, strlen("profile")) == 0) {
+ mutex_lock(&rdev->pm.mutex);
+ rdev->pm.pm_method = PM_METHOD_PROFILE;
+ /* disable dynpm */
+ rdev->pm.dynpm_state = DYNPM_STATE_DISABLED;
+ rdev->pm.dynpm_planned_action = DYNPM_ACTION_NONE;
+ cancel_delayed_work(&rdev->pm.dynpm_idle_work);
+ mutex_unlock(&rdev->pm.mutex);
+ } else {
+ DRM_ERROR("invalid power method!\n");
+ goto fail;
+ }
+ radeon_pm_compute_clocks(rdev);
+fail:
return count;
}
-static DEVICE_ATTR(power_state, S_IRUGO | S_IWUSR, radeon_get_power_state_static, radeon_set_power_state_static);
-static DEVICE_ATTR(dynpm, S_IRUGO | S_IWUSR, radeon_get_dynpm, radeon_set_dynpm);
-
+static DEVICE_ATTR(power_profile, S_IRUGO | S_IWUSR, radeon_get_pm_profile, radeon_set_pm_profile);
+static DEVICE_ATTR(power_method, S_IRUGO | S_IWUSR, radeon_get_pm_method, radeon_set_pm_method);
-static const char *pm_state_names[4] = {
- "PM_STATE_DISABLED",
- "PM_STATE_MINIMUM",
- "PM_STATE_PAUSED",
- "PM_STATE_ACTIVE"
-};
-
-static const char *pm_state_types[5] = {
- "",
- "Powersave",
- "Battery",
- "Balanced",
- "Performance",
-};
-
-static void radeon_print_power_mode_info(struct radeon_device *rdev)
+void radeon_pm_suspend(struct radeon_device *rdev)
{
- int i, j;
- bool is_default;
-
- DRM_INFO("%d Power State(s)\n", rdev->pm.num_power_states);
- for (i = 0; i < rdev->pm.num_power_states; i++) {
- if (rdev->pm.default_power_state_index == i)
- is_default = true;
- else
- is_default = false;
- DRM_INFO("State %d %s %s\n", i,
- pm_state_types[rdev->pm.power_state[i].type],
- is_default ? "(default)" : "");
- if ((rdev->flags & RADEON_IS_PCIE) && !(rdev->flags & RADEON_IS_IGP))
- DRM_INFO("\t%d PCIE Lanes\n", rdev->pm.power_state[i].pcie_lanes);
- if (rdev->pm.power_state[i].flags & RADEON_PM_STATE_SINGLE_DISPLAY_ONLY)
- DRM_INFO("\tSingle display only\n");
- DRM_INFO("\t%d Clock Mode(s)\n", rdev->pm.power_state[i].num_clock_modes);
- for (j = 0; j < rdev->pm.power_state[i].num_clock_modes; j++) {
- if (rdev->flags & RADEON_IS_IGP)
- DRM_INFO("\t\t%d engine: %d\n",
- j,
- rdev->pm.power_state[i].clock_info[j].sclk * 10);
- else
- DRM_INFO("\t\t%d engine/memory: %d/%d\n",
- j,
- rdev->pm.power_state[i].clock_info[j].sclk * 10,
- rdev->pm.power_state[i].clock_info[j].mclk * 10);
- if (rdev->pm.power_state[i].clock_info[j].flags & RADEON_PM_MODE_NO_DISPLAY)
- DRM_INFO("\t\tNo display only\n");
- }
- }
+ mutex_lock(&rdev->pm.mutex);
+ cancel_delayed_work(&rdev->pm.dynpm_idle_work);
+ rdev->pm.current_power_state_index = -1;
+ rdev->pm.current_clock_mode_index = -1;
+ rdev->pm.current_sclk = 0;
+ rdev->pm.current_mclk = 0;
+ mutex_unlock(&rdev->pm.mutex);
}
-void radeon_sync_with_vblank(struct radeon_device *rdev)
+void radeon_pm_resume(struct radeon_device *rdev)
{
- if (rdev->pm.active_crtcs) {
- rdev->pm.vblank_sync = false;
- wait_event_timeout(
- rdev->irq.vblank_queue, rdev->pm.vblank_sync,
- msecs_to_jiffies(RADEON_WAIT_VBLANK_TIMEOUT));
- }
+ radeon_pm_compute_clocks(rdev);
}
int radeon_pm_init(struct radeon_device *rdev)
{
- rdev->pm.state = PM_STATE_DISABLED;
- rdev->pm.planned_action = PM_ACTION_NONE;
- rdev->pm.can_upclock = true;
- rdev->pm.can_downclock = true;
+ /* default to profile method */
+ rdev->pm.pm_method = PM_METHOD_PROFILE;
+ rdev->pm.dynpm_state = DYNPM_STATE_DISABLED;
+ rdev->pm.dynpm_planned_action = DYNPM_ACTION_NONE;
+ rdev->pm.dynpm_can_upclock = true;
+ rdev->pm.dynpm_can_downclock = true;
+ rdev->pm.current_sclk = 0;
+ rdev->pm.current_mclk = 0;
if (rdev->bios) {
if (rdev->is_atom_bios)
radeon_atombios_get_power_modes(rdev);
else
radeon_combios_get_power_modes(rdev);
- radeon_print_power_mode_info(rdev);
+ radeon_pm_init_profile(rdev);
+ rdev->pm.current_power_state_index = -1;
+ rdev->pm.current_clock_mode_index = -1;
}
- if (radeon_debugfs_pm_init(rdev)) {
- DRM_ERROR("Failed to register debugfs file for PM!\n");
- }
+ if (rdev->pm.num_power_states > 1) {
+ if (rdev->pm.pm_method == PM_METHOD_PROFILE) {
+ mutex_lock(&rdev->pm.mutex);
+ rdev->pm.profile = PM_PROFILE_DEFAULT;
+ radeon_pm_update_profile(rdev);
+ radeon_pm_set_clocks(rdev);
+ mutex_unlock(&rdev->pm.mutex);
+ }
- /* where's the best place to put this? */
- device_create_file(rdev->dev, &dev_attr_power_state);
- device_create_file(rdev->dev, &dev_attr_dynpm);
+ /* where's the best place to put these? */
+ device_create_file(rdev->dev, &dev_attr_power_profile);
+ device_create_file(rdev->dev, &dev_attr_power_method);
- INIT_DELAYED_WORK(&rdev->pm.idle_work, radeon_pm_idle_work_handler);
+#ifdef CONFIG_ACPI
+ rdev->acpi_nb.notifier_call = radeon_acpi_event;
+ register_acpi_notifier(&rdev->acpi_nb);
+#endif
+ INIT_DELAYED_WORK(&rdev->pm.dynpm_idle_work, radeon_dynpm_idle_work_handler);
- if ((radeon_dynpm != -1 && radeon_dynpm) && (rdev->pm.num_power_states > 1)) {
- rdev->pm.state = PM_STATE_PAUSED;
- DRM_INFO("radeon: dynamic power management enabled\n");
- }
+ if (radeon_debugfs_pm_init(rdev)) {
+ DRM_ERROR("Failed to register debugfs file for PM!\n");
+ }
- DRM_INFO("radeon: power management initialized\n");
+ DRM_INFO("radeon: power management initialized\n");
+ }
return 0;
}
void radeon_pm_fini(struct radeon_device *rdev)
{
- if (rdev->pm.state != PM_STATE_DISABLED) {
- /* cancel work */
- cancel_delayed_work_sync(&rdev->pm.idle_work);
- /* reset default clocks */
- rdev->pm.state = PM_STATE_DISABLED;
- rdev->pm.planned_action = PM_ACTION_DEFAULT;
- radeon_pm_set_clocks(rdev, true);
- } else if ((rdev->pm.current_power_state_index !=
- rdev->pm.default_power_state_index) ||
- (rdev->pm.current_clock_mode_index != 0)) {
- rdev->pm.requested_power_state_index = rdev->pm.default_power_state_index;
- rdev->pm.requested_clock_mode_index = 0;
+ if (rdev->pm.num_power_states > 1) {
mutex_lock(&rdev->pm.mutex);
- radeon_pm_set_clocks(rdev, true);
+ if (rdev->pm.pm_method == PM_METHOD_PROFILE) {
+ rdev->pm.profile = PM_PROFILE_DEFAULT;
+ radeon_pm_update_profile(rdev);
+ radeon_pm_set_clocks(rdev);
+ } else if (rdev->pm.pm_method == PM_METHOD_DYNPM) {
+ /* cancel work */
+ cancel_delayed_work_sync(&rdev->pm.dynpm_idle_work);
+ /* reset default clocks */
+ rdev->pm.dynpm_state = DYNPM_STATE_DISABLED;
+ rdev->pm.dynpm_planned_action = DYNPM_ACTION_DEFAULT;
+ radeon_pm_set_clocks(rdev);
+ }
mutex_unlock(&rdev->pm.mutex);
- }
- device_remove_file(rdev->dev, &dev_attr_power_state);
- device_remove_file(rdev->dev, &dev_attr_dynpm);
+ device_remove_file(rdev->dev, &dev_attr_power_profile);
+ device_remove_file(rdev->dev, &dev_attr_power_method);
+#ifdef CONFIG_ACPI
+ unregister_acpi_notifier(&rdev->acpi_nb);
+#endif
+ }
if (rdev->pm.i2c_bus)
radeon_i2c_destroy(rdev->pm.i2c_bus);
@@ -347,6 +481,9 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev)
struct drm_crtc *crtc;
struct radeon_crtc *radeon_crtc;
+ if (rdev->pm.num_power_states < 2)
+ return;
+
mutex_lock(&rdev->pm.mutex);
rdev->pm.active_crtcs = 0;
@@ -360,55 +497,56 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev)
}
}
- if (rdev->pm.state == PM_STATE_DISABLED) {
- mutex_unlock(&rdev->pm.mutex);
- return;
- }
-
- /* Note, radeon_pm_set_clocks is called with static_switch set
- * to true since we always want to statically set the clocks,
- * not wait for vbl.
- */
- if (rdev->pm.active_crtc_count > 1) {
- if (rdev->pm.state == PM_STATE_ACTIVE) {
- cancel_delayed_work(&rdev->pm.idle_work);
-
- rdev->pm.state = PM_STATE_PAUSED;
- rdev->pm.planned_action = PM_ACTION_DEFAULT;
- radeon_pm_set_clocks(rdev, true);
-
- DRM_DEBUG("radeon: dynamic power management deactivated\n");
- }
- } else if (rdev->pm.active_crtc_count == 1) {
- /* TODO: Increase clocks if needed for current mode */
-
- if (rdev->pm.state == PM_STATE_MINIMUM) {
- rdev->pm.state = PM_STATE_ACTIVE;
- rdev->pm.planned_action = PM_ACTION_UPCLOCK;
- radeon_pm_set_clocks(rdev, true);
-
- queue_delayed_work(rdev->wq, &rdev->pm.idle_work,
- msecs_to_jiffies(RADEON_IDLE_LOOP_MS));
- } else if (rdev->pm.state == PM_STATE_PAUSED) {
- rdev->pm.state = PM_STATE_ACTIVE;
- queue_delayed_work(rdev->wq, &rdev->pm.idle_work,
- msecs_to_jiffies(RADEON_IDLE_LOOP_MS));
- DRM_DEBUG("radeon: dynamic power management activated\n");
- }
- } else { /* count == 0 */
- if (rdev->pm.state != PM_STATE_MINIMUM) {
- cancel_delayed_work(&rdev->pm.idle_work);
-
- rdev->pm.state = PM_STATE_MINIMUM;
- rdev->pm.planned_action = PM_ACTION_MINIMUM;
- radeon_pm_set_clocks(rdev, true);
+ if (rdev->pm.pm_method == PM_METHOD_PROFILE) {
+ radeon_pm_update_profile(rdev);
+ radeon_pm_set_clocks(rdev);
+ } else if (rdev->pm.pm_method == PM_METHOD_DYNPM) {
+ if (rdev->pm.dynpm_state != DYNPM_STATE_DISABLED) {
+ if (rdev->pm.active_crtc_count > 1) {
+ if (rdev->pm.dynpm_state == DYNPM_STATE_ACTIVE) {
+ cancel_delayed_work(&rdev->pm.dynpm_idle_work);
+
+ rdev->pm.dynpm_state = DYNPM_STATE_PAUSED;
+ rdev->pm.dynpm_planned_action = DYNPM_ACTION_DEFAULT;
+ radeon_pm_get_dynpm_state(rdev);
+ radeon_pm_set_clocks(rdev);
+
+ DRM_DEBUG("radeon: dynamic power management deactivated\n");
+ }
+ } else if (rdev->pm.active_crtc_count == 1) {
+ /* TODO: Increase clocks if needed for current mode */
+
+ if (rdev->pm.dynpm_state == DYNPM_STATE_MINIMUM) {
+ rdev->pm.dynpm_state = DYNPM_STATE_ACTIVE;
+ rdev->pm.dynpm_planned_action = DYNPM_ACTION_UPCLOCK;
+ radeon_pm_get_dynpm_state(rdev);
+ radeon_pm_set_clocks(rdev);
+
+ queue_delayed_work(rdev->wq, &rdev->pm.dynpm_idle_work,
+ msecs_to_jiffies(RADEON_IDLE_LOOP_MS));
+ } else if (rdev->pm.dynpm_state == DYNPM_STATE_PAUSED) {
+ rdev->pm.dynpm_state = DYNPM_STATE_ACTIVE;
+ queue_delayed_work(rdev->wq, &rdev->pm.dynpm_idle_work,
+ msecs_to_jiffies(RADEON_IDLE_LOOP_MS));
+ DRM_DEBUG("radeon: dynamic power management activated\n");
+ }
+ } else { /* count == 0 */
+ if (rdev->pm.dynpm_state != DYNPM_STATE_MINIMUM) {
+ cancel_delayed_work(&rdev->pm.dynpm_idle_work);
+
+ rdev->pm.dynpm_state = DYNPM_STATE_MINIMUM;
+ rdev->pm.dynpm_planned_action = DYNPM_ACTION_MINIMUM;
+ radeon_pm_get_dynpm_state(rdev);
+ radeon_pm_set_clocks(rdev);
+ }
+ }
}
}
mutex_unlock(&rdev->pm.mutex);
}
-bool radeon_pm_in_vbl(struct radeon_device *rdev)
+static bool radeon_pm_in_vbl(struct radeon_device *rdev)
{
u32 stat_crtc = 0, vbl = 0, position = 0;
bool in_vbl = true;
@@ -480,7 +618,7 @@ bool radeon_pm_in_vbl(struct radeon_device *rdev)
return in_vbl;
}
-bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish)
+static bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish)
{
u32 stat_crtc = 0;
bool in_vbl = radeon_pm_in_vbl(rdev);
@@ -491,16 +629,16 @@ bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish)
return in_vbl;
}
-static void radeon_pm_idle_work_handler(struct work_struct *work)
+static void radeon_dynpm_idle_work_handler(struct work_struct *work)
{
struct radeon_device *rdev;
int resched;
rdev = container_of(work, struct radeon_device,
- pm.idle_work.work);
+ pm.dynpm_idle_work.work);
resched = ttm_bo_lock_delayed_workqueue(&rdev->mman.bdev);
mutex_lock(&rdev->pm.mutex);
- if (rdev->pm.state == PM_STATE_ACTIVE) {
+ if (rdev->pm.dynpm_state == DYNPM_STATE_ACTIVE) {
unsigned long irq_flags;
int not_processed = 0;
@@ -516,23 +654,23 @@ static void radeon_pm_idle_work_handler(struct work_struct *work)
read_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags);
if (not_processed >= 3) { /* should upclock */
- if (rdev->pm.planned_action == PM_ACTION_DOWNCLOCK) {
- rdev->pm.planned_action = PM_ACTION_NONE;
- } else if (rdev->pm.planned_action == PM_ACTION_NONE &&
- rdev->pm.can_upclock) {
- rdev->pm.planned_action =
- PM_ACTION_UPCLOCK;
- rdev->pm.action_timeout = jiffies +
+ if (rdev->pm.dynpm_planned_action == DYNPM_ACTION_DOWNCLOCK) {
+ rdev->pm.dynpm_planned_action = DYNPM_ACTION_NONE;
+ } else if (rdev->pm.dynpm_planned_action == DYNPM_ACTION_NONE &&
+ rdev->pm.dynpm_can_upclock) {
+ rdev->pm.dynpm_planned_action =
+ DYNPM_ACTION_UPCLOCK;
+ rdev->pm.dynpm_action_timeout = jiffies +
msecs_to_jiffies(RADEON_RECLOCK_DELAY_MS);
}
} else if (not_processed == 0) { /* should downclock */
- if (rdev->pm.planned_action == PM_ACTION_UPCLOCK) {
- rdev->pm.planned_action = PM_ACTION_NONE;
- } else if (rdev->pm.planned_action == PM_ACTION_NONE &&
- rdev->pm.can_downclock) {
- rdev->pm.planned_action =
- PM_ACTION_DOWNCLOCK;
- rdev->pm.action_timeout = jiffies +
+ if (rdev->pm.dynpm_planned_action == DYNPM_ACTION_UPCLOCK) {
+ rdev->pm.dynpm_planned_action = DYNPM_ACTION_NONE;
+ } else if (rdev->pm.dynpm_planned_action == DYNPM_ACTION_NONE &&
+ rdev->pm.dynpm_can_downclock) {
+ rdev->pm.dynpm_planned_action =
+ DYNPM_ACTION_DOWNCLOCK;
+ rdev->pm.dynpm_action_timeout = jiffies +
msecs_to_jiffies(RADEON_RECLOCK_DELAY_MS);
}
}
@@ -540,15 +678,16 @@ static void radeon_pm_idle_work_handler(struct work_struct *work)
/* Note, radeon_pm_set_clocks is called with static_switch set
* to false since we want to wait for vbl to avoid flicker.
*/
- if (rdev->pm.planned_action != PM_ACTION_NONE &&
- jiffies > rdev->pm.action_timeout) {
- radeon_pm_set_clocks(rdev, false);
+ if (rdev->pm.dynpm_planned_action != DYNPM_ACTION_NONE &&
+ jiffies > rdev->pm.dynpm_action_timeout) {
+ radeon_pm_get_dynpm_state(rdev);
+ radeon_pm_set_clocks(rdev);
}
}
mutex_unlock(&rdev->pm.mutex);
ttm_bo_unlock_delayed_workqueue(&rdev->mman.bdev, resched);
- queue_delayed_work(rdev->wq, &rdev->pm.idle_work,
+ queue_delayed_work(rdev->wq, &rdev->pm.dynpm_idle_work,
msecs_to_jiffies(RADEON_IDLE_LOOP_MS));
}
@@ -563,7 +702,6 @@ static int radeon_debugfs_pm_info(struct seq_file *m, void *data)
struct drm_device *dev = node->minor->dev;
struct radeon_device *rdev = dev->dev_private;
- seq_printf(m, "state: %s\n", pm_state_names[rdev->pm.state]);
seq_printf(m, "default engine clock: %u0 kHz\n", rdev->clock.default_sclk);
seq_printf(m, "current engine clock: %u0 kHz\n", radeon_get_engine_clock(rdev));
seq_printf(m, "default memory clock: %u0 kHz\n", rdev->clock.default_mclk);
diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c
index dc76fe7..9e4240b 100644
--- a/drivers/gpu/drm/radeon/rs400.c
+++ b/drivers/gpu/drm/radeon/rs400.c
@@ -456,7 +456,6 @@ int rs400_suspend(struct radeon_device *rdev)
void rs400_fini(struct radeon_device *rdev)
{
- radeon_pm_fini(rdev);
r100_cp_fini(rdev);
r100_wb_fini(rdev);
r100_ib_fini(rdev);
@@ -507,8 +506,6 @@ int rs400_init(struct radeon_device *rdev)
/* Initialize clocks */
radeon_get_clock_info(rdev->ddev);
- /* Initialize power management */
- radeon_pm_init(rdev);
/* initialize memory controller */
rs400_mc_init(rdev);
/* Fence driver */
diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c
index 8e0c460..e8c68e9 100644
--- a/drivers/gpu/drm/radeon/rs600.c
+++ b/drivers/gpu/drm/radeon/rs600.c
@@ -846,7 +846,6 @@ int rs600_suspend(struct radeon_device *rdev)
void rs600_fini(struct radeon_device *rdev)
{
- radeon_pm_fini(rdev);
r100_cp_fini(rdev);
r100_wb_fini(rdev);
r100_ib_fini(rdev);
@@ -896,8 +895,6 @@ int rs600_init(struct radeon_device *rdev)
/* Initialize clocks */
radeon_get_clock_info(rdev->ddev);
- /* Initialize power management */
- radeon_pm_init(rdev);
/* initialize memory controller */
rs600_mc_init(rdev);
rs600_debugfs(rdev);
diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c
index e8edfe6..bcc3319 100644
--- a/drivers/gpu/drm/radeon/rs690.c
+++ b/drivers/gpu/drm/radeon/rs690.c
@@ -676,7 +676,6 @@ int rs690_suspend(struct radeon_device *rdev)
void rs690_fini(struct radeon_device *rdev)
{
- radeon_pm_fini(rdev);
r100_cp_fini(rdev);
r100_wb_fini(rdev);
r100_ib_fini(rdev);
@@ -727,8 +726,6 @@ int rs690_init(struct radeon_device *rdev)
/* Initialize clocks */
radeon_get_clock_info(rdev->ddev);
- /* Initialize power management */
- radeon_pm_init(rdev);
/* initialize memory controller */
rs690_mc_init(rdev);
rv515_debugfs(rdev);
diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c
index 2009f4b..7d9a7b0 100644
--- a/drivers/gpu/drm/radeon/rv515.c
+++ b/drivers/gpu/drm/radeon/rv515.c
@@ -445,7 +445,6 @@ void rv515_set_safe_registers(struct radeon_device *rdev)
void rv515_fini(struct radeon_device *rdev)
{
- radeon_pm_fini(rdev);
r100_cp_fini(rdev);
r100_wb_fini(rdev);
r100_ib_fini(rdev);
@@ -494,8 +493,6 @@ int rv515_init(struct radeon_device *rdev)
return -EINVAL;
/* Initialize clocks */
radeon_get_clock_info(rdev->ddev);
- /* Initialize power management */
- radeon_pm_init(rdev);
/* initialize AGP */
if (rdev->flags & RADEON_IS_AGP) {
r = radeon_agp_init(rdev);
diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c
index 7c55182..253f24a 100644
--- a/drivers/gpu/drm/radeon/rv770.c
+++ b/drivers/gpu/drm/radeon/rv770.c
@@ -1091,8 +1091,6 @@ int rv770_init(struct radeon_device *rdev)
r = radeon_clocks_init(rdev);
if (r)
return r;
- /* Initialize power management */
- radeon_pm_init(rdev);
/* Fence driver */
r = radeon_fence_driver_init(rdev);
if (r)
@@ -1161,7 +1159,6 @@ int rv770_init(struct radeon_device *rdev)
void rv770_fini(struct radeon_device *rdev)
{
- radeon_pm_fini(rdev);
r600_blit_fini(rdev);
r700_cp_fini(rdev);
r600_wb_fini(rdev);
--
1.5.6.3
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH 9/9] drm/radeon/kms/pm: make pm spam debug only
2010-05-07 21:16 ` [PATCH 8/9] drm/radeon/kms/pm: rework power management Alex Deucher
@ 2010-05-07 21:16 ` Alex Deucher
0 siblings, 0 replies; 19+ messages in thread
From: Alex Deucher @ 2010-05-07 21:16 UTC (permalink / raw)
To: airlied, dri-devel; +Cc: mjg59
Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
---
drivers/gpu/drm/radeon/r100.c | 16 ++++++++--------
drivers/gpu/drm/radeon/r600.c | 14 +++++++-------
drivers/gpu/drm/radeon/radeon_pm.c | 16 ++++++++--------
drivers/gpu/drm/radeon/rs600.c | 2 +-
4 files changed, 24 insertions(+), 24 deletions(-)
diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
index 4c5d21b..9a59ba4 100644
--- a/drivers/gpu/drm/radeon/r100.c
+++ b/drivers/gpu/drm/radeon/r100.c
@@ -141,13 +141,13 @@ void r100_pm_get_dynpm_state(struct radeon_device *rdev)
/* only one clock mode per power state */
rdev->pm.requested_clock_mode_index = 0;
- DRM_INFO("Requested: e: %d m: %d p: %d\n",
- rdev->pm.power_state[rdev->pm.requested_power_state_index].
- clock_info[rdev->pm.requested_clock_mode_index].sclk,
- rdev->pm.power_state[rdev->pm.requested_power_state_index].
- clock_info[rdev->pm.requested_clock_mode_index].mclk,
- rdev->pm.power_state[rdev->pm.requested_power_state_index].
- pcie_lanes);
+ DRM_DEBUG("Requested: e: %d m: %d p: %d\n",
+ rdev->pm.power_state[rdev->pm.requested_power_state_index].
+ clock_info[rdev->pm.requested_clock_mode_index].sclk,
+ rdev->pm.power_state[rdev->pm.requested_power_state_index].
+ clock_info[rdev->pm.requested_clock_mode_index].mclk,
+ rdev->pm.power_state[rdev->pm.requested_power_state_index].
+ pcie_lanes);
}
void r100_pm_init_profile(struct radeon_device *rdev)
@@ -266,7 +266,7 @@ void r100_pm_misc(struct radeon_device *rdev)
rdev->pm.power_state[rdev->pm.current_power_state_index].pcie_lanes)) {
radeon_set_pcie_lanes(rdev,
ps->pcie_lanes);
- DRM_INFO("Setting: p: %d\n", ps->pcie_lanes);
+ DRM_DEBUG("Setting: p: %d\n", ps->pcie_lanes);
}
}
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index 618d76d..0fef335 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -251,13 +251,13 @@ void r600_pm_get_dynpm_state(struct radeon_device *rdev)
}
}
- DRM_INFO("Requested: e: %d m: %d p: %d\n",
- rdev->pm.power_state[rdev->pm.requested_power_state_index].
- clock_info[rdev->pm.requested_clock_mode_index].sclk,
- rdev->pm.power_state[rdev->pm.requested_power_state_index].
- clock_info[rdev->pm.requested_clock_mode_index].mclk,
- rdev->pm.power_state[rdev->pm.requested_power_state_index].
- pcie_lanes);
+ DRM_DEBUG("Requested: e: %d m: %d p: %d\n",
+ rdev->pm.power_state[rdev->pm.requested_power_state_index].
+ clock_info[rdev->pm.requested_clock_mode_index].sclk,
+ rdev->pm.power_state[rdev->pm.requested_power_state_index].
+ clock_info[rdev->pm.requested_clock_mode_index].mclk,
+ rdev->pm.power_state[rdev->pm.requested_power_state_index].
+ pcie_lanes);
}
static int r600_pm_get_type_index(struct radeon_device *rdev,
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
index 1827317..c88edae 100644
--- a/drivers/gpu/drm/radeon/radeon_pm.c
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
@@ -52,9 +52,9 @@ static int radeon_acpi_event(struct notifier_block *nb,
if (strcmp(entry->device_class, ACPI_AC_CLASS) == 0) {
if (power_supply_is_system_supplied() > 0)
- DRM_INFO("pm: AC\n");
+ DRM_DEBUG("pm: AC\n");
else
- DRM_INFO("pm: DC\n");
+ DRM_DEBUG("pm: DC\n");
if (rdev->pm.pm_method == PM_METHOD_PROFILE) {
if (rdev->pm.profile == PM_PROFILE_AUTO) {
@@ -183,7 +183,7 @@ static void radeon_set_power_state(struct radeon_device *rdev)
radeon_set_engine_clock(rdev, sclk);
radeon_pm_debug_check_in_vbl(rdev, true);
rdev->pm.current_sclk = sclk;
- DRM_INFO("Setting: e: %d\n", sclk);
+ DRM_DEBUG("Setting: e: %d\n", sclk);
}
/* set memory clock */
@@ -192,7 +192,7 @@ static void radeon_set_power_state(struct radeon_device *rdev)
radeon_set_memory_clock(rdev, mclk);
radeon_pm_debug_check_in_vbl(rdev, true);
rdev->pm.current_mclk = mclk;
- DRM_INFO("Setting: m: %d\n", mclk);
+ DRM_DEBUG("Setting: m: %d\n", mclk);
}
radeon_pm_finish(rdev);
} else {
@@ -203,7 +203,7 @@ static void radeon_set_power_state(struct radeon_device *rdev)
radeon_set_engine_clock(rdev, sclk);
radeon_pm_finish(rdev);
rdev->pm.current_sclk = sclk;
- DRM_INFO("Setting: e: %d\n", sclk);
+ DRM_DEBUG("Setting: e: %d\n", sclk);
}
/* set memory clock */
if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) {
@@ -212,14 +212,14 @@ static void radeon_set_power_state(struct radeon_device *rdev)
radeon_set_memory_clock(rdev, mclk);
radeon_pm_finish(rdev);
rdev->pm.current_mclk = mclk;
- DRM_INFO("Setting: m: %d\n", mclk);
+ DRM_DEBUG("Setting: m: %d\n", mclk);
}
}
rdev->pm.current_power_state_index = rdev->pm.requested_power_state_index;
rdev->pm.current_clock_mode_index = rdev->pm.requested_clock_mode_index;
} else
- DRM_INFO("pm: GUI not idle!!!\n");
+ DRM_DEBUG("pm: GUI not idle!!!\n");
}
static void radeon_pm_set_clocks(struct radeon_device *rdev)
@@ -624,7 +624,7 @@ static bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish
bool in_vbl = radeon_pm_in_vbl(rdev);
if (in_vbl == false)
- DRM_INFO("not in vbl for pm change %08x at %s\n", stat_crtc,
+ DRM_DEBUG("not in vbl for pm change %08x at %s\n", stat_crtc,
finish ? "exit" : "entry");
return in_vbl;
}
diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c
index e8c68e9..79887ca 100644
--- a/drivers/gpu/drm/radeon/rs600.c
+++ b/drivers/gpu/drm/radeon/rs600.c
@@ -135,7 +135,7 @@ void rs600_pm_misc(struct radeon_device *rdev)
rdev->pm.power_state[rdev->pm.current_power_state_index].pcie_lanes)) {
radeon_set_pcie_lanes(rdev,
ps->pcie_lanes);
- DRM_INFO("Setting: p: %d\n", ps->pcie_lanes);
+ DRM_DEBUG("Setting: p: %d\n", ps->pcie_lanes);
}
}
--
1.5.6.3
^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [PATCH 0/9] drm/radeon/kms: update pm code
2010-05-07 21:16 [PATCH 0/9] drm/radeon/kms: update pm code Alex Deucher
2010-05-07 21:16 ` [PATCH 1/9] drm/radeon/kms: enable misc pm power state features on r5xx, rs6xx Alex Deucher
@ 2010-05-07 21:23 ` Matthew Garrett
2010-05-07 22:24 ` Alex Deucher
2010-05-08 11:14 ` Klaus Doblmann B.A.
2010-05-10 16:04 ` Andy Furniss
3 siblings, 1 reply; 19+ messages in thread
From: Matthew Garrett @ 2010-05-07 21:23 UTC (permalink / raw)
To: Alex Deucher; +Cc: dri-devel
On Fri, May 07, 2010 at 05:16:11PM -0400, Alex Deucher wrote:
> "auto" selects between low and high power states based on the whether the system
> is on battery power or not. Even lower power states are selected when the monitors
> are in the dpms off state.
Beyond the constraints imposed in terms of some modes not being
available on battery, I'd prefer to leave the ac/battery decision up to
userspace. Having it be default behaviour at the kernel level is
plausibly confusing.
--
Matthew Garrett | mjg59@srcf.ucam.org
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 0/9] drm/radeon/kms: update pm code
2010-05-07 21:23 ` [PATCH 0/9] drm/radeon/kms: update pm code Matthew Garrett
@ 2010-05-07 22:24 ` Alex Deucher
0 siblings, 0 replies; 19+ messages in thread
From: Alex Deucher @ 2010-05-07 22:24 UTC (permalink / raw)
To: Matthew Garrett; +Cc: dri-devel
On Fri, May 7, 2010 at 5:23 PM, Matthew Garrett <mjg59@srcf.ucam.org> wrote:
> On Fri, May 07, 2010 at 05:16:11PM -0400, Alex Deucher wrote:
>
>> "auto" selects between low and high power states based on the whether the system
>> is on battery power or not. Even lower power states are selected when the monitors
>> are in the dpms off state.
>
> Beyond the constraints imposed in terms of some modes not being
> available on battery, I'd prefer to leave the ac/battery decision up to
> userspace. Having it be default behaviour at the kernel level is
> plausibly confusing.
Sounds fine. Just have userspace switch between the low and high
profiles for battery and ac rather than using auto. auto is useful as
a user option in the interim while userspace gets updated.
Alex
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 0/9] drm/radeon/kms: update pm code
2010-05-07 21:16 [PATCH 0/9] drm/radeon/kms: update pm code Alex Deucher
2010-05-07 21:16 ` [PATCH 1/9] drm/radeon/kms: enable misc pm power state features on r5xx, rs6xx Alex Deucher
2010-05-07 21:23 ` [PATCH 0/9] drm/radeon/kms: update pm code Matthew Garrett
@ 2010-05-08 11:14 ` Klaus Doblmann B.A.
2010-05-08 15:29 ` Alex Deucher
2010-05-10 16:04 ` Andy Furniss
3 siblings, 1 reply; 19+ messages in thread
From: Klaus Doblmann B.A. @ 2010-05-08 11:14 UTC (permalink / raw)
To: dri-devel
On Fri, 7 May 2010 17:16:11 -0400
Alex Deucher <alexdeucher@gmail.com> wrote:
> This set of patches applies on top of the code in drm-radeon-testing.
>
> I've been testing this code pretty hard this week and it's been solid.
> In addition to some fixes on top of what's in d-r-t, it also reworks
> the pm code to support two basic methods:
>
> 1. "dynpm"
> 2. "profile"
>
> You can select the methods via sysfs. Echo "dynpm" or "profile" to
> /sys/class/drm/card-0/device/power_method.
>
> The "dynpm" method dynamically changes the clocks based on the number of pending
> fences, so performance is ramped up when running GPU intensive apps, and
> ramped down when the GPU is idle. The reclocking is attemped during
> vertical blanking periods, but due to the timing of the reclocking
> functions, doesn't not always complete in the blanking period, which can
> lead to flicker in the display. Due to this, dynpm only works when a single
> head is active.
Hi Alex,
I just built a new version of d-r-t with your patches from yesterday
applied on top and wanted to share my experience with you and the list
(Radeon 2600XT mobile):
Dynpm has gotten unusable for me as there's a noticeable effect on
mouse movement (getting sluggish)
>
> The "profile" method exposes 4 profiles that can be selected from:
> 1. "default"
> 2. "auto"
> 3. "low"
> 4. "high"
> Select the profile by echoing the selected profile to
> /sys/class/drm/card-0/device/power_profile.
>
the profile setting works but I can't check which clock speeds are
set as I don't get any feedback (dmesg) anymore (Someone have any
input on this?). The temps are unaffected whether I use the low or high
profile, the only way I can tell that some things are working is by a
2000 fps-difference when running glxgears (something like 4000 on low
and 6000 on high). I also attached a wattmeter to my my machine and the
wattage alternates but I think I'm getting something along the lines of
a 10W decrease in power consumption - it's very hard to tell, though.
dynpm is a bit more effective and I even get lower temps (just under
50° compared to over 53 with the profile settings) but it's unusable
right now as I already mentioned.
All in all very nice work so far (this goes for all of you who've
worked on radeon KMS PM!) - with the latest set of patches this is the
first "revision" of KMS PM that actually "works" on my machine :)
Klaus
--
Klaus Doblmann B.A. - http://straightrazorguy.net - FSF member #7570
PGP-Key: http://www.doblmann.de/pgp_key.asc
http://twitter.com/klausdoblmann
A: Because it messes up the order in which people normally read text.
See http://en.wikipedia.org/wiki/Posting_style
Q: Why is top-posting such a bad thing?
A: Top-posting.
Q: What is the most annoying thing in e-mail?
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 0/9] drm/radeon/kms: update pm code
2010-05-08 11:14 ` Klaus Doblmann B.A.
@ 2010-05-08 15:29 ` Alex Deucher
2010-05-08 18:46 ` Klaus Doblmann B.A.
0 siblings, 1 reply; 19+ messages in thread
From: Alex Deucher @ 2010-05-08 15:29 UTC (permalink / raw)
To: Klaus Doblmann B.A.; +Cc: dri-devel
On Sat, May 8, 2010 at 7:14 AM, Klaus Doblmann B.A.
<klaus.doblmann@gmail.com> wrote:
> On Fri, 7 May 2010 17:16:11 -0400
> Alex Deucher <alexdeucher@gmail.com> wrote:
>
>> This set of patches applies on top of the code in drm-radeon-testing.
>>
>> I've been testing this code pretty hard this week and it's been solid.
>> In addition to some fixes on top of what's in d-r-t, it also reworks
>> the pm code to support two basic methods:
>>
>> 1. "dynpm"
>> 2. "profile"
>>
>> You can select the methods via sysfs. Echo "dynpm" or "profile" to
>> /sys/class/drm/card-0/device/power_method.
>>
>> The "dynpm" method dynamically changes the clocks based on the number of pending
>> fences, so performance is ramped up when running GPU intensive apps, and
>> ramped down when the GPU is idle. The reclocking is attemped during
>> vertical blanking periods, but due to the timing of the reclocking
>> functions, doesn't not always complete in the blanking period, which can
>> lead to flicker in the display. Due to this, dynpm only works when a single
>> head is active.
>
> Hi Alex,
>
> I just built a new version of d-r-t with your patches from yesterday
> applied on top and wanted to share my experience with you and the list
> (Radeon 2600XT mobile):
>
> Dynpm has gotten unusable for me as there's a noticeable effect on
> mouse movement (getting sluggish)
>
>>
>> The "profile" method exposes 4 profiles that can be selected from:
>> 1. "default"
>> 2. "auto"
>> 3. "low"
>> 4. "high"
>> Select the profile by echoing the selected profile to
>> /sys/class/drm/card-0/device/power_profile.
>>
>
> the profile setting works but I can't check which clock speeds are
> set as I don't get any feedback (dmesg) anymore (Someone have any
> input on this?). The temps are unaffected whether I use the low or high
> profile, the only way I can tell that some things are working is by a
> 2000 fps-difference when running glxgears (something like 4000 on low
> and 6000 on high). I also attached a wattmeter to my my machine and the
> wattage alternates but I think I'm getting something along the lines of
> a 10W decrease in power consumption - it's very hard to tell, though.
> dynpm is a bit more effective and I even get lower temps (just under
> 50° compared to over 53 with the profile settings) but it's unusable
> right now as I already mentioned.
>
> All in all very nice work so far (this goes for all of you who've
> worked on radeon KMS PM!) - with the latest set of patches this is the
> first "revision" of KMS PM that actually "works" on my machine :)
>
Thanks for testing; we are definitely planning on further
improvements, this is just a step on the way. The power drops
further when your monitors go off so that will save additional power
when your machine is idle. If you want to see the state transitions,
revert this patch:
http://people.freedesktop.org/~agd5f/pm-drt/0009-drm-radeon-kms-pm-make-pm-spam-debug-only.patch
However, it will spam your kernel log.
Alex
> Klaus
>
> --
> Klaus Doblmann B.A. - http://straightrazorguy.net - FSF member #7570
> PGP-Key: http://www.doblmann.de/pgp_key.asc
> http://twitter.com/klausdoblmann
>
> A: Because it messes up the order in which people normally read text.
> See http://en.wikipedia.org/wiki/Posting_style
> Q: Why is top-posting such a bad thing?
> A: Top-posting.
> Q: What is the most annoying thing in e-mail?
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
>
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 0/9] drm/radeon/kms: update pm code
2010-05-08 15:29 ` Alex Deucher
@ 2010-05-08 18:46 ` Klaus Doblmann B.A.
0 siblings, 0 replies; 19+ messages in thread
From: Klaus Doblmann B.A. @ 2010-05-08 18:46 UTC (permalink / raw)
To: Alex Deucher; +Cc: dri-devel
On Sat, 8 May 2010 11:29:10 -0400
Alex Deucher <alexdeucher@gmail.com> wrote:
> On Sat, May 8, 2010 at 7:14 AM, Klaus Doblmann B.A.
> <klaus.doblmann@gmail.com> wrote:
> > the profile setting works but I can't check which clock speeds are
> > set as I don't get any feedback (dmesg) anymore (Someone have any
> > input on this?). The temps are unaffected whether I use the low or high
> > profile, the only way I can tell that some things are working is by a
> > 2000 fps-difference when running glxgears (something like 4000 on low
> > and 6000 on high). I also attached a wattmeter to my my machine and the
> > wattage alternates but I think I'm getting something along the lines of
> > a 10W decrease in power consumption - it's very hard to tell, though.
> > dynpm is a bit more effective and I even get lower temps (just under
> > 50° compared to over 53 with the profile settings) but it's unusable
> > right now as I already mentioned.
> >
> > All in all very nice work so far (this goes for all of you who've
> > worked on radeon KMS PM!) - with the latest set of patches this is the
> > first "revision" of KMS PM that actually "works" on my machine :)
> >
>
> Thanks for testing; we are definitely planning on further
> improvements, this is just a step on the way. The power drops
> further when your monitors go off so that will save additional power
> when your machine is idle. If you want to see the state transitions,
> revert this patch:
> http://people.freedesktop.org/~agd5f/pm-drt/0009-drm-radeon-kms-pm-make-pm-spam-debug-only.patch
> However, it will spam your kernel log.
>
> Alex
>
Hi Alex,
thanks for the suggestion!
It seems I spoke a bit too soon about everything working. I suspended
my machine and now came back after a few hours and it seems the latest
patches (well, I only could test the pm code in linus' tree of -34 up
to now due to display corruptions so there's a lot of changes since
then) in d-r-t killed suspend for me
- the machine doesn't come back up and hardlocks. Too bad I can't find
anything about it in my logs :(
Klaus
--
Klaus Doblmann B.A. - http://straightrazorguy.net - FSF member #7570
PGP-Key: http://www.doblmann.de/pgp_key.asc
http://twitter.com/klausdoblmann
A: Because it messes up the order in which people normally read text.
See http://en.wikipedia.org/wiki/Posting_style
Q: Why is top-posting such a bad thing?
A: Top-posting.
Q: What is the most annoying thing in e-mail?
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 0/9] drm/radeon/kms: update pm code
2010-05-07 21:16 [PATCH 0/9] drm/radeon/kms: update pm code Alex Deucher
` (2 preceding siblings ...)
2010-05-08 11:14 ` Klaus Doblmann B.A.
@ 2010-05-10 16:04 ` Andy Furniss
2010-05-10 16:47 ` Alex Deucher
3 siblings, 1 reply; 19+ messages in thread
From: Andy Furniss @ 2010-05-10 16:04 UTC (permalink / raw)
To: Alex Deucher; +Cc: mjg59, dri-devel
Alex Deucher wrote:
> The "profile" method exposes 4 profiles that can be selected from:
> 1. "default"
> 2. "auto"
> 3. "low"
> 4. "high"
> Select the profile by echoing the selected profile to
> /sys/class/drm/card-0/device/power_profile.
Testing on a rv670 desktop it seems that low does not force the card to
low clock.
Before these patches went in I could force low by
echo 2.0 > /sys/class/drm/card0/device/power_state for 2 screens or
echo 1.0 > /sys/class/drm/card0/device/power_state for one screen.
Though dmesg didn't always report setting it did work (using bench mark
to verify) - I could also get dmesg to confirm by echo 2.0 echo 2.2 then
echo 2.0.
Running current drt with the info -> debug patch reverted I can't get
echo low > /sys/class/drm/card0/device/power_profile
to lower the clock whatever I try - one screen, two screens forcing high
then low etc. (nothing in dmesg and benchmark gives full clock results)
dynpm works as before and I do get low clock in dpms with profile.
One separate question - do I need to use the module param dynclks=1 or
is it the default?
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 0/9] drm/radeon/kms: update pm code
2010-05-10 16:04 ` Andy Furniss
@ 2010-05-10 16:47 ` Alex Deucher
2010-05-10 17:25 ` Andy Furniss
0 siblings, 1 reply; 19+ messages in thread
From: Alex Deucher @ 2010-05-10 16:47 UTC (permalink / raw)
To: Andy Furniss; +Cc: mjg59, dri-devel
On Mon, May 10, 2010 at 12:04 PM, Andy Furniss <andyqos@ukfsn.org> wrote:
> Alex Deucher wrote:
>
>> The "profile" method exposes 4 profiles that can be selected from:
>> 1. "default"
>> 2. "auto"
>> 3. "low"
>> 4. "high"
>> Select the profile by echoing the selected profile to
>> /sys/class/drm/card-0/device/power_profile.
>
> Testing on a rv670 desktop it seems that low does not force the card to low
> clock.
>
> Before these patches went in I could force low by
>
> echo 2.0 > /sys/class/drm/card0/device/power_state for 2 screens or
> echo 1.0 > /sys/class/drm/card0/device/power_state for one screen.
>
> Though dmesg didn't always report setting it did work (using bench mark to
> verify) - I could also get dmesg to confirm by echo 2.0 echo 2.2 then echo
> 2.0.
>
> Running current drt with the info -> debug patch reverted I can't get
>
> echo low > /sys/class/drm/card0/device/power_profile
>
> to lower the clock whatever I try - one screen, two screens forcing high
> then low etc. (nothing in dmesg and benchmark gives full clock results)
>
Send me a copy of your vbios, I may need to adjust the profile table
for rv670. As root:
cd /sys/bus/pci/devices/<pci bus id>
echo 1 > rom
cat rom > /tmp/vbios.rom
echo 0 > rom
> dynpm works as before and I do get low clock in dpms with profile.
>
> One separate question - do I need to use the module param dynclks=1 or is it
> the default?
>
The module parameter is obsolete. you can enable it dynamically via
sysfs (power_method). The default pm method is profile.
Alex
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 0/9] drm/radeon/kms: update pm code
2010-05-10 16:47 ` Alex Deucher
@ 2010-05-10 17:25 ` Andy Furniss
2010-05-10 17:28 ` Rafał Miłecki
0 siblings, 1 reply; 19+ messages in thread
From: Andy Furniss @ 2010-05-10 17:25 UTC (permalink / raw)
To: Alex Deucher; +Cc: mjg59, dri-devel
Alex Deucher wrote:
> Send me a copy of your vbios, I may need to adjust the profile table
> for rv670. As root:
> cd /sys/bus/pci/devices/<pci bus id>
> echo 1> rom
> cat rom> /tmp/vbios.rom
> echo 0> rom
Sent
>> One separate question - do I need to use the module param dynclks=1 or is it
>> the default?
>>
>
> The module parameter is obsolete. you can enable it dynamically via
> sysfs (power_method). The default pm method is profile.
OK, I know dynpm was removed - but this is dynclks are the two the same?
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 0/9] drm/radeon/kms: update pm code
2010-05-10 17:25 ` Andy Furniss
@ 2010-05-10 17:28 ` Rafał Miłecki
0 siblings, 0 replies; 19+ messages in thread
From: Rafał Miłecki @ 2010-05-10 17:28 UTC (permalink / raw)
To: Andy Furniss; +Cc: mjg59, dri-devel
2010/5/10 Andy Furniss <andyqos@ukfsn.org>:
>> The module parameter is obsolete. you can enable it dynamically via
>> sysfs (power_method). The default pm method is profile.
>
> OK, I know dynpm was removed - but this is dynclks are the two the same?
dynclks is for disabling clocking unused blocks. It means you don't
provide clock signal to blocks and save some power. It was the case in
older hardware, newer don't use that command anymore. I believe newer
hardware handles that automatically.
--
Rafał
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply [flat|nested] 19+ messages in thread
end of thread, other threads:[~2010-05-10 17:28 UTC | newest]
Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-05-07 21:16 [PATCH 0/9] drm/radeon/kms: update pm code Alex Deucher
2010-05-07 21:16 ` [PATCH 1/9] drm/radeon/kms: enable misc pm power state features on r5xx, rs6xx Alex Deucher
2010-05-07 21:16 ` [PATCH 2/9] drm/radeon/kms: enable misc pm power state features on r1xx-r4xx Alex Deucher
2010-05-07 21:16 ` [PATCH 3/9] drm/radeon/kms: re-enable gui idle interrupts on r6xx+ Alex Deucher
2010-05-07 21:16 ` [PATCH 4/9] radeon: Split out ring locking and allocation Alex Deucher
2010-05-07 21:16 ` [PATCH 5/9] radeon: Use fences to gate entry to reclocking on <r600 Alex Deucher
2010-05-07 21:16 ` [PATCH 6/9] drm/radeon/kms: fix lock ordering in ring, ib handling Alex Deucher
2010-05-07 21:16 ` [PATCH 7/9] drm/radeon/kms/pm: add support for no display power states Alex Deucher
2010-05-07 21:16 ` [PATCH 8/9] drm/radeon/kms/pm: rework power management Alex Deucher
2010-05-07 21:16 ` [PATCH 9/9] drm/radeon/kms/pm: make pm spam debug only Alex Deucher
2010-05-07 21:23 ` [PATCH 0/9] drm/radeon/kms: update pm code Matthew Garrett
2010-05-07 22:24 ` Alex Deucher
2010-05-08 11:14 ` Klaus Doblmann B.A.
2010-05-08 15:29 ` Alex Deucher
2010-05-08 18:46 ` Klaus Doblmann B.A.
2010-05-10 16:04 ` Andy Furniss
2010-05-10 16:47 ` Alex Deucher
2010-05-10 17:25 ` Andy Furniss
2010-05-10 17:28 ` Rafał Miłecki
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.