diff options
Diffstat (limited to 'drivers')
| -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 | } |
