From c84f906b30b8f76b58c01a10a3f7102f376bb133 Mon Sep 17 00:00:00 2001 From: Amine Najahi Date: Wed, 21 Aug 2019 09:11:47 -0400 Subject: [PATCH 1/4] disp: msm: sde: add support for lutdma absolute mdss addressing Add support for absolute mdss addressing lutdma payload. This will allow any mdss register to be programmed using lutdma. Change-Id: I3af3a85182a75a0583c49c797d6adf99b6ba2ee7 Signed-off-by: Amine Najahi --- msm/sde/sde_hw_reg_dma_v1.c | 50 +++++++++++++++++++++++++++---------- msm/sde/sde_reg_dma.h | 3 ++- 2 files changed, 39 insertions(+), 14 deletions(-) diff --git a/msm/sde/sde_hw_reg_dma_v1.c b/msm/sde/sde_hw_reg_dma_v1.c index e8911cf80661..47c4f5f13fad 100644 --- a/msm/sde/sde_hw_reg_dma_v1.c +++ b/msm/sde/sde_hw_reg_dma_v1.c @@ -1,7 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ + #include #include "sde_hw_mdss.h" #include "sde_hw_ctl.h" @@ -14,6 +15,7 @@ #define ALIGNED_OFFSET (U32_MAX & ~(GUARD_BYTES)) #define ADDR_ALIGN BIT(8) #define MAX_RELATIVE_OFF (BIT(20) - 1) +#define ABSOLUTE_RANGE BIT(27) #define DECODE_SEL_OP (BIT(HW_BLK_SELECT)) #define REG_WRITE_OP ((BIT(REG_SINGLE_WRITE)) | (BIT(REG_BLK_WRITE_SINGLE)) | \ @@ -39,6 +41,7 @@ #define GRP_DMA_HW_BLK_SELECT (DMA0 | DMA1 | DMA2 | DMA3) #define GRP_DSPP_HW_BLK_SELECT (DSPP0 | DSPP1 | DSPP2 | DSPP3) #define GRP_LTM_HW_BLK_SELECT (LTM0 | LTM1) +#define GRP_MDSS_HW_BLK_SELECT (MDSS) #define BUFFER_SPACE_LEFT(cfg) ((cfg)->dma_buf->buffer_size - \ (cfg)->dma_buf->index) @@ -162,7 +165,7 @@ static void get_decode_sel(unsigned long blk, u32 *decode_sel) int i = 0; *decode_sel = 0; - for_each_set_bit(i, &blk, 31) { + for_each_set_bit(i, &blk, REG_DMA_BLK_MAX) { switch (BIT(i)) { case VIG0: *decode_sel |= BIT(0); @@ -212,6 +215,9 @@ static void get_decode_sel(unsigned long blk, u32 *decode_sel) case LTM1: *decode_sel |= BIT(23); break; + case MDSS: + *decode_sel |= BIT(31); + break; default: DRM_ERROR("block not supported %zx\n", (size_t)BIT(i)); break; @@ -240,6 +246,9 @@ int write_multi_reg_index(struct sde_reg_dma_setup_ops_cfg *cfg) cfg->dma_buf->index); loc[0] = HW_INDEX_REG_WRITE_OPCODE; loc[0] |= (cfg->blk_offset & MAX_RELATIVE_OFF); + if (cfg->blk == MDSS) + loc[0] |= ABSOLUTE_RANGE; + loc[1] = SIZE_DWORD(cfg->data_size); cfg->dma_buf->index += ops_mem_size[cfg->ops]; @@ -253,6 +262,9 @@ int write_multi_reg_inc(struct sde_reg_dma_setup_ops_cfg *cfg) loc = (u32 *)((u8 *)cfg->dma_buf->vaddr + cfg->dma_buf->index); loc[0] = AUTO_INC_REG_WRITE_OPCODE; + if (cfg->blk == MDSS) + loc[0] |= ABSOLUTE_RANGE; + loc[0] |= (cfg->blk_offset & MAX_RELATIVE_OFF); loc[1] = SIZE_DWORD(cfg->data_size); cfg->dma_buf->index += ops_mem_size[cfg->ops]; @@ -268,6 +280,9 @@ static int write_multi_lut_reg(struct sde_reg_dma_setup_ops_cfg *cfg) cfg->dma_buf->index); loc[0] = BLK_REG_WRITE_OPCODE; loc[0] |= (cfg->blk_offset & MAX_RELATIVE_OFF); + if (cfg->blk == MDSS) + loc[0] |= ABSOLUTE_RANGE; + loc[1] = (cfg->inc) ? 0 : BIT(31); loc[1] |= (cfg->wrap_size & WRAP_MAX_SIZE) << 16; loc[1] |= ((SIZE_DWORD(cfg->data_size)) & MAX_DWORDS_SZ); @@ -285,6 +300,9 @@ static int write_single_reg(struct sde_reg_dma_setup_ops_cfg *cfg) cfg->dma_buf->index); loc[0] = SINGLE_REG_WRITE_OPCODE; loc[0] |= (cfg->blk_offset & MAX_RELATIVE_OFF); + if (cfg->blk == MDSS) + loc[0] |= ABSOLUTE_RANGE; + loc[1] = *cfg->data; cfg->dma_buf->index += ops_mem_size[cfg->ops]; cfg->dma_buf->ops_completed |= REG_WRITE_OP; @@ -301,6 +319,9 @@ static int write_single_modify(struct sde_reg_dma_setup_ops_cfg *cfg) cfg->dma_buf->index); loc[0] = SINGLE_REG_MODIFY_OPCODE; loc[0] |= (cfg->blk_offset & MAX_RELATIVE_OFF); + if (cfg->blk == MDSS) + loc[0] |= ABSOLUTE_RANGE; + loc[1] = cfg->mask; loc[2] = *cfg->data; cfg->dma_buf->index += ops_mem_size[cfg->ops]; @@ -381,6 +402,7 @@ static int validate_write_reg(struct sde_reg_dma_setup_ops_cfg *cfg) static int validate_write_decode_sel(struct sde_reg_dma_setup_ops_cfg *cfg) { u32 remain_len; + bool vig_blk, dma_blk, dspp_blk, mdss_blk; remain_len = BUFFER_SPACE_LEFT(cfg); if (remain_len < ops_mem_size[HW_BLK_SELECT]) { @@ -393,15 +415,16 @@ static int validate_write_decode_sel(struct sde_reg_dma_setup_ops_cfg *cfg) DRM_ERROR("blk set as 0\n"); return -EINVAL; } - /* VIG, DMA and DSPP can't be combined */ - if (((cfg->blk & GRP_VIG_HW_BLK_SELECT) && - (cfg->blk & GRP_DSPP_HW_BLK_SELECT)) || - ((cfg->blk & GRP_DMA_HW_BLK_SELECT) && - (cfg->blk & GRP_DSPP_HW_BLK_SELECT)) || - ((cfg->blk & GRP_VIG_HW_BLK_SELECT) && - (cfg->blk & GRP_DMA_HW_BLK_SELECT))) { - DRM_ERROR("invalid blk combination %x\n", - cfg->blk); + + vig_blk = (cfg->blk & GRP_VIG_HW_BLK_SELECT) ? true : false; + dma_blk = (cfg->blk & GRP_DMA_HW_BLK_SELECT) ? true : false; + dspp_blk = (cfg->blk & GRP_DSPP_HW_BLK_SELECT) ? true : false; + mdss_blk = (cfg->blk & MDSS) ? true : false; + + if ((vig_blk && dspp_blk) || (dma_blk && dspp_blk) || + (vig_blk && dma_blk) || + (mdss_blk && (vig_blk | dma_blk | dspp_blk))) { + DRM_ERROR("invalid blk combination %x\n", cfg->blk); return -EINVAL; } @@ -685,7 +708,7 @@ static int check_support_v1(enum sde_reg_dma_features feature, if (!is_supported) return -EINVAL; - if (feature >= REG_DMA_FEATURES_MAX || blk >= MDSS) { + if (feature >= REG_DMA_FEATURES_MAX || blk >= BIT(REG_DMA_BLK_MAX)) { *is_supported = false; return ret; } @@ -805,7 +828,8 @@ static struct sde_reg_dma_buffer *alloc_reg_dma_buf_v1(u32 size) int rc = 0; if (!size || SIZE_DWORD(size) > MAX_DWORDS_SZ) { - DRM_ERROR("invalid buffer size %d\n", size); + DRM_ERROR("invalid buffer size %d, max %d\n", + SIZE_DWORD(size), MAX_DWORDS_SZ); return ERR_PTR(-EINVAL); } diff --git a/msm/sde/sde_reg_dma.h b/msm/sde/sde_reg_dma.h index 1454e41457b3..49a97255f81b 100644 --- a/msm/sde/sde_reg_dma.h +++ b/msm/sde/sde_reg_dma.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _SDE_REG_DMA_H @@ -131,6 +131,7 @@ enum sde_reg_dma_setup_ops { REG_DMA_SETUP_OPS_MAX, }; +#define REG_DMA_BLK_MAX 32 /** * enum sde_reg_dma_blk - defines blocks for which reg dma op should be * performed From 119b84ea5c6caf1d4ec1d2b7f5c2cae70b0c995c Mon Sep 17 00:00:00 2001 From: Amine Najahi Date: Wed, 21 Aug 2019 09:39:09 -0400 Subject: [PATCH 2/4] disp: msm: sde: add atomic check handling in cp framework Add atomic check handling in color processing framework. This will check cp features during the validate phase. Change-Id: I6d94316a749ad247aec0554c31fa56af6db61ab6 Signed-off-by: Amine Najahi --- msm/sde/sde_color_processing.c | 129 +++++++++++++++++++++++++++++++-- msm/sde/sde_color_processing.h | 11 ++- msm/sde/sde_crtc.c | 6 ++ 3 files changed, 138 insertions(+), 8 deletions(-) diff --git a/msm/sde/sde_color_processing.c b/msm/sde/sde_color_processing.c index 18cbfa1cf959..d0319c1ed350 100644 --- a/msm/sde/sde_color_processing.c +++ b/msm/sde/sde_color_processing.c @@ -171,7 +171,7 @@ enum { static void _sde_cp_crtc_enable_hist_irq(struct sde_crtc *sde_crtc); -typedef int (*set_feature_wrapper)(struct sde_hw_dspp *hw_dspp, +typedef int (*feature_wrapper)(struct sde_hw_dspp *hw_dspp, struct sde_hw_cp_cfg *hw_cfg, struct sde_crtc *hw_crtc); @@ -655,9 +655,13 @@ static int set_ltm_hist_crtl_feature(struct sde_hw_dspp *hw_dspp, return ret; } -set_feature_wrapper crtc_feature_wrappers[SDE_CP_CRTC_MAX_FEATURES]; -#define setup_crtc_feature_wrappers(wrappers) \ +feature_wrapper check_crtc_feature_wrappers[SDE_CP_CRTC_MAX_FEATURES]; +#define setup_check_crtc_feature_wrappers(wrappers) \ +memset(wrappers, 0, sizeof(wrappers)) + +feature_wrapper set_crtc_feature_wrappers[SDE_CP_CRTC_MAX_FEATURES]; +#define setup_set_crtc_feature_wrappers(wrappers) \ do { \ memset(wrappers, 0, sizeof(wrappers)); \ wrappers[SDE_CP_CRTC_DSPP_VLUT] = set_dspp_vlut_feature; \ @@ -1182,6 +1186,68 @@ static void _sde_cp_crtc_enable_hist_irq(struct sde_crtc *sde_crtc) spin_unlock_irqrestore(&node->state_lock, flags); } +static int sde_cp_crtc_checkfeature(struct sde_cp_node *prop_node, + struct sde_crtc *sde_crtc, struct sde_crtc_state *sde_crtc_state) +{ + struct sde_hw_cp_cfg hw_cfg; + struct sde_hw_mixer *hw_lm; + struct sde_hw_dspp *hw_dspp; + u32 num_mixers = sde_crtc->num_mixers; + int i = 0, ret = 0; + bool feature_enabled = false; + feature_wrapper check_feature = NULL; + + if (!prop_node || !sde_crtc || !sde_crtc_state) { + DRM_ERROR("invalid arguments"); + return -EINVAL; + } + + if (prop_node->feature >= SDE_CP_CRTC_MAX_FEATURES) { + DRM_ERROR("invalid feature %d\n", prop_node->feature); + return -EINVAL; + } + + check_feature = check_crtc_feature_wrappers[prop_node->feature]; + if (check_feature == NULL) + return 0; + + memset(&hw_cfg, 0, sizeof(hw_cfg)); + sde_cp_get_hw_payload(prop_node, &hw_cfg, &feature_enabled); + hw_cfg.num_of_mixers = sde_crtc->num_mixers; + hw_cfg.last_feature = 0; + + for (i = 0; i < num_mixers; i++) { + hw_dspp = sde_crtc->mixers[i].hw_dspp; + if (!hw_dspp || i >= DSPP_MAX) + continue; + hw_cfg.dspp[i] = hw_dspp; + } + + for (i = 0; i < num_mixers && !ret; i++) { + hw_lm = sde_crtc->mixers[i].hw_lm; + hw_dspp = sde_crtc->mixers[i].hw_dspp; + if (!hw_lm) { + ret = -EINVAL; + continue; + } + hw_cfg.ctl = sde_crtc->mixers[i].hw_ctl; + hw_cfg.mixer_info = hw_lm; + + /* use incoming state information */ + hw_cfg.displayh = num_mixers * + sde_crtc_state->lm_roi[i].w; + hw_cfg.displayv = sde_crtc_state->lm_roi[i].h; + + DRM_DEBUG_DRIVER("check cp feature %d on mixer %d\n", + prop_node->feature, hw_lm->idx - LM_0); + ret = check_feature(hw_dspp, &hw_cfg, sde_crtc); + if (ret) + break; + } + + return ret; +} + static void sde_cp_crtc_setfeature(struct sde_cp_node *prop_node, struct sde_crtc *sde_crtc) { @@ -1206,11 +1272,11 @@ static void sde_cp_crtc_setfeature(struct sde_cp_node *prop_node, } if ((prop_node->feature >= SDE_CP_CRTC_MAX_FEATURES) || - crtc_feature_wrappers[prop_node->feature] == NULL) { + set_crtc_feature_wrappers[prop_node->feature] == NULL) { ret = -EINVAL; } else { - set_feature_wrapper set_feature = - crtc_feature_wrappers[prop_node->feature]; + feature_wrapper set_feature = + set_crtc_feature_wrappers[prop_node->feature]; catalog = get_kms(&sde_crtc->base)->catalog; hw_cfg.broadcast_disabled = catalog->dma_cfg.broadcast_disabled; @@ -1314,6 +1380,54 @@ void sde_cp_dspp_flush_helper(struct sde_crtc *sde_crtc, u32 feature) } } +int sde_cp_crtc_check_properties(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + struct sde_crtc *sde_crtc = NULL; + struct sde_crtc_state *sde_crtc_state = NULL; + struct sde_cp_node *prop_node = NULL, *n = NULL; + int ret = 0; + + if (!crtc || !crtc->dev || !state) { + DRM_ERROR("invalid crtc %pK dev %pK state %pK\n", crtc, + (crtc ? crtc->dev : NULL), state); + return -EINVAL; + } + + sde_crtc = to_sde_crtc(crtc); + if (!sde_crtc) { + DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc); + return -EINVAL; + } + + sde_crtc_state = to_sde_crtc_state(state); + if (!sde_crtc_state) { + DRM_ERROR("invalid sde_crtc_state %pK\n", sde_crtc_state); + return -EINVAL; + } + mutex_lock(&sde_crtc->crtc_cp_lock); + + if (list_empty(&sde_crtc->dirty_list)) { + DRM_DEBUG_DRIVER("Dirty list is empty\n"); + goto exit; + } + + list_for_each_entry_safe(prop_node, n, &sde_crtc->dirty_list, + dirty_list) { + ret = sde_cp_crtc_checkfeature(prop_node, sde_crtc, + sde_crtc_state); + if (ret) { + DRM_ERROR("failed check on prop_node %u\n", + prop_node->property_id); + goto exit; + } + } + +exit: + mutex_unlock(&sde_crtc->crtc_cp_lock); + return ret; +} + void sde_cp_crtc_apply_properties(struct drm_crtc *crtc) { struct sde_crtc *sde_crtc = NULL; @@ -1444,7 +1558,8 @@ void sde_cp_crtc_install_properties(struct drm_crtc *crtc) SDE_CP_CRTC_MAX_FEATURES), GFP_KERNEL); setup_dspp_prop_install_funcs(dspp_prop_install_func); setup_lm_prop_install_funcs(lm_prop_install_func); - setup_crtc_feature_wrappers(crtc_feature_wrappers); + setup_set_crtc_feature_wrappers(set_crtc_feature_wrappers); + setup_check_crtc_feature_wrappers(check_crtc_feature_wrappers); } if (!priv->cp_property) goto exit; diff --git a/msm/sde/sde_color_processing.h b/msm/sde/sde_color_processing.h index 51fd95d78b61..9c03e65b8e81 100644 --- a/msm/sde/sde_color_processing.h +++ b/msm/sde/sde_color_processing.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ #ifndef _SDE_COLOR_PROCESSING_H @@ -93,6 +93,15 @@ void sde_cp_crtc_destroy_properties(struct drm_crtc *crtc); */ int sde_cp_crtc_set_property(struct drm_crtc *crtc, struct drm_property *property, uint64_t val); +/** + * sde_cp_crtc_check_properties: Verify color processing properties for a crtc. + * Should be called during atomic check call. + * @crtc: Pointer to crtc. + * @state: Pointer to crtc state. + * @returns: 0 on success, non-zero otherwise + */ +int sde_cp_crtc_check_properties(struct drm_crtc *crtc, + struct drm_crtc_state *state); /** * sde_cp_crtc_apply_properties: Enable/disable properties diff --git a/msm/sde/sde_crtc.c b/msm/sde/sde_crtc.c index ce58186d96ea..7f85b65cc956 100644 --- a/msm/sde/sde_crtc.c +++ b/msm/sde/sde_crtc.c @@ -4655,6 +4655,12 @@ static int sde_crtc_atomic_check(struct drm_crtc *crtc, goto end; } + rc = sde_cp_crtc_check_properties(crtc, state); + if (rc) { + SDE_ERROR("crtc%d failed cp properties check %d\n", + crtc->base.id, rc); + goto end; + } end: kfree(pstates); kfree(multirect_plane); From d26c9811cad672bf9dc4cc9283388de3fb399393 Mon Sep 17 00:00:00 2001 From: Amine Najahi Date: Tue, 8 Oct 2019 22:33:10 -0400 Subject: [PATCH 3/4] disp: msm: sde: add partial update handling in cp framework Add partial update handling for color processing features. This will validate and set cp features for each frame if applicable. Change-Id: Id78c1f4ecbd74781c0c03c04efb528d6a8b91264 Signed-off-by: Amine Najahi --- msm/sde/sde_color_processing.c | 281 ++++++++++++++++++++++++++++++--- msm/sde/sde_crtc.h | 3 +- 2 files changed, 259 insertions(+), 25 deletions(-) diff --git a/msm/sde/sde_color_processing.c b/msm/sde/sde_color_processing.c index d0319c1ed350..c8e37f78c834 100644 --- a/msm/sde/sde_color_processing.c +++ b/msm/sde/sde_color_processing.c @@ -6,6 +6,7 @@ #define pr_fmt(fmt) "%s: " fmt, __func__ #include +#include #include #include "sde_color_processing.h" #include "sde_kms.h" @@ -122,7 +123,7 @@ static void lm_gc_install_property(struct drm_crtc *crtc); #define setup_lm_prop_install_funcs(func) \ (func[SDE_MIXER_GC] = lm_gc_install_property) -enum { +enum sde_cp_crtc_features { /* Append new DSPP features before SDE_CP_CRTC_DSPP_MAX */ /* DSPP Features start */ SDE_CP_CRTC_DSPP_IGC, @@ -169,12 +170,27 @@ enum { SDE_CP_CRTC_MAX_FEATURES, }; +enum sde_cp_crtc_pu_features { + SDE_CP_CRTC_MAX_PU_FEATURES, +}; + +static enum sde_cp_crtc_pu_features + sde_cp_crtc_pu_to_feature[SDE_CP_CRTC_MAX_PU_FEATURES]; + static void _sde_cp_crtc_enable_hist_irq(struct sde_crtc *sde_crtc); typedef int (*feature_wrapper)(struct sde_hw_dspp *hw_dspp, struct sde_hw_cp_cfg *hw_cfg, struct sde_crtc *hw_crtc); + +static struct sde_kms *get_kms(struct drm_crtc *crtc) +{ + struct msm_drm_private *priv = crtc->dev->dev_private; + + return to_sde_kms(priv->kms); +} + static int set_dspp_vlut_feature(struct sde_hw_dspp *hw_dspp, struct sde_hw_cp_cfg *hw_cfg, struct sde_crtc *hw_crtc) @@ -703,6 +719,14 @@ do { \ wrappers[SDE_CP_CRTC_DSPP_LTM_HIST_CTL] = set_ltm_hist_crtl_feature; \ } while (0) +feature_wrapper set_crtc_pu_feature_wrappers[SDE_CP_CRTC_MAX_PU_FEATURES]; +#define setup_set_crtc_pu_feature_wrappers(wrappers) \ +memset(wrappers, 0, sizeof(wrappers)) + +feature_wrapper check_crtc_pu_feature_wrappers[SDE_CP_CRTC_MAX_PU_FEATURES]; +#define setup_check_crtc_pu_feature_wrappers(wrappers) \ +memset(wrappers, 0, sizeof(wrappers)) + #define INIT_PROP_ATTACH(p, crtc, prop, node, feature, val) \ do { \ (p)->crtc = crtc; \ @@ -890,12 +914,6 @@ static int sde_cp_enable_crtc_property(struct drm_crtc *crtc, return ret; } -static struct sde_kms *get_kms(struct drm_crtc *crtc) -{ - struct msm_drm_private *priv = crtc->dev->dev_private; - - return to_sde_kms(priv->kms); -} static void sde_cp_crtc_prop_attach(struct sde_cp_prop_attach *prop_attach) { @@ -1380,6 +1398,90 @@ void sde_cp_dspp_flush_helper(struct sde_crtc *sde_crtc, u32 feature) } } +static int sde_cp_crtc_check_pu_features(struct drm_crtc *crtc) +{ + int ret = 0, i = 0, j = 0; + struct sde_crtc *sde_crtc; + struct sde_crtc_state *sde_crtc_state; + struct sde_hw_cp_cfg hw_cfg; + struct sde_hw_dspp *hw_dspp; + + if (!crtc) { + DRM_ERROR("invalid crtc %pK\n", crtc); + return -EINVAL; + } + + sde_crtc = to_sde_crtc(crtc); + if (!sde_crtc) { + DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc); + return -EINVAL; + } + + sde_crtc_state = to_sde_crtc_state(crtc->state); + if (!sde_crtc_state) { + DRM_ERROR("invalid sde_crtc_state %pK\n", sde_crtc_state); + return -EINVAL; + } + + for (i = 0; i < sde_crtc->num_mixers; i++) { + if (!sde_crtc->mixers[i].hw_lm) { + DRM_ERROR("invalid lm in mixer %d\n", i); + return -EINVAL; + } + + if (!sde_crtc->mixers[i].hw_ctl) { + DRM_ERROR("invalid ctl in mixer %d\n", i); + return -EINVAL; + } + + if (!sde_crtc->mixers[i].hw_dspp) { + DRM_ERROR("invalid dspp in mixer %d\n", i); + return -EINVAL; + } + } + + /* early return when not a partial update frame */ + if (sde_crtc_state->user_roi_list.num_rects == 0) { + DRM_DEBUG_DRIVER("no partial update required\n"); + return 0; + } + + memset(&hw_cfg, 0, sizeof(hw_cfg)); + hw_cfg.num_of_mixers = sde_crtc->num_mixers; + hw_cfg.payload = &sde_crtc_state->user_roi_list; + hw_cfg.len = sizeof(sde_crtc_state->user_roi_list); + for (i = 0; i < hw_cfg.num_of_mixers; i++) + hw_cfg.dspp[i] = sde_crtc->mixers[i].hw_dspp; + + for (i = 0; i < SDE_CP_CRTC_MAX_PU_FEATURES; i++) { + feature_wrapper check_pu_feature = + check_crtc_pu_feature_wrappers[i]; + + if (!check_pu_feature) + continue; + + for (j = 0; j < hw_cfg.num_of_mixers; j++) { + hw_dspp = sde_crtc->mixers[j].hw_dspp; + + /* use incoming state information */ + hw_cfg.mixer_info = sde_crtc->mixers[j].hw_lm; + hw_cfg.ctl = sde_crtc->mixers[j].hw_ctl; + hw_cfg.displayh = hw_cfg.num_of_mixers * + sde_crtc_state->lm_roi[i].w; + hw_cfg.displayv = sde_crtc_state->lm_roi[i].h; + + ret = check_pu_feature(hw_dspp, &hw_cfg, sde_crtc); + if (ret) { + DRM_ERROR("failed pu feature %d in mixer %d\n", + i, j); + return -EAGAIN; + } + } + } + + return ret; +} + int sde_cp_crtc_check_properties(struct drm_crtc *crtc, struct drm_crtc_state *state) { @@ -1407,6 +1509,12 @@ int sde_cp_crtc_check_properties(struct drm_crtc *crtc, } mutex_lock(&sde_crtc->crtc_cp_lock); + ret = sde_cp_crtc_check_pu_features(crtc); + if (ret) { + DRM_ERROR("failed check pu features, ret %d\n", ret); + goto exit; + } + if (list_empty(&sde_crtc->dirty_list)) { DRM_DEBUG_DRIVER("Dirty list is empty\n"); goto exit; @@ -1428,6 +1536,120 @@ exit: return ret; } +static int sde_cp_crtc_set_pu_features(struct drm_crtc *crtc, bool *need_flush) +{ + int ret = 0, i = 0, j = 0; + struct sde_crtc *sde_crtc; + struct sde_crtc_state *sde_crtc_state; + struct sde_hw_cp_cfg hw_cfg; + struct sde_hw_dspp *hw_dspp; + struct sde_hw_mixer *hw_lm; + struct sde_mdss_cfg *catalog; + struct sde_rect user_rect, cached_rect; + + if (!need_flush) { + DRM_ERROR("invalid need_flush %pK\n", need_flush); + return -EINVAL; + } + + if (!crtc) { + DRM_ERROR("invalid crtc %pK\n", crtc); + return -EINVAL; + } + + sde_crtc = to_sde_crtc(crtc); + if (!sde_crtc) { + DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc); + return -EINVAL; + } + + sde_crtc_state = to_sde_crtc_state(crtc->state); + if (!sde_crtc_state) { + DRM_ERROR("invalid sde_crtc_state %pK\n", sde_crtc_state); + return -EINVAL; + } + + for (i = 0; i < sde_crtc->num_mixers; i++) { + if (!sde_crtc->mixers[i].hw_lm) { + DRM_ERROR("invalid lm in mixer %d\n", i); + return -EINVAL; + } + + if (!sde_crtc->mixers[i].hw_ctl) { + DRM_ERROR("invalid ctl in mixer %d\n", i); + return -EINVAL; + } + + if (!sde_crtc->mixers[i].hw_dspp) { + DRM_ERROR("invalid dspp in mixer %d\n", i); + return -EINVAL; + } + } + + /* early return if not a partial update frame or no change in rois */ + if (sde_crtc_state->user_roi_list.num_rects == 0) { + DRM_DEBUG_DRIVER("no partial update required\n"); + memset(&sde_crtc_state->cached_user_roi_list, 0, + sizeof(struct msm_roi_list)); + return 0; + } + + sde_kms_rect_merge_rectangles(&sde_crtc_state->user_roi_list, + &user_rect); + sde_kms_rect_merge_rectangles(&sde_crtc_state->cached_user_roi_list, + &cached_rect); + if (sde_kms_rect_is_equal(&user_rect, &cached_rect)) { + DRM_DEBUG_DRIVER("no change in list of ROIs\n"); + return 0; + } + + catalog = get_kms(&sde_crtc->base)->catalog; + memset(&hw_cfg, 0, sizeof(hw_cfg)); + hw_cfg.num_of_mixers = sde_crtc->num_mixers; + hw_cfg.broadcast_disabled = catalog->dma_cfg.broadcast_disabled; + hw_cfg.payload = &sde_crtc_state->user_roi_list; + hw_cfg.len = sizeof(sde_crtc_state->user_roi_list); + for (i = 0; i < hw_cfg.num_of_mixers; i++) + hw_cfg.dspp[i] = sde_crtc->mixers[i].hw_dspp; + + for (i = 0; i < SDE_CP_CRTC_MAX_PU_FEATURES; i++) { + feature_wrapper set_pu_feature = + set_crtc_pu_feature_wrappers[i]; + + if (!set_pu_feature) + continue; + + for (j = 0; j < hw_cfg.num_of_mixers; j++) { + hw_lm = sde_crtc->mixers[j].hw_lm; + hw_dspp = sde_crtc->mixers[j].hw_dspp; + + hw_cfg.mixer_info = hw_lm; + hw_cfg.ctl = sde_crtc->mixers[j].hw_ctl; + hw_cfg.displayh = hw_cfg.num_of_mixers * + hw_lm->cfg.out_width; + hw_cfg.displayv = hw_lm->cfg.out_height; + + ret = set_pu_feature(hw_dspp, &hw_cfg, sde_crtc); + /* feature does not need flush when ret > 0 */ + if (ret < 0) { + DRM_ERROR("failed pu feature %d in mixer %d\n", + i, j); + return ret; + } else if (ret == 0) { + sde_cp_dspp_flush_helper(sde_crtc, + sde_cp_crtc_pu_to_feature[i]); + *need_flush = true; + } + } + } + + memcpy(&sde_crtc_state->cached_user_roi_list, + &sde_crtc_state->user_roi_list, + sizeof(struct msm_roi_list)); + + return 0; +} + void sde_cp_crtc_apply_properties(struct drm_crtc *crtc) { struct sde_crtc *sde_crtc = NULL; @@ -1435,6 +1657,8 @@ void sde_cp_crtc_apply_properties(struct drm_crtc *crtc) struct sde_cp_node *prop_node = NULL, *n = NULL; struct sde_hw_ctl *ctl; u32 num_mixers = 0, i = 0; + int rc = 0; + bool need_flush = false; if (!crtc || !crtc->dev) { DRM_ERROR("invalid crtc %pK dev %pK\n", crtc, @@ -1450,43 +1674,48 @@ void sde_cp_crtc_apply_properties(struct drm_crtc *crtc) num_mixers = sde_crtc->num_mixers; if (!num_mixers) { - DRM_DEBUG_DRIVER("no mixers for this crtc\n"); + DRM_ERROR("no mixers for this crtc\n"); return; } mutex_lock(&sde_crtc->crtc_cp_lock); - /* Check if dirty lists are empty and ad features are disabled for - * early return. If ad properties are active then we need to issue - * dspp flush. - **/ if (list_empty(&sde_crtc->dirty_list) && - list_empty(&sde_crtc->ad_dirty)) { - if (list_empty(&sde_crtc->ad_active)) { - DRM_DEBUG_DRIVER("Dirty list is empty\n"); - goto exit; - } - set_dspp_flush = true; + list_empty(&sde_crtc->ad_dirty) && + list_empty(&sde_crtc->ad_active) && + list_empty(&sde_crtc->active_list)) { + DRM_DEBUG_DRIVER("all lists are empty\n"); + goto exit; } - if (!list_empty(&sde_crtc->ad_active)) - sde_cp_ad_set_prop(sde_crtc, AD_IPC_RESET); + rc = sde_cp_crtc_set_pu_features(crtc, &need_flush); + if (rc) { + DRM_ERROR("failed set pu features, skip cp updates\n"); + goto exit; + } else if (need_flush) { + set_dspp_flush = true; + set_lm_flush = true; + } list_for_each_entry_safe(prop_node, n, &sde_crtc->dirty_list, - dirty_list) { + dirty_list) { sde_cp_crtc_setfeature(prop_node, sde_crtc); sde_cp_dspp_flush_helper(sde_crtc, prop_node->feature); - /* Set the flush flag to true */ if (prop_node->is_dspp_feature) set_dspp_flush = true; else set_lm_flush = true; } - list_for_each_entry_safe(prop_node, n, &sde_crtc->ad_dirty, - dirty_list) { + if (!list_empty(&sde_crtc->ad_active)) { + sde_cp_ad_set_prop(sde_crtc, AD_IPC_RESET); set_dspp_flush = true; + } + + list_for_each_entry_safe(prop_node, n, &sde_crtc->ad_dirty, + dirty_list) { sde_cp_crtc_setfeature(prop_node, sde_crtc); + set_dspp_flush = true; } for (i = 0; i < num_mixers; i++) { @@ -1560,6 +1789,10 @@ void sde_cp_crtc_install_properties(struct drm_crtc *crtc) setup_lm_prop_install_funcs(lm_prop_install_func); setup_set_crtc_feature_wrappers(set_crtc_feature_wrappers); setup_check_crtc_feature_wrappers(check_crtc_feature_wrappers); + setup_set_crtc_pu_feature_wrappers( + set_crtc_pu_feature_wrappers); + setup_check_crtc_pu_feature_wrappers( + check_crtc_pu_feature_wrappers); } if (!priv->cp_property) goto exit; diff --git a/msm/sde/sde_crtc.h b/msm/sde/sde_crtc.h index f22bf6a6434c..67ab431dc165 100644 --- a/msm/sde/sde_crtc.h +++ b/msm/sde/sde_crtc.h @@ -350,6 +350,7 @@ struct sde_crtc { * @lm_roi : Current LM ROI, possibly sub-rectangle of mode. * Origin top left of CRTC. * @user_roi_list : List of user's requested ROIs as from set property + * @cached_user_roi_list : Copy of user_roi_list from previous PU frame * @property_state: Local storage for msm_prop properties * @property_values: Current crtc property values * @input_fence_timeout_ns : Cached input fence timeout, in ns @@ -376,7 +377,7 @@ struct sde_crtc_state { struct sde_rect crtc_roi; struct sde_rect lm_bounds[CRTC_DUAL_MIXERS]; struct sde_rect lm_roi[CRTC_DUAL_MIXERS]; - struct msm_roi_list user_roi_list; + struct msm_roi_list user_roi_list, cached_user_roi_list; struct msm_property_state property_state; struct msm_property_value property_values[CRTC_PROP_COUNT]; From 3a9fbba852b3508e3577af46ebecd57858725ee6 Mon Sep 17 00:00:00 2001 From: Amine Najahi Date: Mon, 16 Dec 2019 10:32:46 -0500 Subject: [PATCH 4/4] msm: drm: uapi: add rounded corner uapi Add uapi for rounded corner programming. Change-Id: Id91892677c924c8e6871fe2708f89814a1435841 Signed-off-by: Amine Najahi --- include/uapi/display/drm/msm_drm_pp.h | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/include/uapi/display/drm/msm_drm_pp.h b/include/uapi/display/drm/msm_drm_pp.h index 264552359d09..59d23bef39c6 100644 --- a/include/uapi/display/drm/msm_drm_pp.h +++ b/include/uapi/display/drm/msm_drm_pp.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _MSM_DRM_PP_H_ @@ -570,4 +570,21 @@ struct drm_msm_ad4_manual_str_cfg { __u32 in_str; __u32 out_str; }; + +#define RC_DATA_SIZE_MAX 2720 +#define RC_CFG_SIZE_MAX 4 + +struct drm_msm_rc_mask_cfg { + __u64 flags; + __u32 cfg_param_01; + __u32 cfg_param_02; + __u32 cfg_param_03; + __u32 cfg_param_04[RC_CFG_SIZE_MAX]; + __u32 cfg_param_05[RC_CFG_SIZE_MAX]; + __u32 cfg_param_06[RC_CFG_SIZE_MAX]; + __u64 cfg_param_07; + __u32 cfg_param_08; + __u64 cfg_param_09[RC_DATA_SIZE_MAX]; +}; + #endif /* _MSM_DRM_PP_H_ */