diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/base.c b/drivers/gpu/drm/nouveau/core/subdev/therm/base.c index 6502dfb95dd6..1674c74a76c8 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/base.c @@ -40,6 +40,8 @@ nouveau_therm_attr_get(struct nouveau_therm *therm, return priv->bios_fan.min_duty; case NOUVEAU_THERM_ATTR_FAN_MAX_DUTY: return priv->bios_fan.max_duty; + case NOUVEAU_THERM_ATTR_FAN_MODE: + return priv->fan.mode; case NOUVEAU_THERM_ATTR_THRS_FAN_BOOST: return priv->bios_sensor.thrs_fan_boost.temp; case NOUVEAU_THERM_ATTR_THRS_FAN_BOOST_HYST: @@ -82,6 +84,8 @@ nouveau_therm_attr_set(struct nouveau_therm *therm, value = priv->bios_fan.min_duty; priv->bios_fan.max_duty = value; return 0; + case NOUVEAU_THERM_ATTR_FAN_MODE: + return nouveau_therm_fan_set_mode(therm, value); case NOUVEAU_THERM_ATTR_THRS_FAN_BOOST: priv->bios_sensor.thrs_fan_boost.temp = value; return 0; diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/fan.c b/drivers/gpu/drm/nouveau/core/subdev/therm/fan.c index 409b95d5b679..b29237970fa0 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/fan.c +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/fan.c @@ -69,6 +69,9 @@ nouveau_therm_fan_set(struct nouveau_therm *therm, int percent) u32 divs, duty; int ret; + if (priv->fan.mode == FAN_CONTROL_NONE) + return -EINVAL; + if (!priv->fan.pwm_set) return -ENODEV; @@ -138,7 +141,52 @@ nouveau_therm_fan_sense(struct nouveau_therm *therm) return 0; } -static void +int +nouveau_therm_fan_set_mode(struct nouveau_therm *therm, + enum nouveau_therm_fan_mode mode) +{ + struct nouveau_therm_priv *priv = (void *)therm; + + if (priv->fan.mode == mode) + return 0; + + if (mode < FAN_CONTROL_NONE || mode >= FAN_CONTROL_NR) + return -EINVAL; + + switch (mode) + { + case FAN_CONTROL_NONE: + nv_info(therm, "switch fan to no-control mode\n"); + break; + case FAN_CONTROL_MANUAL: + nv_info(therm, "switch fan to manual mode\n"); + break; + case FAN_CONTROL_NR: + break; + } + + priv->fan.mode = mode; + return 0; +} + +int +nouveau_therm_fan_user_get(struct nouveau_therm *therm) +{ + return nouveau_therm_fan_get(therm); +} + +int +nouveau_therm_fan_user_set(struct nouveau_therm *therm, int percent) +{ + struct nouveau_therm_priv *priv = (void *)therm; + + if (priv->fan.mode != FAN_CONTROL_MANUAL) + return -EINVAL; + + return nouveau_therm_fan_set(therm, percent); +} + +void nouveau_therm_fan_set_defaults(struct nouveau_therm *therm) { struct nouveau_therm_priv *priv = (void *)therm; @@ -180,5 +228,7 @@ nouveau_therm_fan_ctor(struct nouveau_therm *therm) nv_error(therm, "parsing the thermal table failed\n"); nouveau_therm_fan_safety_checks(therm); + nouveau_therm_fan_set_mode(therm, FAN_CONTROL_NONE); + return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/nv40.c b/drivers/gpu/drm/nouveau/core/subdev/therm/nv40.c index 9021b541da8d..fcf2cfe731d6 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/nv40.c +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/nv40.c @@ -142,8 +142,8 @@ nv40_therm_ctor(struct nouveau_object *parent, priv->fan.pwm_set = nv40_fan_pwm_set; therm->temp_get = nv40_temp_get; - therm->fan_get = nouveau_therm_fan_get; - therm->fan_set = nouveau_therm_fan_set; + therm->fan_get = nouveau_therm_fan_user_get; + therm->fan_set = nouveau_therm_fan_user_set; therm->fan_sense = nouveau_therm_fan_sense; therm->attr_get = nouveau_therm_attr_get; therm->attr_set = nouveau_therm_attr_set; diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c index de7dc20ed436..f87a7a3eb4e7 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c @@ -136,8 +136,8 @@ nv50_therm_ctor(struct nouveau_object *parent, priv->fan.pwm_clock = nv50_fan_pwm_clock; therm->temp_get = nv50_temp_get; - therm->fan_get = nouveau_therm_fan_get; - therm->fan_set = nouveau_therm_fan_set; + therm->fan_get = nouveau_therm_fan_user_get; + therm->fan_set = nouveau_therm_fan_user_set; therm->fan_sense = nouveau_therm_fan_sense; therm->attr_get = nouveau_therm_attr_get; therm->attr_set = nouveau_therm_attr_set; diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/priv.h b/drivers/gpu/drm/nouveau/core/subdev/therm/priv.h index c53eb5396972..1c3cd6abc36e 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/priv.h +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/priv.h @@ -38,6 +38,7 @@ struct nouveau_therm_priv { /* fan priv */ struct { + enum nouveau_therm_fan_mode mode; int percent; int (*pwm_get)(struct nouveau_therm *, int line, u32*, u32*); @@ -63,5 +64,10 @@ int nouveau_therm_sensor_ctor(struct nouveau_therm *therm); int nouveau_therm_fan_ctor(struct nouveau_therm *therm); int nouveau_therm_fan_get(struct nouveau_therm *therm); int nouveau_therm_fan_set(struct nouveau_therm *therm, int percent); +int nouveau_therm_fan_user_get(struct nouveau_therm *therm); +int nouveau_therm_fan_user_set(struct nouveau_therm *therm, int percent); +int nouveau_therm_fan_set_mode(struct nouveau_therm *therm, + enum nouveau_therm_fan_mode mode); + int nouveau_therm_fan_sense(struct nouveau_therm *therm); diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c b/drivers/gpu/drm/nouveau/nouveau_pm.c index 0dca191ee173..b9d5335df742 100644 --- a/drivers/gpu/drm/nouveau/nouveau_pm.c +++ b/drivers/gpu/drm/nouveau/nouveau_pm.c @@ -503,6 +503,45 @@ nouveau_hwmon_show_fan0_input(struct device *d, struct device_attribute *attr, static SENSOR_DEVICE_ATTR(fan0_input, S_IRUGO, nouveau_hwmon_show_fan0_input, NULL, 0); + static ssize_t +nouveau_hwmon_get_pwm1_enable(struct device *d, + struct device_attribute *a, char *buf) +{ + struct drm_device *dev = dev_get_drvdata(d); + struct nouveau_drm *drm = nouveau_drm(dev); + struct nouveau_therm *therm = nouveau_therm(drm->device); + int ret; + + ret = therm->attr_get(therm, NOUVEAU_THERM_ATTR_FAN_MODE); + if (ret < 0) + return ret; + + return sprintf(buf, "%i\n", ret); +} + +static ssize_t +nouveau_hwmon_set_pwm1_enable(struct device *d, struct device_attribute *a, + const char *buf, size_t count) +{ + struct drm_device *dev = dev_get_drvdata(d); + struct nouveau_drm *drm = nouveau_drm(dev); + struct nouveau_therm *therm = nouveau_therm(drm->device); + long value; + int ret; + + if (strict_strtol(buf, 10, &value) == -EINVAL) + return -EINVAL; + + ret = therm->attr_set(therm, NOUVEAU_THERM_ATTR_FAN_MODE, value); + if (ret) + return ret; + else + return count; +} +static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, + nouveau_hwmon_get_pwm1_enable, + nouveau_hwmon_set_pwm1_enable, 0); + static ssize_t nouveau_hwmon_get_pwm1(struct device *d, struct device_attribute *a, char *buf) { @@ -638,6 +677,7 @@ static struct attribute *hwmon_fan_rpm_attributes[] = { NULL }; static struct attribute *hwmon_pwm_fan_attributes[] = { + &sensor_dev_attr_pwm1_enable.dev_attr.attr, &sensor_dev_attr_pwm1.dev_attr.attr, &sensor_dev_attr_pwm1_min.dev_attr.attr, &sensor_dev_attr_pwm1_max.dev_attr.attr,