diff options
-rw-r--r-- | drivers/gpu/drm/Kconfig | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/evergreen.c | 17 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/evergreend.h | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/r600.c | 15 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/r600d.h | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon.h | 13 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_atombios.c | 16 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_pm.c | 82 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/rv770.c | 15 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/rv770d.h | 5 |
10 files changed, 170 insertions, 4 deletions
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 5b7a1a4692a0..4cab0c6397e3 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig | |||
@@ -61,6 +61,7 @@ config DRM_RADEON | |||
61 | select DRM_KMS_HELPER | 61 | select DRM_KMS_HELPER |
62 | select DRM_TTM | 62 | select DRM_TTM |
63 | select POWER_SUPPLY | 63 | select POWER_SUPPLY |
64 | select HWMON | ||
64 | help | 65 | help |
65 | Choose this option if you have an ATI Radeon graphics card. There | 66 | Choose this option if you have an ATI Radeon graphics card. There |
66 | are both PCI and AGP versions. You don't need to choose this to | 67 | are both PCI and AGP versions. You don't need to choose this to |
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 057192acdd36..1b7da39cc587 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c | |||
@@ -39,6 +39,23 @@ | |||
39 | static void evergreen_gpu_init(struct radeon_device *rdev); | 39 | static void evergreen_gpu_init(struct radeon_device *rdev); |
40 | void evergreen_fini(struct radeon_device *rdev); | 40 | void evergreen_fini(struct radeon_device *rdev); |
41 | 41 | ||
42 | /* get temperature in millidegrees */ | ||
43 | u32 evergreen_get_temp(struct radeon_device *rdev) | ||
44 | { | ||
45 | u32 temp = (RREG32(CG_MULT_THERMAL_STATUS) & ASIC_T_MASK) >> | ||
46 | ASIC_T_SHIFT; | ||
47 | u32 actual_temp = 0; | ||
48 | |||
49 | if ((temp >> 10) & 1) | ||
50 | actual_temp = 0; | ||
51 | else if ((temp >> 9) & 1) | ||
52 | actual_temp = 255; | ||
53 | else | ||
54 | actual_temp = (temp >> 1) & 0xff; | ||
55 | |||
56 | return actual_temp * 1000; | ||
57 | } | ||
58 | |||
42 | void evergreen_pm_misc(struct radeon_device *rdev) | 59 | void evergreen_pm_misc(struct radeon_device *rdev) |
43 | { | 60 | { |
44 | int req_ps_idx = rdev->pm.requested_power_state_index; | 61 | int req_ps_idx = rdev->pm.requested_power_state_index; |
diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h index a1cd621780e2..9b7532dd30f7 100644 --- a/drivers/gpu/drm/radeon/evergreend.h +++ b/drivers/gpu/drm/radeon/evergreend.h | |||
@@ -165,6 +165,11 @@ | |||
165 | #define SE_DB_BUSY (1 << 30) | 165 | #define SE_DB_BUSY (1 << 30) |
166 | #define SE_CB_BUSY (1 << 31) | 166 | #define SE_CB_BUSY (1 << 31) |
167 | 167 | ||
168 | #define CG_MULT_THERMAL_STATUS 0x740 | ||
169 | #define ASIC_T(x) ((x) << 16) | ||
170 | #define ASIC_T_MASK 0x7FF0000 | ||
171 | #define ASIC_T_SHIFT 16 | ||
172 | |||
168 | #define HDP_HOST_PATH_CNTL 0x2C00 | 173 | #define HDP_HOST_PATH_CNTL 0x2C00 |
169 | #define HDP_NONSURFACE_BASE 0x2C04 | 174 | #define HDP_NONSURFACE_BASE 0x2C04 |
170 | #define HDP_NONSURFACE_INFO 0x2C08 | 175 | #define HDP_NONSURFACE_INFO 0x2C08 |
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index a73a6e17588d..15fe6c214034 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c | |||
@@ -92,6 +92,21 @@ void r600_gpu_init(struct radeon_device *rdev); | |||
92 | void r600_fini(struct radeon_device *rdev); | 92 | void r600_fini(struct radeon_device *rdev); |
93 | void r600_irq_disable(struct radeon_device *rdev); | 93 | void r600_irq_disable(struct radeon_device *rdev); |
94 | 94 | ||
95 | /* get temperature in millidegrees */ | ||
96 | u32 rv6xx_get_temp(struct radeon_device *rdev) | ||
97 | { | ||
98 | u32 temp = (RREG32(CG_THERMAL_STATUS) & ASIC_T_MASK) >> | ||
99 | ASIC_T_SHIFT; | ||
100 | u32 actual_temp = 0; | ||
101 | |||
102 | if ((temp >> 7) & 1) | ||
103 | actual_temp = 0; | ||
104 | else | ||
105 | actual_temp = (temp >> 1) & 0xff; | ||
106 | |||
107 | return actual_temp * 1000; | ||
108 | } | ||
109 | |||
95 | void r600_pm_get_dynpm_state(struct radeon_device *rdev) | 110 | void r600_pm_get_dynpm_state(struct radeon_device *rdev) |
96 | { | 111 | { |
97 | int i; | 112 | int i; |
diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h index 59c1f8793e60..23205f032872 100644 --- a/drivers/gpu/drm/radeon/r600d.h +++ b/drivers/gpu/drm/radeon/r600d.h | |||
@@ -239,6 +239,11 @@ | |||
239 | #define GRBM_SOFT_RESET 0x8020 | 239 | #define GRBM_SOFT_RESET 0x8020 |
240 | #define SOFT_RESET_CP (1<<0) | 240 | #define SOFT_RESET_CP (1<<0) |
241 | 241 | ||
242 | #define CG_THERMAL_STATUS 0x7F4 | ||
243 | #define ASIC_T(x) ((x) << 0) | ||
244 | #define ASIC_T_MASK 0x1FF | ||
245 | #define ASIC_T_SHIFT 0 | ||
246 | |||
242 | #define HDP_HOST_PATH_CNTL 0x2C00 | 247 | #define HDP_HOST_PATH_CNTL 0x2C00 |
243 | #define HDP_NONSURFACE_BASE 0x2C04 | 248 | #define HDP_NONSURFACE_BASE 0x2C04 |
244 | #define HDP_NONSURFACE_INFO 0x2C08 | 249 | #define HDP_NONSURFACE_INFO 0x2C08 |
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index a5c1a3e9dd39..d4d776d2f1e0 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h | |||
@@ -178,6 +178,9 @@ void radeon_combios_get_power_modes(struct radeon_device *rdev); | |||
178 | void radeon_atombios_get_power_modes(struct radeon_device *rdev); | 178 | void radeon_atombios_get_power_modes(struct radeon_device *rdev); |
179 | void radeon_atom_set_voltage(struct radeon_device *rdev, u16 level); | 179 | void radeon_atom_set_voltage(struct radeon_device *rdev, u16 level); |
180 | void rs690_pm_info(struct radeon_device *rdev); | 180 | void rs690_pm_info(struct radeon_device *rdev); |
181 | extern u32 rv6xx_get_temp(struct radeon_device *rdev); | ||
182 | extern u32 rv770_get_temp(struct radeon_device *rdev); | ||
183 | extern u32 evergreen_get_temp(struct radeon_device *rdev); | ||
181 | 184 | ||
182 | /* | 185 | /* |
183 | * Fences. | 186 | * Fences. |
@@ -670,6 +673,13 @@ struct radeon_pm_profile { | |||
670 | int dpms_on_cm_idx; | 673 | int dpms_on_cm_idx; |
671 | }; | 674 | }; |
672 | 675 | ||
676 | enum radeon_int_thermal_type { | ||
677 | THERMAL_TYPE_NONE, | ||
678 | THERMAL_TYPE_RV6XX, | ||
679 | THERMAL_TYPE_RV770, | ||
680 | THERMAL_TYPE_EVERGREEN, | ||
681 | }; | ||
682 | |||
673 | struct radeon_voltage { | 683 | struct radeon_voltage { |
674 | enum radeon_voltage_type type; | 684 | enum radeon_voltage_type type; |
675 | /* gpio voltage */ | 685 | /* gpio voltage */ |
@@ -765,6 +775,9 @@ struct radeon_pm { | |||
765 | enum radeon_pm_profile_type profile; | 775 | enum radeon_pm_profile_type profile; |
766 | int profile_index; | 776 | int profile_index; |
767 | struct radeon_pm_profile profiles[PM_PROFILE_MAX]; | 777 | struct radeon_pm_profile profiles[PM_PROFILE_MAX]; |
778 | /* internal thermal controller on rv6xx+ */ | ||
779 | enum radeon_int_thermal_type int_thermal_type; | ||
780 | struct device *int_hwmon_dev; | ||
768 | }; | 781 | }; |
769 | 782 | ||
770 | 783 | ||
diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 99bd8a9c56b3..5dd86b95b992 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c | |||
@@ -1773,14 +1773,22 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) | |||
1773 | } | 1773 | } |
1774 | 1774 | ||
1775 | /* add the i2c bus for thermal/fan chip */ | 1775 | /* add the i2c bus for thermal/fan chip */ |
1776 | /* no support for internal controller yet */ | ||
1777 | if (controller->ucType > 0) { | 1776 | if (controller->ucType > 0) { |
1778 | if ((controller->ucType == ATOM_PP_THERMALCONTROLLER_RV6xx) || | 1777 | if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV6xx) { |
1779 | (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV770) || | ||
1780 | (controller->ucType == ATOM_PP_THERMALCONTROLLER_EVERGREEN)) { | ||
1781 | DRM_INFO("Internal thermal controller %s fan control\n", | 1778 | DRM_INFO("Internal thermal controller %s fan control\n", |
1782 | (controller->ucFanParameters & | 1779 | (controller->ucFanParameters & |
1783 | ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); | 1780 | ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); |
1781 | rdev->pm.int_thermal_type = THERMAL_TYPE_RV6XX; | ||
1782 | } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV770) { | ||
1783 | DRM_INFO("Internal thermal controller %s fan control\n", | ||
1784 | (controller->ucFanParameters & | ||
1785 | ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); | ||
1786 | rdev->pm.int_thermal_type = THERMAL_TYPE_RV770; | ||
1787 | } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_EVERGREEN) { | ||
1788 | DRM_INFO("Internal thermal controller %s fan control\n", | ||
1789 | (controller->ucFanParameters & | ||
1790 | ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); | ||
1791 | rdev->pm.int_thermal_type = THERMAL_TYPE_EVERGREEN; | ||
1784 | } else if ((controller->ucType == | 1792 | } else if ((controller->ucType == |
1785 | ATOM_PP_THERMALCONTROLLER_EXTERNAL_GPIO) || | 1793 | ATOM_PP_THERMALCONTROLLER_EXTERNAL_GPIO) || |
1786 | (controller->ucType == | 1794 | (controller->ucType == |
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: | |||
423 | static DEVICE_ATTR(power_profile, S_IRUGO | S_IWUSR, radeon_get_pm_profile, radeon_set_pm_profile); | 425 | static DEVICE_ATTR(power_profile, S_IRUGO | S_IWUSR, radeon_get_pm_profile, radeon_set_pm_profile); |
424 | static DEVICE_ATTR(power_method, S_IRUGO | S_IWUSR, radeon_get_pm_method, radeon_set_pm_method); | 426 | static DEVICE_ATTR(power_method, S_IRUGO | S_IWUSR, radeon_get_pm_method, radeon_set_pm_method); |
425 | 427 | ||
428 | static 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 | |||
454 | static 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 | |||
461 | static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, radeon_hwmon_show_temp, NULL, 0); | ||
462 | static SENSOR_DEVICE_ATTR(name, S_IRUGO, radeon_hwmon_show_name, NULL, 0); | ||
463 | |||
464 | static 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 | |||
470 | static const struct attribute_group hwmon_attrgroup = { | ||
471 | .attrs = hwmon_attributes, | ||
472 | }; | ||
473 | |||
474 | static 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 | |||
496 | static 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 | |||
426 | void radeon_pm_suspend(struct radeon_device *rdev) | 504 | void 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 | } |
diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 6a7bf1091971..836c15ab84d1 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c | |||
@@ -42,6 +42,21 @@ | |||
42 | static void rv770_gpu_init(struct radeon_device *rdev); | 42 | static void rv770_gpu_init(struct radeon_device *rdev); |
43 | void rv770_fini(struct radeon_device *rdev); | 43 | void rv770_fini(struct radeon_device *rdev); |
44 | 44 | ||
45 | /* get temperature in millidegrees */ | ||
46 | u32 rv770_get_temp(struct radeon_device *rdev) | ||
47 | { | ||
48 | u32 temp = (RREG32(CG_MULT_THERMAL_STATUS) & ASIC_T_MASK) >> | ||
49 | ASIC_T_SHIFT; | ||
50 | u32 actual_temp = 0; | ||
51 | |||
52 | if ((temp >> 9) & 1) | ||
53 | actual_temp = 0; | ||
54 | else | ||
55 | actual_temp = (temp >> 1) & 0xff; | ||
56 | |||
57 | return actual_temp * 1000; | ||
58 | } | ||
59 | |||
45 | void rv770_pm_misc(struct radeon_device *rdev) | 60 | void rv770_pm_misc(struct radeon_device *rdev) |
46 | { | 61 | { |
47 | int req_ps_idx = rdev->pm.requested_power_state_index; | 62 | int req_ps_idx = rdev->pm.requested_power_state_index; |
diff --git a/drivers/gpu/drm/radeon/rv770d.h b/drivers/gpu/drm/radeon/rv770d.h index 9506f8cb99e0..fd733f268e3d 100644 --- a/drivers/gpu/drm/radeon/rv770d.h +++ b/drivers/gpu/drm/radeon/rv770d.h | |||
@@ -122,6 +122,11 @@ | |||
122 | #define GUI_ACTIVE (1<<31) | 122 | #define GUI_ACTIVE (1<<31) |
123 | #define GRBM_STATUS2 0x8014 | 123 | #define GRBM_STATUS2 0x8014 |
124 | 124 | ||
125 | #define CG_MULT_THERMAL_STATUS 0x740 | ||
126 | #define ASIC_T(x) ((x) << 16) | ||
127 | #define ASIC_T_MASK 0x3FF0000 | ||
128 | #define ASIC_T_SHIFT 16 | ||
129 | |||
125 | #define HDP_HOST_PATH_CNTL 0x2C00 | 130 | #define HDP_HOST_PATH_CNTL 0x2C00 |
126 | #define HDP_NONSURFACE_BASE 0x2C04 | 131 | #define HDP_NONSURFACE_BASE 0x2C04 |
127 | #define HDP_NONSURFACE_INFO 0x2C08 | 132 | #define HDP_NONSURFACE_INFO 0x2C08 |