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:
                        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;
 
        u32 divs, duty;
        int ret;
 
+       if (priv->fan.mode == FAN_CONTROL_NONE)
+               return -EINVAL;
+
        if (!priv->fan.pwm_set)
                return -ENODEV;
 
                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;
                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;
 }
 
        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;
 
        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;
 
 
        /* fan priv */
        struct {
+               enum nouveau_therm_fan_mode mode;
                int percent;
 
                int (*pwm_get)(struct nouveau_therm *, int line, u32*, u32*);
 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);
 
 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)
 {
        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,