Skip to contentSkip to conversation

add common fan control asic callbacks

PATCH New Oleg Chernovskiy 1 participant 3 messages Dec 7, 2014

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/3 add common fan control asic callbacks

Adds 4 callbacks for managing fan state/speed
* fan_ctrl_set_mode - manages fan control mode (nonzero == manual)
* fan_ctrl_get_mode - queries fan control mode
* set_fan_speed_percent - manages fan speed as percentage value
* get_fan_speed_percent - queries fan speed as percentage value

---
 drivers/gpu/drm/radeon/radeon.h | 4 ++++
 1 file changed, 4 insertions(+)
drivers/gpu/drm/radeon/radeon.h +4 -0
index 54529b8..4195e6c 100644
@@ -1967,6 +1967,10 @@ struct radeon_asic {
 		bool (*vblank_too_short)(struct radeon_device *rdev);
 		void (*powergate_uvd)(struct radeon_device *rdev, bool gate);
 		void (*enable_bapm)(struct radeon_device *rdev, bool enable);
+		void (*fan_ctrl_set_mode)(struct radeon_device *rdev, u32 mode);
+		u32 (*fan_ctrl_get_mode)(struct radeon_device *rdev);
+		int (*set_fan_speed_percent)(struct radeon_device *rdev, u32 speed);
+		int (*get_fan_speed_percent)(struct radeon_device *rdev, u32 *speed);
 	} dpm;
 	/* pageflipping */
 	struct {
Signature · 6 lines
2.1.3

_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel
#1 lore raw

PATCH 2/3 add hwmon interface for managing fan pwm

This adds percent-based fan control. Attributes (I hope) follow the sysfs-interface specification:
* pwm1 - fan speed query/manage
* pwm1_max, pwm1_min - min/max values for fan pwm (constant)
* pwm1_enable - fan control query/manage (enable/disable)

(There is no rpm-based control for now)

---
 drivers/gpu/drm/radeon/radeon_pm.c | 129 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 128 insertions(+), 1 deletion(-)
drivers/gpu/drm/radeon/radeon_pm.c +128 -1
index 32522cc..58daa23 100644
@@ -24,6 +24,7 @@
 #include "radeon.h"
 #include "avivod.h"
 #include "atom.h"
+#include "r600_dpm.h"
 #include <linux/power_supply.h>
 #include <linux/hwmon.h>
 #include <linux/hwmon-sysfs.h>
@@ -554,6 +555,94 @@ fail:
 	return count;
 }
 
+static ssize_t radeon_hwmon_get_pwm1_enable(struct device *dev,
+							   struct device_attribute *attr,
+							   char *buf)
+{
+	struct radeon_device *rdev = dev_get_drvdata(dev);
+	u32 pwm_mode = 0;
+
+	if(rdev->asic->dpm.fan_ctrl_get_mode)
+		pwm_mode = rdev->asic->dpm.fan_ctrl_get_mode(rdev);
+
+	return sprintf(buf, "%i\n", pwm_mode == FDO_PWM_MODE_STATIC);
+}
+
+static ssize_t radeon_hwmon_set_pwm1_enable(struct device *dev,
+							   struct device_attribute *attr,
+							   const char *buf,
+							   size_t count)
+{
+	struct radeon_device *rdev = dev_get_drvdata(dev);
+	int err;
+	int value;
+
+	if(!rdev->asic->dpm.fan_ctrl_set_mode)
+		return -EINVAL;
+
+	err = kstrtoint(buf, 10, &value);
+	if(err)
+		return err;
+
+	switch(value) {
+	case 1: // manual, percent-based
+		rdev->asic->dpm.fan_ctrl_set_mode(rdev, FDO_PWM_MODE_STATIC);
+		break;
+	default: // disable
+		rdev->asic->dpm.fan_ctrl_set_mode(rdev, 0);
+		break;
+	}
+
+	return count;
+}
+
+static ssize_t radeon_hwmon_get_pwm1_min(struct device *dev,
+							   struct device_attribute *attr,
+							   char *buf)
+{
+	return sprintf(buf, "%i\n", 0);
+}
+
+static ssize_t radeon_hwmon_get_pwm1_max(struct device *dev,
+							   struct device_attribute *attr,
+							   char *buf)
+{
+	return sprintf(buf, "%i\n", 100); // pwm uses percent-based fan-control
+}
+
+static ssize_t radeon_hwmon_set_pwm1(struct device *dev,
+							   struct device_attribute *attr,
+							   const char *buf, size_t count)
+{
+	struct radeon_device *rdev = dev_get_drvdata(dev);
+	int err;
+	u32 value;
+
+	err = kstrtou32(buf, 10, &value);
+	if(err)
+		return err;
+
+	err = rdev->asic->dpm.set_fan_speed_percent(rdev, value);
+	if(err)
+		return err;
+
+	return count;
+}
+
+static ssize_t radeon_hwmon_get_pwm1(struct device *dev,
+							   struct device_attribute *attr,
+							   char *buf)
+{
+	struct radeon_device *rdev = dev_get_drvdata(dev);
+	int err;
+	u32 speed;
+	err = rdev->asic->dpm.get_fan_speed_percent(rdev, &speed);
+	if(err)
+		return err;
+
+	return sprintf(buf, "%i\n", speed);
+}
+
 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 DEVICE_ATTR(power_dpm_state, S_IRUGO | S_IWUSR, radeon_get_dpm_state, radeon_set_dpm_state);
@@ -601,11 +690,20 @@ static ssize_t radeon_hwmon_show_temp_thresh(struct device *dev,
 static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, radeon_hwmon_show_temp, NULL, 0);
 static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, radeon_hwmon_show_temp_thresh, NULL, 0);
 static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO, radeon_hwmon_show_temp_thresh, NULL, 1);
+static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, radeon_hwmon_get_pwm1, radeon_hwmon_set_pwm1, 0);
+static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, radeon_hwmon_get_pwm1_enable, radeon_hwmon_set_pwm1_enable, 0);
+static SENSOR_DEVICE_ATTR(pwm1_min, S_IRUGO, radeon_hwmon_get_pwm1_min, NULL, 0);
+static SENSOR_DEVICE_ATTR(pwm1_max, S_IRUGO, radeon_hwmon_get_pwm1_max, NULL, 0);
+
 
 static struct attribute *hwmon_attributes[] = {
 	&sensor_dev_attr_temp1_input.dev_attr.attr,
 	&sensor_dev_attr_temp1_crit.dev_attr.attr,
 	&sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
+	&sensor_dev_attr_pwm1.dev_attr.attr,
+	&sensor_dev_attr_pwm1_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm1_min.dev_attr.attr,
+	&sensor_dev_attr_pwm1_max.dev_attr.attr,
 	NULL
 };
 
@@ -614,6 +712,7 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj,
 {
 	struct device *dev = container_of(kobj, struct device, kobj);
 	struct radeon_device *rdev = dev_get_drvdata(dev);
+	umode_t effective_mode = attr->mode;
 
 	/* Skip limit attributes if DPM is not enabled */
 	if (rdev->pm.pm_method != PM_METHOD_DPM &&
@@ -621,7 +720,35 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj,
 	     attr == &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr))
 		return 0;
 
-	return attr->mode;
+	/* Skip fan attributes if fan is not present */
+	if(rdev->pm.no_fan &&
+		(attr == &sensor_dev_attr_pwm1.dev_attr.attr ||
+		 attr == &sensor_dev_attr_pwm1_enable.dev_attr.attr ||
+		 attr == &sensor_dev_attr_pwm1_max.dev_attr.attr ||
+		 attr == &sensor_dev_attr_pwm1_min.dev_attr.attr))
+		return 0;
+
+	/* mask fan attributes if we have no bindings for this asic to expose */
+	if((!rdev->asic->dpm.get_fan_speed_percent &&
+		 attr == &sensor_dev_attr_pwm1.dev_attr.attr) || // can't query fan
+		 (!rdev->asic->dpm.fan_ctrl_get_mode &&
+		  attr == &sensor_dev_attr_pwm1_enable.dev_attr.attr)) // can't query state
+		effective_mode &= ~S_IRUGO;
+
+	if((!rdev->asic->dpm.set_fan_speed_percent &&
+		 attr == &sensor_dev_attr_pwm1.dev_attr.attr) || // can't manage fan
+		 (!rdev->asic->dpm.fan_ctrl_set_mode &&
+		  attr == &sensor_dev_attr_pwm1_enable.dev_attr.attr)) // can't manage state
+		effective_mode &= ~S_IWUSR;
+
+	/* hide max/min values if we can't both query and manage the fan */
+	if((!rdev->asic->dpm.set_fan_speed_percent &&
+		 !rdev->asic->dpm.get_fan_speed_percent) &&
+		 (attr == &sensor_dev_attr_pwm1_max.dev_attr.attr ||
+		  attr == &sensor_dev_attr_pwm1_min.dev_attr.attr))
+		return 0;
+
+	return effective_mode;
 }
 
 static const struct attribute_group hwmon_attrgroup = {
Signature · 6 lines
2.1.3

_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel
#2 lore raw

PATCH 3/3 bind fan control on CI cards to hwmon interface

In reply to Oleg Chernovskiy

This adds a possibility to control fan on CI parts via exported hwmon variables. Note that automatic ucode fan management pauses if you choose to enable manual fan control

---
 drivers/gpu/drm/radeon/ci_dpm.c      | 32 ++++++++++++++++++++++++--------
 drivers/gpu/drm/radeon/radeon_asic.c |  4 ++++
 drivers/gpu/drm/radeon/radeon_asic.h |  7 +++++++
 3 files changed, 35 insertions(+), 8 deletions(-)
drivers/gpu/drm/radeon/ci_dpm.c +24 -8
index f373a81..cbba2b6 100644
@@ -187,6 +187,8 @@ static int ci_update_uvd_dpm(struct radeon_device *rdev, bool gate);
 static PPSMC_Result ci_send_msg_to_smc_with_parameter(struct radeon_device *rdev,
 						      PPSMC_Msg msg, u32 parameter);
 
+static void ci_thermal_start_smc_fan_control(struct radeon_device *rdev);
+
 static struct ci_power_info *ci_get_pi(struct radeon_device *rdev)
 {
         struct ci_power_info *pi = rdev->pm.dpm.priv;
@@ -1046,7 +1048,6 @@ static int ci_fan_ctrl_start_smc_fan_control(struct radeon_device *rdev)
 	return 0;
 }
 
-#if 0
 static int ci_fan_ctrl_stop_smc_fan_control(struct radeon_device *rdev)
 {
 	PPSMC_Result ret;
@@ -1058,7 +1059,7 @@ static int ci_fan_ctrl_stop_smc_fan_control(struct radeon_device *rdev)
 		return -EINVAL;
 }
 
-static int ci_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev,
+int ci_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev,
 					     u32 *speed)
 {
 	u32 duty, duty100;
@@ -1083,7 +1084,7 @@ static int ci_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev,
 	return 0;
 }
 
-static int ci_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev,
+int ci_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev,
 					     u32 speed)
 {
 	u32 tmp;
@@ -1096,9 +1097,6 @@ static int ci_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev,
 	if (speed > 100)
 		return -EINVAL;
 
-	if (rdev->pm.dpm.fan.ucode_fan_control)
-		ci_fan_ctrl_stop_smc_fan_control(rdev);
-
 	duty100 = (RREG32_SMC(CG_FDO_CTRL1) & FMAX_DUTY100_MASK) >> FMAX_DUTY100_SHIFT;
 
 	if (duty100 == 0)
@@ -1112,11 +1110,29 @@ static int ci_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev,
 	tmp |= FDO_STATIC_DUTY(duty);
 	WREG32_SMC(CG_FDO_CTRL0, tmp);
 
-	ci_fan_ctrl_set_static_mode(rdev, FDO_PWM_MODE_STATIC);
-
 	return 0;
 }
 
+void ci_fan_ctrl_set_mode(struct radeon_device *rdev, u32 mode)
+{
+	if(mode) {
+		// stop auto-manage
+		if (rdev->pm.dpm.fan.ucode_fan_control)
+			ci_fan_ctrl_stop_smc_fan_control(rdev);
+		ci_fan_ctrl_set_static_mode(rdev, mode);
+	} else {
+		// restart auto-manage
+		ci_thermal_start_smc_fan_control(rdev);
+	}
+}
+
+u32 ci_fan_cntrl_get_mode(struct radeon_device *rdev)
+{
+	u32 tmp = RREG32_SMC(CG_FDO_CTRL2) & FDO_PWM_MODE_MASK;
+	return (tmp >> FDO_PWM_MODE_SHIFT);
+}
+
+#if 0
 static int ci_fan_ctrl_get_fan_speed_rpm(struct radeon_device *rdev,
 					 u32 *speed)
 {
drivers/gpu/drm/radeon/radeon_asic.c +4 -0
index 850de57..d2c517c 100644
@@ -2104,6 +2104,10 @@ static struct radeon_asic ci_asic = {
 		.force_performance_level = &ci_dpm_force_performance_level,
 		.vblank_too_short = &ci_dpm_vblank_too_short,
 		.powergate_uvd = &ci_dpm_powergate_uvd,
+		.fan_ctrl_set_mode = &ci_fan_ctrl_set_mode,
+		.fan_ctrl_get_mode = &ci_fan_cntrl_get_mode,
+		.get_fan_speed_percent = &ci_fan_ctrl_get_fan_speed_percent,
+		.set_fan_speed_percent = &ci_fan_ctrl_set_fan_speed_percent,
 	},
 	.pflip = {
 		.page_flip = &evergreen_page_flip,
drivers/gpu/drm/radeon/radeon_asic.h +7 -0
index 2a45d54..edd64dc 100644
@@ -861,6 +861,13 @@ int ci_dpm_force_performance_level(struct radeon_device *rdev,
 bool ci_dpm_vblank_too_short(struct radeon_device *rdev);
 void ci_dpm_powergate_uvd(struct radeon_device *rdev, bool gate);
 
+int ci_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev,
+						 u32 *speed);
+int ci_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev,
+						 u32 speed);
+u32 ci_fan_cntrl_get_mode(struct radeon_device *rdev);
+void ci_fan_ctrl_set_mode(struct radeon_device *rdev, u32 mode);
+
 int kv_dpm_init(struct radeon_device *rdev);
 int kv_dpm_enable(struct radeon_device *rdev);
 int kv_dpm_late_enable(struct radeon_device *rdev);
Signature · 6 lines
2.1.3

_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel