Browse Source

sde: wb: add changes to support Dedicated-CWB

Add new capture/tap point as CRTC property for
D-CWB feature. Update the hardware blocks and
corresponding APIs to configure D-CWB data path.
Add new hardware pingpong blocks that
are dedicated for CWB.

Change-Id: I22576df1768b50f9f47d8527f62913b01ff4d9a7
Signed-off-by: Chandan Uddaraju <[email protected]>
Chandan Uddaraju 4 năm trước cách đây
mục cha
commit
4fe3d97078

+ 12 - 1
msm/sde/sde_crtc.c

@@ -5454,6 +5454,12 @@ static void sde_crtc_install_properties(struct drm_crtc *crtc,
 		{CAPTURE_DSPP_OUT, "capture_pp_out"},
 	};
 
+	static const struct drm_prop_enum_list e_dcwb_data_points[] = {
+		{CAPTURE_MIXER_OUT, "capture_mixer_out"},
+		{CAPTURE_DSPP_OUT, "capture_pp_out"},
+		{CAPTURE_DEMURA_OUT, "capture_demura_out"},
+	};
+
 	static const struct drm_prop_enum_list e_idle_pc_state[] = {
 		{IDLE_PC_NONE, "idle_pc_none"},
 		{IDLE_PC_ENABLE, "idle_pc_enable"},
@@ -5524,7 +5530,12 @@ static void sde_crtc_install_properties(struct drm_crtc *crtc,
 			ARRAY_SIZE(e_idle_pc_state), 0,
 			CRTC_PROP_IDLE_PC_STATE);
 
-	if (catalog->has_cwb_support)
+	if (catalog->has_dedicated_cwb_support)
+		msm_property_install_enum(&sde_crtc->property_info,
+				"capture_mode", 0, 0, e_dcwb_data_points,
+				ARRAY_SIZE(e_dcwb_data_points), 0,
+				CRTC_PROP_CAPTURE_OUTPUT);
+	else if (catalog->has_cwb_support)
 		msm_property_install_enum(&sde_crtc->property_info,
 				"capture_mode", 0, 0, e_cwb_data_points,
 				ARRAY_SIZE(e_cwb_data_points), 0,

+ 3 - 1
msm/sde/sde_crtc.h

@@ -56,10 +56,12 @@ enum sde_crtc_client_type {
  * enum sde_crtc_output_capture_point
  * @MIXER_OUT : capture mixer output
  * @DSPP_OUT : capture output of dspp
+ * @CAPTURE_DEMURA_OUT : capture output of demura
  */
 enum sde_crtc_output_capture_point {
 	CAPTURE_MIXER_OUT,
-	CAPTURE_DSPP_OUT
+	CAPTURE_DSPP_OUT,
+	CAPTURE_DEMURA_OUT
 };
 
 /**

+ 49 - 18
msm/sde/sde_encoder_phys_wb.c

@@ -467,12 +467,14 @@ static void _sde_encoder_phys_wb_setup_cwb(struct sde_encoder_phys *phys_enc,
 
 	hw_ctl = crtc->mixers[0].hw_ctl;
 	if (hw_ctl && hw_ctl->ops.setup_intf_cfg_v1 &&
-			test_bit(SDE_WB_CWB_CTRL, &hw_wb->caps->features)) {
+			test_bit(SDE_WB_CWB_CTRL | SDE_WB_DCWB_CTRL,
+					&hw_wb->caps->features)) {
 		struct sde_hw_intf_cfg_v1 intf_cfg = { 0, };
 
 		for (i = 0; i < crtc->num_mixers; i++)
-			intf_cfg.cwb[intf_cfg.cwb_count++] =
-				(enum sde_cwb)(hw_pp->idx + i);
+			intf_cfg.cwb[intf_cfg.cwb_count++] = (enum sde_cwb)
+				(test_bit(SDE_WB_DCWB_CTRL, &hw_wb->caps->features) ?
+					((hw_pp->idx % 2) + i) : (hw_pp->idx + i));
 
 		if (hw_pp->merge_3d && (intf_cfg.merge_3d_count <
 				MAX_MERGE_3D_PER_CTL_V1) && need_merge)
@@ -483,12 +485,17 @@ static void _sde_encoder_phys_wb_setup_cwb(struct sde_encoder_phys *phys_enc,
 			hw_pp->ops.setup_3d_mode(hw_pp, (enable && need_merge) ?
 					BLEND_3D_H_ROW_INT : 0);
 
-		if (hw_wb->ops.bind_pingpong_blk)
+		if ((hw_wb->ops.bind_pingpong_blk) &&
+				test_bit(SDE_WB_CWB_CTRL, &hw_wb->caps->features))
 			hw_wb->ops.bind_pingpong_blk(hw_wb, enable, hw_pp->idx);
 
+		if ((hw_wb->ops.bind_dcwb_pp_blk) &&
+				test_bit(SDE_WB_DCWB_CTRL, &hw_wb->caps->features))
+			hw_wb->ops.bind_dcwb_pp_blk(hw_wb, enable, hw_pp->idx);
+
 		if (hw_ctl->ops.update_intf_cfg) {
 			hw_ctl->ops.update_intf_cfg(hw_ctl, &intf_cfg, enable);
-			SDE_DEBUG("in CWB mode on CTL_%d PP-%d merge3d:%d\n",
+			SDE_DEBUG("in CWB/DCWB mode on CTL_%d PP-%d merge3d:%d\n",
 					hw_ctl->idx - CTL_0,
 					hw_pp->idx - PINGPONG_0,
 					hw_pp->merge_3d ?
@@ -503,7 +510,7 @@ static void _sde_encoder_phys_wb_setup_cwb(struct sde_encoder_phys *phys_enc,
 
 		if (hw_ctl && hw_ctl->ops.update_wb_cfg) {
 			hw_ctl->ops.update_wb_cfg(hw_ctl, intf_cfg, enable);
-			SDE_DEBUG("in CWB mode adding WB for CTL_%d\n",
+			SDE_DEBUG("in CWB/DCWB mode adding WB for CTL_%d\n",
 					hw_ctl->idx - CTL_0);
 		}
 	}
@@ -593,13 +600,14 @@ static void _sde_enc_phys_wb_detect_cwb(struct sde_encoder_phys *phys_enc,
 	u32 encoder_mask = 0;
 
 	/* Check if WB has CWB support */
-	if (wb_cfg->features & BIT(SDE_WB_HAS_CWB)) {
+	if ((wb_cfg->features & BIT(SDE_WB_HAS_CWB))
+			|| (wb_cfg->features & BIT(SDE_WB_HAS_DCWB))) {
 		encoder_mask = crtc_state->encoder_mask;
 		encoder_mask &= ~drm_encoder_mask(phys_enc->parent);
 	}
 	phys_enc->in_clone_mode = encoder_mask ? true : false;
 
-	SDE_DEBUG("detect CWB - status:%d\n", phys_enc->in_clone_mode);
+	SDE_DEBUG("detect CWB(OR)DCWB - status:%d\n", phys_enc->in_clone_mode);
 }
 
 static int _sde_enc_phys_wb_validate_cwb(struct sde_encoder_phys *phys_enc,
@@ -863,6 +871,7 @@ static void _sde_encoder_phys_wb_update_cwb_flush(
 	int i = 0;
 	int cwb_capture_mode = 0;
 	enum sde_cwb cwb_idx = 0;
+	enum sde_dcwb dcwb_idx = 0;
 	enum sde_cwb src_pp_idx = 0;
 	bool dspp_out = false;
 	bool need_merge = false;
@@ -895,9 +904,19 @@ static void _sde_encoder_phys_wb_update_cwb_flush(
 	dspp_out = (cwb_capture_mode == CAPTURE_DSPP_OUT);
 	need_merge = (crtc->num_mixers > 1) ? true : false;
 
-	if (src_pp_idx > CWB_0 ||  ((cwb_idx + crtc->num_mixers) > CWB_MAX)) {
-		SDE_ERROR("invalid hw config for CWB\n");
-		return;
+	if (test_bit(SDE_WB_DCWB_CTRL, &hw_wb->caps->features)) {
+		dcwb_idx = (enum sde_dcwb) ((hw_pp->idx % 2) + i);
+		if ((dcwb_idx + crtc->num_mixers) > DCWB_MAX) {
+			SDE_ERROR("invalid hw config for DCWB. dcwb_idx=%d, num_mixers=%d\n",
+				dcwb_idx, crtc->num_mixers);
+			return;
+		}
+	} else {
+		if (src_pp_idx > CWB_0 ||  ((cwb_idx + crtc->num_mixers) > CWB_MAX)) {
+			SDE_ERROR("invalid hw config for CWB. pp_idx-%d, cwb_idx=%d, num_mixers=%d\n",
+				src_pp_idx, dcwb_idx, crtc->num_mixers);
+			return;
+		}
 	}
 
 	if (hw_ctl->ops.update_bitmask)
@@ -908,18 +927,30 @@ static void _sde_encoder_phys_wb_update_cwb_flush(
 		hw_ctl->ops.update_bitmask(hw_ctl, SDE_HW_FLUSH_CDM,
 				hw_cdm->idx, 1);
 
-	if (test_bit(SDE_WB_CWB_CTRL, &hw_wb->caps->features)) {
+	if (test_bit(SDE_WB_CWB_CTRL | SDE_WB_DCWB_CTRL,
+					&hw_wb->caps->features)) {
 		for (i = 0; i < crtc->num_mixers; i++) {
-			cwb_idx = (enum sde_cwb) (hw_pp->idx + i);
 			src_pp_idx = (enum sde_cwb) (src_pp_idx + i);
 
-			if (hw_wb->ops.program_cwb_ctrl)
-				hw_wb->ops.program_cwb_ctrl(hw_wb, cwb_idx,
+			if (test_bit(SDE_WB_DCWB_CTRL, &hw_wb->caps->features)) {
+				dcwb_idx = (enum sde_dcwb) ((hw_pp->idx % 2) + i);
+				if (hw_wb->ops.program_dcwb_ctrl)
+					hw_wb->ops.program_dcwb_ctrl(hw_wb, dcwb_idx,
+						src_pp_idx, cwb_capture_mode,
+						enable);
+				if (hw_ctl->ops.update_bitmask)
+					hw_ctl->ops.update_bitmask(hw_ctl,
+						SDE_HW_FLUSH_CWB, dcwb_idx, 1);
+
+			} else if (test_bit(SDE_WB_CWB_CTRL, &hw_wb->caps->features)) {
+				cwb_idx = (enum sde_cwb) (hw_pp->idx + i);
+				if (hw_wb->ops.program_cwb_ctrl)
+					hw_wb->ops.program_cwb_ctrl(hw_wb, cwb_idx,
 						src_pp_idx, dspp_out, enable);
-
-			if (hw_ctl->ops.update_bitmask)
-				hw_ctl->ops.update_bitmask(hw_ctl,
+				if (hw_ctl->ops.update_bitmask)
+					hw_ctl->ops.update_bitmask(hw_ctl,
 						SDE_HW_FLUSH_CWB, cwb_idx, 1);
+			}
 		}
 
 		if (need_merge && hw_ctl->ops.update_bitmask

+ 18 - 2
msm/sde/sde_hw_catalog.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
  */
 
 #define pr_fmt(fmt)	"[drm:%s:%d] " fmt, __func__, __LINE__
@@ -306,6 +306,7 @@ enum {
 enum {
 	PP_OFF,
 	PP_LEN,
+	PP_CWB,
 	TE_OFF,
 	TE_LEN,
 	TE2_OFF,
@@ -782,6 +783,7 @@ static struct sde_prop_type ds_prop[] = {
 static struct sde_prop_type pp_prop[] = {
 	{PP_OFF, "qcom,sde-pp-off", true, PROP_TYPE_U32_ARRAY},
 	{PP_LEN, "qcom,sde-pp-size", false, PROP_TYPE_U32},
+	{PP_CWB, "qcom,sde-pp-cwb", false, PROP_TYPE_U32_ARRAY},
 	{TE_OFF, "qcom,sde-te-off", false, PROP_TYPE_U32_ARRAY},
 	{TE_LEN, "qcom,sde-te-size", false, PROP_TYPE_U32},
 	{TE2_OFF, "qcom,sde-te2-off", false, PROP_TYPE_U32_ARRAY},
@@ -2349,7 +2351,18 @@ static int sde_wb_parse_dt(struct device_node *np, struct sde_mdss_cfg *sde_cfg)
 		if (IS_SDE_CTL_REV_100(sde_cfg->ctl_rev))
 			set_bit(SDE_WB_INPUT_CTRL, &wb->features);
 
-		if (sde_cfg->has_cwb_support) {
+		if (sde_cfg->has_dedicated_cwb_support) {
+			set_bit(SDE_WB_HAS_DCWB, &wb->features);
+			if (IS_SDE_CTL_REV_100(sde_cfg->ctl_rev))
+				set_bit(SDE_WB_DCWB_CTRL, &wb->features);
+			if (major_version >= SDE_HW_MAJOR(SDE_HW_VER_810)) {
+				sde_cfg->cwb_blk_off = 0x66A00;
+				sde_cfg->cwb_blk_stride = 0x400;
+			} else {
+				sde_cfg->cwb_blk_off = 0x83000;
+				sde_cfg->cwb_blk_stride = 0x100;
+			}
+		} else if (sde_cfg->has_cwb_support) {
 			set_bit(SDE_WB_HAS_CWB, &wb->features);
 			if (IS_SDE_CTL_REV_100(sde_cfg->ctl_rev))
 				set_bit(SDE_WB_CWB_CTRL, &wb->features);
@@ -3629,6 +3642,9 @@ static int sde_pp_parse_dt(struct device_node *np, struct sde_mdss_cfg *sde_cfg)
 		if (PROP_VALUE_ACCESS(prop_value, PP_SLAVE, i))
 			set_bit(SDE_PINGPONG_SLAVE, &pp->features);
 
+		if (PROP_VALUE_ACCESS(prop_value, PP_CWB, i))
+			set_bit(SDE_PINGPONG_CWB, &pp->features);
+
 		if (major_version < SDE_HW_MAJOR(SDE_HW_VER_700)) {
 			sblk->dsc.base = PROP_VALUE_ACCESS(prop_value,
 					DSC_OFF, i);

+ 9 - 1
msm/sde/sde_hw_catalog.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
  */
 
 #ifndef _SDE_HW_CATALOG_H
@@ -401,6 +401,7 @@ enum {
  * @SDE_PINGPONG_DITHER,         Dither blocks
  * @SDE_PINGPONG_DITHER_LUMA,    Dither sub-blocks and features
  * @SDE_PINGPONG_MERGE_3D,  Separate MERGE_3D block exists
+ * @SDE_PINGPONG_CWB,           PP block supports CWB
  * @SDE_PINGPONG_MAX
  */
 enum {
@@ -412,6 +413,7 @@ enum {
 	SDE_PINGPONG_DITHER,
 	SDE_PINGPONG_DITHER_LUMA,
 	SDE_PINGPONG_MERGE_3D,
+	SDE_PINGPONG_CWB,
 	SDE_PINGPONG_MAX
 };
 
@@ -508,7 +510,9 @@ enum {
  * @SDE_WB_INPUT_CTRL       Writeback supports from which pp block input pixel
  *                          data arrives.
  * @SDE_WB_HAS_CWB          Writeback block supports concurrent writeback
+ * @SDE_WB_HAS_DCWB         Writeback block supports dedicated CWB
  * @SDE_WB_CWB_CTRL         Separate CWB control is available for configuring
+ * @SDE_WB_DCWB_CTRL        Separate DCWB control is available for configuring
  * @SDE_WB_MAX              maximum value
  */
 enum {
@@ -529,7 +533,9 @@ enum {
 	SDE_WB_CDP,
 	SDE_WB_INPUT_CTRL,
 	SDE_WB_HAS_CWB,
+	SDE_WB_HAS_DCWB,
 	SDE_WB_CWB_CTRL,
+	SDE_WB_DCWB_CTRL,
 	SDE_WB_MAX
 };
 
@@ -1400,6 +1406,7 @@ struct sde_perf_cfg {
  * @has_cdp            Client driven prefetch feature status
  * @has_wb_ubwc        UBWC feature supported on WB
  * @has_cwb_support    indicates if device supports primary capture through CWB
+ * @has_dedicated_cwb_support    indicates if device supports dedicated path for CWB capture
  * @cwb_blk_off        CWB offset address
  * @cwb_blk_stride     offset between each CWB blk
  * @ubwc_version       UBWC feature version (0x0 for not supported)
@@ -1481,6 +1488,7 @@ struct sde_mdss_cfg {
 	bool has_dim_layer;
 	bool has_wb_ubwc;
 	bool has_cwb_support;
+	bool has_dedicated_cwb_support;
 	u32 cwb_blk_off;
 	u32 cwb_blk_stride;
 	u32 ubwc_version;

+ 5 - 0
msm/sde/sde_hw_ctl.c

@@ -161,6 +161,11 @@ 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 CWB bits in CTL_CWB_FLUSH for dedicated cwb
+ */
+static const u32 dcwb_flush_tbl[CWB_MAX] = {SDE_NONE, SDE_NONE, 0, 1};
+
 /**
  * list of DSPP sub-blk flush bits in CTL_DSPP_x_FLUSH
  */

+ 10 - 1
msm/sde/sde_hw_mdss.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
  */
 
 #ifndef _SDE_HW_MDSS_H
@@ -223,6 +223,8 @@ enum sde_pingpong {
 	PINGPONG_3,
 	PINGPONG_4,
 	PINGPONG_5,
+	PINGPONG_CWB_0,
+	PINGPONG_CWB_1,
 	PINGPONG_S0,
 	PINGPONG_MAX
 };
@@ -302,6 +304,12 @@ enum sde_cwb {
 	CWB_MAX
 };
 
+enum sde_dcwb {
+	DCWB_0 = 0x1,
+	DCWB_1,
+	DCWB_MAX
+};
+
 enum sde_wd_timer {
 	WD_TIMER_0 = 0x1,
 	WD_TIMER_1,
@@ -335,6 +343,7 @@ enum sde_merge_3d {
 	MERGE_3D_0 = 1,
 	MERGE_3D_1,
 	MERGE_3D_2,
+	MERGE_3D_CWB_0,
 	MERGE_3D_MAX
 };
 

+ 74 - 1
msm/sde/sde_hw_wb.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
  */
 
 #include "sde_hw_mdss.h"
@@ -99,6 +99,31 @@ static void _sde_hw_cwb_ctrl_init(struct sde_mdss_cfg *m,
 	}
 }
 
+static void _sde_hw_dcwb_ctrl_init(struct sde_mdss_cfg *m,
+		void __iomem *addr, struct sde_hw_blk_reg_map *b)
+{
+	int i;
+	u32 blk_off;
+	char name[64] = {0};
+
+	if (!b)
+		return;
+
+	b->base_off = addr;
+	b->blk_off = m->cwb_blk_off;
+	b->length = 0x20;
+	b->hwversion = m->hwversion;
+	b->log_mask = SDE_DBG_MASK_WB;
+
+	for (i = 0; i < m->pingpong_count; i++) {
+		snprintf(name, sizeof(name), "dcwb%d", i);
+		blk_off = b->blk_off + (m->cwb_blk_stride * i);
+
+		sde_dbg_reg_register_dump_range(SDE_DBG_NAME, name,
+				blk_off, blk_off + b->length, 0xff);
+	}
+}
+
 static void sde_hw_wb_setup_outaddress(struct sde_hw_wb *ctx,
 		struct sde_hw_wb_cfg *data)
 {
@@ -270,6 +295,46 @@ static void sde_hw_wb_bind_pingpong_blk(
 	SDE_REG_WRITE(c, WB_MUX, mux_cfg);
 }
 
+static void sde_hw_wb_bind_dcwb_pp_blk(
+		struct sde_hw_wb *ctx,
+		bool enable,
+		const enum sde_pingpong pp)
+{
+	struct sde_hw_blk_reg_map *c;
+	int mux_cfg = 0xF;
+
+	if (!ctx)
+		return;
+
+	c = &ctx->hw;
+	if (enable)
+		mux_cfg = 0xd;
+
+	SDE_REG_WRITE(c, WB_MUX, mux_cfg);
+}
+
+static void sde_hw_wb_program_dcwb_ctrl(struct sde_hw_wb *ctx,
+	const enum sde_dcwb cur_idx, const enum sde_cwb data_src,
+	int tap_location, bool enable)
+{
+	struct sde_hw_blk_reg_map *c;
+	u32 blk_base;
+
+	if (!ctx)
+		return;
+
+	c = &ctx->dcwb_hw;
+	blk_base  = ctx->catalog->cwb_blk_stride * (cur_idx - DCWB_0);
+
+	if (enable) {
+		SDE_REG_WRITE(c, blk_base + CWB_CTRL_SRC_SEL, data_src - CWB_0);
+		SDE_REG_WRITE(c, blk_base + CWB_CTRL_MODE, tap_location);
+	} else {
+		SDE_REG_WRITE(c, blk_base + CWB_CTRL_SRC_SEL, 0xf);
+		SDE_REG_WRITE(c, blk_base + CWB_CTRL_MODE, 0x0);
+	}
+}
+
 static void sde_hw_wb_program_cwb_ctrl(struct sde_hw_wb *ctx,
 	const enum sde_cwb cur_idx, const enum sde_cwb data_src,
 	bool dspp_out, bool enable)
@@ -312,6 +377,11 @@ static void _setup_wb_ops(struct sde_hw_wb_ops *ops,
 
 	if (test_bit(SDE_WB_CWB_CTRL, &features))
 		ops->program_cwb_ctrl = sde_hw_wb_program_cwb_ctrl;
+
+	if (test_bit(SDE_WB_DCWB_CTRL, &features)) {
+		ops->program_dcwb_ctrl = sde_hw_wb_program_dcwb_ctrl;
+		ops->bind_dcwb_pp_blk = sde_hw_wb_bind_dcwb_pp_blk;
+	}
 }
 
 static struct sde_hw_blk_ops sde_hw_ops = {
@@ -362,6 +432,9 @@ struct sde_hw_wb *sde_hw_wb_init(enum sde_wb idx,
 	if (test_bit(SDE_WB_CWB_CTRL, &cfg->features))
 		_sde_hw_cwb_ctrl_init(m, addr, &c->cwb_hw);
 
+	if (test_bit(SDE_WB_DCWB_CTRL, &cfg->features))
+		_sde_hw_dcwb_ctrl_init(m, addr, &c->dcwb_hw);
+
 	return c;
 
 blk_init_error:

+ 24 - 1
msm/sde/sde_hw_wb.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
  */
 
 #ifndef _SDE_HW_WB_H
@@ -114,6 +114,16 @@ struct sde_hw_wb_ops {
 			bool enable,
 			const enum sde_pingpong pp);
 
+	/**
+	 * bind_dcwb_pp_blk - enable/disable the connection with cwb pp
+	 * @ctx: Pointer to wb context
+	 * @enable: enable/disable connection
+	 * @pp: pingpong blk id
+	 */
+	void (*bind_dcwb_pp_blk)(struct sde_hw_wb *ctx,
+			bool enable,
+			const enum sde_pingpong pp);
+
 	/**
 	 * program_cwb_ctrl - program cwb block configp
 	 * @ctx: Pointer to wb context
@@ -124,6 +134,17 @@ struct sde_hw_wb_ops {
 	 */
 	void (*program_cwb_ctrl)(struct sde_hw_wb *ctx, const enum sde_cwb cwb,
 		const enum sde_cwb data_src, bool dspp_out, bool enable);
+
+	/**
+	 * program_dcwb_ctrl - program cwb block configp
+	 * @ctx: Pointer to wb context
+	 * @pp_idx: Current CWB block index to poram
+	 * @data_src: Source CWB/PingPong block index
+	 * @tap_location: Tap LM output, dspp output or Demura output
+	 * @enable: enable or disable the CWB path to tap the output
+	 */
+	void (*program_dcwb_ctrl)(struct sde_hw_wb *ctx, const enum sde_dcwb cwb,
+		const enum sde_cwb data_src, int tap_location, bool enable);
 };
 
 /**
@@ -137,6 +158,7 @@ struct sde_hw_wb_ops {
  * @ops: function pointers
  * @hw_mdp: MDP top level hardware block
  * @cwb_hw: CWB control hwio details
+ * @dcwb_hw: DCWB control hwio details
  */
 struct sde_hw_wb {
 	struct sde_hw_blk base;
@@ -153,6 +175,7 @@ struct sde_hw_wb {
 
 	struct sde_hw_mdp *hw_mdp;
 	struct sde_hw_blk_reg_map cwb_hw;
+	struct sde_hw_blk_reg_map dcwb_hw;
 };
 
 /**