diff options
author | Alex Deucher <alexdeucher@gmail.com> | 2010-05-07 15:10:16 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2010-05-18 18:21:52 +1000 |
commit | ce8f53709bf440100cb9d31b1303291551cf517f (patch) | |
tree | 6785882522ae04486ae900b5c8dbc700dadad2f3 /drivers/gpu | |
parent | d7311171c4cc8d6231427f7ac5056b939a184b80 (diff) |
drm/radeon/kms/pm: rework power management
- 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>
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/drm/radeon/Kconfig | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/evergreen.c | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/r100.c | 128 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/r300.c | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/r420.c | 32 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/r520.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/r600.c | 332 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon.h | 87 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_asic.c | 56 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_asic.h | 12 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_device.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_display.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_drv.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_pm.c | 628 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/rs400.c | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/rs600.c | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/rs690.c | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/rv515.c | 3 | ||||
-rw-r--r-- | 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 1c02d23f6fc..80c5b3ea28b 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 8d86d0568d9..8c8e4d3cbaa 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 4161a35dd3d..4c5d21bfa2c 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 5d622cb39b3..5c54db51de8 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 3759d838429..87c0e384003 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 870111e26bd..34330df2848 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 08a328c4165..618d76d366a 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) |