Skip to content

Commit 39a750f

Browse files
f-izzolumag
authored andcommitted
drm/msm/dpu: Add DSPP GC driver to provide GAMMA_LUT DRM property
Add support for DSPP GC block in DPU driver for Qualcomm SoCs. Expose the GAMMA_LUT DRM property, which is needed to enable night light and basic screen color calibration. I used LineageOS downstream kernel as a reference and found the LUT format by trial-and-error on OnePlus 6. Tested on oneplus-enchilada (sdm845-mainline 6.16-dev) and xiaomi-tissot (msm8953-mainline 6.12/main). Tested-by: David Heidelberg <david@ixit.cz> # Pixel 3 (next-20251018) Tested-by: Guido Günther <agx@sigxcpu.org> # on sdm845-shift-axolotl Signed-off-by: Federico Amedeo Izzo <federico@izzo.pro> Tested-by: Steev Klimaszewski <threeway@gmail.com> Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com> Patchwork: https://patchwork.freedesktop.org/patch/682102/ Link: https://lore.kernel.org/r/20251019-dpu-add-dspp-gc-driver-v3-1-840491934e56@izzo.pro Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
1 parent f185076 commit 39a750f

6 files changed

Lines changed: 163 additions & 14 deletions

File tree

drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c

Lines changed: 72 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -819,12 +819,42 @@ static void _dpu_crtc_get_pcc_coeff(struct drm_crtc_state *state,
819819
cfg->b.b = CONVERT_S3_15(ctm->matrix[8]);
820820
}
821821

822+
static void _dpu_crtc_get_gc_lut(struct drm_crtc_state *state,
823+
struct dpu_hw_gc_lut *gc_lut)
824+
{
825+
struct drm_color_lut *lut;
826+
int i;
827+
u32 val_even, val_odd;
828+
829+
lut = (struct drm_color_lut *)state->gamma_lut->data;
830+
831+
if (!lut)
832+
return;
833+
834+
/* Pack 1024 10-bit entries in 512 32-bit registers */
835+
for (i = 0; i < PGC_TBL_LEN; i++) {
836+
val_even = drm_color_lut_extract(lut[i * 2].green, 10);
837+
val_odd = drm_color_lut_extract(lut[i * 2 + 1].green, 10);
838+
gc_lut->c0[i] = val_even | (val_odd << 16);
839+
val_even = drm_color_lut_extract(lut[i * 2].blue, 10);
840+
val_odd = drm_color_lut_extract(lut[i * 2 + 1].blue, 10);
841+
gc_lut->c1[i] = val_even | (val_odd << 16);
842+
val_even = drm_color_lut_extract(lut[i * 2].red, 10);
843+
val_odd = drm_color_lut_extract(lut[i * 2 + 1].red, 10);
844+
gc_lut->c2[i] = val_even | (val_odd << 16);
845+
}
846+
847+
/* Disable 8-bit rounding mode */
848+
gc_lut->flags = 0;
849+
}
850+
822851
static void _dpu_crtc_setup_cp_blocks(struct drm_crtc *crtc)
823852
{
824853
struct drm_crtc_state *state = crtc->state;
825854
struct dpu_crtc_state *cstate = to_dpu_crtc_state(crtc->state);
826855
struct dpu_crtc_mixer *mixer = cstate->mixers;
827856
struct dpu_hw_pcc_cfg cfg;
857+
struct dpu_hw_gc_lut *gc_lut;
828858
struct dpu_hw_ctl *ctl;
829859
struct dpu_hw_dspp *dspp;
830860
int i;
@@ -837,19 +867,38 @@ static void _dpu_crtc_setup_cp_blocks(struct drm_crtc *crtc)
837867
ctl = mixer[i].lm_ctl;
838868
dspp = mixer[i].hw_dspp;
839869

840-
if (!dspp || !dspp->ops.setup_pcc)
870+
if (!dspp)
841871
continue;
842872

843-
if (!state->ctm) {
844-
dspp->ops.setup_pcc(dspp, NULL);
845-
} else {
846-
_dpu_crtc_get_pcc_coeff(state, &cfg);
847-
dspp->ops.setup_pcc(dspp, &cfg);
873+
if (dspp->ops.setup_pcc) {
874+
if (!state->ctm) {
875+
dspp->ops.setup_pcc(dspp, NULL);
876+
} else {
877+
_dpu_crtc_get_pcc_coeff(state, &cfg);
878+
dspp->ops.setup_pcc(dspp, &cfg);
879+
}
880+
881+
/* stage config flush mask */
882+
ctl->ops.update_pending_flush_dspp(ctl,
883+
mixer[i].hw_dspp->idx, DPU_DSPP_PCC);
848884
}
849885

850-
/* stage config flush mask */
851-
ctl->ops.update_pending_flush_dspp(ctl,
852-
mixer[i].hw_dspp->idx, DPU_DSPP_PCC);
886+
if (dspp->ops.setup_gc) {
887+
if (!state->gamma_lut) {
888+
dspp->ops.setup_gc(dspp, NULL);
889+
} else {
890+
gc_lut = kzalloc(sizeof(*gc_lut), GFP_KERNEL);
891+
if (!gc_lut)
892+
continue;
893+
_dpu_crtc_get_gc_lut(state, gc_lut);
894+
dspp->ops.setup_gc(dspp, gc_lut);
895+
kfree(gc_lut);
896+
}
897+
898+
/* stage config flush mask */
899+
ctl->ops.update_pending_flush_dspp(ctl,
900+
mixer[i].hw_dspp->idx, DPU_DSPP_GC);
901+
}
853902
}
854903
}
855904

@@ -1347,7 +1396,7 @@ static struct msm_display_topology dpu_crtc_get_topology(
13471396
*
13481397
* If DSC is enabled, use 2 LMs for 2:2:1 topology
13491398
*
1350-
* Add dspps to the reservation requirements if ctm is requested
1399+
* Add dspps to the reservation requirements if ctm or gamma_lut are requested
13511400
*
13521401
* Only hardcode num_lm to 2 for cases where num_intf == 2 and CWB is not
13531402
* enabled. This is because in cases where CWB is enabled, num_intf will
@@ -1366,7 +1415,7 @@ static struct msm_display_topology dpu_crtc_get_topology(
13661415
else
13671416
topology.num_lm = 1;
13681417

1369-
if (crtc_state->ctm)
1418+
if (crtc_state->ctm || crtc_state->gamma_lut)
13701419
topology.num_dspp = topology.num_lm;
13711420

13721421
return topology;
@@ -1478,7 +1527,8 @@ static int dpu_crtc_atomic_check(struct drm_crtc *crtc,
14781527
bool needs_dirtyfb = dpu_crtc_needs_dirtyfb(crtc_state);
14791528

14801529
/* don't reallocate resources if only ACTIVE has beeen changed */
1481-
if (crtc_state->mode_changed || crtc_state->connectors_changed) {
1530+
if (crtc_state->mode_changed || crtc_state->connectors_changed ||
1531+
crtc_state->color_mgmt_changed) {
14821532
rc = dpu_crtc_assign_resources(crtc, crtc_state);
14831533
if (rc < 0)
14841534
return rc;
@@ -1841,8 +1891,16 @@ struct drm_crtc *dpu_crtc_init(struct drm_device *dev, struct drm_plane *plane,
18411891

18421892
drm_crtc_helper_add(crtc, &dpu_crtc_helper_funcs);
18431893

1844-
if (dpu_kms->catalog->dspp_count)
1845-
drm_crtc_enable_color_mgmt(crtc, 0, true, 0);
1894+
if (dpu_kms->catalog->dspp_count) {
1895+
const struct dpu_dspp_cfg *dspp = &dpu_kms->catalog->dspp[0];
1896+
1897+
if (dspp->sblk->gc.base) {
1898+
drm_mode_crtc_set_gamma_size(crtc, DPU_GAMMA_LUT_SIZE);
1899+
drm_crtc_enable_color_mgmt(crtc, 0, true, DPU_GAMMA_LUT_SIZE);
1900+
} else {
1901+
drm_crtc_enable_color_mgmt(crtc, 0, true, 0);
1902+
}
1903+
}
18461904

18471905
/* save user friendly CRTC name for later */
18481906
snprintf(dpu_crtc->name, DPU_CRTC_NAME_SIZE, "crtc%u", crtc->base.id);

drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,11 +402,15 @@ static const struct dpu_lm_sub_blks qcm2290_lm_sblk = {
402402
static const struct dpu_dspp_sub_blks msm8998_dspp_sblk = {
403403
.pcc = {.name = "pcc", .base = 0x1700,
404404
.len = 0x90, .version = 0x10007},
405+
.gc = {.name = "gc", .base = 0x17c0,
406+
.len = 0x40, .version = 0x10007},
405407
};
406408

407409
static const struct dpu_dspp_sub_blks sdm845_dspp_sblk = {
408410
.pcc = {.name = "pcc", .base = 0x1700,
409411
.len = 0x90, .version = 0x40000},
412+
.gc = {.name = "gc", .base = 0x17c0,
413+
.len = 0x40, .version = 0x10008},
410414
};
411415

412416
static const struct dpu_dspp_sub_blks sm8750_dspp_sblk = {

drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,11 @@ enum {
7777
/**
7878
* DSPP sub-blocks
7979
* @DPU_DSPP_PCC Panel color correction block
80+
* @DPU_DSPP_GC Gamma correction block
8081
*/
8182
enum {
8283
DPU_DSPP_PCC = 0x1,
84+
DPU_DSPP_GC,
8385
DPU_DSPP_MAX
8486
};
8587

@@ -328,9 +330,11 @@ struct dpu_lm_sub_blks {
328330
/**
329331
* struct dpu_dspp_sub_blks: Information of DSPP block
330332
* @pcc: pixel color correction block
333+
* @gc: gamma correction block
331334
*/
332335
struct dpu_dspp_sub_blks {
333336
struct dpu_pp_blk pcc;
337+
struct dpu_pp_blk gc;
334338
};
335339

336340
struct dpu_pingpong_sub_blks {

drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,9 @@ static void dpu_hw_ctl_update_pending_flush_dspp_sub_blocks(
399399
case DPU_DSPP_PCC:
400400
ctx->pending_dspp_flush_mask[dspp - DSPP_0] |= BIT(4);
401401
break;
402+
case DPU_DSPP_GC:
403+
ctx->pending_dspp_flush_mask[dspp - DSPP_0] |= BIT(5);
404+
break;
402405
default:
403406
return;
404407
}

drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.c

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,18 @@
2424
#define PCC_BLUE_G_OFF 0x24
2525
#define PCC_BLUE_B_OFF 0x30
2626

27+
/* DSPP_GC */
28+
#define GC_EN BIT(0)
29+
#define GC_DIS 0
30+
#define GC_8B_ROUND_EN BIT(1)
31+
#define GC_LUT_SWAP_OFF 0x1c
32+
#define GC_C0_OFF 0x4
33+
#define GC_C1_OFF 0xc
34+
#define GC_C2_OFF 0x14
35+
#define GC_C0_INDEX_OFF 0x8
36+
#define GC_C1_INDEX_OFF 0x10
37+
#define GC_C2_INDEX_OFF 0x18
38+
2739
static void dpu_setup_dspp_pcc(struct dpu_hw_dspp *ctx,
2840
struct dpu_hw_pcc_cfg *cfg)
2941
{
@@ -63,6 +75,46 @@ static void dpu_setup_dspp_pcc(struct dpu_hw_dspp *ctx,
6375
DPU_REG_WRITE(&ctx->hw, base, PCC_EN);
6476
}
6577

78+
static void dpu_setup_dspp_gc(struct dpu_hw_dspp *ctx,
79+
struct dpu_hw_gc_lut *gc_lut)
80+
{
81+
int i = 0;
82+
u32 base, reg;
83+
84+
if (!ctx) {
85+
DRM_ERROR("invalid ctx\n");
86+
return;
87+
}
88+
89+
base = ctx->cap->sblk->gc.base;
90+
91+
if (!base) {
92+
DRM_ERROR("invalid ctx %pK gc base\n", ctx);
93+
return;
94+
}
95+
96+
if (!gc_lut) {
97+
DRM_DEBUG_DRIVER("disable gc feature\n");
98+
DPU_REG_WRITE(&ctx->hw, base, GC_DIS);
99+
return;
100+
}
101+
102+
DPU_REG_WRITE(&ctx->hw, base + GC_C0_INDEX_OFF, 0);
103+
DPU_REG_WRITE(&ctx->hw, base + GC_C1_INDEX_OFF, 0);
104+
DPU_REG_WRITE(&ctx->hw, base + GC_C2_INDEX_OFF, 0);
105+
106+
for (i = 0; i < PGC_TBL_LEN; i++) {
107+
DPU_REG_WRITE(&ctx->hw, base + GC_C0_OFF, gc_lut->c0[i]);
108+
DPU_REG_WRITE(&ctx->hw, base + GC_C1_OFF, gc_lut->c1[i]);
109+
DPU_REG_WRITE(&ctx->hw, base + GC_C2_OFF, gc_lut->c2[i]);
110+
}
111+
112+
DPU_REG_WRITE(&ctx->hw, base + GC_LUT_SWAP_OFF, BIT(0));
113+
114+
reg = GC_EN | ((gc_lut->flags & PGC_8B_ROUND) ? GC_8B_ROUND_EN : 0);
115+
DPU_REG_WRITE(&ctx->hw, base, reg);
116+
}
117+
66118
/**
67119
* dpu_hw_dspp_init() - Initializes the DSPP hw driver object.
68120
* should be called once before accessing every DSPP.
@@ -92,6 +144,8 @@ struct dpu_hw_dspp *dpu_hw_dspp_init(struct drm_device *dev,
92144
c->cap = cfg;
93145
if (c->cap->sblk->pcc.base)
94146
c->ops.setup_pcc = dpu_setup_dspp_pcc;
147+
if (c->cap->sblk->gc.base)
148+
c->ops.setup_gc = dpu_setup_dspp_gc;
95149

96150
return c;
97151
}

drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,25 @@ struct dpu_hw_pcc_cfg {
3333
struct dpu_hw_pcc_coeff b;
3434
};
3535

36+
#define DPU_GAMMA_LUT_SIZE 1024
37+
#define PGC_TBL_LEN 512
38+
#define PGC_8B_ROUND BIT(0)
39+
40+
/**
41+
* struct dpu_hw_gc_lut - gc lut feature structure
42+
* @flags: flags for the feature values can be:
43+
* - PGC_8B_ROUND
44+
* @c0: color0 component lut
45+
* @c1: color1 component lut
46+
* @c2: color2 component lut
47+
*/
48+
struct dpu_hw_gc_lut {
49+
__u64 flags;
50+
__u32 c0[PGC_TBL_LEN];
51+
__u32 c1[PGC_TBL_LEN];
52+
__u32 c2[PGC_TBL_LEN];
53+
};
54+
3655
/**
3756
* struct dpu_hw_dspp_ops - interface to the dspp hardware driver functions
3857
* Caller must call the init function to get the dspp context for each dspp
@@ -46,6 +65,13 @@ struct dpu_hw_dspp_ops {
4665
*/
4766
void (*setup_pcc)(struct dpu_hw_dspp *ctx, struct dpu_hw_pcc_cfg *cfg);
4867

68+
/**
69+
* setup_gc - setup dspp gc
70+
* @ctx: Pointer to dspp context
71+
* @gc_lut: Pointer to lut content
72+
*/
73+
void (*setup_gc)(struct dpu_hw_dspp *ctx, struct dpu_hw_gc_lut *gc_lut);
74+
4975
};
5076

5177
/**

0 commit comments

Comments
 (0)