diff options
| -rw-r--r-- | drivers/gpu/drm/msm/mdp4/mdp4_crtc.c | 61 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/mdp4/mdp4_kms.c | 2 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/mdp4/mdp4_kms.h | 2 |
3 files changed, 50 insertions, 15 deletions
diff --git a/drivers/gpu/drm/msm/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/mdp4/mdp4_crtc.c index 1d52896dfa89..019d530187ff 100644 --- a/drivers/gpu/drm/msm/mdp4/mdp4_crtc.c +++ b/drivers/gpu/drm/msm/mdp4/mdp4_crtc.c | |||
| @@ -53,6 +53,10 @@ struct mdp4_crtc { | |||
| 53 | struct drm_pending_vblank_event *event; | 53 | struct drm_pending_vblank_event *event; |
| 54 | struct msm_fence_cb pageflip_cb; | 54 | struct msm_fence_cb pageflip_cb; |
| 55 | 55 | ||
| 56 | #define PENDING_CURSOR 0x1 | ||
| 57 | #define PENDING_FLIP 0x2 | ||
| 58 | atomic_t pending; | ||
| 59 | |||
| 56 | /* the fb that we currently hold a scanout ref to: */ | 60 | /* the fb that we currently hold a scanout ref to: */ |
| 57 | struct drm_framebuffer *fb; | 61 | struct drm_framebuffer *fb; |
| 58 | 62 | ||
| @@ -93,7 +97,8 @@ static void update_fb(struct drm_crtc *crtc, bool async, | |||
| 93 | } | 97 | } |
| 94 | } | 98 | } |
| 95 | 99 | ||
| 96 | static void complete_flip(struct drm_crtc *crtc, bool canceled) | 100 | /* if file!=NULL, this is preclose potential cancel-flip path */ |
| 101 | static void complete_flip(struct drm_crtc *crtc, struct drm_file *file) | ||
| 97 | { | 102 | { |
| 98 | struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); | 103 | struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); |
| 99 | struct drm_device *dev = crtc->dev; | 104 | struct drm_device *dev = crtc->dev; |
| @@ -103,11 +108,14 @@ static void complete_flip(struct drm_crtc *crtc, bool canceled) | |||
| 103 | spin_lock_irqsave(&dev->event_lock, flags); | 108 | spin_lock_irqsave(&dev->event_lock, flags); |
| 104 | event = mdp4_crtc->event; | 109 | event = mdp4_crtc->event; |
| 105 | if (event) { | 110 | if (event) { |
| 106 | mdp4_crtc->event = NULL; | 111 | /* if regular vblank case (!file) or if cancel-flip from |
| 107 | if (canceled) | 112 | * preclose on file that requested flip, then send the |
| 108 | event->base.destroy(&event->base); | 113 | * event: |
| 109 | else | 114 | */ |
| 115 | if (!file || (event->base.file_priv == file)) { | ||
| 116 | mdp4_crtc->event = NULL; | ||
| 110 | drm_send_vblank_event(dev, mdp4_crtc->id, event); | 117 | drm_send_vblank_event(dev, mdp4_crtc->id, event); |
| 118 | } | ||
| 111 | } | 119 | } |
| 112 | spin_unlock_irqrestore(&dev->event_lock, flags); | 120 | spin_unlock_irqrestore(&dev->event_lock, flags); |
| 113 | } | 121 | } |
| @@ -132,17 +140,29 @@ static void crtc_flush(struct drm_crtc *crtc) | |||
| 132 | mdp4_write(mdp4_kms, REG_MDP4_OVERLAY_FLUSH, flush); | 140 | mdp4_write(mdp4_kms, REG_MDP4_OVERLAY_FLUSH, flush); |
| 133 | } | 141 | } |
| 134 | 142 | ||
| 143 | static void request_pending(struct drm_crtc *crtc, uint32_t pending) | ||
| 144 | { | ||
| 145 | struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); | ||
| 146 | |||
| 147 | atomic_or(pending, &mdp4_crtc->pending); | ||
| 148 | mdp4_irq_register(get_kms(crtc), &mdp4_crtc->vblank); | ||
| 149 | } | ||
| 150 | |||
| 135 | static void pageflip_cb(struct msm_fence_cb *cb) | 151 | static void pageflip_cb(struct msm_fence_cb *cb) |
| 136 | { | 152 | { |
| 137 | struct mdp4_crtc *mdp4_crtc = | 153 | struct mdp4_crtc *mdp4_crtc = |
| 138 | container_of(cb, struct mdp4_crtc, pageflip_cb); | 154 | container_of(cb, struct mdp4_crtc, pageflip_cb); |
| 139 | struct drm_crtc *crtc = &mdp4_crtc->base; | 155 | struct drm_crtc *crtc = &mdp4_crtc->base; |
| 156 | struct drm_framebuffer *fb = crtc->fb; | ||
| 157 | |||
| 158 | if (!fb) | ||
| 159 | return; | ||
| 140 | 160 | ||
| 141 | mdp4_plane_set_scanout(mdp4_crtc->plane, crtc->fb); | 161 | mdp4_plane_set_scanout(mdp4_crtc->plane, fb); |
| 142 | crtc_flush(crtc); | 162 | crtc_flush(crtc); |
| 143 | 163 | ||
| 144 | /* enable vblank to complete flip: */ | 164 | /* enable vblank to complete flip: */ |
| 145 | mdp4_irq_register(get_kms(crtc), &mdp4_crtc->vblank); | 165 | request_pending(crtc, PENDING_FLIP); |
| 146 | } | 166 | } |
| 147 | 167 | ||
| 148 | static void unref_fb_worker(struct drm_flip_work *work, void *val) | 168 | static void unref_fb_worker(struct drm_flip_work *work, void *val) |
| @@ -386,6 +406,7 @@ static int mdp4_crtc_page_flip(struct drm_crtc *crtc, | |||
| 386 | struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); | 406 | struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); |
| 387 | struct drm_device *dev = crtc->dev; | 407 | struct drm_device *dev = crtc->dev; |
| 388 | struct drm_gem_object *obj; | 408 | struct drm_gem_object *obj; |
| 409 | unsigned long flags; | ||
| 389 | 410 | ||
| 390 | if (mdp4_crtc->event) { | 411 | if (mdp4_crtc->event) { |
| 391 | dev_err(dev->dev, "already pending flip!\n"); | 412 | dev_err(dev->dev, "already pending flip!\n"); |
| @@ -394,7 +415,10 @@ static int mdp4_crtc_page_flip(struct drm_crtc *crtc, | |||
| 394 | 415 | ||
| 395 | obj = msm_framebuffer_bo(new_fb, 0); | 416 | obj = msm_framebuffer_bo(new_fb, 0); |
| 396 | 417 | ||
| 418 | spin_lock_irqsave(&dev->event_lock, flags); | ||
| 397 | mdp4_crtc->event = event; | 419 | mdp4_crtc->event = event; |
| 420 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
| 421 | |||
| 398 | update_fb(crtc, true, new_fb); | 422 | update_fb(crtc, true, new_fb); |
| 399 | 423 | ||
| 400 | return msm_gem_queue_inactive_cb(obj, &mdp4_crtc->pageflip_cb); | 424 | return msm_gem_queue_inactive_cb(obj, &mdp4_crtc->pageflip_cb); |
| @@ -506,6 +530,8 @@ static int mdp4_crtc_cursor_set(struct drm_crtc *crtc, | |||
| 506 | drm_gem_object_unreference_unlocked(old_bo); | 530 | drm_gem_object_unreference_unlocked(old_bo); |
| 507 | } | 531 | } |
| 508 | 532 | ||
| 533 | request_pending(crtc, PENDING_CURSOR); | ||
| 534 | |||
| 509 | return 0; | 535 | return 0; |
| 510 | 536 | ||
| 511 | fail: | 537 | fail: |
| @@ -550,13 +576,21 @@ static void mdp4_crtc_vblank_irq(struct mdp4_irq *irq, uint32_t irqstatus) | |||
| 550 | struct mdp4_crtc *mdp4_crtc = container_of(irq, struct mdp4_crtc, vblank); | 576 | struct mdp4_crtc *mdp4_crtc = container_of(irq, struct mdp4_crtc, vblank); |
| 551 | struct drm_crtc *crtc = &mdp4_crtc->base; | 577 | struct drm_crtc *crtc = &mdp4_crtc->base; |
| 552 | struct msm_drm_private *priv = crtc->dev->dev_private; | 578 | struct msm_drm_private *priv = crtc->dev->dev_private; |
| 579 | unsigned pending; | ||
| 553 | 580 | ||
| 554 | update_cursor(crtc); | ||
| 555 | complete_flip(crtc, false); | ||
| 556 | mdp4_irq_unregister(get_kms(crtc), &mdp4_crtc->vblank); | 581 | mdp4_irq_unregister(get_kms(crtc), &mdp4_crtc->vblank); |
| 557 | 582 | ||
| 558 | drm_flip_work_commit(&mdp4_crtc->unref_fb_work, priv->wq); | 583 | pending = atomic_xchg(&mdp4_crtc->pending, 0); |
| 559 | drm_flip_work_commit(&mdp4_crtc->unref_cursor_work, priv->wq); | 584 | |
| 585 | if (pending & PENDING_FLIP) { | ||
| 586 | complete_flip(crtc, NULL); | ||
| 587 | drm_flip_work_commit(&mdp4_crtc->unref_fb_work, priv->wq); | ||
| 588 | } | ||
| 589 | |||
| 590 | if (pending & PENDING_CURSOR) { | ||
| 591 | update_cursor(crtc); | ||
| 592 | drm_flip_work_commit(&mdp4_crtc->unref_cursor_work, priv->wq); | ||
| 593 | } | ||
| 560 | } | 594 | } |
| 561 | 595 | ||
| 562 | static void mdp4_crtc_err_irq(struct mdp4_irq *irq, uint32_t irqstatus) | 596 | static void mdp4_crtc_err_irq(struct mdp4_irq *irq, uint32_t irqstatus) |
| @@ -573,9 +607,10 @@ uint32_t mdp4_crtc_vblank(struct drm_crtc *crtc) | |||
| 573 | return mdp4_crtc->vblank.irqmask; | 607 | return mdp4_crtc->vblank.irqmask; |
| 574 | } | 608 | } |
| 575 | 609 | ||
| 576 | void mdp4_crtc_cancel_pending_flip(struct drm_crtc *crtc) | 610 | void mdp4_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file) |
| 577 | { | 611 | { |
| 578 | complete_flip(crtc, true); | 612 | DBG("cancel: %p", file); |
| 613 | complete_flip(crtc, file); | ||
| 579 | } | 614 | } |
| 580 | 615 | ||
| 581 | /* set dma config, ie. the format the encoder wants. */ | 616 | /* set dma config, ie. the format the encoder wants. */ |
diff --git a/drivers/gpu/drm/msm/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/mdp4/mdp4_kms.c index c2485a71faa8..8972ac35a43d 100644 --- a/drivers/gpu/drm/msm/mdp4/mdp4_kms.c +++ b/drivers/gpu/drm/msm/mdp4/mdp4_kms.c | |||
| @@ -135,7 +135,7 @@ static void mdp4_preclose(struct msm_kms *kms, struct drm_file *file) | |||
| 135 | unsigned i; | 135 | unsigned i; |
| 136 | 136 | ||
| 137 | for (i = 0; i < priv->num_crtcs; i++) | 137 | for (i = 0; i < priv->num_crtcs; i++) |
| 138 | mdp4_crtc_cancel_pending_flip(priv->crtcs[i]); | 138 | mdp4_crtc_cancel_pending_flip(priv->crtcs[i], file); |
| 139 | } | 139 | } |
| 140 | 140 | ||
| 141 | static void mdp4_destroy(struct msm_kms *kms) | 141 | static void mdp4_destroy(struct msm_kms *kms) |
diff --git a/drivers/gpu/drm/msm/mdp4/mdp4_kms.h b/drivers/gpu/drm/msm/mdp4/mdp4_kms.h index 11c34387aeb6..eb015c834087 100644 --- a/drivers/gpu/drm/msm/mdp4/mdp4_kms.h +++ b/drivers/gpu/drm/msm/mdp4/mdp4_kms.h | |||
| @@ -207,7 +207,7 @@ struct drm_plane *mdp4_plane_init(struct drm_device *dev, | |||
| 207 | enum mdp4_pipe pipe_id, bool private_plane); | 207 | enum mdp4_pipe pipe_id, bool private_plane); |
| 208 | 208 | ||
| 209 | uint32_t mdp4_crtc_vblank(struct drm_crtc *crtc); | 209 | uint32_t mdp4_crtc_vblank(struct drm_crtc *crtc); |
| 210 | void mdp4_crtc_cancel_pending_flip(struct drm_crtc *crtc); | 210 | void mdp4_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file); |
| 211 | void mdp4_crtc_set_config(struct drm_crtc *crtc, uint32_t config); | 211 | void mdp4_crtc_set_config(struct drm_crtc *crtc, uint32_t config); |
| 212 | void mdp4_crtc_set_intf(struct drm_crtc *crtc, enum mdp4_intf intf); | 212 | void mdp4_crtc_set_intf(struct drm_crtc *crtc, enum mdp4_intf intf); |
| 213 | void mdp4_crtc_attach(struct drm_crtc *crtc, struct drm_plane *plane); | 213 | void mdp4_crtc_attach(struct drm_crtc *crtc, struct drm_plane *plane); |
