aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/radeon/radeon_pm.c
diff options
context:
space:
mode:
authorAlex Deucher <alexdeucher@gmail.com>2010-07-02 12:58:16 -0400
committerDave Airlie <airlied@redhat.com>2010-08-01 20:00:00 -0400
commit21a8122ad38c60d73fe5dc51051414c3564d174a (patch)
treeb20f2bb711e3230fdc3195042c901596de4677e2 /drivers/gpu/drm/radeon/radeon_pm.c
parentd7a2952f1adec32018a78ec0c2f504dd72f38e25 (diff)
drm/radeon/kms: add support for internal thermal sensors (v3)
rv6xx/rv7xx/evergreen families supported; older asics did not have an internal thermal sensor. Note, not all oems use the internal thermal sensor, so it's only exposed in cases where it is used. Note also, that most laptops use an oem specific ACPI solution for GPU thermal information rather than using the internal thermal sensor directly. v2: export millidegrees celsius, use hwmon device properly. v3: fix Kconfig Signed-off-by: Alex Deucher <alexdeucher@gmail.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/radeon/radeon_pm.c')
-rw-r--r--drivers/gpu/drm/radeon/radeon_pm.c82
1 files changed, 82 insertions, 0 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
index 115d26b762cc..ed66062ae9d0 100644
--- a/drivers/gpu/drm/radeon/radeon_pm.c
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
@@ -27,6 +27,8 @@
27#include <linux/acpi.h> 27#include <linux/acpi.h>
28#endif 28#endif
29#include <linux/power_supply.h> 29#include <linux/power_supply.h>
30#include <linux/hwmon.h>
31#include <linux/hwmon-sysfs.h>
30 32
31#define RADEON_IDLE_LOOP_MS 100 33#define RADEON_IDLE_LOOP_MS 100
32#define RADEON_RECLOCK_DELAY_MS 200 34#define RADEON_RECLOCK_DELAY_MS 200
@@ -423,6 +425,82 @@ fail:
423static DEVICE_ATTR(power_profile, S_IRUGO | S_IWUSR, radeon_get_pm_profile, radeon_set_pm_profile); 425static DEVICE_ATTR(power_profile, S_IRUGO | S_IWUSR, radeon_get_pm_profile, radeon_set_pm_profile);
424static DEVICE_ATTR(power_method, S_IRUGO | S_IWUSR, radeon_get_pm_method, radeon_set_pm_method); 426static DEVICE_ATTR(power_method, S_IRUGO | S_IWUSR, radeon_get_pm_method, radeon_set_pm_method);
425 427
428static ssize_t radeon_hwmon_show_temp(struct device *dev,
429 struct device_attribute *attr,
430 char *buf)
431{
432 struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
433 struct radeon_device *rdev = ddev->dev_private;
434 u32 temp;
435
436 switch (rdev->pm.int_thermal_type) {
437 case THERMAL_TYPE_RV6XX:
438 temp = rv6xx_get_temp(rdev);
439 break;
440 case THERMAL_TYPE_RV770:
441 temp = rv770_get_temp(rdev);
442 break;
443 case THERMAL_TYPE_EVERGREEN:
444 temp = evergreen_get_temp(rdev);
445 break;
446 default:
447 temp = 0;
448 break;
449 }
450
451 return snprintf(buf, PAGE_SIZE, "%d\n", temp);
452}
453
454static ssize_t radeon_hwmon_show_name(struct device *dev,
455 struct device_attribute *attr,
456 char *buf)
457{
458 return sprintf(buf, "radeon\n");
459}
460
461static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, radeon_hwmon_show_temp, NULL, 0);
462static SENSOR_DEVICE_ATTR(name, S_IRUGO, radeon_hwmon_show_name, NULL, 0);
463
464static struct attribute *hwmon_attributes[] = {
465 &sensor_dev_attr_temp1_input.dev_attr.attr,
466 &sensor_dev_attr_name.dev_attr.attr,
467 NULL
468};
469
470static const struct attribute_group hwmon_attrgroup = {
471 .attrs = hwmon_attributes,
472};
473
474static void radeon_hwmon_init(struct radeon_device *rdev)
475{
476 int err;
477
478 rdev->pm.int_hwmon_dev = NULL;
479
480 switch (rdev->pm.int_thermal_type) {
481 case THERMAL_TYPE_RV6XX:
482 case THERMAL_TYPE_RV770:
483 case THERMAL_TYPE_EVERGREEN:
484 rdev->pm.int_hwmon_dev = hwmon_device_register(rdev->dev);
485 dev_set_drvdata(rdev->pm.int_hwmon_dev, rdev->ddev);
486 err = sysfs_create_group(&rdev->pm.int_hwmon_dev->kobj,
487 &hwmon_attrgroup);
488 if (err)
489 DRM_ERROR("Unable to create hwmon sysfs file: %d\n", err);
490 break;
491 default:
492 break;
493 }
494}
495
496static void radeon_hwmon_fini(struct radeon_device *rdev)
497{
498 if (rdev->pm.int_hwmon_dev) {
499 sysfs_remove_group(&rdev->pm.int_hwmon_dev->kobj, &hwmon_attrgroup);
500 hwmon_device_unregister(rdev->pm.int_hwmon_dev);
501 }
502}
503
426void radeon_pm_suspend(struct radeon_device *rdev) 504void radeon_pm_suspend(struct radeon_device *rdev)
427{ 505{
428 bool flush_wq = false; 506 bool flush_wq = false;
@@ -470,6 +548,7 @@ int radeon_pm_init(struct radeon_device *rdev)
470 rdev->pm.dynpm_can_downclock = true; 548 rdev->pm.dynpm_can_downclock = true;
471 rdev->pm.current_sclk = rdev->clock.default_sclk; 549 rdev->pm.current_sclk = rdev->clock.default_sclk;
472 rdev->pm.current_mclk = rdev->clock.default_mclk; 550 rdev->pm.current_mclk = rdev->clock.default_mclk;
551 rdev->pm.int_thermal_type = THERMAL_TYPE_NONE;
473 552
474 if (rdev->bios) { 553 if (rdev->bios) {
475 if (rdev->is_atom_bios) 554 if (rdev->is_atom_bios)
@@ -480,6 +559,8 @@ int radeon_pm_init(struct radeon_device *rdev)
480 radeon_pm_init_profile(rdev); 559 radeon_pm_init_profile(rdev);
481 } 560 }
482 561
562 /* set up the internal thermal sensor if applicable */
563 radeon_hwmon_init(rdev);
483 if (rdev->pm.num_power_states > 1) { 564 if (rdev->pm.num_power_states > 1) {
484 /* where's the best place to put these? */ 565 /* where's the best place to put these? */
485 ret = device_create_file(rdev->dev, &dev_attr_power_profile); 566 ret = device_create_file(rdev->dev, &dev_attr_power_profile);
@@ -535,6 +616,7 @@ void radeon_pm_fini(struct radeon_device *rdev)
535#endif 616#endif
536 } 617 }
537 618
619 radeon_hwmon_fini(rdev);
538 if (rdev->pm.i2c_bus) 620 if (rdev->pm.i2c_bus)
539 radeon_i2c_destroy(rdev->pm.i2c_bus); 621 radeon_i2c_destroy(rdev->pm.i2c_bus);
540} 622}