diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index f32506a..cae0122 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -631,6 +631,79 @@ static int drm_atomic_crtc_check(struct drm_crtc *crtc,
 	return 0;
 }
 
+static bool drm_atomic_async_check(struct drm_atomic_state *state)
+{
+	struct drm_crtc *crtc;
+	struct drm_crtc_state *crtc_state;
+	struct drm_crtc_commit *commit;
+	struct drm_plane *__plane, *plane = NULL;
+	struct drm_plane_state *__plane_state, *plane_state = NULL;
+	const struct drm_plane_helper_funcs *funcs;
+	int i, n_planes = 0;
+
+	for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
+		if (drm_atomic_crtc_needs_modeset(crtc_state))
+			return false;
+	}
+
+	for_each_new_plane_in_state(state, __plane, __plane_state, i) {
+		n_planes++;
+		plane = __plane;
+		plane_state = __plane_state;
+	}
+
+	if (!plane || n_planes != 1)
+		return false;
+
+	if (!plane->state->crtc)
+		return false;
+
+	if (plane_state->fence)
+		return false;
+
+	for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
+		if (plane->crtc != crtc)
+			continue;
+
+		spin_lock(&crtc->commit_lock);
+		commit = list_first_entry_or_null(&crtc->commit_list,
+						  struct drm_crtc_commit,
+						  commit_entry);
+		if (!commit) {
+			spin_unlock(&crtc->commit_lock);
+			continue;
+		}
+		spin_unlock(&crtc->commit_lock);
+
+		for_each_plane_in_state(crtc_state->state, __plane,
+					__plane_state, i) {
+			if (__plane == plane) {
+				return false;
+			}
+		}
+	}
+
+	/* Not configuring new scaling in the async path. */
+	if (plane->state->crtc_w != plane_state->crtc_w ||
+	    plane->state->crtc_h != plane_state->crtc_h ||
+	    plane->state->src_w != plane_state->src_w ||
+	    plane->state->src_h != plane_state->src_h) {
+		return false;
+	}
+
+	funcs = plane->helper_private;
+
+	if (!funcs->atomic_async_update)
+		return false;
+
+	if (funcs->atomic_async_check) {
+		if (funcs->atomic_async_check(plane, plane_state) < 0)
+			return false;
+	}
+
+	return true;
+}
+
 static void drm_atomic_crtc_print_state(struct drm_printer *p,
 		const struct drm_crtc_state *state)
 {
@@ -1591,6 +1664,8 @@ int drm_atomic_check_only(struct drm_atomic_state *state)
 		}
 	}
 
+	state->async_update = drm_atomic_async_check(state);
+
 	return ret;
 }
 EXPORT_SYMBOL(drm_atomic_check_only);
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 8be9719..a79e06c 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -1235,6 +1235,36 @@ static void commit_work(struct work_struct *work)
 }
 
 /**
+ * drm_atomic_helper_async_commit - commit state asynchronously
+ *
+ * This function commits a state asynchronously. It should be used
+ * on a state only when drm_atomic_async_check() succeds. Async
+ * commits are not supposed to swap the states like normal sync commits,
+ * but just do in-place change on the current state.
+ */
+void drm_atomic_helper_async_commit(struct drm_device *dev,
+				    struct drm_atomic_state *state)
+{
+	struct drm_plane *plane;
+	struct drm_plane_state *plane_state;
+	const struct drm_plane_helper_funcs *funcs;
+	int i;
+
+	for_each_new_plane_in_state(state, plane, plane_state, i) {
+		funcs = plane->helper_private;
+
+		plane->state->src_x = plane_state->src_x;
+		plane->state->src_y = plane_state->src_y;
+		plane->state->crtc_x = plane_state->crtc_x;
+		plane->state->crtc_y = plane_state->crtc_y;
+
+		if (funcs && funcs->atomic_async_update)
+			funcs->atomic_async_update(plane, plane_state);
+	}
+}
+EXPORT_SYMBOL(drm_atomic_helper_async_commit);
+
+/**
  * drm_atomic_helper_commit - commit validated state object
  * @dev: DRM device
  * @state: the driver state object
@@ -1258,6 +1288,17 @@ int drm_atomic_helper_commit(struct drm_device *dev,
 {
 	int ret;
 
+	if (state->async_update) {
+		ret = drm_atomic_helper_prepare_planes(dev, state);
+		if (ret)
+			return ret;
+
+		drm_atomic_helper_async_commit(dev, state);
+		drm_atomic_helper_cleanup_planes(dev, state);
+
+		return 0;
+	}
+
 	ret = drm_atomic_helper_setup_commit(state, nonblock);
 	if (ret)
 		return ret;
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index 788daf7..c00c565 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -160,6 +160,8 @@ struct __drm_connnectors_state {
  * @dev: parent DRM device
  * @allow_modeset: allow full modeset
  * @legacy_cursor_update: hint to enforce legacy cursor IOCTL semantics
+ * @legacy_set_config: Disable conflicting encoders instead of failing with -EINVAL.
+ * @async_update: hint for asynchronous plane update
  * @planes: pointer to array of structures with per-plane data
  * @crtcs: pointer to array of CRTC pointers
  * @num_connector: size of the @connectors and @connector_states arrays
@@ -172,6 +174,8 @@ struct drm_atomic_state {
 	struct drm_device *dev;
 	bool allow_modeset : 1;
 	bool legacy_cursor_update : 1;
+	bool legacy_set_config : 1;
+	bool async_update : 1;
 	struct __drm_planes_state *planes;
 	struct __drm_crtcs_state *crtcs;
 	int num_connector;
diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
index f0a8678..8571b51 100644
--- a/include/drm/drm_atomic_helper.h
+++ b/include/drm/drm_atomic_helper.h
@@ -44,6 +44,8 @@ void drm_atomic_helper_commit_tail(struct drm_atomic_state *state);
 int drm_atomic_helper_commit(struct drm_device *dev,
 			     struct drm_atomic_state *state,
 			     bool nonblock);
+void drm_atomic_helper_async_commit(struct drm_device *dev,
+				    struct drm_atomic_state *state);
 
 int drm_atomic_helper_wait_for_fences(struct drm_device *dev,
 					struct drm_atomic_state *state,
diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h
index c01c328..3efa4cc 100644
--- a/include/drm/drm_modeset_helper_vtables.h
+++ b/include/drm/drm_modeset_helper_vtables.h
@@ -1048,6 +1048,53 @@ struct drm_plane_helper_funcs {
 	 */
 	void (*atomic_disable)(struct drm_plane *plane,
 			       struct drm_plane_state *old_state);
+
+	/**
+	 * @atomic_async_check:
+	 *
+	 * Drivers should use this function check if the plane state
+	 * can be updated in a async fashion.
+	 *
+	 * This hook is called by drm_atomic_async_check() in the process
+	 * to figure out if an given update can be committed asynchronously,
+	 * that is, if it can jump ahead the state currently queued for
+	 * update.
+	 *
+	 * Check drm_atomic_async_check() to see what is already there
+	 * to discover potential async updates.
+	 *
+	 * RETURNS:
+	 *
+	 * Return 0 on success and -EINVAL if the update can't be async.
+	 * Error return doesn't mean that the update can't be applied,
+	 * it just mean that it can't be an async one.
+	 *
+	 * FIXME:
+	 *  - It only works for single plane updates
+	 *  - It can't do async update if the plane is already being update
+	 *  by the queued state
+	 *  - Async Pageflips are not supported yet
+	 */
+	int (*atomic_async_check)(struct drm_plane *plane,
+				  struct drm_plane_state *state);
+
+	/**
+	 * @atomic_async_update:
+	 *
+	 * Drivers should use this functions to perform asynchronous
+	 * updates of planes, that is jump ahead the currently queued
+	 * state for and update the plane.
+	 *
+	 * This hook is called by drm_atomic_helper_async_commit().
+	 *
+	 * Note that differently from the &drm_plane_helper_funcs.atomic_update
+	 * this hook takes the new &drm_plane_state as parameter. When doing
+	 * async_update drivers shouldn't replace the &drm_plane_state but
+	 * just, update the current one with the new plane configurations in
+	 * the new plane_state.
+	 */
+	void (*atomic_async_update)(struct drm_plane *plane,
+				    struct drm_plane_state *new_state);
 };
 
 /**
