static void mdp4_overlay_dtv_ov_start(struct msm_fb_data_type *mfd) { unsigned long flag; /* enable irq */ if (mfd->ov_start) return; #ifdef CONFIG_MACH_LGE /* QCT Patch : Prevent kernel Crash (mdp4_overlay1_done_dtv()) */ if (!dtv_pipe) { pr_debug("%s: no mixer1 base layer pipe allocated!\n", __func__); return; } #endif 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); mfd->dma->waiting = TRUE; outp32(MDP_INTR_CLEAR, INTR_OVERLAY1_DONE); mdp_intr_mask |= INTR_OVERLAY1_DONE; outp32(MDP_INTR_ENABLE, mdp_intr_mask); spin_unlock_irqrestore(&mdp_spin_lock, flag); mfd->ov_start = true; }
void mdp4_dmae_done_dtv(void) { int cndx; struct vsycn_ctrl *vctrl; struct mdp4_overlay_pipe *pipe; cndx = 0; if (cndx >= MAX_CONTROLLER) { pr_err("%s: out or range: cndx=%d\n", __func__, cndx); return; } vctrl = &vsync_ctrl_db[cndx]; pipe = vctrl->base_pipe; if (pipe == NULL) return; pr_debug("%s: cpu=%d\n", __func__, smp_processor_id()); spin_lock(&vctrl->spin_lock); if (vctrl->blt_change) { if (pipe->ov_blt_addr) { mdp4_overlayproc_cfg(pipe); mdp4_overlay_dmae_xy(pipe); mdp4_dtv_blt_ov_update(pipe); pipe->blt_ov_done++; vsync_irq_enable(INTR_OVERLAY1_DONE, MDP_OVERLAY1_TERM); mdp4_stat.kickoff_ov1++; outpdw(MDP_BASE + 0x0008, 0); } vctrl->blt_change = 0; } if (mdp_rev <= MDP_REV_41) mdp4_mixer_blend_cfg(MDP4_MIXER1); complete_all(&vctrl->dmae_comp); mdp4_overlay_dma_commit(MDP4_MIXER1); vsync_irq_disable(INTR_DMA_E_DONE, MDP_DMA_E_TERM); spin_unlock(&vctrl->spin_lock); }
/* * mdp4_dmae_done_dtv: called from isr */ void mdp4_dmae_done_dtv(void) { int cndx; struct vsycn_ctrl *vctrl; struct mdp4_overlay_pipe *pipe; cndx = 0; if (cndx >= MAX_CONTROLLER) { pr_err("%s: out or range: cndx=%d\n", __func__, cndx); return; } vctrl = &vsync_ctrl_db[cndx]; pipe = vctrl->base_pipe; spin_lock(&vctrl->spin_lock); if (vctrl->blt_change) { if (pipe->ov_blt_addr) { mdp4_overlayproc_cfg(pipe); mdp4_overlay_dmae_xy(pipe); mdp4_dtv_blt_ov_update(pipe); pipe->blt_ov_done++; /* Prefill one frame */ vsync_irq_enable(INTR_OVERLAY1_DONE, MDP_OVERLAY1_TERM); /* kickoff overlay1 engine */ mdp4_stat.kickoff_ov1++; outpdw(MDP_BASE + 0x0008, 0); } vctrl->blt_change = 0; } vctrl->dmae_intr_cnt--; if (vctrl->dmae_wait_cnt) { complete_all(&vctrl->dmae_comp); vctrl->dmae_wait_cnt = 0; /* reset */ } else { mdp4_overlay_dma_commit(MDP4_MIXER1); } vsync_irq_disable(INTR_DMA_E_DONE, MDP_DMA_E_TERM); spin_unlock(&vctrl->spin_lock); }
static void mdp4_overlay_dtv_ov_start(struct msm_fb_data_type *mfd) { unsigned long flag; /* enable irq */ 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); mfd->dma->waiting = TRUE; outp32(MDP_INTR_CLEAR, INTR_OVERLAY1_DONE); mdp_intr_mask |= INTR_OVERLAY1_DONE; outp32(MDP_INTR_ENABLE, mdp_intr_mask); spin_unlock_irqrestore(&mdp_spin_lock, flag); mfd->ov_start = true; }
int mdp4_dtv_pipe_commit(int cndx, int wait) { int i, undx; int mixer = 0; struct vsycn_ctrl *vctrl; struct vsync_update *vp; struct mdp4_overlay_pipe *pipe; struct mdp4_overlay_pipe *real_pipe; unsigned long flags; int cnt = 0; vctrl = &vsync_ctrl_db[cndx]; mutex_lock(&vctrl->update_lock); undx = vctrl->update_ndx; vp = &vctrl->vlist[undx]; pipe = vctrl->base_pipe; mixer = pipe->mixer_num; mdp4_overlay_iommu_unmap_freelist(mixer); if (vp->update_cnt == 0) { mutex_unlock(&vctrl->update_lock); return 0; } /* HTC FIXME: Sometime the mdp hang happened if mdp only create HDMI base pipe and do mdp4_dtv_pipe_commit. So checking all mdp pipe to prevent fail condition happened. */ if(!dtv_pipe_ready) { for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) { real_pipe = mdp4_overlay_ndx2pipe(i); if (real_pipe && real_pipe->pipe_used != 0 && real_pipe->pipe_type != OVERLAY_TYPE_BF && real_pipe->mixer_num == MDP4_MIXER1) { dtv_pipe_ready = true; break; } } if(!dtv_pipe_ready && dtv_enabled) { PR_DISP_INFO("Dtv real pipe is not ready, skip this time\n"); mutex_unlock(&vctrl->update_lock); return 0; } } vctrl->update_ndx++; vctrl->update_ndx &= 0x01; vp->update_cnt = 0; /* reset */ mutex_unlock(&vctrl->update_lock); pipe = vp->plist; for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) { if (pipe->pipe_used) { cnt++; real_pipe = mdp4_overlay_ndx2pipe(pipe->pipe_ndx); if (real_pipe && real_pipe->pipe_used) { /* pipe not unset */ mdp4_overlay_vsync_commit(pipe); } /* free previous iommu to freelist * which will be freed at next * pipe_commit */ mdp4_overlay_iommu_pipe_free(pipe->pipe_ndx, 0); pipe->pipe_used = 0; /* clear */ } } mdp4_mixer_stage_commit(mixer); /* start timing generator & mmu if they are not started yet */ mdp4_overlay_dtv_start(); pipe = vctrl->base_pipe; spin_lock_irqsave(&vctrl->spin_lock, flags); if (pipe->ov_blt_addr) { mdp4_dtv_blt_ov_update(pipe); pipe->blt_ov_done++; vsync_irq_enable(INTR_OVERLAY1_DONE, MDP_OVERLAY1_TERM); mb(); pipe->blt_ov_koff++; /* kickoff overlay1 engine */ mdp4_stat.kickoff_ov1++; outpdw(MDP_BASE + 0x0008, 0); } else { /* schedule second phase update at dmap */ INIT_COMPLETION(vctrl->dmae_comp); vsync_irq_enable(INTR_DMA_E_DONE, MDP_DMA_E_TERM); } spin_unlock_irqrestore(&vctrl->spin_lock, flags); mdp4_stat.overlay_commit[pipe->mixer_num]++; if (wait) mdp4_dtv_wait4dmae(cndx); return cnt; }
int mdp4_dtv_pipe_commit(int cndx, int wait) { int i, undx; int mixer = 0; struct vsycn_ctrl *vctrl; struct vsync_update *vp; struct mdp4_overlay_pipe *pipe; struct mdp4_overlay_pipe *real_pipe; unsigned long flags; int cnt = 0; vctrl = &vsync_ctrl_db[cndx]; mutex_lock(&vctrl->update_lock); undx = vctrl->update_ndx; vp = &vctrl->vlist[undx]; pipe = vctrl->base_pipe; mixer = pipe->mixer_num; mdp4_overlay_iommu_unmap_freelist(mixer); if (vp->update_cnt == 0) { mutex_unlock(&vctrl->update_lock); return 0; } vctrl->update_ndx++; vctrl->update_ndx &= 0x01; vp->update_cnt = 0; /* reset */ mutex_unlock(&vctrl->update_lock); pipe = vp->plist; for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) { if (pipe->pipe_used) { cnt++; real_pipe = mdp4_overlay_ndx2pipe(pipe->pipe_ndx); if (real_pipe && real_pipe->pipe_used) { /* pipe not unset */ mdp4_overlay_vsync_commit(pipe); } /* free previous iommu to freelist * which will be freed at next * pipe_commit */ mdp4_overlay_iommu_pipe_free(pipe->pipe_ndx, 0); pipe->pipe_used = 0; /* clear */ } } mdp4_mixer_stage_commit(mixer); /* start timing generator & mmu if they are not started yet */ mdp4_overlay_dtv_start(); pipe = vctrl->base_pipe; spin_lock_irqsave(&vctrl->spin_lock, flags); if (pipe->ov_blt_addr) { mdp4_dtv_blt_ov_update(pipe); pipe->blt_ov_done++; vsync_irq_enable(INTR_OVERLAY1_DONE, MDP_OVERLAY1_TERM); mb(); pipe->blt_ov_koff++; /* kickoff overlay1 engine */ mdp4_stat.kickoff_ov1++; outpdw(MDP_BASE + 0x0008, 0); } else { /* schedule second phase update at dmap */ INIT_COMPLETION(vctrl->dmae_comp); vsync_irq_enable(INTR_DMA_E_DONE, MDP_DMA_E_TERM); } spin_unlock_irqrestore(&vctrl->spin_lock, flags); mdp4_stat.overlay_commit[pipe->mixer_num]++; if (wait) mdp4_dtv_wait4dmae(cndx); return cnt; }
int mdp4_dtv_pipe_commit(void) { int i, undx; int mixer = 0; struct vsycn_ctrl *vctrl; struct vsync_update *vp; struct mdp4_overlay_pipe *pipe; struct mdp4_overlay_pipe *real_pipe; unsigned long flags; int cnt = 0; vctrl = &vsync_ctrl_db[0]; mutex_lock(&vctrl->update_lock); undx = vctrl->update_ndx; vp = &vctrl->vlist[undx]; pipe = vctrl->base_pipe; mixer = pipe->mixer_num; mdp4_overlay_iommu_unmap_freelist(mixer); if (vp->update_cnt == 0) { mutex_unlock(&vctrl->update_lock); return 0; } vctrl->update_ndx++; vctrl->update_ndx &= 0x01; vp->update_cnt = 0; mutex_unlock(&vctrl->update_lock); pipe = vp->plist; for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) { if (pipe->pipe_used) { cnt++; real_pipe = mdp4_overlay_ndx2pipe(pipe->pipe_ndx); if (real_pipe && real_pipe->pipe_used) { mdp4_overlay_vsync_commit(pipe); } mdp4_overlay_iommu_pipe_free(pipe->pipe_ndx, 0); pipe->pipe_used = 0; } } mdp4_mixer_stage_commit(mixer); mdp4_overlay_dtv_start(); pipe = vctrl->base_pipe; spin_lock_irqsave(&vctrl->spin_lock, flags); if (pipe->ov_blt_addr) { mdp4_dtv_blt_ov_update(pipe); pipe->blt_ov_done++; vsync_irq_enable(INTR_OVERLAY1_DONE, MDP_OVERLAY1_TERM); mb(); pipe->blt_ov_koff++; mdp4_stat.kickoff_ov1++; outpdw(MDP_BASE + 0x0008, 0); } else { INIT_COMPLETION(vctrl->dmae_comp); vsync_irq_enable(INTR_DMA_E_DONE, MDP_DMA_E_TERM); } spin_unlock_irqrestore(&vctrl->spin_lock, flags); mdp4_stat.overlay_commit[pipe->mixer_num]++; return cnt; }
int mdp4_dtv_pipe_commit(int cndx, int wait) { int i, undx; int mixer = 0; struct vsycn_ctrl *vctrl; struct vsync_update *vp; struct mdp4_overlay_pipe *pipe; struct mdp4_overlay_pipe *real_pipe; unsigned long flags; int cnt = 0; vctrl = &vsync_ctrl_db[cndx]; mutex_lock(&vctrl->update_lock); undx = vctrl->update_ndx; vp = &vctrl->vlist[undx]; pipe = vctrl->base_pipe; if (pipe == NULL) { pr_err("%s: NO base pipe\n", __func__); mutex_unlock(&vctrl->update_lock); return 0; } mixer = pipe->mixer_num; mdp_update_pm(vctrl->mfd, vctrl->vsync_time); /* * allow stage_commit without pipes queued * (vp->update_cnt == 0) to unstage pipes after * overlay_unset */ vctrl->update_ndx++; vctrl->update_ndx &= 0x01; vp->update_cnt = 0; /* reset */ mutex_unlock(&vctrl->update_lock); pipe = vp->plist; for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) { if (pipe->pipe_used) { cnt++; real_pipe = mdp4_overlay_ndx2pipe(pipe->pipe_ndx); if (real_pipe && real_pipe->pipe_used) { /* pipe not unset */ mdp4_overlay_vsync_commit(pipe); } } } mdp4_mixer_stage_commit(mixer); /* start timing generator & mmu if they are not started yet */ mdp4_overlay_dtv_start(); /* * there has possibility that pipe commit come very close to next vsync * this may cause two consecutive pie_commits happen within same vsync * period which casue iommu page fault when previous iommu buffer * freed. Set ION_IOMMU_UNMAP_DELAYED flag at ion_map_iommu() to * add delay unmap iommu buffer to fix this problem. * Also ion_unmap_iommu() may take as long as 9 ms to free an ion buffer. * therefore mdp4_overlay_iommu_unmap_freelist(mixer) should be called * ater stage_commit() to ensure pipe_commit (up to stage_commit) * is completed within vsync period. */ /* free previous committed iommu back to pool */ mdp4_overlay_iommu_unmap_freelist(mixer); pipe = vp->plist; for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) { if (pipe->pipe_used) { /* free previous iommu to freelist * which will be freed at next * pipe_commit */ mdp4_overlay_iommu_pipe_free(pipe->pipe_ndx, 0); pipe->pipe_used = 0; /* clear */ } } pipe = vctrl->base_pipe; spin_lock_irqsave(&vctrl->spin_lock, flags); if (pipe->ov_blt_addr) { mdp4_dtv_blt_ov_update(pipe); pipe->blt_ov_done++; vsync_irq_enable(INTR_OVERLAY1_DONE, MDP_OVERLAY1_TERM); mb(); pipe->blt_ov_koff++; /* kickoff overlay1 engine */ mdp4_stat.kickoff_ov1++; outpdw(MDP_BASE + 0x0008, 0); } else { /* schedule second phase update at dmap */ INIT_COMPLETION(vctrl->dmae_comp); vsync_irq_enable(INTR_DMA_E_DONE, MDP_DMA_E_TERM); } spin_unlock_irqrestore(&vctrl->spin_lock, flags); mdp4_stat.overlay_commit[pipe->mixer_num]++; if (wait) mdp4_dtv_wait4dmae(0); return cnt; }
int mdp4_dtv_pipe_commit(int cndx, int wait) { int i, undx; int mixer = 0; struct vsycn_ctrl *vctrl; struct vsync_update *vp; struct mdp4_overlay_pipe *pipe; struct mdp4_overlay_pipe *real_pipe; unsigned long flags; int cnt = 0; vctrl = &vsync_ctrl_db[cndx]; mutex_lock(&vctrl->update_lock); undx = vctrl->update_ndx; vp = &vctrl->vlist[undx]; pipe = vctrl->base_pipe; mixer = pipe->mixer_num; mdp4_overlay_iommu_unmap_freelist(mixer); if (vp->update_cnt == 0) { mutex_unlock(&vctrl->update_lock); return 0; } if(!dtv_pipe_ready) { for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) { real_pipe = mdp4_overlay_ndx2pipe(i); if (real_pipe && real_pipe->pipe_used != 0 && real_pipe->pipe_type != OVERLAY_TYPE_BF && real_pipe->mixer_num == MDP4_MIXER1) { dtv_pipe_ready = true; break; } } if(!dtv_pipe_ready && dtv_enabled) { PR_DISP_INFO("Dtv real pipe is not ready, skip this time\n"); mutex_unlock(&vctrl->update_lock); return 0; } } vctrl->update_ndx++; vctrl->update_ndx &= 0x01; vp->update_cnt = 0; mutex_unlock(&vctrl->update_lock); pipe = vp->plist; for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) { if (pipe->pipe_used) { cnt++; real_pipe = mdp4_overlay_ndx2pipe(pipe->pipe_ndx); if (real_pipe && real_pipe->pipe_used) { mdp4_overlay_vsync_commit(pipe); } mdp4_overlay_iommu_pipe_free(pipe->pipe_ndx, 0); pipe->pipe_used = 0; } } mdp4_mixer_stage_commit(mixer); mdp4_overlay_dtv_start(); pipe = vctrl->base_pipe; spin_lock_irqsave(&vctrl->spin_lock, flags); if (pipe->ov_blt_addr) { mdp4_dtv_blt_ov_update(pipe); pipe->blt_ov_done++; vsync_irq_enable(INTR_OVERLAY1_DONE, MDP_OVERLAY1_TERM); mb(); pipe->blt_ov_koff++; mdp4_stat.kickoff_ov1++; outpdw(MDP_BASE + 0x0008, 0); } else { INIT_COMPLETION(vctrl->dmae_comp); vsync_irq_enable(INTR_DMA_E_DONE, MDP_DMA_E_TERM); } spin_unlock_irqrestore(&vctrl->spin_lock, flags); mdp4_stat.overlay_commit[pipe->mixer_num]++; if (wait) mdp4_dtv_wait4dmae(cndx); return cnt; }