diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2011-02-06 22:29:23 -0500 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2011-02-24 15:45:11 -0500 |
commit | cdccc70eff1eaf3627a716374f9ebc115fc4621c (patch) | |
tree | 744a5a9e35c5749326d3bfb85336afceb24c2b4d /drivers/gpu/drm/nouveau/nv50_display.c | |
parent | 45c4e0aae96c6354bf5131a282a74fe38d032de3 (diff) |
drm/nv50-nvc0: initialise display sync channels
Also imports a couple of helper functions that'll be used to implement
page flipping in the following commits..
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau/nv50_display.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nv50_display.c | 123 |
1 files changed, 122 insertions, 1 deletions
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 09d7994ea099..75a376cc342a 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c | |||
@@ -178,7 +178,7 @@ nv50_display_init(struct drm_device *dev) | |||
178 | 178 | ||
179 | nv_wr32(dev, NV50_PDISPLAY_OBJECTS, (evo->ramin->vinst >> 8) | 9); | 179 | nv_wr32(dev, NV50_PDISPLAY_OBJECTS, (evo->ramin->vinst >> 8) | 9); |
180 | 180 | ||
181 | ret = RING_SPACE(evo, 11); | 181 | ret = RING_SPACE(evo, 15); |
182 | if (ret) | 182 | if (ret) |
183 | return ret; | 183 | return ret; |
184 | BEGIN_RING(evo, 0, NV50_EVO_UNK84, 2); | 184 | BEGIN_RING(evo, 0, NV50_EVO_UNK84, 2); |
@@ -192,6 +192,11 @@ nv50_display_init(struct drm_device *dev) | |||
192 | OUT_RING(evo, 0); | 192 | OUT_RING(evo, 0); |
193 | BEGIN_RING(evo, 0, NV50_EVO_CRTC(0, UNK082C), 1); | 193 | BEGIN_RING(evo, 0, NV50_EVO_CRTC(0, UNK082C), 1); |
194 | OUT_RING(evo, 0); | 194 | OUT_RING(evo, 0); |
195 | /* required to make display sync channels not hate life */ | ||
196 | BEGIN_RING(evo, 0, NV50_EVO_CRTC(0, UNK900), 1); | ||
197 | OUT_RING (evo, 0x00000311); | ||
198 | BEGIN_RING(evo, 0, NV50_EVO_CRTC(1, UNK900), 1); | ||
199 | OUT_RING (evo, 0x00000311); | ||
195 | FIRE_RING(evo); | 200 | FIRE_RING(evo); |
196 | if (!nv_wait(dev, 0x640004, 0xffffffff, evo->dma.put << 2)) | 201 | if (!nv_wait(dev, 0x640004, 0xffffffff, evo->dma.put << 2)) |
197 | NV_ERROR(dev, "evo pushbuf stalled\n"); | 202 | NV_ERROR(dev, "evo pushbuf stalled\n"); |
@@ -366,6 +371,122 @@ nv50_display_destroy(struct drm_device *dev) | |||
366 | kfree(disp); | 371 | kfree(disp); |
367 | } | 372 | } |
368 | 373 | ||
374 | void | ||
375 | nv50_display_flip_stop(struct drm_crtc *crtc) | ||
376 | { | ||
377 | struct nv50_display *disp = nv50_display(crtc->dev); | ||
378 | struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); | ||
379 | struct nv50_display_crtc *dispc = &disp->crtc[nv_crtc->index]; | ||
380 | struct nouveau_channel *evo = dispc->sync; | ||
381 | int ret; | ||
382 | |||
383 | ret = RING_SPACE(evo, 8); | ||
384 | if (ret) { | ||
385 | WARN_ON(1); | ||
386 | return; | ||
387 | } | ||
388 | |||
389 | BEGIN_RING(evo, 0, 0x0084, 1); | ||
390 | OUT_RING (evo, 0x00000000); | ||
391 | BEGIN_RING(evo, 0, 0x0094, 1); | ||
392 | OUT_RING (evo, 0x00000000); | ||
393 | BEGIN_RING(evo, 0, 0x00c0, 1); | ||
394 | OUT_RING (evo, 0x00000000); | ||
395 | BEGIN_RING(evo, 0, 0x0080, 1); | ||
396 | OUT_RING (evo, 0x00000000); | ||
397 | FIRE_RING (evo); | ||
398 | } | ||
399 | |||
400 | int | ||
401 | nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, | ||
402 | struct nouveau_channel *chan) | ||
403 | { | ||
404 | struct drm_nouveau_private *dev_priv = crtc->dev->dev_private; | ||
405 | struct nouveau_framebuffer *nv_fb = nouveau_framebuffer(fb); | ||
406 | struct nv50_display *disp = nv50_display(crtc->dev); | ||
407 | struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); | ||
408 | struct nv50_display_crtc *dispc = &disp->crtc[nv_crtc->index]; | ||
409 | struct nouveau_channel *evo = dispc->sync; | ||
410 | int ret; | ||
411 | |||
412 | ret = RING_SPACE(evo, 24); | ||
413 | if (unlikely(ret)) | ||
414 | return ret; | ||
415 | |||
416 | /* synchronise with the rendering channel, if necessary */ | ||
417 | if (likely(chan)) { | ||
418 | u64 offset = dispc->sem.bo->vma.offset + dispc->sem.offset; | ||
419 | |||
420 | ret = RING_SPACE(chan, 10); | ||
421 | if (ret) { | ||
422 | WIND_RING(evo); | ||
423 | return ret; | ||
424 | } | ||
425 | |||
426 | if (dev_priv->chipset < 0xc0) { | ||
427 | BEGIN_RING(chan, NvSubSw, 0x0060, 2); | ||
428 | OUT_RING (chan, NvEvoSema0 + nv_crtc->index); | ||
429 | OUT_RING (chan, dispc->sem.offset); | ||
430 | BEGIN_RING(chan, NvSubSw, 0x006c, 1); | ||
431 | OUT_RING (chan, 0xf00d0000 | dispc->sem.value); | ||
432 | BEGIN_RING(chan, NvSubSw, 0x0064, 2); | ||
433 | OUT_RING (chan, dispc->sem.offset ^ 0x10); | ||
434 | OUT_RING (chan, 0x74b1e000); | ||
435 | BEGIN_RING(chan, NvSubSw, 0x0060, 1); | ||
436 | if (dev_priv->chipset < 0x84) | ||
437 | OUT_RING (chan, NvSema); | ||
438 | else | ||
439 | OUT_RING (chan, chan->vram_handle); | ||
440 | } else { | ||
441 | BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0010, 4); | ||
442 | OUT_RING (chan, upper_32_bits(offset)); | ||
443 | OUT_RING (chan, lower_32_bits(offset)); | ||
444 | OUT_RING (chan, 0xf00d0000 | dispc->sem.value); | ||
445 | OUT_RING (chan, 0x1002); | ||
446 | BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0010, 4); | ||
447 | OUT_RING (chan, upper_32_bits(offset)); | ||
448 | OUT_RING (chan, lower_32_bits(offset ^ 0x10)); | ||
449 | OUT_RING (chan, 0x74b1e000); | ||
450 | OUT_RING (chan, 0x1001); | ||
451 | } | ||
452 | FIRE_RING (chan); | ||
453 | } else { | ||
454 | nouveau_bo_wr32(dispc->sem.bo, dispc->sem.offset / 4, | ||
455 | 0xf00d0000 | dispc->sem.value); | ||
456 | } | ||
457 | |||
458 | /* queue the flip on the crtc's "display sync" channel */ | ||
459 | BEGIN_RING(evo, 0, 0x0100, 1); | ||
460 | OUT_RING (evo, 0xfffe0000); | ||
461 | BEGIN_RING(evo, 0, 0x0084, 5); | ||
462 | OUT_RING (evo, chan ? 0x00000100 : 0x00000010); | ||
463 | OUT_RING (evo, dispc->sem.offset); | ||
464 | OUT_RING (evo, 0xf00d0000 | dispc->sem.value); | ||
465 | OUT_RING (evo, 0x74b1e000); | ||
466 | OUT_RING (evo, NvEvoSync); | ||
467 | BEGIN_RING(evo, 0, 0x00a0, 2); | ||
468 | OUT_RING (evo, 0x00000000); | ||
469 | OUT_RING (evo, 0x00000000); | ||
470 | BEGIN_RING(evo, 0, 0x00c0, 1); | ||
471 | OUT_RING (evo, nv_fb->r_dma); | ||
472 | BEGIN_RING(evo, 0, 0x0110, 2); | ||
473 | OUT_RING (evo, 0x00000000); | ||
474 | OUT_RING (evo, 0x00000000); | ||
475 | BEGIN_RING(evo, 0, 0x0800, 5); | ||
476 | OUT_RING (evo, (nv_fb->nvbo->bo.mem.start << PAGE_SHIFT) >> 8); | ||
477 | OUT_RING (evo, 0); | ||
478 | OUT_RING (evo, (fb->height << 16) | fb->width); | ||
479 | OUT_RING (evo, nv_fb->r_pitch); | ||
480 | OUT_RING (evo, nv_fb->r_format); | ||
481 | BEGIN_RING(evo, 0, 0x0080, 1); | ||
482 | OUT_RING (evo, 0x00000000); | ||
483 | FIRE_RING (evo); | ||
484 | |||
485 | dispc->sem.offset ^= 0x10; | ||
486 | dispc->sem.value++; | ||
487 | return 0; | ||
488 | } | ||
489 | |||
369 | static u16 | 490 | static u16 |
370 | nv50_display_script_select(struct drm_device *dev, struct dcb_entry *dcb, | 491 | nv50_display_script_select(struct drm_device *dev, struct dcb_entry *dcb, |
371 | u32 mc, int pxclk) | 492 | u32 mc, int pxclk) |