Merge remote branch 'intel/drm-intel-next' of /ssd/git/drm-next into drm-core-next
[sfrench/cifs-2.6.git] / drivers / gpu / drm / radeon / radeon_pm.c
index 115d26b762cc2b3db9301c86e66d97505f6fd291..95f8b3a3c43d993ee6eac9ea3a713b5aa35d3935 100644 (file)
@@ -27,6 +27,8 @@
 #include <linux/acpi.h>
 #endif
 #include <linux/power_supply.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
 
 #define RADEON_IDLE_LOOP_MS 100
 #define RADEON_RECLOCK_DELAY_MS 200
@@ -60,9 +62,9 @@ static int radeon_acpi_event(struct notifier_block *nb,
 
        if (strcmp(entry->device_class, ACPI_AC_CLASS) == 0) {
                if (power_supply_is_system_supplied() > 0)
-                       DRM_DEBUG("pm: AC\n");
+                       DRM_DEBUG_DRIVER("pm: AC\n");
                else
-                       DRM_DEBUG("pm: DC\n");
+                       DRM_DEBUG_DRIVER("pm: DC\n");
 
                if (rdev->pm.pm_method == PM_METHOD_PROFILE) {
                        if (rdev->pm.profile == PM_PROFILE_AUTO) {
@@ -196,7 +198,7 @@ static void radeon_set_power_state(struct radeon_device *rdev)
                        radeon_set_engine_clock(rdev, sclk);
                        radeon_pm_debug_check_in_vbl(rdev, true);
                        rdev->pm.current_sclk = sclk;
-                       DRM_DEBUG("Setting: e: %d\n", sclk);
+                       DRM_DEBUG_DRIVER("Setting: e: %d\n", sclk);
                }
 
                /* set memory clock */
@@ -205,7 +207,7 @@ static void radeon_set_power_state(struct radeon_device *rdev)
                        radeon_set_memory_clock(rdev, mclk);
                        radeon_pm_debug_check_in_vbl(rdev, true);
                        rdev->pm.current_mclk = mclk;
-                       DRM_DEBUG("Setting: m: %d\n", mclk);
+                       DRM_DEBUG_DRIVER("Setting: m: %d\n", mclk);
                }
 
                if (misc_after)
@@ -217,7 +219,7 @@ static void radeon_set_power_state(struct radeon_device *rdev)
                rdev->pm.current_power_state_index = rdev->pm.requested_power_state_index;
                rdev->pm.current_clock_mode_index = rdev->pm.requested_clock_mode_index;
        } else
-               DRM_DEBUG("pm: GUI not idle!!!\n");
+               DRM_DEBUG_DRIVER("pm: GUI not idle!!!\n");
 }
 
 static void radeon_pm_set_clocks(struct radeon_device *rdev)
@@ -292,27 +294,27 @@ static void radeon_pm_print_states(struct radeon_device *rdev)
        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);
+       DRM_DEBUG_DRIVER("%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,
+               DRM_DEBUG_DRIVER("State %d: %s\n", i,
                        radeon_pm_state_type_name[power_state->type]);
                if (i == rdev->pm.default_power_state_index)
-                       DRM_DEBUG("\tDefault");
+                       DRM_DEBUG_DRIVER("\tDefault");
                if ((rdev->flags & RADEON_IS_PCIE) && !(rdev->flags & RADEON_IS_IGP))
-                       DRM_DEBUG("\t%d PCIE Lanes\n", power_state->pcie_lanes);
+                       DRM_DEBUG_DRIVER("\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);
+                       DRM_DEBUG_DRIVER("\tSingle display only\n");
+               DRM_DEBUG_DRIVER("\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",
+                               DRM_DEBUG_DRIVER("\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",
+                               DRM_DEBUG_DRIVER("\t\t%d e: %d\tm: %d\tv: %d%s\n",
                                        j,
                                        clock_info->sclk * 10,
                                        clock_info->mclk * 10,
@@ -333,6 +335,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");
 }
 
@@ -423,6 +426,82 @@ fail:
 static DEVICE_ATTR(power_profile, S_IRUGO | S_IWUSR, radeon_get_pm_profile, radeon_set_pm_profile);
 static DEVICE_ATTR(power_method, S_IRUGO | S_IWUSR, radeon_get_pm_method, radeon_set_pm_method);
 
+static ssize_t radeon_hwmon_show_temp(struct device *dev,
+                                     struct device_attribute *attr,
+                                     char *buf)
+{
+       struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
+       struct radeon_device *rdev = ddev->dev_private;
+       u32 temp;
+
+       switch (rdev->pm.int_thermal_type) {
+       case THERMAL_TYPE_RV6XX:
+               temp = rv6xx_get_temp(rdev);
+               break;
+       case THERMAL_TYPE_RV770:
+               temp = rv770_get_temp(rdev);
+               break;
+       case THERMAL_TYPE_EVERGREEN:
+               temp = evergreen_get_temp(rdev);
+               break;
+       default:
+               temp = 0;
+               break;
+       }
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", temp);
+}
+
+static ssize_t radeon_hwmon_show_name(struct device *dev,
+                                     struct device_attribute *attr,
+                                     char *buf)
+{
+       return sprintf(buf, "radeon\n");
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, radeon_hwmon_show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(name, S_IRUGO, radeon_hwmon_show_name, NULL, 0);
+
+static struct attribute *hwmon_attributes[] = {
+       &sensor_dev_attr_temp1_input.dev_attr.attr,
+       &sensor_dev_attr_name.dev_attr.attr,
+       NULL
+};
+
+static const struct attribute_group hwmon_attrgroup = {
+       .attrs = hwmon_attributes,
+};
+
+static void radeon_hwmon_init(struct radeon_device *rdev)
+{
+       int err;
+
+       rdev->pm.int_hwmon_dev = NULL;
+
+       switch (rdev->pm.int_thermal_type) {
+       case THERMAL_TYPE_RV6XX:
+       case THERMAL_TYPE_RV770:
+       case THERMAL_TYPE_EVERGREEN:
+               rdev->pm.int_hwmon_dev = hwmon_device_register(rdev->dev);
+               dev_set_drvdata(rdev->pm.int_hwmon_dev, rdev->ddev);
+               err = sysfs_create_group(&rdev->pm.int_hwmon_dev->kobj,
+                                        &hwmon_attrgroup);
+               if (err)
+                       DRM_ERROR("Unable to create hwmon sysfs file: %d\n", err);
+               break;
+       default:
+               break;
+       }
+}
+
+static void radeon_hwmon_fini(struct radeon_device *rdev)
+{
+       if (rdev->pm.int_hwmon_dev) {
+               sysfs_remove_group(&rdev->pm.int_hwmon_dev->kobj, &hwmon_attrgroup);
+               hwmon_device_unregister(rdev->pm.int_hwmon_dev);
+       }
+}
+
 void radeon_pm_suspend(struct radeon_device *rdev)
 {
        bool flush_wq = false;
@@ -470,6 +549,7 @@ int radeon_pm_init(struct radeon_device *rdev)
        rdev->pm.dynpm_can_downclock = true;
        rdev->pm.current_sclk = rdev->clock.default_sclk;
        rdev->pm.current_mclk = rdev->clock.default_mclk;
+       rdev->pm.int_thermal_type = THERMAL_TYPE_NONE;
 
        if (rdev->bios) {
                if (rdev->is_atom_bios)
@@ -480,6 +560,8 @@ int radeon_pm_init(struct radeon_device *rdev)
                radeon_pm_init_profile(rdev);
        }
 
+       /* set up the internal thermal sensor if applicable */
+       radeon_hwmon_init(rdev);
        if (rdev->pm.num_power_states > 1) {
                /* where's the best place to put these? */
                ret = device_create_file(rdev->dev, &dev_attr_power_profile);
@@ -535,6 +617,7 @@ void radeon_pm_fini(struct radeon_device *rdev)
 #endif
        }
 
+       radeon_hwmon_fini(rdev);
        if (rdev->pm.i2c_bus)
                radeon_i2c_destroy(rdev->pm.i2c_bus);
 }
@@ -575,7 +658,7 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev)
                                        radeon_pm_get_dynpm_state(rdev);
                                        radeon_pm_set_clocks(rdev);
 
-                                       DRM_DEBUG("radeon: dynamic power management deactivated\n");
+                                       DRM_DEBUG_DRIVER("radeon: dynamic power management deactivated\n");
                                }
                        } else if (rdev->pm.active_crtc_count == 1) {
                                /* TODO: Increase clocks if needed for current mode */
@@ -592,7 +675,7 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev)
                                        rdev->pm.dynpm_state = DYNPM_STATE_ACTIVE;
                                        queue_delayed_work(rdev->wq, &rdev->pm.dynpm_idle_work,
                                                           msecs_to_jiffies(RADEON_IDLE_LOOP_MS));
-                                       DRM_DEBUG("radeon: dynamic power management activated\n");
+                                       DRM_DEBUG_DRIVER("radeon: dynamic power management activated\n");
                                }
                        } else { /* count == 0 */
                                if (rdev->pm.dynpm_state != DYNPM_STATE_MINIMUM) {
@@ -688,7 +771,7 @@ static bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish
        bool in_vbl = radeon_pm_in_vbl(rdev);
 
        if (in_vbl == false)
-               DRM_DEBUG("not in vbl for pm change %08x at %s\n", stat_crtc,
+               DRM_DEBUG_DRIVER("not in vbl for pm change %08x at %s\n", stat_crtc,
                         finish ? "exit" : "entry");
        return in_vbl;
 }