* [PATCH] drm/radeon/kms: add support for internal thermal sensors
@ 2010-06-01 20:31 Alex Deucher
2010-06-01 20:42 ` Matthew Garrett
0 siblings, 1 reply; 9+ messages in thread
From: Alex Deucher @ 2010-06-01 20:31 UTC (permalink / raw)
To: airlied, dri-devel; +Cc: mjg59
rv6xx/rv7xx/evergreen families supported; older asics did
not have an internal thermal sensor. Exposed via sysfs
gpu_temp attribute.
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.
Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
---
drivers/gpu/drm/radeon/Kconfig | 1 +
drivers/gpu/drm/radeon/evergreen.c | 73 ++++++++++++++++++++++++++++++
drivers/gpu/drm/radeon/evergreend.h | 5 ++
drivers/gpu/drm/radeon/r600.c | 71 +++++++++++++++++++++++++++++
drivers/gpu/drm/radeon/r600d.h | 5 ++
drivers/gpu/drm/radeon/radeon.h | 16 +++++++
drivers/gpu/drm/radeon/radeon_atombios.c | 18 ++++++-
drivers/gpu/drm/radeon/radeon_pm.c | 19 ++++++++
drivers/gpu/drm/radeon/rv770.c | 71 +++++++++++++++++++++++++++++
drivers/gpu/drm/radeon/rv770d.h | 5 ++
10 files changed, 281 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/radeon/Kconfig b/drivers/gpu/drm/radeon/Kconfig
index 80c5b3e..2e3896d 100644
--- a/drivers/gpu/drm/radeon/Kconfig
+++ b/drivers/gpu/drm/radeon/Kconfig
@@ -2,6 +2,7 @@ config DRM_RADEON_KMS
bool "Enable modesetting on radeon by default - NEW DRIVER"
depends on DRM_RADEON
depends on POWER_SUPPLY
+ depends on HWMON
help
Choose this option if you want kernel modesetting enabled by default.
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
index 69c4b27..5d5a7b1 100644
--- a/drivers/gpu/drm/radeon/evergreen.c
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -24,6 +24,8 @@
#include <linux/firmware.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
#include "drmP.h"
#include "radeon.h"
#include "radeon_asic.h"
@@ -39,6 +41,77 @@
static void evergreen_gpu_init(struct radeon_device *rdev);
void evergreen_fini(struct radeon_device *rdev);
+static ssize_t evergreen_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 = (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 snprintf(buf, PAGE_SIZE, "%d\n", actual_temp);
+}
+
+static SENSOR_DEVICE_ATTR(gpu_temp, S_IRUGO, evergreen_hwmon_show_temp, NULL, 0);
+
+static struct attribute *evergreen_hwmon_attributes[2] = {
+ &sensor_dev_attr_gpu_temp.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group evergreen_hwmon_attrgroup = {
+ .attrs = evergreen_hwmon_attributes,
+};
+
+int evergreen_hwmon_init(struct radeon_device *rdev)
+{
+ struct device *int_hwmon_dev;
+ int ret;
+
+ rdev->pm.int_hwmon_dev = NULL;
+
+ int_hwmon_dev = kzalloc(sizeof(struct device), GFP_KERNEL);
+ if (!int_hwmon_dev) {
+ dev_err(rdev->dev, "no memory\n");
+ return -ENOMEM;
+ }
+
+ /* where's the best place to put this? */
+ sysfs_create_group(&rdev->dev->kobj, &evergreen_hwmon_attrgroup);
+
+ int_hwmon_dev = hwmon_device_register(rdev->dev);
+ if (IS_ERR(int_hwmon_dev)) {
+ dev_err(rdev->dev, "error registering with hwmon\n");
+ ret = PTR_ERR(int_hwmon_dev);
+ sysfs_remove_group(&rdev->dev->kobj, &evergreen_hwmon_attrgroup);
+ kfree(int_hwmon_dev);
+ return ret;
+ }
+
+ rdev->pm.int_hwmon_dev = int_hwmon_dev;
+
+ return 0;
+}
+
+void evergreen_hwmon_fini(struct radeon_device *rdev)
+{
+ if (rdev->pm.int_hwmon_dev) {
+ sysfs_remove_group(&rdev->dev->kobj, &evergreen_hwmon_attrgroup);
+ hwmon_device_unregister(rdev->pm.int_hwmon_dev);
+ kfree(rdev->pm.int_hwmon_dev);
+ rdev->pm.int_hwmon_dev = NULL;
+ }
+}
+
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..a57f590 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -29,6 +29,8 @@
#include <linux/seq_file.h>
#include <linux/firmware.h>
#include <linux/platform_device.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
#include "drmP.h"
#include "radeon_drm.h"
#include "radeon.h"
@@ -92,6 +94,75 @@ void r600_gpu_init(struct radeon_device *rdev);
void r600_fini(struct radeon_device *rdev);
void r600_irq_disable(struct radeon_device *rdev);
+static ssize_t rv6xx_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 = (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 snprintf(buf, PAGE_SIZE, "%d\n", actual_temp);
+}
+
+static SENSOR_DEVICE_ATTR(gpu_temp, S_IRUGO, rv6xx_hwmon_show_temp, NULL, 0);
+
+static struct attribute *rv6xx_hwmon_attributes[2] = {
+ &sensor_dev_attr_gpu_temp.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group rv6xx_hwmon_attrgroup = {
+ .attrs = rv6xx_hwmon_attributes,
+};
+
+int rv6xx_hwmon_init(struct radeon_device *rdev)
+{
+ struct device *int_hwmon_dev;
+ int ret;
+
+ rdev->pm.int_hwmon_dev = NULL;
+
+ int_hwmon_dev = kzalloc(sizeof(struct device), GFP_KERNEL);
+ if (!int_hwmon_dev) {
+ dev_err(rdev->dev, "no memory\n");
+ return -ENOMEM;
+ }
+
+ /* where's the best place to put this? */
+ sysfs_create_group(&rdev->dev->kobj, &rv6xx_hwmon_attrgroup);
+
+ int_hwmon_dev = hwmon_device_register(rdev->dev);
+ if (IS_ERR(int_hwmon_dev)) {
+ dev_err(rdev->dev, "error registering with hwmon\n");
+ ret = PTR_ERR(int_hwmon_dev);
+ sysfs_remove_group(&rdev->dev->kobj, &rv6xx_hwmon_attrgroup);
+ kfree(int_hwmon_dev);
+ return ret;
+ }
+
+ rdev->pm.int_hwmon_dev = int_hwmon_dev;
+
+ return 0;
+}
+
+void rv6xx_hwmon_fini(struct radeon_device *rdev)
+{
+ if (rdev->pm.int_hwmon_dev) {
+ sysfs_remove_group(&rdev->dev->kobj, &rv6xx_hwmon_attrgroup);
+ hwmon_device_unregister(rdev->pm.int_hwmon_dev);
+ kfree(rdev->pm.int_hwmon_dev);
+ rdev->pm.int_hwmon_dev = NULL;
+ }
+}
+
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 a2561c0..943f042 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -177,6 +177,12 @@ 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 int rv6xx_hwmon_init(struct radeon_device *rdev);
+extern void rv6xx_hwmon_fini(struct radeon_device *rdev);
+extern int rv770_hwmon_init(struct radeon_device *rdev);
+extern void rv770_hwmon_fini(struct radeon_device *rdev);
+extern int evergreen_hwmon_init(struct radeon_device *rdev);
+extern void evergreen_hwmon_fini(struct radeon_device *rdev);
/*
* Fences.
@@ -663,6 +669,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 */
@@ -757,6 +770,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 107ada0..34249b2 100644
--- a/drivers/gpu/drm/radeon/radeon_atombios.c
+++ b/drivers/gpu/drm/radeon/radeon_atombios.c
@@ -1766,12 +1766,24 @@ 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;
+ rv6xx_hwmon_init(rdev);
+ } 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;
+ rv770_hwmon_init(rdev);
+ } 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;
+ evergreen_hwmon_init(rdev);
} 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 a51326c..f497394 100644
--- a/drivers/gpu/drm/radeon/radeon_pm.c
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
@@ -399,6 +399,8 @@ 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;
+ rdev->pm.int_hwmon_dev = NULL;
if (rdev->bios) {
if (rdev->is_atom_bios)
@@ -464,6 +466,23 @@ void radeon_pm_fini(struct radeon_device *rdev)
#endif
}
+ switch (rdev->pm.int_thermal_type) {
+ case THERMAL_TYPE_RV6XX:
+ if (rdev->pm.int_hwmon_dev)
+ rv6xx_hwmon_fini(rdev);
+ break;
+ case THERMAL_TYPE_RV770:
+ if (rdev->pm.int_hwmon_dev)
+ rv770_hwmon_fini(rdev);
+ break;
+ case THERMAL_TYPE_EVERGREEN:
+ if (rdev->pm.int_hwmon_dev)
+ evergreen_hwmon_fini(rdev);
+ break;
+ default:
+ break;
+ }
+
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..01904d3 100644
--- a/drivers/gpu/drm/radeon/rv770.c
+++ b/drivers/gpu/drm/radeon/rv770.c
@@ -28,6 +28,8 @@
#include <linux/firmware.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
#include "drmP.h"
#include "radeon.h"
#include "radeon_asic.h"
@@ -42,6 +44,75 @@
static void rv770_gpu_init(struct radeon_device *rdev);
void rv770_fini(struct radeon_device *rdev);
+static ssize_t rv770_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 = (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 snprintf(buf, PAGE_SIZE, "%d\n", actual_temp);
+}
+
+static SENSOR_DEVICE_ATTR(gpu_temp, S_IRUGO, rv770_hwmon_show_temp, NULL, 0);
+
+static struct attribute *rv770_hwmon_attributes[2] = {
+ &sensor_dev_attr_gpu_temp.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group rv770_hwmon_attrgroup = {
+ .attrs = rv770_hwmon_attributes,
+};
+
+int rv770_hwmon_init(struct radeon_device *rdev)
+{
+ struct device *int_hwmon_dev;
+ int ret;
+
+ rdev->pm.int_hwmon_dev = NULL;
+
+ int_hwmon_dev = kzalloc(sizeof(struct device), GFP_KERNEL);
+ if (!int_hwmon_dev) {
+ dev_err(rdev->dev, "no memory\n");
+ return -ENOMEM;
+ }
+
+ /* where's the best place to put this? */
+ sysfs_create_group(&rdev->dev->kobj, &rv770_hwmon_attrgroup);
+
+ int_hwmon_dev = hwmon_device_register(rdev->dev);
+ if (IS_ERR(int_hwmon_dev)) {
+ dev_err(rdev->dev, "error registering with hwmon\n");
+ ret = PTR_ERR(int_hwmon_dev);
+ sysfs_remove_group(&rdev->dev->kobj, &rv770_hwmon_attrgroup);
+ kfree(int_hwmon_dev);
+ return ret;
+ }
+
+ rdev->pm.int_hwmon_dev = int_hwmon_dev;
+
+ return 0;
+}
+
+void rv770_hwmon_fini(struct radeon_device *rdev)
+{
+ if (rdev->pm.int_hwmon_dev) {
+ sysfs_remove_group(&rdev->dev->kobj, &rv770_hwmon_attrgroup);
+ hwmon_device_unregister(rdev->pm.int_hwmon_dev);
+ kfree(rdev->pm.int_hwmon_dev);
+ rdev->pm.int_hwmon_dev = NULL;
+ }
+}
+
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.5.6.3
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH] drm/radeon/kms: add support for internal thermal sensors
2010-06-01 20:31 [PATCH] drm/radeon/kms: add support for internal thermal sensors Alex Deucher
@ 2010-06-01 20:42 ` Matthew Garrett
2010-06-01 21:41 ` Alex Deucher
0 siblings, 1 reply; 9+ messages in thread
From: Matthew Garrett @ 2010-06-01 20:42 UTC (permalink / raw)
To: Alex Deucher; +Cc: dri-devel
On Tue, Jun 01, 2010 at 04:31:41PM -0400, Alex Deucher wrote:
> rv6xx/rv7xx/evergreen families supported; older asics did
> not have an internal thermal sensor. Exposed via sysfs
> gpu_temp attribute.
This really should be done via the standard hwmon naming - some of the
sensor tools depend on it. If there's only one sensor per GPU
"temp1_input" is correct, with a "name" attribute indicating which card
provides it. Also, make sure that you're exporting in millidegrees
rather than degrees.
> Note also, that most laptops use an oem specific ACPI solution for
> GPU thermal information rather than using the internal thermal
> sensor directly.
Is there any mechanism for determining which ACPI thermal zone is
associated with the GPU, or is this something that's hardcoded into the
drivers?
> + /* where's the best place to put this? */
> + sysfs_create_group(&rdev->dev->kobj, &evergreen_hwmon_attrgroup);
They should be under the hwmon device.
--
Matthew Garrett | mjg59@srcf.ucam.org
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] drm/radeon/kms: add support for internal thermal sensors
2010-06-01 20:42 ` Matthew Garrett
@ 2010-06-01 21:41 ` Alex Deucher
2010-06-01 21:45 ` Matthew Garrett
0 siblings, 1 reply; 9+ messages in thread
From: Alex Deucher @ 2010-06-01 21:41 UTC (permalink / raw)
To: Matthew Garrett; +Cc: dri-devel
On Tue, Jun 1, 2010 at 4:42 PM, Matthew Garrett <mjg59@srcf.ucam.org> wrote:
> On Tue, Jun 01, 2010 at 04:31:41PM -0400, Alex Deucher wrote:
>> rv6xx/rv7xx/evergreen families supported; older asics did
>> not have an internal thermal sensor. Exposed via sysfs
>> gpu_temp attribute.
>
> This really should be done via the standard hwmon naming - some of the
> sensor tools depend on it. If there's only one sensor per GPU
> "temp1_input" is correct, with a "name" attribute indicating which card
> provides it. Also, make sure that you're exporting in millidegrees
> rather than degrees.
OK. Celsius I assume?
>
>> Note also, that most laptops use an oem specific ACPI solution for
>> GPU thermal information rather than using the internal thermal
>> sensor directly.
>
> Is there any mechanism for determining which ACPI thermal zone is
> associated with the GPU, or is this something that's hardcoded into the
> drivers?
I'll see if I can find out.
>
>> + /* where's the best place to put this? */
>> + sysfs_create_group(&rdev->dev->kobj, &evergreen_hwmon_attrgroup);
>
> They should be under the hwmon device.
Should this be a new device? I wasn't able to find a good example of
a hwmon driver that was part of another driver rather than a
standalone device.
Thanks!
Alex
>
> --
> Matthew Garrett | mjg59@srcf.ucam.org
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] drm/radeon/kms: add support for internal thermal sensors
2010-06-01 21:41 ` Alex Deucher
@ 2010-06-01 21:45 ` Matthew Garrett
2010-06-01 22:52 ` [PATCH] drm/radeon/kms: add support for internal thermal sensors (v2) Alex Deucher
0 siblings, 1 reply; 9+ messages in thread
From: Matthew Garrett @ 2010-06-01 21:45 UTC (permalink / raw)
To: Alex Deucher; +Cc: dri-devel
On Tue, Jun 01, 2010 at 05:41:34PM -0400, Alex Deucher wrote:
> On Tue, Jun 1, 2010 at 4:42 PM, Matthew Garrett <mjg59@srcf.ucam.org> wrote:
> > sensor tools depend on it. If there's only one sensor per GPU
> > "temp1_input" is correct, with a "name" attribute indicating which card
> > provides it. Also, make sure that you're exporting in millidegrees
> > rather than degrees.
>
> OK. Celsius I assume?
Sorry, yes.
> >> + /* where's the best place to put this? */
> >> + sysfs_create_group(&rdev->dev->kobj, &evergreen_hwmon_attrgroup);
> >
> > They should be under the hwmon device.
>
> Should this be a new device? I wasn't able to find a good example of
> a hwmon driver that was part of another driver rather than a
> standalone device.
It's what you get back from hwmon_register_device.
http://lists.freedesktop.org/archives/nouveau/2009-November/004087.html
is how I did this for nouveau, although it's not merged.
--
Matthew Garrett | mjg59@srcf.ucam.org
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH] drm/radeon/kms: add support for internal thermal sensors (v2)
2010-06-01 21:45 ` Matthew Garrett
@ 2010-06-01 22:52 ` Alex Deucher
2010-06-02 11:55 ` Julien Cristau
0 siblings, 1 reply; 9+ messages in thread
From: Alex Deucher @ 2010-06-01 22:52 UTC (permalink / raw)
To: airlied, dri-devel; +Cc: mjg59
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.
Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
---
drivers/gpu/drm/radeon/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/radeon/Kconfig b/drivers/gpu/drm/radeon/Kconfig
index 80c5b3e..2e3896d 100644
--- a/drivers/gpu/drm/radeon/Kconfig
+++ b/drivers/gpu/drm/radeon/Kconfig
@@ -2,6 +2,7 @@ config DRM_RADEON_KMS
bool "Enable modesetting on radeon by default - NEW DRIVER"
depends on DRM_RADEON
depends on POWER_SUPPLY
+ depends on HWMON
help
Choose this option if you want kernel modesetting enabled by default.
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 a2561c0..3da4378 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.
@@ -663,6 +666,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 */
@@ -757,6 +767,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 107ada0..4b4c31c 100644
--- a/drivers/gpu/drm/radeon/radeon_atombios.c
+++ b/drivers/gpu/drm/radeon/radeon_atombios.c
@@ -1764,14 +1764,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 a51326c..752c98a 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);
@@ -399,6 +477,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)
@@ -410,6 +489,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);
@@ -464,6 +545,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.5.6.3
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH] drm/radeon/kms: add support for internal thermal sensors (v2)
2010-06-01 22:52 ` [PATCH] drm/radeon/kms: add support for internal thermal sensors (v2) Alex Deucher
@ 2010-06-02 11:55 ` Julien Cristau
2010-06-02 15:51 ` Alex Deucher
0 siblings, 1 reply; 9+ messages in thread
From: Julien Cristau @ 2010-06-02 11:55 UTC (permalink / raw)
To: Alex Deucher; +Cc: mjg59, dri-devel
On Tue, Jun 1, 2010 at 18:52:30 -0400, Alex Deucher wrote:
> diff --git a/drivers/gpu/drm/radeon/Kconfig b/drivers/gpu/drm/radeon/Kconfig
> index 80c5b3e..2e3896d 100644
> --- a/drivers/gpu/drm/radeon/Kconfig
> +++ b/drivers/gpu/drm/radeon/Kconfig
> @@ -2,6 +2,7 @@ config DRM_RADEON_KMS
> bool "Enable modesetting on radeon by default - NEW DRIVER"
> depends on DRM_RADEON
> depends on POWER_SUPPLY
> + depends on HWMON
> help
> Choose this option if you want kernel modesetting enabled by default.
>
Shouldn't these be under CONFIG_DRM_RADEON, with _KMS only changing the
default value of the modeset parameter? Otherwise you could still try
to build the driver with _KMS off, and CONFIG_HWMON disabled (which I
assume is going to fail).
Cheers,
Julien
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] drm/radeon/kms: add support for internal thermal sensors (v2)
2010-06-02 11:55 ` Julien Cristau
@ 2010-06-02 15:51 ` Alex Deucher
2010-06-02 16:59 ` [PATCH] drm/radeon/kms: add support for internal thermal sensors (v3) Alex Deucher
0 siblings, 1 reply; 9+ messages in thread
From: Alex Deucher @ 2010-06-02 15:51 UTC (permalink / raw)
To: Julien Cristau; +Cc: mjg59, dri-devel
On Wed, Jun 2, 2010 at 7:55 AM, Julien Cristau <jcristau@debian.org> wrote:
> On Tue, Jun 1, 2010 at 18:52:30 -0400, Alex Deucher wrote:
>
>> diff --git a/drivers/gpu/drm/radeon/Kconfig b/drivers/gpu/drm/radeon/Kconfig
>> index 80c5b3e..2e3896d 100644
>> --- a/drivers/gpu/drm/radeon/Kconfig
>> +++ b/drivers/gpu/drm/radeon/Kconfig
>> @@ -2,6 +2,7 @@ config DRM_RADEON_KMS
>> bool "Enable modesetting on radeon by default - NEW DRIVER"
>> depends on DRM_RADEON
>> depends on POWER_SUPPLY
>> + depends on HWMON
>> help
>> Choose this option if you want kernel modesetting enabled by default.
>>
> Shouldn't these be under CONFIG_DRM_RADEON, with _KMS only changing the
> default value of the modeset parameter? Otherwise you could still try
> to build the driver with _KMS off, and CONFIG_HWMON disabled (which I
> assume is going to fail).
Yes, I patched an old version of the tree without this patch:
http://git.kernel.org/?p=linux/kernel/git/airlied/drm-2.6.git;a=commitdiff;h=5d9b7e2d2db95549aeab129c95d588236137a4c8
I'll update the patch.
>
> Cheers,
> Julien
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH] drm/radeon/kms: add support for internal thermal sensors (v3)
2010-06-02 15:51 ` Alex Deucher
@ 2010-06-02 16:59 ` Alex Deucher
2010-06-02 21:46 ` Frieder Ferlemann
0 siblings, 1 reply; 9+ messages in thread
From: Alex Deucher @ 2010-06-02 16:59 UTC (permalink / raw)
To: airlied, dri-devel
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>
---
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
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH] drm/radeon/kms: add support for internal thermal sensors (v3)
2010-06-02 16:59 ` [PATCH] drm/radeon/kms: add support for internal thermal sensors (v3) Alex Deucher
@ 2010-06-02 21:46 ` Frieder Ferlemann
0 siblings, 0 replies; 9+ messages in thread
From: Frieder Ferlemann @ 2010-06-02 21:46 UTC (permalink / raw)
To: dri-devel
Hi,
Am 02.06.2010 18:59, schrieb Alex Deucher:
> +/* get temperature in millidegrees */
> +u32 evergreen_get_temp(struct radeon_device *rdev)
Could it be named evergreen_get_temp_mcelsius_clipped_to_above_zero ?^)
Seriously: would it make sense to have:
u32 evergreen_get_temp_mkelvin(struct radeon_device *rdev)
With all that it implies? Just that it's there?)
Greetings,
Frieder
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2010-06-02 21:46 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-06-01 20:31 [PATCH] drm/radeon/kms: add support for internal thermal sensors Alex Deucher
2010-06-01 20:42 ` Matthew Garrett
2010-06-01 21:41 ` Alex Deucher
2010-06-01 21:45 ` Matthew Garrett
2010-06-01 22:52 ` [PATCH] drm/radeon/kms: add support for internal thermal sensors (v2) Alex Deucher
2010-06-02 11:55 ` Julien Cristau
2010-06-02 15:51 ` Alex Deucher
2010-06-02 16:59 ` [PATCH] drm/radeon/kms: add support for internal thermal sensors (v3) Alex Deucher
2010-06-02 21:46 ` Frieder Ferlemann
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.