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 */