]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - drivers/gpu/drm/radeon/radeon_pm.c
drm/radeon/kms: fix radeon mid power profile reporting
[net-next-2.6.git] / drivers / gpu / drm / radeon / radeon_pm.c
index fcdf1db1e3ce692b619667823f6a70e4057d7069..3fa6984d9896094c3b0318ff486186c6cdf7ebdd 100644 (file)
 #define RADEON_WAIT_VBLANK_TIMEOUT 200
 #define RADEON_WAIT_IDLE_TIMEOUT 200
 
+static const char *radeon_pm_state_type_name[5] = {
+       "Default",
+       "Powersave",
+       "Battery",
+       "Balanced",
+       "Performance",
+};
+
 static void radeon_dynpm_idle_work_handler(struct work_struct *work);
 static int radeon_debugfs_pm_init(struct radeon_device *rdev);
 static bool radeon_pm_in_vbl(struct radeon_device *rdev);
@@ -278,6 +286,42 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev)
        mutex_unlock(&rdev->ddev->struct_mutex);
 }
 
+static void radeon_pm_print_states(struct radeon_device *rdev)
+{
+       int i, j;
+       struct radeon_power_state *power_state;
+       struct radeon_pm_clock_info *clock_info;
+
+       DRM_DEBUG("%d Power State(s)\n", rdev->pm.num_power_states);
+       for (i = 0; i < rdev->pm.num_power_states; i++) {
+               power_state = &rdev->pm.power_state[i];
+               DRM_DEBUG("State %d: %s\n", i,
+                       radeon_pm_state_type_name[power_state->type]);
+               if (i == rdev->pm.default_power_state_index)
+                       DRM_DEBUG("\tDefault");
+               if ((rdev->flags & RADEON_IS_PCIE) && !(rdev->flags & RADEON_IS_IGP))
+                       DRM_DEBUG("\t%d PCIE Lanes\n", power_state->pcie_lanes);
+               if (power_state->flags & RADEON_PM_STATE_SINGLE_DISPLAY_ONLY)
+                       DRM_DEBUG("\tSingle display only\n");
+               DRM_DEBUG("\t%d Clock Mode(s)\n", power_state->num_clock_modes);
+               for (j = 0; j < power_state->num_clock_modes; j++) {
+                       clock_info = &(power_state->clock_info[j]);
+                       if (rdev->flags & RADEON_IS_IGP)
+                               DRM_DEBUG("\t\t%d e: %d%s\n",
+                                       j,
+                                       clock_info->sclk * 10,
+                                       clock_info->flags & RADEON_PM_MODE_NO_DISPLAY ? "\tNo display only" : "");
+                       else
+                               DRM_DEBUG("\t\t%d e: %d\tm: %d\tv: %d%s\n",
+                                       j,
+                                       clock_info->sclk * 10,
+                                       clock_info->mclk * 10,
+                                       clock_info->voltage.voltage,
+                                       clock_info->flags & RADEON_PM_MODE_NO_DISPLAY ? "\tNo display only" : "");
+               }
+       }
+}
+
 static ssize_t radeon_get_pm_profile(struct device *dev,
                                     struct device_attribute *attr,
                                     char *buf)
@@ -289,6 +333,7 @@ static ssize_t radeon_get_pm_profile(struct device *dev,
        return snprintf(buf, PAGE_SIZE, "%s\n",
                        (cp == PM_PROFILE_AUTO) ? "auto" :
                        (cp == PM_PROFILE_LOW) ? "low" :
+                       (cp == PM_PROFILE_MID) ? "mid" :
                        (cp == PM_PROFILE_HIGH) ? "high" : "default");
 }
 
@@ -353,13 +398,20 @@ static ssize_t radeon_set_pm_method(struct device *dev,
                rdev->pm.dynpm_planned_action = DYNPM_ACTION_DEFAULT;
                mutex_unlock(&rdev->pm.mutex);
        } else if (strncmp("profile", buf, strlen("profile")) == 0) {
+               bool flush_wq = false;
+
                mutex_lock(&rdev->pm.mutex);
-               rdev->pm.pm_method = PM_METHOD_PROFILE;
+               if (rdev->pm.pm_method == PM_METHOD_DYNPM) {
+                       cancel_delayed_work(&rdev->pm.dynpm_idle_work);
+                       flush_wq = true;
+               }
                /* disable dynpm */
                rdev->pm.dynpm_state = DYNPM_STATE_DISABLED;
                rdev->pm.dynpm_planned_action = DYNPM_ACTION_NONE;
-               cancel_delayed_work(&rdev->pm.dynpm_idle_work);
+               rdev->pm.pm_method = PM_METHOD_PROFILE;
                mutex_unlock(&rdev->pm.mutex);
+               if (flush_wq)
+                       flush_workqueue(rdev->wq);
        } else {
                DRM_ERROR("invalid power method!\n");
                goto fail;
@@ -374,9 +426,18 @@ static DEVICE_ATTR(power_method, S_IRUGO | S_IWUSR, radeon_get_pm_method, radeon
 
 void radeon_pm_suspend(struct radeon_device *rdev)
 {
+       bool flush_wq = false;
+
        mutex_lock(&rdev->pm.mutex);
-       cancel_delayed_work(&rdev->pm.dynpm_idle_work);
+       if (rdev->pm.pm_method == PM_METHOD_DYNPM) {
+               cancel_delayed_work(&rdev->pm.dynpm_idle_work);
+               if (rdev->pm.dynpm_state == DYNPM_STATE_ACTIVE)
+                       rdev->pm.dynpm_state = DYNPM_STATE_SUSPENDED;
+               flush_wq = true;
+       }
        mutex_unlock(&rdev->pm.mutex);
+       if (flush_wq)
+               flush_workqueue(rdev->wq);
 }
 
 void radeon_pm_resume(struct radeon_device *rdev)
@@ -387,6 +448,13 @@ void radeon_pm_resume(struct radeon_device *rdev)
        rdev->pm.current_clock_mode_index = 0;
        rdev->pm.current_sclk = rdev->clock.default_sclk;
        rdev->pm.current_mclk = rdev->clock.default_mclk;
+       rdev->pm.current_vddc = rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.voltage;
+       if (rdev->pm.pm_method == PM_METHOD_DYNPM
+           && rdev->pm.dynpm_state == DYNPM_STATE_SUSPENDED) {
+               rdev->pm.dynpm_state = DYNPM_STATE_ACTIVE;
+               queue_delayed_work(rdev->wq, &rdev->pm.dynpm_idle_work,
+                                       msecs_to_jiffies(RADEON_IDLE_LOOP_MS));
+       }
        mutex_unlock(&rdev->pm.mutex);
        radeon_pm_compute_clocks(rdev);
 }
@@ -409,6 +477,7 @@ int radeon_pm_init(struct radeon_device *rdev)
                        radeon_atombios_get_power_modes(rdev);
                else
                        radeon_combios_get_power_modes(rdev);
+               radeon_pm_print_states(rdev);
                radeon_pm_init_profile(rdev);
        }
 
@@ -440,6 +509,8 @@ int radeon_pm_init(struct radeon_device *rdev)
 void radeon_pm_fini(struct radeon_device *rdev)
 {
        if (rdev->pm.num_power_states > 1) {
+               bool flush_wq = false;
+
                mutex_lock(&rdev->pm.mutex);
                if (rdev->pm.pm_method == PM_METHOD_PROFILE) {
                        rdev->pm.profile = PM_PROFILE_DEFAULT;
@@ -447,13 +518,16 @@ void radeon_pm_fini(struct radeon_device *rdev)
                        radeon_pm_set_clocks(rdev);
                } else if (rdev->pm.pm_method == PM_METHOD_DYNPM) {
                        /* cancel work */
-                       cancel_delayed_work_sync(&rdev->pm.dynpm_idle_work);
+                       cancel_delayed_work(&rdev->pm.dynpm_idle_work);
+                       flush_wq = true;
                        /* reset default clocks */
                        rdev->pm.dynpm_state = DYNPM_STATE_DISABLED;
                        rdev->pm.dynpm_planned_action = DYNPM_ACTION_DEFAULT;
                        radeon_pm_set_clocks(rdev);
                }
                mutex_unlock(&rdev->pm.mutex);
+               if (flush_wq)
+                       flush_workqueue(rdev->wq);
 
                device_remove_file(rdev->dev, &dev_attr_power_profile);
                device_remove_file(rdev->dev, &dev_attr_power_method);
@@ -674,12 +748,12 @@ static void radeon_dynpm_idle_work_handler(struct work_struct *work)
                        radeon_pm_get_dynpm_state(rdev);
                        radeon_pm_set_clocks(rdev);
                }
+
+               queue_delayed_work(rdev->wq, &rdev->pm.dynpm_idle_work,
+                                       msecs_to_jiffies(RADEON_IDLE_LOOP_MS));
        }
        mutex_unlock(&rdev->pm.mutex);
        ttm_bo_unlock_delayed_workqueue(&rdev->mman.bdev, resched);
-
-       queue_delayed_work(rdev->wq, &rdev->pm.dynpm_idle_work,
-                                       msecs_to_jiffies(RADEON_IDLE_LOOP_MS));
 }
 
 /*
@@ -698,6 +772,8 @@ static int radeon_debugfs_pm_info(struct seq_file *m, void *data)
        seq_printf(m, "default memory clock: %u0 kHz\n", rdev->clock.default_mclk);
        if (rdev->asic->get_memory_clock)
                seq_printf(m, "current memory clock: %u0 kHz\n", radeon_get_memory_clock(rdev));
+       if (rdev->pm.current_vddc)
+               seq_printf(m, "voltage: %u mV\n", rdev->pm.current_vddc);
        if (rdev->asic->get_pcie_lanes)
                seq_printf(m, "PCIE lanes: %d\n", radeon_get_pcie_lanes(rdev));