diff options
| author | Martin Peres <martin.peres@labri.fr> | 2014-02-17 21:56:11 -0500 |
|---|---|---|
| committer | Ben Skeggs <bskeggs@redhat.com> | 2014-03-26 00:08:24 -0400 |
| commit | 9c9191aaf844e237c025ef574e13d3e1c174c765 (patch) | |
| tree | 2ad1f6317680d4a9fa4db13c145b78b99d5ad7cd | |
| parent | 61679fe153b2b9ea5b5e2ab93305419e85e99a9d (diff) | |
drm/nvd7/therm: handle another kind of PWM fans
This should fix fan management on many nvd7+ chipsets.
Signed-off-by: Martin Peres <martin.peres@labri.fr>
Tested-by: Timothée Ravier <tim@siosm.fr>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
6 files changed, 35 insertions, 16 deletions
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/therm.h b/drivers/gpu/drm/nouveau/core/include/subdev/therm.h index 69891d4a3fe7..d4a68179e586 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/therm.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/therm.h | |||
| @@ -31,7 +31,7 @@ struct nouveau_therm { | |||
| 31 | int (*pwm_ctrl)(struct nouveau_therm *, int line, bool); | 31 | int (*pwm_ctrl)(struct nouveau_therm *, int line, bool); |
| 32 | int (*pwm_get)(struct nouveau_therm *, int line, u32 *, u32 *); | 32 | int (*pwm_get)(struct nouveau_therm *, int line, u32 *, u32 *); |
| 33 | int (*pwm_set)(struct nouveau_therm *, int line, u32, u32); | 33 | int (*pwm_set)(struct nouveau_therm *, int line, u32, u32); |
| 34 | int (*pwm_clock)(struct nouveau_therm *); | 34 | int (*pwm_clock)(struct nouveau_therm *, int line); |
| 35 | 35 | ||
| 36 | int (*fan_get)(struct nouveau_therm *); | 36 | int (*fan_get)(struct nouveau_therm *); |
| 37 | int (*fan_set)(struct nouveau_therm *, int); | 37 | int (*fan_set)(struct nouveau_therm *, int); |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/fan.c b/drivers/gpu/drm/nouveau/core/subdev/therm/fan.c index 29d4c417a5b3..ceb85281cbe9 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/fan.c +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/fan.c | |||
| @@ -242,7 +242,8 @@ nouveau_therm_fan_ctor(struct nouveau_therm *therm) | |||
| 242 | /* attempt to locate a drivable fan, and determine control method */ | 242 | /* attempt to locate a drivable fan, and determine control method */ |
| 243 | ret = gpio->find(gpio, 0, DCB_GPIO_FAN, 0xff, &func); | 243 | ret = gpio->find(gpio, 0, DCB_GPIO_FAN, 0xff, &func); |
| 244 | if (ret == 0) { | 244 | if (ret == 0) { |
| 245 | if (func.log[0] & DCB_GPIO_LOG_DIR_IN) { | 245 | /* FIXME: is this really the place to perform such checks ? */ |
| 246 | if (func.line != 16 && func.log[0] & DCB_GPIO_LOG_DIR_IN) { | ||
| 246 | nv_debug(therm, "GPIO_FAN is in input mode\n"); | 247 | nv_debug(therm, "GPIO_FAN is in input mode\n"); |
| 247 | ret = -EINVAL; | 248 | ret = -EINVAL; |
| 248 | } else { | 249 | } else { |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/fanpwm.c b/drivers/gpu/drm/nouveau/core/subdev/therm/fanpwm.c index 5f71db8e8992..9a5c07340263 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/fanpwm.c +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/fanpwm.c | |||
| @@ -67,7 +67,7 @@ nouveau_fanpwm_set(struct nouveau_therm *therm, int percent) | |||
| 67 | if (priv->base.bios.pwm_freq) { | 67 | if (priv->base.bios.pwm_freq) { |
| 68 | divs = 1; | 68 | divs = 1; |
| 69 | if (therm->pwm_clock) | 69 | if (therm->pwm_clock) |
| 70 | divs = therm->pwm_clock(therm); | 70 | divs = therm->pwm_clock(therm, priv->func.line); |
| 71 | divs /= priv->base.bios.pwm_freq; | 71 | divs /= priv->base.bios.pwm_freq; |
| 72 | } | 72 | } |
| 73 | 73 | ||
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c index 8cf7597a2182..321db927d638 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c | |||
| @@ -93,7 +93,7 @@ nv50_fan_pwm_set(struct nouveau_therm *therm, int line, u32 divs, u32 duty) | |||
| 93 | } | 93 | } |
| 94 | 94 | ||
| 95 | int | 95 | int |
| 96 | nv50_fan_pwm_clock(struct nouveau_therm *therm) | 96 | nv50_fan_pwm_clock(struct nouveau_therm *therm, int line) |
| 97 | { | 97 | { |
| 98 | int chipset = nv_device(therm)->chipset; | 98 | int chipset = nv_device(therm)->chipset; |
| 99 | int crystal = nv_device(therm)->crystal; | 99 | int crystal = nv_device(therm)->crystal; |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/nvd0.c b/drivers/gpu/drm/nouveau/core/subdev/therm/nvd0.c index 4dd4f81ae873..43fec17ea540 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/nvd0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/nvd0.c | |||
| @@ -32,10 +32,12 @@ static int | |||
| 32 | pwm_info(struct nouveau_therm *therm, int line) | 32 | pwm_info(struct nouveau_therm *therm, int line) |
| 33 | { | 33 | { |
| 34 | u32 gpio = nv_rd32(therm, 0x00d610 + (line * 0x04)); | 34 | u32 gpio = nv_rd32(therm, 0x00d610 + (line * 0x04)); |
| 35 | |||
| 35 | switch (gpio & 0x000000c0) { | 36 | switch (gpio & 0x000000c0) { |
| 36 | case 0x00000000: /* normal mode, possibly pwm forced off by us */ | 37 | case 0x00000000: /* normal mode, possibly pwm forced off by us */ |
| 37 | case 0x00000040: /* nvio special */ | 38 | case 0x00000040: /* nvio special */ |
| 38 | switch (gpio & 0x0000001f) { | 39 | switch (gpio & 0x0000001f) { |
| 40 | case 0x00: return 2; | ||
| 39 | case 0x19: return 1; | 41 | case 0x19: return 1; |
| 40 | case 0x1c: return 0; | 42 | case 0x1c: return 0; |
| 41 | default: | 43 | default: |
| @@ -56,8 +58,9 @@ nvd0_fan_pwm_ctrl(struct nouveau_therm *therm, int line, bool enable) | |||
| 56 | int indx = pwm_info(therm, line); | 58 | int indx = pwm_info(therm, line); |
| 57 | if (indx < 0) | 59 | if (indx < 0) |
| 58 | return indx; | 60 | return indx; |
| 59 | 61 | else if (indx < 2) | |
| 60 | nv_mask(therm, 0x00d610 + (line * 0x04), 0x000000c0, data); | 62 | nv_mask(therm, 0x00d610 + (line * 0x04), 0x000000c0, data); |
| 63 | /* nothing to do for indx == 2, it seems hardwired to PTHERM */ | ||
| 61 | return 0; | 64 | return 0; |
| 62 | } | 65 | } |
| 63 | 66 | ||
| @@ -67,10 +70,15 @@ nvd0_fan_pwm_get(struct nouveau_therm *therm, int line, u32 *divs, u32 *duty) | |||
| 67 | int indx = pwm_info(therm, line); | 70 | int indx = pwm_info(therm, line); |
| 68 | if (indx < 0) | 71 | if (indx < 0) |
| 69 | return indx; | 72 | return indx; |
| 70 | 73 | else if (indx < 2) { | |
| 71 | if (nv_rd32(therm, 0x00d610 + (line * 0x04)) & 0x00000040) { | 74 | if (nv_rd32(therm, 0x00d610 + (line * 0x04)) & 0x00000040) { |
| 72 | *divs = nv_rd32(therm, 0x00e114 + (indx * 8)); | 75 | *divs = nv_rd32(therm, 0x00e114 + (indx * 8)); |
| 73 | *duty = nv_rd32(therm, 0x00e118 + (indx * 8)); | 76 | *duty = nv_rd32(therm, 0x00e118 + (indx * 8)); |
| 77 | return 0; | ||
| 78 | } | ||
| 79 | } else if (indx == 2) { | ||
| 80 | *divs = nv_rd32(therm, 0x0200d8) & 0x1fff; | ||
| 81 | *duty = nv_rd32(therm, 0x0200dc) & 0x1fff; | ||
| 74 | return 0; | 82 | return 0; |
| 75 | } | 83 | } |
| 76 | 84 | ||
| @@ -83,16 +91,26 @@ nvd0_fan_pwm_set(struct nouveau_therm *therm, int line, u32 divs, u32 duty) | |||
| 83 | int indx = pwm_info(therm, line); | 91 | int indx = pwm_info(therm, line); |
| 84 | if (indx < 0) | 92 | if (indx < 0) |
| 85 | return indx; | 93 | return indx; |
| 86 | 94 | else if (indx < 2) { | |
| 87 | nv_wr32(therm, 0x00e114 + (indx * 8), divs); | 95 | nv_wr32(therm, 0x00e114 + (indx * 8), divs); |
| 88 | nv_wr32(therm, 0x00e118 + (indx * 8), duty | 0x80000000); | 96 | nv_wr32(therm, 0x00e118 + (indx * 8), duty | 0x80000000); |
| 97 | } else if (indx == 2) { | ||
| 98 | nv_mask(therm, 0x0200d8, 0x1fff, divs); /* keep the high bits */ | ||
| 99 | nv_wr32(therm, 0x0200dc, duty | 0x40000000); | ||
| 100 | } | ||
| 89 | return 0; | 101 | return 0; |
| 90 | } | 102 | } |
| 91 | 103 | ||
| 92 | static int | 104 | static int |
| 93 | nvd0_fan_pwm_clock(struct nouveau_therm *therm) | 105 | nvd0_fan_pwm_clock(struct nouveau_therm *therm, int line) |
| 94 | { | 106 | { |
| 95 | return (nv_device(therm)->crystal * 1000) / 20; | 107 | int indx = pwm_info(therm, line); |
| 108 | if (indx < 0) | ||
| 109 | return 0; | ||
| 110 | else if (indx < 2) | ||
| 111 | return (nv_device(therm)->crystal * 1000) / 20; | ||
| 112 | else | ||
| 113 | return nv_device(therm)->crystal * 1000 / 10; | ||
| 96 | } | 114 | } |
| 97 | 115 | ||
| 98 | static int | 116 | static int |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/priv.h b/drivers/gpu/drm/nouveau/core/subdev/therm/priv.h index 96f8f95693ce..916fca5c7816 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/priv.h +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/priv.h | |||
| @@ -143,7 +143,7 @@ void nv40_therm_intr(struct nouveau_subdev *); | |||
| 143 | int nv50_fan_pwm_ctrl(struct nouveau_therm *, int, bool); | 143 | int nv50_fan_pwm_ctrl(struct nouveau_therm *, int, bool); |
| 144 | int nv50_fan_pwm_get(struct nouveau_therm *, int, u32 *, u32 *); | 144 | int nv50_fan_pwm_get(struct nouveau_therm *, int, u32 *, u32 *); |
| 145 | int nv50_fan_pwm_set(struct nouveau_therm *, int, u32, u32); | 145 | int nv50_fan_pwm_set(struct nouveau_therm *, int, u32, u32); |
| 146 | int nv50_fan_pwm_clock(struct nouveau_therm *); | 146 | int nv50_fan_pwm_clock(struct nouveau_therm *, int); |
| 147 | int nv84_temp_get(struct nouveau_therm *therm); | 147 | int nv84_temp_get(struct nouveau_therm *therm); |
| 148 | int nv84_therm_fini(struct nouveau_object *object, bool suspend); | 148 | int nv84_therm_fini(struct nouveau_object *object, bool suspend); |
| 149 | 149 | ||
