diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c
index 516da56..9fc7364 100644
--- a/drivers/gpu/drm/omapdrm/omap_crtc.c
+++ b/drivers/gpu/drm/omapdrm/omap_crtc.c
@@ -541,17 +541,44 @@ static void omap_crtc_atomic_flush(struct drm_crtc *crtc)
 	omap_crtc_flush(crtc);
 
 	dispc_runtime_put();
+
+	crtc->invert_dimensions = !!(crtc->primary->state->rotation &
+				    (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270)));
 }
 
-static int omap_crtc_set_property(struct drm_crtc *crtc,
-		struct drm_property *property, uint64_t val)
+static int omap_crtc_atomic_set_property(struct drm_crtc *crtc,
+					 struct drm_crtc_state *state,
+					 struct drm_property *property,
+					 uint64_t val)
 {
-	if (property == crtc->dev->mode_config.rotation_property) {
-		crtc->invert_dimensions =
-				!!(val & ((1LL << DRM_ROTATE_90) | (1LL << DRM_ROTATE_270)));
-	}
+	struct drm_plane_state *plane_state;
+	struct drm_plane *plane = crtc->primary;
+
+	/*
+	 * Delegate property set to the primary plane. Get the plane state and
+	 * set the property directly.
+	 */
+
+	plane_state = drm_atomic_get_plane_state(state->state, plane);
+	if (!plane_state)
+		return -EINVAL;
+
+	return drm_atomic_plane_set_property(plane, plane_state, property, val);
+}
 
-	return omap_plane_set_property(crtc->primary, property, val);
+static int omap_crtc_atomic_get_property(struct drm_crtc *crtc,
+					 const struct drm_crtc_state *state,
+					 struct drm_property *property,
+					 uint64_t *val)
+{
+	/*
+	 * Delegate property get to the primary plane. The
+	 * drm_atomic_plane_get_property() function isn't exported, but can be
+	 * called through drm_object_property_get_value() as that will call
+	 * drm_atomic_get_property() for atomic drivers.
+	 */
+	return drm_object_property_get_value(&crtc->primary->base, property,
+					     val);
 }
 
 static const struct drm_crtc_funcs omap_crtc_funcs = {
@@ -559,9 +586,11 @@ static const struct drm_crtc_funcs omap_crtc_funcs = {
 	.set_config = drm_atomic_helper_set_config,
 	.destroy = omap_crtc_destroy,
 	.page_flip = drm_atomic_helper_page_flip,
-	.set_property = omap_crtc_set_property,
+	.set_property = drm_atomic_helper_crtc_set_property,
 	.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
 	.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
+	.atomic_set_property = omap_crtc_atomic_set_property,
+	.atomic_get_property = omap_crtc_atomic_get_property,
 };
 
 static const struct drm_crtc_helper_funcs omap_crtc_helper_funcs = {
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h
index db973b0..bef3002 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.h
+++ b/drivers/gpu/drm/omapdrm/omap_drv.h
@@ -153,8 +153,6 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
 int omap_plane_set_enable(struct drm_plane *plane, bool enable);
 void omap_plane_install_properties(struct drm_plane *plane,
 		struct drm_mode_object *obj);
-int omap_plane_set_property(struct drm_plane *plane,
-		struct drm_property *property, uint64_t val);
 
 struct drm_encoder *omap_encoder_init(struct drm_device *dev,
 		struct omap_dss_device *dssdev);
diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c
index 7813e48..0d93468 100644
--- a/drivers/gpu/drm/omapdrm/omap_plane.c
+++ b/drivers/gpu/drm/omapdrm/omap_plane.c
@@ -51,10 +51,22 @@ struct omap_plane {
 	struct omap_drm_irq error_irq;
 };
 
-static int __omap_plane_setup(struct omap_plane *omap_plane,
-			      struct drm_crtc *crtc,
-			      struct drm_framebuffer *fb)
+struct omap_plane_state {
+	struct drm_plane_state base;
+
+	unsigned int zorder;
+};
+
+static inline struct omap_plane_state *
+to_omap_plane_state(struct drm_plane_state *state)
 {
+	return container_of(state, struct omap_plane_state, base);
+}
+
+static int omap_plane_setup(struct omap_plane *omap_plane)
+{
+	struct drm_plane_state *state = omap_plane->base.state;
+	struct omap_plane_state *omap_state = to_omap_plane_state(state);
 	struct omap_overlay_info *info = &omap_plane->info;
 	struct drm_device *dev = omap_plane->base.dev;
 	int ret;
@@ -66,8 +78,10 @@ static int __omap_plane_setup(struct omap_plane *omap_plane,
 		return 0;
 	}
 
+	info->zorder = omap_state->zorder;
+
 	/* update scanout: */
-	omap_framebuffer_update_scanout(fb, &omap_plane->win, info);
+	omap_framebuffer_update_scanout(state->fb, &omap_plane->win, info);
 
 	DBG("%dx%d -> %dx%d (%d)", info->width, info->height,
 			info->out_width, info->out_height,
@@ -76,11 +90,11 @@ static int __omap_plane_setup(struct omap_plane *omap_plane,
 			&info->paddr, &info->p_uv_addr);
 
 	dispc_ovl_set_channel_out(omap_plane->id,
-				  omap_crtc_channel(crtc));
+				  omap_crtc_channel(state->crtc));
 
 	/* and finally, update omapdss: */
 	ret = dispc_ovl_setup(omap_plane->id, info, false,
-			      omap_crtc_timings(crtc), false);
+			      omap_crtc_timings(state->crtc), false);
 	if (ret) {
 		dev_err(dev->dev, "dispc_ovl_setup failed: %d\n", ret);
 		return ret;
@@ -91,27 +105,21 @@ static int __omap_plane_setup(struct omap_plane *omap_plane,
 	return 0;
 }
 
-static int omap_plane_setup(struct omap_plane *omap_plane)
-{
-	struct drm_plane *plane = &omap_plane->base;
-	int ret;
-
-	dispc_runtime_get();
-	ret = __omap_plane_setup(omap_plane, plane->crtc, plane->fb);
-	dispc_runtime_put();
-
-	return ret;
-}
-
 int omap_plane_set_enable(struct drm_plane *plane, bool enable)
 {
 	struct omap_plane *omap_plane = to_omap_plane(plane);
+	int ret;
 
 	if (enable == omap_plane->enabled)
 		return 0;
 
 	omap_plane->enabled = enable;
-	return omap_plane_setup(omap_plane);
+
+	dispc_runtime_get();
+	ret = omap_plane_setup(omap_plane);
+	dispc_runtime_put();
+
+	return ret;
 }
 
 static int omap_plane_prepare_fb(struct drm_plane *plane,
@@ -140,8 +148,10 @@ static void omap_plane_atomic_update(struct drm_plane *plane,
 	if (!state->fb || !state->crtc)
 		return;
 
+	win->rotation = state->rotation;
+
 	/* omap_framebuffer_update_scanout() takes adjusted src */
-	switch (omap_plane->win.rotation & 0xf) {
+	switch (state->rotation & 0xf) {
 	case BIT(DRM_ROTATE_90):
 	case BIT(DRM_ROTATE_270):
 		src_w = state->src_h;
@@ -165,23 +175,24 @@ static void omap_plane_atomic_update(struct drm_plane *plane,
 	win->src_h = src_h >> 16;
 
 	omap_plane->enabled = true;
-	__omap_plane_setup(omap_plane, state->crtc, state->fb);
+	omap_plane_setup(omap_plane);
 }
 
 static void omap_plane_atomic_disable(struct drm_plane *plane,
 				      struct drm_plane_state *old_state)
 {
+	struct omap_plane_state *omap_state = to_omap_plane_state(plane->state);
 	struct omap_plane *omap_plane = to_omap_plane(plane);
 
-	omap_plane->win.rotation = BIT(DRM_ROTATE_0);
-	omap_plane->info.zorder = plane->type == DRM_PLANE_TYPE_PRIMARY
-				? 0 : omap_plane->id;
+	plane->state->rotation = BIT(DRM_ROTATE_0);
+	omap_state->zorder = plane->type == DRM_PLANE_TYPE_PRIMARY
+			   ? 0 : omap_plane->id;
 
 	if (!omap_plane->enabled)
 		return;
 
 	omap_plane->enabled = false;
-	__omap_plane_setup(omap_plane, NULL, NULL);
+	omap_plane_setup(omap_plane);
 }
 
 static const struct drm_plane_helper_funcs omap_plane_helper_funcs = {
@@ -191,6 +202,33 @@ static const struct drm_plane_helper_funcs omap_plane_helper_funcs = {
 	.atomic_disable = omap_plane_atomic_disable,
 };
 
+static void omap_plane_reset(struct drm_plane *plane)
+{
+	struct omap_plane *omap_plane = to_omap_plane(plane);
+	struct omap_plane_state *omap_state;
+
+	if (plane->state && plane->state->fb)
+		drm_framebuffer_unreference(plane->state->fb);
+
+	kfree(plane->state);
+	plane->state = NULL;
+
+	omap_state = kzalloc(sizeof(*omap_state), GFP_KERNEL);
+	if (omap_state == NULL)
+		return;
+
+	/*
+	 * Set defaults depending on whether we are a primary or overlay
+	 * plane.
+	 */
+	omap_state->zorder = plane->type == DRM_PLANE_TYPE_PRIMARY
+			   ? 0 : omap_plane->id;
+	omap_state->base.rotation = BIT(DRM_ROTATE_0);
+
+	plane->state = &omap_state->base;
+	plane->state->plane = plane;
+}
+
 static void omap_plane_destroy(struct drm_plane *plane)
 {
 	struct omap_plane *omap_plane = to_omap_plane(plane);
@@ -220,45 +258,74 @@ void omap_plane_install_properties(struct drm_plane *plane,
 	drm_object_attach_property(obj, priv->zorder_prop, 0);
 }
 
-int omap_plane_set_property(struct drm_plane *plane,
-		struct drm_property *property, uint64_t val)
+static struct drm_plane_state *
+omap_plane_atomic_duplicate_state(struct drm_plane *plane)
+{
+	struct omap_plane_state *omap_state;
+
+	omap_state = kmemdup(to_omap_plane_state(plane->state),
+			      sizeof(*omap_state), GFP_KERNEL);
+	if (!omap_state)
+		return NULL;
+
+	if (omap_state->base.fb)
+		drm_framebuffer_reference(omap_state->base.fb);
+
+	return &omap_state->base;
+}
+
+static void omap_plane_atomic_destroy_state(struct drm_plane *plane,
+					    struct drm_plane_state *state)
+{
+	if (state->fb)
+		drm_framebuffer_unreference(state->fb);
+
+	kfree(to_omap_plane_state(state));
+}
+
+static int omap_plane_atomic_set_property(struct drm_plane *plane,
+					  struct drm_plane_state *state,
+					  struct drm_property *property,
+					  uint64_t val)
 {
-	struct omap_plane *omap_plane = to_omap_plane(plane);
 	struct omap_drm_private *priv = plane->dev->dev_private;
-	int ret;
+	struct omap_plane_state *omap_state = to_omap_plane_state(state);
 
-	if (property == plane->dev->mode_config.rotation_property) {
-		DBG("%s: rotation: %02x", omap_plane->name, (uint32_t)val);
-		omap_plane->win.rotation = val;
-	} else if (property == priv->zorder_prop) {
-		DBG("%s: zorder: %02x", omap_plane->name, (uint32_t)val);
-		omap_plane->info.zorder = val;
-	} else {
+	if (property == priv->zorder_prop)
+		omap_state->zorder = val;
+	else
 		return -EINVAL;
-	}
 
-	/*
-	 * We're done if the plane is disabled, properties will be applied the
-	 * next time it becomes enabled.
-	 */
-	if (!omap_plane->enabled)
-		return 0;
+	return 0;
+}
 
-	ret = omap_plane_setup(omap_plane);
-	if (ret < 0)
-		return ret;
+static int omap_plane_atomic_get_property(struct drm_plane *plane,
+					  const struct drm_plane_state *state,
+					  struct drm_property *property,
+					  uint64_t *val)
+{
+	struct omap_drm_private *priv = plane->dev->dev_private;
+	const struct omap_plane_state *omap_state =
+		container_of(state, const struct omap_plane_state, base);
+
+	if (property == priv->zorder_prop)
+		*val = omap_state->zorder;
+	else
+		return -EINVAL;
 
-	return omap_crtc_flush(plane->crtc);
+	return 0;
 }
 
 static const struct drm_plane_funcs omap_plane_funcs = {
 	.update_plane = drm_atomic_helper_update_plane,
 	.disable_plane = drm_atomic_helper_disable_plane,
-	.reset = drm_atomic_helper_plane_reset,
+	.reset = omap_plane_reset,
 	.destroy = omap_plane_destroy,
-	.set_property = omap_plane_set_property,
-	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
-	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+	.set_property = drm_atomic_helper_plane_set_property,
+	.atomic_duplicate_state = omap_plane_atomic_duplicate_state,
+	.atomic_destroy_state = omap_plane_atomic_destroy_state,
+	.atomic_set_property = omap_plane_atomic_set_property,
+	.atomic_get_property = omap_plane_atomic_get_property,
 };
 
 static void omap_plane_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
@@ -330,16 +397,6 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
 	info->global_alpha = 0xff;
 	info->mirror = 0;
 
-	/* Set defaults depending on whether we are a CRTC or overlay
-	 * layer.
-	 * TODO add ioctl to give userspace an API to change this.. this
-	 * will come in a subsequent patch.
-	 */
-	if (type == DRM_PLANE_TYPE_PRIMARY)
-		omap_plane->info.zorder = 0;
-	else
-		omap_plane->info.zorder = id;
-
 	return plane;
 
 error:
