diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/drm/nouveau/nv50_display.c | 189 |
1 files changed, 106 insertions, 83 deletions
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index e26caf63db0c..87a5a56ed358 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c | |||
@@ -55,9 +55,9 @@ | |||
55 | 55 | ||
56 | /* offsets in shared sync bo of various structures */ | 56 | /* offsets in shared sync bo of various structures */ |
57 | #define EVO_SYNC(c, o) ((c) * 0x0100 + (o)) | 57 | #define EVO_SYNC(c, o) ((c) * 0x0100 + (o)) |
58 | #define EVO_MAST_NTFY EVO_SYNC( 0, 0x00) | 58 | #define EVO_MAST_NTFY EVO_SYNC( 0, 0x00) |
59 | #define EVO_FLIP_SEM0(c) EVO_SYNC((c), 0x00) | 59 | #define EVO_FLIP_SEM0(c) EVO_SYNC((c) + 1, 0x00) |
60 | #define EVO_FLIP_SEM1(c) EVO_SYNC((c), 0x10) | 60 | #define EVO_FLIP_SEM1(c) EVO_SYNC((c) + 1, 0x10) |
61 | 61 | ||
62 | #define EVO_CORE_HANDLE (0xd1500000) | 62 | #define EVO_CORE_HANDLE (0xd1500000) |
63 | #define EVO_CHAN_HANDLE(t,i) (0xd15c0000 | (((t) & 0x00ff) << 8) | (i)) | 63 | #define EVO_CHAN_HANDLE(t,i) (0xd15c0000 | (((t) & 0x00ff) << 8) | (i)) |
@@ -341,10 +341,8 @@ struct nv50_curs { | |||
341 | 341 | ||
342 | struct nv50_sync { | 342 | struct nv50_sync { |
343 | struct nv50_dmac base; | 343 | struct nv50_dmac base; |
344 | struct { | 344 | u32 addr; |
345 | u32 offset; | 345 | u32 data; |
346 | u16 value; | ||
347 | } sem; | ||
348 | }; | 346 | }; |
349 | 347 | ||
350 | struct nv50_ovly { | 348 | struct nv50_ovly { |
@@ -471,13 +469,33 @@ nv50_display_crtc_sema(struct drm_device *dev, int crtc) | |||
471 | return nv50_disp(dev)->sync; | 469 | return nv50_disp(dev)->sync; |
472 | } | 470 | } |
473 | 471 | ||
472 | struct nv50_display_flip { | ||
473 | struct nv50_disp *disp; | ||
474 | struct nv50_sync *chan; | ||
475 | }; | ||
476 | |||
477 | static bool | ||
478 | nv50_display_flip_wait(void *data) | ||
479 | { | ||
480 | struct nv50_display_flip *flip = data; | ||
481 | if (nouveau_bo_rd32(flip->disp->sync, flip->chan->addr / 4) == | ||
482 | flip->chan->data); | ||
483 | return true; | ||
484 | usleep_range(1, 2); | ||
485 | return false; | ||
486 | } | ||
487 | |||
474 | void | 488 | void |
475 | nv50_display_flip_stop(struct drm_crtc *crtc) | 489 | nv50_display_flip_stop(struct drm_crtc *crtc) |
476 | { | 490 | { |
477 | struct nv50_sync *sync = nv50_sync(crtc); | 491 | struct nouveau_device *device = nouveau_dev(crtc->dev); |
492 | struct nv50_display_flip flip = { | ||
493 | .disp = nv50_disp(crtc->dev), | ||
494 | .chan = nv50_sync(crtc), | ||
495 | }; | ||
478 | u32 *push; | 496 | u32 *push; |
479 | 497 | ||
480 | push = evo_wait(sync, 8); | 498 | push = evo_wait(flip.chan, 8); |
481 | if (push) { | 499 | if (push) { |
482 | evo_mthd(push, 0x0084, 1); | 500 | evo_mthd(push, 0x0084, 1); |
483 | evo_data(push, 0x00000000); | 501 | evo_data(push, 0x00000000); |
@@ -487,8 +505,10 @@ nv50_display_flip_stop(struct drm_crtc *crtc) | |||
487 | evo_data(push, 0x00000000); | 505 | evo_data(push, 0x00000000); |
488 | evo_mthd(push, 0x0080, 1); | 506 | evo_mthd(push, 0x0080, 1); |
489 | evo_data(push, 0x00000000); | 507 | evo_data(push, 0x00000000); |
490 | evo_kick(push, sync); | 508 | evo_kick(push, flip.chan); |
491 | } | 509 | } |
510 | |||
511 | nv_wait_cb(device, nv50_display_flip_wait, &flip); | ||
492 | } | 512 | } |
493 | 513 | ||
494 | int | 514 | int |
@@ -496,11 +516,10 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, | |||
496 | struct nouveau_channel *chan, u32 swap_interval) | 516 | struct nouveau_channel *chan, u32 swap_interval) |
497 | { | 517 | { |
498 | struct nouveau_framebuffer *nv_fb = nouveau_framebuffer(fb); | 518 | struct nouveau_framebuffer *nv_fb = nouveau_framebuffer(fb); |
499 | struct nv50_disp *disp = nv50_disp(crtc->dev); | ||
500 | struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); | 519 | struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); |
501 | struct nv50_sync *sync = nv50_sync(crtc); | 520 | struct nv50_sync *sync = nv50_sync(crtc); |
521 | int head = nv_crtc->index, ret; | ||
502 | u32 *push; | 522 | u32 *push; |
503 | int ret; | ||
504 | 523 | ||
505 | swap_interval <<= 4; | 524 | swap_interval <<= 4; |
506 | if (swap_interval == 0) | 525 | if (swap_interval == 0) |
@@ -510,66 +529,64 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, | |||
510 | if (unlikely(push == NULL)) | 529 | if (unlikely(push == NULL)) |
511 | return -EBUSY; | 530 | return -EBUSY; |
512 | 531 | ||
513 | /* synchronise with the rendering channel, if necessary */ | 532 | if (chan && nv_mclass(chan->object) < NV84_CHANNEL_IND_CLASS) { |
514 | if (likely(chan)) { | 533 | ret = RING_SPACE(chan, 8); |
515 | if (nv_mclass(chan->object) < NV84_CHANNEL_IND_CLASS) { | 534 | if (ret) |
516 | ret = RING_SPACE(chan, 8); | 535 | return ret; |
517 | if (ret) | 536 | |
518 | return ret; | 537 | BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 2); |
519 | 538 | OUT_RING (chan, NvEvoSema0 + head); | |
520 | BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 2); | 539 | OUT_RING (chan, sync->addr ^ 0x10); |
521 | OUT_RING (chan, NvEvoSema0 + nv_crtc->index); | 540 | BEGIN_NV04(chan, 0, NV11_SUBCHAN_SEMAPHORE_RELEASE, 1); |
522 | OUT_RING (chan, sync->sem.offset); | 541 | OUT_RING (chan, sync->data + 1); |
523 | BEGIN_NV04(chan, 0, NV11_SUBCHAN_SEMAPHORE_RELEASE, 1); | 542 | BEGIN_NV04(chan, 0, NV11_SUBCHAN_SEMAPHORE_OFFSET, 2); |
524 | OUT_RING (chan, 0xf00d0000 | sync->sem.value); | 543 | OUT_RING (chan, sync->addr); |
525 | BEGIN_NV04(chan, 0, NV11_SUBCHAN_SEMAPHORE_OFFSET, 2); | 544 | OUT_RING (chan, sync->data); |
526 | OUT_RING (chan, sync->sem.offset ^ 0x10); | 545 | } else |
527 | OUT_RING (chan, 0x74b1e000); | 546 | if (chan && nv_mclass(chan->object) < NVC0_CHANNEL_IND_CLASS) { |
528 | } else | 547 | u64 addr = nv84_fence_crtc(chan, head) + sync->addr; |
529 | if (nv_mclass(chan->object) < NVC0_CHANNEL_IND_CLASS) { | 548 | ret = RING_SPACE(chan, 12); |
530 | u64 offset = nv84_fence_crtc(chan, nv_crtc->index); | 549 | if (ret) |
531 | offset += sync->sem.offset; | 550 | return ret; |
532 | 551 | ||
533 | ret = RING_SPACE(chan, 12); | 552 | BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 1); |
534 | if (ret) | 553 | OUT_RING (chan, chan->vram); |
535 | return ret; | 554 | BEGIN_NV04(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4); |
536 | 555 | OUT_RING (chan, upper_32_bits(addr ^ 0x10)); | |
537 | BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 1); | 556 | OUT_RING (chan, lower_32_bits(addr ^ 0x10)); |
538 | OUT_RING (chan, chan->vram); | 557 | OUT_RING (chan, sync->data + 1); |
539 | BEGIN_NV04(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4); | 558 | OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_WRITE_LONG); |
540 | OUT_RING (chan, upper_32_bits(offset)); | 559 | BEGIN_NV04(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4); |
541 | OUT_RING (chan, lower_32_bits(offset)); | 560 | OUT_RING (chan, upper_32_bits(addr)); |
542 | OUT_RING (chan, 0xf00d0000 | sync->sem.value); | 561 | OUT_RING (chan, lower_32_bits(addr)); |
543 | OUT_RING (chan, 0x00000002); | 562 | OUT_RING (chan, sync->data); |
544 | BEGIN_NV04(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4); | 563 | OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_EQUAL); |
545 | OUT_RING (chan, upper_32_bits(offset)); | 564 | } else |
546 | OUT_RING (chan, lower_32_bits(offset ^ 0x10)); | 565 | if (chan) { |
547 | OUT_RING (chan, 0x74b1e000); | 566 | u64 addr = nv84_fence_crtc(chan, head) + sync->addr; |
548 | OUT_RING (chan, 0x00000001); | 567 | ret = RING_SPACE(chan, 10); |
549 | } else { | 568 | if (ret) |
550 | u64 offset = nv84_fence_crtc(chan, nv_crtc->index); | 569 | return ret; |
551 | offset += sync->sem.offset; | 570 | |
552 | 571 | BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4); | |
553 | ret = RING_SPACE(chan, 10); | 572 | OUT_RING (chan, upper_32_bits(addr ^ 0x10)); |
554 | if (ret) | 573 | OUT_RING (chan, lower_32_bits(addr ^ 0x10)); |
555 | return ret; | 574 | OUT_RING (chan, sync->data + 1); |
556 | 575 | OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_WRITE_LONG | | |
557 | BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4); | 576 | NVC0_SUBCHAN_SEMAPHORE_TRIGGER_YIELD); |
558 | OUT_RING (chan, upper_32_bits(offset)); | 577 | BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4); |
559 | OUT_RING (chan, lower_32_bits(offset)); | 578 | OUT_RING (chan, upper_32_bits(addr)); |
560 | OUT_RING (chan, 0xf00d0000 | sync->sem.value); | 579 | OUT_RING (chan, lower_32_bits(addr)); |
561 | OUT_RING (chan, 0x00001002); | 580 | OUT_RING (chan, sync->data); |
562 | BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4); | 581 | OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_EQUAL | |
563 | OUT_RING (chan, upper_32_bits(offset)); | 582 | NVC0_SUBCHAN_SEMAPHORE_TRIGGER_YIELD); |
564 | OUT_RING (chan, lower_32_bits(offset ^ 0x10)); | 583 | } |
565 | OUT_RING (chan, 0x74b1e000); | ||
566 | OUT_RING (chan, 0x00001001); | ||
567 | } | ||
568 | 584 | ||
585 | if (chan) { | ||
586 | sync->addr ^= 0x10; | ||
587 | sync->data++; | ||
569 | FIRE_RING (chan); | 588 | FIRE_RING (chan); |
570 | } else { | 589 | } else { |
571 | nouveau_bo_wr32(disp->sync, sync->sem.offset / 4, | ||
572 | 0xf00d0000 | sync->sem.value); | ||
573 | evo_sync(crtc->dev); | 590 | evo_sync(crtc->dev); |
574 | } | 591 | } |
575 | 592 | ||
@@ -583,9 +600,9 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, | |||
583 | evo_data(push, 0x40000000); | 600 | evo_data(push, 0x40000000); |
584 | } | 601 | } |
585 | evo_mthd(push, 0x0088, 4); | 602 | evo_mthd(push, 0x0088, 4); |
586 | evo_data(push, sync->sem.offset); | 603 | evo_data(push, sync->addr); |
587 | evo_data(push, 0xf00d0000 | sync->sem.value); | 604 | evo_data(push, sync->data++); |
588 | evo_data(push, 0x74b1e000); | 605 | evo_data(push, sync->data); |
589 | evo_data(push, NvEvoSync); | 606 | evo_data(push, NvEvoSync); |
590 | evo_mthd(push, 0x00a0, 2); | 607 | evo_mthd(push, 0x00a0, 2); |
591 | evo_data(push, 0x00000000); | 608 | evo_data(push, 0x00000000); |
@@ -613,9 +630,6 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, | |||
613 | evo_mthd(push, 0x0080, 1); | 630 | evo_mthd(push, 0x0080, 1); |
614 | evo_data(push, 0x00000000); | 631 | evo_data(push, 0x00000000); |
615 | evo_kick(push, sync); | 632 | evo_kick(push, sync); |
616 | |||
617 | sync->sem.offset ^= 0x10; | ||
618 | sync->sem.value++; | ||
619 | return 0; | 633 | return 0; |
620 | } | 634 | } |
621 | 635 | ||
@@ -1387,7 +1401,8 @@ nv50_crtc_create(struct drm_device *dev, struct nouveau_object *core, int index) | |||
1387 | if (ret) | 1401 | if (ret) |
1388 | goto out; | 1402 | goto out; |
1389 | 1403 | ||
1390 | head->sync.sem.offset = EVO_SYNC(1 + index, 0x00); | 1404 | head->sync.addr = EVO_FLIP_SEM0(index); |
1405 | head->sync.data = 0x00000000; | ||
1391 | 1406 | ||
1392 | /* allocate overlay resources */ | 1407 | /* allocate overlay resources */ |
1393 | ret = nv50_pioc_create(disp->core, NV50_DISP_OIMM_CLASS, index, | 1408 | ret = nv50_pioc_create(disp->core, NV50_DISP_OIMM_CLASS, index, |
@@ -2120,15 +2135,23 @@ nv50_display_fini(struct drm_device *dev) | |||
2120 | int | 2135 | int |
2121 | nv50_display_init(struct drm_device *dev) | 2136 | nv50_display_init(struct drm_device *dev) |
2122 | { | 2137 | { |
2123 | u32 *push = evo_wait(nv50_mast(dev), 32); | 2138 | struct nv50_disp *disp = nv50_disp(dev); |
2124 | if (push) { | 2139 | struct drm_crtc *crtc; |
2125 | evo_mthd(push, 0x0088, 1); | 2140 | u32 *push; |
2126 | evo_data(push, NvEvoSync); | 2141 | |
2127 | evo_kick(push, nv50_mast(dev)); | 2142 | push = evo_wait(nv50_mast(dev), 32); |
2128 | return 0; | 2143 | if (!push) |
2144 | return -EBUSY; | ||
2145 | |||
2146 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | ||
2147 | struct nv50_sync *sync = nv50_sync(crtc); | ||
2148 | nouveau_bo_wr32(disp->sync, sync->addr / 4, sync->data); | ||
2129 | } | 2149 | } |
2130 | 2150 | ||
2131 | return -EBUSY; | 2151 | evo_mthd(push, 0x0088, 1); |
2152 | evo_data(push, NvEvoSync); | ||
2153 | evo_kick(push, nv50_mast(dev)); | ||
2154 | return 0; | ||
2132 | } | 2155 | } |
2133 | 2156 | ||
2134 | void | 2157 | void |