dev_priv->display.color_commit(crtc_state);
 }
 
+static bool intel_can_preload_luts(const struct intel_crtc_state *new_crtc_state)
+{
+       struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc);
+       struct intel_atomic_state *state =
+               to_intel_atomic_state(new_crtc_state->uapi.state);
+       const struct intel_crtc_state *old_crtc_state =
+               intel_atomic_get_old_crtc_state(state, crtc);
+
+       return !old_crtc_state->hw.gamma_lut &&
+               !old_crtc_state->hw.degamma_lut;
+}
+
+static bool chv_can_preload_luts(const struct intel_crtc_state *new_crtc_state)
+{
+       struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc);
+       struct intel_atomic_state *state =
+               to_intel_atomic_state(new_crtc_state->uapi.state);
+       const struct intel_crtc_state *old_crtc_state =
+               intel_atomic_get_old_crtc_state(state, crtc);
+
+       /*
+        * CGM_PIPE_MODE is itself single buffered. We'd have to
+        * somehow split it out from chv_load_luts() if we wanted
+        * the ability to preload the CGM LUTs/CSC without tearing.
+        */
+       if (old_crtc_state->cgm_mode || new_crtc_state->cgm_mode)
+               return false;
+
+       return !old_crtc_state->hw.gamma_lut;
+}
+
+static bool glk_can_preload_luts(const struct intel_crtc_state *new_crtc_state)
+{
+       struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc);
+       struct intel_atomic_state *state =
+               to_intel_atomic_state(new_crtc_state->uapi.state);
+       const struct intel_crtc_state *old_crtc_state =
+               intel_atomic_get_old_crtc_state(state, crtc);
+
+       /*
+        * The hardware degamma is active whenever the pipe
+        * CSC is active. Thus even if the old state has no
+        * software degamma we need to avoid clobbering the
+        * linear hardware degamma mid scanout.
+        */
+       return !old_crtc_state->csc_enable &&
+               !old_crtc_state->hw.gamma_lut;
+}
+
 int intel_color_check(struct intel_crtc_state *crtc_state)
 {
        struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
        if (ret)
                return ret;
 
+       crtc_state->preload_luts = intel_can_preload_luts(crtc_state);
+
        return 0;
 }
 
        if (ret)
                return ret;
 
+       crtc_state->preload_luts = chv_can_preload_luts(crtc_state);
+
        return 0;
 }
 
        if (ret)
                return ret;
 
+       crtc_state->preload_luts = intel_can_preload_luts(crtc_state);
+
        return 0;
 }
 
        if (ret)
                return ret;
 
+       crtc_state->preload_luts = intel_can_preload_luts(crtc_state);
+
        return 0;
 }
 
        if (ret)
                return ret;
 
+       crtc_state->preload_luts = glk_can_preload_luts(crtc_state);
+
        return 0;
 }
 
 
        crtc_state->csc_mode = icl_csc_mode(crtc_state);
 
+       crtc_state->preload_luts = intel_can_preload_luts(crtc_state);
+
        return 0;
 }
 
 
                /* vblanks work again, re-enable pipe CRC. */
                intel_crtc_enable_pipe_crc(crtc);
        } else {
+               if (new_crtc_state->preload_luts &&
+                   (new_crtc_state->uapi.color_mgmt_changed ||
+                    new_crtc_state->update_pipe))
+                       intel_color_load_luts(new_crtc_state);
+
                intel_pre_plane_update(old_crtc_state, new_crtc_state);
 
                if (new_crtc_state->update_pipe)
        for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) {
                if (new_crtc_state->hw.active &&
                    !needs_modeset(new_crtc_state) &&
+                   !new_crtc_state->preload_luts &&
                    (new_crtc_state->uapi.color_mgmt_changed ||
                     new_crtc_state->update_pipe))
                        intel_color_load_luts(new_crtc_state);