msm: display: make pan display as a non-blocking call

Schedule a workqueue, do the current job in the workqueue handler.
Block the second entry if the first one has not finished

Change-Id: I9466c7795bd9d6765f468bf30f4021802d904c36
Signed-off-by: Ken Zhang <kenz@codeaurora.org>

Conflicts:

	drivers/video/msm/msm_fb.c

Signed-off-by: Naseer Ahmed <naseer@codeaurora.org>
This commit is contained in:
Naseer Ahmed 2012-10-01 19:00:22 -04:00 committed by Iliyan Malchev
parent e0501cd8dd
commit c2f0fb04a0
2 changed files with 120 additions and 3 deletions

View file

@ -113,6 +113,8 @@ static int msm_fb_mmap(struct fb_info *info, struct vm_area_struct * vma);
static int mdp_bl_scale_config(struct msm_fb_data_type *mfd,
struct mdp_bl_scale_data *data);
static void msm_fb_scale_bl(__u32 *bl_lvl);
static void msm_fb_commit_wq_handler(struct work_struct *work);
static int msm_fb_pan_idle(struct msm_fb_data_type *mfd);
#ifdef CONFIG_LGE_DISP_FBREAD
static ssize_t msm_fb_read(struct fb_info *info, char __user *buf,
@ -990,7 +992,7 @@ static void msm_fb_fillrect(struct fb_info *info,
const struct fb_fillrect *rect)
{
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
msm_fb_pan_idle(mfd);
cfb_fillrect(info, rect);
if (!mfd->hw_refresh && (info->var.yoffset == 0) &&
!mfd->sw_currently_refreshing) {
@ -1011,6 +1013,7 @@ static void msm_fb_copyarea(struct fb_info *info,
{
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
msm_fb_pan_idle(mfd);
cfb_copyarea(info, area);
if (!mfd->hw_refresh && (info->var.yoffset == 0) &&
!mfd->sw_currently_refreshing) {
@ -1030,6 +1033,7 @@ static void msm_fb_imageblit(struct fb_info *info, const struct fb_image *image)
{
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
msm_fb_pan_idle(mfd);
cfb_imageblit(info, image);
if (!mfd->hw_refresh && (info->var.yoffset == 0) &&
!mfd->sw_currently_refreshing) {
@ -1055,6 +1059,7 @@ static int msm_fb_blank(int blank_mode, struct fb_info *info)
event.data = &blank_mode;
fb_notifier_call_chain(FB_EVENT_BLANK, &event);
}
msm_fb_pan_idle(mfd);
return msm_fb_blank_sub(blank_mode, info, mfd->op_enable);
}
@ -1081,6 +1086,7 @@ static int msm_fb_mmap(struct fb_info *info, struct vm_area_struct * vma)
u32 len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len);
unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
msm_fb_pan_idle(mfd);
if (off >= len) {
/* memory mapped io */
off -= len;
@ -1445,7 +1451,15 @@ static int msm_fb_register(struct msm_fb_data_type *mfd)
mfd->msmfb_no_update_notify_timer.data = (unsigned long)mfd;
init_completion(&mfd->msmfb_update_notify);
init_completion(&mfd->msmfb_no_update_notify);
init_completion(&mfd->commit_comp);
mutex_init(&mfd->sync_mutex);
INIT_WORK(&mfd->commit_work, msm_fb_commit_wq_handler);
mfd->msm_fb_backup = kzalloc(sizeof(struct msm_fb_backup_type),
GFP_KERNEL);
if (mfd->msm_fb_backup == 0) {
pr_err("error: not enough memory!\n");
return -ENOMEM;
}
fbram_offset = PAGE_ALIGN((int)fbram)-(int)fbram;
fbram += fbram_offset;
fbram_phys += fbram_offset;
@ -1772,18 +1786,83 @@ int msm_fb_wait_for_fence(struct msm_fb_data_type *mfd)
}
int msm_fb_signal_timeline(struct msm_fb_data_type *mfd)
{
mutex_lock(&mfd->sync_mutex);
if (mfd->timeline) {
sw_sync_timeline_inc(mfd->timeline, 1);
mfd->timeline_value++;
}
mfd->last_rel_fence = mfd->cur_rel_fence;
mfd->cur_rel_fence = 0;
mutex_unlock(&mfd->sync_mutex);
return 0;
}
DEFINE_SEMAPHORE(msm_fb_pan_sem);
static int msm_fb_pan_idle(struct msm_fb_data_type *mfd)
{
int ret = 0;
mutex_lock(&mfd->sync_mutex);
if (mfd->is_committing) {
mutex_unlock(&mfd->sync_mutex);
ret = wait_for_completion_timeout(&mfd->commit_comp,
msecs_to_jiffies(WAIT_FENCE_TIMEOUT));
if (ret <= 0)
pr_err("%s wait for commit_comp timeout %d %d",
__func__, ret, mfd->is_committing);
} else {
mutex_unlock(&mfd->sync_mutex);
}
return ret;
}
static int msm_fb_pan_display(struct fb_var_screeninfo *var,
struct fb_info *info)
{
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
struct msm_fb_backup_type *fb_backup;
int ret = 0;
/*
* If framebuffer is 2, io pen display is not allowed.
*/
if (bf_supported && info->node == 2) {
pr_err("%s: no pan display for fb%d!",
__func__, info->node);
return -EPERM;
}
if (info->node != 0 || mfd->cont_splash_done) /* primary */
if ((!mfd->op_enable) || (!mfd->panel_power_on))
return -EPERM;
if (var->xoffset > (info->var.xres_virtual - info->var.xres))
return -EINVAL;
if (var->yoffset > (info->var.yres_virtual - info->var.yres))
return -EINVAL;
msm_fb_pan_idle(mfd);
mutex_lock(&mfd->sync_mutex);
if (info->fix.xpanstep)
info->var.xoffset =
(var->xoffset / info->fix.xpanstep) * info->fix.xpanstep;
if (info->fix.ypanstep)
info->var.yoffset =
(var->yoffset / info->fix.ypanstep) * info->fix.ypanstep;
fb_backup = (struct msm_fb_backup_type *)mfd->msm_fb_backup;
memcpy(&fb_backup->info, info, sizeof(struct fb_info));
memcpy(&fb_backup->var, var, sizeof(struct fb_var_screeninfo));
mfd->is_committing = 1;
INIT_COMPLETION(mfd->commit_comp);
schedule_work(&mfd->commit_work);
mutex_unlock(&mfd->sync_mutex);
return ret;
}
static int msm_fb_pan_display_sub(struct fb_var_screeninfo *var,
struct fb_info *info)
{
struct mdp_dirty_region dirty;
struct mdp_dirty_region *dirtyPtr = NULL;
@ -1876,6 +1955,8 @@ static int msm_fb_pan_display(struct fb_var_screeninfo *var,
mdp_set_dma_pan_info(info, dirtyPtr,
(var->activate == FB_ACTIVATE_VBL));
/* async call */
mdp_dma_pan_update(info);
msm_fb_signal_timeline(mfd);
up(&msm_fb_pan_sem);
@ -1897,10 +1978,30 @@ static int msm_fb_pan_display(struct fb_var_screeninfo *var,
return 0;
}
static void msm_fb_commit_wq_handler(struct work_struct *work)
{
struct msm_fb_data_type *mfd;
struct fb_var_screeninfo *var;
struct fb_info *info;
struct msm_fb_backup_type *fb_backup;
mfd = container_of(work, struct msm_fb_data_type, commit_work);
fb_backup = (struct msm_fb_backup_type *)mfd->msm_fb_backup;
var = &fb_backup->var;
info = &fb_backup->info;
msm_fb_pan_display_sub(var, info);
mutex_lock(&mfd->sync_mutex);
mfd->is_committing = 0;
complete_all(&mfd->commit_comp);
mutex_unlock(&mfd->sync_mutex);
}
static int msm_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
msm_fb_pan_idle(mfd);
if (var->rotate != FB_ROTATE_UR)
return -EINVAL;
if (var->grayscale != info->var.grayscale)
@ -2031,7 +2132,7 @@ static int msm_fb_set_par(struct fb_info *info)
struct fb_var_screeninfo *var = &info->var;
int old_imgType;
int blank = 0;
msm_fb_pan_idle(mfd);
old_imgType = mfd->fb_imgType;
switch (var->bits_per_pixel) {
case 16:
@ -3431,6 +3532,7 @@ static int msmfb_handle_buf_sync_ioctl(struct msm_fb_data_type *mfd,
pr_err("%s:copy_from_user failed", __func__);
return ret;
}
mutex_lock(&mfd->sync_mutex);
for (i = 0; i < buf_sync->acq_fen_fd_cnt; i++) {
fence = sync_fence_fdget(acq_fen_fd[i]);
if (fence == NULL) {
@ -3471,6 +3573,7 @@ static int msmfb_handle_buf_sync_ioctl(struct msm_fb_data_type *mfd,
goto buf_sync_err_2;
}
mfd->acq_fen_cnt = buf_sync->acq_fen_fd_cnt;
mutex_unlock(&mfd->sync_mutex);
return ret;
buf_sync_err_2:
sync_fence_put(mfd->cur_rel_fence);
@ -3481,6 +3584,7 @@ buf_sync_err_1:
for (i = 0; i < fence_cnt; i++)
sync_fence_put(mfd->acq_fen[i]);
mfd->acq_fen_cnt = 0;
mutex_unlock(&mfd->sync_mutex);
return ret;
}
static int msm_fb_ioctl(struct fb_info *info, unsigned int cmd,
@ -3502,6 +3606,7 @@ static int msm_fb_ioctl(struct fb_info *info, unsigned int cmd,
struct msmfb_mdp_pp mdp_pp;
struct mdp_buf_sync buf_sync;
int ret = 0;
msm_fb_pan_idle(mfd);
switch (cmd) {
#ifdef CONFIG_FB_MSM_OVERLAY

View file

@ -195,6 +195,18 @@ struct msm_fb_data_type {
struct sync_fence *last_rel_fence;
struct sw_sync_timeline *timeline;
int timeline_value;
u32 last_acq_fen_cnt;
struct sync_fence *last_acq_fen[MDP_MAX_FENCE_FD];
struct mutex sync_mutex;
struct completion commit_comp;
u32 is_committing;
struct work_struct commit_work;
void *msm_fb_backup;
};
struct msm_fb_backup_type {
struct fb_info info;
struct fb_var_screeninfo var;
struct msm_fb_data_type mfd;
};
struct dentry *msm_fb_get_debugfs_root(void);