drm/radeon/kms/pm: add asic specific callbacks for getting power state (v2)
authorAlex Deucher <alexdeucher@gmail.com>
Thu, 22 Apr 2010 18:03:55 +0000 (14:03 -0400)
committerDave Airlie <airlied@redhat.com>
Tue, 18 May 2010 08:20:58 +0000 (18:20 +1000)
This also simplifies the code and enables reclocking with multiple heads
active by tracking whether the power states are single or multi-head
capable.

Eventually, we will want to select a power state based on external
factors (AC/DC state, user selection, etc.).

(v2) Update for evergreen

Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
drivers/gpu/drm/radeon/atombios_crtc.c
drivers/gpu/drm/radeon/r100.c
drivers/gpu/drm/radeon/r600.c
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_asic.c
drivers/gpu/drm/radeon/radeon_asic.h
drivers/gpu/drm/radeon/radeon_atombios.c
drivers/gpu/drm/radeon/radeon_combios.c
drivers/gpu/drm/radeon/radeon_legacy_crtc.c
drivers/gpu/drm/radeon/radeon_pm.c

index 12fb12a..b11aa37 100644 (file)
@@ -251,6 +251,7 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode)
                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:
@@ -260,6 +261,7 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode)
                if (ASIC_IS_DCE3(rdev))
                        atombios_enable_crtc_memreq(crtc, ATOM_DISABLE);
                atombios_enable_crtc(crtc, ATOM_DISABLE);
+               radeon_crtc->enabled = false;
                break;
        }
 
index b076b96..a6b2aca 100644 (file)
@@ -67,41 +67,133 @@ 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)
+{
+       int i;
+       rdev->pm.can_upclock = true;
+       rdev->pm.can_downclock = true;
+
+       switch (action) {
+       case PM_ACTION_MINIMUM:
+               rdev->pm.requested_power_state_index = 0;
+               rdev->pm.can_downclock = false;
+               break;
+       case PM_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;
+               } 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)
+                                               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;
+               }
+               break;
+       case PM_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;
+               } 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)
+                                               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;
+               }
+               break;
+       case PM_ACTION_NONE:
+       default:
+               DRM_ERROR("Requested mode for not defined action\n");
+               return;
+       }
+       /* 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].
+                non_clock_info.pcie_lanes);
+}
+
 void r100_set_power_state(struct radeon_device *rdev)
 {
-       /* if *_clock_mode are the same, *_power_state are as well */
-       if (rdev->pm.requested_clock_mode == rdev->pm.current_clock_mode)
+       u32 sclk, mclk;
+
+       if (rdev->pm.current_power_state_index == rdev->pm.requested_power_state_index)
                return;
 
-       DRM_INFO("Setting: e: %d m: %d p: %d\n",
-                rdev->pm.requested_clock_mode->sclk,
-                rdev->pm.requested_clock_mode->mclk,
-                rdev->pm.requested_power_state->non_clock_info.pcie_lanes);
+       if (radeon_gui_idle(rdev)) {
 
-       /* set pcie lanes */
-       /* TODO */
+               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;
 
-       /* set voltage */
-       /* TODO */
+               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;
 
-       /* set engine clock */
-       radeon_sync_with_vblank(rdev);
-       radeon_pm_debug_check_in_vbl(rdev, false);
-       radeon_set_engine_clock(rdev, rdev->pm.requested_clock_mode->sclk);
-       radeon_pm_debug_check_in_vbl(rdev, true);
+               /* set pcie lanes */
+               /* TODO */
+
+               /* set voltage */
+               /* TODO */
+
+               /* set engine clock */
+               if (sclk != rdev->pm.current_sclk) {
+                       radeon_sync_with_vblank(rdev);
+                       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);
+               }
 
 #if 0
-       /* set memory clock */
-       if (rdev->asic->set_memory_clock) {
-               radeon_sync_with_vblank(rdev);
-               radeon_pm_debug_check_in_vbl(rdev, false);
-               radeon_set_memory_clock(rdev, rdev->pm.requested_clock_mode->mclk);
-               radeon_pm_debug_check_in_vbl(rdev, true);
-       }
+               /* set memory clock */
+               if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) {
+                       radeon_sync_with_vblank(rdev);
+                       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);
+               }
 #endif
 
-       rdev->pm.current_power_state = rdev->pm.requested_power_state;
-       rdev->pm.current_clock_mode = rdev->pm.requested_clock_mode;
+               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");
 }
 
 bool r100_gui_idle(struct radeon_device *rdev)
index c2d1946..cc27979 100644 (file)
@@ -92,41 +92,206 @@ 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_set_power_state(struct radeon_device *rdev)
+void r600_get_power_state(struct radeon_device *rdev,
+                         enum radeon_pm_action action)
 {
-       /* if *_clock_mode are the same, *_power_state are as well */
-       if (rdev->pm.requested_clock_mode == rdev->pm.current_clock_mode)
-               return;
+       int i;
+
+       rdev->pm.can_upclock = true;
+       rdev->pm.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 (action) {
+               case PM_ACTION_MINIMUM:
+                       rdev->pm.requested_power_state_index = min_power_state_index;
+                       rdev->pm.requested_clock_mode_index = 0;
+                       rdev->pm.can_downclock = false;
+                       break;
+               case PM_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;
+                       } 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)
+                                                       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 PM_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;
+                       } 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)
+                                                       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 PM_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_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 (action) {
+               case PM_ACTION_MINIMUM:
+                       rdev->pm.requested_clock_mode_index = 0;
+                       rdev->pm.can_downclock = false;
+                       break;
+               case PM_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;
+                               } 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;
+                       }
+                       break;
+               case PM_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;
+                               } 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;
+                       }
+                       break;
+               case PM_ACTION_NONE:
+               default:
+                       DRM_ERROR("Requested mode for not defined action\n");
+                       return;
+               }
+       }
 
-       DRM_INFO("Setting: e: %d m: %d p: %d\n",
-                rdev->pm.requested_clock_mode->sclk,
-                rdev->pm.requested_clock_mode->mclk,
-                rdev->pm.requested_power_state->non_clock_info.pcie_lanes);
+       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].
+                non_clock_info.pcie_lanes);
+}
 
-       /* set pcie lanes */
-       /* TODO */
+void r600_set_power_state(struct radeon_device *rdev)
+{
+       u32 sclk, mclk;
 
-       /* set voltage */
-       /* TODO */
+       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;
 
-       /* set engine clock */
-       radeon_sync_with_vblank(rdev);
-       radeon_pm_debug_check_in_vbl(rdev, false);
-       radeon_set_engine_clock(rdev, rdev->pm.requested_clock_mode->sclk);
-       radeon_pm_debug_check_in_vbl(rdev, true);
+       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;
+
+               /* set pcie lanes */
+               /* TODO */
+
+               /* set voltage */
+               /* TODO */
+
+               /* set engine clock */
+               if (sclk != rdev->pm.current_sclk) {
+                       radeon_sync_with_vblank(rdev);
+                       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);
+               }
 
 #if 0
-       /* set memory clock */
-       if (rdev->asic->set_memory_clock) {
-               radeon_sync_with_vblank(rdev);
-               radeon_pm_debug_check_in_vbl(rdev, false);
-               radeon_set_memory_clock(rdev, rdev->pm.requested_clock_mode->mclk);
-               radeon_pm_debug_check_in_vbl(rdev, true);
-       }
+               /* set memory clock */
+               if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) {
+                       radeon_sync_with_vblank(rdev);
+                       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);
+               }
 #endif
 
-       rdev->pm.current_power_state = rdev->pm.requested_power_state;
-       rdev->pm.current_clock_mode = rdev->pm.requested_clock_mode;
+               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");
 }
 
 bool r600_gui_idle(struct radeon_device *rdev)
index 11fe1d1..b5eccc4 100644 (file)
@@ -672,6 +672,9 @@ struct radeon_pm_clock_info {
        u32 flags;
 };
 
+/* state flags */
+#define RADEON_PM_SINGLE_DISPLAY_ONLY (1 << 0)
+
 struct radeon_power_state {
        enum radeon_pm_state_type type;
        /* XXX: use a define for num clock modes */
@@ -682,6 +685,8 @@ struct radeon_power_state {
        /* non clock info about this state */
        struct radeon_pm_non_clock_info non_clock_info;
        bool voltage_drop_active;
+       /* standardized state flags */
+       u32 flags;
 };
 
 /*
@@ -695,8 +700,10 @@ struct radeon_pm {
        enum radeon_pm_state    state;
        enum radeon_pm_action   planned_action;
        unsigned long           action_timeout;
-       bool                    downclocked;
-       int                     active_crtcs;
+       bool                    can_upclock;
+       bool                    can_downclock;
+       u32                     active_crtcs;
+       int                     active_crtc_count;
        int                     req_vblank;
        bool                    vblank_sync;
        bool                    gui_idle;
@@ -716,11 +723,13 @@ struct radeon_pm {
        struct radeon_power_state power_state[8];
        /* number of valid power states */
        int                     num_power_states;
-       struct radeon_power_state *current_power_state;
-       struct radeon_pm_clock_info *current_clock_mode;
-       struct radeon_power_state *requested_power_state;
-       struct radeon_pm_clock_info *requested_clock_mode;
-       struct radeon_power_state *default_power_state;
+       int                     current_power_state_index;
+       int                     current_clock_mode_index;
+       int                     requested_power_state_index;
+       int                     requested_clock_mode_index;
+       int                     default_power_state_index;
+       u32                     current_sclk;
+       u32                     current_mclk;
        struct radeon_i2c_chan *i2c_bus;
 };
 
@@ -810,6 +819,7 @@ 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);
 };
 
@@ -1218,6 +1228,7 @@ 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) (rdev)->asic->set_power_state((rdev))
 
 /* Common functions */
index 48893fb..1053115 100644 (file)
@@ -166,6 +166,7 @@ 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,
 };
 
@@ -206,6 +207,7 @@ 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,
 };
 
@@ -247,6 +249,7 @@ 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,
 };
 
@@ -287,6 +290,7 @@ 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,
 };
 
@@ -328,6 +332,7 @@ 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,
 };
 
@@ -369,6 +374,7 @@ 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,
 };
 
@@ -410,6 +416,7 @@ 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,
 };
 
@@ -451,6 +458,7 @@ 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,
 };
 
@@ -492,6 +500,7 @@ 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,
 };
 
@@ -533,6 +542,7 @@ 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,
 };
 
@@ -573,6 +583,7 @@ 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,
 };
 
@@ -613,6 +624,7 @@ 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,
 };
 
@@ -653,6 +665,7 @@ 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,
 };
 
@@ -691,6 +704,7 @@ 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,
 };
 
index 90d8e6d..71b21bb 100644 (file)
@@ -128,6 +128,8 @@ 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);
+extern void r100_get_power_state(struct radeon_device *rdev,
+                                enum radeon_pm_action action);
 
 /*
  * r200,rv250,rs300,rv280
@@ -274,6 +276,8 @@ void r600_hpd_set_polarity(struct radeon_device *rdev,
 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);
+extern void r600_get_power_state(struct radeon_device *rdev,
+                                enum radeon_pm_action action);
 
 /*
  * rv770,rv730,rv710,rv740
index aa0a973..dbfb837 100644 (file)
@@ -1489,7 +1489,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
        int state_index = 0, mode_index = 0;
        struct radeon_i2c_bus_rec i2c_bus;
 
-       rdev->pm.default_power_state = NULL;
+       rdev->pm.default_power_state_index = -1;
 
        if (atom_parse_data_header(mode_info->atom_context, index, NULL,
                                   &frev, &crev, &data_offset)) {
@@ -1520,12 +1520,6 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
                                        if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) ||
                                            (rdev->pm.power_state[state_index].clock_info[0].sclk == 0))
                                                continue;
-                                       /* skip overclock modes for now */
-                                       if ((rdev->pm.power_state[state_index].clock_info[0].mclk >
-                                            rdev->clock.default_mclk + RADEON_MODE_OVERCLOCK_MARGIN) ||
-                                           (rdev->pm.power_state[state_index].clock_info[0].sclk >
-                                            rdev->clock.default_sclk + RADEON_MODE_OVERCLOCK_MARGIN))
-                                               continue;
                                        rdev->pm.power_state[state_index].non_clock_info.pcie_lanes =
                                                power_info->info.asPowerPlayInfo[i].ucNumPciELanes;
                                        misc = le32_to_cpu(power_info->info.asPowerPlayInfo[i].ulMiscInfo);
@@ -1547,6 +1541,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;
                                        /* order matters! */
                                        if (misc & ATOM_PM_MISCINFO_POWER_SAVING_MODE)
                                                rdev->pm.power_state[state_index].type =
@@ -1560,15 +1555,20 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
                                        if (misc & ATOM_PM_MISCINFO_LOAD_BALANCE_EN)
                                                rdev->pm.power_state[state_index].type =
                                                        POWER_STATE_TYPE_BALANCED;
-                                       if (misc & ATOM_PM_MISCINFO_3D_ACCELERATION_EN)
+                                       if (misc & ATOM_PM_MISCINFO_3D_ACCELERATION_EN) {
                                                rdev->pm.power_state[state_index].type =
                                                        POWER_STATE_TYPE_PERFORMANCE;
+                                               rdev->pm.power_state[state_index].flags &=
+                                                       ~RADEON_PM_SINGLE_DISPLAY_ONLY;
+                                       }
                                        if (misc & ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE) {
                                                rdev->pm.power_state[state_index].type =
                                                        POWER_STATE_TYPE_DEFAULT;
-                                               rdev->pm.default_power_state = &rdev->pm.power_state[state_index];
+                                               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];
+                                               rdev->pm.power_state[state_index].flags &=
+                                                       ~RADEON_PM_SINGLE_DISPLAY_ONLY;
                                        }
                                        state_index++;
                                        break;
@@ -1582,12 +1582,6 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
                                        if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) ||
                                            (rdev->pm.power_state[state_index].clock_info[0].sclk == 0))
                                                continue;
-                                       /* skip overclock modes for now */
-                                       if ((rdev->pm.power_state[state_index].clock_info[0].mclk >
-                                            rdev->clock.default_mclk + RADEON_MODE_OVERCLOCK_MARGIN) ||
-                                           (rdev->pm.power_state[state_index].clock_info[0].sclk >
-                                            rdev->clock.default_sclk + RADEON_MODE_OVERCLOCK_MARGIN))
-                                               continue;
                                        rdev->pm.power_state[state_index].non_clock_info.pcie_lanes =
                                                power_info->info_2.asPowerPlayInfo[i].ucNumPciELanes;
                                        misc = le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMiscInfo);
@@ -1610,6 +1604,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;
                                        /* order matters! */
                                        if (misc & ATOM_PM_MISCINFO_POWER_SAVING_MODE)
                                                rdev->pm.power_state[state_index].type =
@@ -1623,18 +1618,26 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
                                        if (misc & ATOM_PM_MISCINFO_LOAD_BALANCE_EN)
                                                rdev->pm.power_state[state_index].type =
                                                        POWER_STATE_TYPE_BALANCED;
-                                       if (misc & ATOM_PM_MISCINFO_3D_ACCELERATION_EN)
+                                       if (misc & ATOM_PM_MISCINFO_3D_ACCELERATION_EN) {
                                                rdev->pm.power_state[state_index].type =
                                                        POWER_STATE_TYPE_PERFORMANCE;
+                                               rdev->pm.power_state[state_index].flags &=
+                                                       ~RADEON_PM_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;
                                        if (misc & ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE) {
                                                rdev->pm.power_state[state_index].type =
                                                        POWER_STATE_TYPE_DEFAULT;
-                                               rdev->pm.default_power_state = &rdev->pm.power_state[state_index];
+                                               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];
+                                               rdev->pm.power_state[state_index].flags &=
+                                                       ~RADEON_PM_SINGLE_DISPLAY_ONLY;
                                        }
                                        state_index++;
                                        break;
@@ -1648,12 +1651,6 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
                                        if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) ||
                                            (rdev->pm.power_state[state_index].clock_info[0].sclk == 0))
                                                continue;
-                                       /* skip overclock modes for now */
-                                       if ((rdev->pm.power_state[state_index].clock_info[0].mclk >
-                                            rdev->clock.default_mclk + RADEON_MODE_OVERCLOCK_MARGIN) ||
-                                           (rdev->pm.power_state[state_index].clock_info[0].sclk >
-                                            rdev->clock.default_sclk + RADEON_MODE_OVERCLOCK_MARGIN))
-                                               continue;
                                        rdev->pm.power_state[state_index].non_clock_info.pcie_lanes =
                                                power_info->info_3.asPowerPlayInfo[i].ucNumPciELanes;
                                        misc = le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMiscInfo);
@@ -1682,6 +1679,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;
                                        /* order matters! */
                                        if (misc & ATOM_PM_MISCINFO_POWER_SAVING_MODE)
                                                rdev->pm.power_state[state_index].type =
@@ -1695,16 +1693,19 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
                                        if (misc & ATOM_PM_MISCINFO_LOAD_BALANCE_EN)
                                                rdev->pm.power_state[state_index].type =
                                                        POWER_STATE_TYPE_BALANCED;
-                                       if (misc & ATOM_PM_MISCINFO_3D_ACCELERATION_EN)
+                                       if (misc & ATOM_PM_MISCINFO_3D_ACCELERATION_EN) {
                                                rdev->pm.power_state[state_index].type =
                                                        POWER_STATE_TYPE_PERFORMANCE;
+                                               rdev->pm.power_state[state_index].flags &=
+                                                       ~RADEON_PM_SINGLE_DISPLAY_ONLY;
+                                       }
                                        if (misc2 & ATOM_PM_MISCINFO2_SYSTEM_AC_LITE_MODE)
                                                rdev->pm.power_state[state_index].type =
                                                        POWER_STATE_TYPE_BALANCED;
                                        if (misc & ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE) {
                                                rdev->pm.power_state[state_index].type =
                                                        POWER_STATE_TYPE_DEFAULT;
-                                               rdev->pm.default_power_state = &rdev->pm.power_state[state_index];
+                                               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];
                                        }
@@ -1713,12 +1714,14 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
                                }
                        }
                        /* last mode is usually default */
-                       if (!rdev->pm.default_power_state) {
+                       if (rdev->pm.default_power_state_index == -1) {
                                rdev->pm.power_state[state_index - 1].type =
                                        POWER_STATE_TYPE_DEFAULT;
-                               rdev->pm.default_power_state = &rdev->pm.power_state[state_index - 1];
+                               rdev->pm.default_power_state_index = state_index - 1;
                                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;
                        }
                } else {
                        /* add the i2c bus for thermal/fan chip */
@@ -1774,10 +1777,6 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
                                                /* skip invalid modes */
                                                if (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0)
                                                        continue;
-                                               /* skip overclock modes for now */
-                                               if (rdev->pm.power_state[state_index].clock_info[mode_index].sclk >
-                                                   rdev->clock.default_sclk + RADEON_MODE_OVERCLOCK_MARGIN)
-                                                       continue;
                                                rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type =
                                                        VOLTAGE_SW;
                                                rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage =
@@ -1801,12 +1800,6 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
                                                if ((rdev->pm.power_state[state_index].clock_info[mode_index].mclk == 0) ||
                                                    (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0))
                                                        continue;
-                                               /* skip overclock modes for now */
-                                               if ((rdev->pm.power_state[state_index].clock_info[mode_index].mclk >
-                                                    rdev->clock.default_mclk + RADEON_MODE_OVERCLOCK_MARGIN) ||
-                                                   (rdev->pm.power_state[state_index].clock_info[mode_index].sclk >
-                                                    rdev->clock.default_sclk + RADEON_MODE_OVERCLOCK_MARGIN))
-                                                       continue;
                                                rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type =
                                                        VOLTAGE_SW;
                                                rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage =
@@ -1831,12 +1824,6 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
                                                if ((rdev->pm.power_state[state_index].clock_info[mode_index].mclk == 0) ||
                                                    (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0))
                                                        continue;
-                                               /* skip overclock modes for now */
-                                               if ((rdev->pm.power_state[state_index].clock_info[mode_index].mclk >
-                                                    rdev->clock.default_mclk + RADEON_MODE_OVERCLOCK_MARGIN) ||
-                                                   (rdev->pm.power_state[state_index].clock_info[mode_index].sclk >
-                                                    rdev->clock.default_sclk + RADEON_MODE_OVERCLOCK_MARGIN))
-                                                       continue;
                                                rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type =
                                                        VOLTAGE_SW;
                                                rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage =
@@ -1865,10 +1852,14 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
                                                        POWER_STATE_TYPE_PERFORMANCE;
                                                break;
                                        }
+                                       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;
                                        if (misc2 & ATOM_PPLIB_CLASSIFICATION_BOOT) {
                                                rdev->pm.power_state[state_index].type =
                                                        POWER_STATE_TYPE_DEFAULT;
-                                               rdev->pm.default_power_state = &rdev->pm.power_state[state_index];
+                                               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[mode_index - 1];
                                        }
@@ -1876,10 +1867,10 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
                                }
                        }
                        /* first mode is usually default */
-                       if (!rdev->pm.default_power_state) {
+                       if (rdev->pm.default_power_state_index == -1) {
                                rdev->pm.power_state[0].type =
                                        POWER_STATE_TYPE_DEFAULT;
-                               rdev->pm.default_power_state = &rdev->pm.power_state[0];
+                               rdev->pm.default_power_state_index = 0;
                                rdev->pm.power_state[0].default_clock_mode =
                                        &rdev->pm.power_state[0].clock_info[0];
                        }
@@ -1898,15 +1889,15 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
                        rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = radeon_get_pcie_lanes(rdev);
                else
                        rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = 16;
-               rdev->pm.default_power_state = &rdev->pm.power_state[state_index];
+               rdev->pm.default_power_state_index = state_index;
+               rdev->pm.power_state[state_index].flags = 0;
                state_index++;
        }
 
        rdev->pm.num_power_states = state_index;
 
-       rdev->pm.current_power_state = rdev->pm.default_power_state;
-       rdev->pm.current_clock_mode =
-               rdev->pm.default_power_state->default_clock_mode;
+       rdev->pm.current_power_state_index = rdev->pm.default_power_state_index;
+       rdev->pm.current_clock_mode_index = 0;
 }
 
 void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable)
index 4419858..6a9ec85 100644 (file)
@@ -2368,7 +2368,7 @@ void radeon_combios_get_power_modes(struct radeon_device *rdev)
        u8 rev, blocks, tmp;
        int state_index = 0;
 
-       rdev->pm.default_power_state = NULL;
+       rdev->pm.default_power_state_index = -1;
 
        if (rdev->flags & RADEON_IS_MOBILITY) {
                offset = combios_get_table_offset(dev, COMBIOS_POWERPLAY_INFO_TABLE);
@@ -2441,6 +2441,7 @@ void radeon_combios_get_power_modes(struct radeon_device *rdev)
                        if (rev > 6)
                                rdev->pm.power_state[state_index].non_clock_info.pcie_lanes =
                                        RBIOS8(offset + 0x5 + 0x10);
+                       rdev->pm.power_state[state_index].flags = RADEON_PM_SINGLE_DISPLAY_ONLY;
                        state_index++;
                } else {
                        /* XXX figure out some good default low power mode for mobility cards w/out power tables */
@@ -2462,12 +2463,12 @@ default_mode:
                rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = radeon_get_pcie_lanes(rdev);
        else
                rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = 16;
-       rdev->pm.default_power_state = &rdev->pm.power_state[state_index];
+       rdev->pm.power_state[state_index].flags = 0;
+       rdev->pm.default_power_state_index = state_index;
        rdev->pm.num_power_states = state_index + 1;
 
-       rdev->pm.current_power_state = rdev->pm.default_power_state;
-       rdev->pm.current_clock_mode =
-               rdev->pm.default_power_state->default_clock_mode;
+       rdev->pm.current_power_state_index = rdev->pm.default_power_state_index;
+       rdev->pm.current_clock_mode_index = 0;
 }
 
 void radeon_external_tmds_setup(struct drm_encoder *encoder)
index 60c0dcb..f4f9cb2 100644 (file)
@@ -323,6 +323,7 @@ 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:
@@ -335,6 +336,7 @@ void radeon_crtc_dpms(struct drm_crtc *crtc, int mode)
                                                                                    RADEON_CRTC_DISP_REQ_EN_B));
                        WREG32_P(RADEON_CRTC_EXT_CNTL, mask, ~mask);
                }
+               radeon_crtc->enabled = false;
                break;
        }
 
index 129956d..10ef892 100644 (file)
@@ -56,7 +56,7 @@ static void radeon_print_power_mode_info(struct radeon_device *rdev)
 
        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 == &rdev->pm.power_state[i])
+               if (rdev->pm.default_power_state_index == i)
                        is_default = true;
                else
                        is_default = false;
@@ -65,6 +65,8 @@ 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].non_clock_info.pcie_lanes);
+               if (rdev->pm.power_state[i].flags & RADEON_PM_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)
@@ -80,106 +82,6 @@ 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, j;
-       enum radeon_pm_state_type wanted_types[2];
-       int wanted_count;
-
-       switch (type) {
-       case POWER_STATE_TYPE_DEFAULT:
-       default:
-               return rdev->pm.default_power_state;
-       case POWER_STATE_TYPE_POWERSAVE:
-               if (rdev->flags & RADEON_IS_MOBILITY) {
-                       wanted_types[0] = POWER_STATE_TYPE_POWERSAVE;
-                       wanted_types[1] = POWER_STATE_TYPE_BATTERY;
-                       wanted_count = 2;
-               } else {
-                       wanted_types[0] = POWER_STATE_TYPE_PERFORMANCE;
-                       wanted_count = 1;
-               }
-               break;
-       case POWER_STATE_TYPE_BATTERY:
-               if (rdev->flags & RADEON_IS_MOBILITY) {
-                       wanted_types[0] = POWER_STATE_TYPE_BATTERY;
-                       wanted_types[1] = POWER_STATE_TYPE_POWERSAVE;
-                       wanted_count = 2;
-               } else {
-                       wanted_types[0] = POWER_STATE_TYPE_PERFORMANCE;
-                       wanted_count = 1;
-               }
-               break;
-       case POWER_STATE_TYPE_BALANCED:
-       case POWER_STATE_TYPE_PERFORMANCE:
-               wanted_types[0] = type;
-               wanted_count = 1;
-               break;
-       }
-
-       for (i = 0; i < wanted_count; i++) {
-               for (j = 0; j < rdev->pm.num_power_states; j++) {
-                       if (rdev->pm.power_state[j].type == wanted_types[i])
-                               return &rdev->pm.power_state[j];
-               }
-       }
-
-       return rdev->pm.default_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_MINIMUM:
-               rdev->pm.requested_power_state = radeon_pick_power_state(rdev, POWER_STATE_TYPE_BATTERY);
-               rdev->pm.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_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_clock_mode =
-                       radeon_pick_clock_mode(rdev, rdev->pm.requested_power_state, POWER_MODE_TYPE_HIGH);
-               break;
-       case PM_ACTION_NONE:
-       default:
-               DRM_ERROR("Requested mode for not defined action\n");
-               return;
-       }
-       DRM_INFO("Requested: e: %d m: %d p: %d\n",
-                rdev->pm.requested_clock_mode->sclk,
-                rdev->pm.requested_clock_mode->mclk,
-                rdev->pm.requested_power_state->non_clock_info.pcie_lanes);
-}
-
 void radeon_sync_with_vblank(struct radeon_device *rdev)
 {
        if (rdev->pm.active_crtcs) {
@@ -194,7 +96,8 @@ int radeon_pm_init(struct radeon_device *rdev)
 {
        rdev->pm.state = PM_STATE_DISABLED;
        rdev->pm.planned_action = PM_ACTION_NONE;
-       rdev->pm.downclocked = false;
+       rdev->pm.can_upclock = true;
+       rdev->pm.can_downclock = true;
 
        if (rdev->bios) {
                if (rdev->is_atom_bios)
@@ -229,9 +132,8 @@ void radeon_pm_fini(struct radeon_device *rdev)
 void radeon_pm_compute_clocks(struct radeon_device *rdev)
 {
        struct drm_device *ddev = rdev->ddev;
-       struct drm_connector *connector;
+       struct drm_crtc *crtc;
        struct radeon_crtc *radeon_crtc;
-       int count = 0;
 
        if (rdev->pm.state == PM_STATE_DISABLED)
                return;
@@ -239,29 +141,27 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev)
        mutex_lock(&rdev->pm.mutex);
 
        rdev->pm.active_crtcs = 0;
-       list_for_each_entry(connector,
-               &ddev->mode_config.connector_list, head) {
-               if (connector->encoder &&
-                   connector->encoder->crtc &&
-                   connector->dpms != DRM_MODE_DPMS_OFF) {
-                       radeon_crtc = to_radeon_crtc(connector->encoder->crtc);
+       rdev->pm.active_crtc_count = 0;
+       list_for_each_entry(crtc,
+               &ddev->mode_config.crtc_list, head) {
+               radeon_crtc = to_radeon_crtc(crtc);
+               if (radeon_crtc->enabled) {
                        rdev->pm.active_crtcs |= (1 << radeon_crtc->crtc_id);
-                       ++count;
+                       rdev->pm.active_crtc_count++;
                }
        }
 
-       if (count > 1) {
+       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;
-                       if (rdev->pm.downclocked)
-                               radeon_pm_set_clocks(rdev);
+                       radeon_pm_set_clocks(rdev);
 
                        DRM_DEBUG("radeon: dynamic power management deactivated\n");
                }
-       } else if (count == 1) {
+       } else if (rdev->pm.active_crtc_count == 1) {
                /* TODO: Increase clocks if needed for current mode */
 
                if (rdev->pm.state == PM_STATE_MINIMUM) {
@@ -271,15 +171,13 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev)
 
                        queue_delayed_work(rdev->wq, &rdev->pm.idle_work,
                                msecs_to_jiffies(RADEON_IDLE_LOOP_MS));
-               }
-               else if (rdev->pm.state == PM_STATE_PAUSED) {
+               } 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 */
+       } else { /* count == 0 */
                if (rdev->pm.state != PM_STATE_MINIMUM) {
                        cancel_delayed_work(&rdev->pm.idle_work);
 
@@ -359,19 +257,6 @@ bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish)
 static void radeon_pm_set_clocks_locked(struct radeon_device *rdev)
 {
        /*radeon_fence_wait_last(rdev);*/
-       switch (rdev->pm.planned_action) {
-       case PM_ACTION_UPCLOCK:
-               rdev->pm.downclocked = false;
-               break;
-       case PM_ACTION_DOWNCLOCK:
-               rdev->pm.downclocked = true;
-               break;
-       case PM_ACTION_MINIMUM:
-               break;
-       case PM_ACTION_NONE:
-               DRM_ERROR("%s: PM_ACTION_NONE\n", __func__);
-               break;
-       }
 
        radeon_set_power_state(rdev);
        rdev->pm.planned_action = PM_ACTION_NONE;
@@ -437,7 +322,7 @@ static void radeon_pm_idle_work_handler(struct work_struct *work)
                        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.downclocked) {
+                                  rdev->pm.can_upclock) {
                                rdev->pm.planned_action =
                                        PM_ACTION_UPCLOCK;
                                rdev->pm.action_timeout = jiffies +
@@ -447,7 +332,7 @@ static void radeon_pm_idle_work_handler(struct work_struct *work)
                        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.downclocked) {
+                                  rdev->pm.can_downclock) {
                                rdev->pm.planned_action =
                                        PM_ACTION_DOWNCLOCK;
                                rdev->pm.action_timeout = jiffies +