diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2011-09-16 11:42:12 -0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2011-12-21 04:01:12 -0500 |
commit | a175094cd8f3d46060d8e3510bdca57eb2369a86 (patch) | |
tree | 18b8167ad75ebac3456d69da17b645eafc0f000a /drivers/gpu/drm/nouveau/nouveau_pm.c | |
parent | 85a2a365216e8e4eccf826e7dcc06c6298ab5fc1 (diff) |
drm/nouveau/pm: introduce generic handler for on-chip fan controller
The handling of the internal pwm fan controller is similar enough between
current chipsets that it makes sense to share the logic, and bugfixes :)
No hw backends converted yet, will automatically fall-through to the
"old" per-chipset fanspeed hooks for now.
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_pm.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_pm.c | 94 |
1 files changed, 78 insertions, 16 deletions
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 | ||
37 | static int | 37 | static int |
38 | nouveau_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 | |||
70 | static int | ||
71 | nouveau_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 | |||
105 | static int | ||
38 | nouveau_pm_clock_set(struct drm_device *dev, struct nouveau_pm_level *perflvl, | 106 | nouveau_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 | |||
471 | nouveau_hwmon_get_pwm0(struct device *d, struct device_attribute *a, char *buf) | 537 | nouveau_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) |