aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.h2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_pm.c94
2 files changed, 80 insertions, 16 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index 251eaf87fa28..ea4009eaab20 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -554,6 +554,8 @@ struct nouveau_pm_engine {
554 554
555 int (*voltage_get)(struct drm_device *); 555 int (*voltage_get)(struct drm_device *);
556 int (*voltage_set)(struct drm_device *, int voltage); 556 int (*voltage_set)(struct drm_device *, int voltage);
557 int (*pwm_get)(struct drm_device *, struct dcb_gpio_entry*, u32*, u32*);
558 int (*pwm_set)(struct drm_device *, struct dcb_gpio_entry*, u32, u32);
557 int (*fanspeed_get)(struct drm_device *); 559 int (*fanspeed_get)(struct drm_device *);
558 int (*fanspeed_set)(struct drm_device *, int fanspeed); 560 int (*fanspeed_set)(struct drm_device *, int fanspeed);
559 int (*temp_get)(struct drm_device *); 561 int (*temp_get)(struct drm_device *);
diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c b/drivers/gpu/drm/nouveau/nouveau_pm.c
index 23b297fd6f61..b94364dbe352 100644
--- a/drivers/gpu/drm/nouveau/nouveau_pm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_pm.c
@@ -35,6 +35,74 @@
35#include <linux/hwmon-sysfs.h> 35#include <linux/hwmon-sysfs.h>
36 36
37static int 37static int
38nouveau_pwmfan_get(struct drm_device *dev)
39{
40 struct drm_nouveau_private *dev_priv = dev->dev_private;
41 struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio;
42 struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
43 struct dcb_gpio_entry *gpio;
44 u32 divs, duty;
45 int ret;
46
47 if (!pm->pwm_get) {
48 if (pm->fanspeed_get)
49 return pm->fanspeed_get(dev);
50 return -ENODEV;
51 }
52
53 gpio = nouveau_bios_gpio_entry(dev, DCB_GPIO_PWM_FAN);
54 if (gpio) {
55 ret = pm->pwm_get(dev, gpio, &divs, &duty);
56 if (ret == 0) {
57 divs = max(divs, duty);
58 if (dev_priv->card_type <= NV_40 ||
59 (gpio->state[0] & 1))
60 duty = divs - duty;
61 return (duty * 100) / divs;
62 }
63
64 return pgpio->get(dev, gpio->tag) * 100;
65 }
66
67 return -ENODEV;
68}
69
70static int
71nouveau_pwmfan_set(struct drm_device *dev, int percent)
72{
73 struct drm_nouveau_private *dev_priv = dev->dev_private;
74 struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
75 struct dcb_gpio_entry *gpio;
76 u32 divs, duty;
77
78 if (!pm->pwm_set) {
79 if (pm->fanspeed_set)
80 return pm->fanspeed_set(dev, percent);
81 return -ENODEV;
82 }
83
84 gpio = nouveau_bios_gpio_entry(dev, DCB_GPIO_PWM_FAN);
85 if (gpio) {
86 divs = pm->pwm_divisor;
87 if (pm->fan.pwm_freq) {
88 /*XXX: PNVIO clock more than likely... */
89 divs = 135000 / pm->fan.pwm_freq;
90 if (dev_priv->chipset < 0xa3)
91 divs /= 4;
92 }
93
94 duty = ((divs * percent) + 99) / 100;
95 if (dev_priv->card_type <= NV_40 ||
96 (gpio->state[0] & 1))
97 duty = divs - duty;
98
99 return pm->pwm_set(dev, gpio, divs, duty);
100 }
101
102 return -ENODEV;
103}
104
105static int
38nouveau_pm_clock_set(struct drm_device *dev, struct nouveau_pm_level *perflvl, 106nouveau_pm_clock_set(struct drm_device *dev, struct nouveau_pm_level *perflvl,
39 u8 id, u32 khz) 107 u8 id, u32 khz)
40{ 108{
@@ -68,9 +136,9 @@ nouveau_pm_perflvl_set(struct drm_device *dev, struct nouveau_pm_level *perflvl)
68 * on recent boards.. or maybe on some other factor we don't 136 * on recent boards.. or maybe on some other factor we don't
69 * know about? 137 * know about?
70 */ 138 */
71 if (pm->fanspeed_set && perflvl->fanspeed) { 139 if (perflvl->fanspeed) {
72 ret = pm->fanspeed_set(dev, perflvl->fanspeed); 140 ret = nouveau_pwmfan_set(dev, perflvl->fanspeed);
73 if (ret) 141 if (ret && ret != -ENODEV)
74 NV_ERROR(dev, "set fanspeed failed: %d\n", ret); 142 NV_ERROR(dev, "set fanspeed failed: %d\n", ret);
75 } 143 }
76 144
@@ -171,11 +239,9 @@ nouveau_pm_perflvl_get(struct drm_device *dev, struct nouveau_pm_level *perflvl)
171 } 239 }
172 } 240 }
173 241
174 if (pm->fanspeed_get) { 242 ret = nouveau_pwmfan_get(dev);
175 ret = pm->fanspeed_get(dev); 243 if (ret > 0)
176 if (ret > 0) 244 perflvl->fanspeed = ret;
177 perflvl->fanspeed = ret;
178 }
179 245
180 return 0; 246 return 0;
181} 247}
@@ -471,12 +537,9 @@ static ssize_t
471nouveau_hwmon_get_pwm0(struct device *d, struct device_attribute *a, char *buf) 537nouveau_hwmon_get_pwm0(struct device *d, struct device_attribute *a, char *buf)
472{ 538{
473 struct drm_device *dev = dev_get_drvdata(d); 539 struct drm_device *dev = dev_get_drvdata(d);
474 struct drm_nouveau_private *dev_priv = dev->dev_private; 540 int ret;
475 struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
476 int ret = -ENODEV;
477 541
478 if (pm->fanspeed_get) 542 ret = nouveau_pwmfan_get(dev);
479 ret = pm->fanspeed_get(dev);
480 if (ret < 0) 543 if (ret < 0)
481 return ret; 544 return ret;
482 545
@@ -504,8 +567,7 @@ nouveau_hwmon_set_pwm0(struct device *d, struct device_attribute *a,
504 if (value > pm->fan.max_duty) 567 if (value > pm->fan.max_duty)
505 value = pm->fan.max_duty; 568 value = pm->fan.max_duty;
506 569
507 if (pm->fanspeed_set) 570 ret = nouveau_pwmfan_set(dev, value);
508 ret = pm->fanspeed_set(dev, value);
509 if (ret) 571 if (ret)
510 return ret; 572 return ret;
511 573
@@ -660,7 +722,7 @@ nouveau_hwmon_init(struct drm_device *dev)
660 /*XXX: incorrect, need better detection for this, some boards have 722 /*XXX: incorrect, need better detection for this, some boards have
661 * the gpio entries for pwm fan control even when there's no 723 * the gpio entries for pwm fan control even when there's no
662 * actual fan connected to it... therm table? */ 724 * actual fan connected to it... therm table? */
663 if (pm->fanspeed_get && pm->fanspeed_get(dev) >= 0) { 725 if (nouveau_pwmfan_get(dev) >= 0) {
664 ret = sysfs_create_group(&dev->pdev->dev.kobj, 726 ret = sysfs_create_group(&dev->pdev->dev.kobj,
665 &hwmon_pwm_fan_attrgroup); 727 &hwmon_pwm_fan_attrgroup);
666 if (ret) 728 if (ret)