diff options
-rw-r--r-- | drivers/gpu/drm/nouveau/nvc0_pm.c | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/drivers/gpu/drm/nouveau/nvc0_pm.c b/drivers/gpu/drm/nouveau/nvc0_pm.c index ce65f81bb871..1348f29b544d 100644 --- a/drivers/gpu/drm/nouveau/nvc0_pm.c +++ b/drivers/gpu/drm/nouveau/nvc0_pm.c | |||
@@ -164,6 +164,7 @@ struct nvc0_pm_clock { | |||
164 | }; | 164 | }; |
165 | 165 | ||
166 | struct nvc0_pm_state { | 166 | struct nvc0_pm_state { |
167 | struct nouveau_pm_level *perflvl; | ||
167 | struct nvc0_pm_clock eng[16]; | 168 | struct nvc0_pm_clock eng[16]; |
168 | }; | 169 | }; |
169 | 170 | ||
@@ -335,6 +336,7 @@ nvc0_pm_clocks_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl) | |||
335 | return ERR_PTR(ret); | 336 | return ERR_PTR(ret); |
336 | } | 337 | } |
337 | 338 | ||
339 | info->perflvl = perflvl; | ||
338 | return info; | 340 | return info; |
339 | } | 341 | } |
340 | 342 | ||
@@ -375,12 +377,126 @@ prog_clk(struct drm_device *dev, int clk, struct nvc0_pm_clock *info) | |||
375 | nv_mask(dev, 0x137250 + (clk * 0x04), 0x00003f3f, info->mdiv); | 377 | nv_mask(dev, 0x137250 + (clk * 0x04), 0x00003f3f, info->mdiv); |
376 | } | 378 | } |
377 | 379 | ||
380 | static void | ||
381 | mclk_precharge(struct nouveau_mem_exec_func *exec) | ||
382 | { | ||
383 | } | ||
384 | |||
385 | static void | ||
386 | mclk_refresh(struct nouveau_mem_exec_func *exec) | ||
387 | { | ||
388 | } | ||
389 | |||
390 | static void | ||
391 | mclk_refresh_auto(struct nouveau_mem_exec_func *exec, bool enable) | ||
392 | { | ||
393 | nv_wr32(exec->dev, 0x10f210, enable ? 0x80000000 : 0x00000000); | ||
394 | } | ||
395 | |||
396 | static void | ||
397 | mclk_refresh_self(struct nouveau_mem_exec_func *exec, bool enable) | ||
398 | { | ||
399 | } | ||
400 | |||
401 | static void | ||
402 | mclk_wait(struct nouveau_mem_exec_func *exec, u32 nsec) | ||
403 | { | ||
404 | udelay((nsec + 500) / 1000); | ||
405 | } | ||
406 | |||
407 | static u32 | ||
408 | mclk_mrg(struct nouveau_mem_exec_func *exec, int mr) | ||
409 | { | ||
410 | struct drm_device *dev = exec->dev; | ||
411 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
412 | if (dev_priv->vram_type != NV_MEM_TYPE_GDDR5) { | ||
413 | if (mr <= 1) | ||
414 | return nv_rd32(dev, 0x10f300 + ((mr - 0) * 4)); | ||
415 | return nv_rd32(dev, 0x10f320 + ((mr - 2) * 4)); | ||
416 | } else { | ||
417 | if (mr == 0) | ||
418 | return nv_rd32(dev, 0x10f300 + (mr * 4)); | ||
419 | else | ||
420 | if (mr <= 7) | ||
421 | return nv_rd32(dev, 0x10f32c + (mr * 4)); | ||
422 | return nv_rd32(dev, 0x10f34c); | ||
423 | } | ||
424 | } | ||
425 | |||
426 | static void | ||
427 | mclk_mrs(struct nouveau_mem_exec_func *exec, int mr, u32 data) | ||
428 | { | ||
429 | struct drm_device *dev = exec->dev; | ||
430 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
431 | if (dev_priv->vram_type != NV_MEM_TYPE_GDDR5) { | ||
432 | if (mr <= 1) { | ||
433 | nv_wr32(dev, 0x10f300 + ((mr - 0) * 4), data); | ||
434 | if (dev_priv->vram_rank_B) | ||
435 | nv_wr32(dev, 0x10f308 + ((mr - 0) * 4), data); | ||
436 | } else | ||
437 | if (mr <= 3) { | ||
438 | nv_wr32(dev, 0x10f320 + ((mr - 2) * 4), data); | ||
439 | if (dev_priv->vram_rank_B) | ||
440 | nv_wr32(dev, 0x10f328 + ((mr - 2) * 4), data); | ||
441 | } | ||
442 | } else { | ||
443 | if (mr == 0) nv_wr32(dev, 0x10f300 + (mr * 4), data); | ||
444 | else if (mr <= 7) nv_wr32(dev, 0x10f32c + (mr * 4), data); | ||
445 | else if (mr == 15) nv_wr32(dev, 0x10f34c, data); | ||
446 | } | ||
447 | } | ||
448 | |||
449 | static void | ||
450 | mclk_clock_set(struct nouveau_mem_exec_func *exec) | ||
451 | { | ||
452 | } | ||
453 | |||
454 | static void | ||
455 | mclk_timing_set(struct nouveau_mem_exec_func *exec) | ||
456 | { | ||
457 | struct nvc0_pm_state *info = exec->priv; | ||
458 | struct nouveau_pm_level *perflvl = info->perflvl; | ||
459 | int i; | ||
460 | |||
461 | for (i = 0; i < 5; i++) | ||
462 | nv_wr32(exec->dev, 0x10f290 + (i * 4), perflvl->timing.reg[i]); | ||
463 | } | ||
464 | |||
465 | static void | ||
466 | prog_mem(struct drm_device *dev, struct nvc0_pm_state *info) | ||
467 | { | ||
468 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
469 | struct nouveau_mem_exec_func exec = { | ||
470 | .dev = dev, | ||
471 | .precharge = mclk_precharge, | ||
472 | .refresh = mclk_refresh, | ||
473 | .refresh_auto = mclk_refresh_auto, | ||
474 | .refresh_self = mclk_refresh_self, | ||
475 | .wait = mclk_wait, | ||
476 | .mrg = mclk_mrg, | ||
477 | .mrs = mclk_mrs, | ||
478 | .clock_set = mclk_clock_set, | ||
479 | .timing_set = mclk_timing_set, | ||
480 | .priv = info | ||
481 | }; | ||
482 | |||
483 | if (dev_priv->chipset < 0xd0) | ||
484 | nv_wr32(dev, 0x611200, 0x00003300); | ||
485 | |||
486 | nouveau_mem_exec(&exec, info->perflvl); | ||
487 | |||
488 | if (dev_priv->chipset < 0xd0) | ||
489 | nv_wr32(dev, 0x611200, 0x00003300); | ||
490 | } | ||
378 | int | 491 | int |
379 | nvc0_pm_clocks_set(struct drm_device *dev, void *data) | 492 | nvc0_pm_clocks_set(struct drm_device *dev, void *data) |
380 | { | 493 | { |
381 | struct nvc0_pm_state *info = data; | 494 | struct nvc0_pm_state *info = data; |
382 | int i; | 495 | int i; |
383 | 496 | ||
497 | if (0) | ||
498 | prog_mem(dev, info); | ||
499 | |||
384 | for (i = 0; i < 16; i++) { | 500 | for (i = 0; i < 16; i++) { |
385 | if (!info->eng[i].freq) | 501 | if (!info->eng[i].freq) |
386 | continue; | 502 | continue; |