struct drm_crtc_state *
 intel_crtc_duplicate_state(struct drm_crtc *crtc)
 {
+       const struct intel_crtc_state *old_crtc_state = to_intel_crtc_state(crtc->state);
        struct intel_crtc_state *crtc_state;
 
-       crtc_state = kmemdup(crtc->state, sizeof(*crtc_state), GFP_KERNEL);
+       crtc_state = kmemdup(old_crtc_state, sizeof(*crtc_state), GFP_KERNEL);
        if (!crtc_state)
                return NULL;
 
 intel_crtc_destroy_state(struct drm_crtc *crtc,
                         struct drm_crtc_state *state)
 {
-       drm_atomic_helper_crtc_destroy_state(crtc, state);
+       struct intel_crtc_state *crtc_state = to_intel_crtc_state(state);
+
+       __drm_atomic_helper_crtc_destroy_state(&crtc_state->base);
+       kfree(crtc_state);
 }
 
 static void intel_atomic_setup_scaler(struct intel_crtc_scaler_state *scaler_state,
 
 
        /* Keep base drm_crtc_state intact, only clear our extended struct */
        BUILD_BUG_ON(offsetof(struct intel_crtc_state, base));
+       BUILD_BUG_ON(offsetof(struct intel_crtc_state, uapi));
+       BUILD_BUG_ON(offsetof(struct intel_crtc_state, hw));
        memcpy(&crtc_state->base + 1, &saved_state->base + 1,
               sizeof(*crtc_state) - sizeof(crtc_state->base));
 
 
 #define intel_atomic_crtc_state_for_each_plane_state( \
                  plane, plane_state, \
                  crtc_state) \
-       for_each_intel_plane_mask(((crtc_state)->base.state->dev), (plane), \
-                               ((crtc_state)->base.plane_mask)) \
+       for_each_intel_plane_mask(((crtc_state)->uapi.state->dev), (plane), \
+                               ((crtc_state)->uapi.plane_mask)) \
                for_each_if ((plane_state = \
-                             to_intel_plane_state(__drm_atomic_get_current_plane_state((crtc_state)->base.state, &plane->base))))
+                             to_intel_plane_state(__drm_atomic_get_current_plane_state((crtc_state)->uapi.state, &plane->base))))
 
 void intel_link_compute_m_n(u16 bpp, int nlanes,
                            int pixel_clock, int link_clock,
 
 };
 
 struct intel_crtc_state {
+       union {
        struct drm_crtc_state base;
+       /*
+        * uapi (drm) state. This is the software state shown to userspace.
+        * In particular, the following members are used for bookkeeping:
+        * - crtc
+        * - state
+        * - *_changed
+        * - event
+        * - commit
+        * - mode_blob
+        */
+       struct drm_crtc_state uapi;
+
+       /*
+        * actual hardware state, the state we program to the hardware.
+        * The following members are used to verify the hardware state:
+        * - enable
+        * - active
+        * - mode / adjusted_mode
+        * - color property blobs.
+        *
+        * During initial hw readout, they need to be copied to uapi.
+        */
+       struct drm_crtc_state hw;
+       };
 
        /**
         * quirks - bitfield with hw state readout quirks
 
 #define to_intel_atomic_state(x) container_of(x, struct intel_atomic_state, base)
 #define to_intel_crtc(x) container_of(x, struct intel_crtc, base)
-#define to_intel_crtc_state(x) container_of(x, struct intel_crtc_state, base)
+#define to_intel_crtc_state(x) container_of(x, struct intel_crtc_state, uapi)
 #define to_intel_connector(x) container_of(x, struct intel_connector, base)
 #define to_intel_encoder(x) container_of(x, struct intel_encoder, base)
 #define to_intel_framebuffer(x) container_of(x, struct intel_framebuffer, base)