diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 6668d2c9713333fe8ed61675209b75212f338561..a3216a7f7ccc535fa6d4c5e3962930a8e2be5999 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -1620,3 +1620,89 @@ drm_atomic_helper_connector_set_property(struct drm_connector *connector, goto retry; } EXPORT_SYMBOL(drm_atomic_helper_connector_set_property); + +/** + * drm_atomic_helper_page_flip - execute a legacy page flip + * @crtc: DRM crtc + * @fb: DRM framebuffer + * @event: optional DRM event to signal upon completion + * @flags: flip flags for non-vblank sync'ed updates + * + * Provides a default page flip implementation using the atomic driver interface. + * + * Note that for now so called async page flips (i.e. updates which are not + * synchronized to vblank) are not supported, since the atomic interfaces have + * no provisions for this yet. + * + * Returns: + * Returns 0 on success, negative errno numbers on failure. + */ +int drm_atomic_helper_page_flip(struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_pending_vblank_event *event, + uint32_t flags) +{ + struct drm_plane *plane = crtc->primary; + struct drm_atomic_state *state; + struct drm_plane_state *plane_state; + struct drm_crtc_state *crtc_state; + int ret = 0; + + if (flags & DRM_MODE_PAGE_FLIP_ASYNC) + return -EINVAL; + + state = drm_atomic_state_alloc(plane->dev); + if (!state) + return -ENOMEM; + + state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc); +retry: + crtc_state = drm_atomic_get_crtc_state(state, crtc); + if (IS_ERR(crtc_state)) { + ret = PTR_ERR(crtc_state); + goto fail; + } + crtc_state->event = event; + + plane_state = drm_atomic_get_plane_state(state, plane); + if (IS_ERR(plane_state)) { + ret = PTR_ERR(plane_state); + goto fail; + } + + ret = drm_atomic_set_crtc_for_plane(plane_state, crtc); + if (ret != 0) + goto fail; + plane_state->fb = fb; + + ret = drm_atomic_async_commit(state); + if (ret != 0) + goto fail; + + /* TODO: ->page_flip is the only driver callback where the core + * doesn't update plane->fb. For now patch it up here. */ + plane->fb = plane->state->fb; + + /* Driver takes ownership of state on successful async commit. */ + return 0; +fail: + if (ret == -EDEADLK) + goto backoff; + + drm_atomic_state_free(state); + + return ret; +backoff: + drm_atomic_legacy_backoff(state); + drm_atomic_state_clear(state); + + /* + * Someone might have exchanged the framebuffer while we dropped locks + * in the backoff code. We need to fix up the fb refcount tracking the + * core does for us. + */ + plane->old_fb = plane->fb; + + goto retry; +} +EXPORT_SYMBOL(drm_atomic_helper_page_flip); diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h index 8cd6fe7a48e56bc882c6ae0b18e8a4ab805a5a96..28a2f3a815fd81d922f82405032fb9ec88857672 100644 --- a/include/drm/drm_atomic_helper.h +++ b/include/drm/drm_atomic_helper.h @@ -69,5 +69,10 @@ int drm_atomic_helper_plane_set_property(struct drm_plane *plane, int drm_atomic_helper_connector_set_property(struct drm_connector *connector, struct drm_property *property, uint64_t val); +int drm_atomic_helper_page_flip(struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_pending_vblank_event *event, + uint32_t flags); + #endif /* DRM_ATOMIC_HELPER_H_ */