From 56a49ded66c4f3e5e074357ab867c63cbd6a3f25 Mon Sep 17 00:00:00 2001 From: Kuogee Hsieh Date: Fri, 18 Jan 2013 14:16:31 -0800 Subject: [PATCH] msm_fb: display: replace msleep with wait4vsync vsync is controlled by frame work which means vsync irq off may happen at any instance. This patch use a reference count to control vsync irq enable/disable so that wait4vsync can replace msleep safely during suspend. Change-Id: Ief84b1b421436e1f750288eb9a9760a9cb96c555 Signed-off-by: Kuogee Hsieh --- drivers/video/msm/mdp4.h | 16 ++++---- drivers/video/msm/mdp4_overlay.c | 10 ++--- drivers/video/msm/mdp4_overlay_dsi_cmd.c | 15 ++----- drivers/video/msm/mdp4_overlay_dsi_video.c | 46 ++++++++++++++++------ drivers/video/msm/mdp4_overlay_dtv.c | 42 ++++++++++++++------ drivers/video/msm/mdp4_overlay_lcdc.c | 41 ++++++++++++++----- 6 files changed, 112 insertions(+), 58 deletions(-) diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h index ba099c3787b9..c491725e0ba0 100644 --- a/drivers/video/msm/mdp4.h +++ b/drivers/video/msm/mdp4.h @@ -488,7 +488,7 @@ int mdp4_overlay_dtv_set(struct msm_fb_data_type *mfd, int mdp4_overlay_dtv_unset(struct msm_fb_data_type *mfd, struct mdp4_overlay_pipe *pipe); void mdp4_dmae_done_dtv(void); -void mdp4_dtv_wait4vsync(int cndx, long long *vtime); +void mdp4_dtv_wait4vsync(int cndx); void mdp4_dtv_vsync_ctrl(struct fb_info *info, int enable); void mdp4_dtv_base_swap(int cndx, struct mdp4_overlay_pipe *pipe); #else @@ -521,7 +521,7 @@ static inline void mdp4_dmae_done_dtv(void) { /* empty */ } -static inline void mdp4_dtv_wait4vsync(int cndx, long long *vtime) +static inline void mdp4_dtv_wait4vsync(int cndx) { /* empty */ } @@ -597,7 +597,7 @@ int mdp4_overlay_format2type(uint32 format); int mdp4_overlay_format2pipe(struct mdp4_overlay_pipe *pipe); 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_wait4vsync(struct fb_info *info, long long *vtime); +int mdp4_overlay_wait4vsync(struct fb_info *info); int mdp4_overlay_vsync_ctrl(struct fb_info *info, int enable); int mdp4_overlay_unset(struct fb_info *info, int ndx); int mdp4_overlay_unset_mixer(int mixer); @@ -628,7 +628,7 @@ void mdp4_overlay1_done_dtv(void); void mdp4_overlay1_done_atv(void); void mdp4_primary_vsync_lcdc(void); void mdp4_external_vsync_dtv(void); -void mdp4_lcdc_wait4vsync(int cndx, long long *vtime); +void mdp4_lcdc_wait4vsync(int cndx); void mdp4_overlay_lcdc_vsync_push(struct msm_fb_data_type *mfd, struct mdp4_overlay_pipe *pipe); void mdp4_mddi_overlay_dmas_restore(void); @@ -786,8 +786,8 @@ int mdp4_dsi_video_off(struct platform_device *pdev); int mdp4_dsi_video_on(struct platform_device *pdev); void mdp4_primary_vsync_dsi_video(void); void mdp4_dsi_cmd_base_swap(int cndx, struct mdp4_overlay_pipe *pipe); -void mdp4_dsi_cmd_wait4vsync(int cndx, long long *vtime); -void mdp4_dsi_video_wait4vsync(int cndx, long long *vtime); +void mdp4_dsi_cmd_wait4vsync(int cndx); +void mdp4_dsi_video_wait4vsync(int cndx); void mdp4_dsi_cmd_pipe_queue(int cndx, struct mdp4_overlay_pipe *pipe); void mdp4_dsi_video_pipe_queue(int cndx, struct mdp4_overlay_pipe *pipe); void mdp4_dsi_cmd_vsync_ctrl(struct fb_info *info, int enable); @@ -825,10 +825,10 @@ static inline void mdp4_dsi_cmd_base_swap(int cndx, struct mdp4_overlay_pipe *pipe) { } -static inline void mdp4_dsi_cmd_wait4vsync(int cndx, long long *vtime) +static inline void mdp4_dsi_cmd_wait4vsync(int cndx) { } -static inline void mdp4_dsi_video_wait4vsync(int cndx, long long *vtime) +static inline void mdp4_dsi_video_wait4vsync(int cndx) { } static inline void mdp4_dsi_cmd_pipe_queue(int cndx, diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c index 5c96e37fb320..d21211d4aa82 100644 --- a/drivers/video/msm/mdp4_overlay.c +++ b/drivers/video/msm/mdp4_overlay.c @@ -3224,17 +3224,17 @@ int mdp4_overlay_unset(struct fb_info *info, int ndx) return 0; } -int mdp4_overlay_wait4vsync(struct fb_info *info, long long *vtime) +int mdp4_overlay_wait4vsync(struct fb_info *info) { if (!hdmi_prim_display && info->node == 0) { if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) - mdp4_dsi_video_wait4vsync(0, vtime); + mdp4_dsi_video_wait4vsync(0); else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) - mdp4_dsi_cmd_wait4vsync(0, vtime); + mdp4_dsi_cmd_wait4vsync(0); else if (ctrl->panel_mode & MDP4_PANEL_LCDC) - mdp4_lcdc_wait4vsync(0, vtime); + mdp4_lcdc_wait4vsync(0); } else if (hdmi_prim_display || info->node == 1) { - mdp4_dtv_wait4vsync(0, vtime); + mdp4_dtv_wait4vsync(0); } return 0; diff --git a/drivers/video/msm/mdp4_overlay_dsi_cmd.c b/drivers/video/msm/mdp4_overlay_dsi_cmd.c index 23e6d1db7ea1..380364b4a364 100644 --- a/drivers/video/msm/mdp4_overlay_dsi_cmd.c +++ b/drivers/video/msm/mdp4_overlay_dsi_cmd.c @@ -388,11 +388,8 @@ int mdp4_dsi_cmd_pipe_commit(int cndx, int wait) mdp4_stat.overlay_commit[pipe->mixer_num]++; - if (wait) { - long long tick; - - mdp4_dsi_cmd_wait4vsync(0, &tick); - } + if (wait) + mdp4_dsi_cmd_wait4vsync(0); return cnt; } @@ -444,7 +441,7 @@ void mdp4_dsi_cmd_vsync_ctrl(struct fb_info *info, int enable) mutex_unlock(&vctrl->update_lock); } -void mdp4_dsi_cmd_wait4vsync(int cndx, long long *vtime) +void mdp4_dsi_cmd_wait4vsync(int cndx) { struct vsycn_ctrl *vctrl; struct mdp4_overlay_pipe *pipe; @@ -458,10 +455,8 @@ void mdp4_dsi_cmd_wait4vsync(int cndx, long long *vtime) vctrl = &vsync_ctrl_db[cndx]; pipe = vctrl->base_pipe; - if (atomic_read(&vctrl->suspend) > 0) { - *vtime = -1; + if (atomic_read(&vctrl->suspend) > 0) return; - } spin_lock_irqsave(&vctrl->spin_lock, flags); if (vctrl->wait_vsync_cnt == 0) @@ -471,8 +466,6 @@ void mdp4_dsi_cmd_wait4vsync(int cndx, long long *vtime) wait_for_completion(&vctrl->vsync_comp); mdp4_stat.wait4vsync0++; - - *vtime = ktime_to_ns(vctrl->vsync_time); } static void mdp4_dsi_cmd_wait4dmap(int cndx) diff --git a/drivers/video/msm/mdp4_overlay_dsi_video.c b/drivers/video/msm/mdp4_overlay_dsi_video.c index 6239cce43a8b..4daffcd8d5c1 100644 --- a/drivers/video/msm/mdp4_overlay_dsi_video.c +++ b/drivers/video/msm/mdp4_overlay_dsi_video.c @@ -265,6 +265,31 @@ int mdp4_dsi_video_pipe_commit(int cndx, int wait) return cnt; } +static void mdp4_video_vsync_irq_ctrl(int cndx, int enable) +{ + struct vsycn_ctrl *vctrl; + static int vsync_irq_cnt; + + vctrl = &vsync_ctrl_db[cndx]; + + mutex_lock(&vctrl->update_lock); + if (enable) { + if (vsync_irq_cnt == 0) + vsync_irq_enable(INTR_PRIMARY_VSYNC, + MDP_PRIM_VSYNC_TERM); + vsync_irq_cnt++; + } else { + if (vsync_irq_cnt) { + vsync_irq_cnt--; + if (vsync_irq_cnt == 0) + vsync_irq_disable(INTR_PRIMARY_VSYNC, + MDP_PRIM_VSYNC_TERM); + } + } + pr_debug("%s: enable=%d cnt=%d\n", __func__, enable, vsync_irq_cnt); + mutex_unlock(&vctrl->update_lock); +} + void mdp4_dsi_video_vsync_ctrl(struct fb_info *info, int enable) { struct vsycn_ctrl *vctrl; @@ -279,16 +304,13 @@ void mdp4_dsi_video_vsync_ctrl(struct fb_info *info, int enable) vctrl->vsync_irq_enabled = enable; - if (enable) - vsync_irq_enable(INTR_PRIMARY_VSYNC, MDP_PRIM_VSYNC_TERM); - else - vsync_irq_disable(INTR_PRIMARY_VSYNC, MDP_PRIM_VSYNC_TERM); + mdp4_video_vsync_irq_ctrl(cndx, enable); if (vctrl->vsync_irq_enabled && atomic_read(&vctrl->suspend) == 0) atomic_set(&vctrl->vsync_resume, 1); } -void mdp4_dsi_video_wait4vsync(int cndx, long long *vtime) +void mdp4_dsi_video_wait4vsync(int cndx) { struct vsycn_ctrl *vctrl; struct mdp4_overlay_pipe *pipe; @@ -302,14 +324,14 @@ void mdp4_dsi_video_wait4vsync(int cndx, long long *vtime) vctrl = &vsync_ctrl_db[cndx]; pipe = vctrl->base_pipe; - if (atomic_read(&vctrl->suspend) > 0) { - *vtime = -1; + if (atomic_read(&vctrl->suspend) > 0) return; - } /* start timing generator & mmu if they are not started yet */ mdp4_overlay_dsi_video_start(); + mdp4_video_vsync_irq_ctrl(cndx, 1); + spin_lock_irqsave(&vctrl->spin_lock, flags); if (vctrl->wait_vsync_cnt == 0) INIT_COMPLETION(vctrl->vsync_comp); @@ -318,9 +340,8 @@ void mdp4_dsi_video_wait4vsync(int cndx, long long *vtime) spin_unlock_irqrestore(&vctrl->spin_lock, flags); wait_for_completion(&vctrl->vsync_comp); + mdp4_video_vsync_irq_ctrl(cndx, 0); mdp4_stat.wait4vsync0++; - - *vtime = ktime_to_ns(vctrl->vsync_time); } static void mdp4_dsi_video_wait4dmap(int cndx) @@ -692,7 +713,7 @@ int mdp4_dsi_video_off(struct platform_device *pdev) atomic_set(&vctrl->suspend, 1); atomic_set(&vctrl->vsync_resume, 0); - msleep(20); /* >= 17 ms */ + mdp4_dsi_video_wait4vsync(cndx); complete_all(&vctrl->vsync_comp); @@ -1058,13 +1079,12 @@ static void mdp4_dsi_video_do_blt(struct msm_fb_data_type *mfd, int enable) if (vctrl->blt_ctrl == OVERLAY_BLT_SWITCH_TG_OFF) { int tg_enabled; - long long vtime; pr_info("%s: blt enabled by switching TG off\n", __func__); vctrl->blt_change = 0; tg_enabled = inpdw(MDP_BASE + DSI_VIDEO_BASE) & 0x01; if (tg_enabled) { - mdp4_dsi_video_wait4vsync(0, &vtime); + mdp4_dsi_video_wait4vsync(cndx); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE, 0); mdp4_dsi_video_wait4dmap_done(0); } diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c index 34983a4a4f5c..2ffb80a9a28c 100644 --- a/drivers/video/msm/mdp4_overlay_dtv.c +++ b/drivers/video/msm/mdp4_overlay_dtv.c @@ -246,6 +246,31 @@ int mdp4_dtv_pipe_commit(int cndx, int wait) return cnt; } +static void mdp4_dtv_vsync_irq_ctrl(int cndx, int enable) +{ + struct vsycn_ctrl *vctrl; + static int vsync_irq_cnt; + + vctrl = &vsync_ctrl_db[cndx]; + + mutex_lock(&vctrl->update_lock); + if (enable) { + if (vsync_irq_cnt == 0) + vsync_irq_enable(INTR_EXTERNAL_VSYNC, + MDP_EXTER_VSYNC_TERM); + vsync_irq_cnt++; + } else { + if (vsync_irq_cnt) { + vsync_irq_cnt--; + if (vsync_irq_cnt == 0) + vsync_irq_disable(INTR_EXTERNAL_VSYNC, + MDP_EXTER_VSYNC_TERM); + } + } + pr_debug("%s: enable=%d cnt=%d\n", __func__, enable, vsync_irq_cnt); + mutex_unlock(&vctrl->update_lock); +} + void mdp4_dtv_vsync_ctrl(struct fb_info *info, int enable) { struct vsycn_ctrl *vctrl; @@ -263,16 +288,13 @@ void mdp4_dtv_vsync_ctrl(struct fb_info *info, int enable) vctrl->vsync_irq_enabled = enable; - if (enable) - vsync_irq_enable(INTR_EXTERNAL_VSYNC, MDP_EXTER_VSYNC_TERM); - else - vsync_irq_disable(INTR_EXTERNAL_VSYNC, MDP_EXTER_VSYNC_TERM); + mdp4_dtv_vsync_irq_ctrl(cndx, enable); if (vctrl->vsync_irq_enabled && atomic_read(&vctrl->suspend) == 0) atomic_set(&vctrl->vsync_resume, 1); } -void mdp4_dtv_wait4vsync(int cndx, long long *vtime) +void mdp4_dtv_wait4vsync(int cndx) { struct vsycn_ctrl *vctrl; struct mdp4_overlay_pipe *pipe; @@ -289,6 +311,8 @@ void mdp4_dtv_wait4vsync(int cndx, long long *vtime) if (atomic_read(&vctrl->suspend) > 0) return; + mdp4_dtv_vsync_irq_ctrl(cndx, 1); + spin_lock_irqsave(&vctrl->spin_lock, flags); if (vctrl->wait_vsync_cnt == 0) @@ -297,9 +321,8 @@ void mdp4_dtv_wait4vsync(int cndx, long long *vtime) spin_unlock_irqrestore(&vctrl->spin_lock, flags); wait_for_completion(&vctrl->vsync_comp); + mdp4_dtv_vsync_irq_ctrl(cndx, 0); mdp4_stat.wait4vsync1++; - - *vtime = ktime_to_ns(vctrl->vsync_time); } static void mdp4_dtv_wait4dmae(int cndx) @@ -608,10 +631,7 @@ int mdp4_dtv_off(struct platform_device *pdev) atomic_set(&vctrl->suspend, 1); atomic_set(&vctrl->vsync_resume, 0); - if (vctrl->vsync_irq_enabled) { - while (vctrl->wait_vsync_cnt) - msleep(20); /* >= 17 ms */ - } + mdp4_dtv_wait4vsync(cndx); complete_all(&vctrl->vsync_comp); diff --git a/drivers/video/msm/mdp4_overlay_lcdc.c b/drivers/video/msm/mdp4_overlay_lcdc.c index 9feaaca07470..a5f640fc7381 100644 --- a/drivers/video/msm/mdp4_overlay_lcdc.c +++ b/drivers/video/msm/mdp4_overlay_lcdc.c @@ -270,6 +270,31 @@ int mdp4_lcdc_pipe_commit(int cndx, int wait) return cnt; } +static void mdp4_lcdc_vsync_irq_ctrl(int cndx, int enable) +{ + struct vsycn_ctrl *vctrl; + static int vsync_irq_cnt; + + vctrl = &vsync_ctrl_db[cndx]; + + mutex_lock(&vctrl->update_lock); + if (enable) { + if (vsync_irq_cnt == 0) + vsync_irq_enable(INTR_PRIMARY_VSYNC, + MDP_PRIM_VSYNC_TERM); + vsync_irq_cnt++; + } else { + if (vsync_irq_cnt) { + vsync_irq_cnt--; + if (vsync_irq_cnt == 0) + vsync_irq_disable(INTR_PRIMARY_VSYNC, + MDP_PRIM_VSYNC_TERM); + } + } + pr_debug("%s: enable=%d cnt=%d\n", __func__, enable, vsync_irq_cnt); + mutex_unlock(&vctrl->update_lock); +} + void mdp4_lcdc_vsync_ctrl(struct fb_info *info, int enable) { struct vsycn_ctrl *vctrl; @@ -284,16 +309,13 @@ void mdp4_lcdc_vsync_ctrl(struct fb_info *info, int enable) vctrl->vsync_irq_enabled = enable; - if (enable) - vsync_irq_enable(INTR_PRIMARY_VSYNC, MDP_PRIM_VSYNC_TERM); - else - vsync_irq_disable(INTR_PRIMARY_VSYNC, MDP_PRIM_VSYNC_TERM); + mdp4_lcdc_vsync_irq_ctrl(cndx, enable); if (vctrl->vsync_irq_enabled && atomic_read(&vctrl->suspend) == 0) atomic_set(&vctrl->vsync_resume, 1); } -void mdp4_lcdc_wait4vsync(int cndx, long long *vtime) +void mdp4_lcdc_wait4vsync(int cndx) { struct vsycn_ctrl *vctrl; struct mdp4_overlay_pipe *pipe; @@ -307,14 +329,14 @@ void mdp4_lcdc_wait4vsync(int cndx, long long *vtime) vctrl = &vsync_ctrl_db[cndx]; pipe = vctrl->base_pipe; - if (atomic_read(&vctrl->suspend) > 0) { - *vtime = -1; + if (atomic_read(&vctrl->suspend) > 0) return; - } /* start timing generator & mmu if they are not started yet */ mdp4_overlay_lcdc_start(); + mdp4_lcdc_vsync_irq_ctrl(cndx, 1); + spin_lock_irqsave(&vctrl->spin_lock, flags); if (vctrl->wait_vsync_cnt == 0) @@ -323,9 +345,8 @@ void mdp4_lcdc_wait4vsync(int cndx, long long *vtime) spin_unlock_irqrestore(&vctrl->spin_lock, flags); wait_for_completion(&vctrl->vsync_comp); + mdp4_lcdc_vsync_irq_ctrl(cndx, 0); mdp4_stat.wait4vsync0++; - - *vtime = vctrl->vsync_time.tv64; } static void mdp4_lcdc_wait4dmap(int cndx)