**************************************************************************/
 
 #include "vmwgfx_kms.h"
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
 
 
 /* Might need a hrtimer here? */
 }
 
 
+/**
+ * vmw_du_crtc_duplicate_state - duplicate crtc state
+ * @crtc: DRM crtc
+ *
+ * Allocates and returns a copy of the crtc state (both common and
+ * vmw-specific) for the specified crtc.
+ *
+ * Returns: The newly allocated crtc state, or NULL on failure.
+ */
+struct drm_crtc_state *
+vmw_du_crtc_duplicate_state(struct drm_crtc *crtc)
+{
+       struct drm_crtc_state *state;
+       struct vmw_crtc_state *vcs;
+
+       if (WARN_ON(!crtc->state))
+               return NULL;
+
+       vcs = kmemdup(crtc->state, sizeof(*vcs), GFP_KERNEL);
+
+       if (!vcs)
+               return NULL;
+
+       state = &vcs->base;
+
+       __drm_atomic_helper_crtc_duplicate_state(crtc, state);
+
+       return state;
+}
+
+
+/**
+ * vmw_du_crtc_reset - creates a blank vmw crtc state
+ * @crtc: DRM crtc
+ *
+ * Resets the atomic state for @crtc by freeing the state pointer (which
+ * might be NULL, e.g. at driver load time) and allocating a new empty state
+ * object.
+ */
+void vmw_du_crtc_reset(struct drm_crtc *crtc)
+{
+       struct vmw_crtc_state *vcs;
+
+
+       if (crtc->state) {
+               __drm_atomic_helper_crtc_destroy_state(crtc->state);
+
+               kfree(vmw_crtc_state_to_vcs(crtc->state));
+       }
+
+       vcs = kzalloc(sizeof(*vcs), GFP_KERNEL);
+
+       if (!vcs) {
+               DRM_ERROR("Cannot allocate vmw_crtc_state\n");
+               return;
+       }
+
+       crtc->state = &vcs->base;
+       crtc->state->crtc = crtc;
+}
+
+
+/**
+ * vmw_du_crtc_destroy_state - destroy crtc state
+ * @crtc: DRM crtc
+ * @state: state object to destroy
+ *
+ * Destroys the crtc state (both common and vmw-specific) for the
+ * specified plane.
+ */
+void
+vmw_du_crtc_destroy_state(struct drm_crtc *crtc,
+                         struct drm_crtc_state *state)
+{
+       drm_atomic_helper_crtc_destroy_state(crtc, state);
+}
+
+
 /*
  * Generic framebuffer code
  */
 }
 
 
+
 int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data,
                                struct drm_file *file_priv)
 {
 
        DRM_FORMAT_ARGB8888,
 };
 
+
+#define vmw_crtc_state_to_vcs(x) container_of(x, struct vmw_crtc_state, base)
+
+
+/**
+ * Derived class for crtc state object
+ *
+ * @base DRM crtc object
+ */
+struct vmw_crtc_state {
+       struct drm_crtc_state base;
+};
+
 /**
  * Base class display unit.
  *
                            uint32_t handle, uint32_t width, uint32_t height,
                            int32_t hot_x, int32_t hot_y);
 int vmw_du_crtc_cursor_move(struct drm_crtc *crtc, int x, int y);
+int vmw_du_connector_set_property(struct drm_connector *connector,
+                                 struct drm_property *property,
+                                 uint64_t val);
 int vmw_du_connector_dpms(struct drm_connector *connector, int mode);
 void vmw_du_connector_save(struct drm_connector *connector);
 void vmw_du_connector_restore(struct drm_connector *connector);
 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_property *property,
-                                 uint64_t val);
 int vmw_kms_helper_dirty(struct vmw_private *dev_priv,
                         struct vmw_framebuffer *framebuffer,
                         const struct drm_clip_rect *clips,
                               uint32_t src_x, uint32_t src_y,
                               uint32_t src_w, uint32_t src_h);
 
+void vmw_du_crtc_reset(struct drm_crtc *crtc);
+struct drm_crtc_state *vmw_du_crtc_duplicate_state(struct drm_crtc *crtc);
+void vmw_du_crtc_destroy_state(struct drm_crtc *crtc,
+                               struct drm_crtc_state *state);
 
 /*
  * Legacy display unit functions - vmwgfx_ldu.c
 
 static const struct drm_crtc_funcs vmw_legacy_crtc_funcs = {
        .gamma_set = vmw_du_crtc_gamma_set,
        .destroy = vmw_ldu_crtc_destroy,
+       .reset = vmw_du_crtc_reset,
+       .atomic_duplicate_state = vmw_du_crtc_duplicate_state,
+       .atomic_destroy_state = vmw_du_crtc_destroy_state,
        .set_config = vmw_ldu_crtc_set_config,
 };
 
        ldu->base.pref_width = dev_priv->initial_width;
        ldu->base.pref_height = dev_priv->initial_height;
        ldu->base.pref_mode = NULL;
+
+       /*
+        * Remove this after enabling atomic because property values can
+        * only exist in a state object
+        */
        ldu->base.is_implicit = true;
 
        /* Initialize primary plane */
                goto err_free_encoder;
        }
 
+       /* FIXME: Turn on after plane/connector states are implemented. */
+       /* vmw_du_crtc_reset(crtc); */
        ret = drm_crtc_init_with_planes(dev, crtc, &ldu->base.primary,
                                        &ldu->base.cursor,
                                        &vmw_legacy_crtc_funcs, NULL);
 
 static const struct drm_crtc_funcs vmw_screen_object_crtc_funcs = {
        .gamma_set = vmw_du_crtc_gamma_set,
        .destroy = vmw_sou_crtc_destroy,
+       .reset = vmw_du_crtc_reset,
+       .atomic_duplicate_state = vmw_du_crtc_duplicate_state,
+       .atomic_destroy_state = vmw_du_crtc_destroy_state,
        .set_config = vmw_sou_crtc_set_config,
        .page_flip = vmw_sou_crtc_page_flip,
 };
        sou->base.pref_width = dev_priv->initial_width;
        sou->base.pref_height = dev_priv->initial_height;
        sou->base.pref_mode = NULL;
+
+       /*
+        * Remove this after enabling atomic because property values can
+        * only exist in a state object
+        */
        sou->base.is_implicit = false;
 
        /* Initialize primary plane */
                goto err_free_encoder;
        }
 
+       /* FIXME: Turn on after plane/connector states are implemented. */
+       /* vmw_du_crtc_reset(crtc); */
        ret = drm_crtc_init_with_planes(dev, crtc, &sou->base.primary,
                                        &sou->base.cursor,
                                        &vmw_screen_object_crtc_funcs, NULL);
 
 static const struct drm_crtc_funcs vmw_stdu_crtc_funcs = {
        .gamma_set = vmw_du_crtc_gamma_set,
        .destroy = vmw_stdu_crtc_destroy,
+       .reset = vmw_du_crtc_reset,
+       .atomic_duplicate_state = vmw_du_crtc_duplicate_state,
+       .atomic_destroy_state = vmw_du_crtc_destroy_state,
        .set_config = vmw_stdu_crtc_set_config,
        .page_flip = vmw_stdu_crtc_page_flip,
 };
        stdu->base.pref_active = (unit == 0);
        stdu->base.pref_width  = dev_priv->initial_width;
        stdu->base.pref_height = dev_priv->initial_height;
+
+       /*
+        * Remove this after enabling atomic because property values can
+        * only exist in a state object
+        */
        stdu->base.is_implicit = false;
 
        /* Initialize primary plane */
                goto err_free_encoder;
        }
 
+       /* FIXME: Turn on after plane/connector states are implemented. */
+       /* vmw_du_crtc_reset(crtc); */
        ret = drm_crtc_init_with_planes(dev, crtc, &stdu->base.primary,
                                        &stdu->base.cursor,
                                        &vmw_stdu_crtc_funcs, NULL);