aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2011-08-13 22:43:47 -0400
committerBen Skeggs <bskeggs@redhat.com>2011-12-21 04:01:11 -0500
commitcb9fa62671ace5ac40b9924e9014cebf04b78228 (patch)
tree4dc19083d28b04a44cc89e6f4b66efe154c6b370 /drivers/gpu
parent8f27c54342dffbfbafbddd6e43f011e6cb16d285 (diff)
drm/nv50/pm: add support for pwm fan control
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_pm.c7
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_pm.h2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_state.c4
-rw-r--r--drivers/gpu/drm/nouveau/nv50_pm.c74
4 files changed, 85 insertions, 2 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c b/drivers/gpu/drm/nouveau/nouveau_pm.c
index 607e4965f4ff..ee2872ed60ee 100644
--- a/drivers/gpu/drm/nouveau/nouveau_pm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_pm.c
@@ -167,8 +167,11 @@ nouveau_pm_perflvl_get(struct drm_device *dev, struct nouveau_pm_level *perflvl)
167 } 167 }
168 } 168 }
169 169
170 if (pm->fanspeed_get) 170 if (pm->fanspeed_get) {
171 perflvl->fanspeed = pm->fanspeed_get(dev); 171 ret = pm->fanspeed_get(dev);
172 if (ret > 0)
173 perflvl->fanspeed = ret;
174 }
172 175
173 return 0; 176 return 0;
174} 177}
diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.h b/drivers/gpu/drm/nouveau/nouveau_pm.h
index f19b0507fdfd..1b0bcef9ff35 100644
--- a/drivers/gpu/drm/nouveau/nouveau_pm.h
+++ b/drivers/gpu/drm/nouveau/nouveau_pm.h
@@ -66,6 +66,8 @@ int nv50_pm_clock_get(struct drm_device *, u32 id);
66void *nv50_pm_clock_pre(struct drm_device *, struct nouveau_pm_level *, 66void *nv50_pm_clock_pre(struct drm_device *, struct nouveau_pm_level *,
67 u32 id, int khz); 67 u32 id, int khz);
68void nv50_pm_clock_set(struct drm_device *, void *); 68void nv50_pm_clock_set(struct drm_device *, void *);
69int nv50_pm_fanspeed_get(struct drm_device *);
70int nv50_pm_fanspeed_set(struct drm_device *, int percent);
69 71
70/* nva3_pm.c */ 72/* nva3_pm.c */
71int nva3_pm_clocks_get(struct drm_device *, struct nouveau_pm_level *); 73int nva3_pm_clocks_get(struct drm_device *, struct nouveau_pm_level *);
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c
index e7ba6e7c0938..16195e9a9f91 100644
--- a/drivers/gpu/drm/nouveau/nouveau_state.c
+++ b/drivers/gpu/drm/nouveau/nouveau_state.c
@@ -386,6 +386,8 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
386 engine->pm.temp_get = nv84_temp_get; 386 engine->pm.temp_get = nv84_temp_get;
387 else 387 else
388 engine->pm.temp_get = nv40_temp_get; 388 engine->pm.temp_get = nv40_temp_get;
389 engine->pm.fanspeed_get = nv50_pm_fanspeed_get;
390 engine->pm.fanspeed_set = nv50_pm_fanspeed_set;
389 engine->vram.init = nv50_vram_init; 391 engine->vram.init = nv50_vram_init;
390 engine->vram.takedown = nv50_vram_fini; 392 engine->vram.takedown = nv50_vram_fini;
391 engine->vram.get = nv50_vram_new; 393 engine->vram.get = nv50_vram_new;
@@ -441,6 +443,8 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
441 engine->pm.clocks_get = nvc0_pm_clocks_get; 443 engine->pm.clocks_get = nvc0_pm_clocks_get;
442 engine->pm.voltage_get = nouveau_voltage_gpio_get; 444 engine->pm.voltage_get = nouveau_voltage_gpio_get;
443 engine->pm.voltage_set = nouveau_voltage_gpio_set; 445 engine->pm.voltage_set = nouveau_voltage_gpio_set;
446 engine->pm.fanspeed_get = nv50_pm_fanspeed_get;
447 engine->pm.fanspeed_set = nv50_pm_fanspeed_set;
444 break; 448 break;
445 case 0xd0: 449 case 0xd0:
446 engine->instmem.init = nvc0_instmem_init; 450 engine->instmem.init = nvc0_instmem_init;
diff --git a/drivers/gpu/drm/nouveau/nv50_pm.c b/drivers/gpu/drm/nouveau/nv50_pm.c
index 3d5a86b98282..713c718206e3 100644
--- a/drivers/gpu/drm/nouveau/nv50_pm.c
+++ b/drivers/gpu/drm/nouveau/nv50_pm.c
@@ -144,3 +144,77 @@ nv50_pm_clock_set(struct drm_device *dev, void *pre_state)
144 kfree(state); 144 kfree(state);
145} 145}
146 146
147struct pwm_info {
148 int id;
149 int invert;
150 u8 tag;
151 u32 ctrl;
152 int line;
153};
154
155static int
156nv50_pm_fanspeed_pwm(struct drm_device *dev, struct pwm_info *pwm)
157{
158 struct dcb_gpio_entry *gpio;
159
160 gpio = nouveau_bios_gpio_entry(dev, 0x09);
161 if (gpio) {
162 pwm->tag = gpio->tag;
163 pwm->id = (gpio->line == 9) ? 1 : 0;
164 pwm->invert = gpio->state[0] & 1;
165 pwm->ctrl = (gpio->line < 16) ? 0xe100 : 0xe28c;
166 pwm->line = (gpio->line & 0xf);
167 return 0;
168 }
169
170 return -ENOENT;
171}
172
173int
174nv50_pm_fanspeed_get(struct drm_device *dev)
175{
176 struct drm_nouveau_private *dev_priv = dev->dev_private;
177 struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio;
178 struct pwm_info pwm;
179 int ret;
180
181 ret = nv50_pm_fanspeed_pwm(dev, &pwm);
182 if (ret)
183 return ret;
184
185 if (nv_rd32(dev, pwm.ctrl) & (0x00000001 << pwm.line)) {
186 u32 divs = nv_rd32(dev, 0x00e114 + (pwm.id * 8));
187 u32 duty = nv_rd32(dev, 0x00e118 + (pwm.id * 8));
188 if (divs) {
189 divs = max(divs, duty);
190 if (pwm.invert)
191 duty = divs - duty;
192 return (duty * 100) / divs;
193 }
194
195 return 0;
196 }
197
198 return pgpio->get(dev, pwm.tag) * 100;
199}
200
201int
202nv50_pm_fanspeed_set(struct drm_device *dev, int percent)
203{
204 struct pwm_info pwm;
205 u32 divs, duty;
206 int ret;
207
208 ret = nv50_pm_fanspeed_pwm(dev, &pwm);
209 if (ret)
210 return ret;
211
212 divs = nv_rd32(dev, 0x00e114 + (pwm.id * 8));
213 duty = ((divs * percent) + 99) / 100;
214 if (pwm.invert)
215 duty = divs - duty;
216
217 nv_mask(dev, pwm.ctrl, 0x00010001 << pwm.line, 0x00000001 << pwm.line);
218 nv_wr32(dev, 0x00e118 + (pwm.id * 8), 0x80000000 | duty);
219 return 0;
220}