msm_fb: display: Add support for 4 layer MDP composition

Add 4 layers composition support to MDP by allowing borderfill
pipe to be used as base layer of mdp blending. This releases
RGB1 base pipe which can be used as a general purpose pipe.

Change-Id:I517485d738e8bb555a263b3ea885d78d5e4f4396
Signed-off-by: Kuogee Hsieh <khsieh@codeaurora.org>
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index 7fd2d91..30579e7 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -1887,7 +1887,7 @@
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 
 	if (mdp_rev >= MDP_REV_41 && mfd->panel.type == MIPI_CMD_PANEL)
-		mdp_dsi_cmd_overlay_suspend();
+		mdp_dsi_cmd_overlay_suspend(mfd);
 	return ret;
 }
 
@@ -1897,7 +1897,6 @@
 
 #ifdef CONFIG_FB_MSM_MDP40
 	struct msm_fb_data_type *mfd;
-	mdp4_overlay_ctrl_db_reset();
 
 	mfd = platform_get_drvdata(pdev);
 
diff --git a/drivers/video/msm/mdp.h b/drivers/video/msm/mdp.h
index b104b33..f1a6899 100644
--- a/drivers/video/msm/mdp.h
+++ b/drivers/video/msm/mdp.h
@@ -825,7 +825,7 @@
 #endif
 
 #ifndef CONFIG_FB_MSM_MDP40
-static inline void mdp_dsi_cmd_overlay_suspend(void)
+static inline void mdp_dsi_cmd_overlay_suspend(struct msm_fb_data_type *mfd)
 {
 	/* empty */
 }
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index 905fc21..21513a4 100644
--- a/drivers/video/msm/mdp4.h
+++ b/drivers/video/msm/mdp4.h
@@ -173,6 +173,7 @@
 	MDP4_MIXER_STAGE0,	/* zorder 0 */
 	MDP4_MIXER_STAGE1,	/* zorder 1 */
 	MDP4_MIXER_STAGE2,	/* zorder 2 */
+	MDP4_MIXER_STAGE3,	/* zorder 3 */
 	MDP4_MIXER_STAGE_MAX
 };
 
@@ -256,6 +257,19 @@
 	u8 mark_unmap;
 };
 
+struct blend_cfg {
+	u32 op;
+	u32 bg_alpha;
+	u32 fg_alpha;
+	u32 co3_sel;
+	u32 transp_low0;
+	u32 transp_low1;
+	u32 transp_high0;
+	u32 transp_high1;
+	int solidfill;
+	struct mdp4_overlay_pipe *solidfill_pipe;
+};
+
 struct mdp4_overlay_pipe {
 	uint32 pipe_used;
 	uint32 pipe_type;		/* rgb, video/graphic */
@@ -403,6 +417,7 @@
 void mdp4_intr_clear_set(ulong clear, ulong set);
 void mdp4_dma_p_cfg(void);
 unsigned is_mdp4_hw_reset(void);
+void mdp4_overlay_cfg_init(void);
 void mdp4_hw_init(void);
 void mdp4_isr_read(int);
 void mdp4_clear_lcdc(void);
@@ -417,6 +432,7 @@
 uint32 mdp4_overlay_format(struct mdp4_overlay_pipe *pipe);
 uint32 mdp4_overlay_unpack_pattern(struct mdp4_overlay_pipe *pipe);
 uint32 mdp4_overlay_op_mode(struct mdp4_overlay_pipe *pipe);
+void mdp4_lcdc_base_swap(struct mdp4_overlay_pipe *pipe);
 void mdp4_lcdc_overlay(struct msm_fb_data_type *mfd);
 #ifdef CONFIG_FB_MSM_DTV
 void mdp4_overlay_dtv_start(void);
@@ -489,6 +505,7 @@
 			struct mdp4_overlay_pipe *pipe);
 int mdp4_overlay_dtv_unset(struct msm_fb_data_type *mfd,
 			struct mdp4_overlay_pipe *pipe);
+void mdp4_dtv_base_swap(struct mdp4_overlay_pipe *pipe);
 void mdp4_dtv_overlay(struct msm_fb_data_type *mfd);
 int mdp4_dtv_on(struct platform_device *pdev);
 int mdp4_dtv_off(struct platform_device *pdev);
@@ -506,7 +523,7 @@
 int mdp4_overlay_dsi_state_get(void);
 void mdp4_overlay_rgb_setup(struct mdp4_overlay_pipe *pipe);
 void mdp4_overlay_reg_flush(struct mdp4_overlay_pipe *pipe, int all);
-void mdp4_mixer_blend_setup(struct mdp4_overlay_pipe *pipe);
+void mdp4_mixer_blend_setup(int mixer);
 struct mdp4_overlay_pipe *mdp4_overlay_stage_pipe(int mixer, int stage);
 void mdp4_mixer_stage_up(struct mdp4_overlay_pipe *pipe);
 void mdp4_mixer_stage_down(struct mdp4_overlay_pipe *pipe);
@@ -519,6 +536,7 @@
 int mdp4_overlay_get(struct fb_info *info, struct mdp_overlay *req);
 int mdp4_overlay_set(struct fb_info *info, struct mdp_overlay *req);
 int mdp4_overlay_unset(struct fb_info *info, int ndx);
+int mdp4_overlay_unset_mixer(int mixer);
 int mdp4_overlay_play_wait(struct fb_info *info,
 	struct msmfb_overlay_data *req);
 int mdp4_overlay_play(struct fb_info *info, struct msmfb_overlay_data *req);
@@ -612,6 +630,7 @@
 					struct msmfb_overlay_blt *req);
 int mdp4_dsi_video_overlay_blt_offset(struct msm_fb_data_type *mfd,
 					struct msmfb_overlay_blt *req);
+void mdp4_dsi_video_base_swap(struct mdp4_overlay_pipe *pipe);
 
 #ifdef CONFIG_FB_MSM_MDP40
 static inline void mdp3_dsi_cmd_dma_busy_wait(struct msm_fb_data_type *mfd)
@@ -659,6 +678,10 @@
 {
 	return -ENODEV;
 }
+static inline void mdp4_dsi_video_base_swap(struct mdp4_overlay_pipe *pipe)
+{
+	/* empty */
+}
 #endif
 
 void mdp4_lcdc_overlay_blt(struct msm_fb_data_type *mfd,
@@ -690,7 +713,7 @@
 void mdp4_overlay_dsi_video_vsync_push(struct msm_fb_data_type *mfd,
 				struct mdp4_overlay_pipe *pipe);
 void mdp4_dsi_cmd_overlay_restore(void);
-void mdp_dsi_cmd_overlay_suspend(void);
+void mdp_dsi_cmd_overlay_suspend(struct msm_fb_data_type *mfd);
 #else
 static inline void mdp4_dsi_cmd_dma_busy_wait(struct msm_fb_data_type *mfd)
 {
@@ -714,7 +737,7 @@
 	/* empty */
 }
 #ifdef CONFIG_FB_MSM_MDP40
-static inline void mdp_dsi_cmd_overlay_suspend(void)
+static inline void mdp_dsi_cmd_overlay_suspend(struct msm_fb_data_type *mfd)
 {
 	/* empty */
 }
@@ -727,6 +750,7 @@
 				struct mdp4_overlay_pipe *pipe);
 void mdp4_dsi_cmd_overlay_kickoff(struct msm_fb_data_type *mfd,
 				struct mdp4_overlay_pipe *pipe);
+void mdp4_dsi_cmd_base_swap(struct mdp4_overlay_pipe *pipe);
 
 void mdp4_overlay_panel_3d(int mixer_num, uint32 panel_3d);
 int mdp4_overlay_3d_sbys(struct fb_info *info, struct msmfb_overlay_3d *req);
@@ -747,7 +771,7 @@
 void mdp4_overlay_dsi_video_wait4vsync(struct msm_fb_data_type *mfd);
 void mdp4_primary_vsync_dsi_video(void);
 uint32_t mdp4_ss_table_value(int8_t param, int8_t index);
-void mdp4_overlay_ctrl_db_reset(void);
+void mdp4_overlay_borderfill_stage_down(struct mdp4_overlay_pipe *pipe);
 
 int mdp4_overlay_writeback_on(struct platform_device *pdev);
 int mdp4_overlay_writeback_off(struct platform_device *pdev);
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index ce0dd3d..b4712a1 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -46,8 +46,12 @@
 struct mdp4_overlay_ctrl {
 	struct mdp4_overlay_pipe plist[OVERLAY_PIPE_MAX];
 	struct mdp4_overlay_pipe *stage[MDP4_MIXER_MAX][MDP4_MIXER_STAGE_MAX];
+	struct mdp4_overlay_pipe *baselayer[MDP4_MIXER_MAX];
+	struct blend_cfg blend[MDP4_MIXER_MAX][MDP4_MIXER_STAGE_MAX];
 	uint32 mixer_cfg[MDP4_MIXER_MAX];
+	uint32 flush[MDP4_MIXER_MAX];
 	uint32 cs_controller;
+	uint32 hw_version;
 	uint32 panel_3d;
 	uint32 panel_mode;
 	uint32 mixer0_played;
@@ -198,14 +202,6 @@
 	}
 }
 
-void mdp4_overlay_ctrl_db_reset(void)
-{
-	int i;
-
-	for (i = MDP4_MIXER0; i < MDP4_MIXER_MAX; i++)
-		ctrl->mixer_cfg[i] = 0;
-}
-
 int mdp4_overlay_mixer_play(int mixer_num)
 {
 	if (mixer_num == MDP4_MIXER2)
@@ -236,6 +232,20 @@
 	return ctrl->panel_mode;
 }
 
+void mdp4_overlay_cfg_init(void)
+{
+	if (ctrl->hw_version == 0) {
+		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+		ctrl->hw_version = inpdw(MDP_BASE + 0x0); /* MDP_HW_VERSION */
+		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+	}
+
+	if (ctrl->hw_version >= 0x0402030b) {
+		/* MDP_LAYERMIXER_IN_CFG_UPDATE_METHOD */
+		outpdw(MDP_BASE + 0x100fc, 0x01);
+	}
+}
+
 void mdp4_overlay_dmae_cfg(struct msm_fb_data_type *mfd, int atv)
 {
 	uint32	dmae_cfg_reg;
@@ -847,6 +857,8 @@
 	case MDP_YCRCB_H1V1:
 	case MDP_YCBCR_H1V1:
 		return OVERLAY_TYPE_VIDEO;
+	case MDP_RGB_BORDERFILL:
+		return OVERLAY_TYPE_BF;
 	default:
 		mdp4_stat.err_format++;
 		return -ERANGE;
@@ -1120,6 +1132,9 @@
 			pipe->element2 = C2_R_Cr;   /* R */
 		}
 		pipe->bpp = 3;  /* 3 bpp */
+	case MDP_RGB_BORDERFILL:
+		pipe->alpha_enable = 0;
+		pipe->alpha = 0;
 		break;
 	default:
 		/* not likely */
@@ -1441,13 +1456,13 @@
 		return -ENODEV;
 
 	cnt = 0;
-	ndx = 1; /* ndx 0 if not used */
-
+	ndx = MDP4_MIXER_STAGE_BASE;
 	for ( ; ndx < MDP4_MIXER_STAGE_MAX; ndx++) {
 		pipe = ctrl->stage[mixer_num][ndx];
 		if (pipe == NULL)
 			continue;
 		info->z_order = pipe->mixer_stage - MDP4_MIXER_STAGE0;
+		/* z_order == -1, means base layer */
 		info->ptype = pipe->pipe_type;
 		info->pnum = pipe->pipe_num;
 		info->pndx = pipe->pipe_ndx;
@@ -1458,331 +1473,458 @@
 	return cnt;
 }
 
-static void mdp4_overlay_bg_solidfill_clear(uint32 mixer_num)
-{
-	struct mdp4_overlay_pipe *bg_pipe;
-	unsigned char *rgb_base;
-	uint32 rgb_src_format;
-	int pnum;
-
-	bg_pipe = mdp4_overlay_stage_pipe(mixer_num,
-		MDP4_MIXER_STAGE_BASE);
-	if (bg_pipe && bg_pipe->pipe_type == OVERLAY_TYPE_BF) {
-		bg_pipe = mdp4_overlay_stage_pipe(mixer_num,
-				MDP4_MIXER_STAGE0);
-	}
-
-	if (bg_pipe && bg_pipe->pipe_type == OVERLAY_TYPE_RGB) {
-		rgb_src_format = mdp4_overlay_format(bg_pipe);
-		if (!(rgb_src_format & MDP4_FORMAT_SOLID_FILL)) {
-			pnum = bg_pipe->pipe_num - OVERLAY_PIPE_RGB1;
-			rgb_base = MDP_BASE + MDP4_RGB_BASE;
-			rgb_base += MDP4_RGB_OFF * pnum;
-			outpdw(rgb_base + 0x50, rgb_src_format);
-			outpdw(rgb_base + 0x0058, bg_pipe->op_mode);
-			mdp4_overlay_reg_flush(bg_pipe, 0);
-		}
-	}
-}
-
-void mdp4_mixer_pipe_cleanup(int mixer)
-{
-	struct mdp4_overlay_pipe *pipe;
-	int j;
-
-	for (j = MDP4_MIXER_STAGE_MAX - 1; j > MDP4_MIXER_STAGE_BASE; j--) {
-		pipe = ctrl->stage[mixer][j];
-		if (pipe == NULL)
-			continue;
-		pr_debug("%s(): pipe %u\n", __func__, pipe->pipe_ndx);
-		mdp4_mixer_stage_down(pipe);
-		mdp4_overlay_pipe_free(pipe);
-	}
-}
-
 static void mdp4_mixer_stage_commit(int mixer)
 {
 	struct mdp4_overlay_pipe *pipe;
-	int i, j, off;
-	u32 data = 0, stage, flush_bits = 0, pipe_cnt = 0, pull_mode = 0;
-	u32 cfg[MDP4_MIXER_MAX];
+	int i, num;
+	u32 data, stage;
+	int off;
+	unsigned long flags;
 
-	if (mixer == MDP4_MIXER0)
-		flush_bits |= 0x1;
-	else if (mixer == MDP4_MIXER1)
-		flush_bits |= 0x2;
+	data = 0;
+	for (i = MDP4_MIXER_STAGE_BASE; i < MDP4_MIXER_STAGE_MAX; i++) {
+		pipe = ctrl->stage[mixer][i];
+		if (pipe == NULL)
+			continue;
+		pr_debug("%s: mixer=%d ndx=%d stage=%d\n", __func__,
+					mixer, pipe->pipe_ndx, i);
+		stage = pipe->mixer_stage;
+		if (mixer >= MDP4_MIXER1)
+			stage += 8;
+		stage <<= (4 * pipe->pipe_num);
+		data |= stage;
+	}
 
-	for (i = MDP4_MIXER0; i < MDP4_MIXER_MAX; i++) {
-		cfg[i] = 0;
-		for (j = MDP4_MIXER_STAGE_BASE; j < MDP4_MIXER_STAGE_MAX; j++) {
-			pipe = ctrl->stage[i][j];
-			if (pipe == NULL)
-				break;
-			stage = pipe->mixer_stage;
-			if (i >= MDP4_MIXER1)
-				stage += 8;
-			stage <<= (4 * pipe->pipe_num);
-			cfg[i] |= stage;
-			pipe_cnt++;
+	mdp4_mixer_blend_setup(mixer);
 
-			mdp4_mixer_blend_setup(pipe);
+	off = 0;
+	if (data != ctrl->mixer_cfg[mixer]) {
+		ctrl->mixer_cfg[mixer] = data;
+		if (mixer >= MDP4_MIXER2) {
+			/* MDP_LAYERMIXER2_IN_CFG */
+			off = 0x100f0;
+		} else {
+			/* mixer 0 or 1 */
+			num = mixer + 1;
+			num &= 0x01;
+			data |= ctrl->mixer_cfg[num];
+			off = 0x10100;
 		}
+		pr_debug("%s: mixer=%d data=%x flush=%x\n", __func__,
+				mixer, data, ctrl->flush[mixer]);
 	}
 
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	if (ctrl->mixer_cfg[mixer] != cfg[mixer]) {
-		if ((ctrl->mixer_cfg[MDP4_MIXER0] != cfg[MDP4_MIXER0]) ||
-		    (ctrl->mixer_cfg[MDP4_MIXER1] != cfg[MDP4_MIXER1])) {
-			off = 0x10100;
-			if (ctrl->mixer_cfg[MDP4_MIXER0] != cfg[MDP4_MIXER0]) {
-				flush_bits |= 0x1;
-				ctrl->mixer_cfg[MDP4_MIXER0] = cfg[MDP4_MIXER0];
+	local_irq_save(flags);
+	if (off)
+		outpdw(MDP_BASE + off, data);
 
-				if ((ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) ||
-				    (ctrl->panel_mode & MDP4_PANEL_LCDC))
-					pull_mode = 1;
-			}
-			if (ctrl->mixer_cfg[MDP4_MIXER1] != cfg[MDP4_MIXER1]) {
-				flush_bits |= 0x2;
-				ctrl->mixer_cfg[MDP4_MIXER1] = cfg[MDP4_MIXER1];
-
-				pull_mode = 1;
-			}
-
-			data = cfg[MDP4_MIXER0] | cfg[MDP4_MIXER1];
-
-			pr_debug("%s: mixer=%d data=%x flush=%x\n", __func__,
-			       mixer, data, flush_bits);
-
-			outpdw(MDP_BASE + off, data); /* LAYERMIXER_IN_CFG */
-			if (pull_mode) {
-				outpdw(MDP_BASE + 0x18000, flush_bits);
-			/* wait for vsync on both pull mode interfaces */
-				msleep(20);
-			}
-		}
-
-		if (ctrl->mixer_cfg[MDP4_MIXER2] != cfg[MDP4_MIXER2]) {
-			off = 0x100F0;
-			ctrl->mixer_cfg[MDP4_MIXER2] = cfg[MDP4_MIXER2];
-			data = cfg[MDP4_MIXER2];
-
-			pr_debug("%s: mixer=%d data=%x\n", __func__,
-			       mixer, data);
-
-			outpdw(MDP_BASE + off, data); /* LAYERMIXER_IN_CFG */
-		}
-	} else {
-		if (mixer == MDP4_MIXER0) {
-			if ((ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) ||
-			(ctrl->panel_mode & MDP4_PANEL_LCDC))
-				pull_mode = 1;
-		} else if (mixer == MDP4_MIXER1) {
-			pull_mode = 1;
-		}
-
-		if (pull_mode)
-			outpdw(MDP_BASE + 0x18000, flush_bits);
+	if (ctrl->flush[mixer]) {
+		outpdw(MDP_BASE + 0x18000, ctrl->flush[mixer]);
+		ctrl->flush[mixer] = 0;
 	}
+	local_irq_restore(flags);
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-
-	if (data && pipe_cnt == 1)
-		mdp4_update_perf_level(OVERLAY_PERF_LEVEL4);
 }
 
+
 void mdp4_mixer_stage_up(struct mdp4_overlay_pipe *pipe)
 {
-	struct mdp4_overlay_pipe *spipe;
-	int mixer;
+	struct mdp4_overlay_pipe *pp;
+	int i, mixer;
 
 	mixer = pipe->mixer_num;
 
-	spipe = ctrl->stage[mixer][pipe->mixer_stage];
-	if ((spipe != NULL) && (spipe->pipe_num != pipe->pipe_num)) {
-		mdp4_stat.err_stage++;
-		return;
+	for (i = MDP4_MIXER_STAGE_BASE; i < MDP4_MIXER_STAGE_MAX; i++) {
+		pp = ctrl->stage[mixer][i];
+		if (pp == pipe) {
+			ctrl->stage[mixer][i] = NULL;
+			break;
+		}
 	}
 
 	ctrl->stage[mixer][pipe->mixer_stage] = pipe;	/* keep it */
 
-	if (!(pipe->flags & MDP_OV_PLAY_NOWAIT))
+	if (!(pipe->flags & MDP_OV_PLAY_NOWAIT)) {
+		pr_debug("%s: mixer=%d ndx=%d stage=%d flags=%x\n",
+			__func__, mixer, pipe->pipe_ndx,
+				pipe->mixer_stage, pipe->flags);
 		mdp4_mixer_stage_commit(mixer);
+	}
 }
 
 void mdp4_mixer_stage_down(struct mdp4_overlay_pipe *pipe)
 {
-	struct mdp4_overlay_pipe *spipe;
+	struct mdp4_overlay_pipe *pp;
+	int i, mixer;
 
-	spipe = ctrl->stage[pipe->mixer_num][pipe->mixer_stage];
-	if (spipe == NULL)	/* not running */
+	mixer = pipe->mixer_num;
+
+	for (i = MDP4_MIXER_STAGE_BASE; i < MDP4_MIXER_STAGE_MAX; i++) {
+		pp = ctrl->stage[mixer][i];
+		if (pp == pipe)
+			ctrl->stage[mixer][i] = NULL;  /* clear it */
+	}
+
+	if (!(pipe->flags & MDP_OV_PLAY_NOWAIT)) {
+		pr_debug("%s: mixer=%d ndx=%d stage=%d flags=%x\n",
+			__func__, pipe->mixer_num, pipe->pipe_ndx,
+				pipe->mixer_stage, pipe->flags);
+		mdp4_mixer_stage_commit(pipe->mixer_num);
+	}
+}
+/*
+ * mixer0: rgb3: border color at register 0x15004, 0x15008
+ * mixer1:  vg3: border color at register 0x1D004, 0x1D008
+ * mixer2:  xxx: border color at register 0x8D004, 0x8D008
+ */
+void mdp4_overlay_borderfill_stage_up(struct mdp4_overlay_pipe *pipe)
+{
+	struct mdp4_overlay_pipe *bspipe;
+	int ptype, pnum, pndx, mixer;
+	int format, alpha_enable, alpha;
+
+	if (pipe->pipe_type != OVERLAY_TYPE_BF)
 		return;
 
-	ctrl->stage[pipe->mixer_num][pipe->mixer_stage] = NULL;	/* clear it */
+	mixer = pipe->mixer_num;
 
-	mdp4_mixer_stage_commit(pipe->mixer_num);
+	if (ctrl->baselayer[mixer])
+		return;
+
+	bspipe = ctrl->stage[mixer][MDP4_MIXER_STAGE_BASE];
+
+	/* save original base layer */
+	ctrl->baselayer[mixer] = bspipe;
+
+	pipe->alpha = 0;	/* make sure bf pipe has alpha 0 */
+	ptype = pipe->pipe_type;
+	pnum = pipe->pipe_num;
+	pndx = pipe->pipe_ndx;
+	format = pipe->src_format;
+	alpha_enable = pipe->alpha_enable;
+	alpha = pipe->alpha;
+	*pipe = *bspipe;	/* keep base layer configuration */
+	pipe->pipe_type = ptype;
+	pipe->pipe_num = pnum;
+	pipe->pipe_ndx = pndx;
+	pipe->src_format = format;
+	pipe->alpha_enable = alpha_enable;
+	pipe->alpha = alpha;
+
+	/* free original base layer pipe to be sued as normal pipe */
+	bspipe->pipe_used = 0;
+
+	if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO)
+		mdp4_dsi_video_base_swap(pipe);
+	else if (ctrl->panel_mode & MDP4_PANEL_LCDC)
+		mdp4_lcdc_base_swap(pipe);
+	else if (ctrl->panel_mode & MDP4_PANEL_DTV)
+		mdp4_dtv_base_swap(pipe);
+
+	mdp4_overlay_reg_flush(bspipe, 1);
+	/* borderfill pipe as base layer */
+	mdp4_mixer_stage_up(pipe);
 }
 
-void mdp4_mixer_blend_setup(struct mdp4_overlay_pipe *pipe)
+void mdp4_overlay_borderfill_stage_down(struct mdp4_overlay_pipe *pipe)
 {
-	struct mdp4_overlay_pipe *bg_pipe;
-	unsigned char *overlay_base, *rgb_base;
-	uint32 c0, c1, c2, blend_op, constant_color = 0, rgb_src_format;
-	uint32 fg_color3_out, fg_alpha = 0, bg_alpha = 0;
-	int off, pnum;
+	struct mdp4_overlay_pipe *bspipe;
+	int ptype, pnum, pndx, mixer;
+	int format, alpha_enable, alpha;
 
-	if (pipe->mixer_stage == MDP4_MIXER_STAGE_BASE)
+	if (pipe->pipe_type != OVERLAY_TYPE_BF)
 		return;
 
+	mixer = pipe->mixer_num;
+
+	/* retrieve original base layer */
+	bspipe = ctrl->baselayer[mixer];
+	if (bspipe == NULL) {
+		pr_err("%s: no base layer at mixer=%d\n",
+				__func__, mixer);
+		return;
+	}
+
+	ptype = bspipe->pipe_type;
+	pnum = bspipe->pipe_num;
+	pndx = bspipe->pipe_ndx;
+	format = bspipe->src_format;
+	alpha_enable = bspipe->alpha_enable;
+	alpha = bspipe->alpha;
+	*bspipe = *pipe;	/* restore base layer configuration */
+	bspipe->pipe_type = ptype;
+	bspipe->pipe_num = pnum;
+	bspipe->pipe_ndx = pndx;
+	bspipe->src_format = format;
+	bspipe->alpha_enable = alpha_enable;
+	bspipe->alpha = alpha;
+
+	bspipe->pipe_used++;	/* mark base layer pipe used */
+
+	ctrl->baselayer[mixer] = NULL;
+
+	/* free borderfill pipe */
+	pipe->pipe_used = 0;
+
+	mdp4_dsi_video_base_swap(bspipe);
+
+	/* free borderfill pipe */
+	mdp4_overlay_reg_flush(pipe, 1);
+	mdp4_mixer_stage_down(pipe);
+	mdp4_overlay_pipe_free(pipe);
+
+	/* stage up base layer */
+	mdp4_overlay_reg_flush(bspipe, 1);
+	/* restore original base layer */
+	mdp4_mixer_stage_up(bspipe);
+}
+
+
+static struct mdp4_overlay_pipe *mdp4_background_layer(int mixer,
+			struct mdp4_overlay_pipe *sp)
+{
+	struct mdp4_overlay_pipe *pp;
+	struct mdp4_overlay_pipe *kp;
+	int i;
+
+	kp = ctrl->stage[mixer][MDP4_MIXER_STAGE_BASE];
+	for (i = MDP4_MIXER_STAGE_BASE; i < MDP4_MIXER_STAGE_MAX; i++) {
+		pp = ctrl->stage[mixer][i];
+		if (pp == NULL)
+			continue;
+		if (pp == sp)
+			break;
+
+		if ((pp->dst_x <= sp->dst_x) &&
+			((pp->dst_x + pp->dst_w) >= (sp->dst_x + sp->dst_w))) {
+			if ((pp->dst_y <= sp->dst_y) &&
+				((pp->dst_y + pp->dst_h) >=
+					(sp->dst_y + sp->dst_h))) {
+				kp = pp;
+			}
+		}
+	}
+	return kp;
+}
+
+static void mdp4_overlay_bg_solidfill(struct blend_cfg *blend)
+{
+	struct mdp4_overlay_pipe *pipe;
+	char *base;
+	u32 op_mode, format;
+	int pnum, ptype;
+
+	pipe = blend->solidfill_pipe;
+	if (pipe == NULL)
+		return;
+
+	if (pipe->pipe_type == OVERLAY_TYPE_BF)
+		return;
+
+	ptype = mdp4_overlay_format2type(pipe->src_format);
+	if (ptype == OVERLAY_TYPE_RGB) {
+		pnum = pipe->pipe_num - OVERLAY_PIPE_RGB1;
+		base = MDP_BASE + MDP4_RGB_BASE;
+		base += MDP4_RGB_OFF * pnum;
+	} else {
+		pnum = pipe->pipe_num - OVERLAY_PIPE_VG1;
+		base = MDP_BASE + MDP4_VIDEO_BASE;
+		base += MDP4_VIDEO_OFF * pnum;
+	}
+
+	format = inpdw(base + 0x50);
+	if (blend->solidfill) {
+		format |= MDP4_FORMAT_SOLID_FILL;
+		/*
+		 * If solid fill is enabled, flip and scale
+		 * have to be disabled. otherwise, h/w
+		 * underruns.
+		 */
+		op_mode = inpdw(base + 0x0058);
+		op_mode &= ~(MDP4_OP_FLIP_LR + MDP4_OP_SCALEX_EN);
+		op_mode &= ~(MDP4_OP_FLIP_UD + MDP4_OP_SCALEY_EN);
+		outpdw(base + 0x0058, op_mode);
+		outpdw(base + 0x1008, 0);	/* black */
+	} else {
+		format &= ~MDP4_FORMAT_SOLID_FILL;
+		blend->solidfill_pipe = NULL;
+	}
+
+	outpdw(base + 0x50, format);
+
+	mdp4_overlay_reg_flush(pipe, 0);
+}
+
+/*
+ * D(i+1) = Ks * S + Kd * D(i)
+ */
+void mdp4_mixer_blend_setup(int mixer)
+{
+	struct mdp4_overlay_pipe *d_pipe;
+	struct mdp4_overlay_pipe *s_pipe;
+	struct blend_cfg *blend;
+	int i, off, ptype;
+	int d_alpha, s_alpha;
+	unsigned char *overlay_base;
+	uint32 c0, c1, c2;
+
+
+	d_pipe = ctrl->stage[mixer][MDP4_MIXER_STAGE_BASE];
+	if (d_pipe == NULL) {
+		pr_err("%s: Error: no bg_pipe at mixer=%d\n", __func__, mixer);
+		return;
+	}
+
+	blend = &ctrl->blend[mixer][MDP4_MIXER_STAGE0];
+	for (i = MDP4_MIXER_STAGE0; i < MDP4_MIXER_STAGE_MAX; i++) {
+		blend->solidfill = 0;
+		blend->op = (MDP4_BLEND_FG_ALPHA_FG_CONST |
+				    MDP4_BLEND_BG_ALPHA_BG_CONST);
+		s_pipe = ctrl->stage[mixer][i];
+		if (s_pipe == NULL) {
+			blend++;
+			d_pipe = NULL;
+			d_alpha = 0;
+			continue;
+		}
+		d_pipe = mdp4_background_layer(mixer, s_pipe);
+		d_alpha = d_pipe->alpha_enable;
+		s_alpha = s_pipe->alpha_enable;
+		pr_debug("%s: stage=%d: bg: ndx=%d da=%d dalpha=%x "
+			"fg: ndx=%d sa=%d salpha=%x is_fg=%d\n",
+		 __func__, i-2, d_pipe->pipe_ndx, d_alpha, d_pipe->alpha,
+		s_pipe->pipe_ndx, s_alpha, s_pipe->alpha, s_pipe->is_fg);
+
+		/* base on fg's alpha */
+		blend->bg_alpha = 0x0ff - s_pipe->alpha;
+		blend->fg_alpha = s_pipe->alpha;
+		blend->co3_sel = 1; /* use fg alpha */
+
+		if (s_pipe->is_fg) {
+			if (s_pipe->alpha == 0xff) {
+				blend->solidfill = 1;
+				blend->solidfill_pipe = d_pipe;
+			}
+		} else if (s_alpha) {
+			blend->op = (MDP4_BLEND_BG_ALPHA_FG_PIXEL |
+				    MDP4_BLEND_BG_INV_ALPHA);
+		} else if (d_alpha) {
+			ptype = mdp4_overlay_format2type(s_pipe->src_format);
+			if (ptype == OVERLAY_TYPE_VIDEO) {
+				blend->op = (MDP4_BLEND_BG_ALPHA_BG_PIXEL |
+				    MDP4_BLEND_FG_ALPHA_BG_PIXEL |
+				    MDP4_BLEND_FG_INV_ALPHA);
+				blend->co3_sel = 0; /* use bg alpha */
+			} else {
+				/* s_pipe is rgb without alpha */
+				blend->op = (MDP4_BLEND_FG_ALPHA_FG_CONST |
+					    MDP4_BLEND_BG_ALPHA_BG_CONST);
+				blend->bg_alpha = 0;
+			}
+		}
+
+		if (s_pipe->transp != MDP_TRANSP_NOP) {
+			if (s_pipe->is_fg) {
+				transp_color_key(s_pipe->src_format,
+						s_pipe->transp, &c0, &c1, &c2);
+				/* Fg blocked */
+				blend->op |= MDP4_BLEND_FG_TRANSP_EN;
+				/* lower limit */
+				blend->transp_low0 = (c1 << 16 | c0);
+				blend->transp_low1 = c2;
+				/* upper limit */
+				blend->transp_high0 = (c1 << 16 | c0);
+				blend->transp_high1 = c2;
+			} else {
+				transp_color_key(d_pipe->src_format,
+						s_pipe->transp, &c0, &c1, &c2);
+				/* Fg blocked */
+				blend->op |= MDP4_BLEND_BG_TRANSP_EN;
+				blend--; /* one stage back */
+				/* lower limit */
+				blend->transp_low0 = (c1 << 16 | c0);
+				blend->transp_low1 = c2;
+				/* upper limit */
+				blend->transp_high0 = (c1 << 16 | c0);
+				blend->transp_high1 = c2;
+				blend++; /* back to original stage */
+			}
+		}
+		blend++;
+	}
+
 	/* mixer numer, /dev/fb0, /dev/fb1, /dev/fb2 */
-	if (pipe->mixer_num == MDP4_MIXER2)
+	if (mixer == MDP4_MIXER2)
 		overlay_base = MDP_BASE + MDP4_OVERLAYPROC2_BASE;/* 0x88000 */
-	else if (pipe->mixer_num == MDP4_MIXER1)
+	else if (mixer == MDP4_MIXER1)
 		overlay_base = MDP_BASE + MDP4_OVERLAYPROC1_BASE;/* 0x18000 */
 	else
 		overlay_base = MDP_BASE + MDP4_OVERLAYPROC0_BASE;/* 0x10000 */
 
-	/* stage 0 to stage 2 */
-	off = 0x20 * (pipe->mixer_stage - MDP4_MIXER_STAGE0);
-
-	bg_pipe = mdp4_overlay_stage_pipe(pipe->mixer_num,
-					  MDP4_MIXER_STAGE_BASE);
-	if (bg_pipe == NULL) {
-		pr_err("%s: Error: no bg_pipe\n", __func__);
-		return;
-	}
-
-	if (bg_pipe->pipe_type == OVERLAY_TYPE_BF &&
-	    pipe->mixer_stage > MDP4_MIXER_STAGE0) {
-		bg_pipe = mdp4_overlay_stage_pipe(pipe->mixer_num,
-						  MDP4_MIXER_STAGE0);
-	}
-
-	if (pipe->alpha_enable) {
-		/* alpha channel is lost on VG pipe when downscaling */
-		if (pipe->pipe_type == OVERLAY_TYPE_VIDEO &&
-		    (pipe->dst_w < pipe->src_w || pipe->dst_h < pipe->src_h))
-			fg_alpha = 0;
-		else
-			fg_alpha = 1;
-	}
-
-	if (!fg_alpha && bg_pipe && bg_pipe->alpha_enable) {
-		struct mdp4_overlay_pipe *tmp;
-		int stage;
-
-		bg_alpha = 1;
-		/* check all bg layers are opaque to propagate bg alpha */
-		stage = bg_pipe->mixer_stage + 1;
-		for (; stage < pipe->mixer_stage; stage++) {
-			tmp = mdp4_overlay_stage_pipe(pipe->mixer_num, stage);
-			if (!tmp || tmp->alpha_enable || tmp->is_fg) {
-				bg_alpha = 0;
-				break;
-			}
-		}
-	}
-
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+	blend = &ctrl->blend[mixer][MDP4_MIXER_STAGE_BASE];
+	/* lower limit */
+	outpdw(overlay_base + 0x180, blend->transp_low0);
+	outpdw(overlay_base + 0x184,  blend->transp_low1);
+	/* upper limit */
+	outpdw(overlay_base + 0x188, blend->transp_high0);
+	outpdw(overlay_base + 0x18c,  blend->transp_high1);
+	blend++; /* stage0 */
+	for (i = MDP4_MIXER_STAGE0; i < MDP4_MIXER_STAGE_MAX; i++) {
+		off = 20 * i;
+		off = 0x20 * (i - MDP4_MIXER_STAGE0);
+		if (i == MDP4_MIXER_STAGE3)
+			off -= 4;
 
-	blend_op = (MDP4_BLEND_FG_ALPHA_FG_CONST |
-		    MDP4_BLEND_BG_ALPHA_BG_CONST);
-	outpdw(overlay_base + off + 0x108, pipe->alpha);
-	outpdw(overlay_base + off + 0x10c, 0xff - pipe->alpha);
-	fg_color3_out = 1; /* keep fg alpha by default */
+		if (blend->solidfill_pipe)
+			mdp4_overlay_bg_solidfill(blend);
 
-	if (pipe->is_fg) {
-		if (pipe->alpha == 0xff &&
-			bg_pipe->pipe_type == OVERLAY_TYPE_RGB) {
-			u32 op_mode;
-			pnum = bg_pipe->pipe_num - OVERLAY_PIPE_RGB1;
-			rgb_base = MDP_BASE + MDP4_RGB_BASE;
-			rgb_base += MDP4_RGB_OFF * pnum;
-			rgb_src_format = inpdw(rgb_base + 0x50);
-			rgb_src_format |= MDP4_FORMAT_SOLID_FILL;
-			/*
-			 * If solid fill is enabled, flip and scale
-			 * have to be disabled. otherwise, h/w
-			 * underruns. Also flush the pipe inorder
-			 * to take solid fill into effect.
-			 */
-			op_mode = inpdw(rgb_base + 0x0058);
-			op_mode &= ~(MDP4_OP_FLIP_LR + MDP4_OP_SCALEX_EN);
-			op_mode &= ~(MDP4_OP_FLIP_UD + MDP4_OP_SCALEY_EN);
-			outpdw(rgb_base + 0x0058, op_mode);
-			outpdw(rgb_base + 0x50, rgb_src_format);
-			outpdw(rgb_base + 0x1008, constant_color);
-			mdp4_overlay_reg_flush(bg_pipe, 0);
-		}
-	} else if (fg_alpha) {
-		blend_op = (MDP4_BLEND_BG_ALPHA_FG_PIXEL |
-			    MDP4_BLEND_BG_INV_ALPHA);
-		fg_color3_out = 1; /* keep fg alpha */
-	} else if (bg_alpha) {
-		blend_op = (MDP4_BLEND_BG_ALPHA_BG_PIXEL |
-			    MDP4_BLEND_FG_ALPHA_BG_PIXEL |
-			    MDP4_BLEND_FG_INV_ALPHA);
-		fg_color3_out = 0; /* keep bg alpha */
-	}
-
-	if (pipe->transp != MDP_TRANSP_NOP) {
-		if (pipe->is_fg) {
-			transp_color_key(pipe->src_format, pipe->transp,
-					&c0, &c1, &c2);
-			/* Fg blocked */
-			blend_op |= MDP4_BLEND_FG_TRANSP_EN;
-			/* lower limit */
-			outpdw(overlay_base + off + 0x110,
-					(c1 << 16 | c0));/* low */
-			outpdw(overlay_base + off + 0x114, c2);/* low */
+		outpdw(overlay_base + off + 0x108, blend->fg_alpha);
+		outpdw(overlay_base + off + 0x10c, blend->bg_alpha);
+		outpdw(overlay_base + off + 0x104, blend->op);
+		outpdw(overlay_base + (off << 5) + 0x1004, blend->co3_sel);
+		outpdw(overlay_base + off + 0x110, blend->transp_low0);/* low */
+		outpdw(overlay_base + off + 0x114, blend->transp_low1);/* low */
 			/* upper limit */
-			outpdw(overlay_base + off + 0x118,
-					(c1 << 16 | c0));
-			outpdw(overlay_base + off + 0x11c, c2);
-		} else if (bg_pipe) {
-			transp_color_key(bg_pipe->src_format,
-				pipe->transp, &c0, &c1, &c2);
-			/* bg blocked */
-			blend_op |= MDP4_BLEND_BG_TRANSP_EN;
-			/* lower limit */
-			outpdw(overlay_base + 0x180,
-					(c1 << 16 | c0));/* low */
-			outpdw(overlay_base + 0x184, c2);/* low */
-			/* upper limit */
-			outpdw(overlay_base + 0x188,
-					(c1 << 16 | c0));/* high */
-			outpdw(overlay_base + 0x18c, c2);/* high */
-		}
+		outpdw(overlay_base + off + 0x118, blend->transp_high0);
+		outpdw(overlay_base + off + 0x11c, blend->transp_high1);
+		blend++;
 	}
-
-	outpdw(overlay_base + off + 0x104, blend_op);
-	outpdw(overlay_base + (off << 5) + 0x1004, fg_color3_out);
-
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 }
 
 void mdp4_overlay_reg_flush(struct mdp4_overlay_pipe *pipe, int all)
 {
-	struct mdp4_overlay_pipe *bg_pipe;
-	uint32 bits = 0;
+	int mixer;
+	uint32 *reg;
+
+	mixer = pipe->mixer_num;
+	reg = &ctrl->flush[mixer];
+	*reg |= (1 << (2 + pipe->pipe_num));
 
 	if (all) {
-		if (pipe->mixer_num == MDP4_MIXER1)
-			bits |= 0x02;
+		if (mixer == MDP4_MIXER0)
+			*reg |= 0x01;
 		else
-			bits |= 0x01;
+			*reg |= 0x02;
 	}
+}
 
-	if (pipe->pipe_num <= OVERLAY_PIPE_RGB2)
-		bits |= 1 << (2 + pipe->pipe_num);
-	if (pipe->is_fg && pipe->alpha == 0xFF) {
-		bg_pipe = mdp4_overlay_stage_pipe(pipe->mixer_num,
-						  MDP4_MIXER_STAGE_BASE);
-		bits |= 1 << (2 + bg_pipe->pipe_num);
-	}
+void mdp4_overlay_flush_piggyback(int m0, int m1)
+{
+	u32 data;
 
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	outpdw(MDP_BASE + 0x18000, bits);	/* MDP_OVERLAY_REG_FLUSH */
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+	data = ctrl->flush[m0] | ctrl->flush[m1];
+	ctrl->flush[m0] = data;
+}
+
+void mdp4_overlay_reg_flush_reset(struct mdp4_overlay_pipe *pipe)
+{
+	int mixer;
+
+	mixer = pipe->mixer_num;
+	ctrl->flush[mixer] = 0;
 }
 
 struct mdp4_overlay_pipe *mdp4_overlay_stage_pipe(int mixer, int stage)
@@ -1810,6 +1952,11 @@
 	int i;
 	struct mdp4_overlay_pipe *pipe;
 
+	if (ptype == OVERLAY_TYPE_BF) {
+		if (!mdp4_overlay_borderfill_supported())
+			return NULL;
+	}
+
 	for (i = 0; i < OVERLAY_PIPE_MAX; i++) {
 		pipe = &ctrl->plist[i];
 		if ((pipe->pipe_used == 0) && ((pipe->pipe_type == ptype) ||
@@ -1951,7 +2098,7 @@
 		return -ERANGE;
 	}
 
-	if (req->z_order < 0 || req->z_order > 2) {
+	if (req->z_order < 0 || req->z_order > 3) {
 		pr_err("%s: z_order=%d out of range!\n", __func__,
 				req->z_order);
 		mdp4_stat.err_zorder++;
@@ -2076,12 +2223,12 @@
 	if (req->id == MSMFB_NEW_REQUEST) {  /* new request */
 		pipe->pipe_used++;
 		pipe->mixer_num = mixer;
-		pipe->mixer_stage = req->z_order + MDP4_MIXER_STAGE0;
 		pr_debug("%s: zorder=%d pipe ndx=%d num=%d\n", __func__,
 			req->z_order, pipe->pipe_ndx, pipe->pipe_num);
 
 	}
 
+	pipe->mixer_stage = req->z_order + MDP4_MIXER_STAGE0;
 	pipe->src_width = req->src.width & 0x1fff;	/* source img width */
 	pipe->src_height = req->src.height & 0x1fff;	/* source img height */
 	pipe->src_h = req->src_rect.h & 0x07ff;
@@ -2335,7 +2482,14 @@
 
 void mdp4_update_perf_level(u32 perf_level)
 {
+	static int first = 1;
+
 	new_perf_level = perf_level;
+
+	if (first) {
+		first = 0;
+		mdp4_set_perf_level();
+	}
 }
 
 void mdp4_set_perf_level(void)
@@ -2568,6 +2722,24 @@
 	return 0;
 }
 
+int mdp4_overlay_unset_mixer(int mixer)
+{
+	struct mdp4_overlay_pipe *pipe;
+	int i, cnt = 0;
+
+	for (i = MDP4_MIXER_STAGE3; i >= MDP4_MIXER_STAGE_BASE; i--) {
+		pipe = ctrl->stage[mixer][i];
+		if (pipe == NULL)
+			continue;
+		pipe->flags &= ~MDP_OV_PLAY_NOWAIT;
+		mdp4_mixer_stage_down(pipe);
+		mdp4_overlay_pipe_free(pipe);
+		cnt++;
+	}
+
+	return cnt;
+}
+
 int mdp4_overlay_unset(struct fb_info *info, int ndx)
 {
 	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
@@ -2588,6 +2760,12 @@
 		return -ENODEV;
 	}
 
+	if (pipe->pipe_type == OVERLAY_TYPE_BF) {
+		mdp4_overlay_borderfill_stage_down(pipe);
+		mutex_unlock(&mfd->dma->ov_mutex);
+		return 0;
+	}
+
 	if (pipe->mixer_num == MDP4_MIXER2)
 		ctrl->mixer2_played = 0;
 	else if (pipe->mixer_num == MDP4_MIXER1)
@@ -2609,16 +2787,12 @@
 #endif
 	}
 
-	if (mfd->mdp_rev >= MDP_REV_41 &&
-		mdp4_overlay_is_rgb_type(pipe->src_format) &&
-		!mfd->use_ov0_blt && (pipe->mixer_num == MDP4_MIXER0 ||
-		hdmi_prim_display)) {
-			ctrl->stage[pipe->mixer_num][pipe->mixer_stage] = NULL;
-	} else {
-		if (pipe->is_fg &&
-			!mdp4_overlay_is_rgb_type(pipe->src_format)) {
-			mdp4_overlay_bg_solidfill_clear(pipe->mixer_num);
-			pipe->is_fg = 0;
+	{
+		mdp4_overlay_reg_flush(pipe, 1);
+
+		if (mfd->use_ov0_blt || pipe->mixer_num == MDP4_MIXER1) {
+			/* unstage pipe forcedly */
+			pipe->flags &= ~MDP_OV_PLAY_NOWAIT;
 		}
 
 		mdp4_mixer_stage_down(pipe);
@@ -2779,6 +2953,12 @@
 	if (mutex_lock_interruptible(&mfd->dma->ov_mutex))
 		return -EINTR;
 
+	if (pipe->pipe_type == OVERLAY_TYPE_BF) {
+		mdp4_overlay_borderfill_stage_up(pipe);
+		mutex_unlock(&mfd->dma->ov_mutex);
+		return 0;
+	}
+
 	img = &req->data;
 	get_img(img, info, pipe, 0, &start, &len, &srcp0_file,
 		&ps0_need, &srcp0_ihdl);
@@ -2793,6 +2973,10 @@
 	pipe->srcp0_addr = addr;
 	pipe->srcp0_ystride = pipe->src_width * pipe->bpp;
 
+
+	pr_debug("%s: mixer=%d ndx=%x addr=%x flags=%x\n", __func__,
+		pipe->mixer_num, pipe->pipe_ndx, (int)addr, pipe->flags);
+
 	if ((req->version_key & VERSION_KEY_MASK) == 0xF9E8D700)
 		overlay_version = (req->version_key & ~VERSION_KEY_MASK);
 
@@ -2889,6 +3073,7 @@
 	if (mfd->use_ov1_blt)
 		mdp4_overlay1_update_blt_mode(mfd);
 
+
 	if (pipe->pipe_type == OVERLAY_TYPE_VIDEO) {
 		mdp4_overlay_vg_setup(pipe);	/* video/graphic pipe */
 	} else {
@@ -2901,11 +3086,7 @@
 		mdp4_overlay_rgb_setup(pipe);	/* rgb pipe */
 	}
 
-	if ((ctrl->panel_mode & MDP4_PANEL_DTV) ||
-		(ctrl->panel_mode & MDP4_PANEL_LCDC) ||
-		(ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO))
-		mdp4_overlay_reg_flush(pipe, 0);
-
+	mdp4_overlay_reg_flush(pipe, 1);
 	mdp4_mixer_stage_up(pipe);
 
 	if (pipe->mixer_num == MDP4_MIXER2) {
@@ -2920,6 +3101,9 @@
 		ctrl->mixer1_played++;
 		/* enternal interface */
 		if (ctrl->panel_mode & MDP4_PANEL_DTV) {
+			if (pipe->flags & MDP_OV_PLAY_NOWAIT)
+				mdp4_overlay_flush_piggyback(MDP4_MIXER0,
+							MDP4_MIXER1);
 			mdp4_overlay_dtv_start();
 			mdp4_overlay_dtv_ov_done_push(mfd, pipe);
 			if (!mfd->use_ov1_blt)
@@ -2948,6 +3132,7 @@
 		}
 #endif
 		else {
+			mdp4_overlay_reg_flush_reset(pipe);
 			/* mddi & mipi dsi cmd mode */
 			if (pipe->flags & MDP_OV_PLAY_NOWAIT) {
 				mdp4_stat.overlay_play[pipe->mixer_num]++;
@@ -3107,7 +3292,7 @@
 		return err;
 	}
 
-	mdp4_mixer_blend_setup(pipe);
+	mdp4_mixer_blend_setup(pipe->mixer_num);
 	*ppipe = pipe;
 
 	return 0;
diff --git a/drivers/video/msm/mdp4_overlay_dsi_cmd.c b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
index a5b4b3e..7ba4e75 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_cmd.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
@@ -114,6 +114,11 @@
 	}
 }
 
+void mdp4_dsi_cmd_base_swap(struct mdp4_overlay_pipe *pipe)
+{
+	dsi_pipe = pipe;
+}
+
 void mdp4_overlay_update_dsi_cmd(struct msm_fb_data_type *mfd)
 {
 	MDPIBUF *iBuf = &mfd->ibuf;
@@ -162,6 +167,14 @@
 	} else {
 		pipe = dsi_pipe;
 	}
+
+	if (pipe->pipe_used == 0 ||
+			pipe->mixer_stage != MDP4_MIXER_STAGE_BASE) {
+		pr_err("%s: NOT baselayer\n", __func__);
+		mutex_unlock(&mfd->dma->ov_mutex);
+		return;
+	}
+
 	/*
 	 * configure dsi stream id
 	 * dma_p = 0, dma_s = 1
@@ -207,6 +220,8 @@
 
 	mdp4_overlay_rgb_setup(pipe);
 
+	mdp4_overlay_reg_flush(pipe, 1);
+
 	mdp4_mixer_stage_up(pipe);
 
 	mdp4_overlayproc_cfg(pipe);
@@ -240,6 +255,12 @@
 	dsi_pipe->src_width_3d = r3d->width;
 
 	pipe = dsi_pipe;
+	if (pipe->pipe_used == 0 ||
+			pipe->mixer_stage != MDP4_MIXER_STAGE_BASE) {
+		pr_err("%s: NOT baselayer\n", __func__);
+		mutex_unlock(&mfd->dma->ov_mutex);
+		return;
+	}
 
 	if (pipe->is_3d)
 		mdp4_overlay_panel_3d(pipe->mixer_num, MDP4_3D_SIDE_BY_SIDE);
@@ -282,6 +303,8 @@
 
 	mdp4_overlay_rgb_setup(pipe);
 
+	mdp4_overlay_reg_flush(pipe, 1);
+
 	mdp4_mixer_stage_up(pipe);
 
 	mdp4_overlayproc_cfg(pipe);
@@ -651,12 +674,22 @@
 	mdp4_stat.kickoff_ov0++;
 }
 
-void mdp_dsi_cmd_overlay_suspend(void)
+void mdp_dsi_cmd_overlay_suspend(struct msm_fb_data_type *mfd)
 {
 	/* dis-engage rgb0 from mixer0 */
 	if (dsi_pipe) {
-		mdp4_mixer_stage_down(dsi_pipe);
-		mdp4_iommu_unmap(dsi_pipe);
+		if (mfd->ref_cnt == 0) {
+			/* adb stop */
+			if (dsi_pipe->pipe_type == OVERLAY_TYPE_BF)
+				mdp4_overlay_borderfill_stage_down(dsi_pipe);
+
+			/* dsi_pipe == rgb1 */
+			mdp4_overlay_unset_mixer(dsi_pipe->mixer_num);
+			dsi_pipe = NULL;
+		} else {
+			mdp4_mixer_stage_down(dsi_pipe);
+			mdp4_iommu_unmap(dsi_pipe);
+		}
 	}
 }
 
diff --git a/drivers/video/msm/mdp4_overlay_dsi_video.c b/drivers/video/msm/mdp4_overlay_dsi_video.c
index 574a657..47e6432 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_video.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_video.c
@@ -72,6 +72,11 @@
 static void mdp4_overlay_dsi_video_wait4event(struct msm_fb_data_type *mfd,
 						int intr_done);
 
+void mdp4_dsi_video_base_swap(struct mdp4_overlay_pipe *pipe)
+{
+	dsi_pipe = pipe;
+}
+
 int mdp4_dsi_video_on(struct platform_device *pdev)
 {
 	int dsi_width;
@@ -121,8 +126,6 @@
 	if (mfd->key != MFD_KEY)
 		return -EINVAL;
 
-	mdp4_overlay_ctrl_db_reset();
-
 	fbi = mfd->fbi;
 	var = &fbi->var;
 
@@ -195,8 +198,9 @@
 
 	mdp4_overlay_dmap_xy(pipe);	/* dma_p */
 	mdp4_overlay_dmap_cfg(mfd, 1);
-
 	mdp4_overlay_rgb_setup(pipe);
+	mdp4_overlay_reg_flush(pipe, 1);
+	mdp4_mixer_stage_up(pipe);
 
 	mdp4_overlayproc_cfg(pipe);
 
@@ -294,10 +298,12 @@
 int mdp4_dsi_video_off(struct platform_device *pdev)
 {
 	int ret = 0;
+	struct msm_fb_data_type *mfd;
+
+	mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
 
 	/* MDP cmd block enable */
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	mdp4_mixer_pipe_cleanup(dsi_pipe->mixer_num);
 	MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE, 0);
 	dsi_video_enabled = 0;
 	/* MDP cmd block disable */
@@ -311,8 +317,18 @@
 
 	/* dis-engage rgb0 from mixer0 */
 	if (dsi_pipe) {
-		mdp4_mixer_stage_down(dsi_pipe);
-		mdp4_iommu_unmap(dsi_pipe);
+		if (mfd->ref_cnt == 0) {
+			/* adb stop */
+			if (dsi_pipe->pipe_type == OVERLAY_TYPE_BF)
+				mdp4_overlay_borderfill_stage_down(dsi_pipe);
+
+			/* dsi_pipe == rgb1 */
+			mdp4_overlay_unset_mixer(dsi_pipe->mixer_num);
+			dsi_pipe = NULL;
+		} else {
+			mdp4_mixer_stage_down(dsi_pipe);
+			mdp4_iommu_unmap(dsi_pipe);
+		}
 	}
 
 	return ret;
@@ -387,7 +403,6 @@
 	mdp4_overlay_dmap_cfg(mfd, 1);
 
 	mdp4_overlay_reg_flush(pipe, 1);
-
 	mdp4_mixer_stage_up(pipe);
 
 	mb();
@@ -740,7 +755,6 @@
 
 	spin_unlock_irqrestore(&mdp_spin_lock, flag);
 
-
 	/*
 	 * may need mutex here to sync with whom dsiable
 	 * timing generator
@@ -801,6 +815,12 @@
 	mutex_lock(&mfd->dma->ov_mutex);
 
 	pipe = dsi_pipe;
+	if (pipe->pipe_used == 0 ||
+			pipe->mixer_stage != MDP4_MIXER_STAGE_BASE) {
+		pr_err("%s: NOT baselayer\n", __func__);
+		mutex_unlock(&mfd->dma->ov_mutex);
+		return;
+	}
 
 	if (mfd->display_iova)
 		pipe->srcp0_addr = mfd->display_iova + buf_offset;
@@ -808,7 +828,7 @@
 		pipe->srcp0_addr = (uint32)(buf + buf_offset);
 
 	mdp4_overlay_rgb_setup(pipe);
-	mdp4_overlay_reg_flush(pipe, 0);
+	mdp4_overlay_reg_flush(pipe, 1);
 	mdp4_mixer_stage_up(pipe);
 	mdp4_overlay_dsi_video_start();
 	mdp4_overlay_dsi_video_vsync_push(mfd, pipe);
diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c
index dd96439..c57bd64 100644
--- a/drivers/video/msm/mdp4_overlay_dtv.c
+++ b/drivers/video/msm/mdp4_overlay_dtv.c
@@ -56,6 +56,12 @@
 static struct mdp4_overlay_pipe *dtv_pipe;
 static DECLARE_COMPLETION(dtv_comp);
 
+void mdp4_dtv_base_swap(struct mdp4_overlay_pipe *pipe)
+{
+	if (hdmi_prim_display)
+		dtv_pipe = pipe;
+}
+
 static int mdp4_dtv_start(struct msm_fb_data_type *mfd)
 {
 	int dtv_width;
@@ -208,7 +214,6 @@
 
 	/* MDP cmd block enable */
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	mdp4_mixer_pipe_cleanup(dtv_pipe->mixer_num);
 	msleep(20);
 	MDP_OUTP(MDP_BASE + DTV_BASE, 0);
 	dtv_enabled = 0;
@@ -262,14 +267,20 @@
 
 	if (dtv_pipe != NULL) {
 		mdp4_dtv_stop(mfd);
+		if (hdmi_prim_display && mfd->ref_cnt == 0) {
+			/* adb stop */
+			if (dtv_pipe->pipe_type == OVERLAY_TYPE_BF)
+				mdp4_overlay_borderfill_stage_down(dtv_pipe);
 
-		/* delay to make sure the last frame finishes */
-		msleep(20);
-
-		mdp4_mixer_stage_down(dtv_pipe);
-		mdp4_overlay_pipe_free(dtv_pipe);
-		mdp4_iommu_unmap(dtv_pipe);
-		dtv_pipe = NULL;
+			/* dtv_pipe == rgb1 */
+			mdp4_overlay_unset_mixer(dtv_pipe->mixer_num);
+			dtv_pipe = NULL;
+		} else {
+			mdp4_mixer_stage_down(dtv_pipe);
+			mdp4_overlay_pipe_free(dtv_pipe);
+			mdp4_iommu_unmap(dtv_pipe);
+			dtv_pipe = NULL;
+		}
 	}
 	mdp4_overlay_panel_mode_unset(MDP4_MIXER1, MDP4_PANEL_DTV);
 
@@ -610,7 +621,8 @@
 	*/
 	temp_src_format = inpdw(rgb_base + 0x0050);
 	MDP_OUTP(rgb_base + 0x0050, temp_src_format | BIT(22));
-	mdp4_overlay_reg_flush(dtv_pipe, 0);
+	mdp4_overlay_reg_flush(dtv_pipe, 1);
+	mdp4_mixer_stage_up(dtv_pipe);
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 }
 
@@ -696,11 +708,19 @@
 	}
 	mutex_lock(&mfd->dma->ov_mutex);
 	pipe = dtv_pipe;
+
+	if (hdmi_prim_display && (pipe->pipe_used == 0 ||
+			pipe->mixer_stage != MDP4_MIXER_STAGE_BASE)) {
+		pr_err("%s: NOT baselayer\n", __func__);
+		mutex_unlock(&mfd->dma->ov_mutex);
+		return;
+	}
+
 	if (pipe->pipe_type == OVERLAY_TYPE_RGB) {
 		pipe->srcp0_addr = (uint32) mfd->ibuf.buf;
 		mdp4_overlay_rgb_setup(pipe);
 	}
-	mdp4_overlay_reg_flush(pipe, 0);
+	mdp4_overlay_reg_flush(pipe, 1);
 	mdp4_mixer_stage_up(pipe);
 	mdp4_overlay_dtv_start();
 	mdp4_overlay_dtv_ov_done_push(mfd, pipe);
diff --git a/drivers/video/msm/mdp4_overlay_lcdc.c b/drivers/video/msm/mdp4_overlay_lcdc.c
index a1fecb6..18d2107 100644
--- a/drivers/video/msm/mdp4_overlay_lcdc.c
+++ b/drivers/video/msm/mdp4_overlay_lcdc.c
@@ -46,6 +46,11 @@
 static struct mdp4_overlay_pipe *lcdc_pipe;
 static struct completion lcdc_comp;
 
+void mdp4_lcdc_base_swap(struct mdp4_overlay_pipe *pipe)
+{
+	lcdc_pipe = pipe;
+}
+
 int mdp_lcdc_on(struct platform_device *pdev)
 {
 	int lcdc_width;
@@ -95,8 +100,6 @@
 	if (mfd->key != MFD_KEY)
 		return -EINVAL;
 
-	mdp4_overlay_ctrl_db_reset();
-
 	fbi = mfd->fbi;
 	var = &fbi->var;
 
@@ -155,6 +158,8 @@
 	mdp4_overlay_dmap_cfg(mfd, 1);
 
 	mdp4_overlay_rgb_setup(pipe);
+	mdp4_overlay_reg_flush(pipe, 1);
+	mdp4_mixer_stage_up(pipe);
 
 	mdp4_overlayproc_cfg(pipe);
 
@@ -263,7 +268,6 @@
 
 	/* MDP cmd block enable */
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	mdp4_mixer_pipe_cleanup(lcdc_pipe->mixer_num);
 	MDP_OUTP(MDP_BASE + LCDC_BASE, 0);
 	lcdc_enabled = 0;
 	/* MDP cmd block disable */
@@ -280,8 +284,18 @@
 
 	/* dis-engage rgb0 from mixer0 */
 	if (lcdc_pipe) {
-		mdp4_mixer_stage_down(lcdc_pipe);
-		mdp4_iommu_unmap(lcdc_pipe);
+		if (mfd->ref_cnt == 0) {
+			/* adb stop */
+			if (lcdc_pipe->pipe_type == OVERLAY_TYPE_BF)
+				mdp4_overlay_borderfill_stage_down(lcdc_pipe);
+
+			/* lcdc_pipe == rgb1 */
+			mdp4_overlay_unset_mixer(lcdc_pipe->mixer_num);
+			lcdc_pipe = NULL;
+		} else {
+			mdp4_mixer_stage_down(lcdc_pipe);
+			mdp4_iommu_unmap(lcdc_pipe);
+		}
 	}
 
 #ifdef CONFIG_MSM_BUS_SCALING
@@ -494,7 +508,7 @@
 	}
 }
 /*
- * make sure the MIPI_DSI_WRITEBACK_SIZE defined at boardfile
+ * make sure the WRITEBACK_SIZE defined at boardfile
  * has enough space h * w * 3 * 2
  */
 static void mdp4_lcdc_do_blt(struct msm_fb_data_type *mfd, int enable)
@@ -585,6 +599,12 @@
 	mutex_lock(&mfd->dma->ov_mutex);
 
 	pipe = lcdc_pipe;
+	if (pipe->pipe_used == 0 ||
+			pipe->mixer_stage != MDP4_MIXER_STAGE_BASE) {
+		pr_err("%s: NOT baselayer\n", __func__);
+		mutex_unlock(&mfd->dma->ov_mutex);
+		return;
+	}
 
 	if (mfd->display_iova)
 		pipe->srcp0_addr = mfd->display_iova + buf_offset;
@@ -592,7 +612,7 @@
 		pipe->srcp0_addr = (uint32)(buf + buf_offset);
 
 	mdp4_overlay_rgb_setup(pipe);
-	mdp4_overlay_reg_flush(pipe, 0);
+	mdp4_overlay_reg_flush(pipe, 1);
 	mdp4_mixer_stage_up(pipe);
 	mdp4_overlay_lcdc_start();
 	mdp4_overlay_lcdc_vsync_push(mfd, pipe);
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index 82fbb65..f192b12 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -314,6 +314,8 @@
 	clk_rate = mdp_get_core_clk();
 	mdp4_fetch_cfg(clk_rate);
 
+	mdp4_overlay_cfg_init();
+
 	/* Mark hardware as initialized. Only revisions > v2.1 have a register
 	 * for tracking core reset status. */
 	if (mdp_hw_revision > MDP4_REVISION_V2_1)
@@ -378,6 +380,7 @@
 	outpdw(MDP_INTR_CLEAR, isr);
 
 	if (isr & INTR_PRIMARY_INTF_UDERRUN) {
+		pr_debug("%s: UNDERRUN -- primary\n", __func__);
 		mdp4_stat.intr_underrun_p++;
 		/* When underun occurs mdp clear the histogram registers
 		that are set before in hw_init so restore them back so
@@ -395,8 +398,10 @@
 		}
 	}
 
-	if (isr & INTR_EXTERNAL_INTF_UDERRUN)
+	if (isr & INTR_EXTERNAL_INTF_UDERRUN) {
+		pr_debug("%s: UNDERRUN -- external\n", __func__);
 		mdp4_stat.intr_underrun_e++;
+	}
 
 	isr &= mask;
 
diff --git a/drivers/video/msm/mdp_debugfs.c b/drivers/video/msm/mdp_debugfs.c
index 7defd82..4a0ea4c 100644
--- a/drivers/video/msm/mdp_debugfs.c
+++ b/drivers/video/msm/mdp_debugfs.c
@@ -437,38 +437,38 @@
 	len = snprintf(bp, dlen, "frame_push:\n");
 	bp += len;
 	dlen -= len;
-	len = snprintf(bp, dlen, "rgb1:  %08lu\t\t",
+	len = snprintf(bp, dlen, "rgb1:   %08lu\t",
 		       mdp4_stat.pipe[OVERLAY_PIPE_RGB1]);
 	bp += len;
 	dlen -= len;
-	len = snprintf(bp, dlen, "rgb2:  %08lu\n",
+	len = snprintf(bp, dlen, "rgb2:   %08lu\n",
 		       mdp4_stat.pipe[OVERLAY_PIPE_RGB2]);
 	bp += len;
 	dlen -= len;
-	len = snprintf(bp, dlen, "vg1:   %08lu\t\t",
+	len = snprintf(bp, dlen, "vg1 :   %08lu\t",
 		       mdp4_stat.pipe[OVERLAY_PIPE_VG1]);
 	bp += len;
 	dlen -= len;
-	len = snprintf(bp, dlen, "vg2:   %08lu\n",
+	len = snprintf(bp, dlen, "vg2 :   %08lu\n",
 		       mdp4_stat.pipe[OVERLAY_PIPE_VG2]);
 	bp += len;
 	dlen -= len;
-	len = snprintf(bp, dlen, "err_mixer: %08lu\t", mdp4_stat.err_mixer);
+	len = snprintf(bp, dlen, "err_mixer : %08lu\t", mdp4_stat.err_mixer);
 	bp += len;
 	dlen -= len;
-	len = snprintf(bp, dlen, "err_size : %08lu\n", mdp4_stat.err_size);
+	len = snprintf(bp, dlen, "err_size  : %08lu\n", mdp4_stat.err_size);
 	bp += len;
 	dlen -= len;
-	len = snprintf(bp, dlen, "err_scale: %08lu\t", mdp4_stat.err_scale);
+	len = snprintf(bp, dlen, "err_scale : %08lu\t", mdp4_stat.err_scale);
 	bp += len;
 	dlen -= len;
 	len = snprintf(bp, dlen, "err_format: %08lu\n", mdp4_stat.err_format);
 	bp += len;
 	dlen -= len;
-	len = snprintf(bp, dlen, "err_play:  %08lu\t", mdp4_stat.err_play);
+	len = snprintf(bp, dlen, "err_play  : %08lu\t", mdp4_stat.err_play);
 	bp += len;
 	dlen -= len;
-	len = snprintf(bp, dlen, "err_stage: %08lu\n", mdp4_stat.err_stage);
+	len = snprintf(bp, dlen, "err_stage : %08lu\n", mdp4_stat.err_stage);
 	bp += len;
 	dlen -= len;
 	len = snprintf(bp, dlen, "err_underflow: %08lu\n\n",
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index a0af4b5..f757fae 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -99,6 +99,7 @@
 	MDP_YCRCB_H1V1,   /* YCrCb interleave */
 	MDP_YCBCR_H1V1,   /* YCbCr interleave */
 	MDP_IMGTYPE_LIMIT,
+	MDP_RGB_BORDERFILL,	/* border fill pipe */
 	MDP_BGR_565 = MDP_IMGTYPE2_START,      /* BGR 565 planer */
 	MDP_FB_FORMAT,    /* framebuffer format */
 	MDP_IMGTYPE_LIMIT2 /* Non valid image type after this enum */