diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2011-06-18 02:28:00 -0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2011-09-20 02:02:53 -0400 |
commit | d0f67a48f47a1874622418ba6bc2c45935b01b36 (patch) | |
tree | 085fa2e87f4dedcd54206947a718693a67cb4170 /drivers/gpu/drm/nouveau | |
parent | 78e2933d07124ea28593a1bdadc546294f77a504 (diff) |
drm/nva3/pm: idle graphics engine before changing clocks
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau')
-rw-r--r-- | drivers/gpu/drm/nouveau/nva3_pm.c | 40 |
1 files changed, 40 insertions, 0 deletions
diff --git a/drivers/gpu/drm/nouveau/nva3_pm.c b/drivers/gpu/drm/nouveau/nva3_pm.c index 98ea3aa0bb65..8541d5215e0d 100644 --- a/drivers/gpu/drm/nouveau/nva3_pm.c +++ b/drivers/gpu/drm/nouveau/nva3_pm.c | |||
@@ -264,10 +264,40 @@ out: | |||
264 | return info; | 264 | return info; |
265 | } | 265 | } |
266 | 266 | ||
267 | static bool | ||
268 | nva3_pm_grcp_idle(void *data) | ||
269 | { | ||
270 | struct drm_device *dev = data; | ||
271 | |||
272 | if (!(nv_rd32(dev, 0x400304) & 0x00000001)) | ||
273 | return true; | ||
274 | if (nv_rd32(dev, 0x400308) == 0x0050001c) | ||
275 | return true; | ||
276 | return false; | ||
277 | } | ||
278 | |||
267 | void | 279 | void |
268 | nva3_pm_clocks_set(struct drm_device *dev, void *pre_state) | 280 | nva3_pm_clocks_set(struct drm_device *dev, void *pre_state) |
269 | { | 281 | { |
282 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
270 | struct nva3_pm_state *info = pre_state; | 283 | struct nva3_pm_state *info = pre_state; |
284 | unsigned long flags; | ||
285 | |||
286 | /* prevent any new grctx switches from starting */ | ||
287 | spin_lock_irqsave(&dev_priv->context_switch_lock, flags); | ||
288 | nv_wr32(dev, 0x400324, 0x00000000); | ||
289 | nv_wr32(dev, 0x400328, 0x0050001c); /* wait flag 0x1c */ | ||
290 | /* wait for any pending grctx switches to complete */ | ||
291 | if (!nv_wait_cb(dev, nva3_pm_grcp_idle, dev)) { | ||
292 | NV_ERROR(dev, "pm: ctxprog didn't go idle\n"); | ||
293 | goto cleanup; | ||
294 | } | ||
295 | /* freeze PFIFO */ | ||
296 | nv_mask(dev, 0x002504, 0x00000001, 0x00000001); | ||
297 | if (!nv_wait(dev, 0x002504, 0x00000010, 0x00000010)) { | ||
298 | NV_ERROR(dev, "pm: fifo didn't go idle\n"); | ||
299 | goto cleanup; | ||
300 | } | ||
271 | 301 | ||
272 | prog_pll(dev, 0x00, 0x004200, &info->nclk); | 302 | prog_pll(dev, 0x00, 0x004200, &info->nclk); |
273 | prog_pll(dev, 0x01, 0x004220, &info->sclk); | 303 | prog_pll(dev, 0x01, 0x004220, &info->sclk); |
@@ -285,5 +315,15 @@ nva3_pm_clocks_set(struct drm_device *dev, void *pre_state) | |||
285 | nv_wr32(dev, 0x1002dc, 0); | 315 | nv_wr32(dev, 0x1002dc, 0); |
286 | nv_wr32(dev, 0x100210, 0x80000000); | 316 | nv_wr32(dev, 0x100210, 0x80000000); |
287 | 317 | ||
318 | cleanup: | ||
319 | /* unfreeze PFIFO */ | ||
320 | nv_mask(dev, 0x002504, 0x00000001, 0x00000000); | ||
321 | /* restore ctxprog to normal */ | ||
322 | nv_wr32(dev, 0x400324, 0x00000000); | ||
323 | nv_wr32(dev, 0x400328, 0x0070009c); /* set flag 0x1c */ | ||
324 | /* unblock it if necessary */ | ||
325 | if (nv_rd32(dev, 0x400308) == 0x0050001c) | ||
326 | nv_mask(dev, 0x400824, 0x10000000, 0x10000000); | ||
327 | spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); | ||
288 | kfree(info); | 328 | kfree(info); |
289 | } | 329 | } |