diff options
-rw-r--r-- | drivers/gpu/drm/drm_crtc.c | 26 | ||||
-rw-r--r-- | include/drm/drm_crtc.h | 18 |
2 files changed, 40 insertions, 4 deletions
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index b1dbb60af99f..a316f7336aeb 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c | |||
@@ -5402,6 +5402,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, | |||
5402 | struct drm_crtc *crtc; | 5402 | struct drm_crtc *crtc; |
5403 | struct drm_framebuffer *fb = NULL; | 5403 | struct drm_framebuffer *fb = NULL; |
5404 | struct drm_pending_vblank_event *e = NULL; | 5404 | struct drm_pending_vblank_event *e = NULL; |
5405 | u32 target_vblank = 0; | ||
5405 | int ret = -EINVAL; | 5406 | int ret = -EINVAL; |
5406 | 5407 | ||
5407 | if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS || | 5408 | if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS || |
@@ -5415,6 +5416,19 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, | |||
5415 | if (!crtc) | 5416 | if (!crtc) |
5416 | return -ENOENT; | 5417 | return -ENOENT; |
5417 | 5418 | ||
5419 | if (crtc->funcs->page_flip_target) { | ||
5420 | int r; | ||
5421 | |||
5422 | r = drm_crtc_vblank_get(crtc); | ||
5423 | if (r) | ||
5424 | return r; | ||
5425 | |||
5426 | target_vblank = drm_crtc_vblank_count(crtc) + | ||
5427 | !(page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC); | ||
5428 | } else if (crtc->funcs->page_flip == NULL) { | ||
5429 | return -EINVAL; | ||
5430 | } | ||
5431 | |||
5418 | drm_modeset_lock_crtc(crtc, crtc->primary); | 5432 | drm_modeset_lock_crtc(crtc, crtc->primary); |
5419 | if (crtc->primary->fb == NULL) { | 5433 | if (crtc->primary->fb == NULL) { |
5420 | /* The framebuffer is currently unbound, presumably | 5434 | /* The framebuffer is currently unbound, presumably |
@@ -5425,9 +5439,6 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, | |||
5425 | goto out; | 5439 | goto out; |
5426 | } | 5440 | } |
5427 | 5441 | ||
5428 | if (crtc->funcs->page_flip == NULL) | ||
5429 | goto out; | ||
5430 | |||
5431 | fb = drm_framebuffer_lookup(dev, page_flip->fb_id); | 5442 | fb = drm_framebuffer_lookup(dev, page_flip->fb_id); |
5432 | if (!fb) { | 5443 | if (!fb) { |
5433 | ret = -ENOENT; | 5444 | ret = -ENOENT; |
@@ -5468,7 +5479,12 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, | |||
5468 | } | 5479 | } |
5469 | 5480 | ||
5470 | crtc->primary->old_fb = crtc->primary->fb; | 5481 | crtc->primary->old_fb = crtc->primary->fb; |
5471 | ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags); | 5482 | if (crtc->funcs->page_flip_target) |
5483 | ret = crtc->funcs->page_flip_target(crtc, fb, e, | ||
5484 | page_flip->flags, | ||
5485 | target_vblank); | ||
5486 | else | ||
5487 | ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags); | ||
5472 | if (ret) { | 5488 | if (ret) { |
5473 | if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) | 5489 | if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) |
5474 | drm_event_cancel_free(dev, &e->base); | 5490 | drm_event_cancel_free(dev, &e->base); |
@@ -5481,6 +5497,8 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, | |||
5481 | } | 5497 | } |
5482 | 5498 | ||
5483 | out: | 5499 | out: |
5500 | if (ret) | ||
5501 | drm_crtc_vblank_put(crtc); | ||
5484 | if (fb) | 5502 | if (fb) |
5485 | drm_framebuffer_unreference(fb); | 5503 | drm_framebuffer_unreference(fb); |
5486 | if (crtc->primary->old_fb) | 5504 | if (crtc->primary->old_fb) |
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 44e070800b6d..3c90563e1a54 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h | |||
@@ -581,6 +581,24 @@ struct drm_crtc_funcs { | |||
581 | uint32_t flags); | 581 | uint32_t flags); |
582 | 582 | ||
583 | /** | 583 | /** |
584 | * @page_flip_target: | ||
585 | * | ||
586 | * Same as @page_flip but with an additional parameter specifying the | ||
587 | * absolute target vertical blank period (as reported by | ||
588 | * drm_crtc_vblank_count()) when the flip should take effect. | ||
589 | * | ||
590 | * Note that the core code calls drm_crtc_vblank_get before this entry | ||
591 | * point, and will call drm_crtc_vblank_put if this entry point returns | ||
592 | * any non-0 error code. It's the driver's responsibility to call | ||
593 | * drm_crtc_vblank_put after this entry point returns 0, typically when | ||
594 | * the flip completes. | ||
595 | */ | ||
596 | int (*page_flip_target)(struct drm_crtc *crtc, | ||
597 | struct drm_framebuffer *fb, | ||
598 | struct drm_pending_vblank_event *event, | ||
599 | uint32_t flags, uint32_t target); | ||
600 | |||
601 | /** | ||
584 | * @set_property: | 602 | * @set_property: |
585 | * | 603 | * |
586 | * This is the legacy entry point to update a property attached to the | 604 | * This is the legacy entry point to update a property attached to the |