diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c index bf31b9d92094..073929ebc5bd 100644 --- a/drivers/gpu/drm/drm_atomic_state_helper.c +++ b/drivers/gpu/drm/drm_atomic_state_helper.c @@ -141,6 +141,8 @@ void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc, drm_property_blob_get(state->degamma_lut); if (state->ctm) drm_property_blob_get(state->ctm); + if (state->ctm_post_offset) + drm_property_blob_get(state->ctm_post_offset); if (state->gamma_lut) drm_property_blob_get(state->gamma_lut); state->mode_changed = false; @@ -214,6 +216,7 @@ void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc_state *state) drm_property_blob_put(state->mode_blob); drm_property_blob_put(state->degamma_lut); drm_property_blob_put(state->ctm); + drm_property_blob_put(state->ctm_post_offset); drm_property_blob_put(state->gamma_lut); } EXPORT_SYMBOL(__drm_atomic_helper_crtc_destroy_state); diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c index 79730fa1dd8e..8aadf90c344f 100644 --- a/drivers/gpu/drm/drm_atomic_uapi.c +++ b/drivers/gpu/drm/drm_atomic_uapi.c @@ -430,6 +430,14 @@ static int drm_atomic_crtc_set_property(struct drm_crtc *crtc, &replaced); state->color_mgmt_changed |= replaced; return ret; + } else if (property == config->ctm_post_offset_property) { + ret = drm_atomic_replace_property_blob_from_id(dev, + &state->ctm_post_offset, + val, + sizeof(struct drm_color_ctm_post_offset), -1, + &replaced); + state->color_mgmt_changed |= replaced; + return ret; } else if (property == config->gamma_lut_property) { ret = drm_atomic_replace_property_blob_from_id(dev, &state->gamma_lut, @@ -481,6 +489,8 @@ drm_atomic_crtc_get_property(struct drm_crtc *crtc, *val = (state->degamma_lut) ? state->degamma_lut->base.id : 0; else if (property == config->ctm_property) *val = (state->ctm) ? state->ctm->base.id : 0; + else if (property == config->ctm_post_offset_property) + *val = (state->ctm) ? state->ctm_post_offset->base.id : 0; else if (property == config->gamma_lut_property) *val = (state->gamma_lut) ? state->gamma_lut->base.id : 0; else if (property == config->prop_out_fence_ptr) diff --git a/drivers/gpu/drm/drm_color_mgmt.c b/drivers/gpu/drm/drm_color_mgmt.c index d021497841b8..7d8481dfcfb3 100644 --- a/drivers/gpu/drm/drm_color_mgmt.c +++ b/drivers/gpu/drm/drm_color_mgmt.c @@ -177,9 +177,12 @@ void drm_crtc_enable_color_mgmt(struct drm_crtc *crtc, degamma_lut_size); } - if (has_ctm) + if (has_ctm) { drm_object_attach_property(&crtc->base, config->ctm_property, 0); + drm_object_attach_property(&crtc->base, + config->ctm_post_offset_property, 0); + } if (gamma_lut_size) { drm_object_attach_property(&crtc->base, @@ -330,6 +333,7 @@ static int drm_crtc_legacy_gamma_set(struct drm_crtc *crtc, replaced = drm_property_replace_blob(&crtc_state->degamma_lut, use_gamma_lut ? NULL : blob); replaced |= drm_property_replace_blob(&crtc_state->ctm, NULL); + replaced |= drm_property_replace_blob(&crtc_state->ctm_post_offset, NULL); replaced |= drm_property_replace_blob(&crtc_state->gamma_lut, use_gamma_lut ? blob : NULL); crtc_state->color_mgmt_changed |= replaced; diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_config.c index 141a5b4042b2..13077b7aadea 100644 --- a/drivers/gpu/drm/drm_mode_config.c +++ b/drivers/gpu/drm/drm_mode_config.c @@ -354,6 +354,13 @@ static int drm_mode_create_standard_properties(struct drm_device *dev) return -ENOMEM; dev->mode_config.ctm_property = prop; + prop = drm_property_create(dev, + DRM_MODE_PROP_BLOB, + "CTM_POST_OFFSET", 0); + if (!prop) + return -ENOMEM; + dev->mode_config.ctm_post_offset_property = prop; + prop = drm_property_create(dev, DRM_MODE_PROP_BLOB, "GAMMA_LUT", 0); diff --git a/drivers/gpu/drm/i915/display/intel_atomic.c b/drivers/gpu/drm/i915/display/intel_atomic.c index 18f0a5ae3bac..49f6552d889c 100644 --- a/drivers/gpu/drm/i915/display/intel_atomic.c +++ b/drivers/gpu/drm/i915/display/intel_atomic.c @@ -249,6 +249,8 @@ intel_crtc_duplicate_state(struct drm_crtc *crtc) drm_property_blob_get(crtc_state->hw.degamma_lut); if (crtc_state->hw.ctm) drm_property_blob_get(crtc_state->hw.ctm); + if (crtc_state->hw.ctm_post_offset) + drm_property_blob_get(crtc_state->hw.ctm_post_offset); if (crtc_state->hw.gamma_lut) drm_property_blob_get(crtc_state->hw.gamma_lut); @@ -274,6 +276,7 @@ static void intel_crtc_put_color_blobs(struct intel_crtc_state *crtc_state) drm_property_blob_put(crtc_state->hw.degamma_lut); drm_property_blob_put(crtc_state->hw.gamma_lut); drm_property_blob_put(crtc_state->hw.ctm); + drm_property_blob_put(crtc_state->hw.ctm_post_offset); } void intel_crtc_free_hw_state(struct intel_crtc_state *crtc_state) diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c index 6bda4274eae9..08d64a2074a0 100644 --- a/drivers/gpu/drm/i915/display/intel_color.c +++ b/drivers/gpu/drm/i915/display/intel_color.c @@ -151,6 +151,7 @@ static bool crtc_state_is_legacy_gamma(const struct intel_crtc_state *crtc_state { return !crtc_state->hw.degamma_lut && !crtc_state->hw.ctm && + !crtc_state->hw.ctm_post_offset && crtc_state->hw.gamma_lut && lut_is_legacy(crtc_state->hw.gamma_lut); } @@ -352,13 +353,33 @@ static void ilk_load_csc_matrix(const struct intel_crtc_state *crtc_state) static void icl_load_csc_matrix(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); if (crtc_state->hw.ctm) { u16 coeff[9]; ilk_csc_convert_ctm(crtc_state, coeff); - ilk_update_pipe_csc(crtc, ilk_csc_off_zero, + if (crtc_state->hw.ctm_post_offset) { + const struct drm_color_ctm_post_offset *ctm_post_offset = crtc_state->hw.ctm_post_offset->data; + /* Nop pre/post offsets */ + u16 csc_off[3] = {}; + csc_off[0] = ctm_post_offset->red; + csc_off[1] = ctm_post_offset->green; + csc_off[2] = ctm_post_offset->blue; + drm_dbg_kms(&dev_priv->drm, + "csc_off[0] = %d\n", csc_off[0]); + drm_dbg_kms(&dev_priv->drm, + "csc_off[1] = %d\n", csc_off[1]); + drm_dbg_kms(&dev_priv->drm, + "csc_off[2] = %d\n", csc_off[2]); + ilk_update_pipe_csc(crtc, ilk_csc_off_zero, + coeff, csc_off); + } else { + drm_dbg_kms(&dev_priv->drm, + "csc_off_zero\n"); + ilk_update_pipe_csc(crtc, ilk_csc_off_zero, coeff, ilk_csc_off_zero); + } } if (crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB) { diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 92f5b1b643a3..8bdbaa2e5b94 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -5065,6 +5065,8 @@ intel_crtc_copy_uapi_to_hw_state_nomodeset(struct intel_atomic_state *state, crtc_state->uapi.gamma_lut); drm_property_replace_blob(&crtc_state->hw.ctm, crtc_state->uapi.ctm); + drm_property_replace_blob(&crtc_state->hw.ctm_post_offset, + crtc_state->uapi.ctm_post_offset); } static void @@ -5103,6 +5105,8 @@ copy_bigjoiner_crtc_state_nomodeset(struct intel_atomic_state *state, master_crtc_state->hw.gamma_lut); drm_property_replace_blob(&slave_crtc_state->hw.ctm, master_crtc_state->hw.ctm); + drm_property_replace_blob(&slave_crtc_state->hw.ctm_post_offset, + master_crtc_state->hw.ctm_post_offset); slave_crtc_state->uapi.color_mgmt_changed = master_crtc_state->uapi.color_mgmt_changed; } diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 708e7c14c17c..85d83197fd0f 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1001,7 +1001,7 @@ struct intel_crtc_state { */ struct { bool active, enable; - struct drm_property_blob *degamma_lut, *gamma_lut, *ctm; + struct drm_property_blob *degamma_lut, *gamma_lut, *ctm, *ctm_post_offset; struct drm_display_mode mode, pipe_mode, adjusted_mode; enum drm_scaling_filter scaling_filter; } hw; diff --git a/drivers/gpu/drm/i915/display/intel_modeset_setup.c b/drivers/gpu/drm/i915/display/intel_modeset_setup.c index cbfabd58b75a..1e2b39113ac4 100644 --- a/drivers/gpu/drm/i915/display/intel_modeset_setup.c +++ b/drivers/gpu/drm/i915/display/intel_modeset_setup.c @@ -161,6 +161,9 @@ static void intel_crtc_copy_hw_to_uapi_state(struct intel_crtc_state *crtc_state crtc_state->hw.gamma_lut); drm_property_replace_blob(&crtc_state->uapi.ctm, crtc_state->hw.ctm); + drm_property_replace_blob(&crtc_state->uapi.ctm_post_offset, + crtc_state->hw.ctm_post_offset); + } static void diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 0a502964d9e6..a963bf5a0e7b 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -267,6 +267,14 @@ struct drm_crtc_state { */ struct drm_property_blob *ctm; + /** + * @ctm_post_offset: + * + * Color transformation matrix. See drm_crtc_enable_color_mgmt(). The + * blob (if not NULL) is a &struct drm_color_ctm. + */ + struct drm_property_blob *ctm_post_offset; + /** * @gamma_lut: * diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h index 6b5e01295348..8439ea279852 100644 --- a/include/drm/drm_mode_config.h +++ b/include/drm/drm_mode_config.h @@ -800,6 +800,12 @@ struct drm_mode_config { * degamma LUT. */ struct drm_property *ctm_property; + /** + * @ctm_post_offset_property: Optional CRTC property to set the + * matrix used to convert colors after the lookup in the + * degamma LUT. + */ + struct drm_property *ctm_post_offset_property; /** * @gamma_lut_property: Optional CRTC property to set the LUT used to * convert the colors, after the CTM matrix, to the gamma space of the diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h index 7c88c3d9ceb3..9b503a32221a 100644 --- a/include/uapi/drm/drm_mode.h +++ b/include/uapi/drm/drm_mode.h @@ -840,6 +840,13 @@ struct drm_color_ctm { __u64 matrix[9]; }; +struct drm_color_ctm_post_offset { + /* Data is U0.16 fixed point format. */ + __u16 red; + __u16 green; + __u16 blue; +}; + struct drm_color_lut { /* * Values are mapped linearly to 0.0 - 1.0 range, with 0x0 == 0.0 and