drm/radeon/kms/pm: add mid profile
[safe/jmp/linux-2.6] / drivers / gpu / drm / radeon / r600.c
index 2ec423c..d152cec 100644 (file)
@@ -92,6 +92,488 @@ 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_pm_get_dynpm_state(struct radeon_device *rdev)
+{
+       int i;
+
+       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)) {
+               int min_power_state_index = 0;
+
+               if (rdev->pm.num_power_states > 2)
+                       min_power_state_index = 1;
+
+               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.dynpm_can_downclock = false;
+                       break;
+               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.dynpm_can_downclock = false;
+                       } 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_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;
+                                                       break;
+                                               } else {
+                                                       rdev->pm.requested_power_state_index = i;
+                                                       break;
+                                               }
+                                       }
+                               } else
+                                       rdev->pm.requested_power_state_index =
+                                               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 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.dynpm_can_upclock = false;
+                       } 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_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;
+                                                       break;
+                                               } else {
+                                                       rdev->pm.requested_power_state_index = i;
+                                                       break;
+                                               }
+                                       }
+                               } else
+                                       rdev->pm.requested_power_state_index =
+                                               rdev->pm.current_power_state_index + 1;
+                       }
+                       rdev->pm.requested_clock_mode_index = 0;
+                       break;
+               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.dynpm_can_upclock = false;
+                       break;
+               case DYNPM_ACTION_NONE:
+               default:
+                       DRM_ERROR("Requested mode for not defined action\n");
+                       return;
+               }
+       } else {
+               /* XXX select a power state based on AC/DC, single/dualhead, etc. */
+               /* for now just select the first power state and switch between clock modes */
+               /* power state array is low to high, default is first (0) */
+               if (rdev->pm.active_crtc_count > 1) {
+                       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_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)) {
+                                       rdev->pm.requested_power_state_index = i;
+                                       break;
+                               }
+                       }
+                       /* if nothing selected, grab the default state. */
+                       if (rdev->pm.requested_power_state_index == -1)
+                               rdev->pm.requested_power_state_index = 0;
+               } else
+                       rdev->pm.requested_power_state_index = 1;
+
+               switch (rdev->pm.dynpm_planned_action) {
+               case DYNPM_ACTION_MINIMUM:
+                       rdev->pm.requested_clock_mode_index = 0;
+                       rdev->pm.dynpm_can_downclock = false;
+                       break;
+               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.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.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) &&
+                           (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 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.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.dynpm_can_upclock = false;
+                       }
+                       break;
+               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.dynpm_can_upclock = false;
+                       break;
+               case DYNPM_ACTION_NONE:
+               default:
+                       DRM_ERROR("Requested mode for not defined action\n");
+                       return;
+               }
+       }
+
+       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,
+                                 enum radeon_pm_state_type ps_type,
+                                 int instance)
+{
+       int i;
+       int found_instance = -1;
+
+       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;
+               /* mid sh */
+               rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_ps_idx = 0;
+               rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_ps_idx = 0;
+               rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_cm_idx = 0;
+               rdev->pm.profiles[PM_PROFILE_MID_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;
+               /* mid mh */
+               rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_ps_idx = 0;
+               rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_ps_idx = 0;
+               rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_cm_idx = 0;
+               rdev->pm.profiles[PM_PROFILE_MID_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;
+               /* mid sh */
+               rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_ps_idx = 1;
+               rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_ps_idx = 1;
+               rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_cm_idx = 0;
+               rdev->pm.profiles[PM_PROFILE_MID_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;
+               /* mid mh */
+               rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_ps_idx = 1;
+               rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_ps_idx = 1;
+               rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_cm_idx = 0;
+               rdev->pm.profiles[PM_PROFILE_MID_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;
+               /* mid sh */
+               rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_ps_idx = 2;
+               rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_ps_idx = 2;
+               rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_cm_idx = 0;
+               rdev->pm.profiles[PM_PROFILE_MID_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;
+               /* mid mh */
+               rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_ps_idx = 2;
+               rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_ps_idx = 0;
+               rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_cm_idx = 0;
+               rdev->pm.profiles[PM_PROFILE_MID_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 = 0;
+               /* 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 = 0;
+               /* mid sh */
+               rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index;
+               rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index;
+               rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_cm_idx = 0;
+               rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_cm_idx = 0;
+               /* 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 = 0;
+               /* 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 = 0;
+               /* mid mh */
+               rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index;
+               rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index;
+               rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_cm_idx = 0;
+               rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_cm_idx = 0;
+               /* 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 = 0;
+       } 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 = 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;
+                       /* mid sh */
+                       rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_ps_idx = 1;
+                       rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_ps_idx = 1;
+                       rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_cm_idx = 0;
+                       rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_cm_idx = 1;
+                       /* 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 = 2;
+                       rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = 2;
+                       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;
+                       /* low mh */
+                       rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_ps_idx = 2;
+                       rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_ps_idx = 2;
+                       rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_cm_idx = 0;
+                       rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_cm_idx = 1;
+                       /* 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 = 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 = 2;
+               } 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 = 2;
+                       /* low sh */
+                       if (rdev->flags & RADEON_IS_MOBILITY) {
+                               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 = 0;
+                       } else {
+                               rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx =
+                                       r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0);
+                               rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx =
+                                       r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 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;
+                       }
+                       /* mid sh */
+                       if (rdev->flags & RADEON_IS_MOBILITY) {
+                               rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_ps_idx =
+                                       r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 0);
+                               rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_ps_idx =
+                                       r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 0);
+                               rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_cm_idx = 0;
+                               rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_cm_idx = 1;
+                       } else {
+                               rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_ps_idx =
+                                       r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0);
+                               rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_ps_idx =
+                                       r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0);
+                               rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_cm_idx = 0;
+                               rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_cm_idx = 1;
+                       }
+                       /* 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 */
+                       if (rdev->flags & RADEON_IS_MOBILITY) {
+                               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 = 0;
+                       } else {
+                               rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx =
+                                       r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 1);
+                               rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx =
+                                       r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 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;
+                       }
+                       /* mid mh */
+                       if (rdev->flags & RADEON_IS_MOBILITY) {
+                               rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_ps_idx =
+                                       r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 1);
+                               rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_ps_idx =
+                                       r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 1);
+                               rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_cm_idx = 0;
+                               rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_cm_idx = 1;
+                       } else {
+                               rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_ps_idx =
+                                       r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 1);
+                               rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_ps_idx =
+                                       r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 1);
+                               rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_cm_idx = 0;
+                               rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_cm_idx = 1;
+                       }
+                       /* 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;
+               }
+       }
+}
+
+void r600_pm_misc(struct radeon_device *rdev)
+{
+       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;
+
+       if ((voltage->type == VOLTAGE_SW) && voltage->voltage)
+               radeon_atom_set_voltage(rdev, voltage->voltage);
+
+}
+
+bool r600_gui_idle(struct radeon_device *rdev)
+{
+       if (RREG32(GRBM_STATUS) & GUI_ACTIVE)
+               return false;
+       else
+               return true;
+}
+
 /* hpd for digital panel detect/disconnect */
 bool r600_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd)
 {
@@ -2069,8 +2551,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)
@@ -2135,7 +2615,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);
@@ -2527,6 +3006,7 @@ int r600_irq_set(struct radeon_device *rdev)
        u32 cp_int_cntl = CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE;
        u32 mode_int = 0;
        u32 hpd1, hpd2, hpd3, hpd4 = 0, hpd5 = 0, hpd6 = 0;
+       u32 grbm_int_cntl = 0;
        u32 hdmi1, hdmi2;
 
        if (!rdev->irq.installed) {
@@ -2603,9 +3083,14 @@ int r600_irq_set(struct radeon_device *rdev)
                DRM_DEBUG("r600_irq_set: hdmi 2\n");
                hdmi2 |= R600_HDMI_INT_EN;
        }
+       if (rdev->irq.gui_idle) {
+               DRM_DEBUG("gui idle\n");
+               grbm_int_cntl |= GUI_IDLE_INT_ENABLE;
+       }
 
        WREG32(CP_INT_CNTL, cp_int_cntl);
        WREG32(DxMODE_INT_MASK, mode_int);
+       WREG32(GRBM_INT_CNTL, grbm_int_cntl);
        WREG32(R600_HDMI_BLOCK1 + R600_HDMI_CNTL, hdmi1);
        if (ASIC_IS_DCE3(rdev)) {
                WREG32(R600_HDMI_BLOCK3 + R600_HDMI_CNTL, hdmi2);
@@ -2921,6 +3406,11 @@ restart_ih:
                case 181: /* CP EOP event */
                        DRM_DEBUG("IH: CP EOP\n");
                        break;
+               case 233: /* GUI IDLE */
+                       DRM_DEBUG("IH: CP EOP\n");
+                       rdev->pm.gui_idle = true;
+                       wake_up(&rdev->irq.idle_queue);
+                       break;
                default:
                        DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
                        break;