diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c index 70c65d21fe4..a7685b4006b 100644 --- a/drivers/video/msm/mdp.c +++ b/drivers/video/msm/mdp.c @@ -1321,34 +1321,6 @@ static void send_vsync_work(struct work_struct *work) kobject_uevent_env(&(vsync_cntrl.dev->kobj), KOBJ_CHANGE, envp); } -void mdp3_vsync_irq_enable(int intr, int term) -{ - unsigned long flag; - - spin_lock_irqsave(&mdp_spin_lock, flag); - outp32(MDP_INTR_CLEAR, intr); - mdp_intr_mask |= intr; - outp32(MDP_INTR_ENABLE, mdp_intr_mask); - mdp_enable_irq(term); - spin_unlock_irqrestore(&mdp_spin_lock, flag); -} - -void mdp3_vsync_irq_disable(int intr, int term) -{ - unsigned long flag; - - spin_lock_irqsave(&mdp_spin_lock, flag); - /* required to synchronize between frame update and vsync - * since both use the same LCDC_FRAME_START interrupt - */ - if (intr == LCDC_FRAME_START && dma2_data.waiting == FALSE) { - mdp_intr_mask &= ~intr; - outp32(MDP_INTR_ENABLE, mdp_intr_mask); - } - mdp_disable_irq(term); - spin_unlock_irqrestore(&mdp_spin_lock, flag); -} - #ifdef CONFIG_FB_MSM_MDP303 /* vsync_isr_handler: Called from isr context*/ static void vsync_isr_handler(void) @@ -1806,6 +1778,7 @@ irqreturn_t mdp_isr(int irq, void *ptr) struct mdp_hist_mgmt *mgmt = NULL; char *base_addr; int i, ret; + int vsync_isr; /* Ensure all the register write are complete */ mb(); @@ -1825,8 +1798,23 @@ irqreturn_t mdp_isr(int irq, void *ptr) goto out; /*Primary Vsync interrupt*/ - if (mdp_interrupt & MDP_PRIM_RDPTR) - vsync_isr_handler(); + if (mdp_interrupt & MDP_PRIM_RDPTR) { + spin_lock_irqsave(&mdp_spin_lock, flag); + vsync_isr = vsync_cntrl.vsync_irq_enabled; + if (!vsync_isr) { + mdp_intr_mask &= ~MDP_PRIM_RDPTR; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + } + spin_unlock_irqrestore(&mdp_spin_lock, flag); + + if (vsync_isr) { + vsync_isr_handler(); + } else { + mdp_pipe_ctrl(MDP_CMD_BLOCK, + MDP_BLOCK_POWER_OFF, TRUE); + complete(&vsync_cntrl.vsync_wait); + } + } /* DMA3 TV-Out Start */ if (mdp_interrupt & TV_OUT_DMA3_START) { @@ -1874,21 +1862,26 @@ irqreturn_t mdp_isr(int irq, void *ptr) if (mdp_interrupt & LCDC_FRAME_START) { dma = &dma2_data; spin_lock_irqsave(&mdp_spin_lock, flag); + vsync_isr = vsync_cntrl.vsync_irq_enabled; /* let's disable LCDC interrupt */ if (dma->waiting) { dma->waiting = FALSE; complete(&dma->comp); } - if (vsync_cntrl.vsync_irq_enabled) - vsync_isr_handler(); - - if (!vsync_cntrl.vsync_irq_enabled && !(dma->waiting)) { + if (!vsync_isr) { mdp_intr_mask &= ~LCDC_FRAME_START; outp32(MDP_INTR_ENABLE, mdp_intr_mask); } - spin_unlock_irqrestore(&mdp_spin_lock, flag); + + if (vsync_isr) { + vsync_isr_handler(); + } else { + mdp_pipe_ctrl(MDP_CMD_BLOCK, + MDP_BLOCK_POWER_OFF, TRUE); + complete(&vsync_cntrl.vsync_wait); + } } /* DMA2 LCD-Out Complete */ @@ -2019,6 +2012,7 @@ static void mdp_drv_init(void) atomic_set(&mdp_block_power_cnt[i], 0); } INIT_WORK(&(vsync_cntrl.vsync_work), send_vsync_work); + init_completion(&vsync_cntrl.vsync_wait); #ifdef MSM_FB_ENABLE_DBGFS { struct dentry *root; diff --git a/drivers/video/msm/mdp.h b/drivers/video/msm/mdp.h index 8920b4d5c93..965f819722d 100644 --- a/drivers/video/msm/mdp.h +++ b/drivers/video/msm/mdp.h @@ -96,6 +96,7 @@ struct vsync { struct device *dev; struct work_struct vsync_work; int vsync_irq_enabled; + struct completion vsync_wait; }; extern struct vsync vsync_cntrl; @@ -829,8 +830,6 @@ static inline int mdp_bus_scale_update_request(uint32_t index) void mdp_dma_vsync_ctrl(int enable); void mdp_dma_video_vsync_ctrl(int enable); void mdp_dma_lcdc_vsync_ctrl(int enable); -void mdp3_vsync_irq_enable(int intr, int term); -void mdp3_vsync_irq_disable(int intr, int term); #ifdef MDP_HW_VSYNC void vsync_clk_prepare_enable(void); diff --git a/drivers/video/msm/mdp_dma.c b/drivers/video/msm/mdp_dma.c index a506648ac90..df57ee1e6ee 100644 --- a/drivers/video/msm/mdp_dma.c +++ b/drivers/video/msm/mdp_dma.c @@ -514,18 +514,27 @@ void mdp_dma2_update(struct msm_fb_data_type *mfd) void mdp_dma_vsync_ctrl(int enable) { + unsigned long flag; if (vsync_cntrl.vsync_irq_enabled == enable) return; + spin_lock_irqsave(&mdp_spin_lock, flag); vsync_cntrl.vsync_irq_enabled = enable; + spin_unlock_irqrestore(&mdp_spin_lock, flag); if (enable) { mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); MDP_OUTP(MDP_BASE + 0x021c, 0x10); /* read pointer */ - mdp3_vsync_irq_enable(MDP_PRIM_RDPTR, MDP_VSYNC_TERM); + spin_lock_irqsave(&mdp_spin_lock, flag); + outp32(MDP_INTR_CLEAR, MDP_PRIM_RDPTR); + mdp_intr_mask |= MDP_PRIM_RDPTR; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + mdp_enable_irq(MDP_VSYNC_TERM); + spin_unlock_irqrestore(&mdp_spin_lock, flag); } else { - mdp3_vsync_irq_disable(MDP_PRIM_RDPTR, MDP_VSYNC_TERM); - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + INIT_COMPLETION(vsync_cntrl.vsync_wait); + wait_for_completion(&vsync_cntrl.vsync_wait); + mdp_disable_irq(MDP_VSYNC_TERM); } } diff --git a/drivers/video/msm/mdp_dma_dsi_video.c b/drivers/video/msm/mdp_dma_dsi_video.c index d94896ffca3..09ae82f8bdb 100644 --- a/drivers/video/msm/mdp_dma_dsi_video.c +++ b/drivers/video/msm/mdp_dma_dsi_video.c @@ -249,17 +249,26 @@ int mdp_dsi_video_off(struct platform_device *pdev) void mdp_dma_video_vsync_ctrl(int enable) { + unsigned long flag; if (vsync_cntrl.vsync_irq_enabled == enable) return; + spin_lock_irqsave(&mdp_spin_lock, flag); vsync_cntrl.vsync_irq_enabled = enable; + spin_unlock_irqrestore(&mdp_spin_lock, flag); if (enable) { mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); - mdp3_vsync_irq_enable(LCDC_FRAME_START, MDP_VSYNC_TERM); + spin_lock_irqsave(&mdp_spin_lock, flag); + outp32(MDP_INTR_CLEAR, LCDC_FRAME_START); + mdp_intr_mask |= LCDC_FRAME_START; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + mdp_enable_irq(MDP_VSYNC_TERM); + spin_unlock_irqrestore(&mdp_spin_lock, flag); } else { - mdp3_vsync_irq_disable(LCDC_FRAME_START, MDP_VSYNC_TERM); - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + INIT_COMPLETION(vsync_cntrl.vsync_wait); + wait_for_completion(&vsync_cntrl.vsync_wait); + mdp_disable_irq(MDP_VSYNC_TERM); } } diff --git a/drivers/video/msm/mdp_dma_lcdc.c b/drivers/video/msm/mdp_dma_lcdc.c index e030c9929ae..e1b78c2b250 100644 --- a/drivers/video/msm/mdp_dma_lcdc.c +++ b/drivers/video/msm/mdp_dma_lcdc.c @@ -330,17 +330,26 @@ int mdp_lcdc_off(struct platform_device *pdev) void mdp_dma_lcdc_vsync_ctrl(int enable) { + unsigned long flag; if (vsync_cntrl.vsync_irq_enabled == enable) return; + spin_lock_irqsave(&mdp_spin_lock, flag); vsync_cntrl.vsync_irq_enabled = enable; + spin_unlock_irqrestore(&mdp_spin_lock, flag); if (enable) { mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); - mdp3_vsync_irq_enable(LCDC_FRAME_START, MDP_VSYNC_TERM); + spin_lock_irqsave(&mdp_spin_lock, flag); + outp32(MDP_INTR_CLEAR, LCDC_FRAME_START); + mdp_intr_mask |= LCDC_FRAME_START; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + mdp_enable_irq(MDP_VSYNC_TERM); + spin_unlock_irqrestore(&mdp_spin_lock, flag); } else { - mdp3_vsync_irq_disable(LCDC_FRAME_START, MDP_VSYNC_TERM); - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + INIT_COMPLETION(vsync_cntrl.vsync_wait); + wait_for_completion(&vsync_cntrl.vsync_wait); + mdp_disable_irq(MDP_VSYNC_TERM); } }