diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2011-10-27 12:02:12 +1000 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2011-12-21 19:01:25 +1000 |
commit | 0b627a0b23404d97d1720c0c1abaee602aee9518 (patch) | |
tree | 52dfc4b8ec90e627d81eae4aac287768668977e2 /drivers/gpu/drm/nouveau/nouveau_pm.c | |
parent | ff2b6c6e587cf2add3071b3a9a5c61abbbaf4677 (diff) |
drm/nouveau/pm: change volt/fan before upclock, but after downclock
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 | 49 |
1 files changed, 36 insertions, 13 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c b/drivers/gpu/drm/nouveau/nouveau_pm.c index 4df8e0090df..c6ebf693ffb 100644 --- a/drivers/gpu/drm/nouveau/nouveau_pm.c +++ b/drivers/gpu/drm/nouveau/nouveau_pm.c @@ -97,39 +97,62 @@ nouveau_pwmfan_set(struct drm_device *dev, int percent) } static int -nouveau_pm_perflvl_set(struct drm_device *dev, struct nouveau_pm_level *perflvl) +nouveau_pm_perflvl_aux(struct drm_device *dev, struct nouveau_pm_level *perflvl, + struct nouveau_pm_level *a, struct nouveau_pm_level *b) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_pm_engine *pm = &dev_priv->engine.pm; - void *state; int ret; - if (perflvl == pm->cur) - return 0; - /*XXX: not on all boards, we should control based on temperature * on recent boards.. or maybe on some other factor we don't * know about? */ - if (perflvl->fanspeed) { + if (a->fanspeed && b->fanspeed && b->fanspeed > a->fanspeed) { ret = nouveau_pwmfan_set(dev, perflvl->fanspeed); - if (ret && ret != -ENODEV) - NV_ERROR(dev, "set fanspeed failed: %d\n", ret); + if (ret && ret != -ENODEV) { + NV_ERROR(dev, "fanspeed set failed: %d\n", ret); + return ret; + } } - if (pm->voltage.supported && pm->voltage_set && perflvl->volt_min) { - ret = pm->voltage_set(dev, perflvl->volt_min); - if (ret) { - NV_ERROR(dev, "voltage_set %d failed: %d\n", - perflvl->volt_min, ret); + if (pm->voltage.supported && pm->voltage_set) { + if (a->volt_min && b->volt_min && b->volt_min > a->volt_min) { + ret = pm->voltage_set(dev, perflvl->volt_min); + if (ret) { + NV_ERROR(dev, "voltage set failed: %d\n", ret); + return ret; + } } } + return 0; +} + +static int +nouveau_pm_perflvl_set(struct drm_device *dev, struct nouveau_pm_level *perflvl) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_pm_engine *pm = &dev_priv->engine.pm; + void *state; + int ret; + + if (perflvl == pm->cur) + return 0; + + ret = nouveau_pm_perflvl_aux(dev, perflvl, pm->cur, perflvl); + if (ret) + return ret; + state = pm->clocks_pre(dev, perflvl); if (IS_ERR(state)) return PTR_ERR(state); pm->clocks_set(dev, state); + ret = nouveau_pm_perflvl_aux(dev, perflvl, perflvl, pm->cur); + if (ret) + return ret; + pm->cur = perflvl; return 0; } |