Skip to content

Commit

Permalink
drm/radeon/kms/pm: rework power management
Browse files Browse the repository at this point in the history
- 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>
Signed-off-by: Dave Airlie <airlied@redhat.com>
  • Loading branch information
Alex Deucher authored and Dave Airlie committed May 18, 2010
1 parent d731117 commit ce8f537
Show file tree
Hide file tree
Showing 19 changed files with 790 additions and 519 deletions.
1 change: 1 addition & 0 deletions drivers/gpu/drm/radeon/Kconfig
Original file line number Diff line number Diff line change
@@ -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.

Expand Down
3 changes: 0 additions & 3 deletions drivers/gpu/drm/radeon/evergreen.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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);
Expand Down
128 changes: 40 additions & 88 deletions drivers/gpu/drm/radeon/r100.c
Original file line number Diff line number Diff line change
Expand Up @@ -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++) {
Expand All @@ -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--) {
Expand All @@ -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;
Expand All @@ -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)
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
3 changes: 0 additions & 3 deletions drivers/gpu/drm/radeon/r300.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
32 changes: 29 additions & 3 deletions drivers/gpu/drm/radeon/r420.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
2 changes: 0 additions & 2 deletions drivers/gpu/drm/radeon/r520.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Loading

0 comments on commit ce8f537

Please sign in to comment.