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 <kenz@codeaurora.org>
Signed-off-by: Huaibin Yang <huaibiny@codeaurora.org>
This commit is contained in:
Ken Zhang 2012-09-05 15:43:02 -07:00 committed by Stephen Boyd
parent 69b8f54698
commit 82c6b4cdd7
8 changed files with 64 additions and 4 deletions

View file

@ -35,6 +35,7 @@
#include <asm/mach-types.h>
#include <linux/semaphore.h>
#include <linux/uaccess.h>
#include <mach/event_timer.h>
#include <mach/clk.h>
#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

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -37,7 +37,6 @@
#include <linux/fb.h>
#include <linux/list.h>
#include <linux/types.h>
#include <linux/msm_mdp.h>
#ifdef CONFIG_HAS_EARLYSUSPEND
#include <linux/earlysuspend.h>
@ -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;

View file

@ -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;