Browse Source

Merge "disp: msm: sde: add support for new dspp flush" into display-kernel.lnx.5.4

Linux Build Service Account 5 years ago
parent
commit
bb0ca40080
5 changed files with 182 additions and 3 deletions
  1. 64 1
      msm/sde/sde_color_processing.c
  2. 3 0
      msm/sde/sde_hw_catalog.c
  3. 10 0
      msm/sde/sde_hw_catalog.h
  4. 90 2
      msm/sde/sde_hw_ctl.c
  5. 15 0
      msm/sde/sde_hw_ctl.h

+ 64 - 1
msm/sde/sde_color_processing.c

@@ -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.
  */
 
 #define pr_fmt(fmt)	"%s: " fmt, __func__
@@ -1252,6 +1252,68 @@ static void sde_cp_crtc_setfeature(struct sde_cp_node *prop_node,
 	list_del_init(&prop_node->dirty_list);
 }
 
+static const int dspp_feature_to_sub_blk_tbl[SDE_CP_CRTC_MAX_FEATURES] = {
+	[SDE_CP_CRTC_DSPP_IGC] = SDE_DSPP_IGC,
+	[SDE_CP_CRTC_DSPP_PCC] = SDE_DSPP_PCC,
+	[SDE_CP_CRTC_DSPP_GC] = SDE_DSPP_GC,
+	[SDE_CP_CRTC_DSPP_HSIC] = SDE_DSPP_HSIC,
+	[SDE_CP_CRTC_DSPP_MEMCOL_SKIN] = SDE_DSPP_MEMCOLOR,
+	[SDE_CP_CRTC_DSPP_MEMCOL_SKY] = SDE_DSPP_MEMCOLOR,
+	[SDE_CP_CRTC_DSPP_MEMCOL_FOLIAGE] = SDE_DSPP_MEMCOLOR,
+	[SDE_CP_CRTC_DSPP_MEMCOL_PROT] = SDE_DSPP_MEMCOLOR,
+	[SDE_CP_CRTC_DSPP_SIXZONE] = SDE_DSPP_SIXZONE,
+	[SDE_CP_CRTC_DSPP_GAMUT] = SDE_DSPP_GAMUT,
+	[SDE_CP_CRTC_DSPP_DITHER] = SDE_DSPP_DITHER,
+	[SDE_CP_CRTC_DSPP_HIST_CTRL] = SDE_DSPP_HIST,
+	[SDE_CP_CRTC_DSPP_HIST_IRQ] = SDE_DSPP_HIST,
+	[SDE_CP_CRTC_DSPP_AD] = SDE_DSPP_AD,
+	[SDE_CP_CRTC_DSPP_VLUT] = SDE_DSPP_VLUT,
+	[SDE_CP_CRTC_DSPP_AD_MODE] = SDE_DSPP_AD,
+	[SDE_CP_CRTC_DSPP_AD_INIT] = SDE_DSPP_AD,
+	[SDE_CP_CRTC_DSPP_AD_CFG] = SDE_DSPP_AD,
+	[SDE_CP_CRTC_DSPP_AD_INPUT] = SDE_DSPP_AD,
+	[SDE_CP_CRTC_DSPP_AD_ASSERTIVENESS] = SDE_DSPP_AD,
+	[SDE_CP_CRTC_DSPP_AD_BACKLIGHT] = SDE_DSPP_AD,
+	[SDE_CP_CRTC_DSPP_AD_STRENGTH] = SDE_DSPP_AD,
+	[SDE_CP_CRTC_DSPP_AD_ROI] = SDE_DSPP_AD,
+	[SDE_CP_CRTC_DSPP_LTM] = SDE_DSPP_LTM,
+	[SDE_CP_CRTC_DSPP_LTM_INIT] = SDE_DSPP_LTM,
+	[SDE_CP_CRTC_DSPP_LTM_ROI] = SDE_DSPP_LTM,
+	[SDE_CP_CRTC_DSPP_LTM_HIST_CTL] = SDE_DSPP_LTM,
+	[SDE_CP_CRTC_DSPP_LTM_HIST_THRESH] = SDE_DSPP_LTM,
+	[SDE_CP_CRTC_DSPP_LTM_SET_BUF] = SDE_DSPP_LTM,
+	[SDE_CP_CRTC_DSPP_LTM_QUEUE_BUF] = SDE_DSPP_LTM,
+	[SDE_CP_CRTC_DSPP_LTM_QUEUE_BUF2] = SDE_DSPP_LTM,
+	[SDE_CP_CRTC_DSPP_LTM_QUEUE_BUF3] = SDE_DSPP_LTM,
+	[SDE_CP_CRTC_DSPP_LTM_VLUT] = SDE_DSPP_LTM,
+	[SDE_CP_CRTC_DSPP_MAX] = SDE_DSPP_MAX,
+	[SDE_CP_CRTC_LM_GC] = SDE_DSPP_MAX,
+};
+
+void sde_cp_dspp_flush_helper(struct sde_crtc *sde_crtc, u32 feature)
+{
+	u32 i, sub_blk, num_mixers;
+	enum sde_dspp dspp;
+	struct sde_hw_ctl *ctl;
+
+	if (!sde_crtc || feature >= SDE_CP_CRTC_MAX_FEATURES) {
+		SDE_ERROR("invalid args: sde_crtc %s for feature %d",
+				sde_crtc ? "valid" : "invalid", feature);
+		return;
+	}
+
+	num_mixers = sde_crtc->num_mixers;
+	sub_blk = dspp_feature_to_sub_blk_tbl[feature];
+
+	for (i = 0; i < num_mixers; i++) {
+		ctl = sde_crtc->mixers[i].hw_ctl;
+		dspp = sde_crtc->mixers[i].hw_dspp->idx;
+		if (ctl && ctl->ops.update_bitmask_dspp_subblk)
+			ctl->ops.update_bitmask_dspp_subblk(
+					ctl, dspp, sub_blk, true);
+	}
+}
+
 void sde_cp_crtc_apply_properties(struct drm_crtc *crtc)
 {
 	struct sde_crtc *sde_crtc = NULL;
@@ -1299,6 +1361,7 @@ void sde_cp_crtc_apply_properties(struct drm_crtc *crtc)
 	list_for_each_entry_safe(prop_node, n, &sde_crtc->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;

+ 3 - 0
msm/sde/sde_hw_catalog.c

@@ -1742,6 +1742,9 @@ static int sde_ctl_parse_dt(struct device_node *np,
 			set_bit(SDE_CTL_ACTIVE_CFG, &ctl->features);
 		if (IS_SDE_UIDLE_REV_100(sde_cfg->uidle_cfg.uidle_rev))
 			set_bit(SDE_CTL_UIDLE, &ctl->features);
+		if (SDE_HW_MAJOR(sde_cfg->hwversion) >=
+				SDE_HW_MAJOR(SDE_HW_VER_700))
+			set_bit(SDE_CTL_UNIFIED_DSPP_FLUSH, &ctl->features);
 	}
 end:
 	kfree(prop_value);

+ 10 - 0
msm/sde/sde_hw_catalog.h

@@ -314,6 +314,10 @@ enum {
  * @SDE_DSPP_VLUT            PA VLUT block
  * @SDE_DSPP_AD              AD block
  * @SDE_DSPP_LTM             LTM block
+ * @SDE_DSPP_SPR             SPR block
+ * @SDE_DSPP_DEMURA          Demura block
+ * @SDE_DSPP_RC              RC block
+ * @SDE_DSPP_SB              SB LUT DMA
  * @SDE_DSPP_MAX             maximum value
  */
 enum {
@@ -329,6 +333,10 @@ enum {
 	SDE_DSPP_VLUT,
 	SDE_DSPP_AD,
 	SDE_DSPP_LTM,
+	SDE_DSPP_SPR,
+	SDE_DSPP_DEMURA,
+	SDE_DSPP_RC,
+	SDE_DSPP_SB,
 	SDE_DSPP_MAX
 };
 
@@ -396,6 +404,7 @@ enum {
  * @SDE_CTL_ACTIVE_CFG          CTL configuration is specified using active
  *                              blocks
  * @SDE_CTL_UIDLE               CTL supports uidle
+ * @SDE_CTL_UNIFIED_DSPP_FLUSH  CTL supports only one flush bit for DSPP
  * @SDE_CTL_MAX
  */
 enum {
@@ -404,6 +413,7 @@ enum {
 	SDE_CTL_PRIMARY_PREF,
 	SDE_CTL_ACTIVE_CFG,
 	SDE_CTL_UIDLE,
+	SDE_CTL_UNIFIED_DSPP_FLUSH,
 	SDE_CTL_MAX
 };
 

+ 90 - 2
msm/sde/sde_hw_ctl.c

@@ -45,6 +45,7 @@
 #define   CTL_INTF_FLUSH               0x110
 #define   CTL_CDM_FLUSH                0x114
 #define   CTL_PERIPH_FLUSH             0x128
+#define   CTL_DSPP_0_FLUSH             0x13c
 
 #define  CTL_INTF_MASTER               0x134
 #define  CTL_UIDLE_ACTIVE              0x138
@@ -153,6 +154,28 @@ static const u32 cdm_flush_tbl[CDM_MAX] = {SDE_NONE, 0};
 static const u32 cwb_flush_tbl[CWB_MAX] = {SDE_NONE, SDE_NONE, 1, 2, 3,
 	4, 5};
 
+/**
+ * list of DSPP sub-blk flush bits in CTL_DSPP_x_FLUSH
+ */
+static const u32 dspp_sub_blk_flush_tbl[SDE_DSPP_MAX] = {
+	[SDE_DSPP_IGC] = 2,
+	[SDE_DSPP_PCC] = 4,
+	[SDE_DSPP_GC] = 5,
+	[SDE_DSPP_HSIC] = 0,
+	[SDE_DSPP_MEMCOLOR] = 0,
+	[SDE_DSPP_SIXZONE] = 0,
+	[SDE_DSPP_GAMUT] = 3,
+	[SDE_DSPP_DITHER] = 0,
+	[SDE_DSPP_HIST] = 0,
+	[SDE_DSPP_VLUT] = 1,
+	[SDE_DSPP_AD] = 0,
+	[SDE_DSPP_LTM] = 7,
+	[SDE_DSPP_SPR] = 8,
+	[SDE_DSPP_DEMURA] = 9,
+	[SDE_DSPP_RC] = 10,
+	[SDE_DSPP_SB] = 31,
+};
+
 /**
  * struct ctl_sspp_stage_reg_map: Describes bit layout for a sspp stage cfg
  * @ext: Index to indicate LAYER_x_EXT id for given sspp
@@ -195,6 +218,7 @@ sspp_reg_cfg_tbl[SSPP_MAX][CTL_SSPP_MAX_RECTS] = {
 #define  MERGE_3D_IDX   23
 #define  CDM_IDX        26
 #define  CWB_IDX        28
+#define  DSPP_IDX       29
 #define  PERIPH_IDX     30
 #define  INTF_IDX       31
 
@@ -234,6 +258,18 @@ static int _mixer_stages(const struct sde_lm_cfg *mixer, int count,
 	return stages;
 }
 
+static inline bool _is_dspp_flush_pending(struct sde_hw_ctl *ctx)
+{
+	int i;
+
+	for (i = 0; i < CTL_MAX_DSPP_COUNT; i++) {
+		if (ctx->flush.pending_dspp_flush_masks[i])
+			return true;
+	}
+
+	return false;
+}
+
 static inline int sde_hw_ctl_trigger_start(struct sde_hw_ctl *ctx)
 {
 	if (!ctx)
@@ -585,6 +621,8 @@ static inline int sde_hw_ctl_update_pending_flush_v1(
 		struct sde_hw_ctl *ctx,
 		struct sde_ctl_flush_cfg *cfg)
 {
+	int i;
+
 	if (!ctx || !cfg)
 		return -EINVAL;
 
@@ -597,9 +635,50 @@ static inline int sde_hw_ctl_update_pending_flush_v1(
 		cfg->pending_merge_3d_flush_mask;
 	ctx->flush.pending_cwb_flush_mask |= cfg->pending_cwb_flush_mask;
 	ctx->flush.pending_periph_flush_mask |= cfg->pending_periph_flush_mask;
+	for (i = 0; i < CTL_MAX_DSPP_COUNT; i++)
+		ctx->flush.pending_dspp_flush_masks[i] |=
+				cfg->pending_dspp_flush_masks[i];
+
 	return 0;
 }
 
+static inline int sde_hw_ctl_update_bitmask_dspp_subblk(struct sde_hw_ctl *ctx,
+		enum sde_dspp dspp, u32 sub_blk, bool enable)
+{
+	if (!ctx || dspp < DSPP_0 || dspp >= DSPP_MAX ||
+			sub_blk < SDE_DSPP_IGC || sub_blk >= SDE_DSPP_MAX) {
+		SDE_ERROR("invalid args - ctx %s, dspp %d sub_block %d\n",
+				ctx ? "valid" : "invalid", dspp, sub_blk);
+		return -EINVAL;
+	}
+
+	UPDATE_MASK(ctx->flush.pending_dspp_flush_masks[dspp - DSPP_0],
+			dspp_sub_blk_flush_tbl[sub_blk], enable);
+	if (_is_dspp_flush_pending(ctx))
+		UPDATE_MASK(ctx->flush.pending_flush_mask, DSPP_IDX, 1);
+	else
+		UPDATE_MASK(ctx->flush.pending_flush_mask, DSPP_IDX, 0);
+
+	return 0;
+}
+
+static inline void _sde_hw_ctl_write_dspp_flushes(struct sde_hw_ctl *ctx) {
+	int i;
+	bool has_dspp_flushes = ctx->caps->features &
+			BIT(SDE_CTL_UNIFIED_DSPP_FLUSH);
+
+	if (!has_dspp_flushes)
+		return;
+
+	for (i = 0; i < CTL_MAX_DSPP_COUNT; i++) {
+		u32 pending = ctx->flush.pending_dspp_flush_masks[i];
+
+		if (pending)
+			SDE_REG_WRITE(&ctx->hw, CTL_DSPP_0_FLUSH + (i * 4),
+					pending);
+	}
+}
+
 static inline int sde_hw_ctl_trigger_flush_v1(struct sde_hw_ctl *ctx)
 {
 	if (!ctx)
@@ -626,6 +705,8 @@ static inline int sde_hw_ctl_trigger_flush_v1(struct sde_hw_ctl *ctx)
 	if (ctx->flush.pending_flush_mask & BIT(PERIPH_IDX))
 		SDE_REG_WRITE(&ctx->hw, CTL_PERIPH_FLUSH,
 				ctx->flush.pending_periph_flush_mask);
+	if (ctx->flush.pending_flush_mask & BIT(DSPP_IDX))
+		_sde_hw_ctl_write_dspp_flushes(ctx);
 
 	SDE_REG_WRITE(&ctx->hw, CTL_FLUSH, ctx->flush.pending_flush_mask);
 	return 0;
@@ -1323,11 +1404,18 @@ static void _setup_ctl_ops(struct sde_hw_ctl_ops *ops,
 	ops->get_staged_sspp = sde_hw_ctl_get_staged_sspp;
 	ops->update_bitmask_sspp = sde_hw_ctl_update_bitmask_sspp;
 	ops->update_bitmask_mixer = sde_hw_ctl_update_bitmask_mixer;
-	ops->update_bitmask_dspp = sde_hw_ctl_update_bitmask_dspp;
-	ops->update_bitmask_dspp_pavlut = sde_hw_ctl_update_bitmask_dspp_pavlut;
 	ops->reg_dma_flush = sde_hw_reg_dma_flush;
 	ops->get_start_state = sde_hw_ctl_get_start_state;
 
+	if (cap & BIT(SDE_CTL_UNIFIED_DSPP_FLUSH)) {
+		ops->update_bitmask_dspp_subblk =
+				sde_hw_ctl_update_bitmask_dspp_subblk;
+	} else {
+		ops->update_bitmask_dspp = sde_hw_ctl_update_bitmask_dspp;
+		ops->update_bitmask_dspp_pavlut =
+				sde_hw_ctl_update_bitmask_dspp_pavlut;
+	}
+
 	if (cap & BIT(SDE_CTL_UIDLE))
 		ops->uidle_enable = sde_hw_ctl_uidle_enable;
 };

+ 15 - 0
msm/sde/sde_hw_ctl.h

@@ -13,6 +13,7 @@
 #include "sde_hw_blk.h"
 
 #define INVALID_CTL_STATUS 0xfffff88e
+#define CTL_MAX_DSPP_COUNT (DSPP_MAX - DSPP_0)
 
 /**
  * sde_ctl_mode_sel: Interface mode selection
@@ -129,6 +130,7 @@ struct sde_hw_intf_cfg_v1 {
  * @pending_merge_3d_flush_mask: pending 3d merge block flush
  * @pending_cwb_flush_mask: pending flush for concurrent writeback
  * @pending_periph_flush_mask: pending flush for peripheral module
+ * @pending_dspp_flush_masks: pending flush masks for sub-blks of each DSPP
  */
 struct sde_ctl_flush_cfg {
 	u32 pending_flush_mask;
@@ -139,6 +141,7 @@ struct sde_ctl_flush_cfg {
 	u32 pending_merge_3d_flush_mask;
 	u32 pending_cwb_flush_mask;
 	u32 pending_periph_flush_mask;
+	u32 pending_dspp_flush_masks[CTL_MAX_DSPP_COUNT];
 };
 
 /**
@@ -331,6 +334,18 @@ struct sde_hw_ctl_ops {
 	int (*update_bitmask_dspp_pavlut)(struct sde_hw_ctl *ctx,
 		enum sde_dspp blk, bool enable);
 
+	/**
+	 * Program DSPP sub block specific bit of dspp flush register.
+	 * @ctx       : ctl path ctx pointer
+	 * @dspp      : HW block ID of dspp block
+	 * @sub_blk   : enum of DSPP sub block to flush
+	 * @enable    : true to enable, 0 to disable
+	 *
+	 * This API is for CTL with DSPP flush hierarchy registers.
+	 */
+	int (*update_bitmask_dspp_subblk)(struct sde_hw_ctl *ctx,
+			enum sde_dspp dspp, u32 sub_blk, bool enable);
+
 	/**
 	 * update_bitmask_sspp: updates mask corresponding to sspp
 	 * @blk               : blk id