* involved with the same commit.
         */
        void (*load_luts)(const struct intel_crtc_state *crtc_state);
+       /*
+        * Read out the LUTs from the hardware into the software state.
+        * Used by eg. the hardware state checker.
+        */
        void (*read_luts)(struct intel_crtc_state *crtc_state);
+       /*
+        * Compare the LUTs
+        */
+       bool (*lut_equal)(const struct intel_crtc_state *crtc_state,
+                         const struct drm_property_blob *blob1,
+                         const struct drm_property_blob *blob2,
+                         bool is_pre_csc_lut);
 };
 
 #define CTM_COEFF_SIGN (1ULL << 63)
        i915->display.funcs.color->read_luts(crtc_state);
 }
 
+bool intel_color_lut_equal(const struct intel_crtc_state *crtc_state,
+                          const struct drm_property_blob *blob1,
+                          const struct drm_property_blob *blob2,
+                          bool is_pre_csc_lut)
+{
+       struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
+
+       /*
+        * FIXME c8_planes readout missing thus
+        * .read_luts() doesn't read out post_csc_lut.
+        */
+       if (!is_pre_csc_lut && crtc_state->c8_planes)
+               return true;
+
+       return i915->display.funcs.color->lut_equal(crtc_state, blob1, blob2,
+                                                   is_pre_csc_lut);
+}
+
 static bool need_plane_update(struct intel_plane *plane,
                              const struct intel_crtc_state *crtc_state)
 {
        }
 }
 
+static int i9xx_pre_csc_lut_precision(const struct intel_crtc_state *crtc_state)
+{
+       return 0;
+}
+
+static int ilk_gamma_mode_precision(u32 gamma_mode)
+{
+       switch (gamma_mode) {
+       case GAMMA_MODE_MODE_8BIT:
+               return 8;
+       case GAMMA_MODE_MODE_10BIT:
+               return 10;
+       default:
+               MISSING_CASE(gamma_mode);
+               return 0;
+       }
+}
+
 static bool ilk_has_post_csc_lut(const struct intel_crtc_state *crtc_state)
 {
        if (crtc_state->c8_planes)
                (crtc_state->csc_mode & CSC_POSITION_BEFORE_GAMMA) != 0;
 }
 
+static bool ilk_has_pre_csc_lut(const struct intel_crtc_state *crtc_state)
+{
+       return crtc_state->gamma_enable &&
+               (crtc_state->csc_mode & CSC_POSITION_BEFORE_GAMMA) == 0;
+}
+
 static int ilk_post_csc_lut_precision(const struct intel_crtc_state *crtc_state)
 {
        if (!ilk_has_post_csc_lut(crtc_state))
                return 0;
 
-       switch (crtc_state->gamma_mode) {
-       case GAMMA_MODE_MODE_8BIT:
-               return 8;
-       case GAMMA_MODE_MODE_10BIT:
-               return 10;
-       default:
-               MISSING_CASE(crtc_state->gamma_mode);
+       return ilk_gamma_mode_precision(crtc_state->gamma_mode);
+}
+
+static int ilk_pre_csc_lut_precision(const struct intel_crtc_state *crtc_state)
+{
+       if (!ilk_has_pre_csc_lut(crtc_state))
                return 0;
-       }
+
+       return ilk_gamma_mode_precision(crtc_state->gamma_mode);
+}
+
+static int ivb_post_csc_lut_precision(const struct intel_crtc_state *crtc_state)
+{
+       if (crtc_state->gamma_enable &&
+           crtc_state->gamma_mode == GAMMA_MODE_MODE_SPLIT)
+               return 10;
+
+       return ilk_post_csc_lut_precision(crtc_state);
+}
+
+static int ivb_pre_csc_lut_precision(const struct intel_crtc_state *crtc_state)
+{
+       if (crtc_state->gamma_enable &&
+           crtc_state->gamma_mode == GAMMA_MODE_MODE_SPLIT)
+               return 10;
+
+       return ilk_pre_csc_lut_precision(crtc_state);
 }
 
 static int chv_post_csc_lut_precision(const struct intel_crtc_state *crtc_state)
 {
        if (crtc_state->cgm_mode & CGM_PIPE_MODE_GAMMA)
                return 10;
-       else
-               return i9xx_post_csc_lut_precision(crtc_state);
+
+       return i9xx_post_csc_lut_precision(crtc_state);
+}
+
+static int chv_pre_csc_lut_precision(const struct intel_crtc_state *crtc_state)
+{
+       if (crtc_state->cgm_mode & CGM_PIPE_MODE_DEGAMMA)
+               return 14;
+
+       return 0;
 }
 
 static int glk_post_csc_lut_precision(const struct intel_crtc_state *crtc_state)
        if (!crtc_state->gamma_enable && !crtc_state->c8_planes)
                return 0;
 
-       switch (crtc_state->gamma_mode) {
-       case GAMMA_MODE_MODE_8BIT:
-               return 8;
-       case GAMMA_MODE_MODE_10BIT:
-               return 10;
-       default:
-               MISSING_CASE(crtc_state->gamma_mode);
+       return ilk_gamma_mode_precision(crtc_state->gamma_mode);
+}
+
+static int glk_pre_csc_lut_precision(const struct intel_crtc_state *crtc_state)
+{
+       if (!crtc_state->csc_enable)
                return 0;
-       }
+
+       return 16;
 }
 
 static bool icl_has_post_csc_lut(const struct intel_crtc_state *crtc_state)
        }
 }
 
-int intel_color_get_gamma_bit_precision(const struct intel_crtc_state *crtc_state)
+static int icl_pre_csc_lut_precision(const struct intel_crtc_state *crtc_state)
 {
-       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
-       struct drm_i915_private *i915 = to_i915(crtc->base.dev);
-
-       if (HAS_GMCH(i915)) {
-               if (IS_CHERRYVIEW(i915))
-                       return chv_post_csc_lut_precision(crtc_state);
-               else
-                       return i9xx_post_csc_lut_precision(crtc_state);
-       } else {
-               if (DISPLAY_VER(i915) >= 11)
-                       return icl_post_csc_lut_precision(crtc_state);
-               else if (DISPLAY_VER(i915) == 10)
-                       return glk_post_csc_lut_precision(crtc_state);
-               else if (IS_IRONLAKE(i915))
-                       return ilk_post_csc_lut_precision(crtc_state);
-       }
+       if (!icl_has_pre_csc_lut(crtc_state))
+               return 0;
 
-       return 0;
+       return 16;
 }
 
 static bool err_check(struct drm_color_lut *lut1,
                ((abs((long)lut2->green - lut1->green)) <= err);
 }
 
-static bool intel_color_lut_entries_equal(struct drm_color_lut *lut1,
-                                         struct drm_color_lut *lut2,
-                                         int lut_size, u32 err)
+static bool intel_lut_entries_equal(struct drm_color_lut *lut1,
+                                   struct drm_color_lut *lut2,
+                                   int lut_size, u32 err)
 {
        int i;
 
        return true;
 }
 
-bool intel_color_lut_equal(struct drm_property_blob *blob1,
-                          struct drm_property_blob *blob2,
-                          u32 gamma_mode, u32 bit_precision)
+static bool intel_lut_equal(const struct drm_property_blob *blob1,
+                           const struct drm_property_blob *blob2,
+                           int check_size, int precision)
 {
        struct drm_color_lut *lut1, *lut2;
        int lut_size1, lut_size2;
        if (!blob1 != !blob2)
                return false;
 
+       if (!blob1 != !precision)
+               return false;
+
        if (!blob1)
                return true;
 
        lut_size1 = drm_color_lut_size(blob1);
        lut_size2 = drm_color_lut_size(blob2);
 
-       /* check sw and hw lut size */
        if (lut_size1 != lut_size2)
                return false;
 
        lut1 = blob1->data;
        lut2 = blob2->data;
 
-       err = 0xffff >> bit_precision;
+       err = 0xffff >> precision;
 
-       /* check sw and hw lut entry to be equal */
-       switch (gamma_mode & GAMMA_MODE_MODE_MASK) {
-       case GAMMA_MODE_MODE_8BIT:
-       case GAMMA_MODE_MODE_10BIT:
-               if (!intel_color_lut_entries_equal(lut1, lut2,
-                                                  lut_size2, err))
-                       return false;
-               break;
-       case GAMMA_MODE_MODE_12BIT_MULTI_SEGMENTED:
-               if (!intel_color_lut_entries_equal(lut1, lut2,
-                                                  9, err))
-                       return false;
-               break;
-       default:
-               MISSING_CASE(gamma_mode);
-               return false;
-       }
+       if (!check_size)
+               check_size = lut_size1;
 
-       return true;
+       return intel_lut_entries_equal(lut1, lut2, check_size, err);
+}
+
+static bool i9xx_lut_equal(const struct intel_crtc_state *crtc_state,
+                          const struct drm_property_blob *blob1,
+                          const struct drm_property_blob *blob2,
+                          bool is_pre_csc_lut)
+{
+       if (is_pre_csc_lut)
+               return intel_lut_equal(blob1, blob2, 0,
+                                      i9xx_pre_csc_lut_precision(crtc_state));
+       else
+               return intel_lut_equal(blob1, blob2, 0,
+                                      i9xx_post_csc_lut_precision(crtc_state));
+}
+
+static bool chv_lut_equal(const struct intel_crtc_state *crtc_state,
+                         const struct drm_property_blob *blob1,
+                         const struct drm_property_blob *blob2,
+                         bool is_pre_csc_lut)
+{
+       if (is_pre_csc_lut)
+               return intel_lut_equal(blob1, blob2, 0,
+                                      chv_pre_csc_lut_precision(crtc_state));
+       else
+               return intel_lut_equal(blob1, blob2, 0,
+                                      chv_post_csc_lut_precision(crtc_state));
+}
+
+static bool ilk_lut_equal(const struct intel_crtc_state *crtc_state,
+                         const struct drm_property_blob *blob1,
+                         const struct drm_property_blob *blob2,
+                         bool is_pre_csc_lut)
+{
+       if (is_pre_csc_lut)
+               return intel_lut_equal(blob1, blob2, 0,
+                                      ilk_pre_csc_lut_precision(crtc_state));
+       else
+               return intel_lut_equal(blob1, blob2, 0,
+                                      ilk_post_csc_lut_precision(crtc_state));
+}
+
+static bool ivb_lut_equal(const struct intel_crtc_state *crtc_state,
+                         const struct drm_property_blob *blob1,
+                         const struct drm_property_blob *blob2,
+                         bool is_pre_csc_lut)
+{
+       if (is_pre_csc_lut)
+               return intel_lut_equal(blob1, blob2, 0,
+                                      ivb_pre_csc_lut_precision(crtc_state));
+       else
+               return intel_lut_equal(blob1, blob2, 0,
+                                      ivb_post_csc_lut_precision(crtc_state));
+}
+
+static bool glk_lut_equal(const struct intel_crtc_state *crtc_state,
+                         const struct drm_property_blob *blob1,
+                         const struct drm_property_blob *blob2,
+                         bool is_pre_csc_lut)
+{
+       if (is_pre_csc_lut)
+               return intel_lut_equal(blob1, blob2, 0,
+                                      glk_pre_csc_lut_precision(crtc_state));
+       else
+               return intel_lut_equal(blob1, blob2, 0,
+                                      glk_post_csc_lut_precision(crtc_state));
+}
+
+static bool icl_lut_equal(const struct intel_crtc_state *crtc_state,
+                         const struct drm_property_blob *blob1,
+                         const struct drm_property_blob *blob2,
+                         bool is_pre_csc_lut)
+{
+       int check_size = 0;
+
+       if (is_pre_csc_lut)
+               return intel_lut_equal(blob1, blob2, 0,
+                                      icl_pre_csc_lut_precision(crtc_state));
+
+       /* hw readout broken except for the super fine segment :( */
+       if ((crtc_state->gamma_mode & GAMMA_MODE_MODE_MASK) ==
+           GAMMA_MODE_MODE_12BIT_MULTI_SEGMENTED)
+               check_size = 9;
+
+       return intel_lut_equal(blob1, blob2, check_size,
+                              icl_post_csc_lut_precision(crtc_state));
 }
 
 static struct drm_property_blob *i9xx_read_lut_8(struct intel_crtc *crtc)
        .color_commit_arm = i9xx_color_commit_arm,
        .load_luts = chv_load_luts,
        .read_luts = chv_read_luts,
+       .lut_equal = chv_lut_equal,
 };
 
 static const struct intel_color_funcs i965_color_funcs = {
        .color_commit_arm = i9xx_color_commit_arm,
        .load_luts = i965_load_luts,
        .read_luts = i965_read_luts,
+       .lut_equal = i9xx_lut_equal,
 };
 
 static const struct intel_color_funcs i9xx_color_funcs = {
        .color_commit_arm = i9xx_color_commit_arm,
        .load_luts = i9xx_load_luts,
        .read_luts = i9xx_read_luts,
+       .lut_equal = i9xx_lut_equal,
 };
 
 static const struct intel_color_funcs icl_color_funcs = {
        .color_commit_arm = skl_color_commit_arm,
        .load_luts = icl_load_luts,
        .read_luts = icl_read_luts,
+       .lut_equal = icl_lut_equal,
 };
 
 static const struct intel_color_funcs glk_color_funcs = {
        .color_commit_arm = skl_color_commit_arm,
        .load_luts = glk_load_luts,
        .read_luts = glk_read_luts,
+       .lut_equal = glk_lut_equal,
 };
 
 static const struct intel_color_funcs skl_color_funcs = {
        .color_commit_arm = skl_color_commit_arm,
        .load_luts = bdw_load_luts,
        .read_luts = bdw_read_luts,
+       .lut_equal = ivb_lut_equal,
 };
 
 static const struct intel_color_funcs bdw_color_funcs = {
        .color_commit_arm = hsw_color_commit_arm,
        .load_luts = bdw_load_luts,
        .read_luts = bdw_read_luts,
+       .lut_equal = ivb_lut_equal,
 };
 
 static const struct intel_color_funcs hsw_color_funcs = {
        .color_commit_arm = hsw_color_commit_arm,
        .load_luts = ivb_load_luts,
        .read_luts = ivb_read_luts,
+       .lut_equal = ivb_lut_equal,
 };
 
 static const struct intel_color_funcs ivb_color_funcs = {
        .color_commit_arm = ilk_color_commit_arm,
        .load_luts = ivb_load_luts,
        .read_luts = ivb_read_luts,
+       .lut_equal = ivb_lut_equal,
 };
 
 static const struct intel_color_funcs ilk_color_funcs = {
        .color_commit_arm = ilk_color_commit_arm,
        .load_luts = ilk_load_luts,
        .read_luts = ilk_read_luts,
+       .lut_equal = ilk_lut_equal,
 };
 
 void intel_color_crtc_init(struct intel_crtc *crtc)