diff options
| author | Ken Zhang <kenz@codeaurora.org> | 2012-12-02 21:15:47 -0500 |
|---|---|---|
| committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-23 20:13:54 -0700 |
| commit | ab9f9179e2ec58771e05962e3e6df091be3365d7 (patch) | |
| tree | 784ff7520608cece8069741d70501a048f5a1dcd | |
| parent | 9bc30b3c612e8c326ae1a1378c00130c909fd0b3 (diff) | |
msm: mdss: Non-blocking display commit
Schedule a workqueue, do the current job in the workqueue handler.
Block the second entry if the first one has not finished
Display commit ioctl will do what pan_display
can do, addtionally has customized setting, such
as non-blocking call
Change-Id: Iccced7d7540c6a8bb066f58fa245bbff5ed36fcb
Signed-off-by: Ken Zhang <kenz@codeaurora.org>
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_fb.c | 140 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_fb.h | 12 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp.h | 1 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_overlay.c | 2 |
4 files changed, 152 insertions, 3 deletions
diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c index 23bf58aa7757..62d29d27439a 100644 --- a/drivers/video/fbdev/msm/mdss_fb.c +++ b/drivers/video/fbdev/msm/mdss_fb.c @@ -86,6 +86,9 @@ static int mdss_fb_ioctl(struct fb_info *info, unsigned int cmd, static int mdss_fb_mmap(struct fb_info *info, struct vm_area_struct *vma); static void mdss_fb_release_fences(struct msm_fb_data_type *mfd); +static void mdss_fb_commit_wq_handler(struct work_struct *work); +static void mdss_fb_pan_idle(struct msm_fb_data_type *mfd); + void mdss_fb_no_update_notify_timer_cb(unsigned long data) { struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)data; @@ -358,6 +361,7 @@ static int mdss_fb_suspend_sub(struct msm_fb_data_type *mfd) pr_debug("mdss_fb suspend index=%d\n", mfd->index); + mdss_fb_pan_idle(mfd); ret = mdss_fb_send_panel_event(mfd, MDSS_EVENT_SUSPEND, NULL); if (ret) { pr_warn("unable to suspend fb%d (%d)\n", mfd->index, ret); @@ -392,6 +396,7 @@ static int mdss_fb_resume_sub(struct msm_fb_data_type *mfd) pr_debug("mdss_fb resume index=%d\n", mfd->index); + mdss_fb_pan_idle(mfd); ret = mdss_fb_send_panel_event(mfd, MDSS_EVENT_RESUME, NULL); if (ret) { pr_warn("unable to resume fb%d (%d)\n", mfd->index, ret); @@ -595,6 +600,7 @@ static int mdss_fb_blank_sub(int blank_mode, struct fb_info *info, static int mdss_fb_blank(int blank_mode, struct fb_info *info) { struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + mdss_fb_pan_idle(mfd); return mdss_fb_blank_sub(blank_mode, info, mfd->op_enable); } @@ -611,6 +617,7 @@ static int mdss_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) unsigned long off = vma->vm_pgoff << PAGE_SHIFT; struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + mdss_fb_pan_idle(mfd); if (off >= len) { /* memory mapped io */ off -= len; @@ -914,7 +921,14 @@ static int mdss_fb_register(struct msm_fb_data_type *mfd) mfd->no_update.timer.data = (unsigned long)mfd; init_completion(&mfd->update.comp); init_completion(&mfd->no_update.comp); - + init_completion(&mfd->commit_comp); + INIT_WORK(&mfd->commit_work, mdss_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; + } if (mfd->lut_update) { ret = fb_alloc_cmap(&fbi->cmap, 256, 0); if (ret) @@ -972,6 +986,7 @@ static int mdss_fb_release(struct fb_info *info, int user) return -EINVAL; } + mdss_fb_pan_idle(mfd); mfd->ref_cnt--; if (!mfd->ref_cnt) { @@ -1026,7 +1041,81 @@ static void mdss_fb_release_fences(struct msm_fb_data_type *mfd) mfd->cur_rel_fence = 0; mutex_unlock(&mfd->sync_mutex); } + +static void mdss_fb_pan_idle(struct msm_fb_data_type *mfd) +{ + int ret; + + if (mfd->is_committing) { + ret = wait_for_completion_timeout( + &mfd->commit_comp, + msecs_to_jiffies(WAIT_DISP_OP_TIMEOUT)); + if (ret < 0) + ret = -ERESTARTSYS; + else if (!ret) + pr_err("%s wait for commit_comp timeout %d %d", + __func__, ret, mfd->is_committing); + if (ret <= 0) { + mutex_lock(&mfd->sync_mutex); + mfd->is_committing = 0; + complete_all(&mfd->commit_comp); + mutex_unlock(&mfd->sync_mutex); + } + } +} + +static int mdss_fb_pan_display_ex(struct fb_info *info, + struct mdp_display_commit *disp_commit) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + struct msm_fb_backup_type *fb_backup; + struct fb_var_screeninfo *var = &disp_commit->var; + u32 wait_for_finish = disp_commit->wait_for_finish; + int ret = 0; + + 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; + + mdss_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->disp_commit, disp_commit, + sizeof(struct mdp_display_commit)); + INIT_COMPLETION(mfd->commit_comp); + mfd->is_committing = 1; + schedule_work(&mfd->commit_work); + mutex_unlock(&mfd->sync_mutex); + if (wait_for_finish) + mdss_fb_pan_idle(mfd); + return ret; +} + static int mdss_fb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct mdp_display_commit disp_commit; + memset(&disp_commit, 0, sizeof(disp_commit)); + disp_commit.wait_for_finish = true; + return mdss_fb_pan_display_ex(info, &disp_commit); +} + +static int mdss_fb_pan_display_sub(struct fb_var_screeninfo *var, struct fb_info *info) { struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; @@ -1075,6 +1164,34 @@ static void mdss_fb_var_to_panelinfo(struct fb_var_screeninfo *var, pinfo->vic = var->reserved[3]; } +static void mdss_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; + int ret; + + mfd = container_of(work, struct msm_fb_data_type, commit_work); + fb_backup = (struct msm_fb_backup_type *)mfd->msm_fb_backup; + info = &fb_backup->info; + if (fb_backup->disp_commit.flags & + MDP_DISPLAY_COMMIT_OVERLAY) { + mdss_fb_wait_for_fence(mfd); + mdss_mdp_overlay_kickoff(mfd->ctl); + mdss_fb_signal_timeline(mfd); + } else { + var = &fb_backup->disp_commit.var; + ret = mdss_fb_pan_display_sub(var, info); + if (ret) + pr_err("%s fails: ret = %x", __func__, ret); + } + mutex_lock(&mfd->sync_mutex); + mfd->is_committing = 0; + complete_all(&mfd->commit_comp); + mutex_unlock(&mfd->sync_mutex); +} + static int mdss_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { @@ -1195,6 +1312,7 @@ static int mdss_fb_set_par(struct fb_info *info) struct fb_var_screeninfo *var = &info->var; int old_imgType; + mdss_fb_pan_idle(mfd); old_imgType = mfd->fb_imgType; switch (var->bits_per_pixel) { case 16: @@ -1425,7 +1543,20 @@ buf_sync_err_1: mutex_unlock(&mfd->sync_mutex); return ret; } - +static int mdss_fb_display_commit(struct fb_info *info, + unsigned long *argp) +{ + int ret; + struct mdp_display_commit disp_commit; + ret = copy_from_user(&disp_commit, argp, + sizeof(disp_commit)); + if (ret) { + pr_err("%s:copy_from_user failed", __func__); + return ret; + } + ret = mdss_fb_pan_display_ex(info, &disp_commit); + return ret; +} static int mdss_fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) { @@ -1438,6 +1569,7 @@ static int mdss_fb_ioctl(struct fb_info *info, unsigned int cmd, int ret = -ENOSYS; struct mdp_buf_sync buf_sync; + mdss_fb_pan_idle(mfd); switch (cmd) { case MSMFB_CURSOR: ret = mdss_fb_cursor(info, argp); @@ -1512,6 +1644,10 @@ static int mdss_fb_ioctl(struct fb_info *info, unsigned int cmd, ret = mdss_fb_notify_update(mfd, argp); break; + case MSMFB_DISPLAY_COMMIT: + ret = mdss_fb_display_commit(info, argp); + break; + default: if (mfd->ioctl_handler) ret = mfd->ioctl_handler(mfd, cmd, argp); diff --git a/drivers/video/fbdev/msm/mdss_fb.h b/drivers/video/fbdev/msm/mdss_fb.h index 0c82e273e6eb..f0489d564a84 100644 --- a/drivers/video/fbdev/msm/mdss_fb.h +++ b/drivers/video/fbdev/msm/mdss_fb.h @@ -29,6 +29,8 @@ #define MSM_FB_ENABLE_DBGFS /* 900 ms for fence time out */ #define WAIT_FENCE_TIMEOUT 900 +/* 950 ms for display operation time out */ +#define WAIT_DISP_OP_TIMEOUT 950 #ifndef MAX #define MAX(x, y) (((x) > (y)) ? (x) : (y)) @@ -125,6 +127,16 @@ struct msm_fb_data_type { u32 last_acq_fen_cnt; struct sync_fence *last_acq_fen[MDP_MAX_FENCE_FD]; struct mutex sync_mutex; + /* for non-blocking */ + 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 mdp_display_commit disp_commit; }; int mdss_fb_get_phys_info(unsigned long *start, unsigned long *len, int fb_num); diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h index d93978fb8266..9242564c24e9 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.h +++ b/drivers/video/fbdev/msm/mdss_mdp.h @@ -291,6 +291,7 @@ int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd); int mdss_mdp_overlay_vsync_ctrl(struct msm_fb_data_type *mfd, int en); int mdss_mdp_video_start(struct mdss_mdp_ctl *ctl); int mdss_mdp_writeback_start(struct mdss_mdp_ctl *ctl); +int mdss_mdp_overlay_kickoff(struct mdss_mdp_ctl *ctl); int mdss_mdp_ctl_on(struct msm_fb_data_type *mfd); int mdss_mdp_ctl_off(struct msm_fb_data_type *mfd); diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c index e242bbbe276b..8c9fc9602ea9 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c +++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c @@ -452,7 +452,7 @@ static int mdss_mdp_overlay_cleanup(struct msm_fb_data_type *mfd) return 0; } -static int mdss_mdp_overlay_kickoff(struct mdss_mdp_ctl *ctl) +int mdss_mdp_overlay_kickoff(struct mdss_mdp_ctl *ctl) { struct msm_fb_data_type *mfd = ctl->mfd; int ret; |
