From 82c6b4cdd761ce404f9ae28b7bff74b582bf3546 Mon Sep 17 00:00:00 2001 From: Ken Zhang Date: Wed, 5 Sep 2012 15:43:02 -0700 Subject: [PATCH] msm_fb: display: wake up system around vsync To avoid frame drops due to power collapse, wake up cpu right before vsync. Conflicts: drivers/video/msm/mdp.c drivers/video/msm/msm_fb.h Change-Id: I63385eb329ae5e74cbac5256823fd3a213e0a0e1 Signed-off-by: Ken Zhang Signed-off-by: Huaibin Yang --- drivers/video/msm/mdp.c | 58 +++++++++++++++++++++- drivers/video/msm/mdp.h | 1 + drivers/video/msm/mdp4_overlay_atv.c | 2 + drivers/video/msm/mdp4_overlay_dsi_video.c | 1 + drivers/video/msm/mdp4_overlay_dtv.c | 1 + drivers/video/msm/mdp4_overlay_lcdc.c | 1 + drivers/video/msm/msm_fb.h | 2 +- drivers/video/msm/msm_fb_panel.h | 2 +- 8 files changed, 64 insertions(+), 4 deletions(-) diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c index b80bfdf0a360..6871fe605abf 100644 --- a/drivers/video/msm/mdp.c +++ b/drivers/video/msm/mdp.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include "mdp.h" #include "msm_fb.h" @@ -1405,15 +1406,15 @@ int mdp_ppp_pipe_wait(void) if (wait == TRUE) { ret = wait_for_completion_interruptible_timeout(&mdp_ppp_comp, 5 * HZ); - if (!ret) printk(KERN_ERR "%s: Timed out waiting for the MDP.\n", - __func__); + __func__); } return ret; } +#define MAX_VSYNC_GAP 4 #define DEFAULT_FRAME_RATE 60 u32 mdp_get_panel_framerate(struct msm_fb_data_type *mfd) @@ -1447,6 +1448,53 @@ u32 mdp_get_panel_framerate(struct msm_fb_data_type *mfd) return frame_rate; } +static int mdp_diff_to_next_vsync(ktime_t cur_time, + ktime_t last_vsync, u32 vsync_period) +{ + int diff_from_last, diff_to_next; + /* + * Get interval beween last vsync and current time + * Current time = CPU programming MDP for next Vsync + */ + diff_from_last = + (ktime_to_us(ktime_sub(cur_time, last_vsync))); + diff_from_last /= USEC_PER_MSEC; + /* + * If the last Vsync occurred too long ago, skip programming + * the timer + */ + if (diff_from_last < (vsync_period * MAX_VSYNC_GAP)) { + if (diff_from_last > vsync_period) + diff_to_next = + (diff_from_last - vsync_period) % vsync_period; + else + diff_to_next = vsync_period - diff_from_last; + } else { + /* mark it out of range */ + diff_to_next = vsync_period + 1; + } + return diff_to_next; +} + +void mdp_update_pm(struct msm_fb_data_type *mfd, ktime_t pre_vsync) +{ + u32 vsync_period; + int diff_to_next; + ktime_t cur_time, wakeup_time; + + if (!mfd->cpu_pm_hdl) + return; + vsync_period = mfd->panel_info.frame_interval; + cur_time = ktime_get(); + diff_to_next = mdp_diff_to_next_vsync(cur_time, + pre_vsync, + vsync_period); + if (diff_to_next > vsync_period) + return; + wakeup_time = ktime_add_ns(cur_time, diff_to_next * NSEC_PER_MSEC); + activate_event_timer(mfd->cpu_pm_hdl, wakeup_time); +} + static DEFINE_SPINLOCK(mdp_lock); static int mdp_irq_mask; static int mdp_irq_enabled; @@ -2508,6 +2556,7 @@ static int mdp_probe(struct platform_device *pdev) int rc; resource_size_t size ; unsigned long flag; + u32 frame_rate; #ifdef CONFIG_FB_MSM_MDP40 int intf, if_no; #endif @@ -2910,6 +2959,11 @@ static int mdp_probe(struct platform_device *pdev) mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); } + frame_rate = mdp_get_panel_framerate(mfd); + if (frame_rate) { + mfd->panel_info.frame_interval = 1000 / frame_rate; + mfd->cpu_pm_hdl = add_event_timer(NULL, (void *)mfd); + } mdp_clk_ctrl(0); #ifdef CONFIG_MSM_BUS_SCALING diff --git a/drivers/video/msm/mdp.h b/drivers/video/msm/mdp.h index 0653869a0622..9cc8fe875539 100644 --- a/drivers/video/msm/mdp.h +++ b/drivers/video/msm/mdp.h @@ -911,6 +911,7 @@ int mdp_ppp_v4l2_overlay_clear(void); int mdp_ppp_v4l2_overlay_play(struct fb_info *info, unsigned long srcp0_addr, unsigned long srcp0_size, unsigned long srcp1_addr, unsigned long srcp1_size); +void mdp_update_pm(struct msm_fb_data_type *mfd, ktime_t pre_vsync); u32 mdp_get_panel_framerate(struct msm_fb_data_type *mfd); diff --git a/drivers/video/msm/mdp4_overlay_atv.c b/drivers/video/msm/mdp4_overlay_atv.c index e67b244e9935..90c3da9c039a 100644 --- a/drivers/video/msm/mdp4_overlay_atv.c +++ b/drivers/video/msm/mdp4_overlay_atv.c @@ -184,6 +184,8 @@ void mdp4_atv_overlay(struct msm_fb_data_type *mfd) } else { pipe->srcp0_addr = (uint32)(buf + buf_offset); } + mdp_update_pm(mfd, vsync_ctrl_db[0].vsync_time); + mdp4_overlay_mdp_perf_req(pipe, mfd); mdp4_overlay_mdp_perf_upd(mfd, 1); mdp4_overlay_rgb_setup(pipe); diff --git a/drivers/video/msm/mdp4_overlay_dsi_video.c b/drivers/video/msm/mdp4_overlay_dsi_video.c index 1ab063df624c..fe96e79a6a38 100644 --- a/drivers/video/msm/mdp4_overlay_dsi_video.c +++ b/drivers/video/msm/mdp4_overlay_dsi_video.c @@ -1132,6 +1132,7 @@ void mdp4_dsi_video_overlay(struct msm_fb_data_type *mfd) mdp4_dsi_video_pipe_queue(0, pipe); } + mdp_update_pm(mfd, vsync_ctrl_db[0].vsync_time); mdp4_overlay_mdp_perf_upd(mfd, 1); cnt = mdp4_dsi_video_pipe_commit(cndx, 0); diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c index d7daa05836d1..c03972056603 100644 --- a/drivers/video/msm/mdp4_overlay_dtv.c +++ b/drivers/video/msm/mdp4_overlay_dtv.c @@ -1068,6 +1068,7 @@ void mdp4_dtv_overlay(struct msm_fb_data_type *mfd) pipe->srcp0_addr = (uint32)mfd->ibuf.buf; mdp4_dtv_pipe_queue(0, pipe); } + mdp_update_pm(mfd, vsync_ctrl_db[0].vsync_time); mdp4_overlay_mdp_perf_upd(mfd, 1); mdp4_dtv_pipe_commit(0, 0); diff --git a/drivers/video/msm/mdp4_overlay_lcdc.c b/drivers/video/msm/mdp4_overlay_lcdc.c index c4e4ad949b2c..2b72613d4347 100644 --- a/drivers/video/msm/mdp4_overlay_lcdc.c +++ b/drivers/video/msm/mdp4_overlay_lcdc.c @@ -971,6 +971,7 @@ void mdp4_lcdc_overlay(struct msm_fb_data_type *mfd) mdp4_lcdc_pipe_queue(0, pipe); } + mdp_update_pm(mfd, vsync_ctrl_db[0].vsync_time); mdp4_overlay_mdp_perf_upd(mfd, 1); diff --git a/drivers/video/msm/msm_fb.h b/drivers/video/msm/msm_fb.h index b8acc6c8e5d2..9504751203c0 100644 --- a/drivers/video/msm/msm_fb.h +++ b/drivers/video/msm/msm_fb.h @@ -37,7 +37,6 @@ #include #include #include - #include #ifdef CONFIG_HAS_EARLYSUSPEND #include @@ -191,6 +190,7 @@ struct msm_fb_data_type { u32 writeback_state; bool writeback_active_cnt; int cont_splash_done; + void *cpu_pm_hdl; u32 acq_fen_cnt; struct sync_fence *acq_fen[MDP_MAX_FENCE_FD]; int cur_rel_fen_fd; diff --git a/drivers/video/msm/msm_fb_panel.h b/drivers/video/msm/msm_fb_panel.h index ef58391c1c3f..311dcd166c49 100644 --- a/drivers/video/msm/msm_fb_panel.h +++ b/drivers/video/msm/msm_fb_panel.h @@ -169,7 +169,7 @@ struct msm_panel_info { __u32 frame_count; __u32 is_3d_panel; __u32 frame_rate; - + __u32 frame_interval; struct mddi_panel_info mddi; struct lcd_panel_info lcd;