From 68197b4ba0a3c90190795b97248b840a3e506545 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 5 Dec 2012 14:56:37 +1000 Subject: [PATCH] drm/nouveau/therm: add interfaces to allow forcing off pwm fan control Mostly to allow for the possibility of testing 'toggle' fan control easily. Signed-off-by: Ben Skeggs Signed-off-by: Martin Peres --- .../gpu/drm/nouveau/core/subdev/therm/fan.c | 2 ++ .../gpu/drm/nouveau/core/subdev/therm/nv40.c | 18 +++++++++-- .../gpu/drm/nouveau/core/subdev/therm/nv50.c | 12 ++++++- .../gpu/drm/nouveau/core/subdev/therm/nvd0.c | 31 ++++++++++++++++--- .../gpu/drm/nouveau/core/subdev/therm/priv.h | 1 + 5 files changed, 56 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/fan.c b/drivers/gpu/drm/nouveau/core/subdev/therm/fan.c index 4822733ca885..b4d14490d09e 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/fan.c +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/fan.c @@ -96,6 +96,8 @@ nouveau_therm_fan_set(struct nouveau_therm *therm, int percent) duty = divs - duty; ret = priv->fan.pwm_set(therm, func.line, divs, duty); + if (ret == 0) + ret = priv->fan.pwm_ctrl(therm, func.line, true); return ret; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/nv40.c b/drivers/gpu/drm/nouveau/core/subdev/therm/nv40.c index f2092af62ce3..47a15ecbe008 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/nv40.c +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/nv40.c @@ -79,6 +79,19 @@ nv40_temp_get(struct nouveau_therm *therm) return core_temp; } +int +nv40_fan_pwm_ctrl(struct nouveau_therm *therm, int line, bool enable) +{ + u32 mask = enable ? 0x80000000 : 0x0000000; + if (line == 2) nv_mask(therm, 0x0010f0, 0x80000000, mask); + else if (line == 9) nv_mask(therm, 0x0015f4, 0x80000000, mask); + else { + nv_error(therm, "unknown pwm ctrl for gpio %d\n", line); + return -ENODEV; + } + return 0; +} + int nv40_fan_pwm_get(struct nouveau_therm *therm, int line, u32 *divs, u32 *duty) { @@ -109,11 +122,11 @@ int nv40_fan_pwm_set(struct nouveau_therm *therm, int line, u32 divs, u32 duty) { if (line == 2) { - nv_wr32(therm, 0x0010f0, 0x80000000 | (duty << 16) | divs); + nv_mask(therm, 0x0010f0, 0x7fff7fff, (duty << 16) | divs); } else if (line == 9) { nv_wr32(therm, 0x0015f8, divs); - nv_wr32(therm, 0x0015f4, duty | 0x80000000); + nv_mask(therm, 0x0015f4, 0x7fffffff, duty); } else { nv_error(therm, "unknown pwm ctrl for gpio %d\n", line); return -ENODEV; @@ -136,6 +149,7 @@ nv40_therm_ctor(struct nouveau_object *parent, if (ret) return ret; + priv->base.fan.pwm_ctrl = nv40_fan_pwm_ctrl; priv->base.fan.pwm_get = nv40_fan_pwm_get; priv->base.fan.pwm_set = nv40_fan_pwm_set; priv->base.base.temp_get = nv40_temp_get; diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c index b7e1ecf93409..6ebad82e4feb 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c @@ -54,6 +54,16 @@ pwm_info(struct nouveau_therm *therm, int *line, int *ctrl, int *indx) return 0; } +int +nv50_fan_pwm_ctrl(struct nouveau_therm *therm, int line, bool enable) +{ + u32 data = enable ? 0x00000001 : 0x00000000; + int ctrl, id, ret = pwm_info(therm, &line, &ctrl, &id); + if (ret == 0) + nv_mask(therm, ctrl, 0x00010001 << line, data << line); + return ret; +} + int nv50_fan_pwm_get(struct nouveau_therm *therm, int line, u32 *divs, u32 *duty) { @@ -77,7 +87,6 @@ nv50_fan_pwm_set(struct nouveau_therm *therm, int line, u32 divs, u32 duty) if (ret) return ret; - nv_mask(therm, ctrl, 0x00010001 << line, 0x00000001 << line); nv_wr32(therm, 0x00e114 + (id * 8), divs); nv_wr32(therm, 0x00e118 + (id * 8), duty | 0x80000000); return 0; @@ -129,6 +138,7 @@ nv50_therm_ctor(struct nouveau_object *parent, if (ret) return ret; + priv->base.fan.pwm_ctrl = nv50_fan_pwm_ctrl; priv->base.fan.pwm_get = nv50_fan_pwm_get; priv->base.fan.pwm_set = nv50_fan_pwm_set; priv->base.fan.pwm_clock = nv50_fan_pwm_clock; diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/nvd0.c b/drivers/gpu/drm/nouveau/core/subdev/therm/nvd0.c index f0336a09cf9e..ec06e895b617 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/nvd0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/nvd0.c @@ -32,31 +32,51 @@ static int pwm_info(struct nouveau_therm *therm, int line) { u32 gpio = nv_rd32(therm, 0x00d610 + (line * 0x04)); - if (gpio & 0x00000040) { + switch (gpio & 0x000000c0) { + case 0x00000000: /* normal mode, possibly pwm forced off by us */ + case 0x00000040: /* nvio special */ switch (gpio & 0x0000001f) { case 0x19: return 1; case 0x1c: return 0; default: break; } + default: + break; } nv_error(therm, "GPIO %d unknown PWM: 0x%08x\n", line, gpio); - return -EINVAL; + return -ENODEV; } static int -nvd0_fan_pwm_get(struct nouveau_therm *therm, int line, u32 *divs, u32 *duty) +nvd0_fan_pwm_ctrl(struct nouveau_therm *therm, int line, bool enable) { + u32 data = enable ? 0x00000040 : 0x00000000; int indx = pwm_info(therm, line); if (indx < 0) return indx; - *divs = nv_rd32(therm, 0x00e114 + (indx * 8)); - *duty = nv_rd32(therm, 0x00e118 + (indx * 8)); + nv_mask(therm, 0x00d610 + (line * 0x04), 0x000000c0, data); return 0; } +static int +nvd0_fan_pwm_get(struct nouveau_therm *therm, int line, u32 *divs, u32 *duty) +{ + int indx = pwm_info(therm, line); + if (indx < 0) + return indx; + + if (nv_rd32(therm, 0x00d610 + (line * 0x04)) & 0x00000040) { + *divs = nv_rd32(therm, 0x00e114 + (indx * 8)); + *duty = nv_rd32(therm, 0x00e118 + (indx * 8)); + return 0; + } + + return -EINVAL; +} + static int nvd0_fan_pwm_set(struct nouveau_therm *therm, int line, u32 divs, u32 duty) { @@ -111,6 +131,7 @@ nvd0_therm_ctor(struct nouveau_object *parent, if (ret) return ret; + priv->base.fan.pwm_ctrl = nvd0_fan_pwm_ctrl; priv->base.fan.pwm_get = nvd0_fan_pwm_get; priv->base.fan.pwm_set = nvd0_fan_pwm_set; priv->base.fan.pwm_clock = nvd0_fan_pwm_clock; diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/priv.h b/drivers/gpu/drm/nouveau/core/subdev/therm/priv.h index bb940e9d4e8f..a08ca85e43ff 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/priv.h +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/priv.h @@ -47,6 +47,7 @@ struct nouveau_therm_priv { struct dcb_gpio_func tach; + int (*pwm_ctrl)(struct nouveau_therm *, int line, bool); int (*pwm_get)(struct nouveau_therm *, int line, u32*, u32*); int (*pwm_set)(struct nouveau_therm *, int line, u32, u32); int (*pwm_clock)(struct nouveau_therm *); -- 2.34.1