Skip to content

Commit c7685d1

Browse files
committed
Merge tag 'topic/drm-intel-plane-color-pipeline-2025-12-04' of https://gitlab.freedesktop.org/drm/i915/kernel into drm-next
drm/i915 topic pull request for v6.19: Features and functionality: - Add plane color management support (Uma, Chaitanya) Signed-off-by: Dave Airlie <airlied@redhat.com> From: Jani Nikula <jani.nikula@intel.com> Link: https://patch.msgid.link/e7129c6afd6208719d2f5124da86e810505e7a7b@intel.com
2 parents 86fafc5 + 860daa4 commit c7685d1

15 files changed

Lines changed: 751 additions & 2 deletions

drivers/gpu/drm/i915/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,8 @@ i915-y += \
239239
display/intel_cdclk.o \
240240
display/intel_cmtg.o \
241241
display/intel_color.o \
242+
display/intel_colorop.o \
243+
display/intel_color_pipeline.o \
242244
display/intel_combo_phy.o \
243245
display/intel_connector.o \
244246
display/intel_crtc.o \

drivers/gpu/drm/i915/display/intel_color.c

Lines changed: 335 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
#include "intel_display_utils.h"
3333
#include "intel_dsb.h"
3434
#include "intel_vrr.h"
35+
#include "skl_universal_plane.h"
36+
#include "skl_universal_plane_regs.h"
3537

3638
struct intel_color_funcs {
3739
int (*color_check)(struct intel_atomic_state *state,
@@ -87,6 +89,14 @@ struct intel_color_funcs {
8789
* Read config other than LUTs and CSCs, before them. Optional.
8890
*/
8991
void (*get_config)(struct intel_crtc_state *crtc_state);
92+
93+
/* Plane CSC*/
94+
void (*load_plane_csc_matrix)(struct intel_dsb *dsb,
95+
const struct intel_plane_state *plane_state);
96+
97+
/* Plane Pre/Post CSC */
98+
void (*load_plane_luts)(struct intel_dsb *dsb,
99+
const struct intel_plane_state *plane_state);
90100
};
91101

92102
#define CTM_COEFF_SIGN (1ULL << 63)
@@ -609,6 +619,8 @@ static u16 ctm_to_twos_complement(u64 coeff, int int_bits, int frac_bits)
609619
if (CTM_COEFF_NEGATIVE(coeff))
610620
c = -c;
611621

622+
int_bits = max(int_bits, 1);
623+
612624
c = clamp(c, -(s64)BIT(int_bits + frac_bits - 1),
613625
(s64)(BIT(int_bits + frac_bits - 1) - 1));
614626

@@ -3836,6 +3848,266 @@ static void icl_read_luts(struct intel_crtc_state *crtc_state)
38363848
}
38373849
}
38383850

3851+
static void
3852+
xelpd_load_plane_csc_matrix(struct intel_dsb *dsb,
3853+
const struct intel_plane_state *plane_state)
3854+
{
3855+
struct intel_display *display = to_intel_display(plane_state);
3856+
const struct drm_plane_state *state = &plane_state->uapi;
3857+
enum pipe pipe = to_intel_plane(state->plane)->pipe;
3858+
enum plane_id plane = to_intel_plane(state->plane)->id;
3859+
const struct drm_property_blob *blob = plane_state->hw.ctm;
3860+
struct drm_color_ctm_3x4 *ctm;
3861+
const u64 *input;
3862+
u16 coeffs[9] = {};
3863+
int i, j;
3864+
3865+
if (!icl_is_hdr_plane(display, plane) || !blob)
3866+
return;
3867+
3868+
ctm = blob->data;
3869+
input = ctm->matrix;
3870+
3871+
/*
3872+
* Convert fixed point S31.32 input to format supported by the
3873+
* hardware.
3874+
*/
3875+
for (i = 0, j = 0; i < ARRAY_SIZE(coeffs); i++) {
3876+
u64 abs_coeff = ((1ULL << 63) - 1) & input[j];
3877+
3878+
/*
3879+
* Clamp input value to min/max supported by
3880+
* hardware.
3881+
*/
3882+
abs_coeff = clamp_val(abs_coeff, 0, CTM_COEFF_4_0 - 1);
3883+
3884+
/* sign bit */
3885+
if (CTM_COEFF_NEGATIVE(input[j]))
3886+
coeffs[i] |= 1 << 15;
3887+
3888+
if (abs_coeff < CTM_COEFF_0_125)
3889+
coeffs[i] |= (3 << 12) |
3890+
ILK_CSC_COEFF_FP(abs_coeff, 12);
3891+
else if (abs_coeff < CTM_COEFF_0_25)
3892+
coeffs[i] |= (2 << 12) |
3893+
ILK_CSC_COEFF_FP(abs_coeff, 11);
3894+
else if (abs_coeff < CTM_COEFF_0_5)
3895+
coeffs[i] |= (1 << 12) |
3896+
ILK_CSC_COEFF_FP(abs_coeff, 10);
3897+
else if (abs_coeff < CTM_COEFF_1_0)
3898+
coeffs[i] |= ILK_CSC_COEFF_FP(abs_coeff, 9);
3899+
else if (abs_coeff < CTM_COEFF_2_0)
3900+
coeffs[i] |= (7 << 12) |
3901+
ILK_CSC_COEFF_FP(abs_coeff, 8);
3902+
else
3903+
coeffs[i] |= (6 << 12) |
3904+
ILK_CSC_COEFF_FP(abs_coeff, 7);
3905+
3906+
/* Skip postoffs */
3907+
if (!((j + 2) % 4))
3908+
j += 2;
3909+
else
3910+
j++;
3911+
}
3912+
3913+
intel_de_write_dsb(display, dsb, PLANE_CSC_COEFF(pipe, plane, 0),
3914+
coeffs[0] << 16 | coeffs[1]);
3915+
intel_de_write_dsb(display, dsb, PLANE_CSC_COEFF(pipe, plane, 1),
3916+
coeffs[2] << 16);
3917+
3918+
intel_de_write_dsb(display, dsb, PLANE_CSC_COEFF(pipe, plane, 2),
3919+
coeffs[3] << 16 | coeffs[4]);
3920+
intel_de_write_dsb(display, dsb, PLANE_CSC_COEFF(pipe, plane, 3),
3921+
coeffs[5] << 16);
3922+
3923+
intel_de_write_dsb(display, dsb, PLANE_CSC_COEFF(pipe, plane, 4),
3924+
coeffs[6] << 16 | coeffs[7]);
3925+
intel_de_write_dsb(display, dsb, PLANE_CSC_COEFF(pipe, plane, 5),
3926+
coeffs[8] << 16);
3927+
3928+
intel_de_write_dsb(display, dsb, PLANE_CSC_PREOFF(pipe, plane, 0), 0);
3929+
intel_de_write_dsb(display, dsb, PLANE_CSC_PREOFF(pipe, plane, 1), 0);
3930+
intel_de_write_dsb(display, dsb, PLANE_CSC_PREOFF(pipe, plane, 2), 0);
3931+
3932+
/*
3933+
* Conversion from S31.32 to S0.12. BIT[12] is the signed bit
3934+
*/
3935+
intel_de_write_dsb(display, dsb,
3936+
PLANE_CSC_POSTOFF(pipe, plane, 0),
3937+
ctm_to_twos_complement(input[3], 0, 12));
3938+
intel_de_write_dsb(display, dsb,
3939+
PLANE_CSC_POSTOFF(pipe, plane, 1),
3940+
ctm_to_twos_complement(input[7], 0, 12));
3941+
intel_de_write_dsb(display, dsb,
3942+
PLANE_CSC_POSTOFF(pipe, plane, 2),
3943+
ctm_to_twos_complement(input[11], 0, 12));
3944+
}
3945+
3946+
static void
3947+
xelpd_program_plane_pre_csc_lut(struct intel_dsb *dsb,
3948+
const struct intel_plane_state *plane_state)
3949+
{
3950+
struct intel_display *display = to_intel_display(plane_state);
3951+
const struct drm_plane_state *state = &plane_state->uapi;
3952+
enum pipe pipe = to_intel_plane(state->plane)->pipe;
3953+
enum plane_id plane = to_intel_plane(state->plane)->id;
3954+
const struct drm_color_lut32 *pre_csc_lut = plane_state->hw.degamma_lut->data;
3955+
u32 i, lut_size;
3956+
3957+
if (icl_is_hdr_plane(display, plane)) {
3958+
lut_size = 128;
3959+
3960+
intel_de_write_dsb(display, dsb,
3961+
PLANE_PRE_CSC_GAMC_INDEX_ENH(pipe, plane, 0),
3962+
PLANE_PAL_PREC_AUTO_INCREMENT);
3963+
3964+
if (pre_csc_lut) {
3965+
for (i = 0; i < lut_size; i++) {
3966+
u32 lut_val = drm_color_lut32_extract(pre_csc_lut[i].green, 24);
3967+
3968+
intel_de_write_dsb(display, dsb,
3969+
PLANE_PRE_CSC_GAMC_DATA_ENH(pipe, plane, 0),
3970+
lut_val);
3971+
}
3972+
3973+
/* Program the max register to clamp values > 1.0. */
3974+
/* TODO: Restrict to 0x7ffffff */
3975+
do {
3976+
intel_de_write_dsb(display, dsb,
3977+
PLANE_PRE_CSC_GAMC_DATA_ENH(pipe, plane, 0),
3978+
(1 << 24));
3979+
} while (i++ > 130);
3980+
} else {
3981+
for (i = 0; i < lut_size; i++) {
3982+
u32 v = (i * ((1 << 24) - 1)) / (lut_size - 1);
3983+
3984+
intel_de_write_dsb(display, dsb,
3985+
PLANE_PRE_CSC_GAMC_DATA_ENH(pipe, plane, 0), v);
3986+
}
3987+
3988+
do {
3989+
intel_de_write_dsb(display, dsb,
3990+
PLANE_PRE_CSC_GAMC_DATA_ENH(pipe, plane, 0),
3991+
1 << 24);
3992+
} while (i++ < 130);
3993+
}
3994+
3995+
intel_de_write_dsb(display, dsb, PLANE_PRE_CSC_GAMC_INDEX_ENH(pipe, plane, 0), 0);
3996+
}
3997+
}
3998+
3999+
static void
4000+
xelpd_program_plane_post_csc_lut(struct intel_dsb *dsb,
4001+
const struct intel_plane_state *plane_state)
4002+
{
4003+
struct intel_display *display = to_intel_display(plane_state);
4004+
const struct drm_plane_state *state = &plane_state->uapi;
4005+
enum pipe pipe = to_intel_plane(state->plane)->pipe;
4006+
enum plane_id plane = to_intel_plane(state->plane)->id;
4007+
const struct drm_color_lut32 *post_csc_lut = plane_state->hw.gamma_lut->data;
4008+
u32 i, lut_size, lut_val;
4009+
4010+
if (icl_is_hdr_plane(display, plane)) {
4011+
intel_de_write_dsb(display, dsb, PLANE_POST_CSC_GAMC_INDEX_ENH(pipe, plane, 0),
4012+
PLANE_PAL_PREC_AUTO_INCREMENT);
4013+
/* TODO: Add macro */
4014+
intel_de_write_dsb(display, dsb, PLANE_POST_CSC_GAMC_SEG0_INDEX_ENH(pipe, plane, 0),
4015+
PLANE_PAL_PREC_AUTO_INCREMENT);
4016+
if (post_csc_lut) {
4017+
lut_size = 32;
4018+
for (i = 0; i < lut_size; i++) {
4019+
lut_val = drm_color_lut32_extract(post_csc_lut[i].green, 24);
4020+
4021+
intel_de_write_dsb(display, dsb,
4022+
PLANE_POST_CSC_GAMC_DATA_ENH(pipe, plane, 0),
4023+
lut_val);
4024+
}
4025+
4026+
/* Segment 2 */
4027+
do {
4028+
intel_de_write_dsb(display, dsb,
4029+
PLANE_POST_CSC_GAMC_DATA_ENH(pipe, plane, 0),
4030+
(1 << 24));
4031+
} while (i++ < 34);
4032+
} else {
4033+
/*TODO: Add for segment 0 */
4034+
lut_size = 32;
4035+
for (i = 0; i < lut_size; i++) {
4036+
u32 v = (i * ((1 << 24) - 1)) / (lut_size - 1);
4037+
4038+
intel_de_write_dsb(display, dsb,
4039+
PLANE_POST_CSC_GAMC_DATA_ENH(pipe, plane, 0), v);
4040+
}
4041+
4042+
do {
4043+
intel_de_write_dsb(display, dsb,
4044+
PLANE_POST_CSC_GAMC_DATA_ENH(pipe, plane, 0),
4045+
1 << 24);
4046+
} while (i++ < 34);
4047+
}
4048+
4049+
intel_de_write_dsb(display, dsb, PLANE_POST_CSC_GAMC_INDEX_ENH(pipe, plane, 0), 0);
4050+
intel_de_write_dsb(display, dsb,
4051+
PLANE_POST_CSC_GAMC_SEG0_INDEX_ENH(pipe, plane, 0), 0);
4052+
}
4053+
}
4054+
4055+
static void
4056+
xelpd_plane_load_luts(struct intel_dsb *dsb, const struct intel_plane_state *plane_state)
4057+
{
4058+
if (plane_state->hw.degamma_lut)
4059+
xelpd_program_plane_pre_csc_lut(dsb, plane_state);
4060+
4061+
if (plane_state->hw.gamma_lut)
4062+
xelpd_program_plane_post_csc_lut(dsb, plane_state);
4063+
}
4064+
4065+
static u32 glk_3dlut_10(const struct drm_color_lut32 *color)
4066+
{
4067+
return REG_FIELD_PREP(LUT_3D_DATA_RED_MASK, drm_color_lut32_extract(color->red, 10)) |
4068+
REG_FIELD_PREP(LUT_3D_DATA_GREEN_MASK, drm_color_lut32_extract(color->green, 10)) |
4069+
REG_FIELD_PREP(LUT_3D_DATA_BLUE_MASK, drm_color_lut32_extract(color->blue, 10));
4070+
}
4071+
4072+
static void glk_load_lut_3d(struct intel_dsb *dsb,
4073+
struct intel_crtc *crtc,
4074+
const struct drm_property_blob *blob)
4075+
{
4076+
struct intel_display *display = to_intel_display(crtc->base.dev);
4077+
const struct drm_color_lut32 *lut = blob->data;
4078+
int i, lut_size = drm_color_lut32_size(blob);
4079+
enum pipe pipe = crtc->pipe;
4080+
4081+
if (!dsb && intel_de_read(display, LUT_3D_CTL(pipe)) & LUT_3D_READY) {
4082+
drm_err(display->drm, "[CRTC:%d:%s] 3D LUT not ready, not loading LUTs\n",
4083+
crtc->base.base.id, crtc->base.name);
4084+
return;
4085+
}
4086+
4087+
intel_de_write_dsb(display, dsb, LUT_3D_INDEX(pipe), LUT_3D_AUTO_INCREMENT);
4088+
for (i = 0; i < lut_size; i++)
4089+
intel_de_write_dsb(display, dsb, LUT_3D_DATA(pipe), glk_3dlut_10(&lut[i]));
4090+
intel_de_write_dsb(display, dsb, LUT_3D_INDEX(pipe), 0);
4091+
}
4092+
4093+
static void glk_lut_3d_commit(struct intel_dsb *dsb, struct intel_crtc *crtc, bool enable)
4094+
{
4095+
struct intel_display *display = to_intel_display(crtc);
4096+
enum pipe pipe = crtc->pipe;
4097+
u32 val = 0;
4098+
4099+
if (!dsb && intel_de_read(display, LUT_3D_CTL(pipe)) & LUT_3D_READY) {
4100+
drm_err(display->drm, "[CRTC:%d:%s] 3D LUT not ready, not committing change\n",
4101+
crtc->base.base.id, crtc->base.name);
4102+
return;
4103+
}
4104+
4105+
if (enable)
4106+
val = LUT_3D_ENABLE | LUT_3D_READY | LUT_3D_BIND_PLANE_1;
4107+
4108+
intel_de_write_dsb(display, dsb, LUT_3D_CTL(pipe), val);
4109+
}
4110+
38394111
static const struct intel_color_funcs chv_color_funcs = {
38404112
.color_check = chv_color_check,
38414113
.color_commit_arm = i9xx_color_commit_arm,
@@ -3883,6 +4155,8 @@ static const struct intel_color_funcs tgl_color_funcs = {
38834155
.lut_equal = icl_lut_equal,
38844156
.read_csc = icl_read_csc,
38854157
.get_config = skl_get_config,
4158+
.load_plane_csc_matrix = xelpd_load_plane_csc_matrix,
4159+
.load_plane_luts = xelpd_plane_load_luts,
38864160
};
38874161

38884162
static const struct intel_color_funcs icl_color_funcs = {
@@ -3963,6 +4237,67 @@ static const struct intel_color_funcs ilk_color_funcs = {
39634237
.get_config = ilk_get_config,
39644238
};
39654239

4240+
void intel_color_plane_commit_arm(struct intel_dsb *dsb,
4241+
const struct intel_plane_state *plane_state)
4242+
{
4243+
struct intel_display *display = to_intel_display(plane_state);
4244+
struct intel_crtc *crtc = to_intel_crtc(plane_state->uapi.crtc);
4245+
4246+
if (crtc && intel_color_crtc_has_3dlut(display, crtc->pipe))
4247+
glk_lut_3d_commit(dsb, crtc, !!plane_state->hw.lut_3d);
4248+
}
4249+
4250+
static void
4251+
intel_color_load_plane_csc_matrix(struct intel_dsb *dsb,
4252+
const struct intel_plane_state *plane_state)
4253+
{
4254+
struct intel_display *display = to_intel_display(plane_state);
4255+
4256+
if (display->funcs.color->load_plane_csc_matrix)
4257+
display->funcs.color->load_plane_csc_matrix(dsb, plane_state);
4258+
}
4259+
4260+
static void
4261+
intel_color_load_plane_luts(struct intel_dsb *dsb,
4262+
const struct intel_plane_state *plane_state)
4263+
{
4264+
struct intel_display *display = to_intel_display(plane_state);
4265+
4266+
if (display->funcs.color->load_plane_luts)
4267+
display->funcs.color->load_plane_luts(dsb, plane_state);
4268+
}
4269+
4270+
bool
4271+
intel_color_crtc_has_3dlut(struct intel_display *display, enum pipe pipe)
4272+
{
4273+
if (DISPLAY_VER(display) >= 12)
4274+
return pipe == PIPE_A || pipe == PIPE_B;
4275+
else
4276+
return false;
4277+
}
4278+
4279+
static void
4280+
intel_color_load_3dlut(struct intel_dsb *dsb,
4281+
const struct intel_plane_state *plane_state)
4282+
{
4283+
struct intel_display *display = to_intel_display(plane_state);
4284+
struct intel_crtc *crtc = to_intel_crtc(plane_state->uapi.crtc);
4285+
4286+
if (crtc && intel_color_crtc_has_3dlut(display, crtc->pipe))
4287+
glk_load_lut_3d(dsb, crtc, plane_state->hw.lut_3d);
4288+
}
4289+
4290+
void intel_color_plane_program_pipeline(struct intel_dsb *dsb,
4291+
const struct intel_plane_state *plane_state)
4292+
{
4293+
if (plane_state->hw.ctm)
4294+
intel_color_load_plane_csc_matrix(dsb, plane_state);
4295+
if (plane_state->hw.degamma_lut || plane_state->hw.gamma_lut)
4296+
intel_color_load_plane_luts(dsb, plane_state);
4297+
if (plane_state->hw.lut_3d)
4298+
intel_color_load_3dlut(dsb, plane_state);
4299+
}
4300+
39664301
void intel_color_crtc_init(struct intel_crtc *crtc)
39674302
{
39684303
struct intel_display *display = to_intel_display(crtc);

0 commit comments

Comments
 (0)