diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c index 991ddc7eae1a..d2e3a46460ce 100644 --- a/drivers/video/fbdev/msm/mdss_fb.c +++ b/drivers/video/fbdev/msm/mdss_fb.c @@ -2727,6 +2727,15 @@ static int mdss_fb_pan_display_ex(struct fb_info *info, return ret; } + if (mfd->mdp.pre_commit_fnc) { + ret = mfd->mdp.pre_commit_fnc(mfd); + if (ret) { + pr_err("fb%d: pre commit failed %d\n", + mfd->index, ret); + return ret; + } + } + mutex_lock(&mfd->mdp_sync_pt_data.sync_mutex); if (info->fix.xpanstep) info->var.xoffset = diff --git a/drivers/video/fbdev/msm/mdss_fb.h b/drivers/video/fbdev/msm/mdss_fb.h index 2763f330d9b1..0b9ad9125cba 100644 --- a/drivers/video/fbdev/msm/mdss_fb.h +++ b/drivers/video/fbdev/msm/mdss_fb.h @@ -199,6 +199,7 @@ struct msm_mdp_interface { struct mdp_layer_commit_v1 *commit); int (*pre_commit)(struct msm_fb_data_type *mfd, struct mdp_layer_commit_v1 *commit); + int (*pre_commit_fnc)(struct msm_fb_data_type *mfd); int (*ioctl_handler)(struct msm_fb_data_type *mfd, u32 cmd, void *arg); void (*dma_fnc)(struct msm_fb_data_type *mfd); int (*cursor_update)(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 09d15156154d..1e0a80bb6336 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c +++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c @@ -1370,6 +1370,13 @@ static int __overlay_queue_pipes(struct msm_fb_data_type *mfd) list_for_each_entry(pipe, &mdp5_data->pipes_used, list) { struct mdss_mdp_data *buf; + + if (pipe->dirty) { + pr_err("fb%d: pipe %d dirty! skipping configuration\n", + mfd->index, pipe->num); + continue; + } + /* * When secure display is enabled, if there is a non secure * display pipe, skip that @@ -1472,6 +1479,7 @@ static int __overlay_queue_pipes(struct msm_fb_data_type *mfd) pipe->num); mdss_mdp_mixer_pipe_unstage(pipe, pipe->mixer_left); mdss_mdp_mixer_pipe_unstage(pipe, pipe->mixer_right); + pipe->dirty = true; if (buf) __pipe_buf_mark_cleanup(mfd, buf); @@ -3627,6 +3635,56 @@ static int mdss_fb_get_metadata(struct msm_fb_data_type *mfd, return ret; } +static int __mdss_mdp_clean_dirty_pipes(struct msm_fb_data_type *mfd) +{ + struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); + struct mdss_mdp_pipe *pipe; + int unset_ndx = 0; + + mutex_lock(&mdp5_data->list_lock); + list_for_each_entry(pipe, &mdp5_data->pipes_used, list) { + if (pipe->dirty) + unset_ndx |= pipe->ndx; + } + mutex_unlock(&mdp5_data->list_lock); + if (unset_ndx) + mdss_mdp_overlay_release(mfd, unset_ndx); + + return unset_ndx; +} + +static int mdss_mdp_overlay_precommit(struct msm_fb_data_type *mfd) +{ + struct mdss_overlay_private *mdp5_data; + int ret; + + if (!mfd) + return -ENODEV; + + mdp5_data = mfd_to_mdp5_data(mfd); + if (!mdp5_data) + return -ENODEV; + + ret = mutex_lock_interruptible(&mdp5_data->ov_lock); + if (ret) + return ret; + + /* + * we can assume that any pipes that are still dirty at this point are + * not properly tracked by user land. This could be for any reason, + * mark them for cleanup at this point. + */ + ret = __mdss_mdp_clean_dirty_pipes(mfd); + if (ret) { + pr_warn("fb%d: dirty pipes remaining %x\n", + mfd->index, ret); + ret = -EPIPE; + } + mutex_unlock(&mdp5_data->ov_lock); + + return ret; +} + /* * This routine serves two purposes. * 1. Propagate overlay_id returned from sorted list to original list @@ -4649,6 +4707,7 @@ int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd) mdp5_interface->mode_switch = mdss_mode_switch; mdp5_interface->pend_mode_switch = mdss_pend_mode_switch; mdp5_interface->mode_switch_post = mdss_mode_switch_post; + mdp5_interface->pre_commit_fnc = mdss_mdp_overlay_precommit; mdp5_interface->get_sync_fnc = mdss_mdp_rotator_sync_pt_get; mdp5_interface->splash_init_fnc = mdss_mdp_splash_init; mdp5_interface->configure_panel = mdss_mdp_update_panel_info;