From 4cd8a64b15c1c61fbe164deacd7829899a7c5030 Mon Sep 17 00:00:00 2001 From: Chaitanya Kumar Borah Date: Wed, 3 Dec 2025 14:21:57 +0530 Subject: [PATCH 01/15] drm/i915/display: Add identifiers for driver specific blocks Add macros to identify intel specific color blocks. It will help in mapping drm_color_ops to intel color HW blocks v2:- Prefix enums with INTEL_* (Jani, Suraj) - Remove unnecessary comments (Jani) - Commit message improvements (Suraj) Reviewed-by: Suraj Kandpal Signed-off-by: Chaitanya Kumar Borah Signed-off-by: Uma Shankar Link: https://patch.msgid.link/20251203085211.3663374-2-uma.shankar@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_display_limits.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_display_limits.h b/drivers/gpu/drm/i915/display/intel_display_limits.h index f0fa27e365ab..55fd574ba313 100644 --- a/drivers/gpu/drm/i915/display/intel_display_limits.h +++ b/drivers/gpu/drm/i915/display/intel_display_limits.h @@ -138,4 +138,12 @@ enum hpd_pin { HPD_NUM_PINS }; +enum intel_color_block { + INTEL_PLANE_CB_PRE_CSC_LUT, + INTEL_PLANE_CB_CSC, + INTEL_PLANE_CB_POST_CSC_LUT, + + INTEL_CB_MAX +}; + #endif /* __INTEL_DISPLAY_LIMITS_H__ */ From 3e9b06559aa1c3daa21ff34a25b103f3fa7f0c7a Mon Sep 17 00:00:00 2001 From: Chaitanya Kumar Borah Date: Wed, 3 Dec 2025 14:21:58 +0530 Subject: [PATCH 02/15] drm/i915: Add intel_color_op Add data structure to store intel specific details of colorop v2: - Remove dead code - Convert macro to function (Jani) - Remove colorop state as it is not being used - Refactor to separate file Reviewed-by: Suraj Kandpal Signed-off-by: Chaitanya Kumar Borah Signed-off-by: Uma Shankar Link: https://patch.msgid.link/20251203085211.3663374-3-uma.shankar@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/display/intel_colorop.c | 10 ++++++++++ drivers/gpu/drm/i915/display/intel_colorop.h | 13 +++++++++++++ drivers/gpu/drm/i915/display/intel_display_types.h | 5 +++++ drivers/gpu/drm/xe/Makefile | 1 + 5 files changed, 30 insertions(+) create mode 100644 drivers/gpu/drm/i915/display/intel_colorop.c create mode 100644 drivers/gpu/drm/i915/display/intel_colorop.h diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 7c89e5e0a277..f1ca1413a0dc 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -239,6 +239,7 @@ i915-y += \ display/intel_cdclk.o \ display/intel_cmtg.o \ display/intel_color.o \ + display/intel_colorop.o \ display/intel_combo_phy.o \ display/intel_connector.o \ display/intel_crtc.o \ diff --git a/drivers/gpu/drm/i915/display/intel_colorop.c b/drivers/gpu/drm/i915/display/intel_colorop.c new file mode 100644 index 000000000000..eaab50d2d126 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_colorop.c @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2025 Intel Corporation + */ +#include "intel_colorop.h" + +struct intel_colorop *to_intel_colorop(struct drm_colorop *colorop) +{ + return container_of(colorop, struct intel_colorop, base); +} diff --git a/drivers/gpu/drm/i915/display/intel_colorop.h b/drivers/gpu/drm/i915/display/intel_colorop.h new file mode 100644 index 000000000000..23a29a565949 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_colorop.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2025 Intel Corporation + */ + +#ifndef __INTEL_COLOROP_H__ +#define __INTEL_COLOROP_H__ + +#include "intel_display_types.h" + +struct intel_colorop *to_intel_colorop(struct drm_colorop *colorop); + +#endif /* __INTEL_COLOROP_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 38702a9e0f50..bb8b8466235a 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1985,6 +1985,11 @@ struct intel_dp_mst_encoder { struct intel_connector *connector; }; +struct intel_colorop { + struct drm_colorop base; + enum intel_color_block id; +}; + static inline struct intel_encoder * intel_attached_encoder(struct intel_connector *connector) { diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile index e4b273b025d2..e468407c9457 100644 --- a/drivers/gpu/drm/xe/Makefile +++ b/drivers/gpu/drm/xe/Makefile @@ -242,6 +242,7 @@ xe-$(CONFIG_DRM_XE_DISPLAY) += \ i915-display/intel_cdclk.o \ i915-display/intel_cmtg.o \ i915-display/intel_color.o \ + i915-display/intel_colorop.o \ i915-display/intel_combo_phy.o \ i915-display/intel_connector.o \ i915-display/intel_crtc.o \ From 730df5065ee9d64f972159995832ab1a5626bd4e Mon Sep 17 00:00:00 2001 From: Chaitanya Kumar Borah Date: Wed, 3 Dec 2025 14:21:59 +0530 Subject: [PATCH 03/15] drm/i915/color: Add helper to create intel colorop Add intel colorop create helper v2: - Make function names consistent (Jani) - Remove redundant code related to colorop state - Refactor code to separate files Reviewed-by: Suraj Kandpal Signed-off-by: Chaitanya Kumar Borah Signed-off-by: Uma Shankar Link: https://patch.msgid.link/20251203085211.3663374-4-uma.shankar@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_colorop.c | 25 ++++++++++++++++++++ drivers/gpu/drm/i915/display/intel_colorop.h | 2 ++ 2 files changed, 27 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_colorop.c b/drivers/gpu/drm/i915/display/intel_colorop.c index eaab50d2d126..f2fc0d8780ce 100644 --- a/drivers/gpu/drm/i915/display/intel_colorop.c +++ b/drivers/gpu/drm/i915/display/intel_colorop.c @@ -8,3 +8,28 @@ struct intel_colorop *to_intel_colorop(struct drm_colorop *colorop) { return container_of(colorop, struct intel_colorop, base); } + +struct intel_colorop *intel_colorop_alloc(void) +{ + struct intel_colorop *colorop; + + colorop = kzalloc(sizeof(*colorop), GFP_KERNEL); + if (!colorop) + return ERR_PTR(-ENOMEM); + + return colorop; +} + +struct intel_colorop *intel_colorop_create(enum intel_color_block id) +{ + struct intel_colorop *colorop; + + colorop = intel_colorop_alloc(); + + if (IS_ERR(colorop)) + return colorop; + + colorop->id = id; + + return colorop; +} diff --git a/drivers/gpu/drm/i915/display/intel_colorop.h b/drivers/gpu/drm/i915/display/intel_colorop.h index 23a29a565949..21d58eb9f3d0 100644 --- a/drivers/gpu/drm/i915/display/intel_colorop.h +++ b/drivers/gpu/drm/i915/display/intel_colorop.h @@ -9,5 +9,7 @@ #include "intel_display_types.h" struct intel_colorop *to_intel_colorop(struct drm_colorop *colorop); +struct intel_colorop *intel_colorop_alloc(void); +struct intel_colorop *intel_colorop_create(enum intel_color_block id); #endif /* __INTEL_COLOROP_H__ */ From ef105316819d448630b83044fa83ba12905d9086 Mon Sep 17 00:00:00 2001 From: Chaitanya Kumar Borah Date: Wed, 3 Dec 2025 14:22:00 +0530 Subject: [PATCH 04/15] drm/i915/color: Create a transfer function color pipeline Add a color pipeline with three colorops in the sequence 1D LUT - 3x4 CTM - 1D LUT This pipeline can be used to do any color space conversion or HDR tone mapping v2: Change namespace to drm_plane_colorop* v3: Use simpler/pre-existing colorops for first iteration v4: - s/*_tf_*/*_color_* (Jani) - Refactor to separate files (Jani) - Add missing space in comment (Suraj) - Consolidate patch that adds/attaches pipeline property v5: - Limit MAX_COLOR_PIPELINES to 2.(Suraj) Increase it as and when we add more pipelines. - Remove redundant initialization code (Suraj) v6: - Use drm_plane_create_color_pipeline_property() (Arun) Now MAX_COLOR_PIPELINES is 1 Reviewed-by: Suraj Kandpal Signed-off-by: Uma Shankar Signed-off-by: Chaitanya Kumar Borah Link: https://patch.msgid.link/20251203085211.3663374-5-uma.shankar@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/Makefile | 1 + .../drm/i915/display/intel_color_pipeline.c | 80 +++++++++++++++++++ .../drm/i915/display/intel_color_pipeline.h | 13 +++ drivers/gpu/drm/xe/Makefile | 1 + 4 files changed, 95 insertions(+) create mode 100644 drivers/gpu/drm/i915/display/intel_color_pipeline.c create mode 100644 drivers/gpu/drm/i915/display/intel_color_pipeline.h diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index f1ca1413a0dc..4db24050edb0 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -240,6 +240,7 @@ i915-y += \ display/intel_cmtg.o \ display/intel_color.o \ display/intel_colorop.o \ + display/intel_color_pipeline.o \ display/intel_combo_phy.o \ display/intel_connector.o \ display/intel_crtc.o \ diff --git a/drivers/gpu/drm/i915/display/intel_color_pipeline.c b/drivers/gpu/drm/i915/display/intel_color_pipeline.c new file mode 100644 index 000000000000..489d470cd011 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_color_pipeline.c @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2025 Intel Corporation + */ +#include "intel_colorop.h" +#include "intel_color_pipeline.h" +#include "intel_de.h" +#include "intel_display_types.h" +#include "skl_universal_plane.h" + +#define MAX_COLOR_PIPELINES 1 +#define PLANE_DEGAMMA_SIZE 128 +#define PLANE_GAMMA_SIZE 32 + +static +int _intel_color_pipeline_plane_init(struct drm_plane *plane, struct drm_prop_enum_list *list) +{ + struct intel_colorop *colorop; + struct drm_device *dev = plane->dev; + int ret; + struct drm_colorop *prev_op; + + colorop = intel_colorop_create(INTEL_PLANE_CB_PRE_CSC_LUT); + + ret = drm_plane_colorop_curve_1d_lut_init(dev, &colorop->base, plane, + PLANE_DEGAMMA_SIZE, + DRM_COLOROP_LUT1D_INTERPOLATION_LINEAR, + DRM_COLOROP_FLAG_ALLOW_BYPASS); + + if (ret) + return ret; + + list->type = colorop->base.base.id; + list->name = kasprintf(GFP_KERNEL, "Color Pipeline %d", colorop->base.base.id); + + /* TODO: handle failures and clean up */ + prev_op = &colorop->base; + + colorop = intel_colorop_create(INTEL_PLANE_CB_CSC); + ret = drm_plane_colorop_ctm_3x4_init(dev, &colorop->base, plane, + DRM_COLOROP_FLAG_ALLOW_BYPASS); + if (ret) + return ret; + + drm_colorop_set_next_property(prev_op, &colorop->base); + prev_op = &colorop->base; + + colorop = intel_colorop_create(INTEL_PLANE_CB_POST_CSC_LUT); + ret = drm_plane_colorop_curve_1d_lut_init(dev, &colorop->base, plane, + PLANE_GAMMA_SIZE, + DRM_COLOROP_LUT1D_INTERPOLATION_LINEAR, + DRM_COLOROP_FLAG_ALLOW_BYPASS); + if (ret) + return ret; + + drm_colorop_set_next_property(prev_op, &colorop->base); + + return 0; +} + +int intel_color_pipeline_plane_init(struct drm_plane *plane) +{ + struct drm_device *dev = plane->dev; + struct intel_display *display = to_intel_display(dev); + struct drm_prop_enum_list pipelines[MAX_COLOR_PIPELINES]; + int len = 0; + int ret; + + /* Currently expose pipeline only for HDR planes */ + if (!icl_is_hdr_plane(display, to_intel_plane(plane)->id)) + return 0; + + /* Add pipeline consisting of transfer functions */ + ret = _intel_color_pipeline_plane_init(plane, &pipelines[len]); + if (ret) + return ret; + len++; + + return drm_plane_create_color_pipeline_property(plane, pipelines, len); +} diff --git a/drivers/gpu/drm/i915/display/intel_color_pipeline.h b/drivers/gpu/drm/i915/display/intel_color_pipeline.h new file mode 100644 index 000000000000..7f1d32bc9202 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_color_pipeline.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2025 Intel Corporation + */ + +#ifndef __INTEL_COLOR_PIPELINE_H__ +#define __INTEL_COLOR_PIPELINE_H__ + +struct drm_plane; + +int intel_color_pipeline_plane_init(struct drm_plane *plane); + +#endif /* __INTEL_COLOR_PIPELINE_H__ */ diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile index e468407c9457..aa666f4c0324 100644 --- a/drivers/gpu/drm/xe/Makefile +++ b/drivers/gpu/drm/xe/Makefile @@ -243,6 +243,7 @@ xe-$(CONFIG_DRM_XE_DISPLAY) += \ i915-display/intel_cmtg.o \ i915-display/intel_color.o \ i915-display/intel_colorop.o \ + i915-display/intel_color_pipeline.o \ i915-display/intel_combo_phy.o \ i915-display/intel_connector.o \ i915-display/intel_crtc.o \ From a78f1b6baf4dc240b67155209c81ef0503accf3b Mon Sep 17 00:00:00 2001 From: Chaitanya Kumar Borah Date: Wed, 3 Dec 2025 14:22:01 +0530 Subject: [PATCH 05/15] drm/i915/color: Add framework to program CSC Add framework to program CSC. It enables copying of matrix from UAPI to intel plane state. Also add helper functions which will eventually program values to hardware. Add a crtc state variable to track plane color change. v2: - Add crtc_state->plane_color_changed - Improve comments (Suraj) - s/intel_plane_*_color/intel_plane_color_* (Suraj) v3: - align parameters with open braces (Suraj) - Improve commit message (Suraj) v4: - Re-arrange variable declaration (Suraj) Reviewed-by: Suraj Kandpal Signed-off-by: Chaitanya Kumar Borah Signed-off-by: Uma Shankar Link: https://patch.msgid.link/20251203085211.3663374-6-uma.shankar@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_color.c | 21 ++++++++ drivers/gpu/drm/i915/display/intel_color.h | 4 +- .../drm/i915/display/intel_display_types.h | 4 ++ drivers/gpu/drm/i915/display/intel_plane.c | 49 +++++++++++++++++++ 4 files changed, 77 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c index a217a67ceb43..33fe5c9b4663 100644 --- a/drivers/gpu/drm/i915/display/intel_color.c +++ b/drivers/gpu/drm/i915/display/intel_color.c @@ -87,6 +87,10 @@ struct intel_color_funcs { * Read config other than LUTs and CSCs, before them. Optional. */ void (*get_config)(struct intel_crtc_state *crtc_state); + + /* Plane CSC*/ + void (*load_plane_csc_matrix)(struct intel_dsb *dsb, + const struct intel_plane_state *plane_state); }; #define CTM_COEFF_SIGN (1ULL << 63) @@ -3963,6 +3967,23 @@ static const struct intel_color_funcs ilk_color_funcs = { .get_config = ilk_get_config, }; +static void +intel_color_load_plane_csc_matrix(struct intel_dsb *dsb, + const struct intel_plane_state *plane_state) +{ + struct intel_display *display = to_intel_display(plane_state); + + if (display->funcs.color->load_plane_csc_matrix) + display->funcs.color->load_plane_csc_matrix(dsb, plane_state); +} + +void intel_color_plane_program_pipeline(struct intel_dsb *dsb, + const struct intel_plane_state *plane_state) +{ + if (plane_state->hw.ctm) + intel_color_load_plane_csc_matrix(dsb, plane_state); +} + void intel_color_crtc_init(struct intel_crtc *crtc) { struct intel_display *display = to_intel_display(crtc); diff --git a/drivers/gpu/drm/i915/display/intel_color.h b/drivers/gpu/drm/i915/display/intel_color.h index bf7a12ce9df0..8051c827a1d8 100644 --- a/drivers/gpu/drm/i915/display/intel_color.h +++ b/drivers/gpu/drm/i915/display/intel_color.h @@ -13,6 +13,7 @@ struct intel_crtc_state; struct intel_crtc; struct intel_display; struct intel_dsb; +struct intel_plane_state; struct drm_property_blob; void intel_color_init_hooks(struct intel_display *display); @@ -40,5 +41,6 @@ bool intel_color_lut_equal(const struct intel_crtc_state *crtc_state, const struct drm_property_blob *blob2, bool is_pre_csc_lut); void intel_color_assert_luts(const struct intel_crtc_state *crtc_state); - +void intel_color_plane_program_pipeline(struct intel_dsb *dsb, + const struct intel_plane_state *plane_state); #endif /* __INTEL_COLOR_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index bb8b8466235a..6d8217497583 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -646,6 +646,7 @@ struct intel_plane_state { enum drm_color_encoding color_encoding; enum drm_color_range color_range; enum drm_scaling_filter scaling_filter; + struct drm_property_blob *ctm; } hw; struct i915_vma *ggtt_vma; @@ -1391,6 +1392,9 @@ struct intel_crtc_state { u8 silence_period_sym_clocks; u8 lfps_half_cycle_num_of_syms; } alpm_state; + + /* to track changes in plane color blocks */ + bool plane_color_changed; }; enum intel_pipe_crc_source { diff --git a/drivers/gpu/drm/i915/display/intel_plane.c b/drivers/gpu/drm/i915/display/intel_plane.c index 5105e3278bc4..ad25af7394a6 100644 --- a/drivers/gpu/drm/i915/display/intel_plane.c +++ b/drivers/gpu/drm/i915/display/intel_plane.c @@ -49,6 +49,7 @@ #include "i9xx_plane_regs.h" #include "intel_cdclk.h" #include "intel_cursor.h" +#include "intel_colorop.h" #include "intel_display_rps.h" #include "intel_display_trace.h" #include "intel_display_types.h" @@ -336,6 +337,52 @@ intel_plane_copy_uapi_plane_damage(struct intel_plane_state *new_plane_state, *damage = drm_plane_state_src(&new_uapi_plane_state->uapi); } +static bool +intel_plane_colorop_replace_blob(struct intel_plane_state *plane_state, + struct intel_colorop *intel_colorop, + struct drm_property_blob *blob) +{ + if (intel_colorop->id == INTEL_PLANE_CB_CSC) + return drm_property_replace_blob(&plane_state->hw.ctm, blob); + + return false; +} + +static void +intel_plane_color_copy_uapi_to_hw_state(struct intel_plane_state *plane_state, + const struct intel_plane_state *from_plane_state, + struct intel_crtc *crtc) +{ + struct drm_colorop *iter_colorop, *colorop; + struct drm_colorop_state *new_colorop_state; + struct drm_atomic_state *state = plane_state->uapi.state; + struct intel_colorop *intel_colorop; + struct drm_property_blob *blob; + struct intel_atomic_state *intel_atomic_state = to_intel_atomic_state(state); + struct intel_crtc_state *new_crtc_state = intel_atomic_state ? + intel_atomic_get_new_crtc_state(intel_atomic_state, crtc) : NULL; + bool changed = false; + int i = 0; + + iter_colorop = plane_state->uapi.color_pipeline; + + while (iter_colorop) { + for_each_new_colorop_in_state(state, colorop, new_colorop_state, i) { + if (new_colorop_state->colorop == iter_colorop) { + blob = new_colorop_state->bypass ? NULL : new_colorop_state->data; + intel_colorop = to_intel_colorop(colorop); + changed |= intel_plane_colorop_replace_blob(plane_state, + intel_colorop, + blob); + } + } + iter_colorop = iter_colorop->next; + } + + if (new_crtc_state && changed) + new_crtc_state->plane_color_changed = true; +} + void intel_plane_copy_uapi_to_hw_state(struct intel_plane_state *plane_state, const struct intel_plane_state *from_plane_state, struct intel_crtc *crtc) @@ -364,6 +411,8 @@ void intel_plane_copy_uapi_to_hw_state(struct intel_plane_state *plane_state, plane_state->uapi.src = drm_plane_state_src(&from_plane_state->uapi); plane_state->uapi.dst = drm_plane_state_dest(&from_plane_state->uapi); + + intel_plane_color_copy_uapi_to_hw_state(plane_state, from_plane_state, crtc); } void intel_plane_copy_hw_state(struct intel_plane_state *plane_state, From 6f1e094fb6e98b99bda21133fea55970d82c2045 Mon Sep 17 00:00:00 2001 From: Chaitanya Kumar Borah Date: Wed, 3 Dec 2025 14:22:02 +0530 Subject: [PATCH 06/15] drm/i915/color: Preserve sign bit when int_bits is Zero When int_bits == 0, we lose the sign bit when we do the range check and apply the mask. Fix this by ensuring a minimum of one integer bit, which guarantees space for the sign bit in fully fractional representations (e.g. S0.12) Reviewed-by: Suraj Kandpal Signed-off-by: Chaitanya Kumar Borah Signed-off-by: Uma Shankar Link: https://patch.msgid.link/20251203085211.3663374-7-uma.shankar@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_color.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c index 33fe5c9b4663..81b87fed8878 100644 --- a/drivers/gpu/drm/i915/display/intel_color.c +++ b/drivers/gpu/drm/i915/display/intel_color.c @@ -613,6 +613,8 @@ static u16 ctm_to_twos_complement(u64 coeff, int int_bits, int frac_bits) if (CTM_COEFF_NEGATIVE(coeff)) c = -c; + int_bits = max(int_bits, 1); + c = clamp(c, -(s64)BIT(int_bits + frac_bits - 1), (s64)(BIT(int_bits + frac_bits - 1) - 1)); From f00d02707dc2265c120756f074f27fd3c158ec9c Mon Sep 17 00:00:00 2001 From: Uma Shankar Date: Wed, 3 Dec 2025 14:22:03 +0530 Subject: [PATCH 07/15] drm/i915/color: Add plane CTM callback for D12 and beyond Add callback for setting CTM block in platforms D12 and beyond v2: - Add dsb support - Pass plane_state as we are now doing a uapi to hw state copy - Add support for 3x4 matrix v3: - Add relevant header file - Fix typo (Suraj) - Add callback to TGL+ (Suraj) Reviewed-by: Suraj Kandpal Signed-off-by: Chaitanya Kumar Borah Signed-off-by: Uma Shankar Link: https://patch.msgid.link/20251203085211.3663374-8-uma.shankar@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_color.c | 98 ++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c index 81b87fed8878..2f8e985d51e5 100644 --- a/drivers/gpu/drm/i915/display/intel_color.c +++ b/drivers/gpu/drm/i915/display/intel_color.c @@ -32,6 +32,8 @@ #include "intel_display_utils.h" #include "intel_dsb.h" #include "intel_vrr.h" +#include "skl_universal_plane.h" +#include "skl_universal_plane_regs.h" struct intel_color_funcs { int (*color_check)(struct intel_atomic_state *state, @@ -3842,6 +3844,101 @@ static void icl_read_luts(struct intel_crtc_state *crtc_state) } } +static void +xelpd_load_plane_csc_matrix(struct intel_dsb *dsb, + const struct intel_plane_state *plane_state) +{ + struct intel_display *display = to_intel_display(plane_state); + const struct drm_plane_state *state = &plane_state->uapi; + enum pipe pipe = to_intel_plane(state->plane)->pipe; + enum plane_id plane = to_intel_plane(state->plane)->id; + const struct drm_property_blob *blob = plane_state->hw.ctm; + struct drm_color_ctm_3x4 *ctm; + const u64 *input; + u16 coeffs[9] = {}; + int i, j; + + if (!icl_is_hdr_plane(display, plane) || !blob) + return; + + ctm = blob->data; + input = ctm->matrix; + + /* + * Convert fixed point S31.32 input to format supported by the + * hardware. + */ + for (i = 0, j = 0; i < ARRAY_SIZE(coeffs); i++) { + u64 abs_coeff = ((1ULL << 63) - 1) & input[j]; + + /* + * Clamp input value to min/max supported by + * hardware. + */ + abs_coeff = clamp_val(abs_coeff, 0, CTM_COEFF_4_0 - 1); + + /* sign bit */ + if (CTM_COEFF_NEGATIVE(input[j])) + coeffs[i] |= 1 << 15; + + if (abs_coeff < CTM_COEFF_0_125) + coeffs[i] |= (3 << 12) | + ILK_CSC_COEFF_FP(abs_coeff, 12); + else if (abs_coeff < CTM_COEFF_0_25) + coeffs[i] |= (2 << 12) | + ILK_CSC_COEFF_FP(abs_coeff, 11); + else if (abs_coeff < CTM_COEFF_0_5) + coeffs[i] |= (1 << 12) | + ILK_CSC_COEFF_FP(abs_coeff, 10); + else if (abs_coeff < CTM_COEFF_1_0) + coeffs[i] |= ILK_CSC_COEFF_FP(abs_coeff, 9); + else if (abs_coeff < CTM_COEFF_2_0) + coeffs[i] |= (7 << 12) | + ILK_CSC_COEFF_FP(abs_coeff, 8); + else + coeffs[i] |= (6 << 12) | + ILK_CSC_COEFF_FP(abs_coeff, 7); + + /* Skip postoffs */ + if (!((j + 2) % 4)) + j += 2; + else + j++; + } + + intel_de_write_dsb(display, dsb, PLANE_CSC_COEFF(pipe, plane, 0), + coeffs[0] << 16 | coeffs[1]); + intel_de_write_dsb(display, dsb, PLANE_CSC_COEFF(pipe, plane, 1), + coeffs[2] << 16); + + intel_de_write_dsb(display, dsb, PLANE_CSC_COEFF(pipe, plane, 2), + coeffs[3] << 16 | coeffs[4]); + intel_de_write_dsb(display, dsb, PLANE_CSC_COEFF(pipe, plane, 3), + coeffs[5] << 16); + + intel_de_write_dsb(display, dsb, PLANE_CSC_COEFF(pipe, plane, 4), + coeffs[6] << 16 | coeffs[7]); + intel_de_write_dsb(display, dsb, PLANE_CSC_COEFF(pipe, plane, 5), + coeffs[8] << 16); + + intel_de_write_dsb(display, dsb, PLANE_CSC_PREOFF(pipe, plane, 0), 0); + intel_de_write_dsb(display, dsb, PLANE_CSC_PREOFF(pipe, plane, 1), 0); + intel_de_write_dsb(display, dsb, PLANE_CSC_PREOFF(pipe, plane, 2), 0); + + /* + * Conversion from S31.32 to S0.12. BIT[12] is the signed bit + */ + intel_de_write_dsb(display, dsb, + PLANE_CSC_POSTOFF(pipe, plane, 0), + ctm_to_twos_complement(input[3], 0, 12)); + intel_de_write_dsb(display, dsb, + PLANE_CSC_POSTOFF(pipe, plane, 1), + ctm_to_twos_complement(input[7], 0, 12)); + intel_de_write_dsb(display, dsb, + PLANE_CSC_POSTOFF(pipe, plane, 2), + ctm_to_twos_complement(input[11], 0, 12)); +} + static const struct intel_color_funcs chv_color_funcs = { .color_check = chv_color_check, .color_commit_arm = i9xx_color_commit_arm, @@ -3889,6 +3986,7 @@ static const struct intel_color_funcs tgl_color_funcs = { .lut_equal = icl_lut_equal, .read_csc = icl_read_csc, .get_config = skl_get_config, + .load_plane_csc_matrix = xelpd_load_plane_csc_matrix, }; static const struct intel_color_funcs icl_color_funcs = { From ed0ebbc89f847eebce790a6a308c8c3c1251655a Mon Sep 17 00:00:00 2001 From: Uma Shankar Date: Wed, 3 Dec 2025 14:22:04 +0530 Subject: [PATCH 08/15] drm/i915: Add register definitions for Plane Degamma Add macros to define Plane Degamma registers v2: - Add BSpec links (Suraj) v3: - Add Bspec links in trailer (Suraj) - Fix checkpatch issues (Suraj) BSpec: 50411, 50412, 50413, 50414 Reviewed-by: Suraj Kandpal Signed-off-by: Uma Shankar Signed-off-by: Chaitanya Kumar Borah Link: https://patch.msgid.link/20251203085211.3663374-9-uma.shankar@intel.com Signed-off-by: Jani Nikula --- .../i915/display/skl_universal_plane_regs.h | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane_regs.h b/drivers/gpu/drm/i915/display/skl_universal_plane_regs.h index 6f815b231340..1e5d7ef37f1c 100644 --- a/drivers/gpu/drm/i915/display/skl_universal_plane_regs.h +++ b/drivers/gpu/drm/i915/display/skl_universal_plane_regs.h @@ -254,6 +254,7 @@ #define PLANE_COLOR_PIPE_CSC_ENABLE REG_BIT(23) /* Pre-ICL */ #define PLANE_COLOR_PLANE_CSC_ENABLE REG_BIT(21) /* ICL+ */ #define PLANE_COLOR_INPUT_CSC_ENABLE REG_BIT(20) /* ICL+ */ +#define PLANE_COLOR_PRE_CSC_GAMMA_ENABLE REG_BIT(14) #define PLANE_COLOR_CSC_MODE_MASK REG_GENMASK(19, 17) #define PLANE_COLOR_CSC_MODE_BYPASS REG_FIELD_PREP(PLANE_COLOR_CSC_MODE_MASK, 0) #define PLANE_COLOR_CSC_MODE_YUV601_TO_RGB601 REG_FIELD_PREP(PLANE_COLOR_CSC_MODE_MASK, 1) @@ -290,6 +291,53 @@ _PLANE_INPUT_CSC_POSTOFF_HI_1_A, _PLANE_INPUT_CSC_POSTOFF_HI_1_B, \ _PLANE_INPUT_CSC_POSTOFF_HI_2_A, _PLANE_INPUT_CSC_POSTOFF_HI_2_B) +#define _MMIO_PLANE_GAMC(plane, i, a, b) _MMIO(_PIPE(plane, a, b) + (i) * 4) + +#define _PLANE_PRE_CSC_GAMC_INDEX_ENH_1_A 0x701d0 +#define _PLANE_PRE_CSC_GAMC_INDEX_ENH_1_B 0x711d0 +#define _PLANE_PRE_CSC_GAMC_INDEX_ENH_2_A 0x702d0 +#define _PLANE_PRE_CSC_GAMC_INDEX_ENH_2_B 0x712d0 +#define _PLANE_PRE_CSC_GAMC_INDEX_ENH_1(pipe) _PIPE(pipe, _PLANE_PRE_CSC_GAMC_INDEX_ENH_1_A, \ + _PLANE_PRE_CSC_GAMC_INDEX_ENH_1_B) +#define _PLANE_PRE_CSC_GAMC_INDEX_ENH_2(pipe) _PIPE(pipe, _PLANE_PRE_CSC_GAMC_INDEX_ENH_2_A, \ + _PLANE_PRE_CSC_GAMC_INDEX_ENH_2_B) +#define PLANE_PRE_CSC_GAMC_INDEX_ENH(pipe, plane, i) _MMIO_PLANE_GAMC(plane, i, _PLANE_PRE_CSC_GAMC_INDEX_ENH_1(pipe), \ + _PLANE_PRE_CSC_GAMC_INDEX_ENH_2(pipe)) +#define PLANE_PAL_PREC_AUTO_INCREMENT REG_BIT(10) + +#define _PLANE_PRE_CSC_GAMC_DATA_ENH_1_A 0x701d4 +#define _PLANE_PRE_CSC_GAMC_DATA_ENH_1_B 0x711d4 +#define _PLANE_PRE_CSC_GAMC_DATA_ENH_2_A 0x702d4 +#define _PLANE_PRE_CSC_GAMC_DATA_ENH_2_B 0x712d4 +#define _PLANE_PRE_CSC_GAMC_DATA_ENH_1(pipe) _PIPE(pipe, _PLANE_PRE_CSC_GAMC_DATA_ENH_1_A, \ + _PLANE_PRE_CSC_GAMC_DATA_ENH_1_B) +#define _PLANE_PRE_CSC_GAMC_DATA_ENH_2(pipe) _PIPE(pipe, _PLANE_PRE_CSC_GAMC_DATA_ENH_2_A, \ + _PLANE_PRE_CSC_GAMC_DATA_ENH_2_B) +#define PLANE_PRE_CSC_GAMC_DATA_ENH(pipe, plane, i) _MMIO_PLANE_GAMC(plane, i, _PLANE_PRE_CSC_GAMC_DATA_ENH_1(pipe), \ + _PLANE_PRE_CSC_GAMC_DATA_ENH_2(pipe)) + +#define _PLANE_PRE_CSC_GAMC_INDEX_1_A 0x704d0 +#define _PLANE_PRE_CSC_GAMC_INDEX_1_B 0x714d0 +#define _PLANE_PRE_CSC_GAMC_INDEX_2_A 0x705d0 +#define _PLANE_PRE_CSC_GAMC_INDEX_2_B 0x715d0 +#define _PLANE_PRE_CSC_GAMC_INDEX_1(pipe) _PIPE(pipe, _PLANE_PRE_CSC_GAMC_INDEX_1_A, \ + _PLANE_PRE_CSC_GAMC_INDEX_1_B) +#define _PLANE_PRE_CSC_GAMC_INDEX_2(pipe) _PIPE(pipe, _PLANE_PRE_CSC_GAMC_INDEX_2_A, \ + _PLANE_PRE_CSC_GAMC_INDEX_2_B) +#define PLANE_PRE_CSC_GAMC_INDEX(pipe, plane, i) _MMIO_PLANE_GAMC(plane, i, _PLANE_PRE_CSC_GAMC_INDEX_1(pipe), \ + _PLANE_PRE_CSC_GAMC_INDEX_2(pipe)) + +#define _PLANE_PRE_CSC_GAMC_DATA_1_A 0x704d4 +#define _PLANE_PRE_CSC_GAMC_DATA_1_B 0x714d4 +#define _PLANE_PRE_CSC_GAMC_DATA_2_A 0x705d4 +#define _PLANE_PRE_CSC_GAMC_DATA_2_B 0x715d4 +#define _PLANE_PRE_CSC_GAMC_DATA_1(pipe) _PIPE(pipe, _PLANE_PRE_CSC_GAMC_DATA_1_A, \ + _PLANE_PRE_CSC_GAMC_DATA_1_B) +#define _PLANE_PRE_CSC_GAMC_DATA_2(pipe) _PIPE(pipe, _PLANE_PRE_CSC_GAMC_DATA_2_A, \ + _PLANE_PRE_CSC_GAMC_DATA_2_B) +#define PLANE_PRE_CSC_GAMC_DATA(pipe, plane, i) _MMIO_PLANE_GAMC(plane, i, _PLANE_PRE_CSC_GAMC_DATA_1(pipe), \ + _PLANE_PRE_CSC_GAMC_DATA_2(pipe)) + #define _PLANE_CSC_RY_GY_1_A 0x70210 #define _PLANE_CSC_RY_GY_2_A 0x70310 #define _PLANE_CSC_RY_GY_1_B 0x71210 From 05df71544c44a1767be021285648c090123a92ff Mon Sep 17 00:00:00 2001 From: Uma Shankar Date: Wed, 3 Dec 2025 14:22:05 +0530 Subject: [PATCH 09/15] drm/i915: Add register definitions for Plane Post CSC Add macros to define Plane Post CSC registers v2: - Add Plane Post CSC Gamma Multi Segment Enable bit - Add BSpec entries (Suraj) v3: - Fix checkpatch issues (Suraj) BSpec: 50403, 50404, 50405, 50406, 50409, 50410, Reviewed-by: Suraj Kandpal Signed-off-by: Uma Shankar Signed-off-by: Chaitanya Kumar Borah Link: https://patch.msgid.link/20251203085211.3663374-10-uma.shankar@intel.com Signed-off-by: Jani Nikula --- .../i915/display/skl_universal_plane_regs.h | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane_regs.h b/drivers/gpu/drm/i915/display/skl_universal_plane_regs.h index 1e5d7ef37f1c..6fd4da9f63cf 100644 --- a/drivers/gpu/drm/i915/display/skl_universal_plane_regs.h +++ b/drivers/gpu/drm/i915/display/skl_universal_plane_regs.h @@ -254,6 +254,7 @@ #define PLANE_COLOR_PIPE_CSC_ENABLE REG_BIT(23) /* Pre-ICL */ #define PLANE_COLOR_PLANE_CSC_ENABLE REG_BIT(21) /* ICL+ */ #define PLANE_COLOR_INPUT_CSC_ENABLE REG_BIT(20) /* ICL+ */ +#define PLANE_COLOR_POST_CSC_GAMMA_MULTSEG_ENABLE REG_BIT(15) /* TGL+ */ #define PLANE_COLOR_PRE_CSC_GAMMA_ENABLE REG_BIT(14) #define PLANE_COLOR_CSC_MODE_MASK REG_GENMASK(19, 17) #define PLANE_COLOR_CSC_MODE_BYPASS REG_FIELD_PREP(PLANE_COLOR_CSC_MODE_MASK, 0) @@ -293,6 +294,72 @@ #define _MMIO_PLANE_GAMC(plane, i, a, b) _MMIO(_PIPE(plane, a, b) + (i) * 4) +#define _PLANE_POST_CSC_GAMC_SEG0_INDEX_ENH_1_A 0x70160 +#define _PLANE_POST_CSC_GAMC_SEG0_INDEX_ENH_1_B 0x71160 +#define _PLANE_POST_CSC_GAMC_SEG0_INDEX_ENH_2_A 0x70260 +#define _PLANE_POST_CSC_GAMC_SEG0_INDEX_ENH_2_B 0x71260 +#define _PLANE_POST_CSC_GAMC_SEG0_INDEX_ENH_1(pipe) _PIPE(pipe, _PLANE_POST_CSC_GAMC_SEG0_INDEX_ENH_1_A, \ + _PLANE_POST_CSC_GAMC_SEG0_INDEX_ENH_1_B) +#define _PLANE_POST_CSC_GAMC_SEG0_INDEX_ENH_2(pipe) _PIPE(pipe, _PLANE_POST_CSC_GAMC_SEG0_INDEX_ENH_2_A, \ + _PLANE_POST_CSC_GAMC_SEG0_INDEX_ENH_2_B) +#define PLANE_POST_CSC_GAMC_SEG0_INDEX_ENH(pipe, plane, i) _MMIO_PLANE_GAMC(plane, i, _PLANE_POST_CSC_GAMC_SEG0_INDEX_ENH_1(pipe), \ + _PLANE_POST_CSC_GAMC_SEG0_INDEX_ENH_2(pipe)) + +#define _PLANE_POST_CSC_GAMC_SEG0_DATA_ENH_1_A 0x70164 +#define _PLANE_POST_CSC_GAMC_SEG0_DATA_ENH_1_B 0x71164 +#define _PLANE_POST_CSC_GAMC_SEG0_DATA_ENH_2_A 0x70264 +#define _PLANE_POST_CSC_GAMC_SEG0_DATA_ENH_2_B 0x71264 +#define _PLANE_POST_CSC_GAMC_SEG0_DATA_ENH_1(pipe) _PIPE(pipe, _PLANE_POST_CSC_GAMC_SEG0_DATA_ENH_1_A, \ + _PLANE_POST_CSC_GAMC_SEG0_DATA_ENH_1_B) +#define _PLANE_POST_CSC_GAMC_SEG0_DATA_ENH_2(pipe) _PIPE(pipe, _PLANE_POST_CSC_GAMC_SEG0_DATA_ENH_2_A, \ + _PLANE_POST_CSC_GAMC_SEG0_DATA_ENH_2_B) +#define PLANE_POST_CSC_GAMC_SEG0_DATA_ENH(pipe, plane, i) _MMIO_PLANE_GAMC(plane, i, _PLANE_POST_CSC_GAMC_SEG0_DATA_ENH_1(pipe), \ + _PLANE_POST_CSC_GAMC_SEG0_DATA_ENH_2(pipe)) + +#define _PLANE_POST_CSC_GAMC_INDEX_ENH_1_A 0x701d8 +#define _PLANE_POST_CSC_GAMC_INDEX_ENH_1_B 0x711d8 +#define _PLANE_POST_CSC_GAMC_INDEX_ENH_2_A 0x702d8 +#define _PLANE_POST_CSC_GAMC_INDEX_ENH_2_B 0x712d8 +#define _PLANE_POST_CSC_GAMC_INDEX_ENH_1(pipe) _PIPE(pipe, _PLANE_POST_CSC_GAMC_INDEX_ENH_1_A, \ + _PLANE_POST_CSC_GAMC_INDEX_ENH_1_B) +#define _PLANE_POST_CSC_GAMC_INDEX_ENH_2(pipe) _PIPE(pipe, _PLANE_POST_CSC_GAMC_INDEX_ENH_2_A, \ + _PLANE_POST_CSC_GAMC_INDEX_ENH_2_B) +#define PLANE_POST_CSC_GAMC_INDEX_ENH(pipe, plane, i) _MMIO_PLANE_GAMC(plane, i, _PLANE_POST_CSC_GAMC_INDEX_ENH_1(pipe), \ + _PLANE_POST_CSC_GAMC_INDEX_ENH_2(pipe)) + +#define _PLANE_POST_CSC_GAMC_DATA_ENH_1_A 0x701dc +#define _PLANE_POST_CSC_GAMC_DATA_ENH_1_B 0x711dc +#define _PLANE_POST_CSC_GAMC_DATA_ENH_2_A 0x702dc +#define _PLANE_POST_CSC_GAMC_DATA_ENH_2_B 0x712dc +#define _PLANE_POST_CSC_GAMC_DATA_ENH_1(pipe) _PIPE(pipe, _PLANE_POST_CSC_GAMC_DATA_ENH_1_A, \ + _PLANE_POST_CSC_GAMC_DATA_ENH_1_B) +#define _PLANE_POST_CSC_GAMC_DATA_ENH_2(pipe) _PIPE(pipe, _PLANE_POST_CSC_GAMC_DATA_ENH_2_A, \ + _PLANE_POST_CSC_GAMC_DATA_ENH_2_B) +#define PLANE_POST_CSC_GAMC_DATA_ENH(pipe, plane, i) _MMIO_PLANE_GAMC(plane, i, _PLANE_POST_CSC_GAMC_DATA_ENH_1(pipe), \ + _PLANE_POST_CSC_GAMC_DATA_ENH_2(pipe)) + +#define _PLANE_POST_CSC_GAMC_INDEX_1_A 0x704d8 +#define _PLANE_POST_CSC_GAMC_INDEX_1_B 0x714d8 +#define _PLANE_POST_CSC_GAMC_INDEX_2_A 0x705d8 +#define _PLANE_POST_CSC_GAMC_INDEX_2_B 0x715d8 +#define _PLANE_POST_CSC_GAMC_INDEX_1(pipe) _PIPE(pipe, _PLANE_POST_CSC_GAMC_INDEX_1_A, \ + _PLANE_POST_CSC_GAMC_INDEX_1_B) +#define _PLANE_POST_CSC_GAMC_INDEX_2(pipe) _PIPE(pipe, _PLANE_POST_CSC_GAMC_INDEX_2_A, \ + _PLANE_POST_CSC_GAMC_INDEX_2_B) +#define PLANE_POST_CSC_GAMC_INDEX(pipe, plane, i) _MMIO_PLANE_GAMC(plane, i, _PLANE_POST_CSC_GAMC_INDEX_1(pipe), \ + _PLANE_POST_CSC_GAMC_INDEX_2(pipe)) + +#define _PLANE_POST_CSC_GAMC_DATA_1_A 0x704dc +#define _PLANE_POST_CSC_GAMC_DATA_1_B 0x714dc +#define _PLANE_POST_CSC_GAMC_DATA_2_A 0x705dc +#define _PLANE_POST_CSC_GAMC_DATA_2_B 0x715dc +#define _PLANE_POST_CSC_GAMC_DATA_1(pipe) _PIPE(pipe, _PLANE_POST_CSC_GAMC_DATA_1_A, \ + _PLANE_POST_CSC_GAMC_DATA_1_B) +#define _PLANE_POST_CSC_GAMC_DATA_2(pipe) _PIPE(pipe, _PLANE_POST_CSC_GAMC_DATA_2_A, \ + _PLANE_POST_CSC_GAMC_DATA_2_B) +#define PLANE_POST_CSC_GAMC_DATA(pipe, plane, i) _MMIO_PLANE_GAMC(plane, i, _PLANE_POST_CSC_GAMC_DATA_1(pipe), \ + _PLANE_POST_CSC_GAMC_DATA_2(pipe)) + #define _PLANE_PRE_CSC_GAMC_INDEX_ENH_1_A 0x701d0 #define _PLANE_PRE_CSC_GAMC_INDEX_ENH_1_B 0x711d0 #define _PLANE_PRE_CSC_GAMC_INDEX_ENH_2_A 0x702d0 From 3b7476e786c2250177c5db0b6b9f1348813b9ce0 Mon Sep 17 00:00:00 2001 From: Uma Shankar Date: Wed, 3 Dec 2025 14:22:06 +0530 Subject: [PATCH 10/15] drm/i915/color: Add framework to program PRE/POST CSC LUT Add framework that will help in loading LUT to Pre/Post CSC color blocks. v2: Add dsb support v3: Align enum names v4: Propagate change in lut data to crtc_state Reviewed-by: Suraj Kandpal Signed-off-by: Uma Shankar Signed-off-by: Chaitanya Kumar Borah Link: https://patch.msgid.link/20251203085211.3663374-11-uma.shankar@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_color.c | 16 ++++++++++++++++ .../gpu/drm/i915/display/intel_display_types.h | 2 +- drivers/gpu/drm/i915/display/intel_plane.c | 4 ++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c index 2f8e985d51e5..4ca359d68730 100644 --- a/drivers/gpu/drm/i915/display/intel_color.c +++ b/drivers/gpu/drm/i915/display/intel_color.c @@ -93,6 +93,10 @@ struct intel_color_funcs { /* Plane CSC*/ void (*load_plane_csc_matrix)(struct intel_dsb *dsb, const struct intel_plane_state *plane_state); + + /* Plane Pre/Post CSC */ + void (*load_plane_luts)(struct intel_dsb *dsb, + const struct intel_plane_state *plane_state); }; #define CTM_COEFF_SIGN (1ULL << 63) @@ -4077,11 +4081,23 @@ intel_color_load_plane_csc_matrix(struct intel_dsb *dsb, display->funcs.color->load_plane_csc_matrix(dsb, plane_state); } +static void +intel_color_load_plane_luts(struct intel_dsb *dsb, + const struct intel_plane_state *plane_state) +{ + struct intel_display *display = to_intel_display(plane_state); + + if (display->funcs.color->load_plane_luts) + display->funcs.color->load_plane_luts(dsb, plane_state); +} + void intel_color_plane_program_pipeline(struct intel_dsb *dsb, const struct intel_plane_state *plane_state) { if (plane_state->hw.ctm) intel_color_load_plane_csc_matrix(dsb, plane_state); + if (plane_state->hw.degamma_lut || plane_state->hw.gamma_lut) + intel_color_load_plane_luts(dsb, plane_state); } void intel_color_crtc_init(struct intel_crtc *crtc) diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 6d8217497583..c419a814cb34 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -646,7 +646,7 @@ struct intel_plane_state { enum drm_color_encoding color_encoding; enum drm_color_range color_range; enum drm_scaling_filter scaling_filter; - struct drm_property_blob *ctm; + struct drm_property_blob *ctm, *degamma_lut, *gamma_lut; } hw; struct i915_vma *ggtt_vma; diff --git a/drivers/gpu/drm/i915/display/intel_plane.c b/drivers/gpu/drm/i915/display/intel_plane.c index ad25af7394a6..ade014f18fce 100644 --- a/drivers/gpu/drm/i915/display/intel_plane.c +++ b/drivers/gpu/drm/i915/display/intel_plane.c @@ -344,6 +344,10 @@ intel_plane_colorop_replace_blob(struct intel_plane_state *plane_state, { if (intel_colorop->id == INTEL_PLANE_CB_CSC) return drm_property_replace_blob(&plane_state->hw.ctm, blob); + else if (intel_colorop->id == INTEL_PLANE_CB_PRE_CSC_LUT) + return drm_property_replace_blob(&plane_state->hw.degamma_lut, blob); + else if (intel_colorop->id == INTEL_PLANE_CB_POST_CSC_LUT) + return drm_property_replace_blob(&plane_state->hw.gamma_lut, blob); return false; } From 82caa1c8813fb333303f21dd553c85d36ffb01fe Mon Sep 17 00:00:00 2001 From: Uma Shankar Date: Wed, 3 Dec 2025 14:22:07 +0530 Subject: [PATCH 11/15] drm/i915/color: Program Pre-CSC registers Add callback to program Pre-CSC LUT for TGL and beyond v2: Add DSB support v3: Add support for single segment 1D LUT color op v4: - s/drm_color_lut_32/drm_color_lut32/ (Simon) - Change commit message (Suraj) - Improve comments (Suraj) - Remove multisegmented programming, to be added later - Remove dead code for SDR planes, add when needed BSpec: 50411, 50412, 50413, 50414 Reviewed-by: Suraj Kandpal Signed-off-by: Uma Shankar Signed-off-by: Chaitanya Kumar Borah Link: https://patch.msgid.link/20251203085211.3663374-12-uma.shankar@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_color.c | 61 ++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c index 4ca359d68730..2a114d2964fa 100644 --- a/drivers/gpu/drm/i915/display/intel_color.c +++ b/drivers/gpu/drm/i915/display/intel_color.c @@ -3943,6 +3943,66 @@ xelpd_load_plane_csc_matrix(struct intel_dsb *dsb, ctm_to_twos_complement(input[11], 0, 12)); } +static void +xelpd_program_plane_pre_csc_lut(struct intel_dsb *dsb, + const struct intel_plane_state *plane_state) +{ + struct intel_display *display = to_intel_display(plane_state); + const struct drm_plane_state *state = &plane_state->uapi; + enum pipe pipe = to_intel_plane(state->plane)->pipe; + enum plane_id plane = to_intel_plane(state->plane)->id; + const struct drm_color_lut32 *pre_csc_lut = plane_state->hw.degamma_lut->data; + u32 i, lut_size; + + if (icl_is_hdr_plane(display, plane)) { + lut_size = 128; + + intel_de_write_dsb(display, dsb, + PLANE_PRE_CSC_GAMC_INDEX_ENH(pipe, plane, 0), + PLANE_PAL_PREC_AUTO_INCREMENT); + + if (pre_csc_lut) { + for (i = 0; i < lut_size; i++) { + u32 lut_val = drm_color_lut32_extract(pre_csc_lut[i].green, 24); + + intel_de_write_dsb(display, dsb, + PLANE_PRE_CSC_GAMC_DATA_ENH(pipe, plane, 0), + lut_val); + } + + /* Program the max register to clamp values > 1.0. */ + /* TODO: Restrict to 0x7ffffff */ + do { + intel_de_write_dsb(display, dsb, + PLANE_PRE_CSC_GAMC_DATA_ENH(pipe, plane, 0), + (1 << 24)); + } while (i++ > 130); + } else { + for (i = 0; i < lut_size; i++) { + u32 v = (i * ((1 << 24) - 1)) / (lut_size - 1); + + intel_de_write_dsb(display, dsb, + PLANE_PRE_CSC_GAMC_DATA_ENH(pipe, plane, 0), v); + } + + do { + intel_de_write_dsb(display, dsb, + PLANE_PRE_CSC_GAMC_DATA_ENH(pipe, plane, 0), + 1 << 24); + } while (i++ < 130); + } + + intel_de_write_dsb(display, dsb, PLANE_PRE_CSC_GAMC_INDEX_ENH(pipe, plane, 0), 0); + } +} + +static void +xelpd_plane_load_luts(struct intel_dsb *dsb, const struct intel_plane_state *plane_state) +{ + if (plane_state->hw.degamma_lut) + xelpd_program_plane_pre_csc_lut(dsb, plane_state); +} + static const struct intel_color_funcs chv_color_funcs = { .color_check = chv_color_check, .color_commit_arm = i9xx_color_commit_arm, @@ -3991,6 +4051,7 @@ static const struct intel_color_funcs tgl_color_funcs = { .read_csc = icl_read_csc, .get_config = skl_get_config, .load_plane_csc_matrix = xelpd_load_plane_csc_matrix, + .load_plane_luts = xelpd_plane_load_luts, }; static const struct intel_color_funcs icl_color_funcs = { From bf0fd7375466b7fd58b9b98193cc19b90c856faa Mon Sep 17 00:00:00 2001 From: Uma Shankar Date: Wed, 3 Dec 2025 14:22:08 +0530 Subject: [PATCH 12/15] drm/i915/color: Program Plane Post CSC Registers Extract the LUT and program plane post csc registers. v2: Add DSB support v3: Add support for single segment 1D LUT v4: - s/drm_color_lut_32/drm_color_lut32 (Simon) - Move declaration to beginning of the function (Suraj) - Remove multisegmented code, add it later - Remove dead code for SDR planes, add it later v5: - Fix iterator issues v6: Removed redundant variable (Suraj) Reviewed-by: Suraj Kandpal Signed-off-by: Uma Shankar Signed-off-by: Chaitanya Kumar Borah Link: https://patch.msgid.link/20251203085211.3663374-13-uma.shankar@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_color.c | 59 ++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c index 2a114d2964fa..08f3b5b47b8e 100644 --- a/drivers/gpu/drm/i915/display/intel_color.c +++ b/drivers/gpu/drm/i915/display/intel_color.c @@ -3996,11 +3996,70 @@ xelpd_program_plane_pre_csc_lut(struct intel_dsb *dsb, } } +static void +xelpd_program_plane_post_csc_lut(struct intel_dsb *dsb, + const struct intel_plane_state *plane_state) +{ + struct intel_display *display = to_intel_display(plane_state); + const struct drm_plane_state *state = &plane_state->uapi; + enum pipe pipe = to_intel_plane(state->plane)->pipe; + enum plane_id plane = to_intel_plane(state->plane)->id; + const struct drm_color_lut32 *post_csc_lut = plane_state->hw.gamma_lut->data; + u32 i, lut_size, lut_val; + + if (icl_is_hdr_plane(display, plane)) { + intel_de_write_dsb(display, dsb, PLANE_POST_CSC_GAMC_INDEX_ENH(pipe, plane, 0), + PLANE_PAL_PREC_AUTO_INCREMENT); + /* TODO: Add macro */ + intel_de_write_dsb(display, dsb, PLANE_POST_CSC_GAMC_SEG0_INDEX_ENH(pipe, plane, 0), + PLANE_PAL_PREC_AUTO_INCREMENT); + if (post_csc_lut) { + lut_size = 32; + for (i = 0; i < lut_size; i++) { + lut_val = drm_color_lut32_extract(post_csc_lut[i].green, 24); + + intel_de_write_dsb(display, dsb, + PLANE_POST_CSC_GAMC_DATA_ENH(pipe, plane, 0), + lut_val); + } + + /* Segment 2 */ + do { + intel_de_write_dsb(display, dsb, + PLANE_POST_CSC_GAMC_DATA_ENH(pipe, plane, 0), + (1 << 24)); + } while (i++ < 34); + } else { + /*TODO: Add for segment 0 */ + lut_size = 32; + for (i = 0; i < lut_size; i++) { + u32 v = (i * ((1 << 24) - 1)) / (lut_size - 1); + + intel_de_write_dsb(display, dsb, + PLANE_POST_CSC_GAMC_DATA_ENH(pipe, plane, 0), v); + } + + do { + intel_de_write_dsb(display, dsb, + PLANE_POST_CSC_GAMC_DATA_ENH(pipe, plane, 0), + 1 << 24); + } while (i++ < 34); + } + + intel_de_write_dsb(display, dsb, PLANE_POST_CSC_GAMC_INDEX_ENH(pipe, plane, 0), 0); + intel_de_write_dsb(display, dsb, + PLANE_POST_CSC_GAMC_SEG0_INDEX_ENH(pipe, plane, 0), 0); + } +} + static void xelpd_plane_load_luts(struct intel_dsb *dsb, const struct intel_plane_state *plane_state) { if (plane_state->hw.degamma_lut) xelpd_program_plane_pre_csc_lut(dsb, plane_state); + + if (plane_state->hw.gamma_lut) + xelpd_program_plane_post_csc_lut(dsb, plane_state); } static const struct intel_color_funcs chv_color_funcs = { From 55b0f3cd09a1d8e29f4a33d229ef82d69b25d917 Mon Sep 17 00:00:00 2001 From: Chaitanya Kumar Borah Date: Wed, 3 Dec 2025 14:22:09 +0530 Subject: [PATCH 13/15] drm/i915/color: Add registers for 3D LUT Add registers needed to program 3D LUT v2: - Follow convention documented in i915_reg.h (Jani) - Removing space in trailer (Suraj) - Move registers to intel_color_regs.h BSpec: 69378, 69379, 69380 Reviewed-by: Suraj Kandpal Signed-off-by: Chaitanya Kumar Borah Signed-off-by: Uma Shankar Link: https://patch.msgid.link/20251203085211.3663374-14-uma.shankar@intel.com Signed-off-by: Jani Nikula --- .../gpu/drm/i915/display/intel_color_regs.h | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_color_regs.h b/drivers/gpu/drm/i915/display/intel_color_regs.h index 8eb643cfead7..c370b6029369 100644 --- a/drivers/gpu/drm/i915/display/intel_color_regs.h +++ b/drivers/gpu/drm/i915/display/intel_color_regs.h @@ -316,4 +316,33 @@ #define SKL_BOTTOM_COLOR_CSC_ENABLE REG_BIT(30) #define SKL_BOTTOM_COLOR(pipe) _MMIO_PIPE(pipe, _SKL_BOTTOM_COLOR_A, _SKL_BOTTOM_COLOR_B) +/* 3D LUT */ +#define _LUT_3D_CTL_A 0x490A4 +#define _LUT_3D_CTL_B 0x491A4 +#define LUT_3D_CTL(pipe) _MMIO_PIPE(pipe, _LUT_3D_CTL_A, _LUT_3D_CTL_B) +#define LUT_3D_ENABLE REG_BIT(31) +#define LUT_3D_READY REG_BIT(30) +#define LUT_3D_BINDING_MASK REG_GENMASK(23, 22) +#define LUT_3D_BIND_PIPE REG_FIELD_PREP(LUT_3D_BINDING_MASK, 0) +#define LUT_3D_BIND_PLANE_1 REG_FIELD_PREP(LUT_3D_BINDING_MASK, 1) +#define LUT_3D_BIND_PLANE_2 REG_FIELD_PREP(LUT_3D_BINDING_MASK, 2) +#define LUT_3D_BIND_PLANE_3 REG_FIELD_PREP(LUT_3D_BINDING_MASK, 3) + +#define _LUT_3D_INDEX_A 0x490A8 +#define _LUT_3D_INDEX_B 0x491A8 +#define LUT_3D_INDEX(pipe) _MMIO_PIPE(pipe, _LUT_3D_INDEX_A, _LUT_3D_INDEX_B) +#define LUT_3D_AUTO_INCREMENT REG_BIT(13) +#define LUT_3D_INDEX_VALUE_MASK REG_GENMASK(12, 0) +#define LUT_3D_INDEX_VALUE(x) REG_FIELD_PREP(LUT_3D_INDEX_VALUE_MASK, (x)) + +#define _LUT_3D_DATA_A 0x490AC +#define _LUT_3D_DATA_B 0x491AC +#define LUT_3D_DATA(pipe) _MMIO_PIPE(pipe, _LUT_3D_DATA_A, _LUT_3D_DATA_B) +#define LUT_3D_DATA_RED_MASK REG_GENMASK(29, 20) +#define LUT_3D_DATA_GREEN_MASK REG_GENMASK(19, 10) +#define LUT_3D_DATA_BLUE_MASK REG_GENMASK(9, 0) +#define LUT_3D_DATA_RED(x) REG_FIELD_PREP(LUT_3D_DATA_RED_MASK, (x)) +#define LUT_3D_DATA_GREEN(x) REG_FIELD_PREP(LUT_3D_DATA_GREEN_MASK, (x)) +#define LUT_3D_DATA_BLUE(x) REG_FIELD_PREP(LUT_3D_DATA_BLUE_MASK, (x)) + #endif /* __INTEL_COLOR_REGS_H__ */ From 65db7a1f9cf772d733358de032fee60ad770c1e8 Mon Sep 17 00:00:00 2001 From: Chaitanya Kumar Borah Date: Wed, 3 Dec 2025 14:22:10 +0530 Subject: [PATCH 14/15] drm/i915/color: Add 3D LUT to color pipeline Add helpers to program the 3D LUT registers and arm them. LUT_3D_READY in LUT_3D_CLT is cleared off by the HW once the LUT buffer is loaded into it's internal working RAM. So by the time we try to load/commit new values, we expect it to be cleared off. If not, log an error and return without writing new values. Do it only when writing with MMIO. There is no way to read register within DSB execution. v2: - Add information regarding LUT_3D_READY to commit message (Jani) - Log error instead of a drm_warn and return without committing changes if 3DLUT HW is not ready to accept new values. - Refactor intel_color_crtc_has_3dlut() Also remove Gen10 check (Suraj) v3: - Addressed review comments (Suraj) Reviewed-by: Suraj Kandpal Signed-off-by: Chaitanya Kumar Borah Signed-off-by: Uma Shankar Link: https://patch.msgid.link/20251203085211.3663374-15-uma.shankar@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_color.c | 78 +++++++++++++++++++ drivers/gpu/drm/i915/display/intel_color.h | 4 + .../drm/i915/display/intel_color_pipeline.c | 29 +++++-- .../drm/i915/display/intel_color_pipeline.h | 3 +- .../drm/i915/display/intel_display_limits.h | 1 + .../drm/i915/display/intel_display_types.h | 2 +- drivers/gpu/drm/i915/display/intel_plane.c | 2 + 7 files changed, 112 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c index 08f3b5b47b8e..e7950655434b 100644 --- a/drivers/gpu/drm/i915/display/intel_color.c +++ b/drivers/gpu/drm/i915/display/intel_color.c @@ -4062,6 +4062,52 @@ xelpd_plane_load_luts(struct intel_dsb *dsb, const struct intel_plane_state *pla xelpd_program_plane_post_csc_lut(dsb, plane_state); } +static u32 glk_3dlut_10(const struct drm_color_lut32 *color) +{ + return REG_FIELD_PREP(LUT_3D_DATA_RED_MASK, drm_color_lut32_extract(color->red, 10)) | + REG_FIELD_PREP(LUT_3D_DATA_GREEN_MASK, drm_color_lut32_extract(color->green, 10)) | + REG_FIELD_PREP(LUT_3D_DATA_BLUE_MASK, drm_color_lut32_extract(color->blue, 10)); +} + +static void glk_load_lut_3d(struct intel_dsb *dsb, + struct intel_crtc *crtc, + const struct drm_property_blob *blob) +{ + struct intel_display *display = to_intel_display(crtc->base.dev); + const struct drm_color_lut32 *lut = blob->data; + int i, lut_size = drm_color_lut32_size(blob); + enum pipe pipe = crtc->pipe; + + if (!dsb && intel_de_read(display, LUT_3D_CTL(pipe)) & LUT_3D_READY) { + drm_err(display->drm, "[CRTC:%d:%s] 3D LUT not ready, not loading LUTs\n", + crtc->base.base.id, crtc->base.name); + return; + } + + intel_de_write_dsb(display, dsb, LUT_3D_INDEX(pipe), LUT_3D_AUTO_INCREMENT); + for (i = 0; i < lut_size; i++) + intel_de_write_dsb(display, dsb, LUT_3D_DATA(pipe), glk_3dlut_10(&lut[i])); + intel_de_write_dsb(display, dsb, LUT_3D_INDEX(pipe), 0); +} + +static void glk_lut_3d_commit(struct intel_dsb *dsb, struct intel_crtc *crtc, bool enable) +{ + struct intel_display *display = to_intel_display(crtc); + enum pipe pipe = crtc->pipe; + u32 val = 0; + + if (!dsb && intel_de_read(display, LUT_3D_CTL(pipe)) & LUT_3D_READY) { + drm_err(display->drm, "[CRTC:%d:%s] 3D LUT not ready, not committing change\n", + crtc->base.base.id, crtc->base.name); + return; + } + + if (enable) + val = LUT_3D_ENABLE | LUT_3D_READY | LUT_3D_BIND_PLANE_1; + + intel_de_write_dsb(display, dsb, LUT_3D_CTL(pipe), val); +} + static const struct intel_color_funcs chv_color_funcs = { .color_check = chv_color_check, .color_commit_arm = i9xx_color_commit_arm, @@ -4191,6 +4237,16 @@ static const struct intel_color_funcs ilk_color_funcs = { .get_config = ilk_get_config, }; +void intel_color_plane_commit_arm(struct intel_dsb *dsb, + const struct intel_plane_state *plane_state) +{ + struct intel_display *display = to_intel_display(plane_state); + struct intel_crtc *crtc = to_intel_crtc(plane_state->uapi.crtc); + + if (crtc && intel_color_crtc_has_3dlut(display, crtc->pipe)) + glk_lut_3d_commit(dsb, crtc, !!plane_state->hw.lut_3d); +} + static void intel_color_load_plane_csc_matrix(struct intel_dsb *dsb, const struct intel_plane_state *plane_state) @@ -4211,6 +4267,26 @@ intel_color_load_plane_luts(struct intel_dsb *dsb, display->funcs.color->load_plane_luts(dsb, plane_state); } +bool +intel_color_crtc_has_3dlut(struct intel_display *display, enum pipe pipe) +{ + if (DISPLAY_VER(display) >= 12) + return pipe == PIPE_A || pipe == PIPE_B; + else + return false; +} + +static void +intel_color_load_3dlut(struct intel_dsb *dsb, + const struct intel_plane_state *plane_state) +{ + struct intel_display *display = to_intel_display(plane_state); + struct intel_crtc *crtc = to_intel_crtc(plane_state->uapi.crtc); + + if (crtc && intel_color_crtc_has_3dlut(display, crtc->pipe)) + glk_load_lut_3d(dsb, crtc, plane_state->hw.lut_3d); +} + void intel_color_plane_program_pipeline(struct intel_dsb *dsb, const struct intel_plane_state *plane_state) { @@ -4218,6 +4294,8 @@ void intel_color_plane_program_pipeline(struct intel_dsb *dsb, intel_color_load_plane_csc_matrix(dsb, plane_state); if (plane_state->hw.degamma_lut || plane_state->hw.gamma_lut) intel_color_load_plane_luts(dsb, plane_state); + if (plane_state->hw.lut_3d) + intel_color_load_3dlut(dsb, plane_state); } void intel_color_crtc_init(struct intel_crtc *crtc) diff --git a/drivers/gpu/drm/i915/display/intel_color.h b/drivers/gpu/drm/i915/display/intel_color.h index 8051c827a1d8..c21b9bdf7bb8 100644 --- a/drivers/gpu/drm/i915/display/intel_color.h +++ b/drivers/gpu/drm/i915/display/intel_color.h @@ -15,6 +15,7 @@ struct intel_display; struct intel_dsb; struct intel_plane_state; struct drm_property_blob; +enum pipe; void intel_color_init_hooks(struct intel_display *display); int intel_color_init(struct intel_display *display); @@ -43,4 +44,7 @@ bool intel_color_lut_equal(const struct intel_crtc_state *crtc_state, void intel_color_assert_luts(const struct intel_crtc_state *crtc_state); void intel_color_plane_program_pipeline(struct intel_dsb *dsb, const struct intel_plane_state *plane_state); +void intel_color_plane_commit_arm(struct intel_dsb *dsb, + const struct intel_plane_state *plane_state); +bool intel_color_crtc_has_3dlut(struct intel_display *display, enum pipe pipe); #endif /* __INTEL_COLOR_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_color_pipeline.c b/drivers/gpu/drm/i915/display/intel_color_pipeline.c index 489d470cd011..942d9b9c93ce 100644 --- a/drivers/gpu/drm/i915/display/intel_color_pipeline.c +++ b/drivers/gpu/drm/i915/display/intel_color_pipeline.c @@ -2,6 +2,7 @@ /* * Copyright © 2025 Intel Corporation */ +#include "intel_color.h" #include "intel_colorop.h" #include "intel_color_pipeline.h" #include "intel_de.h" @@ -13,12 +14,14 @@ #define PLANE_GAMMA_SIZE 32 static -int _intel_color_pipeline_plane_init(struct drm_plane *plane, struct drm_prop_enum_list *list) +int _intel_color_pipeline_plane_init(struct drm_plane *plane, struct drm_prop_enum_list *list, + enum pipe pipe) { - struct intel_colorop *colorop; struct drm_device *dev = plane->dev; - int ret; + struct intel_display *display = to_intel_display(dev); struct drm_colorop *prev_op; + struct intel_colorop *colorop; + int ret; colorop = intel_colorop_create(INTEL_PLANE_CB_PRE_CSC_LUT); @@ -36,6 +39,22 @@ int _intel_color_pipeline_plane_init(struct drm_plane *plane, struct drm_prop_en /* TODO: handle failures and clean up */ prev_op = &colorop->base; + if (DISPLAY_VER(display) >= 35 && + intel_color_crtc_has_3dlut(display, pipe) && + plane->type == DRM_PLANE_TYPE_PRIMARY) { + colorop = intel_colorop_create(INTEL_PLANE_CB_3DLUT); + + ret = drm_plane_colorop_3dlut_init(dev, &colorop->base, plane, 17, + DRM_COLOROP_LUT3D_INTERPOLATION_TETRAHEDRAL, + true); + if (ret) + return ret; + + drm_colorop_set_next_property(prev_op, &colorop->base); + + prev_op = &colorop->base; + } + colorop = intel_colorop_create(INTEL_PLANE_CB_CSC); ret = drm_plane_colorop_ctm_3x4_init(dev, &colorop->base, plane, DRM_COLOROP_FLAG_ALLOW_BYPASS); @@ -58,7 +77,7 @@ int _intel_color_pipeline_plane_init(struct drm_plane *plane, struct drm_prop_en return 0; } -int intel_color_pipeline_plane_init(struct drm_plane *plane) +int intel_color_pipeline_plane_init(struct drm_plane *plane, enum pipe pipe) { struct drm_device *dev = plane->dev; struct intel_display *display = to_intel_display(dev); @@ -71,7 +90,7 @@ int intel_color_pipeline_plane_init(struct drm_plane *plane) return 0; /* Add pipeline consisting of transfer functions */ - ret = _intel_color_pipeline_plane_init(plane, &pipelines[len]); + ret = _intel_color_pipeline_plane_init(plane, &pipelines[len], pipe); if (ret) return ret; len++; diff --git a/drivers/gpu/drm/i915/display/intel_color_pipeline.h b/drivers/gpu/drm/i915/display/intel_color_pipeline.h index 7f1d32bc9202..a457d306da7f 100644 --- a/drivers/gpu/drm/i915/display/intel_color_pipeline.h +++ b/drivers/gpu/drm/i915/display/intel_color_pipeline.h @@ -7,7 +7,8 @@ #define __INTEL_COLOR_PIPELINE_H__ struct drm_plane; +enum pipe; -int intel_color_pipeline_plane_init(struct drm_plane *plane); +int intel_color_pipeline_plane_init(struct drm_plane *plane, enum pipe pipe); #endif /* __INTEL_COLOR_PIPELINE_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_display_limits.h b/drivers/gpu/drm/i915/display/intel_display_limits.h index 55fd574ba313..cb3c9c665c44 100644 --- a/drivers/gpu/drm/i915/display/intel_display_limits.h +++ b/drivers/gpu/drm/i915/display/intel_display_limits.h @@ -142,6 +142,7 @@ enum intel_color_block { INTEL_PLANE_CB_PRE_CSC_LUT, INTEL_PLANE_CB_CSC, INTEL_PLANE_CB_POST_CSC_LUT, + INTEL_PLANE_CB_3DLUT, INTEL_CB_MAX }; diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index c419a814cb34..06bf8f7c0989 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -646,7 +646,7 @@ struct intel_plane_state { enum drm_color_encoding color_encoding; enum drm_color_range color_range; enum drm_scaling_filter scaling_filter; - struct drm_property_blob *ctm, *degamma_lut, *gamma_lut; + struct drm_property_blob *ctm, *degamma_lut, *gamma_lut, *lut_3d; } hw; struct i915_vma *ggtt_vma; diff --git a/drivers/gpu/drm/i915/display/intel_plane.c b/drivers/gpu/drm/i915/display/intel_plane.c index ade014f18fce..ab6a58530b39 100644 --- a/drivers/gpu/drm/i915/display/intel_plane.c +++ b/drivers/gpu/drm/i915/display/intel_plane.c @@ -348,6 +348,8 @@ intel_plane_colorop_replace_blob(struct intel_plane_state *plane_state, return drm_property_replace_blob(&plane_state->hw.degamma_lut, blob); else if (intel_colorop->id == INTEL_PLANE_CB_POST_CSC_LUT) return drm_property_replace_blob(&plane_state->hw.gamma_lut, blob); + else if (intel_colorop->id == INTEL_PLANE_CB_3DLUT) + return drm_property_replace_blob(&plane_state->hw.lut_3d, blob); return false; } From 860daa4b0d09a398a0ac9ae6fe67efd73a275968 Mon Sep 17 00:00:00 2001 From: Uma Shankar Date: Wed, 3 Dec 2025 14:22:11 +0530 Subject: [PATCH 15/15] drm/i915/color: Enable Plane Color Pipelines Expose color pipeline and add ability to program it. v2: Set bit to enable multisegmented lut v3: s/drm_color_lut_32/drm_color_lut32 (Simon) v4: - Fix dsb programming - Remove multi-segment LUT, they will be added in later patches - Add pipeline only to TGL+ - Code Refactor Reviewed-by: Suraj Kandpal Signed-off-by: Chaitanya Kumar Borah Signed-off-by: Uma Shankar Signed-off-by: Jani Nikula Link: https://patch.msgid.link/20251203085211.3663374-16-uma.shankar@intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 5 ++++- .../drm/i915/display/skl_universal_plane.c | 21 +++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 069967114bd9..808ac34c1914 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -7296,6 +7296,7 @@ static void intel_atomic_dsb_finish(struct intel_atomic_state *state, struct intel_display *display = to_intel_display(state); struct intel_crtc_state *new_crtc_state = intel_atomic_get_new_crtc_state(state, crtc); + unsigned int size = new_crtc_state->plane_color_changed ? 8192 : 1024; if (!new_crtc_state->use_flipq && !new_crtc_state->use_dsb && @@ -7306,10 +7307,12 @@ static void intel_atomic_dsb_finish(struct intel_atomic_state *state, * Rough estimate: * ~64 registers per each plane * 8 planes = 512 * Double that for pipe stuff and other overhead. + * ~4913 registers for 3DLUT + * ~200 color registers * 3 HDR planes */ new_crtc_state->dsb_commit = intel_dsb_prepare(state, crtc, INTEL_DSB_0, new_crtc_state->use_dsb || - new_crtc_state->use_flipq ? 1024 : 16); + new_crtc_state->use_flipq ? size : 16); if (!new_crtc_state->dsb_commit) { new_crtc_state->use_flipq = false; new_crtc_state->use_dsb = false; diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c index 89c8003ccfe7..ee8e24497d2c 100644 --- a/drivers/gpu/drm/i915/display/skl_universal_plane.c +++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c @@ -11,6 +11,8 @@ #include "pxp/intel_pxp.h" #include "intel_bo.h" +#include "intel_color.h" +#include "intel_color_pipeline.h" #include "intel_de.h" #include "intel_display_irq.h" #include "intel_display_regs.h" @@ -1275,6 +1277,18 @@ static u32 glk_plane_color_ctl(const struct intel_plane_state *plane_state) if (plane_state->force_black) plane_color_ctl |= PLANE_COLOR_PLANE_CSC_ENABLE; + if (plane_state->hw.degamma_lut) + plane_color_ctl |= PLANE_COLOR_PRE_CSC_GAMMA_ENABLE; + + if (plane_state->hw.ctm) + plane_color_ctl |= PLANE_COLOR_PLANE_CSC_ENABLE; + + if (plane_state->hw.gamma_lut) { + plane_color_ctl &= ~PLANE_COLOR_PLANE_GAMMA_DISABLE; + if (drm_color_lut32_size(plane_state->hw.gamma_lut) != 32) + plane_color_ctl |= PLANE_COLOR_POST_CSC_GAMMA_MULTSEG_ENABLE; + } + return plane_color_ctl; } @@ -1556,6 +1570,8 @@ icl_plane_update_noarm(struct intel_dsb *dsb, plane_color_ctl = plane_state->color_ctl | glk_plane_color_ctl_crtc(crtc_state); + intel_color_plane_program_pipeline(dsb, plane_state); + /* The scaler will handle the output position */ if (plane_state->scaler_id >= 0) { crtc_x = 0; @@ -1657,6 +1673,8 @@ icl_plane_update_arm(struct intel_dsb *dsb, icl_plane_update_sel_fetch_arm(dsb, plane, crtc_state, plane_state); + intel_color_plane_commit_arm(dsb, plane_state); + /* * In order to have FBC for fp16 formats pixel normalizer block must be * active. Check if pixel normalizer block need to be enabled for FBC. @@ -3001,6 +3019,9 @@ skl_universal_plane_create(struct intel_display *display, DRM_COLOR_YCBCR_BT709, DRM_COLOR_YCBCR_LIMITED_RANGE); + if (DISPLAY_VER(display) >= 12) + intel_color_pipeline_plane_init(&plane->base, pipe); + drm_plane_create_alpha_property(&plane->base); drm_plane_create_blend_mode_property(&plane->base, BIT(DRM_MODE_BLEND_PIXEL_NONE) |