diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2011-08-13 22:43:47 -0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2011-12-21 04:01:11 -0500 |
commit | cb9fa62671ace5ac40b9924e9014cebf04b78228 (patch) | |
tree | 4dc19083d28b04a44cc89e6f4b66efe154c6b370 /drivers/gpu | |
parent | 8f27c54342dffbfbafbddd6e43f011e6cb16d285 (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.c | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_pm.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_state.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nv50_pm.c | 74 |
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); | |||
66 | void *nv50_pm_clock_pre(struct drm_device *, struct nouveau_pm_level *, | 66 | void *nv50_pm_clock_pre(struct drm_device *, struct nouveau_pm_level *, |
67 | u32 id, int khz); | 67 | u32 id, int khz); |
68 | void nv50_pm_clock_set(struct drm_device *, void *); | 68 | void nv50_pm_clock_set(struct drm_device *, void *); |
69 | int nv50_pm_fanspeed_get(struct drm_device *); | ||
70 | int nv50_pm_fanspeed_set(struct drm_device *, int percent); | ||
69 | 71 | ||
70 | /* nva3_pm.c */ | 72 | /* nva3_pm.c */ |
71 | int nva3_pm_clocks_get(struct drm_device *, struct nouveau_pm_level *); | 73 | int 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 | ||
147 | struct pwm_info { | ||
148 | int id; | ||
149 | int invert; | ||
150 | u8 tag; | ||
151 | u32 ctrl; | ||
152 | int line; | ||
153 | }; | ||
154 | |||
155 | static int | ||
156 | nv50_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 | |||
173 | int | ||
174 | nv50_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 | |||
201 | int | ||
202 | nv50_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 | } | ||