diff options
author | Alex Deucher <alexdeucher@gmail.com> | 2009-12-23 14:28:05 -0500 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2010-02-09 09:32:29 +1000 |
commit | 516d0e46c80d2d20391f4145c2c5e3915253b8bf (patch) | |
tree | cb0ada4d61e4c78bcdc3ce9a97a6b7ad6d79b8f1 /drivers/gpu/drm | |
parent | 0ec0e74f784ca08eab0354ab1dada46924c39b73 (diff) |
drm/radeon/kms: add code to select power state
not hooked up yet.
Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r-- | drivers/gpu/drm/radeon/radeon.h | 9 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_pm.c | 122 |
2 files changed, 131 insertions, 0 deletions
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 53468680de7..ece84fde76a 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -601,6 +601,13 @@ 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, +}; + struct radeon_voltage { enum radeon_voltage_type type; /* gpio voltage */ @@ -641,6 +648,7 @@ struct radeon_power_state { int num_clock_modes; /* currently selected clock mode */ struct radeon_pm_clock_info *current_clock_mode; + struct radeon_pm_clock_info *requested_clock_mode; struct radeon_pm_clock_info *default_clock_mode; /* non clock info about this state */ struct radeon_pm_non_clock_info non_clock_info; @@ -678,6 +686,7 @@ struct radeon_pm { /* number of valid power states */ int num_power_states; struct radeon_power_state *current_power_state; + struct radeon_power_state *requested_power_state; struct radeon_power_state *default_power_state; }; diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 93ba0fb27e9..87d2776624b 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -79,6 +79,128 @@ static void radeon_print_power_mode_info(struct radeon_device *rdev) } } +static struct radeon_power_state * radeon_pick_power_state(struct radeon_device *rdev, + enum radeon_pm_state_type type) +{ + int i; + struct radeon_power_state *power_state = NULL; + + switch (type) { + case POWER_STATE_TYPE_DEFAULT: + default: + return rdev->pm.default_power_state; + case POWER_STATE_TYPE_POWERSAVE: + for (i = 0; i < rdev->pm.num_power_states; i++) { + if (rdev->pm.power_state[i].type == POWER_STATE_TYPE_POWERSAVE) { + power_state = &rdev->pm.power_state[i]; + break; + } + } + if (power_state == NULL) { + for (i = 0; i < rdev->pm.num_power_states; i++) { + if (rdev->pm.power_state[i].type == POWER_STATE_TYPE_BATTERY) { + power_state = &rdev->pm.power_state[i]; + break; + } + } + } + break; + case POWER_STATE_TYPE_BATTERY: + for (i = 0; i < rdev->pm.num_power_states; i++) { + if (rdev->pm.power_state[i].type == POWER_STATE_TYPE_BATTERY) { + power_state = &rdev->pm.power_state[i]; + break; + } + } + if (power_state == NULL) { + for (i = 0; i < rdev->pm.num_power_states; i++) { + if (rdev->pm.power_state[i].type == POWER_STATE_TYPE_POWERSAVE) { + power_state = &rdev->pm.power_state[i]; + break; + } + } + } + break; + case POWER_STATE_TYPE_BALANCED: + case POWER_STATE_TYPE_PERFORMANCE: + for (i = 0; i < rdev->pm.num_power_states; i++) { + if (rdev->pm.power_state[i].type == type) { + power_state = &rdev->pm.power_state[i]; + break; + } + } + break; + } + + if (power_state == NULL) + return rdev->pm.default_power_state; + + return power_state; +} + +static struct radeon_pm_clock_info * radeon_pick_clock_mode(struct radeon_device *rdev, + struct radeon_power_state *power_state, + enum radeon_pm_clock_mode_type type) +{ + switch (type) { + case POWER_MODE_TYPE_DEFAULT: + default: + return power_state->default_clock_mode; + case POWER_MODE_TYPE_LOW: + return &power_state->clock_info[0]; + case POWER_MODE_TYPE_MID: + if (power_state->num_clock_modes > 2) + return &power_state->clock_info[1]; + else + return &power_state->clock_info[0]; + break; + case POWER_MODE_TYPE_HIGH: + return &power_state->clock_info[power_state->num_clock_modes - 1]; + } + +} + +static void radeon_get_power_state(struct radeon_device *rdev, + enum radeon_pm_action action) +{ + switch (action) { + case PM_ACTION_NONE: + default: + rdev->pm.requested_power_state = rdev->pm.current_power_state; + rdev->pm.requested_power_state->requested_clock_mode = + rdev->pm.requested_power_state->current_clock_mode; + break; + case PM_ACTION_MINIMUM: + rdev->pm.requested_power_state = radeon_pick_power_state(rdev, POWER_STATE_TYPE_BATTERY); + rdev->pm.requested_power_state->requested_clock_mode = + radeon_pick_clock_mode(rdev, rdev->pm.requested_power_state, POWER_MODE_TYPE_LOW); + break; + case PM_ACTION_DOWNCLOCK: + rdev->pm.requested_power_state = radeon_pick_power_state(rdev, POWER_STATE_TYPE_POWERSAVE); + rdev->pm.requested_power_state->requested_clock_mode = + radeon_pick_clock_mode(rdev, rdev->pm.requested_power_state, POWER_MODE_TYPE_MID); + break; + case PM_ACTION_UPCLOCK: + rdev->pm.requested_power_state = radeon_pick_power_state(rdev, POWER_STATE_TYPE_DEFAULT); + rdev->pm.requested_power_state->requested_clock_mode = + radeon_pick_clock_mode(rdev, rdev->pm.requested_power_state, POWER_MODE_TYPE_HIGH); + break; + } +} + +static void radeon_set_power_state(struct radeon_device *rdev) +{ + if (rdev->pm.requested_power_state == rdev->pm.current_power_state) + return; + /* set pcie lanes */ + /* set voltage */ + /* set engine clock */ + radeon_set_engine_clock(rdev, rdev->pm.requested_power_state->requested_clock_mode->sclk); + /* set memory clock */ + + rdev->pm.current_power_state = rdev->pm.requested_power_state; +} + int radeon_pm_init(struct radeon_device *rdev) { rdev->pm.state = PM_STATE_DISABLED; |