All of lore.kernel.org
 help / color / mirror / Atom feed
From: Rob Clark <robdclark@gmail.com>
To: dri-devel@lists.freedesktop.org
Subject: [RFCv4 09/14] drm: convert plane to properties/state
Date: Mon, 25 Nov 2013 09:47:33 -0500	[thread overview]
Message-ID: <1385390858-4412-10-git-send-email-robdclark@gmail.com> (raw)
In-Reply-To: <1385390858-4412-1-git-send-email-robdclark@gmail.com>

Break the mutable state of a plane out into a separate structure
and use atomic properties mechanism to set plane attributes.  This
makes it easier to have some helpers for plane->set_property()
and for checking for invalid params.  The idea is that individual
drivers can wrap the state struct in their own struct which adds
driver specific parameters, for easy build-up of state across
multiple set_property() calls and for easy atomic commit or roll-
back.

The same should be done for CRTC, encoder, and connector, but this
patch only includes the first part (plane).
---
 drivers/gpu/drm/drm_atomic_helper.c         | 156 ++++++++++-
 drivers/gpu/drm/drm_crtc.c                  | 397 +++++++++++++++++++---------
 drivers/gpu/drm/drm_fb_helper.c             |  17 +-
 drivers/gpu/drm/exynos/exynos_drm_crtc.c    |   4 +-
 drivers/gpu/drm/exynos/exynos_drm_encoder.c |   6 +-
 drivers/gpu/drm/exynos/exynos_drm_plane.c   |  15 +-
 drivers/gpu/drm/i915/intel_sprite.c         |  21 +-
 drivers/gpu/drm/msm/mdp4/mdp4_crtc.c        |   2 +-
 drivers/gpu/drm/msm/mdp4/mdp4_plane.c       |  19 +-
 drivers/gpu/drm/nouveau/dispnv04/overlay.c  |   8 +-
 drivers/gpu/drm/omapdrm/omap_crtc.c         |   4 +-
 drivers/gpu/drm/omapdrm/omap_drv.c          |   2 +-
 drivers/gpu/drm/omapdrm/omap_plane.c        |  33 ++-
 drivers/gpu/drm/rcar-du/rcar_du_plane.c     |   8 +-
 drivers/gpu/drm/shmobile/shmob_drm_crtc.c   |   2 +-
 drivers/gpu/drm/shmobile/shmob_drm_plane.c  |   6 +-
 drivers/gpu/drm/tegra/dc.c                  |  16 +-
 include/drm/drm_atomic_helper.h             |  39 ++-
 include/drm/drm_crtc.h                      |  88 +++++-
 19 files changed, 654 insertions(+), 189 deletions(-)

diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 8b37cf1..14e0571 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -39,10 +39,12 @@
 void *drm_atomic_helper_begin(struct drm_device *dev, uint32_t flags)
 {
 	struct drm_atomic_helper_state *state;
+	int nplanes = dev->mode_config.num_plane;
 	int sz;
 	void *ptr;
 
 	sz = sizeof(*state);
+	sz += (sizeof(state->planes) + sizeof(state->pstates)) * nplanes;
 
 	ptr = kzalloc(sz, GFP_KERNEL);
 
@@ -57,6 +59,12 @@ void *drm_atomic_helper_begin(struct drm_device *dev, uint32_t flags)
 	state->dev = dev;
 	state->flags = flags;
 
+	state->planes = ptr;
+	ptr = &state->planes[nplanes];
+
+	state->pstates = ptr;
+	ptr = &state->pstates[nplanes];
+
 	return state;
 }
 EXPORT_SYMBOL(drm_atomic_helper_begin);
@@ -92,7 +100,19 @@ EXPORT_SYMBOL(drm_atomic_helper_set_event);
  */
 int drm_atomic_helper_check(struct drm_device *dev, void *state)
 {
-	return 0;  /* for now */
+	struct drm_atomic_helper_state *a = state;
+	int nplanes = dev->mode_config.num_plane;
+	int i, ret = 0;
+
+	for (i = 0; i < nplanes; i++) {
+		if (a->planes[i]) {
+			ret = drm_atomic_check_plane_state(a->planes[i], a->pstates[i]);
+			if (ret)
+				break;
+		}
+	}
+
+	return ret;
 }
 EXPORT_SYMBOL(drm_atomic_helper_check);
 
@@ -168,6 +188,18 @@ fail:
 static void commit_locks(struct drm_atomic_helper_state *a,
 		struct ww_acquire_ctx *ww_ctx)
 {
+	struct drm_device *dev = a->dev;
+	int nplanes = dev->mode_config.num_plane;
+	int i;
+
+	for (i = 0; i < nplanes; i++) {
+		struct drm_plane *plane = a->planes[i];
+		if (plane) {
+			plane->state->state = NULL;
+			drm_atomic_helper_destroy_plane_state(plane, a->pstates[i]);
+		}
+	}
+
 	/* and properly release them (clear in_atomic, remove from list): */
 	mutex_lock(&a->mutex);
 	while (!list_empty(&a->locked)) {
@@ -186,7 +218,17 @@ static void commit_locks(struct drm_atomic_helper_state *a,
 static int atomic_commit(struct drm_atomic_helper_state *a,
 		struct ww_acquire_ctx *ww_ctx)
 {
-	int ret = 0;
+	int nplanes = a->dev->mode_config.num_plane;
+	int i, ret = 0;
+
+	for (i = 0; i < nplanes; i++) {
+		struct drm_plane *plane = a->planes[i];
+		if (plane) {
+			ret = drm_atomic_commit_plane_state(plane, a->pstates[i]);
+			if (ret)
+				break;
+		}
+	}
 
 	commit_locks(a, ww_ctx);
 
@@ -263,7 +305,117 @@ void _drm_atomic_helper_state_free(struct kref *kref)
 }
 EXPORT_SYMBOL(_drm_atomic_helper_state_free);
 
+int drm_atomic_helper_plane_set_property(struct drm_plane *plane, void *state,
+		struct drm_property *property, uint64_t val, void *blob_data)
+{
+	struct drm_plane_state *pstate = drm_atomic_get_plane_state(plane, state);
+	if (IS_ERR(pstate))
+		return PTR_ERR(pstate);
+	return drm_plane_set_property(plane, pstate, property, val, blob_data);
+}
+EXPORT_SYMBOL(drm_atomic_helper_plane_set_property);
+
+void drm_atomic_helper_init_plane_state(struct drm_plane *plane,
+		struct drm_plane_state *pstate, void *state)
+{
+	/* snapshot current state: */
+	*pstate = *plane->state;
+	pstate->state = state;
+}
+EXPORT_SYMBOL(drm_atomic_helper_init_plane_state);
+
+void drm_atomic_helper_destroy_plane_state(struct drm_plane *plane,
+		struct drm_plane_state *state)
+{
+	kfree(state);
+}
+EXPORT_SYMBOL(drm_atomic_helper_destroy_plane_state);
+
+static struct drm_plane_state *
+drm_atomic_helper_get_plane_state(struct drm_plane *plane, void *state)
+{
+	struct drm_atomic_helper_state *a = state;
+	struct drm_plane_state *pstate;
+	int ret;
+
+	/* grab lock of current crtc.. if crtc is NULL then grab all: */
+	if (plane->state->crtc)
+		ret = drm_modeset_lock(&plane->state->crtc->mutex, state);
+	else
+		ret = drm_modeset_lock_all_crtcs(plane->dev, state);
+	if (ret)
+		return ERR_PTR(ret);
+
+	pstate = a->pstates[plane->id];
+
+	if (!pstate) {
+		pstate = kzalloc(sizeof(*pstate), GFP_KERNEL);
+		if (!pstate)
+			return ERR_PTR(-ENOMEM);
+		drm_atomic_helper_init_plane_state(plane, pstate, state);
+		a->planes[plane->id] = plane;
+		a->pstates[plane->id] = pstate;
+	}
+
+	return pstate;
+}
+
+static void
+swap_plane_state(struct drm_plane *plane, struct drm_atomic_helper_state *a)
+{
+	struct drm_plane_state *pstate = a->pstates[plane->id];
+
+	/* clear transient state (only valid during atomic update): */
+	pstate->new_fb = false;
+
+	swap(plane->state, a->pstates[plane->id]);
+	plane->base.propvals = &plane->state->propvals;
+}
+
+static int
+drm_atomic_helper_commit_plane_state(struct drm_plane *plane,
+		struct drm_plane_state *pstate)
+{
+	struct drm_framebuffer *old_fb = NULL, *fb = NULL;
+	int ret = 0;
+
+	fb = pstate->fb;
+
+	if (pstate->crtc && fb) {
+		ret = plane->funcs->update_plane(plane, pstate->crtc, pstate->fb,
+			pstate->crtc_x, pstate->crtc_y, pstate->crtc_w, pstate->crtc_h,
+			pstate->src_x,  pstate->src_y,  pstate->src_w,  pstate->src_h);
+		if (!ret) {
+			/* on success, update state and fb refcnting: */
+			/* NOTE: if we ensure no driver sets plane->state->fb = NULL
+			 * on disable, we can move this up a level and not duplicate
+			 * nearly the same thing for both update_plane and disable_plane
+			 * cases..  I leave it like this for now to be paranoid due to
+			 * the slightly different ordering in the two cases in the
+			 * original code.
+			 */
+			old_fb = plane->state->fb;
+			swap_plane_state(plane, pstate->state);
+			fb = NULL;
+		}
+	} else {
+		old_fb = plane->state->fb;
+		plane->funcs->disable_plane(plane);
+		swap_plane_state(plane, pstate->state);
+	}
+
+
+	if (fb)
+		drm_framebuffer_unreference(fb);
+	if (old_fb)
+		drm_framebuffer_unreference(old_fb);
+
+	return ret;
+}
 
 const struct drm_atomic_helper_funcs drm_atomic_helper_funcs = {
+		.get_plane_state    = drm_atomic_helper_get_plane_state,
+		.check_plane_state  = drm_plane_check_state,
+		.commit_plane_state = drm_atomic_helper_commit_plane_state,
 };
 EXPORT_SYMBOL(drm_atomic_helper_funcs);
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 8180499..bb1a4fe 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -680,7 +680,20 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
 	 * in this manner.
 	 */
 	if (atomic_read(&fb->refcount.refcount) > 1) {
+		void *state;
+
+		state = dev->driver->atomic_begin(dev, 0);
+		if (IS_ERR(state)) {
+			DRM_ERROR("failed to disable crtc and/or plane when fb was deleted\n");
+			return;
+		}
+
+		/* TODO once CRTC is converted to state/properties, we can push the
+		 * locking down into drm_atomic_helper_commit(), since that is where
+		 * the actual changes take place..
+		 */
 		drm_modeset_lock_all(dev);
+
 		/* remove from any CRTC */
 		list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 			if (crtc->fb == fb) {
@@ -695,9 +708,18 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
 		}
 
 		list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
-			if (plane->fb == fb)
-				drm_plane_force_disable(plane);
+			if (plane->state->fb == fb)
+				drm_plane_force_disable(plane, state);
 		}
+
+		/* just disabling stuff shouldn't fail, hopefully: */
+		if(dev->driver->atomic_check(dev, state))
+			DRM_ERROR("failed to disable crtc and/or plane when fb was deleted\n");
+		else
+			dev->driver->atomic_commit(dev, state);
+
+		dev->driver->atomic_end(dev, state);
+
 		drm_modeset_unlock_all(dev);
 	}
 
@@ -993,8 +1015,12 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
 		   const uint32_t *formats, uint32_t format_count,
 		   bool priv)
 {
+	struct drm_mode_config *config = &dev->mode_config;
 	int ret;
 
+	if (!plane->state)
+		plane->state = kzalloc(sizeof(*plane->state), GFP_KERNEL);
+
 	drm_modeset_lock_all(dev);
 
 	ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE);
@@ -1002,7 +1028,7 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
 		goto out;
 
 	plane->base.properties = &plane->properties;
-	plane->base.propvals = &plane->propvals;
+	plane->base.propvals = &plane->state->propvals;
 	plane->dev = dev;
 	plane->funcs = funcs;
 	plane->format_types = kmalloc(sizeof(uint32_t) * format_count,
@@ -1024,11 +1050,23 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
 	 */
 	if (!priv) {
 		list_add_tail(&plane->head, &dev->mode_config.plane_list);
+		plane->id = dev->mode_config.num_plane;
 		dev->mode_config.num_plane++;
 	} else {
 		INIT_LIST_HEAD(&plane->head);
 	}
 
+	drm_object_attach_property(&plane->base, config->prop_fb_id, 0);
+	drm_object_attach_property(&plane->base, config->prop_crtc_id, 0);
+	drm_object_attach_property(&plane->base, config->prop_crtc_x, 0);
+	drm_object_attach_property(&plane->base, config->prop_crtc_y, 0);
+	drm_object_attach_property(&plane->base, config->prop_crtc_w, 0);
+	drm_object_attach_property(&plane->base, config->prop_crtc_h, 0);
+	drm_object_attach_property(&plane->base, config->prop_src_x, 0);
+	drm_object_attach_property(&plane->base, config->prop_src_y, 0);
+	drm_object_attach_property(&plane->base, config->prop_src_w, 0);
+	drm_object_attach_property(&plane->base, config->prop_src_h, 0);
+
  out:
 	drm_modeset_unlock_all(dev);
 
@@ -1060,6 +1098,121 @@ void drm_plane_cleanup(struct drm_plane *plane)
 }
 EXPORT_SYMBOL(drm_plane_cleanup);
 
+int drm_plane_check_state(struct drm_plane *plane,
+		struct drm_plane_state *state)
+{
+	unsigned int fb_width, fb_height;
+	struct drm_framebuffer *fb = state->fb;
+	int i;
+
+	/* disabling the plane is allowed: */
+	if (!fb)
+		return 0;
+
+	fb_width = fb->width << 16;
+	fb_height = fb->height << 16;
+
+	/* Check whether this plane supports the fb pixel format. */
+	for (i = 0; i < plane->format_count; i++)
+		if (fb->pixel_format == plane->format_types[i])
+			break;
+	if (i == plane->format_count) {
+		DRM_DEBUG_KMS("Invalid pixel format 0x%08x\n", fb->pixel_format);
+		return -EINVAL;
+	}
+
+	/* Make sure source coordinates are inside the fb. */
+	if (state->src_w > fb_width ||
+			state->src_x > fb_width - state->src_w ||
+			state->src_h > fb_height ||
+			state->src_y > fb_height - state->src_h) {
+		DRM_DEBUG_KMS("Invalid source coordinates "
+			      "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n",
+			      state->src_w >> 16,
+			      ((state->src_w & 0xffff) * 15625) >> 10,
+			      state->src_h >> 16,
+			      ((state->src_h & 0xffff) * 15625) >> 10,
+			      state->src_x >> 16,
+			      ((state->src_x & 0xffff) * 15625) >> 10,
+			      state->src_y >> 16,
+			      ((state->src_y & 0xffff) * 15625) >> 10);
+		return -ENOSPC;
+	}
+
+	/* Give drivers some help against integer overflows */
+	if (state->crtc_w > INT_MAX ||
+			state->crtc_x > INT_MAX - (int32_t) state->crtc_w ||
+			state->crtc_h > INT_MAX ||
+			state->crtc_y > INT_MAX - (int32_t) state->crtc_h) {
+		DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n",
+			      state->crtc_w, state->crtc_h,
+			      state->crtc_x, state->crtc_y);
+		return -ERANGE;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_plane_check_state);
+
+void drm_plane_commit_state(struct drm_plane *plane,
+		struct drm_plane_state *state)
+{
+	plane->state = state;
+	plane->base.propvals = &state->propvals;
+}
+EXPORT_SYMBOL(drm_plane_commit_state);
+
+int drm_plane_set_property(struct drm_plane *plane,
+		struct drm_plane_state *state,
+		struct drm_property *property,
+		uint64_t value, void *blob_data)
+{
+	struct drm_device *dev = plane->dev;
+	struct drm_mode_config *config = &dev->mode_config;
+
+	drm_object_property_set_value(&plane->base,
+			&state->propvals, property, value, blob_data);
+
+	if (property == config->prop_fb_id) {
+		state->new_fb = true;
+		state->fb = drm_framebuffer_lookup(dev, value);
+	} else if (property == config->prop_crtc_id) {
+		struct drm_mode_object *obj = drm_property_get_obj(property, value);
+		struct drm_crtc *crtc = obj ? obj_to_crtc(obj) : NULL;
+		/* take the lock of the incoming crtc as well, moving
+		 * plane between crtcs is synchronized on both incoming
+		 * and outgoing crtc.
+		 */
+		if (crtc) {
+			int ret = drm_modeset_lock(&crtc->mutex, state->state);
+			if (ret)
+				return ret;
+		}
+		state->crtc = crtc;
+	} else if (property == config->prop_crtc_x) {
+		state->crtc_x = U642I64(value);
+	} else if (property == config->prop_crtc_y) {
+		state->crtc_y = U642I64(value);
+	} else if (property == config->prop_crtc_w) {
+		state->crtc_w = value;
+	} else if (property == config->prop_crtc_h) {
+		state->crtc_h = value;
+	} else if (property == config->prop_src_x) {
+		state->src_x = value;
+	} else if (property == config->prop_src_y) {
+		state->src_y = value;
+	} else if (property == config->prop_src_w) {
+		state->src_w = value;
+	} else if (property == config->prop_src_h) {
+		state->src_h = value;
+	} else {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_plane_set_property);
+
 /**
  * drm_plane_force_disable - Forcibly disable a plane
  * @plane: plane to disable
@@ -1069,20 +1222,15 @@ EXPORT_SYMBOL(drm_plane_cleanup);
  * Used when the plane's current framebuffer is destroyed,
  * and when restoring fbdev mode.
  */
-void drm_plane_force_disable(struct drm_plane *plane)
+void drm_plane_force_disable(struct drm_plane *plane, void *state)
 {
-	int ret;
+	struct drm_mode_config *config = &plane->dev->mode_config;
 
-	if (!plane->fb)
-		return;
-
-	ret = plane->funcs->disable_plane(plane);
-	if (ret)
-		DRM_ERROR("failed to disable plane with busy fb\n");
-	/* disconnect the plane from the fb and crtc: */
-	__drm_framebuffer_unreference(plane->fb);
-	plane->fb = NULL;
-	plane->crtc = NULL;
+	/* should turn off the crtc */
+	drm_mode_plane_set_obj_prop(plane, state,
+		config->prop_crtc_id, 0, NULL);
+	drm_mode_plane_set_obj_prop(plane, state,
+		config->prop_fb_id, 0, NULL);
 }
 EXPORT_SYMBOL(drm_plane_force_disable);
 
@@ -1132,21 +1280,78 @@ EXPORT_SYMBOL(drm_mode_destroy);
 
 static int drm_mode_create_standard_connector_properties(struct drm_device *dev)
 {
-	struct drm_property *edid;
-	struct drm_property *dpms;
+	struct drm_property *prop;
 
 	/*
 	 * Standard properties (apply to all connectors)
 	 */
-	edid = drm_property_create(dev, DRM_MODE_PROP_BLOB |
+	prop = drm_property_create(dev, DRM_MODE_PROP_BLOB |
 				   DRM_MODE_PROP_IMMUTABLE,
 				   "EDID", 0);
-	dev->mode_config.edid_property = edid;
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.edid_property = prop;
 
-	dpms = drm_property_create_enum(dev, 0,
+	prop = drm_property_create_enum(dev, 0,
 				   "DPMS", drm_dpms_enum_list,
 				   ARRAY_SIZE(drm_dpms_enum_list));
-	dev->mode_config.dpms_property = dpms;
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.dpms_property = prop;
+
+
+	prop = drm_property_create_range(dev, 0, "SRC_X", 0, UINT_MAX);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.prop_src_x = prop;
+
+	prop = drm_property_create_range(dev, 0, "SRC_Y", 0, UINT_MAX);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.prop_src_y = prop;
+
+	prop = drm_property_create_range(dev, 0, "SRC_W", 0, UINT_MAX);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.prop_src_w = prop;
+
+	prop = drm_property_create_range(dev, 0, "SRC_H", 0, UINT_MAX);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.prop_src_h = prop;
+
+	prop = drm_property_create_signed_range(dev, 0, "CRTC_X",
+			INT_MIN, INT_MAX);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.prop_crtc_x = prop;
+
+	prop = drm_property_create_signed_range(dev, 0, "CRTC_Y",
+			INT_MIN, INT_MAX);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.prop_crtc_y = prop;
+
+	prop = drm_property_create_range(dev, 0, "CRTC_W", 0, INT_MAX);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.prop_crtc_w = prop;
+
+	prop = drm_property_create_range(dev, 0, "CRTC_H", 0, INT_MAX);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.prop_crtc_h = prop;
+
+	prop = drm_property_create_object(dev, 0, "FB_ID", DRM_MODE_OBJECT_FB);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.prop_fb_id = prop;
+
+	prop = drm_property_create_object(dev, 0,
+			"CRTC_ID", DRM_MODE_OBJECT_CRTC);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.prop_crtc_id = prop;
 
 	return 0;
 }
@@ -1939,13 +2144,13 @@ int drm_mode_getplane(struct drm_device *dev, void *data,
 		goto out;
 	}
 
-	if (plane->crtc)
-		plane_resp->crtc_id = plane->crtc->base.id;
+	if (plane->state->crtc)
+		plane_resp->crtc_id = plane->state->crtc->base.id;
 	else
 		plane_resp->crtc_id = 0;
 
-	if (plane->fb)
-		plane_resp->fb_id = plane->fb->base.id;
+	if (plane->state->fb)
+		plane_resp->fb_id = plane->state->fb->base.id;
 	else
 		plane_resp->fb_id = 0;
 
@@ -1987,20 +2192,19 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
 			struct drm_file *file_priv)
 {
 	struct drm_mode_set_plane *plane_req = data;
+	struct drm_mode_config *config = &dev->mode_config;
 	struct drm_plane *plane;
-	struct drm_crtc *crtc;
-	struct drm_framebuffer *fb = NULL, *old_fb = NULL;
+	void *state;
 	int ret = 0;
-	unsigned int fb_width, fb_height;
-	int i;
 
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
 
-	/*
-	 * First, find the plane, crtc, and fb objects.  If not available,
-	 * we don't bother to call the driver.
-	 */
+retry:
+	state = dev->driver->atomic_begin(dev, 0);
+	if (IS_ERR(state))
+		return PTR_ERR(state);
+
 	plane = drm_plane_find(dev, plane_req->plane_id);
 	if (!plane) {
 		DRM_DEBUG_KMS("Unknown plane ID %d\n",
@@ -2008,98 +2212,37 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
 		return -ENOENT;
 	}
 
-	/* No fb means shut it down */
-	if (!plane_req->fb_id) {
-		drm_modeset_lock_all(dev);
-		old_fb = plane->fb;
-		plane->funcs->disable_plane(plane);
-		plane->crtc = NULL;
-		plane->fb = NULL;
-		drm_modeset_unlock_all(dev);
-		goto out;
-	}
-
-	crtc = drm_crtc_find(dev, plane_req->crtc_id);
-	if (!crtc) {
-		DRM_DEBUG_KMS("Unknown crtc ID %d\n",
-			      plane_req->crtc_id);
-		ret = -ENOENT;
-		goto out;
-	}
-
-	fb = drm_framebuffer_lookup(dev, plane_req->fb_id);
-	if (!fb) {
-		DRM_DEBUG_KMS("Unknown framebuffer ID %d\n",
-			      plane_req->fb_id);
-		ret = -ENOENT;
-		goto out;
-	}
-
-	/* Check whether this plane supports the fb pixel format. */
-	for (i = 0; i < plane->format_count; i++)
-		if (fb->pixel_format == plane->format_types[i])
-			break;
-	if (i == plane->format_count) {
-		DRM_DEBUG_KMS("Invalid pixel format %s\n",
-			      drm_get_format_name(fb->pixel_format));
-		ret = -EINVAL;
-		goto out;
-	}
-
-	fb_width = fb->width << 16;
-	fb_height = fb->height << 16;
-
-	/* Make sure source coordinates are inside the fb. */
-	if (plane_req->src_w > fb_width ||
-	    plane_req->src_x > fb_width - plane_req->src_w ||
-	    plane_req->src_h > fb_height ||
-	    plane_req->src_y > fb_height - plane_req->src_h) {
-		DRM_DEBUG_KMS("Invalid source coordinates "
-			      "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n",
-			      plane_req->src_w >> 16,
-			      ((plane_req->src_w & 0xffff) * 15625) >> 10,
-			      plane_req->src_h >> 16,
-			      ((plane_req->src_h & 0xffff) * 15625) >> 10,
-			      plane_req->src_x >> 16,
-			      ((plane_req->src_x & 0xffff) * 15625) >> 10,
-			      plane_req->src_y >> 16,
-			      ((plane_req->src_y & 0xffff) * 15625) >> 10);
-		ret = -ENOSPC;
-		goto out;
-	}
-
-	/* Give drivers some help against integer overflows */
-	if (plane_req->crtc_w > INT_MAX ||
-	    plane_req->crtc_x > INT_MAX - (int32_t) plane_req->crtc_w ||
-	    plane_req->crtc_h > INT_MAX ||
-	    plane_req->crtc_y > INT_MAX - (int32_t) plane_req->crtc_h) {
-		DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n",
-			      plane_req->crtc_w, plane_req->crtc_h,
-			      plane_req->crtc_x, plane_req->crtc_y);
-		ret = -ERANGE;
+	ret =
+		drm_mode_plane_set_obj_prop(plane, state,
+			config->prop_crtc_id, plane_req->crtc_id, NULL) ||
+		drm_mode_plane_set_obj_prop(plane, state,
+			config->prop_fb_id, plane_req->fb_id, NULL) ||
+		drm_mode_plane_set_obj_prop(plane, state,
+			config->prop_crtc_x, I642U64(plane_req->crtc_x), NULL) ||
+		drm_mode_plane_set_obj_prop(plane, state,
+			config->prop_crtc_y, I642U64(plane_req->crtc_y), NULL) ||
+		drm_mode_plane_set_obj_prop(plane, state,
+			config->prop_crtc_w, plane_req->crtc_w, NULL) ||
+		drm_mode_plane_set_obj_prop(plane, state,
+			config->prop_crtc_h, plane_req->crtc_h, NULL) ||
+		drm_mode_plane_set_obj_prop(plane, state,
+			config->prop_src_w, plane_req->src_w, NULL) ||
+		drm_mode_plane_set_obj_prop(plane, state,
+			config->prop_src_h, plane_req->src_h, NULL) ||
+		drm_mode_plane_set_obj_prop(plane, state,
+			config->prop_src_x, plane_req->src_x, NULL) ||
+		drm_mode_plane_set_obj_prop(plane, state,
+			config->prop_src_y, plane_req->src_y, NULL) ||
+		dev->driver->atomic_check(dev, state);
+	if (ret)
 		goto out;
-	}
 
-	drm_modeset_lock_all(dev);
-	ret = plane->funcs->update_plane(plane, crtc, fb,
-					 plane_req->crtc_x, plane_req->crtc_y,
-					 plane_req->crtc_w, plane_req->crtc_h,
-					 plane_req->src_x, plane_req->src_y,
-					 plane_req->src_w, plane_req->src_h);
-	if (!ret) {
-		old_fb = plane->fb;
-		plane->crtc = crtc;
-		plane->fb = fb;
-		fb = NULL;
-	}
-	drm_modeset_unlock_all(dev);
+	ret = dev->driver->atomic_commit(dev, state);
 
 out:
-	if (fb)
-		drm_framebuffer_unreference(fb);
-	if (old_fb)
-		drm_framebuffer_unreference(old_fb);
-
+	dev->driver->atomic_end(dev, state);
+	if (ret == -EDEADLK)
+		goto retry;
 	return ret;
 }
 
@@ -3427,7 +3570,7 @@ int drm_mode_connector_property_set_ioctl(struct drm_device *dev,
 	return drm_mode_obj_set_property_ioctl(dev, &obj_set_prop, file_priv);
 }
 
-static int drm_mode_connector_set_obj_prop(struct drm_connector *connector,
+int drm_mode_connector_set_obj_prop(struct drm_connector *connector,
 					   void *state, struct drm_property *property,
 					   uint64_t value, void *blob_data)
 {
@@ -3450,8 +3593,9 @@ static int drm_mode_connector_set_obj_prop(struct drm_connector *connector,
 
 	return ret;
 }
+EXPORT_SYMBOL(drm_mode_connector_set_obj_prop);
 
-static int drm_mode_crtc_set_obj_prop(struct drm_crtc *crtc,
+int drm_mode_crtc_set_obj_prop(struct drm_crtc *crtc,
 				      void *state, struct drm_property *property,
 				      uint64_t value, void *blob_data)
 {
@@ -3466,8 +3610,9 @@ static int drm_mode_crtc_set_obj_prop(struct drm_crtc *crtc,
 
 	return ret;
 }
+EXPORT_SYMBOL(drm_mode_crtc_set_obj_prop);
 
-static int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
+int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
 				      void *state, struct drm_property *property,
 				      uint64_t value, void *blob_data)
 {
@@ -3476,12 +3621,10 @@ static int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
 	if (plane->funcs->set_property)
 		ret = plane->funcs->set_property(plane, state, property,
 				value, blob_data);
-	if (!ret)
-		drm_object_property_set_value(&plane->base, &plane->propvals,
-				property, value, NULL);
 
 	return ret;
 }
+EXPORT_SYMBOL(drm_mode_plane_set_obj_prop);
 
 static int drm_mode_set_obj_prop(struct drm_mode_object *obj,
 		void *state, struct drm_property *property, 
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 1b6b6f4..5773468 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -286,12 +286,27 @@ bool drm_fb_helper_restore_fbdev_mode(struct drm_fb_helper *fb_helper)
 	struct drm_device *dev = fb_helper->dev;
 	struct drm_plane *plane;
 	bool error = false;
+	void *state;
 	int i;
 
 	drm_warn_on_modeset_not_all_locked(dev);
 
+	state = dev->driver->atomic_begin(dev, 0);
+	if (IS_ERR(state)) {
+		DRM_ERROR("failed to restore fbdev mode\n");
+		return true;
+	}
+
 	list_for_each_entry(plane, &dev->mode_config.plane_list, head)
-		drm_plane_force_disable(plane);
+		drm_plane_force_disable(plane, state);
+
+	/* just disabling stuff shouldn't fail, hopefully: */
+	if(dev->driver->atomic_check(dev, state))
+		DRM_ERROR("failed to restore fbdev mode\n");
+	else
+		dev->driver->atomic_commit(dev, state);
+
+	dev->driver->atomic_end(dev, state);
 
 	for (i = 0; i < fb_helper->crtc_count; i++) {
 		struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index 82a9fca..4ae55b8 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -124,8 +124,8 @@ exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
 	if (ret)
 		return ret;
 
-	plane->crtc = crtc;
-	plane->fb = crtc->fb;
+	plane->state->crtc = crtc;
+	plane->state->fb = crtc->fb;
 
 	exynos_drm_fn_encoder(crtc, &pipe, exynos_drm_encoder_crtc_pipe);
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
index 06f1b2a..dbe2e19 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
@@ -127,7 +127,7 @@ static void disable_plane_to_crtc(struct drm_device *dev,
 	 * (encoder->crtc)
 	 */
 	list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
-		if (plane->crtc == old_crtc) {
+		if (plane->state->crtc == old_crtc) {
 			/*
 			 * do not change below call order.
 			 *
@@ -138,7 +138,7 @@ static void disable_plane_to_crtc(struct drm_device *dev,
 			 * have new_crtc because new_crtc was set to
 			 * encoder->crtc in advance.
 			 */
-			plane->crtc = new_crtc;
+			plane->state->crtc = new_crtc;
 			plane->funcs->disable_plane(plane);
 		}
 	}
@@ -247,7 +247,7 @@ static void exynos_drm_encoder_disable(struct drm_encoder *encoder)
 
 	/* all planes connected to this encoder should be also disabled. */
 	list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
-		if (plane->crtc == encoder->crtc)
+		if (plane->state->crtc == encoder->crtc)
 			plane->funcs->disable_plane(plane);
 	}
 }
diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c
index 2e31fb8..d585a4c 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_plane.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c
@@ -10,6 +10,7 @@
  */
 
 #include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
 
 #include <drm/exynos_drm.h>
 #include "exynos_drm_drv.h"
@@ -149,7 +150,7 @@ void exynos_plane_commit(struct drm_plane *plane)
 	struct exynos_plane *exynos_plane = to_exynos_plane(plane);
 	struct exynos_drm_overlay *overlay = &exynos_plane->overlay;
 
-	exynos_drm_fn_encoder(plane->crtc, &overlay->zpos,
+	exynos_drm_fn_encoder(plane->state->crtc, &overlay->zpos,
 			exynos_drm_encoder_plane_commit);
 }
 
@@ -162,7 +163,7 @@ void exynos_plane_dpms(struct drm_plane *plane, int mode)
 		if (exynos_plane->enabled)
 			return;
 
-		exynos_drm_fn_encoder(plane->crtc, &overlay->zpos,
+		exynos_drm_fn_encoder(plane->state->crtc, &overlay->zpos,
 				exynos_drm_encoder_plane_enable);
 
 		exynos_plane->enabled = true;
@@ -170,7 +171,7 @@ void exynos_plane_dpms(struct drm_plane *plane, int mode)
 		if (!exynos_plane->enabled)
 			return;
 
-		exynos_drm_fn_encoder(plane->crtc, &overlay->zpos,
+		exynos_drm_fn_encoder(plane->state->crtc, &overlay->zpos,
 				exynos_drm_encoder_plane_disable);
 
 		exynos_plane->enabled = false;
@@ -192,7 +193,7 @@ exynos_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
 	if (ret < 0)
 		return ret;
 
-	plane->crtc = crtc;
+	plane->state->crtc = crtc;
 
 	exynos_plane_commit(plane);
 	exynos_plane_dpms(plane, DRM_MODE_DPMS_ON);
@@ -225,13 +226,17 @@ static int exynos_plane_set_property(struct drm_plane *plane,
 	struct drm_device *dev = plane->dev;
 	struct exynos_plane *exynos_plane = to_exynos_plane(plane);
 	struct exynos_drm_private *dev_priv = dev->dev_private;
+	struct drm_plane_state *pstate = drm_atomic_get_plane_state(plane, state);
+
+	if (IS_ERR(pstate))
+		return PTR_ERR(pstate);
 
 	if (property == dev_priv->plane_zpos_property) {
 		exynos_plane->overlay.zpos = val;
 		return 0;
 	}
 
-	return -EINVAL;
+	return drm_plane_set_property(plane, pstate, property, val, blob_data);
 }
 
 static struct drm_plane_funcs exynos_plane_funcs = {
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
index b9fabf8..0d1d34a 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -897,20 +897,21 @@ static int
 intel_disable_plane(struct drm_plane *plane)
 {
 	struct drm_device *dev = plane->dev;
+	struct drm_plane_state *state = plane->state;
 	struct intel_plane *intel_plane = to_intel_plane(plane);
 	struct intel_crtc *intel_crtc;
 
-	if (!plane->fb)
+	if (!state->fb)
 		return 0;
 
-	if (WARN_ON(!plane->crtc))
+	if (WARN_ON(!state->crtc))
 		return -EINVAL;
 
-	intel_crtc = to_intel_crtc(plane->crtc);
+	intel_crtc = to_intel_crtc(state->crtc);
 
 	if (intel_crtc->active) {
-		intel_enable_primary(plane->crtc);
-		intel_plane->disable_plane(plane, plane->crtc);
+		intel_enable_primary(state->crtc);
+		intel_plane->disable_plane(plane, state->crtc);
 	}
 
 	if (intel_plane->obj) {
@@ -1000,11 +1001,12 @@ out_unlock:
 void intel_plane_restore(struct drm_plane *plane)
 {
 	struct intel_plane *intel_plane = to_intel_plane(plane);
+	struct drm_plane_state *state = plane->state;
 
-	if (!plane->crtc || !plane->fb)
+	if (!state->crtc || !state->fb)
 		return;
 
-	intel_update_plane(plane, plane->crtc, plane->fb,
+	intel_update_plane(plane, state->crtc, state->fb,
 			   intel_plane->crtc_x, intel_plane->crtc_y,
 			   intel_plane->crtc_w, intel_plane->crtc_h,
 			   intel_plane->src_x, intel_plane->src_y,
@@ -1013,7 +1015,9 @@ void intel_plane_restore(struct drm_plane *plane)
 
 void intel_plane_disable(struct drm_plane *plane)
 {
-	if (!plane->crtc || !plane->fb)
+	struct drm_plane_state *state = plane->state;
+
+	if (!state->crtc || !state->fb)
 		return;
 
 	intel_disable_plane(plane);
@@ -1023,6 +1027,7 @@ static const struct drm_plane_funcs intel_plane_funcs = {
 	.update_plane = intel_update_plane,
 	.disable_plane = intel_disable_plane,
 	.destroy = intel_destroy_plane,
+	.set_property = drm_atomic_helper_plane_set_property,
 };
 
 static uint32_t ilk_plane_formats[] = {
diff --git a/drivers/gpu/drm/msm/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/mdp4/mdp4_crtc.c
index 80af12a..37a3fd2 100644
--- a/drivers/gpu/drm/msm/mdp4/mdp4_crtc.c
+++ b/drivers/gpu/drm/msm/mdp4/mdp4_crtc.c
@@ -263,7 +263,7 @@ static void blend_setup(struct drm_crtc *crtc)
 			int idx = idxs[pipe_id];
 			if (idx > 0) {
 				const struct mdp4_format *format =
-					to_mdp4_format(msm_framebuffer_format(plane->fb));
+					to_mdp4_format(msm_framebuffer_format(plane->state->fb));
 				alpha[idx-1] = format->alpha_enable;
 			}
 			mixer_cfg |= mixercfg(mdp4_crtc->mixer, pipe_id, stages[idx]);
diff --git a/drivers/gpu/drm/msm/mdp4/mdp4_plane.c b/drivers/gpu/drm/msm/mdp4/mdp4_plane.c
index 880e96d..037ac83 100644
--- a/drivers/gpu/drm/msm/mdp4/mdp4_plane.c
+++ b/drivers/gpu/drm/msm/mdp4/mdp4_plane.c
@@ -45,11 +45,14 @@ static int mdp4_plane_update(struct drm_plane *plane,
 		uint32_t src_w, uint32_t src_h)
 {
 	struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane);
+	struct drm_plane_state *state = plane->state;
 
 	mdp4_plane->enabled = true;
 
-	if (plane->fb)
-		drm_framebuffer_unreference(plane->fb);
+	if (state->fb) {
+		drm_framebuffer_unreference(state->fb);
+		state->fb = NULL;
+	}
 
 	drm_framebuffer_reference(fb);
 
@@ -62,8 +65,8 @@ static int mdp4_plane_disable(struct drm_plane *plane)
 {
 	struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane);
 	DBG("%s: disable", mdp4_plane->name);
-	if (plane->crtc)
-		mdp4_crtc_detach(plane->crtc, plane);
+	if (plane->state->crtc)
+		mdp4_crtc_detach(plane->state->crtc, plane);
 	return 0;
 }
 
@@ -87,8 +90,10 @@ void mdp4_plane_install_properties(struct drm_plane *plane,
 int mdp4_plane_set_property(struct drm_plane *plane, void *state,
 		struct drm_property *property, uint64_t val, void *blob_data)
 {
-	// XXX
-	return -EINVAL;
+	struct drm_plane_state *pstate = drm_atomic_get_plane_state(plane, state);
+	if (IS_ERR(pstate))
+		return PTR_ERR(pstate);
+	return drm_plane_set_property(plane, pstate, property, val, blob_data);
 }
 
 static const struct drm_plane_funcs mdp4_plane_funcs = {
@@ -117,7 +122,7 @@ void mdp4_plane_set_scanout(struct drm_plane *plane,
 	msm_gem_get_iova(msm_framebuffer_bo(fb, 0), mdp4_kms->id, &iova);
 	mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRCP0_BASE(pipe), iova);
 
-	plane->fb = fb;
+	plane->state->fb = fb;
 }
 
 #define MDP4_VG_PHASE_STEP_DEFAULT	0x20000000
diff --git a/drivers/gpu/drm/nouveau/dispnv04/overlay.c b/drivers/gpu/drm/nouveau/dispnv04/overlay.c
index fc938f7..a6a4375 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/overlay.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/overlay.c
@@ -24,6 +24,7 @@
  */
 
 #include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_fourcc.h>
 
@@ -213,6 +214,10 @@ nv10_set_property(struct drm_plane *plane, void *state,
 		  uint64_t value, void *blob_data)
 {
 	struct nouveau_plane *nv_plane = (struct nouveau_plane *)plane;
+	struct drm_plane_state *pstate = drm_atomic_get_plane_state(plane, state);
+
+	if (IS_ERR(pstate))
+		return PTR_ERR(pstate);
 
 	if (property == nv_plane->props.colorkey)
 		nv_plane->colorkey = value;
@@ -227,7 +232,8 @@ nv10_set_property(struct drm_plane *plane, void *state,
 	else if (property == nv_plane->props.iturbt_709)
 		nv_plane->iturbt_709 = value;
 	else
-		return -EINVAL;
+		return drm_plane_set_property(plane, pstate,
+				property, value, blob_data);
 
 	nv10_set_params(nv_plane);
 	return 0;
diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c
index 357342d..524a81a 100644
--- a/drivers/gpu/drm/omapdrm/omap_crtc.c
+++ b/drivers/gpu/drm/omapdrm/omap_crtc.c
@@ -210,7 +210,7 @@ static void omap_crtc_dpms(struct drm_crtc *crtc, int mode)
 		/* and any attached overlay planes: */
 		for (i = 0; i < priv->num_planes; i++) {
 			struct drm_plane *plane = priv->planes[i];
-			if (plane->crtc == crtc)
+			if (plane->state->crtc == crtc)
 				WARN_ON(omap_plane_dpms(plane, mode));
 		}
 	}
@@ -651,7 +651,7 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
 
 	omap_crtc->channel = channel;
 	omap_crtc->plane = plane;
-	omap_crtc->plane->crtc = crtc;
+	omap_crtc->plane->state->crtc = crtc;
 	omap_crtc->name = channel_names[channel];
 	omap_crtc->pipe = id;
 
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c
index 1b09696..e1e794a 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.c
+++ b/drivers/gpu/drm/omapdrm/omap_drv.c
@@ -559,7 +559,7 @@ static void dev_lastclose(struct drm_device *dev)
 
 		for (i = 0; i < priv->num_planes; i++) {
 			drm_object_property_set_value(&priv->planes[i]->base,
-					&priv->planes[i]->propvals,
+					&priv->planes[i]->state->propvals,
 					priv->rotation_prop, 0, NULL);
 		}
 	}
diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c
index fe32f1b..b85bd61 100644
--- a/drivers/gpu/drm/omapdrm/omap_plane.c
+++ b/drivers/gpu/drm/omapdrm/omap_plane.c
@@ -116,9 +116,10 @@ static void omap_plane_pre_apply(struct omap_drm_apply *apply)
 			container_of(apply, struct omap_plane, apply);
 	struct omap_drm_window *win = &omap_plane->win;
 	struct drm_plane *plane = &omap_plane->base;
+	struct drm_plane_state *state = plane->state;
 	struct drm_device *dev = plane->dev;
 	struct omap_overlay_info *info = &omap_plane->info;
-	struct drm_crtc *crtc = plane->crtc;
+	struct drm_crtc *crtc = state->crtc;
 	enum omap_channel channel;
 	bool enabled = omap_plane->enabled && crtc;
 	bool ilace, replication;
@@ -127,7 +128,7 @@ static void omap_plane_pre_apply(struct omap_drm_apply *apply)
 	DBG("%s, enabled=%d", omap_plane->name, enabled);
 
 	/* if fb has changed, pin new fb: */
-	update_pin(plane, enabled ? plane->fb : NULL);
+	update_pin(plane, enabled ? state->fb : NULL);
 
 	if (!enabled) {
 		dispc_ovl_enable(omap_plane->id, false);
@@ -137,7 +138,7 @@ static void omap_plane_pre_apply(struct omap_drm_apply *apply)
 	channel = omap_crtc_channel(crtc);
 
 	/* update scanout: */
-	omap_framebuffer_update_scanout(plane->fb, win, info);
+	omap_framebuffer_update_scanout(state->fb, win, info);
 
 	DBG("%dx%d -> %dx%d (%d)", info->width, info->height,
 			info->out_width, info->out_height,
@@ -179,16 +180,18 @@ static void omap_plane_post_apply(struct omap_drm_apply *apply)
 		cb.fxn(cb.arg);
 
 	if (omap_plane->enabled) {
-		omap_framebuffer_flush(plane->fb, info->pos_x, info->pos_y,
+		omap_framebuffer_flush(plane->state->fb,
+				info->pos_x, info->pos_y,
 				info->out_width, info->out_height);
 	}
 }
 
 static int apply(struct drm_plane *plane)
 {
-	if (plane->crtc) {
+	struct drm_plane_state *state = plane->state;
+	if (state->crtc) {
 		struct omap_plane *omap_plane = to_omap_plane(plane);
-		return omap_crtc_apply(plane->crtc, &omap_plane->apply);
+		return omap_crtc_apply(state->crtc, &omap_plane->apply);
 	}
 	return 0;
 }
@@ -203,6 +206,7 @@ int omap_plane_mode_set(struct drm_plane *plane,
 {
 	struct omap_plane *omap_plane = to_omap_plane(plane);
 	struct omap_drm_window *win = &omap_plane->win;
+	struct drm_plane_state *state = plane->state;
 
 	win->crtc_x = crtc_x;
 	win->crtc_y = crtc_y;
@@ -225,8 +229,8 @@ int omap_plane_mode_set(struct drm_plane *plane,
 		omap_plane->apply_done_cb.arg = arg;
 	}
 
-	plane->fb = fb;
-	plane->crtc = crtc;
+	state->fb = fb;
+	state->crtc = crtc;
 
 	return apply(plane);
 }
@@ -239,10 +243,12 @@ static int omap_plane_update(struct drm_plane *plane,
 		uint32_t src_w, uint32_t src_h)
 {
 	struct omap_plane *omap_plane = to_omap_plane(plane);
+	struct drm_plane_state *state = plane->state;
+
 	omap_plane->enabled = true;
 
-	if (plane->fb)
-		drm_framebuffer_unreference(plane->fb);
+	if (state->fb)
+		drm_framebuffer_unreference(state->fb);
 
 	drm_framebuffer_reference(fb);
 
@@ -332,8 +338,12 @@ int omap_plane_set_property(struct drm_plane *plane, void *state,
 {
 	struct omap_plane *omap_plane = to_omap_plane(plane);
 	struct omap_drm_private *priv = plane->dev->dev_private;
+	struct drm_plane_state *pstate = drm_atomic_get_plane_state(plane, state);
 	int ret = -EINVAL;
 
+	if (IS_ERR(pstate))
+		return PTR_ERR(pstate);
+
 	if (property == priv->rotation_prop) {
 		DBG("%s: rotation: %02x", omap_plane->name, (uint32_t)val);
 		omap_plane->win.rotation = val;
@@ -342,6 +352,9 @@ int omap_plane_set_property(struct drm_plane *plane, void *state,
 		DBG("%s: zorder: %02x", omap_plane->name, (uint32_t)val);
 		omap_plane->info.zorder = val;
 		ret = apply(plane);
+	} else {
+		ret = drm_plane_set_property(plane, pstate, property,
+				val, blob_data);
 	}
 
 	return ret;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.c b/drivers/gpu/drm/rcar-du/rcar_du_plane.c
index 5691743..4121a58 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_plane.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.c
@@ -14,6 +14,7 @@
 #include <drm/drmP.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 
@@ -403,6 +404,10 @@ static int rcar_du_plane_set_property(struct drm_plane *plane,
 {
 	struct rcar_du_plane *rplane = to_rcar_plane(plane);
 	struct rcar_du_group *rgrp = rplane->group;
+	struct drm_plane_state *pstate = drm_atomic_get_plane_state(plane, state);
+
+	if (IS_ERR(pstate))
+		return PTR_ERR(pstate);
 
 	if (property == rgrp->planes.alpha)
 		rcar_du_plane_set_alpha(rplane, value);
@@ -411,7 +416,8 @@ static int rcar_du_plane_set_property(struct drm_plane *plane,
 	else if (property == rgrp->planes.zpos)
 		rcar_du_plane_set_zpos(rplane, value);
 	else
-		return -EINVAL;
+		return drm_plane_set_property(plane, pstate,
+				property, value, blob_data);
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
index b72ba99..9e86b99 100644
--- a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
+++ b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
@@ -238,7 +238,7 @@ static void shmob_drm_crtc_start(struct shmob_drm_crtc *scrtc)
 
 	/* Setup planes. */
 	list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
-		if (plane->crtc == crtc)
+		if (plane->state->crtc == crtc)
 			shmob_drm_plane_setup(plane);
 	}
 
diff --git a/drivers/gpu/drm/shmobile/shmob_drm_plane.c b/drivers/gpu/drm/shmobile/shmob_drm_plane.c
index 060ae03..22da5c1 100644
--- a/drivers/gpu/drm/shmobile/shmob_drm_plane.c
+++ b/drivers/gpu/drm/shmobile/shmob_drm_plane.c
@@ -14,6 +14,7 @@
 #include <drm/drmP.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 
@@ -166,10 +167,10 @@ void shmob_drm_plane_setup(struct drm_plane *plane)
 {
 	struct shmob_drm_plane *splane = to_shmob_plane(plane);
 
-	if (plane->fb == NULL)
+	if (plane->state->fb == NULL)
 		return;
 
-	__shmob_drm_plane_setup(splane, plane->fb);
+	__shmob_drm_plane_setup(splane, plane->state->fb);
 }
 
 static int
@@ -228,6 +229,7 @@ static void shmob_drm_plane_destroy(struct drm_plane *plane)
 static const struct drm_plane_funcs shmob_drm_plane_funcs = {
 	.update_plane = shmob_drm_plane_update,
 	.disable_plane = shmob_drm_plane_disable,
+	.set_property = drm_atomic_helper_plane_set_property,
 	.destroy = shmob_drm_plane_destroy,
 };
 
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
index ae1cb31..1794c6e 100644
--- a/drivers/gpu/drm/tegra/dc.c
+++ b/drivers/gpu/drm/tegra/dc.c
@@ -73,11 +73,12 @@ static int tegra_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
 
 static int tegra_plane_disable(struct drm_plane *plane)
 {
-	struct tegra_dc *dc = to_tegra_dc(plane->crtc);
+	struct drm_plane_state *state = plane->state;
+	struct tegra_dc *dc = to_tegra_dc(state->crtc);
 	struct tegra_plane *p = to_tegra_plane(plane);
 	unsigned long value;
 
-	if (!plane->crtc)
+	if (!state->crtc)
 		return 0;
 
 	value = WINDOW_A_SELECT << p->index;
@@ -309,13 +310,14 @@ static void tegra_crtc_disable(struct drm_crtc *crtc)
 	struct drm_plane *plane;
 
 	list_for_each_entry(plane, &drm->mode_config.plane_list, head) {
-		if (plane->crtc == crtc) {
+		struct drm_plane_state *state = plane->state;
+		if (state->crtc == crtc) {
 			tegra_plane_disable(plane);
-			plane->crtc = NULL;
+			state->crtc = NULL;
 
-			if (plane->fb) {
-				drm_framebuffer_unreference(plane->fb);
-				plane->fb = NULL;
+			if (state->fb) {
+				drm_framebuffer_unreference(state->fb);
+				state->fb = NULL;
 			}
 		}
 	}
diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
index d77f00e..4ca8360 100644
--- a/include/drm/drm_atomic_helper.h
+++ b/include/drm/drm_atomic_helper.h
@@ -62,7 +62,9 @@
  * struct drm_atomic_helper_funcs - helper funcs used by the atomic helpers
  */
 struct drm_atomic_helper_funcs {
-	int dummy; /* for now */
+	struct drm_plane_state *(*get_plane_state)(struct drm_plane *plane, void *state);
+	int (*check_plane_state)(struct drm_plane *plane, struct drm_plane_state *pstate);
+	int (*commit_plane_state)(struct drm_plane *plane, struct drm_plane_state *pstate);
 };
 
 const extern struct drm_atomic_helper_funcs drm_atomic_helper_funcs;
@@ -76,6 +78,39 @@ int drm_atomic_helper_commit(struct drm_device *dev, void *state);
 int drm_atomic_helper_commit_unlocked(struct drm_device *dev, void *state);
 void drm_atomic_helper_end(struct drm_device *dev, void *state);
 
+int drm_atomic_helper_plane_set_property(struct drm_plane *plane, void *state,
+		struct drm_property *property, uint64_t val, void *blob_data);
+void drm_atomic_helper_init_plane_state(struct drm_plane *plane,
+		struct drm_plane_state *pstate, void *state);
+void drm_atomic_helper_destroy_plane_state(struct drm_plane *plane,
+		struct drm_plane_state *state);
+
+static inline struct drm_plane_state *
+drm_atomic_get_plane_state(struct drm_plane *plane, void *state)
+{
+	const struct drm_atomic_helper_funcs *funcs =
+			plane->dev->driver->atomic_helpers;
+	return funcs->get_plane_state(plane, state);
+}
+
+static inline int
+drm_atomic_check_plane_state(struct drm_plane *plane,
+		struct drm_plane_state *pstate)
+{
+	const struct drm_atomic_helper_funcs *funcs =
+			plane->dev->driver->atomic_helpers;
+	return funcs->check_plane_state(plane, pstate);
+}
+
+static inline int
+drm_atomic_commit_plane_state(struct drm_plane *plane,
+		struct drm_plane_state *pstate)
+{
+	const struct drm_atomic_helper_funcs *funcs =
+			plane->dev->driver->atomic_helpers;
+	return funcs->commit_plane_state(plane, pstate);
+}
+
 /**
  * struct drm_atomic_helper_state - the state object used by atomic helpers
  */
@@ -83,6 +118,8 @@ struct drm_atomic_helper_state {
 	struct kref refcount;
 	struct drm_device *dev;
 	uint32_t flags;
+	struct drm_plane **planes;
+	struct drm_plane_state **pstates;
 
 	bool committed;
 
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 40eec19..9a4c16e 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -753,6 +753,45 @@ struct drm_plane_funcs {
 };
 
 /**
+ * drm_plane_state - mutable plane state
+ * @new_fb: has the fb been changed
+ * @crtc: currently bound CRTC
+ * @fb: currently bound fb
+ * @crtc_x: left position of visible portion of plane on crtc
+ * @crtc_y: upper position of visible portion of plane on crtc
+ * @crtc_w: width of visible portion of plane on crtc
+ * @crtc_h: height of visible portion of plane on crtc
+ * @src_x: left position of visible portion of plane within
+ *   plane (in 16.16)
+ * @src_y: upper position of visible portion of plane within
+ *   plane (in 16.16)
+ * @src_w: width of visible portion of plane (in 16.16)
+ * @src_h: height of visible portion of plane (in 16.16)
+ * @propvals: property values
+ * @state: current global/toplevel state object (for atomic) while an
+ *    update is in progress, NULL otherwise.
+ */
+struct drm_plane_state {
+	bool new_fb            : 1;
+	struct drm_crtc *crtc;
+	struct drm_framebuffer *fb;
+
+	/* Signed dest location allows it to be partially off screen */
+	int32_t crtc_x, crtc_y;
+	uint32_t crtc_w, crtc_h;
+
+	/* Source values are 16.16 fixed point */
+	uint32_t src_x, src_y;
+	uint32_t src_h, src_w;
+
+	bool enabled;
+
+	struct drm_object_property_values propvals;
+
+	void *state;
+};
+
+/**
  * drm_plane - central DRM plane control structure
  * @dev: DRM device this plane belongs to
  * @head: for list management
@@ -760,8 +799,8 @@ struct drm_plane_funcs {
  * @possible_crtcs: pipes this plane can be bound to
  * @format_types: array of formats supported by this plane
  * @format_count: number of formats supported
- * @crtc: currently bound CRTC
- * @fb: currently bound fb
+ * @id: plane number, 0..n
+ * @state: the mutable state
  * @funcs: helper functions
  * @properties: property tracking for this plane
  */
@@ -775,13 +814,17 @@ struct drm_plane {
 	uint32_t *format_types;
 	uint32_t format_count;
 
-	struct drm_crtc *crtc;
-	struct drm_framebuffer *fb;
+	int id;
+
+	/*
+	 * State that can be updated from userspace, and atomically
+	 * commited or rolled back:
+	 */
+	struct drm_plane_state *state;
 
 	const struct drm_plane_funcs *funcs;
 
 	struct drm_object_properties properties;
-	struct drm_object_property_values propvals;
 };
 
 /**
@@ -962,8 +1005,20 @@ struct drm_mode_config {
 	bool poll_running;
 	struct delayed_work output_poll_work;
 
-	/* pointers to standard properties */
+	/* just so blob properties can always be in a list: */
 	struct list_head property_blob_list;
+
+	/* pointers to standard properties */
+	struct drm_property *prop_src_x;
+	struct drm_property *prop_src_y;
+	struct drm_property *prop_src_w;
+	struct drm_property *prop_src_h;
+	struct drm_property *prop_crtc_x;
+	struct drm_property *prop_crtc_y;
+	struct drm_property *prop_crtc_w;
+	struct drm_property *prop_crtc_h;
+	struct drm_property *prop_fb_id;
+	struct drm_property *prop_crtc_id;
 	struct drm_property *edid_property;
 	struct drm_property *dpms_property;
 
@@ -1043,7 +1098,15 @@ extern int drm_plane_init(struct drm_device *dev,
 			  const uint32_t *formats, uint32_t format_count,
 			  bool priv);
 extern void drm_plane_cleanup(struct drm_plane *plane);
-extern void drm_plane_force_disable(struct drm_plane *plane);
+extern void drm_plane_force_disable(struct drm_plane *plane, void *state);
+extern int drm_plane_check_state(struct drm_plane *plane,
+		struct drm_plane_state *state);
+extern void drm_plane_commit_state(struct drm_plane *plane,
+		struct drm_plane_state *state);
+extern int drm_plane_set_property(struct drm_plane *plane,
+		struct drm_plane_state *state,
+		struct drm_property *property,
+		uint64_t value, void *blob_data);
 
 extern void drm_encoder_cleanup(struct drm_encoder *encoder);
 
@@ -1115,6 +1178,17 @@ extern int drm_object_property_set_value(struct drm_mode_object *obj,
 extern int drm_object_property_get_value(struct drm_mode_object *obj,
 					 struct drm_property *property,
 					 uint64_t *value);
+
+int drm_mode_connector_set_obj_prop(struct drm_connector *connector,
+					   void *state, struct drm_property *property,
+					   uint64_t value, void *blob_data);
+int drm_mode_crtc_set_obj_prop(struct drm_crtc *crtc,
+				      void *state, struct drm_property *property,
+				      uint64_t value, void *blob_data);
+int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
+				      void *state, struct drm_property *property,
+				      uint64_t value, void *blob_data);
+
 extern int drm_framebuffer_init(struct drm_device *dev,
 				struct drm_framebuffer *fb,
 				const struct drm_framebuffer_funcs *funcs);
-- 
1.8.4.2

  parent reply	other threads:[~2013-11-25 14:48 UTC|newest]

Thread overview: 32+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-11-25 14:47 [RFCv4 00/14] Atomic/nuclear modeset/pageflip Rob Clark
2013-11-25 14:47 ` [RFCv4 01/14] drm: add atomic fxns Rob Clark
2013-11-25 14:47 ` [RFCv4 02/14] drm: convert crtc to ww_mutex Rob Clark
2013-11-25 14:47 ` [RFCv4 03/14] drm: add object property type Rob Clark
2013-11-25 14:47 ` [RFCv4 04/14] drm: add signed-range " Rob Clark
2013-11-25 14:47 ` [RFCv4 05/14] drm: helpers to find mode objects Rob Clark
2013-11-25 14:47 ` [RFCv4 06/14] drm: split propvals out and blob property support Rob Clark
2013-11-25 14:47 ` [RFCv4 07/14] drm: Allow drm_mode_object_find() to look up an object of any type Rob Clark
2013-11-25 14:47 ` [RFCv4 08/14] drm: Refactor object property check code Rob Clark
2013-11-25 14:47 ` Rob Clark [this message]
2014-01-28 21:52   ` [RFCv4 09/14] drm: convert plane to properties/state Sean Paul
2014-01-29 13:44     ` Rob Clark
2014-02-07  2:53       ` Sean Paul
2014-02-07 12:28         ` Rob Clark
2014-02-10 17:45           ` Sean Paul
2014-02-26 21:30   ` Sean Paul
2014-02-27  0:18     ` Rob Clark
2014-03-03 19:22       ` Sean Paul
2014-03-03 19:40         ` Rob Clark
2014-03-18 15:48   ` Sean Paul
2014-03-18 16:24     ` Rob Clark
2014-03-18 17:33       ` Sean Paul
2013-11-25 14:47 ` [RFCv4 10/14] drm: convert crtc " Rob Clark
2013-12-11 21:48   ` Matt Roper
2013-12-11 23:38     ` Rob Clark
2014-03-04 21:29   ` Sean Paul
2014-03-04 22:04     ` Rob Clark
2014-03-04 22:36       ` Sean Paul
2013-11-25 14:47 ` [RFCv4 11/14] drm: push locking down into restore_fbdev_mode Rob Clark
2013-11-25 14:47 ` [RFCv4 12/14] drm: Atomic modeset ioctl Rob Clark
2013-11-25 14:47 ` [RFCv4 13/14] drm/msm: add atomic support Rob Clark
2013-11-25 14:47 ` [RFCv4 14/14] HACK: drm: allow FB's in drm_mode_object_find Rob Clark

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1385390858-4412-10-git-send-email-robdclark@gmail.com \
    --to=robdclark@gmail.com \
    --cc=dri-devel@lists.freedesktop.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.