drm_atomic_helper_wait_for_dependencies(&state->base);
        drm_dp_mst_atomic_wait_for_dependencies(&state->base);
+       intel_atomic_global_state_wait_for_dependencies(state);
 
        /*
         * During full modesets we write a lot of registers, wait
        intel_pmdemand_post_plane_update(state);
 
        drm_atomic_helper_commit_hw_done(&state->base);
+       intel_atomic_global_state_commit_done(state);
 
        if (state->modeset) {
                /* As one of the primary mmio accessors, KMS has a high
                                        plane->frontbuffer_bit);
 }
 
+static int intel_atomic_setup_commit(struct intel_atomic_state *state, bool nonblock)
+{
+       int ret;
+
+       ret = drm_atomic_helper_setup_commit(&state->base, nonblock);
+       if (ret)
+               return ret;
+
+       ret = intel_atomic_global_state_setup_commit(state);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
 int intel_atomic_commit(struct drm_device *dev, struct drm_atomic_state *_state,
                        bool nonblock)
 {
                return ret;
        }
 
-       ret = drm_atomic_helper_setup_commit(&state->base, nonblock);
+       ret = intel_atomic_setup_commit(state, nonblock);
        if (!ret)
                ret = drm_atomic_helper_swap_state(&state->base, true);
        if (!ret)
 
 #include "intel_display_types.h"
 #include "intel_global_state.h"
 
+struct intel_global_commit {
+       struct kref ref;
+       struct completion done;
+};
+
+static struct intel_global_commit *commit_new(void)
+{
+       struct intel_global_commit *commit;
+
+       commit = kzalloc(sizeof(*commit), GFP_KERNEL);
+       if (!commit)
+               return NULL;
+
+       init_completion(&commit->done);
+       kref_init(&commit->ref);
+
+       return commit;
+}
+
+static void __commit_free(struct kref *kref)
+{
+       struct intel_global_commit *commit =
+               container_of(kref, typeof(*commit), ref);
+
+       kfree(commit);
+}
+
+static struct intel_global_commit *commit_get(struct intel_global_commit *commit)
+{
+       if (commit)
+               kref_get(&commit->ref);
+
+       return commit;
+}
+
+static void commit_put(struct intel_global_commit *commit)
+{
+       if (commit)
+               kref_put(&commit->ref, __commit_free);
+}
+
 static void __intel_atomic_global_state_free(struct kref *kref)
 {
        struct intel_global_state *obj_state =
                container_of(kref, struct intel_global_state, ref);
        struct intel_global_obj *obj = obj_state->obj;
 
+       commit_put(obj_state->commit);
+
        obj->funcs->atomic_destroy_state(obj, obj_state);
 }
 
 
        obj_state->obj = obj;
        obj_state->changed = false;
+       obj_state->serialized = false;
+       obj_state->commit = NULL;
 
        kref_init(&obj_state->ref);
 
 
 int intel_atomic_serialize_global_state(struct intel_global_state *obj_state)
 {
-       struct intel_atomic_state *state = obj_state->state;
-       struct drm_i915_private *dev_priv = to_i915(state->base.dev);
-       struct intel_crtc *crtc;
+       int ret;
 
-       for_each_intel_crtc(&dev_priv->drm, crtc) {
-               struct intel_crtc_state *crtc_state;
+       ret = intel_atomic_lock_global_state(obj_state);
+       if (ret)
+               return ret;
 
-               crtc_state = intel_atomic_get_crtc_state(&state->base, crtc);
-               if (IS_ERR(crtc_state))
-                       return PTR_ERR(crtc_state);
-       }
-
-       obj_state->changed = true;
+       obj_state->serialized = true;
 
        return 0;
 }
                        return false;
        return true;
 }
+
+int
+intel_atomic_global_state_setup_commit(struct intel_atomic_state *state)
+{
+       const struct intel_global_state *old_obj_state;
+       struct intel_global_state *new_obj_state;
+       struct intel_global_obj *obj;
+       int i;
+
+       for_each_oldnew_global_obj_in_state(state, obj, old_obj_state,
+                                           new_obj_state, i) {
+               struct intel_global_commit *commit = NULL;
+
+               if (new_obj_state->serialized) {
+                       /*
+                        * New commit which is going to be completed
+                        * after the hardware reprogramming is done.
+                        */
+                       commit = commit_new();
+                       if (!commit)
+                               return -ENOMEM;
+               } else if (new_obj_state->changed) {
+                       /*
+                        * We're going to swap to this state, so carry the
+                        * previous commit along, in case it's not yet done.
+                        */
+                       commit = commit_get(old_obj_state->commit);
+               }
+
+               new_obj_state->commit = commit;
+       }
+
+       return 0;
+}
+
+int
+intel_atomic_global_state_wait_for_dependencies(struct intel_atomic_state *state)
+{
+       struct drm_i915_private *i915 = to_i915(state->base.dev);
+       const struct intel_global_state *old_obj_state;
+       struct intel_global_obj *obj;
+       int i;
+
+       for_each_old_global_obj_in_state(state, obj, old_obj_state, i) {
+               struct intel_global_commit *commit = old_obj_state->commit;
+               long ret;
+
+               if (!commit)
+                       continue;
+
+               ret = wait_for_completion_timeout(&commit->done, 10 * HZ);
+               if (ret == 0) {
+                       drm_err(&i915->drm, "global state timed out\n");
+                       return -ETIMEDOUT;
+               }
+       }
+
+       return 0;
+}
+
+void
+intel_atomic_global_state_commit_done(struct intel_atomic_state *state)
+{
+       const struct intel_global_state *new_obj_state;
+       struct intel_global_obj *obj;
+       int i;
+
+       for_each_new_global_obj_in_state(state, obj, new_obj_state, i) {
+               struct intel_global_commit *commit = new_obj_state->commit;
+
+               if (!new_obj_state->serialized)
+                       continue;
+
+               complete_all(&commit->done);
+       }
+}