Merge "msm_fb: display: add mdp overlay1 writeback" into msm-3.0
diff --git a/drivers/video/msm/Kconfig b/drivers/video/msm/Kconfig
index de6bf1a..448194a 100644
--- a/drivers/video/msm/Kconfig
+++ b/drivers/video/msm/Kconfig
@@ -301,6 +301,13 @@
---help---
Support for MDP4 OVERLAY0 write back mode
+
+config FB_MSM_OVERLAY1_WRITEBACK
+ depends on FB_MSM_OVERLAY
+ bool "MDP overlay1 write back mode enable"
+ ---help---
+ Support for MDP4 OVERLAY1 write back mode
+
config FB_MSM_WRITEBACK_MSM_PANEL
depends on FB_MSM_OVERLAY
bool "MDP overlay write back panel enable"
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index 1a4ce91..7b5f464 100644
--- a/drivers/video/msm/mdp4.h
+++ b/drivers/video/msm/mdp4.h
@@ -320,6 +320,7 @@
uint32 blt_cnt;
uint32 ov_cnt;
uint32 dmap_cnt;
+ uint32 dmae_cnt;
uint32 blt_end;
uint32 luma_align_size;
struct mdp4_hsic_regs hsic_regs;
@@ -409,8 +410,6 @@
uint32 mdp4_overlay_op_mode(struct mdp4_overlay_pipe *pipe);
void mdp4_lcdc_overlay(struct msm_fb_data_type *mfd);
#ifdef CONFIG_FB_MSM_DTV
-void mdp4_overlay_dtv_vsync_push(struct msm_fb_data_type *mfd,
- struct mdp4_overlay_pipe *pipe);
void mdp4_overlay_dtv_ov_done_push(struct msm_fb_data_type *mfd,
struct mdp4_overlay_pipe *pipe);
void mdp4_overlay_dtv_wait_for_ov(struct msm_fb_data_type *mfd,
@@ -420,11 +419,6 @@
int mdp4_overlay_dtv_unset(struct msm_fb_data_type *mfd,
struct mdp4_overlay_pipe *pipe);
#else
-static inline void mdp4_overlay_dtv_vsync_push(struct msm_fb_data_type *mfd,
- struct mdp4_overlay_pipe *pipe)
-{
- /* empty */
-}
static inline void mdp4_overlay_dtv_ov_done_push(struct msm_fb_data_type *mfd,
struct mdp4_overlay_pipe *pipe)
{
@@ -612,6 +606,8 @@
struct msmfb_overlay_blt *req);
void mdp4_lcdc_overlay_blt_start(struct msm_fb_data_type *mfd);
void mdp4_lcdc_overlay_blt_stop(struct msm_fb_data_type *mfd);
+void mdp4_dtv_overlay_blt_start(struct msm_fb_data_type *mfd);
+void mdp4_dtv_overlay_blt_stop(struct msm_fb_data_type *mfd);
int mdp4_mddi_overlay_blt_offset(int *off);
void mdp4_mddi_overlay_blt(ulong addr);
@@ -687,6 +683,7 @@
struct mdp4_overlay_pipe *pipe);
void mdp4_writeback_dma_busy_wait(struct msm_fb_data_type *mfd);
void mdp4_overlay1_done_writeback(struct mdp_dma_data *dma);
+void mdp4_dma_e_done_dtv(void);
int mdp4_writeback_start(struct fb_info *info);
int mdp4_writeback_stop(struct fb_info *info);
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index ecb0a24..1fd0766 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -239,13 +239,27 @@
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- /* dma_p source */
MDP_OUTP(MDP_BASE + 0xb0004,
(pipe->src_height << 16 | pipe->src_width));
- MDP_OUTP(MDP_BASE + 0xb0008, pipe->srcp0_addr);
- MDP_OUTP(MDP_BASE + 0xb000c, pipe->srcp0_ystride);
-
- /* dma_p dest */
+ if (pipe->blt_addr) {
+ uint32 off, bpp;
+#ifdef BLT_RGB565
+ bpp = 2; /* overlay ouput is RGB565 */
+#else
+ bpp = 3; /* overlay ouput is RGB888 */
+#endif
+ off = 0;
+ if (pipe->ov_cnt & 0x01)
+ off = pipe->src_height * pipe->src_width * bpp;
+ MDP_OUTP(MDP_BASE + 0xb0008, pipe->blt_addr + off);
+ /* RGB888, output of overlay blending */
+ MDP_OUTP(MDP_BASE + 0xb000c, pipe->src_width * bpp);
+ } else {
+ /* dma_e source */
+ MDP_OUTP(MDP_BASE + 0xb0008, pipe->srcp0_addr);
+ MDP_OUTP(MDP_BASE + 0xb000c, pipe->srcp0_ystride);
+ }
+ /* dma_e dest */
MDP_OUTP(MDP_BASE + 0xb0010, (pipe->dst_y << 16 | pipe->dst_x));
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
@@ -1114,7 +1128,7 @@
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
/*
- * BLT only siupport at primary display
+ * BLT support both primary and external external
*/
if (pipe->blt_addr) {
int off, bpp;
@@ -1127,7 +1141,8 @@
data <<= 16;
data |= pipe->src_width;
outpdw(overlay_base + 0x0008, data); /* ROI, height + width */
- if (pipe->mixer_num == MDP4_MIXER0) {
+ if (pipe->mixer_num == MDP4_MIXER0 ||
+ pipe->mixer_num == MDP4_MIXER1) {
off = 0;
if (pipe->ov_cnt & 0x01)
off = pipe->src_height * pipe->src_width * bpp;
diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c
index f2065fd..f454d89 100644
--- a/drivers/video/msm/mdp4_overlay_dtv.c
+++ b/drivers/video/msm/mdp4_overlay_dtv.c
@@ -264,36 +264,6 @@
return ret;
}
-static void mdp4_overlay_dtv_wait4vsync(struct msm_fb_data_type *mfd)
-{
- unsigned long flag;
-
- /* enable irq */
- spin_lock_irqsave(&mdp_spin_lock, flag);
- mdp_enable_irq(MDP_OVERLAY1_TERM);
- INIT_COMPLETION(dtv_pipe->comp);
- mfd->dma->waiting = TRUE;
- outp32(MDP_INTR_CLEAR, INTR_EXTERNAL_VSYNC);
- mdp_intr_mask |= INTR_EXTERNAL_VSYNC;
- outp32(MDP_INTR_ENABLE, mdp_intr_mask);
- spin_unlock_irqrestore(&mdp_spin_lock, flag);
- wait_for_completion_killable(&dtv_pipe->comp);
- mdp_disable_irq(MDP_OVERLAY1_TERM);
-}
-
-void mdp4_overlay_dtv_vsync_push(struct msm_fb_data_type *mfd,
- struct mdp4_overlay_pipe *pipe)
-{
- mdp4_overlay_reg_flush(pipe, 1);
- if (pipe->flags & MDP_OV_PLAY_NOWAIT)
- return;
-
- mdp4_overlay_dtv_wait4vsync(mfd);
-
- /* change mdp clk while mdp is idle` */
- mdp4_set_perf_level();
-}
-
static void mdp4_overlay_dtv_alloc_pipe(struct msm_fb_data_type *mfd,
int32 ptype)
{
@@ -406,6 +376,54 @@
return result;
}
+static void mdp4_dtv_blt_ov_update(struct mdp4_overlay_pipe *pipe)
+{
+ uint32 off, addr;
+ int bpp;
+ char *overlay_base;
+
+ if (pipe->blt_addr == 0)
+ return;
+#ifdef BLT_RGB565
+ bpp = 2; /* overlay ouput is RGB565 */
+#else
+ bpp = 3; /* overlay ouput is RGB888 */
+#endif
+ off = (pipe->ov_cnt & 0x01) ?
+ pipe->src_height * pipe->src_width * bpp : 0;
+
+ addr = pipe->blt_addr + off;
+ pr_debug("%s overlay addr 0x%x\n", __func__, addr);
+ /* overlay 1 */
+ overlay_base = MDP_BASE + MDP4_OVERLAYPROC1_BASE;/* 0x18000 */
+ outpdw(overlay_base + 0x000c, addr);
+ outpdw(overlay_base + 0x001c, addr);
+}
+
+static inline void mdp4_dtv_blt_dmae_update(struct mdp4_overlay_pipe *pipe)
+{
+ uint32 off, addr;
+ int bpp;
+
+ if (pipe->blt_addr == 0)
+ return;
+
+#ifdef BLT_RGB565
+ bpp = 2; /* overlay ouput is RGB565 */
+#else
+ bpp = 3; /* overlay ouput is RGB888 */
+#endif
+ off = (pipe->dmae_cnt & 0x01) ?
+ pipe->src_height * pipe->src_width * bpp : 0;
+ addr = pipe->blt_addr + off;
+ MDP_OUTP(MDP_BASE + 0xb0008, addr);
+}
+
+static inline void mdp4_overlay_dtv_ov_kick_start(void)
+{
+ outpdw(MDP_BASE + 0x0008, 0);
+}
+
static void mdp4_overlay_dtv_ov_start(struct msm_fb_data_type *mfd)
{
unsigned long flag;
@@ -414,6 +432,12 @@
if (mfd->ov_start)
return;
+ if (dtv_pipe->blt_addr) {
+ mdp4_dtv_blt_ov_update(dtv_pipe);
+ dtv_pipe->ov_cnt++;
+ mdp4_overlay_dtv_ov_kick_start();
+ }
+
spin_lock_irqsave(&mdp_spin_lock, flag);
mdp_enable_irq(MDP_OVERLAY1_TERM);
INIT_COMPLETION(dtv_pipe->comp);
@@ -444,6 +468,7 @@
void mdp4_overlay_dtv_ov_done_push(struct msm_fb_data_type *mfd,
struct mdp4_overlay_pipe *pipe)
{
+
mdp4_overlay_reg_flush(pipe, 1);
mdp4_overlay_dtv_ov_start(mfd);
@@ -463,6 +488,11 @@
mdp4_set_perf_level();
}
+void mdp4_dma_e_done_dtv()
+{
+ complete(&dtv_pipe->comp);
+}
+
void mdp4_external_vsync_dtv()
{
complete_all(&dtv_pipe->comp);
@@ -473,6 +503,10 @@
*/
void mdp4_overlay1_done_dtv()
{
+ if (dtv_pipe->blt_addr) {
+ mdp4_dtv_blt_dmae_update(dtv_pipe);
+ dtv_pipe->dmae_cnt++;
+ }
complete_all(&dtv_pipe->comp);
}
@@ -506,6 +540,70 @@
}
#endif
+static void mdp4_overlay_dtv_wait4dmae(struct msm_fb_data_type *mfd)
+{
+ unsigned long flag;
+
+ /* enable irq */
+ spin_lock_irqsave(&mdp_spin_lock, flag);
+ mdp_enable_irq(MDP_DMA_E_TERM);
+ INIT_COMPLETION(dtv_pipe->comp);
+ mfd->dma->waiting = TRUE;
+ outp32(MDP_INTR_CLEAR, INTR_DMA_E_DONE);
+ mdp_intr_mask |= INTR_DMA_E_DONE;
+ outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+ spin_unlock_irqrestore(&mdp_spin_lock, flag);
+ wait_for_completion_killable(&dtv_pipe->comp);
+ mdp_disable_irq(MDP_DMA_E_TERM);
+}
+
+static void mdp4_dtv_do_blt(struct msm_fb_data_type *mfd, int enable)
+{
+ unsigned long flag;
+ int change = 0;
+
+ if (!mfd->ov1_wb_buf->phys_addr) {
+ pr_debug("%s: no writeback buf assigned\n", __func__);
+ return;
+ }
+
+ spin_lock_irqsave(&mdp_spin_lock, flag);
+ if (enable && dtv_pipe->blt_addr == 0) {
+ dtv_pipe->blt_addr = mfd->ov1_wb_buf->phys_addr;
+ change++;
+ dtv_pipe->ov_cnt = 0;
+ dtv_pipe->dmae_cnt = 0;
+ } else if (enable == 0 && dtv_pipe->blt_addr) {
+ dtv_pipe->blt_addr = 0;
+ change++;
+ }
+ pr_debug("%s: blt_addr=%x\n", __func__, (int)dtv_pipe->blt_addr);
+ spin_unlock_irqrestore(&mdp_spin_lock, flag);
+
+ if (!change)
+ return;
+
+ mdp4_overlay_dtv_wait4dmae(mfd);
+
+ MDP_OUTP(MDP_BASE + DTV_BASE, 0); /* stop dtv */
+ msleep(20);
+ mdp4_overlayproc_cfg(dtv_pipe);
+ mdp4_overlay_dmae_xy(dtv_pipe);
+ MDP_OUTP(MDP_BASE + DTV_BASE, 1); /* start dtv */
+}
+
+void mdp4_dtv_overlay_blt_start(struct msm_fb_data_type *mfd)
+{
+ mdp4_allocate_writeback_buf(mfd, MDP4_MIXER1);
+ mdp4_dtv_do_blt(mfd, 1);
+}
+
+void mdp4_dtv_overlay_blt_stop(struct msm_fb_data_type *mfd)
+{
+ mdp4_free_writeback_buf(mfd, MDP4_MIXER1);
+ mdp4_dtv_do_blt(mfd, 0);
+}
+
void mdp4_dtv_overlay(struct msm_fb_data_type *mfd)
{
struct mdp4_overlay_pipe *pipe;
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index bd8ec55..ba6c746 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -554,7 +554,7 @@
mdp_intr_mask &= ~INTR_DMA_E_DONE;
outp32(MDP_INTR_ENABLE, mdp_intr_mask);
dma->busy = FALSE;
-
+ mdp4_dma_e_done_dtv();
if (dma->waiting) {
dma->waiting = FALSE;
complete(&dma->comp);