Fwd: [PATCH] drm/radeon/kms: add support for internal thermal sensors (v3)

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Just passing this along to this list as I know a few people on this
list were waiting for the on-die sensor to be supported. A form of
this patch has been accepted into the mainline for release with
2.6.35. Any questions should be aimed at the dri-devel mailing list.


---------- Forwarded message ----------
From: Alex Deucher <alexdeucher@xxxxxxxxx>
Date: Wed, Jun 2, 2010 at 11:59 AM
Subject: [PATCH] drm/radeon/kms: add support for internal thermal sensors (v3)
To: airlied@xxxxxxxxx, dri-devel@xxxxxxxxxxxxxxxxxxxxx


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@xxxxxxxxx>
---
 drivers/gpu/drm/Kconfig                  |    1 +
 drivers/gpu/drm/radeon/evergreen.c       |   17 ++++++
 drivers/gpu/drm/radeon/evergreend.h      |    5 ++
 drivers/gpu/drm/radeon/r600.c            |   15 ++++++
 drivers/gpu/drm/radeon/r600d.h           |    5 ++
 drivers/gpu/drm/radeon/radeon.h          |   13 +++++
 drivers/gpu/drm/radeon/radeon_atombios.c |   16 ++++--
 drivers/gpu/drm/radeon/radeon_pm.c       |   82 ++++++++++++++++++++++++++++++
 drivers/gpu/drm/radeon/rv770.c           |   15 ++++++
 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 88910e5..b0a1816 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -61,6 +61,7 @@ config DRM_RADEON
        select DRM_KMS_HELPER
        select DRM_TTM
   select POWER_SUPPLY
+   select HWMON
   help
     Choose this option if you have an ATI Radeon graphics card.  There
     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 69c4b27..0dbf490 100644
--- a/drivers/gpu/drm/radeon/evergreen.c
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -39,6 +39,23 @@
 static void evergreen_gpu_init(struct radeon_device *rdev);
 void evergreen_fini(struct radeon_device *rdev);

+/* get temperature in millidegrees */
+u32 evergreen_get_temp(struct radeon_device *rdev)
+{
+   u32 temp = (RREG32(CG_MULT_THERMAL_STATUS) & ASIC_T_MASK) >>
+       ASIC_T_SHIFT;
+   u32 actual_temp = 0;
+
+   if ((temp >> 10) & 1)
+       actual_temp = 0;
+   else if ((temp >> 9) & 1)
+       actual_temp = 255;
+   else
+       actual_temp = (temp >> 1) & 0xff;
+
+   return actual_temp * 1000;
+}
+
 void evergreen_pm_misc(struct radeon_device *rdev)
 {
   int requested_index = rdev->pm.requested_power_state_index;
diff --git a/drivers/gpu/drm/radeon/evergreend.h
b/drivers/gpu/drm/radeon/evergreend.h
index 79683f6..50c5e97 100644
--- a/drivers/gpu/drm/radeon/evergreend.h
+++ b/drivers/gpu/drm/radeon/evergreend.h
@@ -165,6 +165,11 @@
 #define        SE_DB_BUSY                  (1 << 30)
 #define        SE_CB_BUSY                  (1 << 31)

+#define    CG_MULT_THERMAL_STATUS              0x740
+#define        ASIC_T(x)                   ((x) << 16)
+#define        ASIC_T_MASK                 0x7FF0000
+#define        ASIC_T_SHIFT                    16
+
 #define    HDP_HOST_PATH_CNTL              0x2C00
 #define    HDP_NONSURFACE_BASE             0x2C04
 #define    HDP_NONSURFACE_INFO             0x2C08
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index d84d7cf..dc2a3e8 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);
 void r600_fini(struct radeon_device *rdev);
 void r600_irq_disable(struct radeon_device *rdev);

+/* get temperature in millidegrees */
+u32 rv6xx_get_temp(struct radeon_device *rdev)
+{
+   u32 temp = (RREG32(CG_THERMAL_STATUS) & ASIC_T_MASK) >>
+       ASIC_T_SHIFT;
+   u32 actual_temp = 0;
+
+   if ((temp >> 7) & 1)
+       actual_temp = 0;
+   else
+       actual_temp = (temp >> 1) & 0xff;
+
+   return actual_temp * 1000;
+}
+
 void r600_pm_get_dynpm_state(struct radeon_device *rdev)
 {
   int i;
diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h
index 0a354b5..b7318ac 100644
--- a/drivers/gpu/drm/radeon/r600d.h
+++ b/drivers/gpu/drm/radeon/r600d.h
@@ -239,6 +239,11 @@
 #define    GRBM_SOFT_RESET                 0x8020
 #define        SOFT_RESET_CP                   (1<<0)

+#define    CG_THERMAL_STATUS               0x7F4
+#define        ASIC_T(x)                   ((x) << 0)
+#define        ASIC_T_MASK                 0x1FF
+#define        ASIC_T_SHIFT                    0
+
 #define    HDP_HOST_PATH_CNTL              0x2C00
 #define    HDP_NONSURFACE_BASE             0x2C04
 #define    HDP_NONSURFACE_INFO             0x2C08
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 084221d..487798e 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -177,6 +177,9 @@ void radeon_pm_resume(struct radeon_device *rdev);
 void radeon_combios_get_power_modes(struct radeon_device *rdev);
 void radeon_atombios_get_power_modes(struct radeon_device *rdev);
 void radeon_atom_set_voltage(struct radeon_device *rdev, u16 level);
+extern u32 rv6xx_get_temp(struct radeon_device *rdev);
+extern u32 rv770_get_temp(struct radeon_device *rdev);
+extern u32 evergreen_get_temp(struct radeon_device *rdev);

 /*
 * Fences.
@@ -665,6 +668,13 @@ struct radeon_pm_profile {
   int dpms_on_cm_idx;
 };

+enum radeon_int_thermal_type {
+   THERMAL_TYPE_NONE,
+   THERMAL_TYPE_RV6XX,
+   THERMAL_TYPE_RV770,
+   THERMAL_TYPE_EVERGREEN,
+};
+
 struct radeon_voltage {
   enum radeon_voltage_type type;
   /* gpio voltage */
@@ -759,6 +769,9 @@ struct radeon_pm {
   enum radeon_pm_profile_type profile;
   int                     profile_index;
   struct radeon_pm_profile profiles[PM_PROFILE_MAX];
+   /* internal thermal controller on rv6xx+ */
+   enum radeon_int_thermal_type int_thermal_type;
+   struct device           *int_hwmon_dev;
 };


diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c
b/drivers/gpu/drm/radeon/radeon_atombios.c
index 4305cd5..821c319 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)
           }

           /* add the i2c bus for thermal/fan chip */
-           /* no support for internal controller yet */
           if (controller->ucType > 0) {
-               if ((controller->ucType == ATOM_PP_THERMALCONTROLLER_RV6xx) ||
-                   (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV770) ||
-                   (controller->ucType ==
ATOM_PP_THERMALCONTROLLER_EVERGREEN)) {
+               if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV6xx) {
                   DRM_INFO("Internal thermal controller %s fan control\n",
                        (controller->ucFanParameters &
                         ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
+                   rdev->pm.int_thermal_type = THERMAL_TYPE_RV6XX;
+               } else if (controller->ucType ==
ATOM_PP_THERMALCONTROLLER_RV770) {
+                   DRM_INFO("Internal thermal controller %s fan control\n",
+                        (controller->ucFanParameters &
+                         ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
+                   rdev->pm.int_thermal_type = THERMAL_TYPE_RV770;
+               } else if (controller->ucType ==
ATOM_PP_THERMALCONTROLLER_EVERGREEN) {
+                   DRM_INFO("Internal thermal controller %s fan control\n",
+                        (controller->ucFanParameters &
+                         ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
+                   rdev->pm.int_thermal_type = THERMAL_TYPE_EVERGREEN;
               } else if ((controller->ucType ==
                       ATOM_PP_THERMALCONTROLLER_EXTERNAL_GPIO) ||
                      (controller->ucType ==
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c
b/drivers/gpu/drm/radeon/radeon_pm.c
index 0228126..3f9fd92 100644
--- a/drivers/gpu/drm/radeon/radeon_pm.c
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
@@ -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
@@ -373,6 +375,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)
 {
   mutex_lock(&rdev->pm.mutex);
@@ -400,6 +478,7 @@ int radeon_pm_init(struct radeon_device *rdev)
   rdev->pm.dynpm_can_downclock = true;
   rdev->pm.current_sclk = 0;
   rdev->pm.current_mclk = 0;
+   rdev->pm.int_thermal_type = THERMAL_TYPE_NONE;

   if (rdev->bios) {
       if (rdev->is_atom_bios)
@@ -411,6 +490,8 @@ int radeon_pm_init(struct radeon_device *rdev)
       rdev->pm.current_clock_mode_index = -1;
   }

+   /* set up the internal thermal sensor if applicable */
+   radeon_hwmon_init(rdev);
   if (rdev->pm.num_power_states > 1) {
       if (rdev->pm.pm_method == PM_METHOD_PROFILE) {
           mutex_lock(&rdev->pm.mutex);
@@ -469,6 +550,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);
 }
diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c
index 5f76938..6bae486 100644
--- a/drivers/gpu/drm/radeon/rv770.c
+++ b/drivers/gpu/drm/radeon/rv770.c
@@ -42,6 +42,21 @@
 static void rv770_gpu_init(struct radeon_device *rdev);
 void rv770_fini(struct radeon_device *rdev);

+/* get temperature in millidegrees */
+u32 rv770_get_temp(struct radeon_device *rdev)
+{
+   u32 temp = (RREG32(CG_MULT_THERMAL_STATUS) & ASIC_T_MASK) >>
+       ASIC_T_SHIFT;
+   u32 actual_temp = 0;
+
+   if ((temp >> 9) & 1)
+       actual_temp = 0;
+   else
+       actual_temp = (temp >> 1) & 0xff;
+
+   return actual_temp * 1000;
+}
+
 void rv770_pm_misc(struct radeon_device *rdev)
 {
   int requested_index = rdev->pm.requested_power_state_index;
diff --git a/drivers/gpu/drm/radeon/rv770d.h b/drivers/gpu/drm/radeon/rv770d.h
index 9506f8c..fd733f2 100644
--- a/drivers/gpu/drm/radeon/rv770d.h
+++ b/drivers/gpu/drm/radeon/rv770d.h
@@ -122,6 +122,11 @@
 #define        GUI_ACTIVE                  (1<<31)
 #define    GRBM_STATUS2                    0x8014

+#define    CG_MULT_THERMAL_STATUS              0x740
+#define        ASIC_T(x)                   ((x) << 16)
+#define        ASIC_T_MASK                 0x3FF0000
+#define        ASIC_T_SHIFT                    16
+
 #define    HDP_HOST_PATH_CNTL              0x2C00
 #define    HDP_NONSURFACE_BASE             0x2C04
 #define    HDP_NONSURFACE_INFO             0x2C08
--
1.7.0.1

_______________________________________________
dri-devel mailing list
dri-devel@xxxxxxxxxxxxxxxxxxxxx
http://lists.freedesktop.org/mailman/listinfo/dri-devel

_______________________________________________
lm-sensors mailing list
lm-sensors@xxxxxxxxxxxxxx
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors



[Index of Archives]     [Linux Kernel]     [Linux Hardware Monitoring]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux