diff options
author | Boris Brezillon <boris.brezillon@free-electrons.com> | 2017-06-22 16:25:26 -0400 |
---|---|---|
committer | Eric Anholt <eric@anholt.net> | 2017-07-14 16:19:48 -0400 |
commit | 1ed134e6526b1b513a14fba938f6d96aa1c7f3dd (patch) | |
tree | d57d2e7a6373cf7d9536d30f7b65c84dc462733f | |
parent | 6f6e0b217a93011f8e11b9a2d5521a08fcf36990 (diff) |
drm/vc4: Fix VBLANK handling in crtc->enable() path
When we are enabling a CRTC, drm_crtc_vblank_get() is called before
drm_crtc_vblank_on(), which is not supposed to happen (hence the
WARN_ON() in the code). To solve the problem, we delay the 'update
display list' operation after the CRTC is actually enabled.
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Reviewed-by: Eric Anholt <eric@anholt.net>
Link: http://patchwork.freedesktop.org/patch/msgid/1498163126-26678-1-git-send-email-boris.brezillon@free-electrons.com
Fixes: 34c8ea400ff6 ("drm/vc4: Mimic drm_atomic_helper_commit() behavior")
-rw-r--r-- | drivers/gpu/drm/vc4/vc4_crtc.c | 66 |
1 files changed, 43 insertions, 23 deletions
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c index 403bbd5f99a9..a12cc7ea99b6 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c | |||
@@ -520,6 +520,34 @@ static void vc4_crtc_disable(struct drm_crtc *crtc) | |||
520 | SCALER_DISPSTATX_EMPTY); | 520 | SCALER_DISPSTATX_EMPTY); |
521 | } | 521 | } |
522 | 522 | ||
523 | static void vc4_crtc_update_dlist(struct drm_crtc *crtc) | ||
524 | { | ||
525 | struct drm_device *dev = crtc->dev; | ||
526 | struct vc4_dev *vc4 = to_vc4_dev(dev); | ||
527 | struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); | ||
528 | struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state); | ||
529 | |||
530 | if (crtc->state->event) { | ||
531 | unsigned long flags; | ||
532 | |||
533 | crtc->state->event->pipe = drm_crtc_index(crtc); | ||
534 | |||
535 | WARN_ON(drm_crtc_vblank_get(crtc) != 0); | ||
536 | |||
537 | spin_lock_irqsave(&dev->event_lock, flags); | ||
538 | vc4_crtc->event = crtc->state->event; | ||
539 | crtc->state->event = NULL; | ||
540 | |||
541 | HVS_WRITE(SCALER_DISPLISTX(vc4_crtc->channel), | ||
542 | vc4_state->mm.start); | ||
543 | |||
544 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
545 | } else { | ||
546 | HVS_WRITE(SCALER_DISPLISTX(vc4_crtc->channel), | ||
547 | vc4_state->mm.start); | ||
548 | } | ||
549 | } | ||
550 | |||
523 | static void vc4_crtc_enable(struct drm_crtc *crtc) | 551 | static void vc4_crtc_enable(struct drm_crtc *crtc) |
524 | { | 552 | { |
525 | struct drm_device *dev = crtc->dev; | 553 | struct drm_device *dev = crtc->dev; |
@@ -530,6 +558,12 @@ static void vc4_crtc_enable(struct drm_crtc *crtc) | |||
530 | 558 | ||
531 | require_hvs_enabled(dev); | 559 | require_hvs_enabled(dev); |
532 | 560 | ||
561 | /* Enable vblank irq handling before crtc is started otherwise | ||
562 | * drm_crtc_get_vblank() fails in vc4_crtc_update_dlist(). | ||
563 | */ | ||
564 | drm_crtc_vblank_on(crtc); | ||
565 | vc4_crtc_update_dlist(crtc); | ||
566 | |||
533 | /* Turn on the scaler, which will wait for vstart to start | 567 | /* Turn on the scaler, which will wait for vstart to start |
534 | * compositing. | 568 | * compositing. |
535 | */ | 569 | */ |
@@ -541,9 +575,6 @@ static void vc4_crtc_enable(struct drm_crtc *crtc) | |||
541 | /* Turn on the pixel valve, which will emit the vstart signal. */ | 575 | /* Turn on the pixel valve, which will emit the vstart signal. */ |
542 | CRTC_WRITE(PV_V_CONTROL, | 576 | CRTC_WRITE(PV_V_CONTROL, |
543 | CRTC_READ(PV_V_CONTROL) | PV_VCONTROL_VIDEN); | 577 | CRTC_READ(PV_V_CONTROL) | PV_VCONTROL_VIDEN); |
544 | |||
545 | /* Enable vblank irq handling after crtc is started. */ | ||
546 | drm_crtc_vblank_on(crtc); | ||
547 | } | 578 | } |
548 | 579 | ||
549 | static bool vc4_crtc_mode_fixup(struct drm_crtc *crtc, | 580 | static bool vc4_crtc_mode_fixup(struct drm_crtc *crtc, |
@@ -598,7 +629,6 @@ static void vc4_crtc_atomic_flush(struct drm_crtc *crtc, | |||
598 | { | 629 | { |
599 | struct drm_device *dev = crtc->dev; | 630 | struct drm_device *dev = crtc->dev; |
600 | struct vc4_dev *vc4 = to_vc4_dev(dev); | 631 | struct vc4_dev *vc4 = to_vc4_dev(dev); |
601 | struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); | ||
602 | struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state); | 632 | struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state); |
603 | struct drm_plane *plane; | 633 | struct drm_plane *plane; |
604 | bool debug_dump_regs = false; | 634 | bool debug_dump_regs = false; |
@@ -620,25 +650,15 @@ static void vc4_crtc_atomic_flush(struct drm_crtc *crtc, | |||
620 | 650 | ||
621 | WARN_ON_ONCE(dlist_next - dlist_start != vc4_state->mm.size); | 651 | WARN_ON_ONCE(dlist_next - dlist_start != vc4_state->mm.size); |
622 | 652 | ||
623 | if (crtc->state->event) { | 653 | /* Only update DISPLIST if the CRTC was already running and is not |
624 | unsigned long flags; | 654 | * being disabled. |
625 | 655 | * vc4_crtc_enable() takes care of updating the dlist just after | |
626 | crtc->state->event->pipe = drm_crtc_index(crtc); | 656 | * re-enabling VBLANK interrupts and before enabling the engine. |
627 | 657 | * If the CRTC is being disabled, there's no point in updating this | |
628 | WARN_ON(drm_crtc_vblank_get(crtc) != 0); | 658 | * information. |
629 | 659 | */ | |
630 | spin_lock_irqsave(&dev->event_lock, flags); | 660 | if (crtc->state->active && old_state->active) |
631 | vc4_crtc->event = crtc->state->event; | 661 | vc4_crtc_update_dlist(crtc); |
632 | crtc->state->event = NULL; | ||
633 | |||
634 | HVS_WRITE(SCALER_DISPLISTX(vc4_crtc->channel), | ||
635 | vc4_state->mm.start); | ||
636 | |||
637 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
638 | } else { | ||
639 | HVS_WRITE(SCALER_DISPLISTX(vc4_crtc->channel), | ||
640 | vc4_state->mm.start); | ||
641 | } | ||
642 | 662 | ||
643 | if (debug_dump_regs) { | 663 | if (debug_dump_regs) { |
644 | DRM_INFO("CRTC %d HVS after:\n", drm_crtc_index(crtc)); | 664 | DRM_INFO("CRTC %d HVS after:\n", drm_crtc_index(crtc)); |