}
 
        for (i = 0; i < state->num_private_objs; i++) {
-               void *obj_state = state->private_objs[i].obj_state;
+               struct drm_private_obj *obj = state->private_objs[i].ptr;
 
-               state->private_objs[i].funcs->destroy_state(obj_state);
-               state->private_objs[i].obj = NULL;
-               state->private_objs[i].obj_state = NULL;
-               state->private_objs[i].funcs = NULL;
+               if (!obj)
+                       continue;
+
+               obj->funcs->atomic_destroy_state(obj,
+                                                state->private_objs[i].state);
+               state->private_objs[i].ptr = NULL;
+               state->private_objs[i].state = NULL;
        }
        state->num_private_objs = 0;
 
                plane->funcs->atomic_print_state(p, state);
 }
 
+/**
+ * drm_atomic_private_obj_init - initialize private object
+ * @obj: private object
+ * @state: initial private object state
+ * @funcs: pointer to the struct of function pointers that identify the object
+ * type
+ *
+ * Initialize the private object, which can be embedded into any
+ * driver private object that needs its own atomic state.
+ */
+void
+drm_atomic_private_obj_init(struct drm_private_obj *obj,
+                           struct drm_private_state *state,
+                           const struct drm_private_state_funcs *funcs)
+{
+       memset(obj, 0, sizeof(*obj));
+
+       obj->state = state;
+       obj->funcs = funcs;
+}
+EXPORT_SYMBOL(drm_atomic_private_obj_init);
+
+/**
+ * drm_atomic_private_obj_fini - finalize private object
+ * @obj: private object
+ *
+ * Finalize the private object.
+ */
+void
+drm_atomic_private_obj_fini(struct drm_private_obj *obj)
+{
+       obj->funcs->atomic_destroy_state(obj, obj->state);
+}
+EXPORT_SYMBOL(drm_atomic_private_obj_fini);
+
 /**
  * drm_atomic_get_private_obj_state - get private object state
  * @state: global atomic state
  * @obj: private object to get the state for
- * @funcs: pointer to the struct of function pointers that identify the object
- * type
  *
  * This function returns the private object state for the given private object,
  * allocating the state if needed. It does not grab any locks as the caller is
  *
  * Either the allocated state or the error code encoded into a pointer.
  */
-void *
-drm_atomic_get_private_obj_state(struct drm_atomic_state *state, void *obj,
-                             const struct drm_private_state_funcs *funcs)
+struct drm_private_state *
+drm_atomic_get_private_obj_state(struct drm_atomic_state *state,
+                                struct drm_private_obj *obj)
 {
        int index, num_objs, i;
        size_t size;
        struct __drm_private_objs_state *arr;
+       struct drm_private_state *obj_state;
 
        for (i = 0; i < state->num_private_objs; i++)
-               if (obj == state->private_objs[i].obj)
-                       return state->private_objs[i].obj_state;
+               if (obj == state->private_objs[i].ptr)
+                       return state->private_objs[i].state;
 
        num_objs = state->num_private_objs + 1;
        size = sizeof(*state->private_objs) * num_objs;
        index = state->num_private_objs;
        memset(&state->private_objs[index], 0, sizeof(*state->private_objs));
 
-       state->private_objs[index].obj_state = funcs->duplicate_state(state, obj);
-       if (!state->private_objs[index].obj_state)
+       obj_state = obj->funcs->atomic_duplicate_state(obj);
+       if (!obj_state)
                return ERR_PTR(-ENOMEM);
 
-       state->private_objs[index].obj = obj;
-       state->private_objs[index].funcs = funcs;
+       state->private_objs[index].state = obj_state;
+       state->private_objs[index].old_state = obj->state;
+       state->private_objs[index].new_state = obj_state;
+       state->private_objs[index].ptr = obj;
+
        state->num_private_objs = num_objs;
 
-       DRM_DEBUG_ATOMIC("Added new private object state %p to %p\n",
-                        state->private_objs[index].obj_state, state);
+       DRM_DEBUG_ATOMIC("Added new private object %p state %p to %p\n",
+                        obj, obj_state, state);
 
-       return state->private_objs[index].obj_state;
+       return obj_state;
 }
 EXPORT_SYMBOL(drm_atomic_get_private_obj_state);
 
 
        struct drm_plane *plane;
        struct drm_plane_state *old_plane_state, *new_plane_state;
        struct drm_crtc_commit *commit;
-       void *obj, *obj_state;
-       const struct drm_private_state_funcs *funcs;
+       struct drm_private_obj *obj;
+       struct drm_private_state *old_obj_state, *new_obj_state;
 
        if (stall) {
                for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
                plane->state = new_plane_state;
        }
 
-       __for_each_private_obj(state, obj, obj_state, i, funcs)
-               funcs->swap_state(obj, &state->private_objs[i].obj_state);
+       for_each_oldnew_private_obj_in_state(state, obj, old_obj_state, new_obj_state, i) {
+               WARN_ON(obj->state != old_obj_state);
+
+               old_obj_state->state = state;
+               new_obj_state->state = NULL;
+
+               state->private_objs[i].state = old_obj_state;
+               obj->state = new_obj_state;
+       }
 }
 EXPORT_SYMBOL(drm_atomic_helper_swap_state);
 
        return ret;
 }
 EXPORT_SYMBOL(drm_atomic_helper_legacy_gamma_set);
+
+/**
+ * __drm_atomic_helper_private_duplicate_state - copy atomic private state
+ * @obj: CRTC object
+ * @state: new private object state
+ *
+ * Copies atomic state from a private objects's current state and resets inferred values.
+ * This is useful for drivers that subclass the private state.
+ */
+void __drm_atomic_helper_private_obj_duplicate_state(struct drm_private_obj *obj,
+                                                    struct drm_private_state *state)
+{
+       memcpy(state, obj->state, sizeof(*state));
+}
+EXPORT_SYMBOL(__drm_atomic_helper_private_obj_duplicate_state);
 
 #include <drm/drmP.h>
 
 #include <drm/drm_fixed.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
 
 /**
  * DOC: dp mst helper
                (*mgr->cbs->hotplug)(mgr);
 }
 
-void *drm_dp_mst_duplicate_state(struct drm_atomic_state *state, void *obj)
+static struct drm_private_state *
+drm_dp_mst_duplicate_state(struct drm_private_obj *obj)
 {
-       struct drm_dp_mst_topology_mgr *mgr = obj;
-       struct drm_dp_mst_topology_state *new_mst_state;
+       struct drm_dp_mst_topology_state *state;
 
-       if (WARN_ON(!mgr->state))
+       state = kmemdup(obj->state, sizeof(*state), GFP_KERNEL);
+       if (!state)
                return NULL;
 
-       new_mst_state = kmemdup(mgr->state, sizeof(*new_mst_state), GFP_KERNEL);
-       if (new_mst_state)
-               new_mst_state->state = state;
-       return new_mst_state;
-}
-
-void drm_dp_mst_swap_state(void *obj, void **obj_state_ptr)
-{
-       struct drm_dp_mst_topology_mgr *mgr = obj;
-       struct drm_dp_mst_topology_state **topology_state_ptr;
-
-       topology_state_ptr = (struct drm_dp_mst_topology_state **)obj_state_ptr;
+       __drm_atomic_helper_private_obj_duplicate_state(obj, &state->base);
 
-       mgr->state->state = (*topology_state_ptr)->state;
-       swap(*topology_state_ptr, mgr->state);
-       mgr->state->state = NULL;
+       return &state->base;
 }
 
-void drm_dp_mst_destroy_state(void *obj_state)
+static void drm_dp_mst_destroy_state(struct drm_private_obj *obj,
+                                    struct drm_private_state *state)
 {
-       kfree(obj_state);
+       struct drm_dp_mst_topology_state *mst_state =
+               to_dp_mst_topology_state(state);
+
+       kfree(mst_state);
 }
 
 static const struct drm_private_state_funcs mst_state_funcs = {
-       .duplicate_state = drm_dp_mst_duplicate_state,
-       .swap_state = drm_dp_mst_swap_state,
-       .destroy_state = drm_dp_mst_destroy_state,
+       .atomic_duplicate_state = drm_dp_mst_duplicate_state,
+       .atomic_destroy_state = drm_dp_mst_destroy_state,
 };
 
 /**
        struct drm_device *dev = mgr->dev;
 
        WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
-       return drm_atomic_get_private_obj_state(state, mgr,
-                                               &mst_state_funcs);
+       return to_dp_mst_topology_state(drm_atomic_get_private_obj_state(state, &mgr->base));
 }
 EXPORT_SYMBOL(drm_atomic_get_mst_topology_state);
 
                                 int max_dpcd_transaction_bytes,
                                 int max_payloads, int conn_base_id)
 {
+       struct drm_dp_mst_topology_state *mst_state;
+
        mutex_init(&mgr->lock);
        mutex_init(&mgr->qlock);
        mutex_init(&mgr->payload_lock);
        if (test_calc_pbn_mode() < 0)
                DRM_ERROR("MST PBN self-test failed\n");
 
-       mgr->state = kzalloc(sizeof(*mgr->state), GFP_KERNEL);
-       if (mgr->state == NULL)
+       mst_state = kzalloc(sizeof(*mst_state), GFP_KERNEL);
+       if (mst_state == NULL)
                return -ENOMEM;
-       mgr->state->mgr = mgr;
+
+       mst_state->mgr = mgr;
 
        /* max. time slots - one slot for MTP header */
-       mgr->state->avail_slots = 63;
-       mgr->funcs = &mst_state_funcs;
+       mst_state->avail_slots = 63;
+
+       drm_atomic_private_obj_init(&mgr->base,
+                                   &mst_state->base,
+                                   &mst_state_funcs);
 
        return 0;
 }
        mutex_unlock(&mgr->payload_lock);
        mgr->dev = NULL;
        mgr->aux = NULL;
-       kfree(mgr->state);
-       mgr->state = NULL;
+       drm_atomic_private_obj_fini(&mgr->base);
        mgr->funcs = NULL;
 }
 EXPORT_SYMBOL(drm_dp_mst_topology_mgr_destroy);
 
        struct drm_connector_state *state, *old_state, *new_state;
 };
 
+struct drm_private_obj;
+struct drm_private_state;
+
 /**
  * struct drm_private_state_funcs - atomic state functions for private objects
  *
  */
 struct drm_private_state_funcs {
        /**
-        * @duplicate_state:
+        * @atomic_duplicate_state:
         *
         * Duplicate the current state of the private object and return it. It
         * is an error to call this before obj->state has been initialized.
         * Duplicated atomic state or NULL when obj->state is not
         * initialized or allocation failed.
         */
-       void *(*duplicate_state)(struct drm_atomic_state *state, void *obj);
+       struct drm_private_state *(*atomic_duplicate_state)(struct drm_private_obj *obj);
 
        /**
-        * @swap_state:
+        * @atomic_destroy_state:
         *
-        * This function swaps the existing state of a private object @obj with
-        * it's newly created state, the pointer to which is passed as
-        * @obj_state_ptr.
+        * Frees the private object state created with @atomic_duplicate_state.
         */
-       void (*swap_state)(void *obj, void **obj_state_ptr);
+       void (*atomic_destroy_state)(struct drm_private_obj *obj,
+                                    struct drm_private_state *state);
+};
 
-       /**
-        * @destroy_state:
-        *
-        * Frees the private object state created with @duplicate_state.
-        */
-       void (*destroy_state)(void *obj_state);
+struct drm_private_obj {
+       struct drm_private_state *state;
+
+       const struct drm_private_state_funcs *funcs;
+};
+
+struct drm_private_state {
+       struct drm_atomic_state *state;
 };
 
 struct __drm_private_objs_state {
-       void *obj;
-       void *obj_state;
-       const struct drm_private_state_funcs *funcs;
+       struct drm_private_obj *ptr;
+       struct drm_private_state *state, *old_state, *new_state;
 };
 
 /**
                struct drm_connector_state *state, struct drm_property *property,
                uint64_t val);
 
-void * __must_check
+void drm_atomic_private_obj_init(struct drm_private_obj *obj,
+                                struct drm_private_state *state,
+                                const struct drm_private_state_funcs *funcs);
+void drm_atomic_private_obj_fini(struct drm_private_obj *obj);
+
+struct drm_private_state * __must_check
 drm_atomic_get_private_obj_state(struct drm_atomic_state *state,
-                             void *obj,
-                             const struct drm_private_state_funcs *funcs);
+                                struct drm_private_obj *obj);
 
 /**
  * drm_atomic_get_existing_crtc_state - get crtc state, if it exists
                for_each_if (plane)
 
 /**
- * __for_each_private_obj - iterate over all private objects
+ * for_each_oldnew_private_obj_in_state - iterate over all private objects in an atomic update
  * @__state: &struct drm_atomic_state pointer
- * @obj: private object iteration cursor
- * @obj_state: private object state iteration cursor
+ * @obj: &struct drm_private_obj iteration cursor
+ * @old_obj_state: &struct drm_private_state iteration cursor for the old state
+ * @new_obj_state: &struct drm_private_state iteration cursor for the new state
  * @__i: int iteration cursor, for macro-internal use
- * @__funcs: &struct drm_private_state_funcs iteration cursor
  *
- * This macro iterates over the array containing private object data in atomic
- * state
+ * This iterates over all private objects in an atomic update, tracking both
+ * old and new state. This is useful in places where the state delta needs
+ * to be considered, for example in atomic check functions.
  */
-#define __for_each_private_obj(__state, obj, obj_state, __i, __funcs)  \
-       for ((__i) = 0;                                                 \
-            (__i) < (__state)->num_private_objs &&                     \
-            ((obj) = (__state)->private_objs[__i].obj,                 \
-             (__funcs) = (__state)->private_objs[__i].funcs,           \
-             (obj_state) = (__state)->private_objs[__i].obj_state,     \
-             1);                                                       \
-            (__i)++)                                                   \
+#define for_each_oldnew_private_obj_in_state(__state, obj, old_obj_state, new_obj_state, __i) \
+       for ((__i) = 0; \
+            (__i) < (__state)->num_private_objs && \
+                    ((obj) = (__state)->private_objs[__i].ptr, \
+                     (old_obj_state) = (__state)->private_objs[__i].old_state, \
+                     (new_obj_state) = (__state)->private_objs[__i].new_state, 1); \
+            (__i)++) \
+               for_each_if (obj)
+
+/**
+ * for_each_old_private_obj_in_state - iterate over all private objects in an atomic update
+ * @__state: &struct drm_atomic_state pointer
+ * @obj: &struct drm_private_obj iteration cursor
+ * @old_obj_state: &struct drm_private_state iteration cursor for the old state
+ * @__i: int iteration cursor, for macro-internal use
+ *
+ * This iterates over all private objects in an atomic update, tracking only
+ * the old state. This is useful in disable functions, where we need the old
+ * state the hardware is still in.
+ */
+#define for_each_old_private_obj_in_state(__state, obj, old_obj_state, __i) \
+       for ((__i) = 0; \
+            (__i) < (__state)->num_private_objs && \
+                    ((obj) = (__state)->private_objs[__i].ptr, \
+                     (old_obj_state) = (__state)->private_objs[__i].old_state, 1); \
+            (__i)++) \
+               for_each_if (obj)
 
 /**
- * for_each_private_obj - iterate over a specify type of private object
+ * for_each_new_private_obj_in_state - iterate over all private objects in an atomic update
  * @__state: &struct drm_atomic_state pointer
- * @obj_funcs: &struct drm_private_state_funcs function table to filter
- *     private objects
- * @obj: private object iteration cursor
- * @obj_state: private object state iteration cursor
+ * @obj: &struct drm_private_obj iteration cursor
+ * @new_obj_state: &struct drm_private_state iteration cursor for the new state
  * @__i: int iteration cursor, for macro-internal use
- * @__funcs: &struct drm_private_state_funcs iteration cursor
  *
- * This macro iterates over the private objects state array while filtering the
- * objects based on the vfunc table that is passed as @obj_funcs. New macros
- * can be created by passing in the vfunc table associated with a specific
- * private object.
+ * This iterates over all private objects in an atomic update, tracking only
+ * the new state. This is useful in enable functions, where we need the new state the
+ * hardware should be in when the atomic commit operation has completed.
  */
-#define for_each_private_obj(__state, obj_funcs, obj, obj_state, __i, __funcs) \
-       __for_each_private_obj(__state, obj, obj_state, __i, __funcs)           \
-               for_each_if (__funcs == obj_funcs)
+#define for_each_new_private_obj_in_state(__state, obj, new_obj_state, __i) \
+       for ((__i) = 0; \
+            (__i) < (__state)->num_private_objs && \
+                    ((obj) = (__state)->private_objs[__i].ptr, \
+                     (new_obj_state) = (__state)->private_objs[__i].new_state, 1); \
+            (__i)++) \
+               for_each_if (obj)
 
 /**
  * drm_atomic_crtc_needs_modeset - compute combined modeset need
 
 #include <drm/drm_modeset_helper.h>
 
 struct drm_atomic_state;
+struct drm_private_obj;
+struct drm_private_state;
 
 int drm_atomic_helper_check_modeset(struct drm_device *dev,
                                struct drm_atomic_state *state);
                                       u16 *red, u16 *green, u16 *blue,
                                       uint32_t size,
                                       struct drm_modeset_acquire_ctx *ctx);
+void __drm_atomic_helper_private_obj_duplicate_state(struct drm_private_obj *obj,
+                                                    struct drm_private_state *state);
 
 /**
  * drm_atomic_crtc_for_each_plane - iterate over planes currently attached to CRTC
 
        int vcpi;
 };
 
+#define to_dp_mst_topology_state(x) container_of(x, struct drm_dp_mst_topology_state, base)
+
 struct drm_dp_mst_topology_state {
+       struct drm_private_state base;
        int avail_slots;
        struct drm_atomic_state *state;
        struct drm_dp_mst_topology_mgr *mgr;
 };
 
+#define to_dp_mst_topology_mgr(x) container_of(x, struct drm_dp_mst_topology_mgr, base)
+
 /**
  * struct drm_dp_mst_topology_mgr - DisplayPort MST manager
  *
  * on the GPU.
  */
 struct drm_dp_mst_topology_mgr {
+       /**
+        * @base: Base private object for atomic
+        */
+       struct drm_private_obj base;
+
        /**
         * @dev: device pointer for adding i2c devices etc.
         */