Commit 9c9191aa authored by Martin Peres's avatar Martin Peres Committed by Ben Skeggs

drm/nvd7/therm: handle another kind of PWM fans

This should fix fan management on many nvd7+ chipsets.
Signed-off-by: default avatarMartin Peres <martin.peres@labri.fr>
Tested-by: default avatarTimothée Ravier <tim@siosm.fr>
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent 61679fe1
...@@ -31,7 +31,7 @@ struct nouveau_therm { ...@@ -31,7 +31,7 @@ struct nouveau_therm {
int (*pwm_ctrl)(struct nouveau_therm *, int line, bool); int (*pwm_ctrl)(struct nouveau_therm *, int line, bool);
int (*pwm_get)(struct nouveau_therm *, int line, u32 *, u32 *); int (*pwm_get)(struct nouveau_therm *, int line, u32 *, u32 *);
int (*pwm_set)(struct nouveau_therm *, int line, u32, u32); int (*pwm_set)(struct nouveau_therm *, int line, u32, u32);
int (*pwm_clock)(struct nouveau_therm *); int (*pwm_clock)(struct nouveau_therm *, int line);
int (*fan_get)(struct nouveau_therm *); int (*fan_get)(struct nouveau_therm *);
int (*fan_set)(struct nouveau_therm *, int); int (*fan_set)(struct nouveau_therm *, int);
......
...@@ -242,7 +242,8 @@ nouveau_therm_fan_ctor(struct nouveau_therm *therm) ...@@ -242,7 +242,8 @@ nouveau_therm_fan_ctor(struct nouveau_therm *therm)
/* attempt to locate a drivable fan, and determine control method */ /* attempt to locate a drivable fan, and determine control method */
ret = gpio->find(gpio, 0, DCB_GPIO_FAN, 0xff, &func); ret = gpio->find(gpio, 0, DCB_GPIO_FAN, 0xff, &func);
if (ret == 0) { if (ret == 0) {
if (func.log[0] & DCB_GPIO_LOG_DIR_IN) { /* FIXME: is this really the place to perform such checks ? */
if (func.line != 16 && func.log[0] & DCB_GPIO_LOG_DIR_IN) {
nv_debug(therm, "GPIO_FAN is in input mode\n"); nv_debug(therm, "GPIO_FAN is in input mode\n");
ret = -EINVAL; ret = -EINVAL;
} else { } else {
......
...@@ -67,7 +67,7 @@ nouveau_fanpwm_set(struct nouveau_therm *therm, int percent) ...@@ -67,7 +67,7 @@ nouveau_fanpwm_set(struct nouveau_therm *therm, int percent)
if (priv->base.bios.pwm_freq) { if (priv->base.bios.pwm_freq) {
divs = 1; divs = 1;
if (therm->pwm_clock) if (therm->pwm_clock)
divs = therm->pwm_clock(therm); divs = therm->pwm_clock(therm, priv->func.line);
divs /= priv->base.bios.pwm_freq; divs /= priv->base.bios.pwm_freq;
} }
......
...@@ -93,7 +93,7 @@ nv50_fan_pwm_set(struct nouveau_therm *therm, int line, u32 divs, u32 duty) ...@@ -93,7 +93,7 @@ nv50_fan_pwm_set(struct nouveau_therm *therm, int line, u32 divs, u32 duty)
} }
int int
nv50_fan_pwm_clock(struct nouveau_therm *therm) nv50_fan_pwm_clock(struct nouveau_therm *therm, int line)
{ {
int chipset = nv_device(therm)->chipset; int chipset = nv_device(therm)->chipset;
int crystal = nv_device(therm)->crystal; int crystal = nv_device(therm)->crystal;
......
...@@ -32,10 +32,12 @@ static int ...@@ -32,10 +32,12 @@ static int
pwm_info(struct nouveau_therm *therm, int line) pwm_info(struct nouveau_therm *therm, int line)
{ {
u32 gpio = nv_rd32(therm, 0x00d610 + (line * 0x04)); u32 gpio = nv_rd32(therm, 0x00d610 + (line * 0x04));
switch (gpio & 0x000000c0) { switch (gpio & 0x000000c0) {
case 0x00000000: /* normal mode, possibly pwm forced off by us */ case 0x00000000: /* normal mode, possibly pwm forced off by us */
case 0x00000040: /* nvio special */ case 0x00000040: /* nvio special */
switch (gpio & 0x0000001f) { switch (gpio & 0x0000001f) {
case 0x00: return 2;
case 0x19: return 1; case 0x19: return 1;
case 0x1c: return 0; case 0x1c: return 0;
default: default:
...@@ -56,8 +58,9 @@ nvd0_fan_pwm_ctrl(struct nouveau_therm *therm, int line, bool enable) ...@@ -56,8 +58,9 @@ nvd0_fan_pwm_ctrl(struct nouveau_therm *therm, int line, bool enable)
int indx = pwm_info(therm, line); int indx = pwm_info(therm, line);
if (indx < 0) if (indx < 0)
return indx; return indx;
else if (indx < 2)
nv_mask(therm, 0x00d610 + (line * 0x04), 0x000000c0, data); nv_mask(therm, 0x00d610 + (line * 0x04), 0x000000c0, data);
/* nothing to do for indx == 2, it seems hardwired to PTHERM */
return 0; return 0;
} }
...@@ -67,12 +70,17 @@ nvd0_fan_pwm_get(struct nouveau_therm *therm, int line, u32 *divs, u32 *duty) ...@@ -67,12 +70,17 @@ nvd0_fan_pwm_get(struct nouveau_therm *therm, int line, u32 *divs, u32 *duty)
int indx = pwm_info(therm, line); int indx = pwm_info(therm, line);
if (indx < 0) if (indx < 0)
return indx; return indx;
else if (indx < 2) {
if (nv_rd32(therm, 0x00d610 + (line * 0x04)) & 0x00000040) { if (nv_rd32(therm, 0x00d610 + (line * 0x04)) & 0x00000040) {
*divs = nv_rd32(therm, 0x00e114 + (indx * 8)); *divs = nv_rd32(therm, 0x00e114 + (indx * 8));
*duty = nv_rd32(therm, 0x00e118 + (indx * 8)); *duty = nv_rd32(therm, 0x00e118 + (indx * 8));
return 0; return 0;
} }
} else if (indx == 2) {
*divs = nv_rd32(therm, 0x0200d8) & 0x1fff;
*duty = nv_rd32(therm, 0x0200dc) & 0x1fff;
return 0;
}
return -EINVAL; return -EINVAL;
} }
...@@ -83,16 +91,26 @@ nvd0_fan_pwm_set(struct nouveau_therm *therm, int line, u32 divs, u32 duty) ...@@ -83,16 +91,26 @@ nvd0_fan_pwm_set(struct nouveau_therm *therm, int line, u32 divs, u32 duty)
int indx = pwm_info(therm, line); int indx = pwm_info(therm, line);
if (indx < 0) if (indx < 0)
return indx; return indx;
else if (indx < 2) {
nv_wr32(therm, 0x00e114 + (indx * 8), divs); nv_wr32(therm, 0x00e114 + (indx * 8), divs);
nv_wr32(therm, 0x00e118 + (indx * 8), duty | 0x80000000); nv_wr32(therm, 0x00e118 + (indx * 8), duty | 0x80000000);
} else if (indx == 2) {
nv_mask(therm, 0x0200d8, 0x1fff, divs); /* keep the high bits */
nv_wr32(therm, 0x0200dc, duty | 0x40000000);
}
return 0; return 0;
} }
static int static int
nvd0_fan_pwm_clock(struct nouveau_therm *therm) nvd0_fan_pwm_clock(struct nouveau_therm *therm, int line)
{ {
int indx = pwm_info(therm, line);
if (indx < 0)
return 0;
else if (indx < 2)
return (nv_device(therm)->crystal * 1000) / 20; return (nv_device(therm)->crystal * 1000) / 20;
else
return nv_device(therm)->crystal * 1000 / 10;
} }
static int static int
......
...@@ -143,7 +143,7 @@ void nv40_therm_intr(struct nouveau_subdev *); ...@@ -143,7 +143,7 @@ void nv40_therm_intr(struct nouveau_subdev *);
int nv50_fan_pwm_ctrl(struct nouveau_therm *, int, bool); int nv50_fan_pwm_ctrl(struct nouveau_therm *, int, bool);
int nv50_fan_pwm_get(struct nouveau_therm *, int, u32 *, u32 *); int nv50_fan_pwm_get(struct nouveau_therm *, int, u32 *, u32 *);
int nv50_fan_pwm_set(struct nouveau_therm *, int, u32, u32); int nv50_fan_pwm_set(struct nouveau_therm *, int, u32, u32);
int nv50_fan_pwm_clock(struct nouveau_therm *); int nv50_fan_pwm_clock(struct nouveau_therm *, int);
int nv84_temp_get(struct nouveau_therm *therm); int nv84_temp_get(struct nouveau_therm *therm);
int nv84_therm_fini(struct nouveau_object *object, bool suspend); int nv84_therm_fini(struct nouveau_object *object, bool suspend);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment