diff --git a/include/uapi/display/drm/msm_drm_pp.h b/include/uapi/display/drm/msm_drm_pp.h index 3fc2e40b3c..2fd9e6d352 100644 --- a/include/uapi/display/drm/msm_drm_pp.h +++ b/include/uapi/display/drm/msm_drm_pp.h @@ -775,4 +775,11 @@ struct drm_msm_misr_sign { __u64 misr_sign_value[MAX_DSI_DISPLAY]; }; +#define UCSC_SUPPORTED + +#define UCSC_CSC_CFG0_PARAM_LEN FP16_CSC_CFG0_PARAM_LEN +#define UCSC_CSC_CFG1_PARAM_LEN FP16_CSC_CFG1_PARAM_LEN + +typedef struct drm_msm_fp16_csc drm_msm_ucsc_csc; + #endif /* _MSM_DRM_PP_H_ */ diff --git a/msm/msm_drv.h b/msm/msm_drv.h index 1f7be9ffd3..4286b764f9 100644 --- a/msm/msm_drv.h +++ b/msm/msm_drv.h @@ -124,6 +124,7 @@ enum msm_mdp_plane_property { PLANE_PROP_FP16_GC, PLANE_PROP_FP16_CSC, PLANE_PROP_UBWC_STATS_ROI, + PLANE_PROP_UCSC_CSC, /* # of blob properties */ PLANE_PROP_BLOBCOUNT, @@ -147,12 +148,17 @@ enum msm_mdp_plane_property { PLANE_PROP_INVERSE_PMA, PLANE_PROP_FP16_IGC, PLANE_PROP_FP16_UNMULT, + PLANE_PROP_UCSC_UNMULT, + PLANE_PROP_UCSC_ALPHA_DITHER, /* enum/bitmask properties */ PLANE_PROP_BLEND_OP, PLANE_PROP_SRC_CONFIG, PLANE_PROP_FB_TRANSLATION_MODE, PLANE_PROP_MULTIRECT_MODE, + PLANE_PROP_UCSC_IGC, + PLANE_PROP_UCSC_GC, + /* total # of properties */ PLANE_PROP_COUNT diff --git a/msm/sde/sde_hw_catalog.c b/msm/sde/sde_hw_catalog.c index 592bf0eb06..61e9b75a8b 100644 --- a/msm/sde/sde_hw_catalog.c +++ b/msm/sde/sde_hw_catalog.c @@ -298,6 +298,11 @@ enum { VIG_FP16_GC_PROP, VIG_FP16_CSC_PROP, VIG_FP16_UNMULT_PROP, + VIG_UCSC_IGC_PROP, + VIG_UCSC_GC_PROP, + VIG_UCSC_CSC_PROP, + VIG_UCSC_UNMULT_PROP, + VIG_UCSC_ALPHA_DITHER_PROP, VIG_PROP_MAX, }; @@ -312,6 +317,11 @@ enum { DMA_FP16_GC_PROP, DMA_FP16_CSC_PROP, DMA_FP16_UNMULT_PROP, + DMA_UCSC_IGC_PROP, + DMA_UCSC_GC_PROP, + DMA_UCSC_CSC_PROP, + DMA_UCSC_UNMULT_PROP, + DMA_UCSC_ALPHA_DITHER_PROP, DMA_PROP_MAX, }; @@ -731,6 +741,16 @@ static struct sde_prop_type vig_prop[] = { PROP_TYPE_U32_ARRAY}, [VIG_FP16_UNMULT_PROP] = {VIG_FP16_UNMULT_PROP, "qcom,sde-fp16-unmult", false, PROP_TYPE_U32_ARRAY}, + [VIG_UCSC_IGC_PROP] = {VIG_UCSC_IGC_PROP, "qcom,sde-ucsc-igc", false, + PROP_TYPE_U32_ARRAY}, + [VIG_UCSC_GC_PROP] = {VIG_UCSC_GC_PROP, "qcom,sde-ucsc-gc", false, + PROP_TYPE_U32_ARRAY}, + [VIG_UCSC_CSC_PROP] = {VIG_UCSC_CSC_PROP, "qcom,sde-ucsc-csc", false, + PROP_TYPE_U32_ARRAY}, + [VIG_UCSC_UNMULT_PROP] = {VIG_UCSC_UNMULT_PROP, "qcom,sde-ucsc-unmult", + false, PROP_TYPE_U32_ARRAY}, + [VIG_UCSC_ALPHA_DITHER_PROP] = {VIG_UCSC_ALPHA_DITHER_PROP, "qcom,sde-ucsc-alpha-dither", + false, PROP_TYPE_U32_ARRAY}, }; static struct sde_prop_type dma_prop[] = { @@ -754,6 +774,16 @@ static struct sde_prop_type dma_prop[] = { PROP_TYPE_U32_ARRAY}, [DMA_FP16_UNMULT_PROP] = {DMA_FP16_UNMULT_PROP, "qcom,sde-fp16-unmult", false, PROP_TYPE_U32_ARRAY}, + [DMA_UCSC_IGC_PROP] = {DMA_UCSC_IGC_PROP, "qcom,sde-ucsc-igc", false, + PROP_TYPE_U32_ARRAY}, + [DMA_UCSC_GC_PROP] = {DMA_UCSC_GC_PROP, "qcom,sde-ucsc-gc", false, + PROP_TYPE_U32_ARRAY}, + [DMA_UCSC_CSC_PROP] = {DMA_UCSC_CSC_PROP, "qcom,sde-ucsc-csc", false, + PROP_TYPE_U32_ARRAY}, + [DMA_UCSC_UNMULT_PROP] = {DMA_UCSC_UNMULT_PROP, "qcom,sde-ucsc-unmult", + false, PROP_TYPE_U32_ARRAY}, + [DMA_UCSC_ALPHA_DITHER_PROP] = {DMA_UCSC_ALPHA_DITHER_PROP, "qcom,sde-ucsc-alpha-dither", + false, PROP_TYPE_U32_ARRAY}, }; static struct sde_prop_type ctl_prop[] = { @@ -1558,6 +1588,12 @@ static int _sde_sspp_setup_vigs(struct device_node *np, sblk->num_fp16_csc_blk = 0; sblk->num_fp16_unmult_blk = 0; + sblk->num_ucsc_igc_blk = 0; + sblk->num_ucsc_gc_blk = 0; + sblk->num_ucsc_csc_blk = 0; + sblk->num_ucsc_unmult_blk = 0; + sblk->num_ucsc_alpha_dither_blk = 0; + for (j = 0; j < SSPP_SUBBLK_COUNT_MAX; j++) { if (!props[j]) continue; @@ -1589,6 +1625,41 @@ static int _sde_sspp_setup_vigs(struct device_node *np, SDE_SSPP_FP16_UNMULT, VIG_FP16_UNMULT_PROP, true)) sblk->num_fp16_unmult_blk += 1; + + if (_sde_sspp_setup_vcm(sspp, props[j], + "sspp_vig_ucsc_igc", + &sblk->ucsc_igc_blk[j], + SDE_SSPP_UCSC_IGC, VIG_UCSC_IGC_PROP, + true)) + sblk->num_ucsc_igc_blk += 1; + + if (_sde_sspp_setup_vcm(sspp, props[j], + "sspp_vig_ucsc_gc", + &sblk->ucsc_gc_blk[j], + SDE_SSPP_UCSC_GC, VIG_UCSC_GC_PROP, + true)) + sblk->num_ucsc_gc_blk += 1; + + if (_sde_sspp_setup_vcm(sspp, props[j], + "sspp_vig_ucsc_csc", + &sblk->ucsc_csc_blk[j], + SDE_SSPP_UCSC_CSC, VIG_UCSC_CSC_PROP, + true)) + sblk->num_ucsc_csc_blk += 1; + + if (_sde_sspp_setup_vcm(sspp, props[j], + "sspp_vig_ucsc_unmult", + &sblk->ucsc_unmult_blk[j], + SDE_SSPP_UCSC_UNMULT, + VIG_UCSC_UNMULT_PROP, true)) + sblk->num_ucsc_unmult_blk += 1; + + if (_sde_sspp_setup_vcm(sspp, props[j], + "sspp_vig_ucsc_alpha_dither", + &sblk->ucsc_alpha_dither_blk[j], + SDE_SSPP_UCSC_ALPHA_DITHER, + VIG_UCSC_ALPHA_DITHER_PROP, true)) + sblk->num_ucsc_alpha_dither_blk += 1; } /* PP + scaling only supported on VIG rect 0 */ @@ -1804,6 +1875,41 @@ static int _sde_sspp_setup_dmas(struct device_node *np, &sblk->fp16_unmult_blk[j], SDE_SSPP_FP16_UNMULT, DMA_FP16_UNMULT_PROP, true); + + if (props[j]->exists[DMA_UCSC_IGC_PROP]) + _sde_sspp_setup_dgm(sspp, props[j], + "sspp_dma_ucsc_igc", + &sblk->ucsc_igc_blk[j], + SDE_SSPP_UCSC_IGC, + DMA_UCSC_IGC_PROP, true); + + if (props[j]->exists[DMA_UCSC_GC_PROP]) + _sde_sspp_setup_dgm(sspp, props[j], + "sspp_dma_ucsc_gc", + &sblk->ucsc_gc_blk[j], + SDE_SSPP_UCSC_GC, + DMA_UCSC_GC_PROP, true); + + if (props[j]->exists[DMA_UCSC_CSC_PROP]) + _sde_sspp_setup_dgm(sspp, props[j], + "sspp_dma_ucsc_csc", + &sblk->ucsc_csc_blk[j], + SDE_SSPP_UCSC_CSC, + DMA_UCSC_CSC_PROP, true); + + if (props[j]->exists[DMA_UCSC_UNMULT_PROP]) + _sde_sspp_setup_dgm(sspp, props[j], + "sspp_dma_ucsc_unmult", + &sblk->ucsc_unmult_blk[j], + SDE_SSPP_UCSC_UNMULT, + DMA_UCSC_UNMULT_PROP, true); + + if (props[j]->exists[DMA_UCSC_ALPHA_DITHER_PROP]) + _sde_sspp_setup_dgm(sspp, props[j], + "sspp_dma_ucsc_alpha_dither", + &sblk->ucsc_alpha_dither_blk[j], + SDE_SSPP_UCSC_ALPHA_DITHER, + DMA_UCSC_ALPHA_DITHER_PROP, true); } } diff --git a/msm/sde/sde_hw_catalog.h b/msm/sde/sde_hw_catalog.h index 84cb0efd0a..dc04d15017 100644 --- a/msm/sde/sde_hw_catalog.h +++ b/msm/sde/sde_hw_catalog.h @@ -317,6 +317,11 @@ enum { * @SDE_SSPP_UBWC_STATS: Support for ubwc stats * @SDE_SSPP_SCALER_DE_LPF_BLEND: Support for detail enhancer * @SDE_SSPP_LINE_INSERTION Line insertion support + * @SDE_SSPP_UCSC_IGC UCSC IGC color processing block support + * @SDE_SSPP_UCSC_GC UCSC GC color processing block support + * @SDE_SSPP_UCSC_CSC UCSC CSC color processing block support + * @SDE_SSPP_UCSC_UNMULT UCSC alpha unmult color processing block support + * @SDE_SSPP_UCSC_ALPHA_DITHER UCSC alpha dither color processing block support * @SDE_SSPP_MAX maximum value */ enum { @@ -354,6 +359,11 @@ enum { SDE_SSPP_UBWC_STATS, SDE_SSPP_SCALER_DE_LPF_BLEND, SDE_SSPP_LINE_INSERTION, + SDE_SSPP_UCSC_IGC, + SDE_SSPP_UCSC_GC, + SDE_SSPP_UCSC_CSC, + SDE_SSPP_UCSC_UNMULT, + SDE_SSPP_UCSC_ALPHA_DITHER, SDE_SSPP_MAX }; @@ -742,6 +752,7 @@ enum { * @SDE_FEATURE_SYS_CACHE_NSE Support for no-self-evict feature * @SDE_FEATURE_HW_FENCE_IPCC HW fence supports ipcc signaling in dpu * @SDE_FEATURE_EMULATED_ENV Emulated environment supported + * @SDE_FEATURE_UCSC_SUPPORTED UCSC pipe format supported * @SDE_FEATURE_MAX: MAX features value */ enum sde_mdss_features { @@ -786,6 +797,7 @@ enum sde_mdss_features { SDE_FEATURE_SYS_CACHE_NSE, SDE_FEATURE_HW_FENCE_IPCC, SDE_FEATURE_EMULATED_ENV, + SDE_FEATURE_UCSC_SUPPORTED, SDE_FEATURE_MAX }; @@ -969,6 +981,16 @@ enum sde_danger_safe_lut_types { * @fp16_csc_blk: FP16 CSC block array * @num_fp16_unmult_blk: number of FP16 UNMULT blocks * @fp16_unmult_blk: FP16 UNMULT block array + * @num_ucsc_igc_blk: number of UCSC IGC blocks + * @ucsc_igc_blk: UCSC IGC block array + * @num_ucsc_gc_blk: number of UCSC GC blocks + * @ucsc_gc_blk: UCSC GC block array + * @num_ucsc_csc_blk: number of UCSC CSC blocks + * @ucsc_csc_blk: UCSC CSC block array + * @num_ucsc_unmult_blk: number of ucsc UNMULT blocks + * @ucsc_unmult_blk: UCSC UNMULT block array + * @num_ucsc_alpha_dither_blk: number of ucsc ALPHA DITHER blocks + * @ucsc_alpha_dither_blk: UCSC ALPHA DITHER block array * @unmult_offset: Unmult register offset * @format_list: Pointer to list of supported formats * @virt_format_list: Pointer to list of supported formats for virtual planes @@ -1021,6 +1043,16 @@ struct sde_sspp_sub_blks { struct sde_pp_blk fp16_csc_blk[SSPP_SUBBLK_COUNT_MAX]; u32 num_fp16_unmult_blk; struct sde_pp_blk fp16_unmult_blk[SSPP_SUBBLK_COUNT_MAX]; + u32 num_ucsc_igc_blk; + struct sde_pp_blk ucsc_igc_blk[SSPP_SUBBLK_COUNT_MAX]; + u32 num_ucsc_gc_blk; + struct sde_pp_blk ucsc_gc_blk[SSPP_SUBBLK_COUNT_MAX]; + u32 num_ucsc_csc_blk; + struct sde_pp_blk ucsc_csc_blk[SSPP_SUBBLK_COUNT_MAX]; + u32 num_ucsc_unmult_blk; + struct sde_pp_blk ucsc_unmult_blk[SSPP_SUBBLK_COUNT_MAX]; + u32 num_ucsc_alpha_dither_blk; + struct sde_pp_blk ucsc_alpha_dither_blk[SSPP_SUBBLK_COUNT_MAX]; u32 unmult_offset[SSPP_SUBBLK_COUNT_MAX]; const struct sde_format_extended *format_list; diff --git a/msm/sde/sde_hw_color_proc_v4.c b/msm/sde/sde_hw_color_proc_v4.c index a1f429e2d5..fb70f3273d 100644 --- a/msm/sde/sde_hw_color_proc_v4.c +++ b/msm/sde/sde_hw_color_proc_v4.c @@ -759,3 +759,286 @@ int sde_spr_read_opr_value(struct sde_hw_dspp *ctx, uint32_t *opr_value) return 0; } + +void sde_setup_ucsc_cscv1(struct sde_hw_pipe *ctx, + enum sde_sspp_multirect_index index, void *data) +{ + struct sde_hw_cp_cfg *hw_cfg = data; + drm_msm_ucsc_csc *ucsc_csc; + u32 csc_base, csc, i, offset = 0; + + if (!ctx || !data || index == SDE_SSPP_RECT_MAX) { + DRM_ERROR("invalid parameter\tctx: %pK\tdata: %pK\tindex: %d\n", + ctx, data, index); + return; + } + + if (index == SDE_SSPP_RECT_SOLO || index == SDE_SSPP_RECT_0) + csc_base = ctx->cap->sblk->ucsc_csc_blk[0].base; + else + csc_base = ctx->cap->sblk->ucsc_csc_blk[1].base; + + if (!csc_base) { + DRM_ERROR("invalid offset for UCSC CSC CP block\tpipe: %d\tindex: %d\n", + ctx->idx, index); + return; + } + + ucsc_csc = (drm_msm_ucsc_csc *)(hw_cfg->payload); + if (!ucsc_csc) + goto write_base; + + if (hw_cfg->len != sizeof(drm_msm_ucsc_csc) || + !hw_cfg->payload) { + DRM_ERROR("invalid hw_cfg payload\tpipe: %d\tindex: %d\tlen: %d\tpayload: %pK\n", + ctx->idx, index, hw_cfg->len, hw_cfg->payload); + return; + } + + if (ucsc_csc->cfg_param_0_len != UCSC_CSC_CFG0_PARAM_LEN) { + DRM_ERROR("invalid param 0 length! Got: %d\tExpected: %d\tpipe: %d\tindex: %d\n", + ucsc_csc->cfg_param_0_len, UCSC_CSC_CFG0_PARAM_LEN, + ctx->idx, index); + return; + } else if (ucsc_csc->cfg_param_1_len != UCSC_CSC_CFG1_PARAM_LEN) { + DRM_ERROR("invalid param 1 length! Got: %d\tExpected: %d\tpipe: %d\tindex: %d\n", + ucsc_csc->cfg_param_1_len, UCSC_CSC_CFG1_PARAM_LEN, + ctx->idx, index); + return; + } + + for (i = 0; i < (ucsc_csc->cfg_param_0_len / 2); i++) { + offset += 0x4; + csc = ucsc_csc->cfg_param_0[2 * i] & 0xFFFF; + csc |= (ucsc_csc->cfg_param_0[2 * i + 1] & 0xFFFF) << 16; + SDE_REG_WRITE(&ctx->hw, csc_base + offset, csc); + } + for (i = 0; i < (ucsc_csc->cfg_param_1_len / 2); i++) { + offset += 0x4; + csc = ucsc_csc->cfg_param_1[2 * i] & 0xFFFF; + csc |= (ucsc_csc->cfg_param_1[2 * i + 1] & 0xFFFF) << 16; + SDE_REG_WRITE(&ctx->hw, csc_base + offset, csc); + } + +write_base: + csc = SDE_REG_READ(&ctx->hw, csc_base); + if (ucsc_csc) + csc |= BIT(2); + else + csc &= ~BIT(2); + + SDE_REG_WRITE(&ctx->hw, csc_base, csc); +} + +void sde_setup_ucsc_gcv1(struct sde_hw_pipe *ctx, + enum sde_sspp_multirect_index index, void *data) +{ + struct sde_hw_cp_cfg *hw_cfg = data; + int *ucsc_gc; + u32 gc_base, gc; + + if (!ctx || !data || index == SDE_SSPP_RECT_MAX) { + DRM_ERROR("invalid parameter\tctx: %pK\tdata: %pK\tindex: %d\n", + ctx, data, index); + return; + } + + if (index == SDE_SSPP_RECT_SOLO || index == SDE_SSPP_RECT_0) + gc_base = ctx->cap->sblk->ucsc_gc_blk[0].base; + else + gc_base = ctx->cap->sblk->ucsc_gc_blk[1].base; + + if (!gc_base) { + DRM_ERROR("invalid offset for UCSC GC CP block\tpipe: %d\tindex: %d\n", + ctx->idx, index); + return; + } + + ucsc_gc = (int *)(hw_cfg->payload); + + if (!ucsc_gc || (hw_cfg->len != sizeof(int))) { + DRM_ERROR("invalid hw_cfg payload\tpipe: %d\tindex: %d\tlen: %d\tpayload: %pK\n", + ctx->idx, index, hw_cfg->len, ucsc_gc); + return; + } + + gc = SDE_REG_READ(&ctx->hw, gc_base); + gc &= 0x60707; + + if (*ucsc_gc == UCSC_GC_MODE_DISABLE) { + DRM_INFO("UCSC GC is not enabled!\n"); + goto reset_gc; + } + + if (ucsc_gc && *ucsc_gc) { + gc |= BIT(4); + + switch (*ucsc_gc) + { + case UCSC_GC_MODE_SRGB: + break; + case UCSC_GC_MODE_PQ: + gc |= BIT(5); + break; + case UCSC_GC_MODE_GAMMA2_2: + gc |= BIT(6); + break; + case UCSC_GC_MODE_HLG: + gc |= BIT(5)|BIT(6); + break; + default: + DRM_ERROR("Invalid UCSC GC mode \tmode: %d\n", *ucsc_gc); + return; + } + } + +reset_gc: + SDE_REG_WRITE(&ctx->hw, gc_base, gc); +} + +void sde_setup_ucsc_igcv1(struct sde_hw_pipe *ctx, + enum sde_sspp_multirect_index index, void *data) +{ + struct sde_hw_cp_cfg *hw_cfg = data; + int *ucsc_igc; + u32 igc_base, igc; + + if (!ctx || !data || index == SDE_SSPP_RECT_MAX) { + DRM_ERROR("invalid parameter\tctx: %pK\tdata: %pK\tindex: %d\n", + ctx, data, index); + return; + } + + if (index == SDE_SSPP_RECT_SOLO || index == SDE_SSPP_RECT_0) + igc_base = ctx->cap->sblk->ucsc_igc_blk[0].base; + else + igc_base = ctx->cap->sblk->ucsc_igc_blk[1].base; + + if (!igc_base) { + DRM_ERROR("invalid offset for UCSC GC CP block\tpipe: %d\tindex: %d\n", + ctx->idx, index); + return; + } + + ucsc_igc = (int *)(hw_cfg->payload); + + if (!ucsc_igc || (hw_cfg->len != sizeof(int))) { + DRM_ERROR("invalid hw_cfg payload\tpipe: %d\tindex: %d\tlen: %d\tpayload: %pK\n", + ctx->idx, index, hw_cfg->len, ucsc_igc); + return; + } + + igc = SDE_REG_READ(&ctx->hw, igc_base); + igc &= 0x600FD; + + if (*ucsc_igc == UCSC_IGC_MODE_DISABLE) { + DRM_INFO("UCSC IGC is not enabled!\n"); + goto reset_igc; + } + + if (ucsc_igc && *ucsc_igc) { + igc |= BIT(1); + + switch (*ucsc_igc) + { + case UCSC_IGC_MODE_SRGB: + break; + case UCSC_IGC_MODE_REC709: + igc |= BIT(8); + break; + case UCSC_IGC_MODE_GAMMA2_2: + igc |= BIT(9); + break; + case UCSC_IGC_MODE_HLG: + igc |= BIT(8)|BIT(9); + break; + case UCSC_IGC_MODE_PQ: + igc |= BIT(10); + break; + default: + DRM_ERROR("Invalid UCSC IGC mode \tmode: %d\n", *ucsc_igc); + return; + } + } + +reset_igc: + SDE_REG_WRITE(&ctx->hw, igc_base, igc); +} + +void sde_setup_ucsc_unmultv1(struct sde_hw_pipe *ctx, + enum sde_sspp_multirect_index index, void *data) +{ + struct sde_hw_cp_cfg *hw_cfg = data; + bool *ucsc_unmult; + u32 unmult_base, unmult; + + if (!ctx || !data || index == SDE_SSPP_RECT_MAX) { + DRM_ERROR("invalid parameter\tctx: %pK\tdata: %pK\tindex: %d\n", + ctx, data, index); + return; + } else if (hw_cfg->len != sizeof(bool) || !hw_cfg->payload) { + DRM_ERROR("invalid hw_cfg payload\tpipe: %d\tindex: %d\tlen: %d\tpayload: %pK\n", + ctx->idx, index, hw_cfg->len, hw_cfg->payload); + return; + } + + if (index == SDE_SSPP_RECT_SOLO || index == SDE_SSPP_RECT_0) + unmult_base = ctx->cap->sblk->ucsc_unmult_blk[0].base; + else + unmult_base = ctx->cap->sblk->ucsc_unmult_blk[1].base; + + if (!unmult_base) { + DRM_ERROR("invalid offset for UCSC UNMULT CP block\tpipe: %d\tindex: %d\n", + ctx->idx, index); + return; + } + + unmult = SDE_REG_READ(&ctx->hw, unmult_base); + ucsc_unmult = (bool *)(hw_cfg->payload); + + if (ucsc_unmult && *ucsc_unmult) + unmult |= BIT(0)|BIT(18); + else + unmult &= ~(BIT(0)|BIT(18)); + + SDE_REG_WRITE(&ctx->hw, unmult_base, unmult); +} + +void sde_setup_ucsc_alpha_ditherv1(struct sde_hw_pipe *ctx, + enum sde_sspp_multirect_index index, void *data) +{ + struct sde_hw_cp_cfg *hw_cfg = data; + bool *ucsc_alpha_dither; + u32 alpha_dither_base, alpha_dither; + + if (!ctx || index == SDE_SSPP_RECT_MAX) { + DRM_ERROR("invalid parameter\tctx: %pK\tindex: %d\n", + ctx, index); + return; + } else if (hw_cfg->len != sizeof(bool) || !hw_cfg->payload) { + DRM_ERROR("invalid hw_cfg payload\tpipe: %d\tindex: %d\tlen: %d\tpayload: %pK\n", + ctx->idx, index, hw_cfg->len, hw_cfg->payload); + return; + } + + if (index == SDE_SSPP_RECT_SOLO || index == SDE_SSPP_RECT_0) + alpha_dither_base = ctx->cap->sblk->ucsc_alpha_dither_blk[0].base; + else + alpha_dither_base = ctx->cap->sblk->ucsc_alpha_dither_blk[1].base; + + if (!alpha_dither_base) { + DRM_ERROR("invalid offset for UCSC ALPHA DITHER CP block\tpipe: %d\tindex: %d\n", + ctx->idx, index); + return; + } + + alpha_dither = SDE_REG_READ(&ctx->hw, alpha_dither_base); + ucsc_alpha_dither = (bool *)(hw_cfg->payload); + + if (ucsc_alpha_dither && *ucsc_alpha_dither) + alpha_dither |= BIT(17); + else + alpha_dither &= ~BIT(17); + + SDE_REG_WRITE(&ctx->hw, alpha_dither_base, alpha_dither); +} diff --git a/msm/sde/sde_hw_color_proc_v4.h b/msm/sde/sde_hw_color_proc_v4.h index 0a1c1839b3..62bbdf70c6 100644 --- a/msm/sde/sde_hw_color_proc_v4.h +++ b/msm/sde/sde_hw_color_proc_v4.h @@ -161,4 +161,49 @@ void sde_demura_pu_cfg(struct sde_hw_dspp *ctx, void *cfg); */ int sde_spr_read_opr_value(struct sde_hw_dspp *ctx, uint32_t *opr_value); +/** + * sde_setup_ucsc_cscv1 - api to set UCSC CSC cp block + * @ctx: pointer to pipe object + * @index: pipe rectangle to operate on + * @data: pointer to sde_hw_cp_cfg object containing drm_msm_ucsc_csc data + */ +void sde_setup_ucsc_cscv1(struct sde_hw_pipe *ctx, + enum sde_sspp_multirect_index index, void *data); + +/** + * sde_setup_ucsc_gcv1 - api to set UCSC GC cp block + * @ctx: pointer to pipe object + * @index: pipe rectangle to operate on + * @data: pointer to sde_hw_cp_cfg object containing gc mode data + */ +void sde_setup_ucsc_gcv1(struct sde_hw_pipe *ctx, + enum sde_sspp_multirect_index index, void *data); + +/** + * sde_setup_ucsc_igcv1 - api to set UCSC IGC cp block + * @ctx: pointer to pipe object + * @index: pipe rectangle to operate on + * @data: pointer to sde_hw_cp_cfg object containing igc mode data + */ +void sde_setup_ucsc_igcv1(struct sde_hw_pipe *ctx, + enum sde_sspp_multirect_index index, void *data); + +/** + * sde_setup_ucsc_unmultv1 - api to set UCSC UNMULT cp block + * @ctx: pointer to pipe object + * @index: pipe rectangle to operate on + * @data: pointer to sde_hw_cp_cfg object containing bool data + */ +void sde_setup_ucsc_unmultv1(struct sde_hw_pipe *ctx, + enum sde_sspp_multirect_index index, void *data); + +/** + * sde_setup_ucsc_alpha_ditherv1 - api to set UCSC ALPHA DITHER cp block + * @ctx: pointer to pipe object + * @index: pipe rectangle to operate on + * @data: pointer to sde_hw_cp_cfg object containing bool data + */ +void sde_setup_ucsc_alpha_ditherv1(struct sde_hw_pipe *ctx, + enum sde_sspp_multirect_index index, void *data); + #endif /* _SDE_HW_COLOR_PROC_V4_H_ */ diff --git a/msm/sde/sde_hw_sspp.c b/msm/sde/sde_hw_sspp.c index 2aafb8ea5e..dd6c4ef785 100644 --- a/msm/sde/sde_hw_sspp.c +++ b/msm/sde/sde_hw_sspp.c @@ -59,6 +59,7 @@ #define SSPP_DGM_CSC_1 0x1800 #define SSPP_DGM_CSC_SIZE 0xFC #define VIG_GAMUT_SIZE 0x1CC +#define SSPP_UCSC_SIZE 0x80 #define MDSS_MDP_OP_DEINTERLACE BIT(22) #define MDSS_MDP_OP_DEINTERLACE_ODD BIT(23) @@ -1340,6 +1341,26 @@ static void _setup_layer_ops_colorproc(struct sde_hw_pipe *c, if (test_bit(SDE_SSPP_FP16_UNMULT, &features) && IS_SDE_CP_VER_1_0(c->cap->sblk->fp16_unmult_blk[0].version)) c->ops.setup_fp16_unmult = sde_setup_fp16_unmultv1; + + if (test_bit(SDE_SSPP_UCSC_IGC, &features) && + IS_SDE_CP_VER_1_0(c->cap->sblk->ucsc_igc_blk[0].version)) + c->ops.setup_ucsc_igc = sde_setup_ucsc_igcv1; + + if (test_bit(SDE_SSPP_UCSC_GC, &features) && + IS_SDE_CP_VER_1_0(c->cap->sblk->ucsc_gc_blk[0].version)) + c->ops.setup_ucsc_gc = sde_setup_ucsc_gcv1; + + if (test_bit(SDE_SSPP_UCSC_CSC, &features) && + IS_SDE_CP_VER_1_0(c->cap->sblk->ucsc_csc_blk[0].version)) + c->ops.setup_ucsc_csc = sde_setup_ucsc_cscv1; + + if (test_bit(SDE_SSPP_UCSC_UNMULT, &features) && + IS_SDE_CP_VER_1_0(c->cap->sblk->ucsc_unmult_blk[0].version)) + c->ops.setup_ucsc_unmult = sde_setup_ucsc_unmultv1; + + if (test_bit(SDE_SSPP_UCSC_ALPHA_DITHER, &features) && + IS_SDE_CP_VER_1_0(c->cap->sblk->ucsc_alpha_dither_blk[0].version)) + c->ops.setup_ucsc_alpha_dither = sde_setup_ucsc_alpha_ditherv1; } static void sde_hw_sspp_setup_inverse_pma(struct sde_hw_pipe *ctx, @@ -1672,6 +1693,17 @@ struct sde_hw_pipe *sde_hw_sspp_init(enum sde_sspp idx, hw_pipe->hw.blk_off + cfg->sblk->gamut_blk.base + VIG_GAMUT_SIZE, hw_pipe->hw.xin_id); } + + if (test_bit(SDE_SSPP_UCSC_CSC, &hw_pipe->cap->features)) { + sde_dbg_reg_register_dump_range(SDE_DBG_NAME, "UCSC_0", + hw_pipe->hw.blk_off + cfg->sblk->ucsc_csc_blk[0].base, + hw_pipe->hw.blk_off + cfg->sblk->ucsc_csc_blk[0].base +\ + SSPP_UCSC_SIZE, hw_pipe->hw.xin_id); + sde_dbg_reg_register_dump_range(SDE_DBG_NAME, "UCSC_0", + hw_pipe->hw.blk_off + cfg->sblk->ucsc_csc_blk[1].base, + hw_pipe->hw.blk_off + cfg->sblk->ucsc_csc_blk[1].base +\ + SSPP_UCSC_SIZE, hw_pipe->hw.xin_id); + } } if (cfg->sblk->scaler_blk.len && !is_virtual_pipe) diff --git a/msm/sde/sde_hw_sspp.h b/msm/sde/sde_hw_sspp.h index 2aead05d45..7f502b2263 100644 --- a/msm/sde/sde_hw_sspp.h +++ b/msm/sde/sde_hw_sspp.h @@ -97,6 +97,23 @@ enum sde_hw_filter_yuv { SDE_SCALE_BIL }; +enum sde_sspp_ucsc_gc { + UCSC_GC_MODE_DISABLE = 0, + UCSC_GC_MODE_SRGB, + UCSC_GC_MODE_PQ, + UCSC_GC_MODE_GAMMA2_2, + UCSC_GC_MODE_HLG, +}; + +enum sde_sspp_ucsc_igc { + UCSC_IGC_MODE_DISABLE = 0, + UCSC_IGC_MODE_SRGB, + UCSC_IGC_MODE_REC709, + UCSC_IGC_MODE_GAMMA2_2, + UCSC_IGC_MODE_HLG, + UCSC_IGC_MODE_PQ, +}; + struct sde_hw_sharp_cfg { u32 strength; u32 edge_thr; @@ -713,6 +730,51 @@ struct sde_hw_sspp_ops { void (*setup_line_insertion)(struct sde_hw_pipe *ctx, enum sde_sspp_multirect_index index, struct sde_hw_pipe_line_insertion_cfg *cfg); + + /** + * setup_ucsc_csc - set UCSC CSC cp block + * @ctx: Pointer to pipe object + * @index: Pipe rectangle to operate on + * @data: Pointer to sde_hw_cp_cfg object holding drm_msm_ucsc_csc data + */ + void (*setup_ucsc_csc)(struct sde_hw_pipe *ctx, + enum sde_sspp_multirect_index index, void *data); + + /** + * sde_setup_ucsc_gcv1 - set UCSC GC cp block + * @ctx: Pointer to pipe object + * @index: Pipe rectangle to operate on + * @mode: Pointer to sde_hw_cp_cfg object holding GC mode data + */ + void (*setup_ucsc_gc)(struct sde_hw_pipe *ctx, + enum sde_sspp_multirect_index index, void *data); + + /** + * sde_setup_ucsc_igcv1 - set UCSC IGC cp block + * @ctx: Pointer to pipe object + * @index: Pipe rectangle to operate on + * @mode: Pointer to sde_hw_cp_cfg object containing IGC mode data + */ + void (*setup_ucsc_igc)(struct sde_hw_pipe *ctx, + enum sde_sspp_multirect_index index, void *data); + + /** + * sde_setup_ucsc_unmultv1 - set UCSC UNMULT cp block + * @ctx: Pointer to pipe object + * @index: Pipe rectangle to operate on + * @data: Pointer to sde_hw_cp_cfg object containing bool data + */ + void (*setup_ucsc_unmult)(struct sde_hw_pipe *ctx, + enum sde_sspp_multirect_index index, void *data); + + /** + * sde_setup_ucsc_alpha_ditherv1 - set UCSC ALPHA DITHER cp block + * @ctx: Pointer to pipe object + * @index: Pipe rectangle to operate on + * @data: Pointer to sde_hw_cp_cfg object containing bool data + */ + void (*setup_ucsc_alpha_dither)(struct sde_hw_pipe *ctx, + enum sde_sspp_multirect_index index, void *data); }; /** diff --git a/msm/sde/sde_plane.c b/msm/sde/sde_plane.c index 82697ab942..2eed58780e 100644 --- a/msm/sde/sde_plane.c +++ b/msm/sde/sde_plane.c @@ -1163,9 +1163,11 @@ static void sde_color_process_plane_setup(struct drm_plane *plane) size_t memcol_sz = 0, size = 0; struct sde_hw_cp_cfg hw_cfg = {}; struct sde_hw_ctl *ctl = _sde_plane_get_hw_ctl(plane); - bool fp16_igc, fp16_unmult; + bool fp16_igc, fp16_unmult, ucsc_unmult, ucsc_alpha_dither; + int ucsc_gc, ucsc_igc; struct drm_msm_fp16_gc *fp16_gc = NULL; struct drm_msm_fp16_csc *fp16_csc = NULL; + struct drm_msm_ucsc_csc *ucsc_csc = NULL; psde = to_sde_plane(plane); pstate = to_sde_plane_state(plane->state); @@ -1317,6 +1319,68 @@ static void sde_color_process_plane_setup(struct drm_plane *plane) psde->pipe_hw->ops.setup_fp16_unmult(psde->pipe_hw, pstate->multirect_index, &hw_cfg); } + + if (pstate->dirty & SDE_PLANE_DIRTY_UCSC_IGC && + psde->pipe_hw->ops.setup_ucsc_igc) { + ucsc_igc = sde_plane_get_property(pstate, + PLANE_PROP_UCSC_IGC); + hw_cfg.last_feature = 0; + hw_cfg.ctl = ctl; + hw_cfg.len = sizeof(int); + hw_cfg.payload = &ucsc_igc; + psde->pipe_hw->ops.setup_ucsc_igc(psde->pipe_hw, + pstate->multirect_index, &hw_cfg); + } + + if (pstate->dirty & SDE_PLANE_DIRTY_UCSC_GC && + psde->pipe_hw->ops.setup_ucsc_gc) { + ucsc_gc = sde_plane_get_property(pstate, + PLANE_PROP_UCSC_GC); + hw_cfg.last_feature = 0; + hw_cfg.ctl = ctl; + hw_cfg.len = sizeof(int); + hw_cfg.payload = &ucsc_gc; + psde->pipe_hw->ops.setup_ucsc_gc(psde->pipe_hw, + pstate->multirect_index, &hw_cfg); + } + + if (pstate->dirty & SDE_PLANE_DIRTY_UCSC_CSC && + psde->pipe_hw->ops.setup_ucsc_csc) { + ucsc_csc = msm_property_get_blob(&psde->property_info, + &pstate->property_state, + &size, + PLANE_PROP_UCSC_CSC); + hw_cfg.last_feature = 0; + hw_cfg.ctl = ctl; + hw_cfg.len = size; + hw_cfg.payload = ucsc_csc; + psde->pipe_hw->ops.setup_ucsc_csc(psde->pipe_hw, + pstate->multirect_index, &hw_cfg); + } + + if (pstate->dirty & SDE_PLANE_DIRTY_UCSC_UNMULT && + psde->pipe_hw->ops.setup_ucsc_unmult) { + ucsc_unmult = !!sde_plane_get_property(pstate, + PLANE_PROP_UCSC_UNMULT); + hw_cfg.last_feature = 0; + hw_cfg.ctl = ctl; + hw_cfg.len = sizeof(bool); + hw_cfg.payload = &ucsc_unmult; + psde->pipe_hw->ops.setup_ucsc_unmult(psde->pipe_hw, + pstate->multirect_index, &hw_cfg); + } + + if (pstate->dirty & SDE_PLANE_DIRTY_UCSC_ALPHA_DITHER && + psde->pipe_hw->ops.setup_ucsc_alpha_dither) { + ucsc_alpha_dither = !!sde_plane_get_property(pstate, + PLANE_PROP_UCSC_ALPHA_DITHER); + hw_cfg.last_feature = 0; + hw_cfg.ctl = ctl; + hw_cfg.len = sizeof(bool); + hw_cfg.payload = &ucsc_alpha_dither; + psde->pipe_hw->ops.setup_ucsc_alpha_dither(psde->pipe_hw, + pstate->multirect_index, &hw_cfg); + } } static void _sde_plane_setup_scaler(struct sde_plane *psde, @@ -3669,6 +3733,23 @@ static void _sde_plane_install_colorproc_properties(struct sde_plane *psde, char feature_name[256]; bool is_master = !psde->is_virtual; + static const struct drm_prop_enum_list ucsc_gc[] = { + {UCSC_GC_MODE_DISABLE, "disable"}, + {UCSC_GC_MODE_SRGB, "srgb"}, + {UCSC_GC_MODE_PQ, "pq"}, + {UCSC_GC_MODE_GAMMA2_2, "gamma2_2"}, + {UCSC_GC_MODE_HLG, "hlg"}, + }; + + static const struct drm_prop_enum_list ucsc_igc[] = { + {UCSC_IGC_MODE_DISABLE, "disable"}, + {UCSC_IGC_MODE_SRGB, "srgb"}, + {UCSC_IGC_MODE_REC709, "rec709"}, + {UCSC_IGC_MODE_GAMMA2_2, "gamma2_2"}, + {UCSC_IGC_MODE_HLG, "hlg"}, + {UCSC_IGC_MODE_PQ, "pq"}, + }; + if ((is_master && (psde->features & BIT(SDE_SSPP_INVERSE_PMA))) || (psde->features & BIT(SDE_SSPP_DGM_INVERSE_PMA))) { @@ -3765,6 +3846,46 @@ static void _sde_plane_install_colorproc_properties(struct sde_plane *psde, msm_property_install_range(&psde->property_info, feature_name, 0x0, 0, 1, 0, PLANE_PROP_FP16_UNMULT); } + + if (psde->features & BIT(SDE_SSPP_UCSC_IGC)) { + snprintf(feature_name, sizeof(feature_name), "%s%d", + "SDE_SSPP_UCSC_IGC_V", + psde->pipe_sblk->ucsc_igc_blk[0].version >> 16); + msm_property_install_enum(&psde->property_info, feature_name, + 0x0, 0, ucsc_igc, ARRAY_SIZE(ucsc_igc), 0, PLANE_PROP_UCSC_IGC); + } + + if (psde->features & BIT(SDE_SSPP_UCSC_GC)) { + snprintf(feature_name, sizeof(feature_name), "%s%d", + "SDE_SSPP_UCSC_GC_V", + psde->pipe_sblk->ucsc_gc_blk[0].version >> 16); + msm_property_install_enum(&psde->property_info, feature_name, + 0x0, 0, ucsc_gc, ARRAY_SIZE(ucsc_gc), 0, PLANE_PROP_UCSC_GC); + } + + if (psde->features & BIT(SDE_SSPP_UCSC_CSC)) { + snprintf(feature_name, sizeof(feature_name), "%s%d", + "SDE_SSPP_UCSC_CSC_V", + psde->pipe_sblk->ucsc_csc_blk[0].version >> 16); + msm_property_install_blob(&psde->property_info, feature_name, 0, + PLANE_PROP_UCSC_CSC); + } + + if (psde->features & BIT(SDE_SSPP_UCSC_UNMULT)) { + snprintf(feature_name, sizeof(feature_name), "%s%d", + "SDE_SSPP_UCSC_UNMULT_V", + psde->pipe_sblk->ucsc_unmult_blk[0].version >> 16); + msm_property_install_range(&psde->property_info, feature_name, + 0x0, 0, 1, 0, PLANE_PROP_UCSC_UNMULT); + } + + if (psde->features & BIT(SDE_SSPP_UCSC_ALPHA_DITHER)) { + snprintf(feature_name, sizeof(feature_name), "%s%d", + "SDE_SSPP_UCSC_ALPHA_DITHER_V", + psde->pipe_sblk->ucsc_alpha_dither_blk[0].version >> 16); + msm_property_install_range(&psde->property_info, feature_name, + 0x0, 0, 1, 0, PLANE_PROP_UCSC_ALPHA_DITHER); + } } static void _sde_plane_setup_capabilities_blob(struct sde_plane *psde, diff --git a/msm/sde/sde_plane.h b/msm/sde/sde_plane.h index 7eab4726a8..24455391e9 100644 --- a/msm/sde/sde_plane.h +++ b/msm/sde/sde_plane.h @@ -43,11 +43,18 @@ #define SDE_PLANE_DIRTY_FP16_GC 0x800 #define SDE_PLANE_DIRTY_FP16_CSC 0x1000 #define SDE_PLANE_DIRTY_FP16_UNMULT 0x2000 +#define SDE_PLANE_DIRTY_UCSC_IGC 0x4000 +#define SDE_PLANE_DIRTY_UCSC_GC 0x8000 +#define SDE_PLANE_DIRTY_UCSC_CSC 0x10000 +#define SDE_PLANE_DIRTY_UCSC_UNMULT 0x20000 +#define SDE_PLANE_DIRTY_UCSC_ALPHA_DITHER 0x40000 #define SDE_PLANE_DIRTY_CP (SDE_PLANE_DIRTY_VIG_GAMUT |\ SDE_PLANE_DIRTY_VIG_IGC | SDE_PLANE_DIRTY_DMA_IGC |\ SDE_PLANE_DIRTY_DMA_GC | SDE_PLANE_DIRTY_FP16_IGC |\ SDE_PLANE_DIRTY_FP16_GC | SDE_PLANE_DIRTY_FP16_CSC |\ - SDE_PLANE_DIRTY_FP16_UNMULT) + SDE_PLANE_DIRTY_FP16_UNMULT | SDE_PLANE_DIRTY_UCSC_IGC |\ + SDE_PLANE_DIRTY_UCSC_GC | SDE_PLANE_DIRTY_UCSC_CSC |\ + SDE_PLANE_DIRTY_UCSC_UNMULT | SDE_PLANE_DIRTY_UCSC_ALPHA_DITHER) #define SDE_PLANE_DIRTY_ALL (0xFFFFFFFF & ~(SDE_PLANE_DIRTY_CP)) struct sde_plane {