diff mbox

[02/17] drm: add atomic fxns

Message ID 1400956226-28053-3-git-send-email-robdclark@gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Rob Clark May 24, 2014, 6:30 p.m. UTC
The 'atomic' mechanism allows for multiple properties to be updated,
checked, and commited atomically.  This will be the basis of atomic-
modeset and nuclear-pageflip.

The basic flow is:

   state = dev->atomic_begin();
   for (... one or more ...)
      obj->set_property(obj, state, prop, value);
   if (dev->atomic_check(state))
      dev->atomic_commit(state);
   dev->atomic_end(state);

The split of check and commit steps is to allow for ioctls with a
test-only flag (which would skip the commit step).

Signed-off-by: Rob Clark <robdclark@gmail.com>
---
 drivers/gpu/drm/Makefile                    |   2 +-
 drivers/gpu/drm/armada/armada_crtc.c        |   3 +-
 drivers/gpu/drm/armada/armada_output.c      |   3 +-
 drivers/gpu/drm/armada/armada_overlay.c     |   3 +-
 drivers/gpu/drm/ast/ast_drv.c               |   6 ++
 drivers/gpu/drm/ast/ast_drv.h               |   1 +
 drivers/gpu/drm/cirrus/cirrus_drv.c         |   6 ++
 drivers/gpu/drm/cirrus/cirrus_drv.h         |   1 +
 drivers/gpu/drm/drm_atomic.c                | 142 +++++++++++++++++++++++++++
 drivers/gpu/drm/drm_crtc.c                  | 144 +++++++++++++++++-----------
 drivers/gpu/drm/exynos/exynos_drm_crtc.c    |   4 +-
 drivers/gpu/drm/exynos/exynos_drm_drv.c     |   7 ++
 drivers/gpu/drm/exynos/exynos_drm_plane.c   |   4 +-
 drivers/gpu/drm/gma500/cdv_intel_crt.c      |   4 +-
 drivers/gpu/drm/gma500/cdv_intel_dp.c       |   4 +-
 drivers/gpu/drm/gma500/cdv_intel_hdmi.c     |   4 +-
 drivers/gpu/drm/gma500/cdv_intel_lvds.c     |   4 +-
 drivers/gpu/drm/gma500/mdfld_dsi_output.c   |   4 +-
 drivers/gpu/drm/gma500/psb_drv.c            |   7 ++
 drivers/gpu/drm/gma500/psb_drv.h            |   1 +
 drivers/gpu/drm/gma500/psb_intel_drv.h      |   4 +-
 drivers/gpu/drm/gma500/psb_intel_lvds.c     |   4 +-
 drivers/gpu/drm/gma500/psb_intel_sdvo.c     |   4 +-
 drivers/gpu/drm/i915/i915_drv.c             |   8 ++
 drivers/gpu/drm/i915/intel_crt.c            |   4 +-
 drivers/gpu/drm/i915/intel_dp.c             |   4 +-
 drivers/gpu/drm/i915/intel_drv.h            |   1 +
 drivers/gpu/drm/i915/intel_hdmi.c           |   4 +-
 drivers/gpu/drm/i915/intel_lvds.c           |   4 +-
 drivers/gpu/drm/i915/intel_sdvo.c           |   4 +-
 drivers/gpu/drm/i915/intel_tv.c             |   6 +-
 drivers/gpu/drm/mgag200/mgag200_drv.c       |   7 ++
 drivers/gpu/drm/mgag200/mgag200_drv.h       |   1 +
 drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c    |   3 +-
 drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c   |   3 +-
 drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c    |   3 +-
 drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c   |   3 +-
 drivers/gpu/drm/msm/msm_drv.c               |   6 ++
 drivers/gpu/drm/msm/msm_drv.h               |   1 +
 drivers/gpu/drm/nouveau/dispnv04/overlay.c  |   5 +-
 drivers/gpu/drm/nouveau/nouveau_connector.c |   3 +-
 drivers/gpu/drm/nouveau/nouveau_drm.c       |   7 ++
 drivers/gpu/drm/nouveau/nouveau_drm.h       |   1 +
 drivers/gpu/drm/omapdrm/omap_crtc.c         |   6 +-
 drivers/gpu/drm/omapdrm/omap_drv.c          |   6 ++
 drivers/gpu/drm/omapdrm/omap_drv.h          |   4 +-
 drivers/gpu/drm/omapdrm/omap_plane.c        |   3 +-
 drivers/gpu/drm/qxl/qxl_display.c           |   4 +-
 drivers/gpu/drm/qxl/qxl_drv.c               |   9 ++
 drivers/gpu/drm/radeon/radeon_connectors.c  |   9 +-
 drivers/gpu/drm/radeon/radeon_drv.c         |   9 ++
 drivers/gpu/drm/rcar-du/rcar_du_drv.c       |   7 ++
 drivers/gpu/drm/rcar-du/rcar_du_plane.c     |   4 +-
 drivers/gpu/drm/shmobile/shmob_drm_drv.c    |   7 ++
 drivers/gpu/drm/tilcdc/tilcdc_drv.c         |   6 ++
 drivers/gpu/drm/tilcdc/tilcdc_drv.h         |   1 +
 drivers/gpu/drm/tilcdc/tilcdc_slave.c       |   3 +-
 drivers/gpu/drm/udl/udl_connector.c         |   6 +-
 drivers/gpu/drm/udl/udl_drv.c               |   8 ++
 drivers/gpu/drm/vmwgfx/vmwgfx_drv.c         |   7 ++
 drivers/gpu/drm/vmwgfx/vmwgfx_drv.h         |   1 +
 drivers/gpu/drm/vmwgfx/vmwgfx_kms.c         |   4 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_kms.h         |   4 +-
 include/drm/drmP.h                          |  80 ++++++++++++++++
 include/drm/drm_atomic.h                    | 107 +++++++++++++++++++++
 include/drm/drm_crtc.h                      |  15 ++-
 66 files changed, 652 insertions(+), 102 deletions(-)
 create mode 100644 drivers/gpu/drm/drm_atomic.c
 create mode 100644 include/drm/drm_atomic.h
diff mbox

Patch

diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 48e38ba..ba2ed83 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -14,7 +14,7 @@  drm-y       :=	drm_auth.o drm_buffer.o drm_bufs.o drm_cache.o \
 		drm_info.o drm_debugfs.o drm_encoder_slave.o \
 		drm_trace_points.o drm_global.o drm_prime.o \
 		drm_rect.o drm_vma_manager.o drm_flip_work.o \
-		drm_plane_helper.o
+		drm_plane_helper.o drm_atomic.o
 
 drm-$(CONFIG_COMPAT) += drm_ioc32.o
 drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c
index 81c34f9..7d3c649 100644
--- a/drivers/gpu/drm/armada/armada_crtc.c
+++ b/drivers/gpu/drm/armada/armada_crtc.c
@@ -961,7 +961,8 @@  static int armada_drm_crtc_page_flip(struct drm_crtc *crtc,
 
 static int
 armada_drm_crtc_set_property(struct drm_crtc *crtc,
-	struct drm_property *property, uint64_t val)
+	struct drm_atomic_state *state, struct drm_property *property,
+	uint64_t val, void *blob_data)
 {
 	struct armada_private *priv = crtc->dev->dev_private;
 	struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
diff --git a/drivers/gpu/drm/armada/armada_output.c b/drivers/gpu/drm/armada/armada_output.c
index d685a54..9915306 100644
--- a/drivers/gpu/drm/armada/armada_output.c
+++ b/drivers/gpu/drm/armada/armada_output.c
@@ -54,7 +54,8 @@  static void armada_drm_connector_destroy(struct drm_connector *conn)
 }
 
 static int armada_drm_connector_set_property(struct drm_connector *conn,
-	struct drm_property *property, uint64_t value)
+	struct drm_atomic_state *state, struct drm_property *property,
+	uint64_t value, void *blob_data)
 {
 	struct armada_connector *dconn = drm_to_armada_conn(conn);
 
diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c
index c5b06fd..601ba9a 100644
--- a/drivers/gpu/drm/armada/armada_overlay.c
+++ b/drivers/gpu/drm/armada/armada_overlay.c
@@ -283,7 +283,8 @@  static void armada_plane_destroy(struct drm_plane *plane)
 }
 
 static int armada_plane_set_property(struct drm_plane *plane,
-	struct drm_property *property, uint64_t val)
+	struct drm_atomic_state *state, struct drm_property *property,
+	uint64_t val, void *blob_data)
 {
 	struct armada_private *priv = plane->dev->dev_private;
 	struct armada_plane *dplane = drm_to_armada_plane(plane);
diff --git a/drivers/gpu/drm/ast/ast_drv.c b/drivers/gpu/drm/ast/ast_drv.c
index 2ba39ac..cd81d68 100644
--- a/drivers/gpu/drm/ast/ast_drv.c
+++ b/drivers/gpu/drm/ast/ast_drv.c
@@ -215,6 +215,12 @@  static struct drm_driver driver = {
 	.dumb_map_offset = ast_dumb_mmap_offset,
 	.dumb_destroy = drm_gem_dumb_destroy,
 
+	.atomic_begin     = drm_atomic_begin,
+	.atomic_set_event = drm_atomic_set_event,
+	.atomic_check     = drm_atomic_check,
+	.atomic_commit    = drm_atomic_commit,
+	.atomic_end       = drm_atomic_end,
+	.atomic_funcs     = &drm_atomic_funcs,
 };
 
 static int __init ast_init(void)
diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h
index 5d6a875..0d21ff8 100644
--- a/drivers/gpu/drm/ast/ast_drv.h
+++ b/drivers/gpu/drm/ast/ast_drv.h
@@ -29,6 +29,7 @@ 
 #define __AST_DRV_H__
 
 #include <drm/drm_fb_helper.h>
+#include <drm/drm_atomic.h>
 
 #include <drm/ttm/ttm_bo_api.h>
 #include <drm/ttm/ttm_bo_driver.h>
diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.c b/drivers/gpu/drm/cirrus/cirrus_drv.c
index 08ce520..023db21 100644
--- a/drivers/gpu/drm/cirrus/cirrus_drv.c
+++ b/drivers/gpu/drm/cirrus/cirrus_drv.c
@@ -137,6 +137,12 @@  static struct drm_driver driver = {
 	.dumb_create = cirrus_dumb_create,
 	.dumb_map_offset = cirrus_dumb_mmap_offset,
 	.dumb_destroy = drm_gem_dumb_destroy,
+	.atomic_begin     = drm_atomic_begin,
+	.atomic_set_event = drm_atomic_set_event,
+	.atomic_check     = drm_atomic_check,
+	.atomic_commit    = drm_atomic_commit,
+	.atomic_end       = drm_atomic_end,
+	.atomic_funcs     = &drm_atomic_funcs,
 };
 
 static const struct dev_pm_ops cirrus_pm_ops = {
diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.h b/drivers/gpu/drm/cirrus/cirrus_drv.h
index 117d3ec..f929bc8 100644
--- a/drivers/gpu/drm/cirrus/cirrus_drv.h
+++ b/drivers/gpu/drm/cirrus/cirrus_drv.h
@@ -14,6 +14,7 @@ 
 #include <video/vga.h>
 
 #include <drm/drm_fb_helper.h>
+#include <drm/drm_atomic.h>
 
 #include <drm/ttm/ttm_bo_api.h>
 #include <drm/ttm/ttm_bo_driver.h>
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
new file mode 100644
index 0000000..12fcbc0
--- /dev/null
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -0,0 +1,142 @@ 
+/*
+ * Copyright (C) 2014 Red Hat
+ * Author: Rob Clark <robdclark@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic.h>
+
+/**
+ * drm_atomic_begin - start a sequence of atomic updates
+ * @dev: DRM device
+ * @flags: the modifier flags that userspace has requested
+ *
+ * Begin a sequence of atomic property sets.  Returns a driver
+ * private state object that is passed back into the various
+ * object's set_property() fxns, and into the remainder of the
+ * atomic funcs.  The state object should accumulate the changes
+ * from one o more set_property()'s.  At the end, the state can
+ * be checked, and optionally committed.
+ *
+ * RETURNS
+ *   a driver state object, which is passed back in to the
+ *   various other atomic fxns, or error (such as -EBUSY if
+ *   there is still a pending async update)
+ */
+struct drm_atomic_state *drm_atomic_begin(struct drm_device *dev,
+		uint32_t flags)
+{
+	struct drm_atomic_state *state;
+	int sz;
+	void *ptr;
+
+	sz = sizeof(*state);
+
+	ptr = kzalloc(sz, GFP_KERNEL);
+
+	state = ptr;
+	ptr = &state[1];
+
+	kref_init(&state->refcount);
+	state->dev = dev;
+	state->flags = flags;
+	return state;
+}
+EXPORT_SYMBOL(drm_atomic_begin);
+
+/**
+ * drm_atomic_set_event - set a pending event on mode object
+ * @dev: DRM device
+ * @state: the driver state object
+ * @obj: the object to set the event on
+ * @event: the event to send back
+ *
+ * Set pending event for an update on the specified object.  The
+ * event is to be sent back to userspace after the update completes.
+ */
+int drm_atomic_set_event(struct drm_device *dev,
+		struct drm_atomic_state *state, struct drm_mode_object *obj,
+		struct drm_pending_vblank_event *event)
+{
+	return -EINVAL;  /* for now */
+}
+EXPORT_SYMBOL(drm_atomic_set_event);
+
+/**
+ * drm_atomic_check - validate state object
+ * @dev: DRM device
+ * @state: the driver state object
+ *
+ * Check the state object to see if the requested state is
+ * physically possible.
+ *
+ * RETURNS
+ * Zero for success or -errno
+ */
+int drm_atomic_check(struct drm_device *dev, struct drm_atomic_state *state)
+{
+	return 0;  /* for now */
+}
+EXPORT_SYMBOL(drm_atomic_check);
+
+/**
+ * drm_atomic_commit - commit state
+ * @dev: DRM device
+ * @state: the driver state object
+ *
+ * Commit the state.  This will only be called if atomic_check()
+ * succeeds.
+ *
+ * RETURNS
+ * Zero for success or -errno
+ */
+int drm_atomic_commit(struct drm_device *dev, struct drm_atomic_state *state)
+{
+	return 0;  /* for now */
+}
+EXPORT_SYMBOL(drm_atomic_commit);
+
+/**
+ * drm_atomic_end - conclude the atomic update
+ * @dev: DRM device
+ * @state: the driver state object
+ *
+ * Release resources associated with the state object.
+ */
+void drm_atomic_end(struct drm_device *dev, struct drm_atomic_state *state)
+{
+	drm_atomic_state_unreference(state);
+}
+EXPORT_SYMBOL(drm_atomic_end);
+
+void _drm_atomic_state_free(struct kref *kref)
+{
+	struct drm_atomic_state *state =
+		container_of(kref, struct drm_atomic_state, refcount);
+	kfree(state);
+}
+EXPORT_SYMBOL(_drm_atomic_state_free);
+
+
+const struct drm_atomic_funcs drm_atomic_funcs = {
+};
+EXPORT_SYMBOL(drm_atomic_funcs);
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 34f0bf1..1876abb 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -3731,20 +3731,21 @@  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_mode_object *obj,
-					   struct drm_property *property,
-					   uint64_t value)
+static int drm_mode_connector_set_obj_prop(struct drm_connector *connector,
+					   struct drm_atomic_state *state, struct drm_property *property,
+					   uint64_t value, void *blob_data)
 {
 	int ret = -EINVAL;
-	struct drm_connector *connector = obj_to_connector(obj);
 
 	/* Do DPMS ourselves */
 	if (property == connector->dev->mode_config.dpms_property) {
 		if (connector->funcs->dpms)
 			(*connector->funcs->dpms)(connector, (int)value);
 		ret = 0;
-	} else if (connector->funcs->set_property)
-		ret = connector->funcs->set_property(connector, property, value);
+	} else if (connector->funcs->set_property) {
+		ret = connector->funcs->set_property(connector, state,
+				property, value, blob_data);
+	}
 
 	/* store the property value if successful */
 	if (!ret)
@@ -3752,38 +3753,93 @@  static int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj,
 	return ret;
 }
 
-static int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj,
-				      struct drm_property *property,
-				      uint64_t value)
+static int drm_mode_crtc_set_obj_prop(struct drm_crtc *crtc,
+				      struct drm_atomic_state *state, struct drm_property *property,
+				      uint64_t value, void *blob_data)
 {
 	int ret = -EINVAL;
-	struct drm_crtc *crtc = obj_to_crtc(obj);
 
 	if (crtc->funcs->set_property)
-		ret = crtc->funcs->set_property(crtc, property, value);
+		ret = crtc->funcs->set_property(crtc, state, property,
+				value, blob_data);
 	if (!ret)
-		drm_object_property_set_value(obj, property, value);
+		drm_object_property_set_value(&crtc->base, property, value);
 
 	return ret;
 }
 
-static int drm_mode_plane_set_obj_prop(struct drm_mode_object *obj,
-				      struct drm_property *property,
-				      uint64_t value)
+static int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
+				      struct drm_atomic_state *state, struct drm_property *property,
+				      uint64_t value, void *blob_data)
 {
 	int ret = -EINVAL;
-	struct drm_plane *plane = obj_to_plane(obj);
 
 	if (plane->funcs->set_property)
-		ret = plane->funcs->set_property(plane, property, value);
+		ret = plane->funcs->set_property(plane, state, property,
+				value, blob_data);
 	if (!ret)
-		drm_object_property_set_value(obj, property, value);
+		drm_object_property_set_value(&plane->base, property, value);
 
 	return ret;
 }
 
+static int drm_mode_set_obj_prop(struct drm_device *dev,
+		struct drm_mode_object *obj, struct drm_atomic_state *state,
+		struct drm_property *property, uint64_t value, void *blob_data)
+{
+	if (drm_property_change_is_valid(property, value)) {
+		switch (obj->type) {
+		case DRM_MODE_OBJECT_CONNECTOR:
+			return drm_mode_connector_set_obj_prop(obj_to_connector(obj),
+					state, property, value, blob_data);
+		case DRM_MODE_OBJECT_CRTC:
+			return drm_mode_crtc_set_obj_prop(obj_to_crtc(obj),
+					state, property, value, blob_data);
+		case DRM_MODE_OBJECT_PLANE:
+			return drm_mode_plane_set_obj_prop(obj_to_plane(obj),
+					state, property, value, blob_data);
+		}
+	}
+
+	return -EINVAL;
+}
+
+/* call with mode_config mutex held */
+static int drm_mode_set_obj_prop_id(struct drm_device *dev,
+		struct drm_atomic_state *state,
+		uint32_t obj_id, uint32_t obj_type,
+		uint32_t prop_id, uint64_t value, void *blob_data)
+{
+	struct drm_mode_object *arg_obj;
+	struct drm_mode_object *prop_obj;
+	struct drm_property *property;
+	int i;
+
+	arg_obj = drm_mode_object_find(dev, obj_id, obj_type);
+	if (!arg_obj)
+		return -ENOENT;
+	if (!arg_obj->properties)
+		return -EINVAL;
+
+	for (i = 0; i < arg_obj->properties->count; i++)
+		if (arg_obj->properties->ids[i] == prop_id)
+			break;
+
+	if (i == arg_obj->properties->count)
+		return -EINVAL;
+
+	prop_obj = drm_mode_object_find(dev, prop_id,
+					DRM_MODE_OBJECT_PROPERTY);
+	if (!prop_obj)
+		return -ENOENT;
+	property = obj_to_property(prop_obj);
+
+	return drm_mode_set_obj_prop(dev, arg_obj, state, property,
+			value, blob_data);
+}
+
 /**
- * drm_mode_getproperty_ioctl - get the current value of a object's property
+ * drm_mode_obj_get_properties_ioctl - get the current value of a object's property
  * @dev: DRM device
  * @data: ioctl data
  * @file_priv: DRM file info
@@ -3873,57 +3929,35 @@  int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
 				    struct drm_file *file_priv)
 {
 	struct drm_mode_obj_set_property *arg = data;
-	struct drm_mode_object *arg_obj;
-	struct drm_mode_object *prop_obj;
-	struct drm_property *property;
+	struct drm_atomic_state *state;
 	int ret = -EINVAL;
-	int i;
 
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
 
 	drm_modeset_lock_all(dev);
 
-	arg_obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type);
-	if (!arg_obj) {
-		ret = -ENOENT;
-		goto out;
+	state = dev->driver->atomic_begin(dev, 0);
+	if (IS_ERR(state)) {
+		ret = PTR_ERR(state);
+		goto out_unlock;
 	}
-	if (!arg_obj->properties)
-		goto out;
-
-	for (i = 0; i < arg_obj->properties->count; i++)
-		if (arg_obj->properties->ids[i] == arg->prop_id)
-			break;
 
-	if (i == arg_obj->properties->count)
+	ret = drm_mode_set_obj_prop_id(dev, state,
+			arg->obj_id, arg->obj_type,
+			arg->prop_id, arg->value, NULL);
+	if (ret)
 		goto out;
 
-	prop_obj = drm_mode_object_find(dev, arg->prop_id,
-					DRM_MODE_OBJECT_PROPERTY);
-	if (!prop_obj) {
-		ret = -ENOENT;
-		goto out;
-	}
-	property = obj_to_property(prop_obj);
-
-	if (!drm_property_change_is_valid(property, arg->value))
+	ret = dev->driver->atomic_check(dev, state);
+	if (ret)
 		goto out;
 
-	switch (arg_obj->type) {
-	case DRM_MODE_OBJECT_CONNECTOR:
-		ret = drm_mode_connector_set_obj_prop(arg_obj, property,
-						      arg->value);
-		break;
-	case DRM_MODE_OBJECT_CRTC:
-		ret = drm_mode_crtc_set_obj_prop(arg_obj, property, arg->value);
-		break;
-	case DRM_MODE_OBJECT_PLANE:
-		ret = drm_mode_plane_set_obj_prop(arg_obj, property, arg->value);
-		break;
-	}
+	ret = dev->driver->atomic_commit(dev, state);
 
 out:
+	dev->driver->atomic_end(dev, state);
+out_unlock:
 	drm_modeset_unlock_all(dev);
 	return ret;
 }
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index 1ef5ab9..2a56973 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -281,8 +281,10 @@  static void exynos_drm_crtc_destroy(struct drm_crtc *crtc)
 }
 
 static int exynos_drm_crtc_set_property(struct drm_crtc *crtc,
+					struct drm_atomic_state *state,
 					struct drm_property *property,
-					uint64_t val)
+					uint64_t val,
+					void *blob_data)
 {
 	struct drm_device *dev = crtc->dev;
 	struct exynos_drm_private *dev_priv = dev->dev_private;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index 2d27ba2..318969d 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -14,6 +14,7 @@ 
 #include <linux/pm_runtime.h>
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic.h>
 
 #include <linux/anon_inodes.h>
 
@@ -341,6 +342,12 @@  static struct drm_driver exynos_drm_driver = {
 	.dumb_create		= exynos_drm_gem_dumb_create,
 	.dumb_map_offset	= exynos_drm_gem_dumb_map_offset,
 	.dumb_destroy		= drm_gem_dumb_destroy,
+	.atomic_begin     = drm_atomic_begin,
+	.atomic_set_event = drm_atomic_set_event,
+	.atomic_check     = drm_atomic_check,
+	.atomic_commit    = drm_atomic_commit,
+	.atomic_end       = drm_atomic_end,
+	.atomic_funcs     = &drm_atomic_funcs,
 	.prime_handle_to_fd	= drm_gem_prime_handle_to_fd,
 	.prime_fd_to_handle	= drm_gem_prime_fd_to_handle,
 	.gem_prime_export	= exynos_dmabuf_prime_export,
diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c
index 8371cbd..9da0935 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_plane.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c
@@ -212,8 +212,10 @@  static void exynos_plane_destroy(struct drm_plane *plane)
 }
 
 static int exynos_plane_set_property(struct drm_plane *plane,
+				     struct drm_atomic_state *state,
 				     struct drm_property *property,
-				     uint64_t val)
+				     uint64_t val,
+				     void *blob_data)
 {
 	struct drm_device *dev = plane->dev;
 	struct exynos_plane *exynos_plane = to_exynos_plane(plane);
diff --git a/drivers/gpu/drm/gma500/cdv_intel_crt.c b/drivers/gpu/drm/gma500/cdv_intel_crt.c
index c18268c..6d637d3 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_crt.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_crt.c
@@ -205,8 +205,10 @@  static int cdv_intel_crt_get_modes(struct drm_connector *connector)
 }
 
 static int cdv_intel_crt_set_property(struct drm_connector *connector,
+				  struct drm_atomic_state *state,
 				  struct drm_property *property,
-				  uint64_t value)
+				  uint64_t value,
+				  void *blob_data)
 {
 	return 0;
 }
diff --git a/drivers/gpu/drm/gma500/cdv_intel_dp.c b/drivers/gpu/drm/gma500/cdv_intel_dp.c
index 9ff30c2..31d872d 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_dp.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_dp.c
@@ -1645,8 +1645,10 @@  cdv_intel_dp_detect_audio(struct drm_connector *connector)
 
 static int
 cdv_intel_dp_set_property(struct drm_connector *connector,
+		      struct drm_atomic_state *state,
 		      struct drm_property *property,
-		      uint64_t val)
+		      uint64_t val,
+		      void *blob_data)
 {
 	struct drm_psb_private *dev_priv = connector->dev->dev_private;
 	struct gma_encoder *encoder = gma_attached_encoder(connector);
diff --git a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
index b99084b..f0e4d78 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
@@ -150,8 +150,10 @@  static enum drm_connector_status cdv_hdmi_detect(
 }
 
 static int cdv_hdmi_set_property(struct drm_connector *connector,
+				       struct drm_atomic_state *state,
 				       struct drm_property *property,
-				       uint64_t value)
+				       uint64_t value,
+				       void *blob_data)
 {
 	struct drm_encoder *encoder = connector->encoder;
 
diff --git a/drivers/gpu/drm/gma500/cdv_intel_lvds.c b/drivers/gpu/drm/gma500/cdv_intel_lvds.c
index 8ecc920..7ffaed4 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_lvds.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_lvds.c
@@ -452,8 +452,10 @@  static void cdv_intel_lvds_destroy(struct drm_connector *connector)
 }
 
 static int cdv_intel_lvds_set_property(struct drm_connector *connector,
+				       struct drm_atomic_state *state,
 				       struct drm_property *property,
-				       uint64_t value)
+				       uint64_t value,
+				       void *blob_data)
 {
 	struct drm_encoder *encoder = connector->encoder;
 
diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_output.c b/drivers/gpu/drm/gma500/mdfld_dsi_output.c
index 6e91b20..2318a46 100644
--- a/drivers/gpu/drm/gma500/mdfld_dsi_output.c
+++ b/drivers/gpu/drm/gma500/mdfld_dsi_output.c
@@ -243,8 +243,10 @@  mdfld_dsi_connector_detect(struct drm_connector *connector, bool force)
 }
 
 static int mdfld_dsi_connector_set_property(struct drm_connector *connector,
+				struct drm_atomic_state *state,
 				struct drm_property *property,
-				uint64_t value)
+				uint64_t value,
+				void *blob_data)
 {
 	struct drm_encoder *encoder = connector->encoder;
 
diff --git a/drivers/gpu/drm/gma500/psb_drv.c b/drivers/gpu/drm/gma500/psb_drv.c
index 0a3101a..0180292 100644
--- a/drivers/gpu/drm/gma500/psb_drv.c
+++ b/drivers/gpu/drm/gma500/psb_drv.c
@@ -489,6 +489,13 @@  static struct drm_driver driver = {
 	.disable_vblank = psb_disable_vblank,
 	.get_vblank_counter = psb_get_vblank_counter,
 
+	.atomic_begin     = drm_atomic_begin,
+	.atomic_set_event = drm_atomic_set_event,
+	.atomic_check     = drm_atomic_check,
+	.atomic_commit    = drm_atomic_commit,
+	.atomic_end       = drm_atomic_end,
+	.atomic_funcs     = &drm_atomic_funcs,
+
 	.gem_free_object = psb_gem_free_object,
 	.gem_vm_ops = &psb_gem_vm_ops,
 
diff --git a/drivers/gpu/drm/gma500/psb_drv.h b/drivers/gpu/drm/gma500/psb_drv.h
index 55ebe2b..413ea37 100644
--- a/drivers/gpu/drm/gma500/psb_drv.h
+++ b/drivers/gpu/drm/gma500/psb_drv.h
@@ -25,6 +25,7 @@ 
 #include <drm/drmP.h>
 #include <drm/drm_global.h>
 #include <drm/gma_drm.h>
+#include <drm/drm_atomic.h>
 #include "psb_reg.h"
 #include "psb_intel_drv.h"
 #include "gma_display.h"
diff --git a/drivers/gpu/drm/gma500/psb_intel_drv.h b/drivers/gpu/drm/gma500/psb_intel_drv.h
index 336bd3a..96e9759 100644
--- a/drivers/gpu/drm/gma500/psb_intel_drv.h
+++ b/drivers/gpu/drm/gma500/psb_intel_drv.h
@@ -254,8 +254,10 @@  extern bool psb_intel_lvds_mode_fixup(struct drm_encoder *encoder,
 extern int psb_intel_lvds_mode_valid(struct drm_connector *connector,
 				     struct drm_display_mode *mode);
 extern int psb_intel_lvds_set_property(struct drm_connector *connector,
+					struct drm_atomic_state *state,
 					struct drm_property *property,
-					uint64_t value);
+					uint64_t value,
+					void *blob_data);
 extern void psb_intel_lvds_destroy(struct drm_connector *connector);
 extern const struct drm_encoder_funcs psb_intel_lvds_enc_funcs;
 
diff --git a/drivers/gpu/drm/gma500/psb_intel_lvds.c b/drivers/gpu/drm/gma500/psb_intel_lvds.c
index d7778d0..6b64d9d 100644
--- a/drivers/gpu/drm/gma500/psb_intel_lvds.c
+++ b/drivers/gpu/drm/gma500/psb_intel_lvds.c
@@ -569,8 +569,10 @@  void psb_intel_lvds_destroy(struct drm_connector *connector)
 }
 
 int psb_intel_lvds_set_property(struct drm_connector *connector,
+				       struct drm_atomic_state *state,
 				       struct drm_property *property,
-				       uint64_t value)
+				       uint64_t value,
+				       void *blob_data)
 {
 	struct drm_encoder *encoder = connector->encoder;
 
diff --git a/drivers/gpu/drm/gma500/psb_intel_sdvo.c b/drivers/gpu/drm/gma500/psb_intel_sdvo.c
index deeb082..724b525 100644
--- a/drivers/gpu/drm/gma500/psb_intel_sdvo.c
+++ b/drivers/gpu/drm/gma500/psb_intel_sdvo.c
@@ -1705,8 +1705,10 @@  static bool psb_intel_sdvo_detect_hdmi_audio(struct drm_connector *connector)
 
 static int
 psb_intel_sdvo_set_property(struct drm_connector *connector,
+			struct drm_atomic_state *state,
 			struct drm_property *property,
-			uint64_t val)
+			uint64_t val,
+			void *blob_data)
 {
 	struct psb_intel_sdvo *psb_intel_sdvo = intel_attached_sdvo(connector);
 	struct psb_intel_sdvo_connector *psb_intel_sdvo_connector = to_psb_intel_sdvo_connector(connector);
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 208e185..e3a2482 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -1119,6 +1119,14 @@  static struct drm_driver driver = {
 	.dumb_create = i915_gem_dumb_create,
 	.dumb_map_offset = i915_gem_mmap_gtt,
 	.dumb_destroy = drm_gem_dumb_destroy,
+
+	.atomic_begin     = drm_atomic_begin,
+	.atomic_set_event = drm_atomic_set_event,
+	.atomic_check     = drm_atomic_check,
+	.atomic_commit    = drm_atomic_commit,
+	.atomic_end       = drm_atomic_end,
+	.atomic_funcs     = &drm_atomic_funcs,
+
 	.ioctls = i915_ioctls,
 	.fops = &i915_driver_fops,
 	.name = DRIVER_NAME,
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index 22d8347..d4198ff 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -724,8 +724,10 @@  out:
 }
 
 static int intel_crt_set_property(struct drm_connector *connector,
+				  struct drm_atomic_state *state,
 				  struct drm_property *property,
-				  uint64_t value)
+				  uint64_t value,
+				  void *blob_data)
 {
 	return 0;
 }
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 34ed143..c63d210 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -3270,8 +3270,10 @@  intel_dp_detect_audio(struct drm_connector *connector)
 
 static int
 intel_dp_set_property(struct drm_connector *connector,
+		      struct drm_atomic_state *state,
 		      struct drm_property *property,
-		      uint64_t val)
+		      uint64_t val,
+		      void *blob_data)
 {
 	struct drm_i915_private *dev_priv = connector->dev->dev_private;
 	struct intel_connector *intel_connector = to_intel_connector(connector);
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index d8b540b..64aeae0 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -31,6 +31,7 @@ 
 #include "i915_drv.h"
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic.h>
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_dp_helper.h>
 
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index b606162..8e160b0 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -1044,8 +1044,10 @@  intel_hdmi_detect_audio(struct drm_connector *connector)
 
 static int
 intel_hdmi_set_property(struct drm_connector *connector,
+			struct drm_atomic_state *state,
 			struct drm_property *property,
-			uint64_t val)
+			uint64_t val,
+			void *blob_data)
 {
 	struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
 	struct intel_digital_port *intel_dig_port =
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index 1b1541d..4028237 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -486,8 +486,10 @@  static void intel_lvds_destroy(struct drm_connector *connector)
 }
 
 static int intel_lvds_set_property(struct drm_connector *connector,
+				   struct drm_atomic_state *state,
 				   struct drm_property *property,
-				   uint64_t value)
+				   uint64_t value,
+				   void *blob_data)
 {
 	struct intel_connector *intel_connector = to_intel_connector(connector);
 	struct drm_device *dev = connector->dev;
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index 2bf09e8..4e36ee99 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -2052,8 +2052,10 @@  static bool intel_sdvo_detect_hdmi_audio(struct drm_connector *connector)
 
 static int
 intel_sdvo_set_property(struct drm_connector *connector,
+			struct drm_atomic_state *state,
 			struct drm_property *property,
-			uint64_t val)
+			uint64_t val,
+			void *blob_data)
 {
 	struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
 	struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);
diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
index e0193e8..05ee0d5 100644
--- a/drivers/gpu/drm/i915/intel_tv.c
+++ b/drivers/gpu/drm/i915/intel_tv.c
@@ -1444,8 +1444,10 @@  intel_tv_destroy(struct drm_connector *connector)
 
 
 static int
-intel_tv_set_property(struct drm_connector *connector, struct drm_property *property,
-		      uint64_t val)
+intel_tv_set_property(struct drm_connector *connector,
+		      struct drm_atomic_state *state,
+		      struct drm_property *property,
+		      uint64_t val, void *blob_data)
 {
 	struct drm_device *dev = connector->dev;
 	struct intel_tv *intel_tv = intel_attached_tv(connector);
diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c
index f15ea3c..0425bdd 100644
--- a/drivers/gpu/drm/mgag200/mgag200_drv.c
+++ b/drivers/gpu/drm/mgag200/mgag200_drv.c
@@ -103,6 +103,13 @@  static struct drm_driver driver = {
 	.dumb_create = mgag200_dumb_create,
 	.dumb_map_offset = mgag200_dumb_mmap_offset,
 	.dumb_destroy = drm_gem_dumb_destroy,
+
+	.atomic_begin     = drm_atomic_begin,
+	.atomic_set_event = drm_atomic_set_event,
+	.atomic_check     = drm_atomic_check,
+	.atomic_commit    = drm_atomic_commit,
+	.atomic_end       = drm_atomic_end,
+	.atomic_funcs     = &drm_atomic_funcs,
 };
 
 static struct pci_driver mgag200_pci_driver = {
diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h b/drivers/gpu/drm/mgag200/mgag200_drv.h
index cf11ee6..c4d1600 100644
--- a/drivers/gpu/drm/mgag200/mgag200_drv.h
+++ b/drivers/gpu/drm/mgag200/mgag200_drv.h
@@ -16,6 +16,7 @@ 
 #include <video/vga.h>
 
 #include <drm/drm_fb_helper.h>
+#include <drm/drm_atomic.h>
 #include <drm/ttm/ttm_bo_api.h>
 #include <drm/ttm/ttm_bo_driver.h>
 #include <drm/ttm/ttm_placement.h>
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
index ef9957d..efa19c8 100644
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
+++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
@@ -468,7 +468,8 @@  static int mdp4_crtc_page_flip(struct drm_crtc *crtc,
 }
 
 static int mdp4_crtc_set_property(struct drm_crtc *crtc,
-		struct drm_property *property, uint64_t val)
+		struct drm_atomic_state *state, struct drm_property *property,
+		uint64_t val, void *blob_data)
 {
 	// XXX
 	return -EINVAL;
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c
index 66f33db..8c064dc 100644
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c
+++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c
@@ -85,7 +85,8 @@  void mdp4_plane_install_properties(struct drm_plane *plane,
 }
 
 int mdp4_plane_set_property(struct drm_plane *plane,
-		struct drm_property *property, uint64_t val)
+		struct drm_atomic_state *state, struct drm_property *property,
+		uint64_t val, void *blob_data)
 {
 	// XXX
 	return -EINVAL;
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
index 6ea10bd..ff48944 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
@@ -386,7 +386,8 @@  static int mdp5_crtc_page_flip(struct drm_crtc *crtc,
 }
 
 static int mdp5_crtc_set_property(struct drm_crtc *crtc,
-		struct drm_property *property, uint64_t val)
+		struct drm_atomic_state *state, struct drm_property *property,
+		uint64_t val, void *blob_data)
 {
 	// XXX
 	return -EINVAL;
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
index 47f7bbb..5cbf226 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
@@ -100,7 +100,8 @@  void mdp5_plane_install_properties(struct drm_plane *plane,
 }
 
 int mdp5_plane_set_property(struct drm_plane *plane,
-		struct drm_property *property, uint64_t val)
+		struct drm_atomic_state *state, struct drm_property *property,
+		uint64_t val, void *blob_data)
 {
 	// XXX
 	return -EINVAL;
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index 50ec1be..46e0f29 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -815,6 +815,12 @@  static struct drm_driver msm_driver = {
 	.gem_prime_import_sg_table = msm_gem_prime_import_sg_table,
 	.gem_prime_vmap     = msm_gem_prime_vmap,
 	.gem_prime_vunmap   = msm_gem_prime_vunmap,
+	.atomic_begin       = drm_atomic_begin,
+	.atomic_set_event   = drm_atomic_set_event,
+	.atomic_check       = drm_atomic_check,
+	.atomic_commit      = drm_atomic_commit,
+	.atomic_end         = drm_atomic_end,
+	.atomic_funcs       = &drm_atomic_funcs,
 #ifdef CONFIG_DEBUG_FS
 	.debugfs_init       = msm_debugfs_init,
 	.debugfs_cleanup    = msm_debugfs_cleanup,
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index 9d10ee0..afc990e 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -50,6 +50,7 @@  static inline struct device *msm_iommu_get_ctx(const char *ctx_name)
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_fb_helper.h>
+#include <drm/drm_atomic.h>
 #include <drm/msm_drm.h>
 
 struct msm_kms;
diff --git a/drivers/gpu/drm/nouveau/dispnv04/overlay.c b/drivers/gpu/drm/nouveau/dispnv04/overlay.c
index ab03f77..577e6aa 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/overlay.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/overlay.c
@@ -221,8 +221,9 @@  nv10_set_params(struct nouveau_plane *plane)
 
 static int
 nv_set_property(struct drm_plane *plane,
-		struct drm_property *property,
-		uint64_t value)
+		  struct drm_atomic_state *state,
+		  struct drm_property *property,
+		  uint64_t value, void *blob_data)
 {
 	struct nouveau_plane *nv_plane = (struct nouveau_plane *)plane;
 
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
index d07ce02..3351e72 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -447,7 +447,8 @@  nouveau_connector_force(struct drm_connector *connector)
 
 static int
 nouveau_connector_set_property(struct drm_connector *connector,
-			       struct drm_property *property, uint64_t value)
+		struct drm_atomic_state *state, struct drm_property *property,
+		uint64_t value, void *blob_data)
 {
 	struct nouveau_display *disp = nouveau_display(connector->dev);
 	struct nouveau_connector *nv_connector = nouveau_connector(connector);
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c
index ddd8375..9a96d6d 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.c
@@ -858,6 +858,13 @@  driver = {
 	.dumb_map_offset = nouveau_display_dumb_map_offset,
 	.dumb_destroy = drm_gem_dumb_destroy,
 
+	.atomic_begin     = drm_atomic_begin,
+	.atomic_set_event = drm_atomic_set_event,
+	.atomic_check     = drm_atomic_check,
+	.atomic_commit    = drm_atomic_commit,
+	.atomic_end       = drm_atomic_end,
+	.atomic_funcs     = &drm_atomic_funcs,
+
 	.name = DRIVER_NAME,
 	.desc = DRIVER_DESC,
 #ifdef GIT_REVISION
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.h b/drivers/gpu/drm/nouveau/nouveau_drm.h
index 7efbafa..8941696 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.h
@@ -29,6 +29,7 @@ 
 #include <subdev/vm.h>
 
 #include <drmP.h>
+#include <drm/drm_atomic.h>
 #include <drm/nouveau_drm.h>
 
 #include <drm/ttm/ttm_bo_api.h>
diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c
index e3c47a8..a7c0010 100644
--- a/drivers/gpu/drm/omapdrm/omap_crtc.c
+++ b/drivers/gpu/drm/omapdrm/omap_crtc.c
@@ -382,7 +382,8 @@  static int omap_crtc_page_flip_locked(struct drm_crtc *crtc,
 }
 
 static int omap_crtc_set_property(struct drm_crtc *crtc,
-		struct drm_property *property, uint64_t val)
+		struct drm_atomic_state *state, struct drm_property *property,
+		uint64_t val, void *blob_data)
 {
 	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
 	struct omap_drm_private *priv = crtc->dev->dev_private;
@@ -392,7 +393,8 @@  static int omap_crtc_set_property(struct drm_crtc *crtc,
 				!!(val & ((1LL << DRM_ROTATE_90) | (1LL << DRM_ROTATE_270)));
 	}
 
-	return omap_plane_set_property(omap_crtc->plane, property, val);
+	return omap_plane_set_property(omap_crtc->plane, state,
+			property, val, blob_data);
 }
 
 static const struct drm_crtc_funcs omap_crtc_funcs = {
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c
index c8270e4..d3c9161 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.c
+++ b/drivers/gpu/drm/omapdrm/omap_drv.c
@@ -651,6 +651,12 @@  static struct drm_driver omap_drm_driver = {
 		.dumb_create = omap_gem_dumb_create,
 		.dumb_map_offset = omap_gem_dumb_map_offset,
 		.dumb_destroy = drm_gem_dumb_destroy,
+		.atomic_begin     = drm_atomic_begin,
+		.atomic_set_event = drm_atomic_set_event,
+		.atomic_check     = drm_atomic_check,
+		.atomic_commit    = drm_atomic_commit,
+		.atomic_end       = drm_atomic_end,
+		.atomic_funcs     = &drm_atomic_funcs,
 		.ioctls = ioctls,
 		.num_ioctls = DRM_OMAP_NUM_IOCTLS,
 		.fops = &omapdriver_fops,
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h
index 284b80f..346fc8a 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.h
+++ b/drivers/gpu/drm/omapdrm/omap_drv.h
@@ -25,6 +25,7 @@ 
 #include <linux/types.h>
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic.h>
 #include <drm/omap_drm.h>
 #include <linux/platform_data/omap_drm.h>
 
@@ -178,7 +179,8 @@  int omap_plane_mode_set(struct drm_plane *plane,
 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_atomic_state *state, struct drm_property *property,
+		uint64_t val, void *blob_data);
 
 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 3cf31ee..8ae5c49 100644
--- a/drivers/gpu/drm/omapdrm/omap_plane.c
+++ b/drivers/gpu/drm/omapdrm/omap_plane.c
@@ -336,7 +336,8 @@  void omap_plane_install_properties(struct drm_plane *plane,
 }
 
 int omap_plane_set_property(struct drm_plane *plane,
-		struct drm_property *property, uint64_t val)
+		struct drm_atomic_state *state, struct drm_property *property,
+		uint64_t val, void *blob_data)
 {
 	struct omap_plane *omap_plane = to_omap_plane(plane);
 	struct omap_drm_private *priv = plane->dev->dev_private;
diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c
index 3ab9072..b54c970 100644
--- a/drivers/gpu/drm/qxl/qxl_display.c
+++ b/drivers/gpu/drm/qxl/qxl_display.c
@@ -819,8 +819,10 @@  static enum drm_connector_status qxl_conn_detect(
 }
 
 static int qxl_conn_set_property(struct drm_connector *connector,
+				   struct drm_atomic_state *state,
 				   struct drm_property *property,
-				   uint64_t value)
+				   uint64_t value,
+				   void *blob_data)
 {
 	DRM_DEBUG("\n");
 	return 0;
diff --git a/drivers/gpu/drm/qxl/qxl_drv.c b/drivers/gpu/drm/qxl/qxl_drv.c
index 6e93663..1984c2c 100644
--- a/drivers/gpu/drm/qxl/qxl_drv.c
+++ b/drivers/gpu/drm/qxl/qxl_drv.c
@@ -34,6 +34,7 @@ 
 #include "drmP.h"
 #include "drm/drm.h"
 #include "drm_crtc_helper.h"
+#include "drm_atomic.h"
 #include "qxl_drv.h"
 #include "qxl_object.h"
 
@@ -220,6 +221,14 @@  static struct drm_driver qxl_driver = {
 	.dumb_create = qxl_mode_dumb_create,
 	.dumb_map_offset = qxl_mode_dumb_mmap,
 	.dumb_destroy = drm_gem_dumb_destroy,
+
+	.atomic_begin     = drm_atomic_begin,
+	.atomic_set_event = drm_atomic_set_event,
+	.atomic_check     = drm_atomic_check,
+	.atomic_commit    = drm_atomic_commit,
+	.atomic_end       = drm_atomic_end,
+	.atomic_funcs     = &drm_atomic_funcs,
+
 #if defined(CONFIG_DEBUG_FS)
 	.debugfs_init = qxl_debugfs_init,
 	.debugfs_cleanup = qxl_debugfs_takedown,
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c
index ea50e0a..f7ecdfc 100644
--- a/drivers/gpu/drm/radeon/radeon_connectors.c
+++ b/drivers/gpu/drm/radeon/radeon_connectors.c
@@ -359,8 +359,9 @@  static void radeon_add_common_modes(struct drm_encoder *encoder, struct drm_conn
 	}
 }
 
-static int radeon_connector_set_property(struct drm_connector *connector, struct drm_property *property,
-				  uint64_t val)
+static int radeon_connector_set_property(struct drm_connector *connector,
+		struct drm_atomic_state *state, struct drm_property *property,
+		uint64_t val, void *blob_data)
 {
 	struct drm_device *dev = connector->dev;
 	struct radeon_device *rdev = dev->dev_private;
@@ -682,8 +683,10 @@  static void radeon_connector_destroy(struct drm_connector *connector)
 }
 
 static int radeon_lvds_set_property(struct drm_connector *connector,
+				    struct drm_atomic_state *state,
 				    struct drm_property *property,
-				    uint64_t value)
+				    uint64_t value,
+				    void *blob_data)
 {
 	struct drm_device *dev = connector->dev;
 	struct radeon_encoder *radeon_encoder;
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c
index 15447a41..745791d 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -34,6 +34,7 @@ 
 #include "radeon_drv.h"
 
 #include <drm/drm_pciids.h>
+#include <drm/drm_atomic.h>
 #include <linux/console.h>
 #include <linux/module.h>
 #include <linux/pm_runtime.h>
@@ -545,6 +546,14 @@  static struct drm_driver kms_driver = {
 	.dumb_create = radeon_mode_dumb_create,
 	.dumb_map_offset = radeon_mode_dumb_mmap,
 	.dumb_destroy = drm_gem_dumb_destroy,
+
+	.atomic_begin     = drm_atomic_begin,
+	.atomic_set_event = drm_atomic_set_event,
+	.atomic_check     = drm_atomic_check,
+	.atomic_commit    = drm_atomic_commit,
+	.atomic_end       = drm_atomic_end,
+	.atomic_funcs     = &drm_atomic_funcs,
+
 	.fops = &radeon_driver_kms_fops,
 
 	.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
index 792fd1d..3f642a8 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
@@ -21,6 +21,7 @@ 
 
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 
@@ -175,6 +176,12 @@  static struct drm_driver rcar_du_driver = {
 	.dumb_create		= rcar_du_dumb_create,
 	.dumb_map_offset	= drm_gem_cma_dumb_map_offset,
 	.dumb_destroy		= drm_gem_dumb_destroy,
+	.atomic_begin     = drm_atomic_begin,
+	.atomic_set_event = drm_atomic_set_event,
+	.atomic_check     = drm_atomic_check,
+	.atomic_commit    = drm_atomic_commit,
+	.atomic_end       = drm_atomic_end,
+	.atomic_funcs     = &drm_atomic_funcs,
 	.fops			= &rcar_du_fops,
 	.name			= "rcar-du",
 	.desc			= "Renesas R-Car Display Unit",
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.c b/drivers/gpu/drm/rcar-du/rcar_du_plane.c
index 3fb69d9..3a5d843 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_plane.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.c
@@ -397,8 +397,10 @@  done:
 }
 
 static int rcar_du_plane_set_property(struct drm_plane *plane,
+				      struct drm_atomic_state *state,
 				      struct drm_property *property,
-				      uint64_t value)
+				      uint64_t value,
+				      void *blob_data)
 {
 	struct rcar_du_plane *rplane = to_rcar_plane(plane);
 	struct rcar_du_group *rgrp = rplane->group;
diff --git a/drivers/gpu/drm/shmobile/shmob_drm_drv.c b/drivers/gpu/drm/shmobile/shmob_drm_drv.c
index 82c84c7..7474ffb 100644
--- a/drivers/gpu/drm/shmobile/shmob_drm_drv.c
+++ b/drivers/gpu/drm/shmobile/shmob_drm_drv.c
@@ -21,6 +21,7 @@ 
 
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic.h>
 #include <drm/drm_gem_cma_helper.h>
 
 #include "shmob_drm_crtc.h"
@@ -285,6 +286,12 @@  static struct drm_driver shmob_drm_driver = {
 	.dumb_create		= drm_gem_cma_dumb_create,
 	.dumb_map_offset	= drm_gem_cma_dumb_map_offset,
 	.dumb_destroy		= drm_gem_dumb_destroy,
+	.atomic_begin     = drm_atomic_begin,
+	.atomic_set_event = drm_atomic_set_event,
+	.atomic_check     = drm_atomic_check,
+	.atomic_commit    = drm_atomic_commit,
+	.atomic_end       = drm_atomic_end,
+	.atomic_funcs     = &drm_atomic_funcs,
 	.fops			= &shmob_drm_fops,
 	.name			= "shmob-drm",
 	.desc			= "Renesas SH Mobile DRM",
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
index b20b694..3579b07 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
@@ -519,6 +519,12 @@  static struct drm_driver tilcdc_driver = {
 	.dumb_create        = drm_gem_cma_dumb_create,
 	.dumb_map_offset    = drm_gem_cma_dumb_map_offset,
 	.dumb_destroy       = drm_gem_dumb_destroy,
+	.atomic_begin       = drm_atomic_begin,
+	.atomic_set_event   = drm_atomic_set_event,
+	.atomic_check       = drm_atomic_check,
+	.atomic_commit      = drm_atomic_commit,
+	.atomic_end         = drm_atomic_end,
+	.atomic_funcs       = &drm_atomic_funcs,
 #ifdef CONFIG_DEBUG_FS
 	.debugfs_init       = tilcdc_debugfs_init,
 	.debugfs_cleanup    = tilcdc_debugfs_cleanup,
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.h b/drivers/gpu/drm/tilcdc/tilcdc_drv.h
index 0938036..1280a65 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.h
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.h
@@ -31,6 +31,7 @@ 
 
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic.h>
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_slave.c b/drivers/gpu/drm/tilcdc/tilcdc_slave.c
index 595068b..693f3ec 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_slave.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_slave.c
@@ -206,7 +206,8 @@  static struct drm_encoder *slave_connector_best_encoder(
 }
 
 static int slave_connector_set_property(struct drm_connector *connector,
-		struct drm_property *property, uint64_t value)
+		struct drm_atomic_state *state, struct drm_property *property,
+		uint64_t value, void *blob_data)
 {
 	struct drm_encoder *encoder = to_slave_connector(connector)->encoder;
 	return get_slave_funcs(encoder)->set_property(encoder,
diff --git a/drivers/gpu/drm/udl/udl_connector.c b/drivers/gpu/drm/udl/udl_connector.c
index b44d548..936244d 100644
--- a/drivers/gpu/drm/udl/udl_connector.c
+++ b/drivers/gpu/drm/udl/udl_connector.c
@@ -115,9 +115,9 @@  udl_best_single_encoder(struct drm_connector *connector)
 	return encoder;
 }
 
-static int udl_connector_set_property(struct drm_connector *connector,
-				      struct drm_property *property,
-				      uint64_t val)
+static int udl_connector_set_property(struct drm_connector *connector, 
+			       struct drm_atomic_state *state, struct drm_property *property,
+			       uint64_t val, void *blob_data)
 {
 	return 0;
 }
diff --git a/drivers/gpu/drm/udl/udl_drv.c b/drivers/gpu/drm/udl/udl_drv.c
index 3ddd6cd..52ade41 100644
--- a/drivers/gpu/drm/udl/udl_drv.c
+++ b/drivers/gpu/drm/udl/udl_drv.c
@@ -9,6 +9,7 @@ 
 #include <linux/module.h>
 #include <drm/drm_usb.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic.h>
 #include "udl_drv.h"
 
 static struct drm_driver driver;
@@ -88,6 +89,13 @@  static struct drm_driver driver = {
 	.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
 	.gem_prime_import = udl_gem_prime_import,
 
+	.atomic_begin     = drm_atomic_begin,
+	.atomic_set_event = drm_atomic_set_event,
+	.atomic_check     = drm_atomic_check,
+	.atomic_commit    = drm_atomic_commit,
+	.atomic_end       = drm_atomic_end,
+	.atomic_funcs     = &drm_atomic_funcs,
+
 	.name = DRIVER_NAME,
 	.desc = DRIVER_DESC,
 	.date = DRIVER_DATE,
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
index 6bdd15e..3ec6792 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
@@ -1433,6 +1433,13 @@  static struct drm_driver driver = {
 	.prime_fd_to_handle = vmw_prime_fd_to_handle,
 	.prime_handle_to_fd = vmw_prime_handle_to_fd,
 
+	.atomic_begin     = drm_atomic_begin,
+	.atomic_set_event = drm_atomic_set_event,
+	.atomic_check     = drm_atomic_check,
+	.atomic_commit    = drm_atomic_commit,
+	.atomic_end       = drm_atomic_end,
+	.atomic_funcs     = &drm_atomic_funcs,
+
 	.fops = &vmwgfx_driver_fops,
 	.name = VMWGFX_DRIVER_NAME,
 	.desc = VMWGFX_DRIVER_DESC,
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
index 6b252a8..b0d6f3a 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
@@ -30,6 +30,7 @@ 
 
 #include "vmwgfx_reg.h"
 #include <drm/drmP.h>
+#include <drm/drm_atomic.h>
 #include <drm/vmwgfx_drm.h>
 #include <drm/drm_hashtab.h>
 #include <linux/suspend.h>
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index e7199b4..6b9db5e 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -2007,8 +2007,10 @@  int vmw_du_connector_fill_modes(struct drm_connector *connector,
 }
 
 int vmw_du_connector_set_property(struct drm_connector *connector,
+				  struct drm_atomic_state *state,
 				  struct drm_property *property,
-				  uint64_t val)
+				  uint64_t val,
+				  void *blob_data)
 {
 	return 0;
 }
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
index 8d038c3..6b02fdb 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
@@ -141,8 +141,10 @@  vmw_du_connector_detect(struct drm_connector *connector, bool force);
 int vmw_du_connector_fill_modes(struct drm_connector *connector,
 				uint32_t max_width, uint32_t max_height);
 int vmw_du_connector_set_property(struct drm_connector *connector,
+				  struct drm_atomic_state *state,
 				  struct drm_property *property,
-				  uint64_t val);
+				  uint64_t val,
+				  void *blob_data);
 
 
 /*
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index 12f10bc..e8d0d17 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -948,6 +948,86 @@  struct drm_driver {
 			    struct drm_device *dev,
 			    uint32_t handle);
 
+	/*
+	 * Atomic functions:
+	 */
+
+	/**
+	 * atomic_begin - start a sequence of atomic updates
+	 * @dev: DRM device
+	 * @flags: the modifier flags that userspace has requested
+	 *
+	 * Begin a sequence of atomic property sets.  Returns a driver
+	 * private state object that is passed back into the various
+	 * object's set_property() fxns, and into the remainder of the
+	 * atomic funcs.  The state object should accumulate the changes
+	 * from one o more set_property()'s.  At the end, the state can
+	 * be checked, and optionally committed.
+	 *
+	 * RETURNS
+	 *   a driver state object, which is passed back in to the
+	 *   various other atomic fxns, or error (such as -EBUSY if
+	 *   there is still a pending async update)
+	 */
+	struct drm_atomic_state *(*atomic_begin)(struct drm_device *dev, uint32_t flags);
+
+	/**
+	 * atomic_set_event - set a pending event on mode object
+	 * @dev: DRM device
+	 * @state: the driver state object
+	 * @obj: the object to set the event on
+	 * @event: the event to send back
+	 *
+	 * Set pending event for an update on the specified object.  The
+	 * event is to be sent back to userspace after the update completes.
+	 */
+	int (*atomic_set_event)(struct drm_device *dev,
+			struct drm_atomic_state *state, struct drm_mode_object *obj,
+			struct drm_pending_vblank_event *event);
+
+	/**
+	 * atomic_check - validate state object
+	 * @dev: DRM device
+	 * @state: the driver state object
+	 *
+	 * Check the state object to see if the requested state is
+	 * physically possible.
+	 *
+	 * RETURNS
+	 * Zero for success or -errno
+	 */
+	int (*atomic_check)(struct drm_device *dev,
+			struct drm_atomic_state *state);
+
+	/**
+	 * atomic_commit - commit state
+	 * @dev: DRM device
+	 * @state: the driver state object
+	 *
+	 * Commit the state.  This will only be called if atomic_check()
+	 * succeeds.
+	 *
+	 * RETURNS
+	 * Zero for success or -errno
+	 */
+	int (*atomic_commit)(struct drm_device *dev,
+			struct drm_atomic_state *state);
+
+	/**
+	 * atomic_end - conclude the atomic update
+	 * @dev: DRM device
+	 * @state: the driver state object
+
+	 * Release resources associated with the state object.
+	 */
+	void (*atomic_end)(struct drm_device *dev,
+			struct drm_atomic_state *state);
+
+	/**
+	 * Funcs used by drm-atomic-helpers
+	 */
+	const struct drm_atomic_funcs *atomic_funcs;
+
 	/* Driver private ops for this object */
 	const struct vm_operations_struct *gem_vm_ops;
 
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
new file mode 100644
index 0000000..5274212
--- /dev/null
+++ b/include/drm/drm_atomic.h
@@ -0,0 +1,107 @@ 
+/*
+ * Copyright (C) 2014 Red Hat
+ * Author: Rob Clark <robdclark@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef DRM_ATOMIC_HELPER_H_
+#define DRM_ATOMIC_HELPER_H_
+
+/**
+ * DOC: atomic state helpers
+ *
+ * Base helper atomic state and functions.  Drivers are free to either
+ * use these as-is, extend them, or completely replace them, in order
+ * to implement the atomic KMS API.
+ *
+ * A naive driver, with no special constraints or hw support for atomic
+ * updates may simply add the following to their driver struct:
+ *
+ *     .atomic_begin     = drm_atomic_begin,
+ *     .atomic_set_event = drm_atomic_set_event,
+ *     .atomic_check     = drm_atomic_check,
+ *     .atomic_commit    = drm_atomic_commit,
+ *     .atomic_end       = drm_atomic_end,
+ *     .atomics   = &drm_atomic_funcs,
+ *
+ * In addition, if you're plane/crtc doesn't already have it's own custom
+ * properties, then add to your plane/crtc_funcs:
+ *
+ *     .set_property     = drm_atomic_{plane,crtc}_set_property,
+ *
+ * Unlike the crtc helpers, it is intended that the atomic helpers can be
+ * used piecemeal by the drivers, either using all or overriding parts as
+ * needed.
+ *
+ * A driver which can have (for example) conflicting modes across multiple
+ * crtcs (for example, bandwidth limitations or clock/pll configuration
+ * restrictions), can simply wrap drm_atomic_check() with their own
+ * driver specific .atomic_check() function.
+ *
+ * A driver which can support true atomic updates can wrap
+ * drm_atomic_commit().
+ *
+ * A driver with custom properties should override the appropriate get_state(),
+ * check_state(), and commit_state() functions in .atomics if it uses
+ * the drm-atomic-helpers.  Otherwise it is free to use &drm_atomic_funcs
+ * as-is.
+ */
+
+/**
+ * struct drm_atomic_funcs - helper funcs used by the atomic helpers
+ */
+struct drm_atomic_funcs {
+	int dummy; /* for now */
+};
+
+const extern struct drm_atomic_funcs drm_atomic_funcs;
+
+struct drm_atomic_state *drm_atomic_begin(struct drm_device *dev,
+		uint32_t flags);
+int drm_atomic_set_event(struct drm_device *dev,
+		struct drm_atomic_state *state, struct drm_mode_object *obj,
+		struct drm_pending_vblank_event *event);
+int drm_atomic_check(struct drm_device *dev, struct drm_atomic_state *state);
+int drm_atomic_commit(struct drm_device *dev, struct drm_atomic_state *state);
+void drm_atomic_end(struct drm_device *dev, struct drm_atomic_state *state);
+
+/**
+ * struct drm_atomic_state - the state object used by atomic helpers
+ */
+struct drm_atomic_state {
+	struct kref refcount;
+	struct drm_device *dev;
+	uint32_t flags;
+};
+
+static inline void
+drm_atomic_state_reference(struct drm_atomic_state *state)
+{
+	kref_get(&state->refcount);
+}
+
+static inline void
+drm_atomic_state_unreference(struct drm_atomic_state *state)
+{
+	void _drm_atomic_state_free(struct kref *kref);
+	kref_put(&state->refcount, _drm_atomic_state_free);
+}
+
+#endif /* DRM_ATOMIC_HELPER_H_ */
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 698d54e..4790cad 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -200,6 +200,8 @@  struct drm_encoder;
 struct drm_pending_vblank_event;
 struct drm_plane;
 struct drm_bridge;
+struct drm_atomic_state;
+struct drm_atomic_funcs;
 
 /**
  * drm_crtc_funcs - control CRTCs for a given device
@@ -262,7 +264,9 @@  struct drm_crtc_funcs {
 			 uint32_t flags);
 
 	int (*set_property)(struct drm_crtc *crtc,
-			    struct drm_property *property, uint64_t val);
+			    struct drm_atomic_state *state,
+			    struct drm_property *property, uint64_t val,
+			    void *blob_data);
 };
 
 /**
@@ -375,8 +379,9 @@  struct drm_connector_funcs {
 	enum drm_connector_status (*detect)(struct drm_connector *connector,
 					    bool force);
 	int (*fill_modes)(struct drm_connector *connector, uint32_t max_width, uint32_t max_height);
-	int (*set_property)(struct drm_connector *connector, struct drm_property *property,
-			     uint64_t val);
+	int (*set_property)(struct drm_connector *connector,
+			struct drm_atomic_state *state,
+			struct drm_property *property, uint64_t val, void *blob_data);
 	void (*destroy)(struct drm_connector *connector);
 	void (*force)(struct drm_connector *connector);
 };
@@ -541,7 +546,9 @@  struct drm_plane_funcs {
 	void (*destroy)(struct drm_plane *plane);
 
 	int (*set_property)(struct drm_plane *plane,
-			    struct drm_property *property, uint64_t val);
+			    struct drm_atomic_state *state,
+			    struct drm_property *property, uint64_t val,
+			    void *blob_data);
 };
 
 enum drm_plane_type {