diff mbox

[DPU,5/5] drm/msm/dpu: dynamic assignment of hw pipe to plane

Message ID 1529499020-8499-6-git-send-email-skolluku@codeaurora.org (mailing list archive)
State New, archived
Headers show

Commit Message

Sravanthi Kollukuduru June 20, 2018, 12:50 p.m. UTC
Currently, there exists a static binding of hw pipe to
plane. This restricts wide plane support where plane width
exceeds the pipe's maximum width.
To enable such use cases, the hw pipes are dynamically
(re)allocated to a plane during atomic check based on the
plane capabilities.

Signed-off-by: Sravanthi Kollukuduru <skolluku@codeaurora.org>
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c  |  45 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 670 +++++++++++++++++-------------
 drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h |   4 +-
 3 files changed, 414 insertions(+), 305 deletions(-)
diff mbox

Patch

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
index 56f6576..afb8c79 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
@@ -175,7 +175,8 @@  static void _dpu_crtc_blend_setup_mixer(struct drm_crtc *crtc,
 	struct dpu_rect plane_crtc_roi;
 
 	u32 flush_mask;
-	uint32_t stage_idx, lm_idx;
+	uint32_t stage_idx = 0, lm_idx;
+	int i;
 	int zpos_cnt[DPU_STAGE_MAX + 1] = { 0 };
 	bool bg_alpha_enable = false;
 
@@ -204,11 +205,11 @@  static void _dpu_crtc_blend_setup_mixer(struct drm_crtc *crtc,
 
 		dpu_plane_get_ctl_flush(plane, ctl, &flush_mask);
 
-		DPU_DEBUG("crtc %d stage:%d - plane %d sspp %d fb %d\n",
-				crtc->base.id,
-				pstate->stage,
-				plane->base.id,
-				dpu_plane_pipe(plane) - SSPP_VIG0,
+		DPU_DEBUG("crtc %d stage%d: plane%d ssppmode%d[%d %d] fb%d\n",
+				crtc->base.id, pstate->stage,
+				plane->base.id, pstate->num_pipes,
+				dpu_plane_pipe(pstate->pipe_hw[0]) - SSPP_VIG0,
+				dpu_plane_pipe(pstate->pipe_hw[1]) - SSPP_VIG0,
 				state->fb ? state->fb->base.id : -1);
 
 		format = to_dpu_format(msm_framebuffer_format(pstate->base.fb));
@@ -221,19 +222,25 @@  static void _dpu_crtc_blend_setup_mixer(struct drm_crtc *crtc,
 			bg_alpha_enable = true;
 
 		DPU_EVT32(DRMID(crtc), DRMID(plane),
-				state->fb ? state->fb->base.id : -1,
-				state->src_x >> 16, state->src_y >> 16,
-				state->src_w >> 16, state->src_h >> 16,
-				state->crtc_x, state->crtc_y,
-				state->crtc_w, state->crtc_h);
-
-		stage_idx = zpos_cnt[pstate->stage]++;
-		stage_cfg->stage[pstate->stage][stage_idx] =
-					dpu_plane_pipe(plane);
-
-		DPU_EVT32(DRMID(crtc), DRMID(plane), stage_idx,
-			dpu_plane_pipe(plane) - SSPP_VIG0, pstate->stage,
-			format->base.pixel_format, fb ? fb->modifier : 0);
+			state->fb ? state->fb->base.id : -1,
+			state->src_x >> 16, state->src_y >> 16,
+			state->src_w >> 16, state->src_h >> 16,
+			state->crtc_x, state->crtc_y,
+			state->crtc_w, state->crtc_h);
+
+		for (i = 0; i < pstate->num_pipes; i++) {
+			stage_idx = zpos_cnt[pstate->stage]++;
+			if (stage_idx >= PIPES_PER_STAGE)
+				break;
+
+			stage_cfg->stage[pstate->stage][stage_idx] =
+				dpu_plane_pipe(pstate->pipe_hw[i]);
+
+			DPU_EVT32(DRMID(crtc), DRMID(plane), stage_idx,
+				dpu_plane_pipe(pstate->pipe_hw[i]) - SSPP_VIG0,
+				pstate->stage, format->base.pixel_format,
+				fb ? fb->modifier : 0);
+		}
 
 		/* blend config update */
 		for (lm_idx = 0; lm_idx < cstate->num_mixers; lm_idx++) {
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
index be40a2c..2c6960e 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
@@ -81,40 +81,26 @@  enum dpu_plane_qos {
 
 /*
  * struct dpu_plane - local dpu plane structure
- * @aspace: address space pointer
  * @csc_ptr: Points to dpu_csc_cfg structure to use for current
- * @catalog: Points to dpu catalog structure
- * @revalidate: force revalidation of all the plane properties
  */
 struct dpu_plane {
 	struct drm_plane base;
 
 	struct mutex lock;
 
-	enum dpu_sspp pipe;
-	uint32_t features;      /* capabilities from catalog */
 	uint32_t nformats;
 	uint32_t formats[64];
 
-	struct dpu_hw_pipe *pipe_hw;
-	struct dpu_hw_pipe_cfg pipe_cfg;
-	struct dpu_hw_pipe_qos_cfg pipe_qos_cfg;
 	uint32_t color_fill;
 	bool is_error;
-	bool is_rt_pipe;
-	struct dpu_mdss_cfg *catalog;
+	bool is_rt_client;
 
 	struct dpu_csc_cfg *csc_ptr;
-
-	const struct dpu_sspp_sub_blks *pipe_sblk;
-	char pipe_name[DPU_NAME_SIZE];
+	char name[DPU_NAME_SIZE];
 
 	/* debugfs related stuff */
 	struct dentry *debugfs_root;
-	struct dpu_debugfs_regset32 debugfs_src;
-	struct dpu_debugfs_regset32 debugfs_scaler;
-	struct dpu_debugfs_regset32 debugfs_csc;
-	bool debugfs_default_scale;
+
 };
 
 #define to_dpu_plane(x) container_of(x, struct dpu_plane, base)
@@ -141,14 +127,46 @@  static bool dpu_plane_sspp_enabled(struct drm_plane_state *state)
 	return state && state->crtc;
 }
 
+void _dpu_plane_get_roi_config(struct drm_plane_state *state,
+		struct dpu_rect *src, struct dpu_rect *dst)
+{
+	struct dpu_plane_state *pstate = to_dpu_plane_state(state);
+	bool q16_data = true;
+	int div = (pstate->num_pipes == PLANE_DUAL_PIPES) ? 2 : 1;
+
+	DPU_DEBUG("plane %d:", state->plane->base.id);
+
+	if (src) {
+		POPULATE_RECT(src, state->src_x, state->src_y,
+		state->src_w, state->src_h, q16_data);
+
+		DPU_DEBUG("src_rect: %u,%u,(%u/%d)x%u\n",
+			src->x, src->y, src->w, div, src->h);
+
+		src->w /= div;
+	}
+
+	if (dst) {
+		POPULATE_RECT(dst, state->crtc_x, state->crtc_y,
+		state->crtc_w, state->crtc_h, !q16_data);
+
+		DPU_DEBUG("dst_rect: %d,%d,(%u/%d)x%u\n",
+			dst->x, dst->y, dst->w, div, dst->h);
+
+		dst->w /= div;
+	}
+}
+
 /**
  * _dpu_plane_calc_fill_level - calculate fill level of the given source format
  * @plane:		Pointer to drm plane
+ * @pipe_hw:	Pointer to hardware pipe
  * @fmt:		Pointer to source buffer format
  * @src_wdith:		width of source buffer
  * Return: fill level corresponding to the source buffer/format or 0 if error
  */
 static inline int _dpu_plane_calc_fill_level(struct drm_plane *plane,
+		struct dpu_hw_pipe *pipe_hw,
 		const struct dpu_format *fmt, u32 src_width)
 {
 	struct dpu_kms *kms;
@@ -179,12 +197,12 @@  static inline int _dpu_plane_calc_fill_level(struct drm_plane *plane,
 				((src_width + 32) * fmt->bpp);
 		}
 	} else {
-			total_fl = (fixed_buff_size) * 2 /
+		total_fl = (fixed_buff_size) * 2 /
 				((src_width + 32) * fmt->bpp);
 	}
 
-	DPU_DEBUG("plane%u: pnum:%d fmt: %4.4s w:%u fl:%u\n",
-			plane->base.id, pdpu->pipe - SSPP_VIG0,
+	DPU_DEBUG("plane%d: pnum:%d fmt:%4.4s w:%u fl:%u\n",
+			plane->base.id, pipe_hw->idx - SSPP_VIG0,
 			(char *)&fmt->base.pixel_format,
 			src_width, total_fl);
 
@@ -219,39 +237,38 @@  static u64 _dpu_plane_get_qos_lut(const struct dpu_qos_lut_tbl *tbl,
 /**
  * _dpu_plane_set_qos_lut - set QoS LUT of the given plane
  * @plane:		Pointer to drm plane
+ * @pipe_hw:		Pointer to hardware pipe
+ * @pipe_cfg:		Pointer to hardware pipe config
  * @fb:			Pointer to framebuffer associated with the given plane
  */
 static void _dpu_plane_set_qos_lut(struct drm_plane *plane,
-		struct drm_framebuffer *fb)
+	struct dpu_hw_pipe *pipe_hw, struct dpu_hw_pipe_cfg *pipe_cfg,
+	struct drm_framebuffer *fb)
 {
+	struct dpu_kms *kms;
 	struct dpu_plane *pdpu;
 	const struct dpu_format *fmt = NULL;
 	u64 qos_lut;
 	u32 total_fl = 0, lut_usage;
+	struct dpu_hw_pipe_qos_cfg pipe_qos_cfg;
 
-	if (!plane || !fb) {
-		DPU_ERROR("invalid arguments plane %d fb %d\n",
-				plane != 0, fb != 0);
+	if (!plane || !pipe_hw || !pipe_cfg || !fb ||
+		!pipe_hw->ops.setup_creq_lut) {
+		DPU_ERROR("invalid arguments plane %d hw %d cfg %d fb %d\n",
+			plane != 0, pipe_hw != 0, pipe_cfg != 0, fb != 0);
 		return;
 	}
 
 	pdpu = to_dpu_plane(plane);
+	kms = _dpu_plane_get_kms(&pdpu->base);
 
-	if (!pdpu->pipe_hw || !pdpu->pipe_sblk || !pdpu->catalog) {
-		DPU_ERROR("invalid arguments\n");
-		return;
-	} else if (!pdpu->pipe_hw->ops.setup_creq_lut) {
-		return;
-	}
-
-	if (!pdpu->is_rt_pipe) {
+	if (!pdpu->is_rt_client) {
 		lut_usage = DPU_QOS_LUT_USAGE_NRT;
 	} else {
-		fmt = dpu_get_dpu_format_ext(
-				fb->format->format,
-				fb->modifier);
-		total_fl = _dpu_plane_calc_fill_level(plane, fmt,
-				pdpu->pipe_cfg.src_rect.w);
+		fmt = dpu_get_dpu_format_ext(fb->format->format,
+					fb->modifier);
+		total_fl = _dpu_plane_calc_fill_level(plane, pipe_hw,
+					fmt, pipe_cfg->src_rect.w);
 
 		if (fmt && DPU_FORMAT_IS_LINEAR(fmt))
 			lut_usage = DPU_QOS_LUT_USAGE_LINEAR;
@@ -260,53 +277,52 @@  static void _dpu_plane_set_qos_lut(struct drm_plane *plane,
 	}
 
 	qos_lut = _dpu_plane_get_qos_lut(
-			&pdpu->catalog->perf.qos_lut_tbl[lut_usage], total_fl);
+		&kms->catalog->perf.qos_lut_tbl[lut_usage], total_fl);
 
-	pdpu->pipe_qos_cfg.creq_lut = qos_lut;
+	memset(&pipe_qos_cfg, 0, sizeof(struct dpu_hw_pipe_qos_cfg));
+	pipe_qos_cfg.creq_lut = qos_lut;
 
-	trace_dpu_perf_set_qos_luts(pdpu->pipe - SSPP_VIG0,
-			(fmt) ? fmt->base.pixel_format : 0,
-			pdpu->is_rt_pipe, total_fl, qos_lut, lut_usage);
+	trace_dpu_perf_set_qos_luts(pipe_hw->idx - SSPP_VIG0,
+		(fmt) ? fmt->base.pixel_format : 0,
+		pdpu->is_rt_client, total_fl, qos_lut, lut_usage);
 
 	DPU_DEBUG("plane%u: pnum:%d fmt: %4.4s rt:%d fl:%u lut:0x%llx\n",
-			plane->base.id,
-			pdpu->pipe - SSPP_VIG0,
-			fmt ? (char *)&fmt->base.pixel_format : NULL,
-			pdpu->is_rt_pipe, total_fl, qos_lut);
+		plane->base.id, pipe_hw->idx - SSPP_VIG0,
+		fmt ? (char *)&fmt->base.pixel_format : NULL,
+		pdpu->is_rt_client, total_fl, qos_lut);
 
-	pdpu->pipe_hw->ops.setup_creq_lut(pdpu->pipe_hw, &pdpu->pipe_qos_cfg);
+	pipe_hw->ops.setup_creq_lut(pipe_hw, &pipe_qos_cfg);
 }
 
 /**
- * _dpu_plane_set_panic_lut - set danger/safe LUT of the given plane
+ * _dpu_plane_set_danger_lut - set danger/safe LUT of the given plane
  * @plane:		Pointer to drm plane
- * @fb:			Pointer to framebuffer associated with the given plane
+ * @pipe_hw:		Pointer to hardware pipe
+ * @fb:		Pointer to framebuffer associated with the given plane
  */
 static void _dpu_plane_set_danger_lut(struct drm_plane *plane,
-		struct drm_framebuffer *fb)
+		struct dpu_hw_pipe *pipe_hw, struct drm_framebuffer *fb)
 {
+	struct dpu_kms *kms;
 	struct dpu_plane *pdpu;
 	const struct dpu_format *fmt = NULL;
 	u32 danger_lut, safe_lut;
+	struct dpu_hw_pipe_qos_cfg pipe_qos_cfg;
 
-	if (!plane || !fb) {
-		DPU_ERROR("invalid arguments\n");
+	if (!plane || !pipe_hw || !fb ||
+		!pipe_hw->ops.setup_danger_safe_lut) {
+		DPU_ERROR("invalid arguments plane %d hw %d fb %d\n",
+			plane != 0, pipe_hw != 0, fb != 0);
 		return;
 	}
 
 	pdpu = to_dpu_plane(plane);
+	kms = _dpu_plane_get_kms(&pdpu->base);
 
-	if (!pdpu->pipe_hw || !pdpu->pipe_sblk || !pdpu->catalog) {
-		DPU_ERROR("invalid arguments\n");
-		return;
-	} else if (!pdpu->pipe_hw->ops.setup_danger_safe_lut) {
-		return;
-	}
-
-	if (!pdpu->is_rt_pipe) {
-		danger_lut = pdpu->catalog->perf.danger_lut_tbl
+	if (!pdpu->is_rt_client) {
+		danger_lut = kms->catalog->perf.danger_lut_tbl
 				[DPU_QOS_LUT_USAGE_NRT];
-		safe_lut = pdpu->catalog->perf.safe_lut_tbl
+		safe_lut = kms->catalog->perf.safe_lut_tbl
 				[DPU_QOS_LUT_USAGE_NRT];
 	} else {
 		fmt = dpu_get_dpu_format_ext(
@@ -314,105 +330,101 @@  static void _dpu_plane_set_danger_lut(struct drm_plane *plane,
 				fb->modifier);
 
 		if (fmt && DPU_FORMAT_IS_LINEAR(fmt)) {
-			danger_lut = pdpu->catalog->perf.danger_lut_tbl
+			danger_lut = kms->catalog->perf.danger_lut_tbl
 					[DPU_QOS_LUT_USAGE_LINEAR];
-			safe_lut = pdpu->catalog->perf.safe_lut_tbl
+			safe_lut = kms->catalog->perf.safe_lut_tbl
 					[DPU_QOS_LUT_USAGE_LINEAR];
 		} else {
-			danger_lut = pdpu->catalog->perf.danger_lut_tbl
+			danger_lut = kms->catalog->perf.danger_lut_tbl
 					[DPU_QOS_LUT_USAGE_MACROTILE];
-			safe_lut = pdpu->catalog->perf.safe_lut_tbl
+			safe_lut = kms->catalog->perf.safe_lut_tbl
 					[DPU_QOS_LUT_USAGE_MACROTILE];
 		}
 	}
 
-	pdpu->pipe_qos_cfg.danger_lut = danger_lut;
-	pdpu->pipe_qos_cfg.safe_lut = safe_lut;
+	memset(&pipe_qos_cfg, 0, sizeof(struct dpu_hw_pipe_qos_cfg));
+	pipe_qos_cfg.danger_lut = danger_lut;
+	pipe_qos_cfg.safe_lut = safe_lut;
 
-	trace_dpu_perf_set_danger_luts(pdpu->pipe - SSPP_VIG0,
-			(fmt) ? fmt->base.pixel_format : 0,
-			(fmt) ? fmt->fetch_mode : 0,
-			pdpu->pipe_qos_cfg.danger_lut,
-			pdpu->pipe_qos_cfg.safe_lut);
+	trace_dpu_perf_set_danger_luts(pipe_hw->idx - SSPP_VIG0,
+		(fmt) ? fmt->base.pixel_format : 0,
+		(fmt) ? fmt->fetch_mode : 0,
+		pipe_qos_cfg.danger_lut, pipe_qos_cfg.safe_lut);
 
-	DPU_DEBUG("plane%u: pnum:%d fmt: %4.4s mode:%d luts[0x%x, 0x%x]\n",
-		plane->base.id,
-		pdpu->pipe - SSPP_VIG0,
+	DPU_DEBUG("plane%u:pnum:%d fmt:%4.4s mode:%d luts[0x%x,0x%x]\n",
+		plane->base.id, pipe_hw->idx - SSPP_VIG0,
 		fmt ? (char *)&fmt->base.pixel_format : NULL,
-		fmt ? fmt->fetch_mode : -1,
-		pdpu->pipe_qos_cfg.danger_lut,
-		pdpu->pipe_qos_cfg.safe_lut);
+		fmt ? fmt->fetch_mode : -1, pipe_qos_cfg.danger_lut,
+		pipe_qos_cfg.safe_lut);
+
+	pipe_hw->ops.setup_danger_safe_lut(pipe_hw, &pipe_qos_cfg);
 
-	pdpu->pipe_hw->ops.setup_danger_safe_lut(pdpu->pipe_hw,
-			&pdpu->pipe_qos_cfg);
 }
 
 /**
  * _dpu_plane_set_qos_ctrl - set QoS control of the given plane
  * @plane:		Pointer to drm plane
+ * @pipe_hw:		Pointer to hardware pipe
  * @enable:		true to enable QoS control
  * @flags:		QoS control mode (enum dpu_plane_qos)
  */
 static void _dpu_plane_set_qos_ctrl(struct drm_plane *plane,
-	bool enable, u32 flags)
+		struct dpu_hw_pipe *pipe_hw, bool enable, u32 flags)
 {
 	struct dpu_plane *pdpu;
+	struct dpu_hw_pipe_qos_cfg pipe_qos_cfg;
 
-	if (!plane) {
+	if (!plane || !pipe_hw || !pipe_hw->cap->sblk ||
+		!pipe_hw->ops.setup_qos_ctrl) {
 		DPU_ERROR("invalid arguments\n");
 		return;
 	}
 
 	pdpu = to_dpu_plane(plane);
-
-	if (!pdpu->pipe_hw || !pdpu->pipe_sblk) {
-		DPU_ERROR("invalid arguments\n");
-		return;
-	} else if (!pdpu->pipe_hw->ops.setup_qos_ctrl) {
-		return;
-	}
+	memset(&pipe_qos_cfg, 0, sizeof(struct dpu_hw_pipe_qos_cfg));
 
 	if (flags & DPU_PLANE_QOS_VBLANK_CTRL) {
-		pdpu->pipe_qos_cfg.creq_vblank = pdpu->pipe_sblk->creq_vblank;
-		pdpu->pipe_qos_cfg.danger_vblank =
-				pdpu->pipe_sblk->danger_vblank;
-		pdpu->pipe_qos_cfg.vblank_en = enable;
+		pipe_qos_cfg.creq_vblank =
+			pipe_hw->cap->sblk->creq_vblank;
+		pipe_qos_cfg.danger_vblank =
+			pipe_hw->cap->sblk->danger_vblank;
+		pipe_qos_cfg.vblank_en = enable;
 	}
 
 	if (flags & DPU_PLANE_QOS_VBLANK_AMORTIZE) {
 		/* this feature overrules previous VBLANK_CTRL */
-		pdpu->pipe_qos_cfg.vblank_en = false;
-		pdpu->pipe_qos_cfg.creq_vblank = 0; /* clear vblank bits */
+		pipe_qos_cfg.vblank_en = false;
+		/* clear vblank bits */
+		pipe_qos_cfg.creq_vblank = 0;
 	}
 
 	if (flags & DPU_PLANE_QOS_PANIC_CTRL)
-		pdpu->pipe_qos_cfg.danger_safe_en = enable;
+		pipe_qos_cfg.danger_safe_en = enable;
 
-	if (!pdpu->is_rt_pipe) {
-		pdpu->pipe_qos_cfg.vblank_en = false;
-		pdpu->pipe_qos_cfg.danger_safe_en = false;
+	if (!pdpu->is_rt_client) {
+		pipe_qos_cfg.vblank_en = false;
+		pipe_qos_cfg.danger_safe_en = false;
 	}
 
-	DPU_DEBUG("plane%u: pnum:%d ds:%d vb:%d pri[0x%x, 0x%x] is_rt:%d\n",
-		plane->base.id,
-		pdpu->pipe - SSPP_VIG0,
-		pdpu->pipe_qos_cfg.danger_safe_en,
-		pdpu->pipe_qos_cfg.vblank_en,
-		pdpu->pipe_qos_cfg.creq_vblank,
-		pdpu->pipe_qos_cfg.danger_vblank,
-		pdpu->is_rt_pipe);
+	DPU_DEBUG("plane%u:pnum:%d ds:%d vb:%d pr[0x%x,0x%x]is_rt:%d\n",
+		plane->base.id, pipe_hw->idx - SSPP_VIG0,
+		pipe_qos_cfg.danger_safe_en, pipe_qos_cfg.vblank_en,
+		pipe_qos_cfg.creq_vblank, pipe_qos_cfg.danger_vblank,
+		pdpu->is_rt_client);
+
+	pipe_hw->ops.setup_qos_ctrl(pipe_hw, &pipe_qos_cfg);
 
-	pdpu->pipe_hw->ops.setup_qos_ctrl(pdpu->pipe_hw,
-			&pdpu->pipe_qos_cfg);
 }
 
 int dpu_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable)
 {
 	struct dpu_plane *pdpu;
+	struct dpu_plane_state *pstate;
 	struct msm_drm_private *priv;
 	struct dpu_kms *dpu_kms;
+	int i;
 
-	if (!plane || !plane->dev) {
+	if (!plane || !plane->dev || !plane->state) {
 		DPU_ERROR("invalid arguments\n");
 		return -EINVAL;
 	}
@@ -425,12 +437,15 @@  int dpu_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable)
 
 	dpu_kms = to_dpu_kms(priv->kms);
 	pdpu = to_dpu_plane(plane);
+	pstate = to_dpu_plane_state(plane->state);
 
-	if (!pdpu->is_rt_pipe)
+	if (!pdpu->is_rt_client)
 		goto end;
 
 	pm_runtime_get_sync(&dpu_kms->pdev->dev);
-	_dpu_plane_set_qos_ctrl(plane, enable, DPU_PLANE_QOS_PANIC_CTRL);
+	for (i = 0; i < pstate->num_pipes; i++)
+		_dpu_plane_set_qos_ctrl(plane,  pstate->pipe_hw[i],
+			enable, DPU_PLANE_QOS_PANIC_CTRL);
 	pm_runtime_put_sync(&dpu_kms->pdev->dev);
 
 end:
@@ -440,19 +455,22 @@  int dpu_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable)
 /**
  * _dpu_plane_set_ot_limit - set OT limit for the given plane
  * @plane:		Pointer to drm plane
+ * @pipe_hw:		Pointer to hardware pipe
+ * @pipe_cfg:		Pointer to hardware pipe config
  * @crtc:		Pointer to drm crtc
  */
 static void _dpu_plane_set_ot_limit(struct drm_plane *plane,
-		struct drm_crtc *crtc)
+	struct dpu_hw_pipe *pipe_hw, struct dpu_hw_pipe_cfg *pipe_cfg,
+	struct drm_crtc *crtc)
 {
 	struct dpu_plane *pdpu;
 	struct dpu_vbif_set_ot_params ot_params;
 	struct msm_drm_private *priv;
 	struct dpu_kms *dpu_kms;
 
-	if (!plane || !plane->dev || !crtc) {
-		DPU_ERROR("invalid arguments plane %d crtc %d\n",
-				plane != 0, crtc != 0);
+	if (!plane || !plane->dev || !pipe_hw || !pipe_cfg || !crtc) {
+		DPU_ERROR("invalid arguments plane %d hw %d cfg %d crtc %d\n",
+			plane != 0, pipe_hw != 0, pipe_cfg != 0, crtc != 0);
 		return;
 	}
 
@@ -463,38 +481,38 @@  static void _dpu_plane_set_ot_limit(struct drm_plane *plane,
 	}
 
 	dpu_kms = to_dpu_kms(priv->kms);
+
 	pdpu = to_dpu_plane(plane);
-	if (!pdpu->pipe_hw) {
-		DPU_ERROR("invalid pipe reference\n");
-		return;
-	}
 
 	memset(&ot_params, 0, sizeof(ot_params));
-	ot_params.xin_id = pdpu->pipe_hw->cap->xin_id;
-	ot_params.num = pdpu->pipe_hw->idx - SSPP_NONE;
-	ot_params.width = pdpu->pipe_cfg.src_rect.w;
-	ot_params.height = pdpu->pipe_cfg.src_rect.h;
-	ot_params.is_wfd = !pdpu->is_rt_pipe;
+	ot_params.xin_id = pipe_hw->cap->xin_id;
+	ot_params.num = pipe_hw->idx - SSPP_NONE;
+	ot_params.width = pipe_cfg->src_rect.w;
+	ot_params.height = pipe_cfg->src_rect.h;
+	ot_params.is_wfd = !pdpu->is_rt_client;
 	ot_params.frame_rate = crtc->mode.vrefresh;
 	ot_params.vbif_idx = VBIF_RT;
-	ot_params.clk_ctrl = pdpu->pipe_hw->cap->clk_ctrl;
+	ot_params.clk_ctrl = pipe_hw->cap->clk_ctrl;
 	ot_params.rd = true;
 
 	dpu_vbif_set_ot_limit(dpu_kms, &ot_params);
+
 }
 
 /**
  * _dpu_plane_set_vbif_qos - set vbif QoS for the given plane
  * @plane:		Pointer to drm plane
+ * @pipe_hw:		Pointer to hardware pipe
  */
-static void _dpu_plane_set_qos_remap(struct drm_plane *plane)
+static void _dpu_plane_set_qos_remap(struct drm_plane *plane,
+	struct dpu_hw_pipe *pipe_hw)
 {
 	struct dpu_plane *pdpu;
 	struct dpu_vbif_set_qos_params qos_params;
 	struct msm_drm_private *priv;
 	struct dpu_kms *dpu_kms;
 
-	if (!plane || !plane->dev) {
+	if (!plane || !plane->dev || !pipe_hw) {
 		DPU_ERROR("invalid arguments\n");
 		return;
 	}
@@ -507,23 +525,17 @@  static void _dpu_plane_set_qos_remap(struct drm_plane *plane)
 
 	dpu_kms = to_dpu_kms(priv->kms);
 	pdpu = to_dpu_plane(plane);
-	if (!pdpu->pipe_hw) {
-		DPU_ERROR("invalid pipe reference\n");
-		return;
-	}
 
 	memset(&qos_params, 0, sizeof(qos_params));
 	qos_params.vbif_idx = VBIF_RT;
-	qos_params.clk_ctrl = pdpu->pipe_hw->cap->clk_ctrl;
-	qos_params.xin_id = pdpu->pipe_hw->cap->xin_id;
-	qos_params.num = pdpu->pipe_hw->idx - SSPP_VIG0;
-	qos_params.is_rt = pdpu->is_rt_pipe;
+	qos_params.clk_ctrl = pipe_hw->cap->clk_ctrl;
+	qos_params.xin_id = pipe_hw->cap->xin_id;
+	qos_params.num = pipe_hw->idx - SSPP_VIG0;
+	qos_params.is_rt = pdpu->is_rt_client;
 
 	DPU_DEBUG("plane%d pipe:%d vbif:%d xin:%d rt:%d, clk_ctrl:%d\n",
-			plane->base.id, qos_params.num,
-			qos_params.vbif_idx,
-			qos_params.xin_id, qos_params.is_rt,
-			qos_params.clk_ctrl);
+		plane->base.id, qos_params.num, qos_params.vbif_idx,
+		qos_params.xin_id, qos_params.is_rt, qos_params.clk_ctrl);
 
 	dpu_vbif_set_qos_remap(dpu_kms, &qos_params);
 }
@@ -554,25 +566,16 @@  static int _dpu_plane_get_aspace(
 	return 0;
 }
 
-static inline void _dpu_plane_set_scanout(struct drm_plane *plane,
-		struct dpu_plane_state *pstate,
-		struct dpu_hw_pipe_cfg *pipe_cfg,
-		struct drm_framebuffer *fb)
+static inline void _dpu_plane_set_scanout(struct dpu_plane *pdpu,
+	struct dpu_plane_state *pstate, struct dpu_hw_pipe *pipe_hw,
+	struct dpu_hw_pipe_cfg *pipe_cfg, struct drm_framebuffer *fb)
 {
-	struct dpu_plane *pdpu;
 	struct msm_gem_address_space *aspace = NULL;
 	int ret;
 
-	if (!plane || !pstate || !pipe_cfg || !fb) {
-		DPU_ERROR(
-			"invalid arg(s), plane %d state %d cfg %d fb %d\n",
-			plane != 0, pstate != 0, pipe_cfg != 0, fb != 0);
-		return;
-	}
-
-	pdpu = to_dpu_plane(plane);
-	if (!pdpu->pipe_hw) {
-		DPU_ERROR_PLANE(pdpu, "invalid pipe_hw\n");
+	if (!pdpu || !pstate || !pipe_hw || !pipe_cfg || !fb) {
+		DPU_ERROR("invalid: plane %d state %d hw %d cfg %d fb %d\n",
+		pdpu != 0, pstate != 0, pipe_hw != 0, pipe_cfg != 0, fb != 0);
 		return;
 	}
 
@@ -587,8 +590,8 @@  static inline void _dpu_plane_set_scanout(struct drm_plane *plane,
 		DPU_DEBUG_PLANE(pdpu, "not updating same src addrs\n");
 	else if (ret)
 		DPU_ERROR_PLANE(pdpu, "failed to get format layout, %d\n", ret);
-	else if (pdpu->pipe_hw->ops.setup_sourceaddress) {
-		DPU_EVT32_VERBOSE(pdpu->pipe_hw->idx,
+	else if (pipe_hw->ops.setup_sourceaddress) {
+		DPU_EVT32_VERBOSE(pipe_hw->idx,
 				pipe_cfg->layout.width,
 				pipe_cfg->layout.height,
 				pipe_cfg->layout.plane_addr[0],
@@ -599,11 +602,11 @@  static inline void _dpu_plane_set_scanout(struct drm_plane *plane,
 				pipe_cfg->layout.plane_size[2],
 				pipe_cfg->layout.plane_addr[3],
 				pipe_cfg->layout.plane_size[3]);
-		pdpu->pipe_hw->ops.setup_sourceaddress(pdpu->pipe_hw, pipe_cfg);
+		pipe_hw->ops.setup_sourceaddress(pipe_hw, pipe_cfg);
 	}
 }
 
-static void _dpu_plane_setup_scaler3(struct dpu_plane *pdpu,
+static void _dpu_plane_setup_scaler3(
 		struct dpu_plane_state *pstate,
 		uint32_t src_w, uint32_t src_h, uint32_t dst_w, uint32_t dst_h,
 		struct dpu_hw_scaler3_cfg *scale_cfg,
@@ -612,12 +615,12 @@  static void _dpu_plane_setup_scaler3(struct dpu_plane *pdpu,
 {
 	uint32_t i;
 
-	if (!pdpu || !pstate || !scale_cfg || !fmt || !chroma_subsmpl_h ||
-			!chroma_subsmpl_v) {
+	if (!pstate || !scale_cfg || !fmt ||
+		!chroma_subsmpl_h || !chroma_subsmpl_v) {
 		DPU_ERROR(
-			"pdpu %d pstate %d scale_cfg %d fmt %d smp_h %d smp_v %d\n",
-			!!pdpu, !!pstate, !!scale_cfg, !!fmt, chroma_subsmpl_h,
-			chroma_subsmpl_v);
+		"pstate%d scale_cfg%d fmt%d smp_h%d smp_v%d\n",
+		!!pstate, !!scale_cfg, !!fmt, chroma_subsmpl_h,
+		chroma_subsmpl_v);
 		return;
 	}
 
@@ -673,7 +676,7 @@  static void _dpu_plane_setup_scaler3(struct dpu_plane *pdpu,
 	scale_cfg->enable = 1;
 }
 
-static inline void _dpu_plane_setup_csc(struct dpu_plane *pdpu)
+static inline void _dpu_plane_setup_csc(struct dpu_plane *pdpu, u32 features)
 {
 	static const struct dpu_csc_cfg dpu_csc_YUV2RGB_601L = {
 		{
@@ -709,7 +712,7 @@  static inline void _dpu_plane_setup_csc(struct dpu_plane *pdpu)
 		return;
 	}
 
-	if (BIT(DPU_SSPP_CSC_10BIT) & pdpu->features)
+	if (BIT(DPU_SSPP_CSC_10BIT) & features)
 		pdpu->csc_ptr = (struct dpu_csc_cfg *)&dpu_csc10_YUV2RGB_601L;
 	else
 		pdpu->csc_ptr = (struct dpu_csc_cfg *)&dpu_csc_YUV2RGB_601L;
@@ -720,16 +723,18 @@  static inline void _dpu_plane_setup_csc(struct dpu_plane *pdpu)
 			pdpu->csc_ptr->csc_mv[2]);
 }
 
-static void _dpu_plane_setup_scaler(struct dpu_plane *pdpu,
+
+static void _dpu_plane_setup_scaler(
 		struct dpu_plane_state *pstate,
+		struct dpu_hw_pipe_cfg *pipe_cfg,
 		const struct dpu_format *fmt, bool color_fill)
 {
 	struct dpu_hw_pixel_ext *pe;
 	uint32_t chroma_subsmpl_h, chroma_subsmpl_v;
 
-	if (!pdpu || !fmt || !pstate) {
-		DPU_ERROR("invalid arg(s), plane %d fmt %d state %d\n",
-				pdpu != 0, fmt != 0, pstate != 0);
+	if (!fmt || !pstate) {
+		DPU_ERROR("invalid arg(s), fmt %d state %d\n",
+				fmt != 0, pstate != 0);
 		return;
 	}
 
@@ -742,11 +747,11 @@  static void _dpu_plane_setup_scaler(struct dpu_plane *pdpu,
 		drm_format_vert_chroma_subsampling(fmt->base.pixel_format);
 
 	/* update scaler. calculate default config for QSEED3 */
-	_dpu_plane_setup_scaler3(pdpu, pstate,
-			pdpu->pipe_cfg.src_rect.w,
-			pdpu->pipe_cfg.src_rect.h,
-			pdpu->pipe_cfg.dst_rect.w,
-			pdpu->pipe_cfg.dst_rect.h,
+	_dpu_plane_setup_scaler3(pstate,
+			pipe_cfg->src_rect.w,
+			pipe_cfg->src_rect.h,
+			pipe_cfg->dst_rect.w,
+			pipe_cfg->dst_rect.h,
 			&pstate->scaler3_cfg, fmt,
 			chroma_subsmpl_h, chroma_subsmpl_v);
 }
@@ -764,17 +769,14 @@  static int _dpu_plane_color_fill(struct dpu_plane *pdpu,
 	const struct dpu_format *fmt;
 	const struct drm_plane *plane;
 	struct dpu_plane_state *pstate;
+	struct dpu_hw_pipe_cfg pipe_cfg;
+	int i;
 
 	if (!pdpu || !pdpu->base.state) {
 		DPU_ERROR("invalid plane\n");
 		return -EINVAL;
 	}
 
-	if (!pdpu->pipe_hw) {
-		DPU_ERROR_PLANE(pdpu, "invalid plane h/w pointer\n");
-		return -EINVAL;
-	}
-
 	plane = &pdpu->base;
 	pstate = to_dpu_plane_state(plane->state);
 
@@ -786,34 +788,49 @@  static int _dpu_plane_color_fill(struct dpu_plane *pdpu,
 	 */
 	fmt = dpu_get_dpu_format(DRM_FORMAT_ABGR8888);
 
-	/* update sspp */
-	if (fmt && pdpu->pipe_hw->ops.setup_solidfill) {
-		pdpu->pipe_hw->ops.setup_solidfill(pdpu->pipe_hw,
-				(color & 0xFFFFFF) | ((alpha & 0xFF) << 24));
-
-		/* override scaler/decimation if solid fill */
-		pdpu->pipe_cfg.src_rect.x = 0;
-		pdpu->pipe_cfg.src_rect.y = 0;
-		pdpu->pipe_cfg.src_rect.w = pdpu->pipe_cfg.dst_rect.w;
-		pdpu->pipe_cfg.src_rect.h = pdpu->pipe_cfg.dst_rect.h;
-		_dpu_plane_setup_scaler(pdpu, pstate, fmt, true);
+	memset(&pipe_cfg, 0, sizeof(struct dpu_hw_pipe_cfg));
 
-		if (pdpu->pipe_hw->ops.setup_format)
-			pdpu->pipe_hw->ops.setup_format(pdpu->pipe_hw,
-					fmt, DPU_SSPP_SOLID_FILL);
+	_dpu_plane_get_roi_config(plane->state, NULL, &pipe_cfg.dst_rect);
 
-		if (pdpu->pipe_hw->ops.setup_rects)
-			pdpu->pipe_hw->ops.setup_rects(pdpu->pipe_hw,
-					&pdpu->pipe_cfg);
-
-		if (pdpu->pipe_hw->ops.setup_pe)
-			pdpu->pipe_hw->ops.setup_pe(pdpu->pipe_hw,
-					&pstate->pixel_ext);
+	/* update sspp */
+	for (i = 0; i < pstate->num_pipes; i++) {
+		if (fmt && pstate->pipe_hw[i] &&
+			pstate->pipe_hw[i]->ops.setup_solidfill) {
+			pstate->pipe_hw[i]->ops.setup_solidfill(
+				pstate->pipe_hw[i],
+				(color & 0xFFFFFF) | ((alpha & 0xFF) << 24));
 
-		if (pdpu->pipe_hw->ops.setup_scaler)
-			pdpu->pipe_hw->ops.setup_scaler(pdpu->pipe_hw,
-					&pdpu->pipe_cfg, &pstate->pixel_ext,
+			/*
+			 * override scaler/decimation if solid fill
+			 * also, adjust the dst.x in case of dual pipe
+			 */
+			pipe_cfg.dst_rect.x += pipe_cfg.dst_rect.w * i;
+			pipe_cfg.src_rect.x = 0;
+			pipe_cfg.src_rect.y = 0;
+			pipe_cfg.src_rect.w = pipe_cfg.dst_rect.w;
+			pipe_cfg.src_rect.h = pipe_cfg.dst_rect.h;
+
+			_dpu_plane_setup_scaler(pstate, &pipe_cfg, fmt, true);
+
+			if (pstate->pipe_hw[i]->ops.setup_format)
+				pstate->pipe_hw[i]->ops.setup_format(
+					pstate->pipe_hw[i], fmt,
+					DPU_SSPP_SOLID_FILL);
+
+			if (pstate->pipe_hw[i]->ops.setup_rects)
+				pstate->pipe_hw[i]->ops.setup_rects(
+					pstate->pipe_hw[i], &pipe_cfg);
+
+			if (pstate->pipe_hw[i]->ops.setup_pe)
+				pstate->pipe_hw[i]->ops.setup_pe(
+					pstate->pipe_hw[i], &pstate->pixel_ext);
+
+			if (pstate->pipe_hw[i]->ops.setup_scaler)
+				pstate->pipe_hw[i]->ops.setup_scaler(
+					pstate->pipe_hw[i], &pipe_cfg,
+					&pstate->pixel_ext,
 					&pstate->scaler3_cfg);
+		}
 	}
 
 	return 0;
@@ -829,6 +846,7 @@  void dpu_plane_get_ctl_flush(struct drm_plane *plane, struct dpu_hw_ctl *ctl,
 		u32 *flush_sspp)
 {
 	struct dpu_plane_state *pstate;
+	int i;
 
 	if (!plane || !flush_sspp) {
 		DPU_ERROR("invalid parameters\n");
@@ -837,7 +855,10 @@  void dpu_plane_get_ctl_flush(struct drm_plane *plane, struct dpu_hw_ctl *ctl,
 
 	pstate = to_dpu_plane_state(plane->state);
 
-	*flush_sspp = ctl->ops.get_bitmask_sspp(ctl, dpu_plane_pipe(plane));
+	for (i = 0; i < pstate->num_pipes; i++)
+		*flush_sspp |= ctl->ops.get_bitmask_sspp(ctl,
+				dpu_plane_pipe(pstate->pipe_hw[i]));
+
 }
 
 static int dpu_plane_prepare_fb(struct drm_plane *plane,
@@ -921,11 +942,12 @@  static int dpu_plane_sspp_atomic_check(struct drm_plane *plane,
 	struct dpu_kms *kms;
 	struct dpu_plane *pdpu;
 	struct dpu_plane_state *pstate;
+	struct dpu_private_state *dpu_priv_state;
 	const struct dpu_format *fmt;
 	struct dpu_rect src, dst;
 	uint32_t max_upscale, max_downscale, min_src_size, max_linewidth;
 	bool q16_data = true;
-	uint32_t caps = 0;
+	uint32_t caps = 0, req_num_pipes = 0;
 
 	if (!plane || !state) {
 		DPU_ERROR("invalid arg(s), plane %d state %d\n",
@@ -950,7 +972,20 @@  static int dpu_plane_sspp_atomic_check(struct drm_plane *plane,
 		dpu_plane_enabled(plane->state), dpu_plane_enabled(state));
 
 	if (!dpu_plane_enabled(state))
+		goto modeset_update;
+
+	/* With plane virtualization, a drm plane can be attached
+	 * to maximum of two hw pipes, i.e. we can go up to 2x
+	 * the pipe's max width.
+	 */
+	if (src.w > 2 * max_linewidth) {
+		DPU_ERROR_PLANE(pdpu, "invalid src w:%u, line w * 2:%u\n",
+					src.w, max_linewidth * 2);
+		ret = -E2BIG;
 		goto exit;
+	}
+
+	req_num_pipes = (src.w > max_linewidth) ? 2 : 1;
 
 	fmt = to_dpu_format(msm_framebuffer_format(state->fb));
 
@@ -988,13 +1023,6 @@  static int dpu_plane_sspp_atomic_check(struct drm_plane *plane,
 				dst.x, dst.y, dst.w, dst.h);
 		ret = -EINVAL;
 
-	/* check decimated source width */
-	} else if (src.w > max_linewidth) {
-		DPU_ERROR_PLANE(pdpu,
-				"invalid src w:%u, line w:%u\n",
-				src.w, max_linewidth);
-		ret = -E2BIG;
-
 	/* check max scaler capability */
 	} else if (((src.w * max_upscale) < dst.w) ||
 		((src.h * max_upscale) < dst.h) ||
@@ -1006,6 +1034,44 @@  static int dpu_plane_sspp_atomic_check(struct drm_plane *plane,
 		ret = -E2BIG;
 	}
 
+modeset_update:
+	if (!ret) {
+		dpu_priv_state = dpu_get_private_state(state->state);
+		if (IS_ERR(dpu_priv_state))
+			goto exit;
+
+		/**
+		 * (re)allocate hw pipes if mismatch in number of pipes
+		 * or caps of allocated vs requested.
+		 */
+		DPU_DEBUG_PLANE(pdpu, " num pipes %d -> %d caps %d\n",
+			 pstate->num_pipes, req_num_pipes, caps);
+
+		if ((pstate->num_pipes != req_num_pipes) || (pstate->pipe_hw[0]
+			&& (caps & ~pstate->pipe_hw[0]->cap->features))) {
+			/**
+			 * Release called only for planes with pipes attached.
+			 * New plane will have no resources to be released.
+			 */
+			if (pstate->num_pipes)
+				dpu_rm_release_plane_res(&dpu_priv_state->rm,
+							pstate);
+
+			/**
+			 * Reserve called only for planes that are enabled.
+			 * Plane that is disabling will require no resources.
+			 */
+			if (req_num_pipes) {
+				ret = dpu_rm_reserve_plane_res(
+					&dpu_priv_state->rm, pstate,
+					req_num_pipes, caps);
+				if (ret)
+					DPU_ERROR_PLANE(pdpu,
+					"failed to reserve resources\n");
+			}
+		}
+	}
+
 exit:
 	return ret;
 }
@@ -1039,6 +1105,7 @@  void dpu_plane_flush(struct drm_plane *plane)
 {
 	struct dpu_plane *pdpu;
 	struct dpu_plane_state *pstate;
+	int i;
 
 	if (!plane || !plane->state) {
 		DPU_ERROR("invalid plane\n");
@@ -1058,8 +1125,14 @@  void dpu_plane_flush(struct drm_plane *plane)
 	else if (pdpu->color_fill & DPU_PLANE_COLOR_FILL_FLAG)
 		/* force 100% alpha */
 		_dpu_plane_color_fill(pdpu, pdpu->color_fill, 0xFF);
-	else if (pdpu->pipe_hw && pdpu->csc_ptr && pdpu->pipe_hw->ops.setup_csc)
-		pdpu->pipe_hw->ops.setup_csc(pdpu->pipe_hw, pdpu->csc_ptr);
+	else {
+		for (i = 0; i < pstate->num_pipes; i++) {
+			if (pstate->pipe_hw[i] && pdpu->csc_ptr &&
+				pstate->pipe_hw[i]->ops.setup_csc)
+				pstate->pipe_hw[i]->ops.setup_csc(
+					pstate->pipe_hw[i], pdpu->csc_ptr);
+		}
+	}
 
 	/* force black color fill during suspend */
 	if (dpu_kms_is_suspend_state(plane->dev) && suspend_blank)
@@ -1089,6 +1162,7 @@  static int dpu_plane_sspp_atomic_update(struct drm_plane *plane,
 				struct drm_plane_state *old_state)
 {
 	uint32_t nplanes, src_flags;
+	struct dpu_kms *kms;
 	struct dpu_plane *pdpu;
 	struct drm_plane_state *state;
 	struct dpu_plane_state *pstate;
@@ -1097,7 +1171,8 @@  static int dpu_plane_sspp_atomic_update(struct drm_plane *plane,
 	struct drm_crtc *crtc;
 	struct drm_framebuffer *fb;
 	struct dpu_rect src, dst;
-	bool q16_data = true;
+	struct dpu_hw_pipe_cfg pipe_cfg;
+	int i;
 
 	if (!plane) {
 		DPU_ERROR("invalid plane\n");
@@ -1124,96 +1199,115 @@  static int dpu_plane_sspp_atomic_update(struct drm_plane *plane,
 				crtc != 0, fb != 0);
 		return -EINVAL;
 	}
+
+	kms = _dpu_plane_get_kms(&pdpu->base);
+	if (!kms || !kms->catalog) {
+		DPU_ERROR("invalid kms catalog\n");
+		return -EINVAL;
+	}
+
 	fmt = to_dpu_format(msm_framebuffer_format(fb));
 	nplanes = fmt->num_planes;
 
-	memset(&(pdpu->pipe_cfg), 0, sizeof(struct dpu_hw_pipe_cfg));
-
-	_dpu_plane_set_scanout(plane, pstate, &pdpu->pipe_cfg, fb);
+	DPU_DEBUG_PLANE(pdpu, "%4.4s ubwc %d\n",
+		(char *)&fmt->base.pixel_format, DPU_FORMAT_IS_UBWC(fmt));
 
 	pstate->pending = true;
+	pdpu->is_rt_client = (dpu_crtc_get_client_type(crtc) != NRT_CLIENT);
 
-	pdpu->is_rt_pipe = (dpu_crtc_get_client_type(crtc) != NRT_CLIENT);
-	_dpu_plane_set_qos_ctrl(plane, false, DPU_PLANE_QOS_PANIC_CTRL);
+	_dpu_plane_get_roi_config(state, &src, &dst);
 
-	/* update roi config */
-	POPULATE_RECT(&src, state->src_x, state->src_y,
-		state->src_w, state->src_h, q16_data);
-	POPULATE_RECT(&dst, state->crtc_x, state->crtc_y,
-		state->crtc_w, state->crtc_h, !q16_data);
+	for (i = 0; i < pstate->num_pipes; i++) {
+		memset(&pipe_cfg, 0, sizeof(struct dpu_hw_pipe_cfg));
 
-	DPU_DEBUG_PLANE(pdpu,
-		"FB[%u] %u,%u,%ux%u->crtc%u %d,%d,%ux%u, %4.4s ubwc %d\n",
-			fb->base.id, src.x, src.y, src.w, src.h,
-			crtc->base.id, dst.x, dst.y, dst.w, dst.h,
-			(char *)&fmt->base.pixel_format,
-			DPU_FORMAT_IS_UBWC(fmt));
+		_dpu_plane_set_scanout(pdpu, pstate, pstate->pipe_hw[i],
+					&pipe_cfg, fb);
+		_dpu_plane_set_qos_ctrl(plane,  pstate->pipe_hw[i],
+					false, DPU_PLANE_QOS_PANIC_CTRL);
 
+		/*
+		 * if the plane comprises of 2 hw pipes, assume that the width
+		 * is split equally across them. The only parameters that varies
+		 * between the 2 pipes are src_x and dst_x
+		 */
+		src.x += src.w * i;
+		dst.x += dst.w * i;
 
-	pdpu->pipe_cfg.src_rect = src;
-	pdpu->pipe_cfg.dst_rect = dst;
+		pipe_cfg.src_rect = src;
+		pipe_cfg.dst_rect = dst;
 
-	_dpu_plane_setup_scaler(pdpu, pstate, fmt, false);
+		_dpu_plane_setup_scaler(pstate, &pipe_cfg, fmt, false);
 
-	/* override for color fill */
-	if (pdpu->color_fill & DPU_PLANE_COLOR_FILL_FLAG) {
-		/* skip remaining processing on color fill */
-		return 0;
-	}
+		/* override for color fill */
+		if (pdpu->color_fill & DPU_PLANE_COLOR_FILL_FLAG) {
+			/* skip remaining processing on color fill */
+			return 0;
+		}
 
-	if (pdpu->pipe_hw->ops.setup_rects) {
-		pdpu->pipe_hw->ops.setup_rects(pdpu->pipe_hw,
-				&pdpu->pipe_cfg);
-	}
+		if (pstate->pipe_hw[i]->ops.setup_rects) {
+			pstate->pipe_hw[i]->ops.setup_rects(pstate->pipe_hw[i],
+					&pipe_cfg);
+		}
 
-	if (pdpu->pipe_hw->ops.setup_pe)
-		pdpu->pipe_hw->ops.setup_pe(pdpu->pipe_hw,
-				&pstate->pixel_ext);
+		if (pstate->pipe_hw[i]->ops.setup_pe)
+			pstate->pipe_hw[i]->ops.setup_pe(pstate->pipe_hw[i],
+					&pstate->pixel_ext);
 
-	if (pdpu->pipe_hw->ops.setup_scaler)
-		pdpu->pipe_hw->ops.setup_scaler(pdpu->pipe_hw,
-				&pdpu->pipe_cfg, &pstate->pixel_ext,
-				&pstate->scaler3_cfg);
+		if (pstate->pipe_hw[i]->ops.setup_scaler)
+			pstate->pipe_hw[i]->ops.setup_scaler(pstate->pipe_hw[i],
+					&pipe_cfg, &pstate->pixel_ext,
+					&pstate->scaler3_cfg);
 
-	if (pdpu->pipe_hw->ops.setup_format) {
-		src_flags = 0x0;
+		if (pstate->pipe_hw[i]->ops.setup_format) {
+			src_flags = 0x0;
 
-		/* update format */
-		pdpu->pipe_hw->ops.setup_format(pdpu->pipe_hw, fmt, src_flags);
+			/* update format */
+			pstate->pipe_hw[i]->ops.setup_format(
+					pstate->pipe_hw[i], fmt, src_flags);
 
-		if (pdpu->pipe_hw->ops.setup_cdp) {
-			struct dpu_hw_pipe_cdp_cfg *cdp_cfg = &pstate->cdp_cfg;
+			if (pstate->pipe_hw[i]->ops.setup_cdp) {
+				struct dpu_hw_pipe_cdp_cfg *cdp_cfg =
+						&pstate->cdp_cfg;
 
-			memset(cdp_cfg, 0, sizeof(struct dpu_hw_pipe_cdp_cfg));
+				memset(cdp_cfg, 0,
+					sizeof(struct dpu_hw_pipe_cdp_cfg));
 
-			cdp_cfg->enable = pdpu->catalog->perf.cdp_cfg
+				cdp_cfg->enable = kms->catalog->perf.cdp_cfg
 					[DPU_PERF_CDP_USAGE_RT].rd_enable;
-			cdp_cfg->ubwc_meta_enable =
+				cdp_cfg->ubwc_meta_enable =
 					DPU_FORMAT_IS_UBWC(fmt);
-			cdp_cfg->tile_amortize_enable =
+				cdp_cfg->tile_amortize_enable =
 					DPU_FORMAT_IS_UBWC(fmt) ||
 					DPU_FORMAT_IS_TILE(fmt);
-			cdp_cfg->preload_ahead = DPU_SSPP_CDP_PRELOAD_AHEAD_64;
-
-			pdpu->pipe_hw->ops.setup_cdp(pdpu->pipe_hw, cdp_cfg);
+				cdp_cfg->preload_ahead =
+					DPU_SSPP_CDP_PRELOAD_AHEAD_64;
+
+				pstate->pipe_hw[i]->ops.setup_cdp(
+					pstate->pipe_hw[i], cdp_cfg);
+			}
+
+			/* update csc */
+			if (DPU_FORMAT_IS_YUV(fmt))
+				_dpu_plane_setup_csc(pdpu,
+					pstate->pipe_hw[i]->cap->features);
+			else
+				pdpu->csc_ptr = 0;
 		}
 
-		/* update csc */
-		if (DPU_FORMAT_IS_YUV(fmt))
-			_dpu_plane_setup_csc(pdpu);
-		else
-			pdpu->csc_ptr = 0;
-	}
+		_dpu_plane_set_qos_lut(plane, pstate->pipe_hw[i],
+					&pipe_cfg, fb);
+		_dpu_plane_set_danger_lut(plane, pstate->pipe_hw[i], fb);
 
-	_dpu_plane_set_qos_lut(plane, fb);
-	_dpu_plane_set_danger_lut(plane, fb);
+		if (plane->type != DRM_PLANE_TYPE_CURSOR) {
+			_dpu_plane_set_qos_ctrl(plane,  pstate->pipe_hw[i],
+					true, DPU_PLANE_QOS_PANIC_CTRL);
+			_dpu_plane_set_ot_limit(plane,  pstate->pipe_hw[i],
+					&pipe_cfg, crtc);
+		}
 
-	if (plane->type != DRM_PLANE_TYPE_CURSOR) {
-		_dpu_plane_set_qos_ctrl(plane, true, DPU_PLANE_QOS_PANIC_CTRL);
-		_dpu_plane_set_ot_limit(plane, crtc);
+		_dpu_plane_set_qos_remap(plane, pstate->pipe_hw[i]);
 	}
 
-	_dpu_plane_set_qos_remap(plane);
 	return 0;
 }
 
@@ -1270,11 +1364,19 @@  void dpu_plane_restore(struct drm_plane *plane)
 static void dpu_plane_destroy(struct drm_plane *plane)
 {
 	struct dpu_plane *pdpu = plane ? to_dpu_plane(plane) : NULL;
+	struct dpu_plane_state *pstate;
+	int i;
 
 	DPU_DEBUG_PLANE(pdpu, "\n");
 
 	if (pdpu) {
-		_dpu_plane_set_qos_ctrl(plane, false, DPU_PLANE_QOS_PANIC_CTRL);
+		pstate = plane->state ? to_dpu_plane_state(plane->state) : NULL;
+		if (pstate) {
+			for (i = 0; i < pstate->num_pipes; i++)
+				_dpu_plane_set_qos_ctrl(plane,
+					pstate->pipe_hw[i], false,
+					DPU_PLANE_QOS_PANIC_CTRL);
+		}
 
 		mutex_destroy(&pdpu->lock);
 
@@ -1484,7 +1586,7 @@  static int _dpu_plane_init_debugfs(struct drm_plane *plane)
 
 	/* create overall sub-directory for the pipe */
 	pdpu->debugfs_root =
-		debugfs_create_dir(pdpu->pipe_name,
+		debugfs_create_dir(pdpu->name,
 				plane->dev->primary->debugfs_root);
 
 	if (!pdpu->debugfs_root)
@@ -1546,9 +1648,9 @@  static void dpu_plane_early_unregister(struct drm_plane *plane)
 		.atomic_update = dpu_plane_atomic_update,
 };
 
-enum dpu_sspp dpu_plane_pipe(struct drm_plane *plane)
+enum dpu_sspp dpu_plane_pipe(struct dpu_hw_pipe *pipe_hw)
 {
-	return plane ? to_dpu_plane(plane)->pipe : SSPP_NONE;
+	return pipe_hw ? pipe_hw->idx : SSPP_NONE;
 }
 
 /* initialize plane */
@@ -1578,8 +1680,8 @@  struct drm_plane *dpu_plane_init(struct drm_device *dev,
 		DPU_ERROR("[%u]invalid KMS reference\n", pipe);
 		goto exit;
 	}
-	kms = to_dpu_kms(priv->kms);
 
+	kms = to_dpu_kms(priv->kms);
 	if (!kms->catalog) {
 		DPU_ERROR("[%u]invalid catalog reference\n", pipe);
 		goto exit;
@@ -1625,11 +1727,11 @@  struct drm_plane *dpu_plane_init(struct drm_device *dev,
 	drm_plane_helper_add(plane, &dpu_plane_helper_funcs);
 
 	/* save user friendly pipe name for later */
-	snprintf(pdpu->pipe_name, DPU_NAME_SIZE, "plane%u", plane->base.id);
+	snprintf(pdpu->name, DPU_NAME_SIZE, "plane%u", plane->base.id);
 
 	mutex_init(&pdpu->lock);
 
-	DPU_DEBUG("%s created for pipe:%u id:%u\n", pdpu->pipe_name,
+	DPU_DEBUG("%s created for pipe:%u id:%u\n", pdpu->name,
 					pipe, plane->base.id);
 	return plane;
 
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
index 4eb929b..3ebc4c1 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
@@ -71,10 +71,10 @@  struct dpu_plane_state {
 
 /**
  * dpu_plane_pipe - return sspp identifier for the given plane
- * @plane:   Pointer to DRM plane object
+ * @pipe_hw:   Pointer to DPU pipe hw
  * Returns: sspp identifier of the given plane
  */
-enum dpu_sspp dpu_plane_pipe(struct drm_plane *plane);
+enum dpu_sspp dpu_plane_pipe(struct dpu_hw_pipe *pipe_hw);
 
 /**
  * dpu_plane_get_ctl_flush - get control flush mask