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/drm/nouveau/nv50_pm.c | |
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/drm/nouveau/nv50_pm.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nv50_pm.c | 74 |
1 files changed, 74 insertions, 0 deletions
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 | } | ||