forked from Minki/linux
drm/nv50/pm: add support for pwm fan control
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
This commit is contained in:
parent
8f27c54342
commit
cb9fa62671
@ -167,8 +167,11 @@ nouveau_pm_perflvl_get(struct drm_device *dev, struct nouveau_pm_level *perflvl)
|
||||
}
|
||||
}
|
||||
|
||||
if (pm->fanspeed_get)
|
||||
perflvl->fanspeed = pm->fanspeed_get(dev);
|
||||
if (pm->fanspeed_get) {
|
||||
ret = pm->fanspeed_get(dev);
|
||||
if (ret > 0)
|
||||
perflvl->fanspeed = ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -66,6 +66,8 @@ int nv50_pm_clock_get(struct drm_device *, u32 id);
|
||||
void *nv50_pm_clock_pre(struct drm_device *, struct nouveau_pm_level *,
|
||||
u32 id, int khz);
|
||||
void nv50_pm_clock_set(struct drm_device *, void *);
|
||||
int nv50_pm_fanspeed_get(struct drm_device *);
|
||||
int nv50_pm_fanspeed_set(struct drm_device *, int percent);
|
||||
|
||||
/* nva3_pm.c */
|
||||
int nva3_pm_clocks_get(struct drm_device *, struct nouveau_pm_level *);
|
||||
|
@ -386,6 +386,8 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
|
||||
engine->pm.temp_get = nv84_temp_get;
|
||||
else
|
||||
engine->pm.temp_get = nv40_temp_get;
|
||||
engine->pm.fanspeed_get = nv50_pm_fanspeed_get;
|
||||
engine->pm.fanspeed_set = nv50_pm_fanspeed_set;
|
||||
engine->vram.init = nv50_vram_init;
|
||||
engine->vram.takedown = nv50_vram_fini;
|
||||
engine->vram.get = nv50_vram_new;
|
||||
@ -441,6 +443,8 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
|
||||
engine->pm.clocks_get = nvc0_pm_clocks_get;
|
||||
engine->pm.voltage_get = nouveau_voltage_gpio_get;
|
||||
engine->pm.voltage_set = nouveau_voltage_gpio_set;
|
||||
engine->pm.fanspeed_get = nv50_pm_fanspeed_get;
|
||||
engine->pm.fanspeed_set = nv50_pm_fanspeed_set;
|
||||
break;
|
||||
case 0xd0:
|
||||
engine->instmem.init = nvc0_instmem_init;
|
||||
|
@ -144,3 +144,77 @@ nv50_pm_clock_set(struct drm_device *dev, void *pre_state)
|
||||
kfree(state);
|
||||
}
|
||||
|
||||
struct pwm_info {
|
||||
int id;
|
||||
int invert;
|
||||
u8 tag;
|
||||
u32 ctrl;
|
||||
int line;
|
||||
};
|
||||
|
||||
static int
|
||||
nv50_pm_fanspeed_pwm(struct drm_device *dev, struct pwm_info *pwm)
|
||||
{
|
||||
struct dcb_gpio_entry *gpio;
|
||||
|
||||
gpio = nouveau_bios_gpio_entry(dev, 0x09);
|
||||
if (gpio) {
|
||||
pwm->tag = gpio->tag;
|
||||
pwm->id = (gpio->line == 9) ? 1 : 0;
|
||||
pwm->invert = gpio->state[0] & 1;
|
||||
pwm->ctrl = (gpio->line < 16) ? 0xe100 : 0xe28c;
|
||||
pwm->line = (gpio->line & 0xf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int
|
||||
nv50_pm_fanspeed_get(struct drm_device *dev)
|
||||
{
|
||||
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
||||
struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio;
|
||||
struct pwm_info pwm;
|
||||
int ret;
|
||||
|
||||
ret = nv50_pm_fanspeed_pwm(dev, &pwm);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (nv_rd32(dev, pwm.ctrl) & (0x00000001 << pwm.line)) {
|
||||
u32 divs = nv_rd32(dev, 0x00e114 + (pwm.id * 8));
|
||||
u32 duty = nv_rd32(dev, 0x00e118 + (pwm.id * 8));
|
||||
if (divs) {
|
||||
divs = max(divs, duty);
|
||||
if (pwm.invert)
|
||||
duty = divs - duty;
|
||||
return (duty * 100) / divs;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return pgpio->get(dev, pwm.tag) * 100;
|
||||
}
|
||||
|
||||
int
|
||||
nv50_pm_fanspeed_set(struct drm_device *dev, int percent)
|
||||
{
|
||||
struct pwm_info pwm;
|
||||
u32 divs, duty;
|
||||
int ret;
|
||||
|
||||
ret = nv50_pm_fanspeed_pwm(dev, &pwm);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
divs = nv_rd32(dev, 0x00e114 + (pwm.id * 8));
|
||||
duty = ((divs * percent) + 99) / 100;
|
||||
if (pwm.invert)
|
||||
duty = divs - duty;
|
||||
|
||||
nv_mask(dev, pwm.ctrl, 0x00010001 << pwm.line, 0x00000001 << pwm.line);
|
||||
nv_wr32(dev, 0x00e118 + (pwm.id * 8), 0x80000000 | duty);
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user