}
 
 
+int vmw_du_crtc_atomic_check(struct drm_crtc *crtc,
+                            struct drm_crtc_state *new_state)
+{
+       struct vmw_display_unit *du = vmw_crtc_to_du(new_state->crtc);
+       int connector_mask = 1 << drm_connector_index(&du->connector);
+       bool has_primary = new_state->plane_mask &
+                          BIT(drm_plane_index(crtc->primary));
+
+       /* We always want to have an active plane with an active CRTC */
+       if (has_primary != new_state->enable)
+               return -EINVAL;
+
+
+       if (new_state->connector_mask != connector_mask &&
+           new_state->connector_mask != 0) {
+               DRM_ERROR("Invalid connectors configuration\n");
+               return -EINVAL;
+       }
+
+       /*
+        * Our virtual device does not have a dot clock, so use the logical
+        * clock value as the dot clock.
+        */
+       if (new_state->mode.crtc_clock == 0)
+               new_state->adjusted_mode.crtc_clock = new_state->mode.clock;
+
+       return 0;
+}
+
+
+void vmw_du_crtc_atomic_begin(struct drm_crtc *crtc,
+                             struct drm_crtc_state *old_crtc_state)
+{
+}
+
+
+void vmw_du_crtc_atomic_flush(struct drm_crtc *crtc,
+                             struct drm_crtc_state *old_crtc_state)
+{
+       struct drm_pending_vblank_event *event = crtc->state->event;
+
+       if (event) {
+               crtc->state->event = NULL;
+
+               spin_lock_irq(&crtc->dev->event_lock);
+               if (drm_crtc_vblank_get(crtc) == 0)
+                       drm_crtc_arm_vblank_event(crtc, event);
+               else
+                       drm_crtc_send_vblank_event(crtc, event);
+               spin_unlock_irq(&crtc->dev->event_lock);
+       }
+
+}
+
+
 /**
  * vmw_du_crtc_duplicate_state - duplicate crtc state
  * @crtc: DRM crtc
 
  * @surf Display surface for STDU
  * @dmabuf display dmabuf for SOU
  * @content_fb_type Used by STDU.
+ * @dmabuf_size Size of the dmabuf, used by Screen Object Display Unit
  * @pinned pin count for STDU display surface
  */
 struct vmw_plane_state {
        struct vmw_dma_buffer *dmabuf;
 
        int content_fb_type;
+       unsigned long dmabuf_size;
 
        int pinned;
 };
                               uint32_t src_x, uint32_t src_y,
                               uint32_t src_w, uint32_t src_h);
 
+/* Atomic Helpers */
 void vmw_du_plane_reset(struct drm_plane *plane);
 struct drm_plane_state *vmw_du_plane_duplicate_state(struct drm_plane *plane);
 void vmw_du_plane_destroy_state(struct drm_plane *plane,
                                struct drm_plane_state *state);
+int vmw_du_crtc_atomic_check(struct drm_crtc *crtc,
+                            struct drm_crtc_state *state);
+void vmw_du_crtc_atomic_begin(struct drm_crtc *crtc,
+                             struct drm_crtc_state *old_crtc_state);
+void vmw_du_crtc_atomic_flush(struct drm_crtc *crtc,
+                             struct drm_crtc_state *old_crtc_state);
 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,
 
        if (vfb != ld->fb) {
                if (ld->fb && ld->fb->unpin)
                        ld->fb->unpin(ld->fb);
+               vmw_svga_enable(vmw_priv);
                if (vfb->pin)
                        vfb->pin(vfb);
                ld->fb = vfb;
        return 0;
 }
 
+/**
+ * vmw_ldu_crtc_mode_set_nofb - Enable svga
+ *
+ * @crtc: CRTC associated with the new screen
+ *
+ * For LDU, just enable the svga
+ */
+static void vmw_ldu_crtc_mode_set_nofb(struct drm_crtc *crtc)
+{
+}
+
+/**
+ * vmw_ldu_crtc_helper_prepare - Noop
+ *
+ * @crtc: CRTC associated with the new screen
+ *
+ * Prepares the CRTC for a mode set, but we don't need to do anything here.
+ *
+ */
+static void vmw_ldu_crtc_helper_prepare(struct drm_crtc *crtc)
+{
+}
+
+/**
+ * vmw_ldu_crtc_helper_commit - Noop
+ *
+ * @crtc: CRTC associated with the new screen
+ *
+ * This is called after a mode set has been completed.  Here's
+ * usually a good place to call vmw_ldu_add_active/vmw_ldu_del_active
+ * but since for LDU the display plane is closely tied to the
+ * CRTC, it makes more sense to do those at plane update time.
+ */
+static void vmw_ldu_crtc_helper_commit(struct drm_crtc *crtc)
+{
+       struct vmw_private *dev_priv;
+       struct vmw_legacy_display_unit *ldu;
+       struct vmw_framebuffer *vfb;
+       struct drm_framebuffer *fb;
+
+
+       ldu = vmw_crtc_to_ldu(crtc);
+       dev_priv = vmw_priv(crtc->dev);
+       fb       = crtc->primary->fb;
+
+       vfb = (fb) ? vmw_framebuffer_to_vfb(fb) : NULL;
+
+       if (vfb)
+               vmw_ldu_add_active(dev_priv, ldu, vfb);
+       else
+               vmw_ldu_del_active(dev_priv, ldu);
+}
+
+/**
+ * vmw_ldu_crtc_helper_disable - Turns off CRTC
+ *
+ * @crtc: CRTC to be turned off
+ */
+static void vmw_ldu_crtc_helper_disable(struct drm_crtc *crtc)
+{
+}
+
 static int vmw_ldu_crtc_set_config(struct drm_mode_set *set)
 {
        struct vmw_private *dev_priv;
        .atomic_destroy_state = vmw_du_plane_destroy_state,
 };
 
+/*
+ * Atomic Helpers
+ */
+static const struct drm_crtc_helper_funcs vmw_ldu_crtc_helper_funcs = {
+       .prepare = vmw_ldu_crtc_helper_prepare,
+       .commit = vmw_ldu_crtc_helper_commit,
+       .disable = vmw_ldu_crtc_helper_disable,
+       .mode_set = drm_helper_crtc_mode_set,
+       .mode_set_nofb = vmw_ldu_crtc_mode_set_nofb,
+       .atomic_check = vmw_du_crtc_atomic_check,
+       .atomic_begin = vmw_du_crtc_atomic_begin,
+       .atomic_flush = vmw_du_crtc_atomic_flush,
+};
+
 
 static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit)
 {
                goto err_free_unregister;
        }
 
+       drm_crtc_helper_add(crtc, &vmw_ldu_crtc_helper_funcs);
+
        drm_mode_crtc_set_gamma_size(crtc, 256);
 
        drm_object_attach_property(&connector->base,
 
        return ret;
 }
 
+/**
+ * vmw_sou_crtc_mode_set_nofb - Create new screen
+ *
+ * @crtc: CRTC associated with the new screen
+ *
+ * This function creates/destroys a screen.  This function cannot fail, so if
+ * somehow we run into a failure, just do the best we can to get out.
+ */
+static void vmw_sou_crtc_mode_set_nofb(struct drm_crtc *crtc)
+{
+       struct vmw_private *dev_priv;
+       struct vmw_screen_object_unit *sou;
+       struct vmw_framebuffer *vfb;
+       struct drm_framebuffer *fb;
+       struct drm_plane_state *ps;
+       struct vmw_plane_state *vps;
+       int ret;
+
+
+       sou      = vmw_crtc_to_sou(crtc);
+       dev_priv = vmw_priv(crtc->dev);
+       ps       = crtc->primary->state;
+       fb       = ps->fb;
+       vps      = vmw_plane_state_to_vps(ps);
+
+       vfb = (fb) ? vmw_framebuffer_to_vfb(fb) : NULL;
+
+       if (sou->defined) {
+               ret = vmw_sou_fifo_destroy(dev_priv, sou);
+               if (ret) {
+                       DRM_ERROR("Failed to destroy Screen Object\n");
+                       return;
+               }
+       }
+
+       if (vfb) {
+               sou->buffer = vps->dmabuf;
+               sou->buffer_size = vps->dmabuf_size;
+
+               ret = vmw_sou_fifo_create(dev_priv, sou, crtc->x, crtc->y,
+                                         &crtc->mode);
+               if (ret)
+                       DRM_ERROR("Failed to define Screen Object %dx%d\n",
+                                 crtc->x, crtc->y);
+
+               vmw_kms_add_active(dev_priv, &sou->base, vfb);
+       } else {
+               sou->buffer = NULL;
+               sou->buffer_size = 0;
+
+               vmw_kms_del_active(dev_priv, &sou->base);
+       }
+}
+
+/**
+ * vmw_sou_crtc_helper_prepare - Noop
+ *
+ * @crtc: CRTC associated with the new screen
+ *
+ * Prepares the CRTC for a mode set, but we don't need to do anything here.
+ */
+static void vmw_sou_crtc_helper_prepare(struct drm_crtc *crtc)
+{
+}
+
+/**
+ * vmw_sou_crtc_helper_commit - Noop
+ *
+ * @crtc: CRTC associated with the new screen
+ *
+ * This is called after a mode set has been completed.
+ */
+static void vmw_sou_crtc_helper_commit(struct drm_crtc *crtc)
+{
+}
+
+/**
+ * vmw_sou_crtc_helper_disable - Turns off CRTC
+ *
+ * @crtc: CRTC to be turned off
+ */
+static void vmw_sou_crtc_helper_disable(struct drm_crtc *crtc)
+{
+       struct vmw_private *dev_priv;
+       struct vmw_screen_object_unit *sou;
+       int ret;
+
+
+       if (!crtc) {
+               DRM_ERROR("CRTC is NULL\n");
+               return;
+       }
+
+       sou = vmw_crtc_to_sou(crtc);
+       dev_priv = vmw_priv(crtc->dev);
+
+       if (sou->defined) {
+               ret = vmw_sou_fifo_destroy(dev_priv, sou);
+               if (ret)
+                       DRM_ERROR("Failed to destroy Screen Object\n");
+       }
+}
+
 static int vmw_sou_crtc_set_config(struct drm_mode_set *set)
 {
        struct vmw_private *dev_priv;
        .atomic_destroy_state = vmw_du_plane_destroy_state,
 };
 
+/*
+ * Atomic Helpers
+ */
+static const struct drm_crtc_helper_funcs vmw_sou_crtc_helper_funcs = {
+       .prepare = vmw_sou_crtc_helper_prepare,
+       .commit = vmw_sou_crtc_helper_commit,
+       .disable = vmw_sou_crtc_helper_disable,
+       .mode_set = drm_helper_crtc_mode_set,
+       .mode_set_nofb = vmw_sou_crtc_mode_set_nofb,
+       .atomic_check = vmw_du_crtc_atomic_check,
+       .atomic_begin = vmw_du_crtc_atomic_begin,
+       .atomic_flush = vmw_du_crtc_atomic_flush,
+};
+
 
 static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit)
 {
                goto err_free_unregister;
        }
 
+       drm_crtc_helper_add(crtc, &vmw_sou_crtc_helper_funcs);
+
        drm_mode_crtc_set_gamma_size(crtc, 256);
 
        drm_object_attach_property(&connector->base,
 
        return ret;
 }
 
+
+/**
+ * vmw_stdu_crtc_mode_set_nofb - Updates screen target size
+ *
+ * @crtc: CRTC associated with the screen target
+ *
+ * This function defines/destroys a screen target
+ *
+ */
+static void vmw_stdu_crtc_mode_set_nofb(struct drm_crtc *crtc)
+{
+       struct vmw_private *dev_priv;
+       struct vmw_screen_target_display_unit *stdu;
+       int ret;
+
+
+       stdu     = vmw_crtc_to_stdu(crtc);
+       dev_priv = vmw_priv(crtc->dev);
+
+       if (stdu->defined) {
+               ret = vmw_stdu_bind_st(dev_priv, stdu, NULL);
+               if (ret)
+                       DRM_ERROR("Failed to blank CRTC\n");
+
+               (void) vmw_stdu_update_st(dev_priv, stdu);
+
+               ret = vmw_stdu_destroy_st(dev_priv, stdu);
+               if (ret)
+                       DRM_ERROR("Failed to destroy Screen Target\n");
+
+               stdu->content_fb_type = SAME_AS_DISPLAY;
+       }
+
+       if (!crtc->state->enable)
+               return;
+
+       vmw_svga_enable(dev_priv);
+       ret = vmw_stdu_define_st(dev_priv, stdu, &crtc->mode, crtc->x, crtc->y);
+
+       if (ret)
+               DRM_ERROR("Failed to define Screen Target of size %dx%d\n",
+                         crtc->x, crtc->y);
+}
+
+
+static void vmw_stdu_crtc_helper_prepare(struct drm_crtc *crtc)
+{
+}
+
+
+static void vmw_stdu_crtc_helper_commit(struct drm_crtc *crtc)
+{
+       struct vmw_private *dev_priv;
+       struct vmw_screen_target_display_unit *stdu;
+       struct vmw_framebuffer *vfb;
+       struct drm_framebuffer *fb;
+
+
+       stdu     = vmw_crtc_to_stdu(crtc);
+       dev_priv = vmw_priv(crtc->dev);
+       fb       = crtc->primary->fb;
+
+       vfb = (fb) ? vmw_framebuffer_to_vfb(fb) : NULL;
+
+       if (vfb)
+               vmw_kms_add_active(dev_priv, &stdu->base, vfb);
+       else
+               vmw_kms_del_active(dev_priv, &stdu->base);
+}
+
+static void vmw_stdu_crtc_helper_disable(struct drm_crtc *crtc)
+{
+       struct vmw_private *dev_priv;
+       struct vmw_screen_target_display_unit *stdu;
+       int ret;
+
+
+       if (!crtc) {
+               DRM_ERROR("CRTC is NULL\n");
+               return;
+       }
+
+       stdu     = vmw_crtc_to_stdu(crtc);
+       dev_priv = vmw_priv(crtc->dev);
+
+       if (stdu->defined) {
+               ret = vmw_stdu_bind_st(dev_priv, stdu, NULL);
+               if (ret)
+                       DRM_ERROR("Failed to blank CRTC\n");
+
+               (void) vmw_stdu_update_st(dev_priv, stdu);
+
+               ret = vmw_stdu_destroy_st(dev_priv, stdu);
+               if (ret)
+                       DRM_ERROR("Failed to destroy Screen Target\n");
+
+               stdu->content_fb_type = SAME_AS_DISPLAY;
+       }
+}
+
 /**
  * vmw_stdu_crtc_set_config - Sets a mode
  *
 };
 
 
+/*
+ * Atomic Helpers
+ */
+static const struct drm_crtc_helper_funcs vmw_stdu_crtc_helper_funcs = {
+       .prepare = vmw_stdu_crtc_helper_prepare,
+       .commit = vmw_stdu_crtc_helper_commit,
+       .disable = vmw_stdu_crtc_helper_disable,
+       .mode_set = drm_helper_crtc_mode_set,
+       .mode_set_nofb = vmw_stdu_crtc_mode_set_nofb,
+       .atomic_check = vmw_du_crtc_atomic_check,
+       .atomic_begin = vmw_du_crtc_atomic_begin,
+       .atomic_flush = vmw_du_crtc_atomic_flush,
+};
+
+
 /**
  * vmw_stdu_init - Sets up a Screen Target Display Unit
  *
                goto err_free_unregister;
        }
 
+       drm_crtc_helper_add(crtc, &vmw_stdu_crtc_helper_funcs);
+
        drm_mode_crtc_set_gamma_size(crtc, 256);
 
        drm_object_attach_property(&connector->base,