[PATCH 10/19] drm/plane-helper: transitional atomic plane helpers

Daniel Vetter daniel.vetter at ffwll.ch
Sun Jul 27 14:41:39 PDT 2014


Converting a driver to the atomic interface can be a daunting
undertaking. One of the prerequisites is to have full universal planes
support.

To make that transition a bit easier this pathc provides plane helpers
which use the new atomic helper callbacks just only for the plane
changes. This way the plane update functionality can be tested without
being forced to convert everything at once.

Of course a real atomic update capable driver will implement the
all plane properties through the atomic interface, so these helpers
are mostly transitional. But they can be used to enable proper
universal plane support, especially once the crtc helpers have also
been adapted.

v2: Use ->atomic_duplicate_state if available.

Signed-off-by: Daniel Vetter <daniel.vetter at ffwll.ch>
---
 drivers/gpu/drm/drm_plane_helper.c | 181 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 180 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c
index 827ec1a3040b..7befbf017afe 100644
--- a/drivers/gpu/drm/drm_plane_helper.c
+++ b/drivers/gpu/drm/drm_plane_helper.c
@@ -27,7 +27,7 @@
 #include <drm/drmP.h>
 #include <drm/drm_plane_helper.h>
 #include <drm/drm_rect.h>
-#include <drm/drm_plane_helper.h>
+#include <drm/drm_crtc_helper.h>
 
 #define SUBPIXEL_MASK 0xffff
 
@@ -369,3 +369,182 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
 	return drm_crtc_init_with_planes(dev, crtc, primary, NULL, funcs);
 }
 EXPORT_SYMBOL(drm_crtc_init);
+
+/**
+ * drm_primary_helper_update() - Helper for primary plane update
+ * @plane: plane object to update
+ * @crtc: owning CRTC of owning plane
+ * @fb: framebuffer to flip onto plane
+ * @crtc_x: x offset of primary plane on crtc
+ * @crtc_y: y offset of primary plane on crtc
+ * @crtc_w: width of primary plane rectangle on crtc
+ * @crtc_h: height of primary plane rectangle on crtc
+ * @src_x: x offset of @fb for panning
+ * @src_y: y offset of @fb for panning
+ * @src_w: width of source rectangle in @fb
+ * @src_h: height of source rectangle in @fb
+ *
+ * Provides a default plane update handler using the atomic plane update
+ * functions. It is fully left to the driver to check plane constraints and
+ * handle corner-cases like a fully occluded or otherwise invisible plane.
+ *
+ * This is useful for piecewise transitioning of a driver to the atomic helpers.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure
+ */
+int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
+			    struct drm_framebuffer *fb,
+			    int crtc_x, int crtc_y,
+			    unsigned int crtc_w, unsigned int crtc_h,
+			    uint32_t src_x, uint32_t src_y,
+			    uint32_t src_w, uint32_t src_h)
+{
+	struct drm_plane_state *plane_state;
+	struct drm_plane_helper_funcs *plane_funcs;
+	struct drm_crtc_helper_funcs *crtc_funcs;
+	int ret;
+
+	if (plane->funcs->atomic_duplicate_state)
+		plane_state = plane->funcs->atomic_duplicate_state(plane);
+	else if (plane->state)
+		plane_state = kmemdup(plane->state, sizeof(*plane_state),
+				      GFP_KERNEL);
+	else
+		plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL);
+	if (!plane_state)
+		return -ENOMEM;
+
+	plane_state->crtc = crtc;
+	plane_state->fb = fb;
+	plane_state->crtc_x = crtc_x;
+	plane_state->crtc_y = crtc_y;
+	plane_state->crtc_h = crtc_h;
+	plane_state->crtc_w = crtc_w;
+	plane_state->src_x = src_x;
+	plane_state->src_y = src_y;
+	plane_state->src_h = src_h;
+	plane_state->src_w = src_w;
+
+	plane_funcs = plane->helper_private;
+
+	if (plane_funcs->atomic_check) {
+		ret = plane_funcs->atomic_check(plane, plane_state);
+		if (ret)
+			goto fail;
+	}
+
+	if (plane_funcs->prepare_fb) {
+		ret = plane_funcs->prepare_fb(plane, fb);
+		if (ret)
+			goto fail;
+	}
+
+	/* Point of no return, commit sw state. */
+	swap(plane->state, plane_state);
+	fb = plane_state->fb;
+
+	crtc_funcs = crtc->helper_private;
+
+	if (crtc_funcs && crtc_funcs->atomic_begin)
+		crtc_funcs->atomic_begin(crtc);
+
+	plane_funcs->atomic_update(plane);
+
+	if (crtc_funcs && crtc_funcs->atomic_flush)
+		crtc_funcs->atomic_flush(crtc);
+
+	/* There's no way to figure out whether the crtc is running. */
+	ret = drm_crtc_vblank_get(crtc);
+	if (ret == 0) {
+		drm_crtc_vblank_wait(crtc);
+		drm_crtc_vblank_put(crtc);
+	}
+
+	if (plane_funcs->cleanup_fb && fb)
+		plane_funcs->cleanup_fb(plane, fb);
+fail:
+	kfree(plane_state);
+
+	return ret;
+}
+EXPORT_SYMBOL(drm_plane_helper_update);
+
+/**
+ * drm_primary_helper_disable() - Helper for primary plane disable
+ * @plane: plane to disable
+ *
+ * Provides a default plane disable handler using the atomic plane update
+ * functions. It is fully left to the driver to check plane constraints and
+ * handle corner-cases like a fully occluded or otherwise invisible plane.
+ *
+ * This is useful for piecewise transitioning of a driver to the atomic helpers.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure
+ */
+int drm_plane_helper_disable(struct drm_plane *plane)
+{
+	struct drm_plane_state *plane_state;
+	struct drm_plane_helper_funcs *plane_funcs;
+	struct drm_crtc_helper_funcs *crtc_funcs;
+	struct drm_framebuffer *fb = NULL;
+	struct drm_crtc *crtc = plane->crtc;
+	int ret;
+
+	if (WARN_ON(!crtc))
+		return -EINVAL;
+
+	if (plane->funcs->atomic_duplicate_state)
+		plane_state = plane->funcs->atomic_duplicate_state(plane);
+	else if (plane->state)
+		plane_state = kmemdup(plane->state, sizeof(*plane_state),
+				      GFP_KERNEL);
+	else
+		plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL);
+	if (!plane_state)
+		return -ENOMEM;
+
+	plane_funcs = plane->helper_private;
+
+	if (plane_funcs->atomic_check) {
+		ret = plane_funcs->atomic_check(plane, plane_state);
+		if (ret)
+			goto fail;
+	}
+
+	if (plane_funcs->prepare_fb) {
+		ret = plane_funcs->prepare_fb(plane, fb);
+		if (ret)
+			goto fail;
+	}
+
+	/* Point of no return, commit sw state. */
+	swap(plane->state, plane_state);
+	fb = plane_state->fb;
+
+	crtc_funcs = crtc->helper_private;
+
+	if (crtc_funcs && crtc_funcs->atomic_begin)
+		crtc_funcs->atomic_begin(crtc);
+
+	plane_funcs->atomic_update(plane);
+
+	if (crtc_funcs && crtc_funcs->atomic_flush)
+		crtc_funcs->atomic_flush(crtc);
+
+	/* There's no way to figure out whether the crtc is running. */
+	ret = drm_crtc_vblank_get(crtc);
+	if (ret == 0) {
+		drm_crtc_vblank_wait(crtc);
+		drm_crtc_vblank_put(crtc);
+	}
+
+	if (plane_funcs->cleanup_fb && fb)
+		plane_funcs->cleanup_fb(plane, fb);
+fail:
+	kfree(plane_state);
+
+	return ret;
+}
+EXPORT_SYMBOL(drm_plane_helper_disable);
-- 
2.0.1



More information about the dri-devel mailing list