On Wed, Mar 25, 2020 at 1:17 AM Kalyan Thota <kalyan_t@xxxxxxxxxxxxxx> wrote: > > This change adds support for color correction sub block > for SC7180 device. > > Signed-off-by: Kalyan Thota <kalyan_t@xxxxxxxxxxxxxx> Tested-by: Fritz Koenig <frkoenig@xxxxxxxxxx> > --- > drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 77 ++++++++++++++++++++++++++ > drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c | 9 ++- > drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.c | 49 +++++++++++++++- > drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.h | 33 ++++++++++- > 4 files changed, 164 insertions(+), 4 deletions(-) > > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c > index bf51341..156a997 100644 > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c > @@ -9,6 +9,7 @@ > #include <linux/sort.h> > #include <linux/debugfs.h> > #include <linux/ktime.h> > +#include <linux/bits.h> > > #include <drm/drm_crtc.h> > #include <drm/drm_flip_work.h> > @@ -20,6 +21,7 @@ > #include "dpu_kms.h" > #include "dpu_hw_lm.h" > #include "dpu_hw_ctl.h" > +#include "dpu_hw_dspp.h" > #include "dpu_crtc.h" > #include "dpu_plane.h" > #include "dpu_encoder.h" > @@ -40,6 +42,9 @@ > /* timeout in ms waiting for frame done */ > #define DPU_CRTC_FRAME_DONE_TIMEOUT_MS 60 > > +#define CONVERT_S3_15(val) \ > + (((((u64)val) & ~BIT_ULL(63)) >> 17) & GENMASK_ULL(17, 0)) > + > static struct dpu_kms *_dpu_crtc_get_kms(struct drm_crtc *crtc) > { > struct msm_drm_private *priv = crtc->dev->dev_private; > @@ -422,6 +427,74 @@ static void _dpu_crtc_setup_lm_bounds(struct drm_crtc *crtc, > drm_mode_debug_printmodeline(adj_mode); > } > > +static void _dpu_crtc_get_pcc_coeff(struct drm_crtc_state *state, > + struct dpu_hw_pcc_cfg *cfg) > +{ > + struct drm_color_ctm *ctm; > + > + memset(cfg, 0, sizeof(struct dpu_hw_pcc_cfg)); > + > + ctm = (struct drm_color_ctm *)state->ctm->data; > + > + if (!ctm) > + return; > + > + cfg->r.r = CONVERT_S3_15(ctm->matrix[0]); > + cfg->g.r = CONVERT_S3_15(ctm->matrix[1]); > + cfg->b.r = CONVERT_S3_15(ctm->matrix[2]); > + > + cfg->r.g = CONVERT_S3_15(ctm->matrix[3]); > + cfg->g.g = CONVERT_S3_15(ctm->matrix[4]); > + cfg->b.g = CONVERT_S3_15(ctm->matrix[5]); > + > + cfg->r.b = CONVERT_S3_15(ctm->matrix[6]); > + cfg->g.b = CONVERT_S3_15(ctm->matrix[7]); > + cfg->b.b = CONVERT_S3_15(ctm->matrix[8]); > +} > + > +static void _dpu_crtc_setup_cp_blocks(struct drm_crtc *crtc) > +{ > + struct drm_crtc_state *state = crtc->state; > + struct dpu_crtc_state *cstate = to_dpu_crtc_state(crtc->state); > + struct dpu_crtc_mixer *mixer = cstate->mixers; > + struct dpu_hw_pcc_cfg cfg; > + struct dpu_hw_ctl *ctl; > + struct dpu_hw_mixer *lm; > + struct dpu_hw_dspp *dspp; > + int i; > + > + > + if (!state->color_mgmt_changed) > + return; > + > + for (i = 0; i < cstate->num_mixers; i++) { > + ctl = mixer[i].lm_ctl; > + lm = mixer[i].hw_lm; > + dspp = mixer[i].hw_dspp; > + > + if (!dspp || !dspp->ops.setup_pcc) > + continue; > + > + if (!state->ctm) { > + dspp->ops.setup_pcc(dspp, NULL); > + } else { > + _dpu_crtc_get_pcc_coeff(state, &cfg); > + dspp->ops.setup_pcc(dspp, &cfg); > + } > + > + mixer[i].flush_mask |= ctl->ops.get_bitmask_dspp(ctl, > + mixer[i].hw_dspp->idx); > + > + /* stage config flush mask */ > + ctl->ops.update_pending_flush(ctl, mixer[i].flush_mask); > + > + DPU_DEBUG("lm %d, ctl %d, flush mask 0x%x\n", > + mixer[i].hw_lm->idx - DSPP_0, > + ctl->idx - CTL_0, > + mixer[i].flush_mask); > + } > +} > + > static void dpu_crtc_atomic_begin(struct drm_crtc *crtc, > struct drm_crtc_state *old_state) > { > @@ -475,6 +548,8 @@ static void dpu_crtc_atomic_begin(struct drm_crtc *crtc, > > _dpu_crtc_blend_setup(crtc); > > + _dpu_crtc_setup_cp_blocks(crtc); > + > /* > * PP_DONE irq is only used by command mode for now. > * It is better to request pending before FLUSH and START trigger > @@ -1317,6 +1392,8 @@ struct drm_crtc *dpu_crtc_init(struct drm_device *dev, struct drm_plane *plane, > > drm_crtc_helper_add(crtc, &dpu_crtc_helper_funcs); > > + drm_crtc_enable_color_mgmt(crtc, 0, true, 0); > + > /* save user friendly CRTC name for later */ > snprintf(dpu_crtc->name, DPU_CRTC_NAME_SIZE, "crtc%u", crtc->base.id); > > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c > index 19d065a..731b4fb 100644 > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c > @@ -41,7 +41,7 @@ > #define PINGPONG_SDM845_SPLIT_MASK \ > (PINGPONG_SDM845_MASK | BIT(DPU_PINGPONG_TE2)) > > -#define DSPP_SC7180_MASK 0 > +#define DSPP_SC7180_MASK BIT(DPU_DSPP_PCC) > > #define DEFAULT_PIXEL_RAM_SIZE (50 * 1024) > #define DEFAULT_DPU_LINE_WIDTH 2048 > @@ -339,12 +339,17 @@ > /************************************************************* > * DSPP sub blocks config > *************************************************************/ > +static const struct dpu_dspp_sub_blks sc7180_dspp_sblk = { > + .pcc = {.id = DPU_DSPP_PCC, .base = 0x1700, > + .len = 0x90, .version = 0x10000}, > +}; > + > #define DSPP_BLK(_name, _id, _base) \ > {\ > .name = _name, .id = _id, \ > .base = _base, .len = 0x1800, \ > .features = DSPP_SC7180_MASK, \ > - .sblk = NULL, \ > + .sblk = &sc7180_dspp_sblk \ > } > > static const struct dpu_dspp_cfg sc7180_dspp[] = { > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.c > index 75c82e9..b5189ce 100644 > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.c > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.c > @@ -9,10 +9,57 @@ > #include "dpu_kms.h" > > > +/* DSPP_PCC */ > +#define PCC_EN BIT(0) > +#define PCC_DIS 0 > +#define PCC_RED_R_OFF 0x10 > +#define PCC_RED_G_OFF 0x1C > +#define PCC_RED_B_OFF 0x28 > +#define PCC_GREEN_R_OFF 0x14 > +#define PCC_GREEN_G_OFF 0x20 > +#define PCC_GREEN_B_OFF 0x2C > +#define PCC_BLUE_R_OFF 0x18 > +#define PCC_BLUE_G_OFF 0x24 > +#define PCC_BLUE_B_OFF 0x30 > + > +void dpu_setup_dspp_pcc(struct dpu_hw_dspp *ctx, > + struct dpu_hw_pcc_cfg *cfg) > +{ > + > + u32 base = ctx->cap->sblk->pcc.base; > + > + if (!ctx || !base) { > + DRM_ERROR("invalid ctx %pK pcc base 0x%x\n", ctx, base); > + return; > + } > + > + if (!cfg) { > + DRM_DEBUG_DRIVER("disable pcc feature\n"); > + DPU_REG_WRITE(&ctx->hw, base, PCC_DIS); > + return; > + } > + > + DPU_REG_WRITE(&ctx->hw, base + PCC_RED_R_OFF, cfg->r.r); > + DPU_REG_WRITE(&ctx->hw, base + PCC_RED_G_OFF, cfg->r.g); > + DPU_REG_WRITE(&ctx->hw, base + PCC_RED_B_OFF, cfg->r.b); > + > + DPU_REG_WRITE(&ctx->hw, base + PCC_GREEN_R_OFF, cfg->g.r); > + DPU_REG_WRITE(&ctx->hw, base + PCC_GREEN_G_OFF, cfg->g.g); > + DPU_REG_WRITE(&ctx->hw, base + PCC_GREEN_B_OFF, cfg->g.b); > + > + DPU_REG_WRITE(&ctx->hw, base + PCC_BLUE_R_OFF, cfg->b.r); > + DPU_REG_WRITE(&ctx->hw, base + PCC_BLUE_G_OFF, cfg->b.g); > + DPU_REG_WRITE(&ctx->hw, base + PCC_BLUE_B_OFF, cfg->b.b); > + > + DPU_REG_WRITE(&ctx->hw, base, PCC_EN); > +} > + > static void _setup_dspp_ops(struct dpu_hw_dspp *c, > unsigned long features) > { > - return; > + if (test_bit(DPU_DSPP_PCC, &features) && > + IS_SC7180_TARGET(c->hw.hwversion)) > + c->ops.setup_pcc = dpu_setup_dspp_pcc; > } > > static const struct dpu_dspp_cfg *_dspp_offset(enum dpu_dspp dspp, > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.h > index 09807ea..7fa189c 100644 > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.h > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.h > @@ -10,13 +10,44 @@ > struct dpu_hw_dspp; > > /** > + * struct dpu_hw_pcc_coeff - PCC coefficient structure for each color > + * component. > + * @r: red coefficient. > + * @g: green coefficient. > + * @b: blue coefficient. > + */ > + > +struct dpu_hw_pcc_coeff { > + __u32 r; > + __u32 g; > + __u32 b; > +}; > + > +/** > + * struct dpu_hw_pcc - pcc feature structure > + * @r: red coefficients. > + * @g: green coefficients. > + * @b: blue coefficients. > + */ > +struct dpu_hw_pcc_cfg { > + struct dpu_hw_pcc_coeff r; > + struct dpu_hw_pcc_coeff g; > + struct dpu_hw_pcc_coeff b; > +}; > + > +/** > * struct dpu_hw_dspp_ops - interface to the dspp hardware driver functions > * Caller must call the init function to get the dspp context for each dspp > * Assumption is these functions will be called after clocks are enabled > */ > struct dpu_hw_dspp_ops { > + /** > + * setup_pcc - setup dspp pcc > + * @ctx: Pointer to dspp context > + * @cfg: Pointer to configuration > + */ > + void (*setup_pcc)(struct dpu_hw_dspp *ctx, struct dpu_hw_pcc_cfg *cfg); > > - void (*dummy)(struct dpu_hw_dspp *ctx); > }; > > /** > -- > 1.9.1 > > _______________________________________________ > dri-devel mailing list > dri-devel@xxxxxxxxxxxxxxxxxxxxx > https://lists.freedesktop.org/mailman/listinfo/dri-devel