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 | ||