summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/video/fbdev/msm/mdss_fb.c353
-rw-r--r--drivers/video/fbdev/msm/mdss_fb.h28
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_rotator.c8
3 files changed, 239 insertions, 150 deletions
diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c
index 79291062bccc..731ada82b2c6 100644
--- a/drivers/video/fbdev/msm/mdss_fb.c
+++ b/drivers/video/fbdev/msm/mdss_fb.c
@@ -42,6 +42,7 @@
#include <linux/version.h>
#include <linux/vmalloc.h>
#include <linux/file.h>
+#include <linux/kthread.h>
#include <sync.h>
#include <sw_sync.h>
@@ -89,7 +90,7 @@ 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 int __mdss_fb_display_thread(void *data);
static void mdss_fb_pan_idle(struct msm_fb_data_type *mfd);
static int mdss_fb_send_panel_event(struct msm_fb_data_type *mfd,
int event, void *arg);
@@ -389,8 +390,6 @@ static int mdss_fb_probe(struct platform_device *pdev)
if (mfd->mdp_sync_pt_data.timeline == NULL) {
pr_err("%s: cannot create time line", __func__);
return -ENOMEM;
- } else {
- mfd->mdp_sync_pt_data.timeline_value = 0;
}
}
if (mfd->panel.type == WRITEBACK_PANEL)
@@ -1108,6 +1107,8 @@ static int mdss_fb_register(struct msm_fb_data_type *mfd)
mutex_init(&mfd->update.lock);
mutex_init(&mfd->no_update.lock);
mutex_init(&mfd->mdp_sync_pt_data.sync_mutex);
+ atomic_set(&mfd->mdp_sync_pt_data.commit_cnt, 0);
+ atomic_set(&mfd->commits_pending, 0);
init_timer(&mfd->no_update.timer);
mfd->no_update.timer.function = mdss_fb_no_update_notify_timer_cb;
@@ -1115,15 +1116,9 @@ static int mdss_fb_register(struct msm_fb_data_type *mfd)
init_completion(&mfd->update.comp);
init_completion(&mfd->no_update.comp);
init_completion(&mfd->power_off_comp);
- init_completion(&mfd->commit_comp);
init_completion(&mfd->power_set_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;
- }
+ init_waitqueue_head(&mfd->commit_wait_q);
+ init_waitqueue_head(&mfd->idle_wait_q);
ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
if (ret)
@@ -1140,9 +1135,14 @@ static int mdss_fb_register(struct msm_fb_data_type *mfd)
mfd->index, fbi->var.xres, fbi->var.yres,
fbi->fix.smem_len);
- ret = 0;
+ mfd->disp_thread = kthread_run(__mdss_fb_display_thread, mfd,
+ "mdss_fb%d", mfd->index);
+ if (IS_ERR(mfd->disp_thread)) {
+ pr_err("unable to start display thread %d\n", mfd->index);
+ return PTR_ERR(mfd->disp_thread);
+ }
- return ret;
+ return 0;
}
static int mdss_fb_open(struct fb_info *info, int user)
@@ -1269,87 +1269,123 @@ static void mdss_fb_power_setting_idle(struct msm_fb_data_type *mfd)
}
}
-void mdss_fb_wait_for_fence(struct msm_sync_pt_data *sync_pt_data)
+int mdss_fb_wait_for_fence(struct msm_sync_pt_data *sync_pt_data)
{
+ struct sync_fence *fences[MDP_MAX_FENCE_FD];
+ int fence_cnt;
int i, ret = 0;
+
+ pr_debug("%s: wait for fences\n", sync_pt_data->fence_name);
+
+ mutex_lock(&sync_pt_data->sync_mutex);
+ /*
+ * Assuming that acq_fen_cnt is sanitized in bufsync ioctl
+ * to check for sync_pt_data->acq_fen_cnt <= MDP_MAX_FENCE_FD
+ */
+ fence_cnt = sync_pt_data->acq_fen_cnt;
+ sync_pt_data->acq_fen_cnt = 0;
+ if (fence_cnt)
+ memcpy(fences, sync_pt_data->acq_fen,
+ fence_cnt * sizeof(struct sync_fence *));
+ mutex_unlock(&sync_pt_data->sync_mutex);
+
/* buf sync */
- for (i = 0; i < sync_pt_data->acq_fen_cnt; i++) {
- ret = sync_fence_wait(sync_pt_data->acq_fen[i],
+ for (i = 0; i < fence_cnt && !ret; i++) {
+ ret = sync_fence_wait(fences[i],
WAIT_FENCE_FIRST_TIMEOUT);
if (ret == -ETIME) {
- pr_warn("sync_fence_wait timed out! ");
+ pr_warn("%s: sync_fence_wait timed out! ",
+ sync_pt_data->fence_name);
pr_cont("Waiting %ld more seconds\n",
WAIT_FENCE_FINAL_TIMEOUT/MSEC_PER_SEC);
- ret = sync_fence_wait(sync_pt_data->acq_fen[i],
+ ret = sync_fence_wait(fences[i],
WAIT_FENCE_FINAL_TIMEOUT);
}
- if (ret < 0) {
- pr_err("%s: sync_fence_wait failed! ret = %x\n",
- __func__, ret);
- break;
- }
- sync_fence_put(sync_pt_data->acq_fen[i]);
+ sync_fence_put(fences[i]);
}
if (ret < 0) {
- while (i < sync_pt_data->acq_fen_cnt) {
- sync_fence_put(sync_pt_data->acq_fen[i]);
- i++;
- }
+ pr_err("%s: sync_fence_wait failed! ret = %x\n",
+ sync_pt_data->fence_name, ret);
+ for (; i < fence_cnt; i++)
+ sync_fence_put(fences[i]);
}
- sync_pt_data->acq_fen_cnt = 0;
-}
-static void mdss_fb_signal_timeline_locked(
- struct msm_sync_pt_data *sync_pt_data)
-{
- if (sync_pt_data->timeline && !list_empty((const struct list_head *)
- (&(sync_pt_data->timeline->obj.active_list_head)))) {
- sw_sync_timeline_inc(sync_pt_data->timeline, 1);
- sync_pt_data->timeline_value++;
- }
- sync_pt_data->cur_rel_fence = 0;
+ return fence_cnt;
}
+/**
+ * mdss_fb_signal_timeline() - signal a single release fence
+ * @sync_pt_data: Sync point data structure for the timeline which
+ * should be signaled.
+ *
+ * This is called after a frame has been pushed to display. This signals the
+ * timeline to release the fences associated with this frame.
+ */
void mdss_fb_signal_timeline(struct msm_sync_pt_data *sync_pt_data)
{
mutex_lock(&sync_pt_data->sync_mutex);
- mdss_fb_signal_timeline_locked(sync_pt_data);
+ if (atomic_add_unless(&sync_pt_data->commit_cnt, -1, 0) &&
+ sync_pt_data->timeline) {
+ sw_sync_timeline_inc(sync_pt_data->timeline, 1);
+ sync_pt_data->timeline_value++;
+
+ pr_debug("%s: buffer signaled! timeline val=%d remaining=%d\n",
+ sync_pt_data->fence_name, sync_pt_data->timeline_value,
+ atomic_read(&sync_pt_data->commit_cnt));
+ } else {
+ pr_debug("%s timeline signaled without commits val=%d\n",
+ sync_pt_data->fence_name, sync_pt_data->timeline_value);
+ }
mutex_unlock(&sync_pt_data->sync_mutex);
}
+/**
+ * mdss_fb_release_fences() - signal all pending release fences
+ * @mfd: Framebuffer data structure for display
+ *
+ * Release all currently pending release fences, including those that are in
+ * the process to be commited.
+ *
+ * Note: this should only be called during close or suspend sequence.
+ */
static void mdss_fb_release_fences(struct msm_fb_data_type *mfd)
{
+ struct msm_sync_pt_data *sync_pt_data = &mfd->mdp_sync_pt_data;
+ int val;
- mutex_lock(&mfd->mdp_sync_pt_data.sync_mutex);
- if (mfd->mdp_sync_pt_data.timeline) {
- sw_sync_timeline_inc(mfd->mdp_sync_pt_data.timeline, 2);
- mfd->mdp_sync_pt_data.timeline_value += 2;
+ mutex_lock(&sync_pt_data->sync_mutex);
+ if (sync_pt_data->timeline) {
+ val = sync_pt_data->threshold +
+ atomic_read(&sync_pt_data->commit_cnt);
+ sw_sync_timeline_inc(sync_pt_data->timeline, val);
+ sync_pt_data->timeline_value += val;
+ atomic_set(&sync_pt_data->commit_cnt, 0);
}
- mfd->mdp_sync_pt_data.cur_rel_fence = 0;
- mutex_unlock(&mfd->mdp_sync_pt_data.sync_mutex);
+ mutex_unlock(&sync_pt_data->sync_mutex);
}
+
+/**
+ * mdss_fb_pan_idle() - wait for panel programming to be idle
+ * @mfd: Framebuffer data structure for display
+ *
+ * Wait for any pending programming to be done if in the process of programming
+ * hardware configuration. After this function returns it is safe to perform
+ * software updates for next frame.
+ */
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,
+ ret = wait_event_timeout(mfd->idle_wait_q,
+ !atomic_read(&mfd->commits_pending),
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->mdp_sync_pt_data.sync_mutex);
- mdss_fb_signal_timeline_locked(&mfd->mdp_sync_pt_data);
- mfd->is_committing = 0;
- complete_all(&mfd->commit_comp);
- mutex_unlock(&mfd->mdp_sync_pt_data.sync_mutex);
- }
+ if (!ret) {
+ pr_err("wait for idle timeout %d pending=%d\n",
+ ret, atomic_read(&mfd->commits_pending));
+
+ mdss_fb_signal_timeline(&mfd->mdp_sync_pt_data);
}
}
@@ -1357,7 +1393,6 @@ 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;
@@ -1382,13 +1417,12 @@ static int mdss_fb_pan_display_ex(struct fb_info *info,
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);
+ mfd->msm_fb_backup.info = *info;
+ mfd->msm_fb_backup.disp_commit = *disp_commit;
+
+ atomic_inc(&mfd->mdp_sync_pt_data.commit_cnt);
+ atomic_inc(&mfd->commits_pending);
+ wake_up_all(&mfd->commit_wait_q);
mutex_unlock(&mfd->mdp_sync_pt_data.sync_mutex);
if (wait_for_finish)
mdss_fb_pan_idle(mfd);
@@ -1427,14 +1461,12 @@ static int mdss_fb_pan_display_sub(struct fb_var_screeninfo *var,
info->var.yoffset =
(var->yoffset / info->fix.ypanstep) * info->fix.ypanstep;
- mdss_fb_wait_for_fence(&mfd->mdp_sync_pt_data);
if (mfd->mdp.dma_fnc)
mfd->mdp.dma_fnc(mfd);
else
pr_warn("dma function not set for panel type=%d\n",
mfd->panel.type);
- mdss_fb_signal_timeline(&mfd->mdp_sync_pt_data);
- mdss_fb_update_backlight(mfd);
+
return 0;
}
@@ -1452,36 +1484,59 @@ static void mdss_fb_var_to_panelinfo(struct fb_var_screeninfo *var,
pinfo->clk_rate = var->pixclock;
}
-static void mdss_fb_commit_wq_handler(struct work_struct *work)
+/**
+ * __mdss_fb_perform_commit() - process a frame to display
+ * @mfd: Framebuffer data structure for display
+ *
+ * Processes all layers and buffers programmed and ensures all pending release
+ * fences are signaled once the buffer is transfered to display.
+ */
+static int __mdss_fb_perform_commit(struct msm_fb_data_type *mfd)
{
- struct msm_fb_data_type *mfd;
- struct fb_var_screeninfo *var;
- struct fb_info *info;
- struct msm_fb_backup_type *fb_backup;
- int ret = 0;
+ struct msm_sync_pt_data *sync_pt_data = &mfd->mdp_sync_pt_data;
+ struct msm_fb_backup_type *fb_backup = &mfd->msm_fb_backup;
+ int ret = -ENOSYS;
+
+ mdss_fb_wait_for_fence(sync_pt_data);
- 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->mdp_sync_pt_data);
+ if (fb_backup->disp_commit.flags & MDP_DISPLAY_COMMIT_OVERLAY) {
if (mfd->mdp.kickoff_fnc)
ret = mfd->mdp.kickoff_fnc(mfd,
- &fb_backup->disp_commit);
- if (!ret)
- mdss_fb_update_backlight(mfd);
- mdss_fb_signal_timeline(&mfd->mdp_sync_pt_data);
+ &fb_backup->disp_commit);
+ else
+ pr_warn("no kickoff function setup for fb%d\n",
+ mfd->index);
} else {
- var = &fb_backup->disp_commit.var;
- ret = mdss_fb_pan_display_sub(var, info);
+ ret = mdss_fb_pan_display_sub(&fb_backup->disp_commit.var,
+ &fb_backup->info);
if (ret)
- pr_err("%s fails: ret = %x", __func__, ret);
+ pr_err("pan display failed %x on fb%d\n", ret,
+ mfd->index);
}
- mutex_lock(&mfd->mdp_sync_pt_data.sync_mutex);
- mfd->is_committing = 0;
- complete_all(&mfd->commit_comp);
- mutex_unlock(&mfd->mdp_sync_pt_data.sync_mutex);
+ if (!ret)
+ mdss_fb_update_backlight(mfd);
+
+ mdss_fb_signal_timeline(sync_pt_data);
+
+ return ret;
+}
+
+static int __mdss_fb_display_thread(void *data)
+{
+ struct msm_fb_data_type *mfd = data;
+ int ret;
+
+ while (1) {
+ wait_event(mfd->commit_wait_q,
+ atomic_read(&mfd->commits_pending));
+
+ ret = __mdss_fb_perform_commit(mfd);
+
+ atomic_dec(&mfd->commits_pending);
+ wake_up_all(&mfd->idle_wait_q);
+ }
+
+ return ret;
}
static int mdss_fb_check_var(struct fb_var_screeninfo *var,
@@ -1753,12 +1808,52 @@ static int mdss_fb_set_lut(struct fb_info *info, void __user *p)
return 0;
}
+/**
+ * mdss_fb_sync_get_rel_fence() - get release fence from sync pt timeline
+ * @sync_pt_data: Sync pt structure holding timeline and fence info.
+ *
+ * Function returns a release fence on the timeline associated with the
+ * sync pt struct given and it's associated information. The release fence
+ * created can be used to signal when buffers provided will be released.
+ */
+static struct sync_fence *__mdss_fb_sync_get_rel_fence(
+ struct msm_sync_pt_data *sync_pt_data)
+{
+ struct sync_pt *rel_sync_pt;
+ struct sync_fence *rel_fence;
+ int val;
+
+ val = sync_pt_data->timeline_value + sync_pt_data->threshold +
+ atomic_read(&sync_pt_data->commit_cnt);
+
+ pr_debug("%s: buf sync rel fence timeline=%d\n",
+ sync_pt_data->fence_name, val);
+
+ rel_sync_pt = sw_sync_pt_create(sync_pt_data->timeline, val);
+ if (rel_sync_pt == NULL) {
+ pr_err("%s: cannot create sync point\n",
+ sync_pt_data->fence_name);
+ return NULL;
+ }
+
+ /* create fence */
+ rel_fence = sync_fence_create(sync_pt_data->fence_name, rel_sync_pt);
+ if (rel_fence == NULL) {
+ sync_pt_free(rel_sync_pt);
+ pr_err("%s: cannot create fence\n", sync_pt_data->fence_name);
+ return NULL;
+ }
+
+ return rel_fence;
+}
+
static int mdss_fb_handle_buf_sync_ioctl(struct msm_sync_pt_data *sync_pt_data,
struct mdp_buf_sync *buf_sync)
{
int i, ret = 0;
int acq_fen_fd[MDP_MAX_FENCE_FD];
- struct sync_fence *fence;
+ struct sync_fence *fence, *rel_fence;
+ int rel_fen_fd;
if ((buf_sync->acq_fen_fd_cnt > MDP_MAX_FENCE_FD) ||
(sync_pt_data->timeline == NULL))
@@ -1768,16 +1863,22 @@ static int mdss_fb_handle_buf_sync_ioctl(struct msm_sync_pt_data *sync_pt_data,
ret = copy_from_user(acq_fen_fd, buf_sync->acq_fen_fd,
buf_sync->acq_fen_fd_cnt * sizeof(int));
if (ret) {
- pr_err("%s:copy_from_user failed", __func__);
+ pr_err("%s: copy_from_user failed", sync_pt_data->fence_name);
return ret;
}
+ i = mdss_fb_wait_for_fence(sync_pt_data);
+ if (i > 0)
+ pr_warn("%s: waited on %d active fences\n",
+ sync_pt_data->fence_name, i);
+
mutex_lock(&sync_pt_data->sync_mutex);
for (i = 0; i < buf_sync->acq_fen_fd_cnt; i++) {
fence = sync_fence_fdget(acq_fen_fd[i]);
if (fence == NULL) {
- pr_info("%s: null fence! i=%d fd=%d\n", __func__, i,
- acq_fen_fd[i]);
+ pr_err("%s: null fence! i=%d fd=%d\n",
+ sync_pt_data->fence_name, i,
+ acq_fen_fd[i]);
ret = -EINVAL;
break;
}
@@ -1787,54 +1888,40 @@ static int mdss_fb_handle_buf_sync_ioctl(struct msm_sync_pt_data *sync_pt_data,
if (ret)
goto buf_sync_err_1;
- if (buf_sync->flags & MDP_BUF_SYNC_FLAG_WAIT)
- mdss_fb_wait_for_fence(sync_pt_data);
-
- sync_pt_data->cur_rel_sync_pt = sw_sync_pt_create(
- sync_pt_data->timeline, sync_pt_data->timeline_value +
- sync_pt_data->threshold);
-
- if (sync_pt_data->cur_rel_sync_pt == NULL) {
- pr_err("%s: cannot create sync point", __func__);
- ret = -ENOMEM;
- goto buf_sync_err_1;
- }
- /* create fence */
- sync_pt_data->cur_rel_fence = sync_fence_create(
- sync_pt_data->fence_name, sync_pt_data->cur_rel_sync_pt);
-
- if (sync_pt_data->cur_rel_fence == NULL) {
- sync_pt_free(sync_pt_data->cur_rel_sync_pt);
- sync_pt_data->cur_rel_sync_pt = NULL;
- pr_err("%s: cannot create fence", __func__);
- ret = -ENOMEM;
+ rel_fence = __mdss_fb_sync_get_rel_fence(sync_pt_data);
+ if (IS_ERR_OR_NULL(rel_fence)) {
+ pr_err("%s: unable to retrieve release fence\n",
+ sync_pt_data->fence_name);
+ ret = rel_fence ? PTR_ERR(rel_fence) : -ENOMEM;
goto buf_sync_err_1;
}
+
/* create fd */
- sync_pt_data->cur_rel_fen_fd = get_unused_fd_flags(0);
- if (sync_pt_data->cur_rel_fen_fd < 0) {
- pr_err("%s: get_unused_fd_flags failed", __func__);
- ret = -EIO;
+ rel_fen_fd = get_unused_fd_flags(0);
+ if (rel_fen_fd < 0) {
+ pr_err("%s: get_unused_fd_flags failed\n",
+ sync_pt_data->fence_name);
+ ret = -EIO;
goto buf_sync_err_2;
}
- sync_fence_install(sync_pt_data->cur_rel_fence,
- sync_pt_data->cur_rel_fen_fd);
- ret = copy_to_user(buf_sync->rel_fen_fd,
- &sync_pt_data->cur_rel_fen_fd, sizeof(int));
+ sync_fence_install(rel_fence, rel_fen_fd);
+ ret = copy_to_user(buf_sync->rel_fen_fd, &rel_fen_fd, sizeof(int));
if (ret) {
- pr_err("%s:copy_to_user failed", __func__);
+ pr_err("%s: copy_to_user failed\n", sync_pt_data->fence_name);
goto buf_sync_err_3;
}
mutex_unlock(&sync_pt_data->sync_mutex);
+
+ if (buf_sync->flags & MDP_BUF_SYNC_FLAG_WAIT)
+ mdss_fb_wait_for_fence(sync_pt_data);
+
return ret;
buf_sync_err_3:
- put_unused_fd(sync_pt_data->cur_rel_fen_fd);
+ put_unused_fd(rel_fen_fd);
buf_sync_err_2:
- sync_fence_put(sync_pt_data->cur_rel_fence);
- sync_pt_data->cur_rel_fence = NULL;
- sync_pt_data->cur_rel_fen_fd = 0;
+ sync_fence_put(rel_fence);
buf_sync_err_1:
for (i = 0; i < sync_pt_data->acq_fen_cnt; i++)
sync_fence_put(sync_pt_data->acq_fen[i]);
diff --git a/drivers/video/fbdev/msm/mdss_fb.h b/drivers/video/fbdev/msm/mdss_fb.h
index 8611bc5c3882..8d1099376ce8 100644
--- a/drivers/video/fbdev/msm/mdss_fb.h
+++ b/drivers/video/fbdev/msm/mdss_fb.h
@@ -60,12 +60,12 @@ struct msm_sync_pt_data {
char *fence_name;
u32 acq_fen_cnt;
struct sync_fence *acq_fen[MDP_MAX_FENCE_FD];
- int cur_rel_fen_fd;
- struct sync_pt *cur_rel_sync_pt;
- struct sync_fence *cur_rel_fence;
+
struct sw_sync_timeline *timeline;
int timeline_value;
u32 threshold;
+
+ atomic_t commit_cnt;
struct mutex sync_mutex;
};
@@ -108,6 +108,11 @@ struct mdss_fb_proc_info {
struct list_head list;
};
+struct msm_fb_backup_type {
+ struct fb_info info;
+ struct mdp_display_commit disp_commit;
+};
+
struct msm_fb_data_type {
u32 key;
u32 index;
@@ -162,10 +167,12 @@ struct msm_fb_data_type {
struct msm_sync_pt_data mdp_sync_pt_data;
/* for non-blocking */
- struct completion commit_comp;
- u32 is_committing;
- struct work_struct commit_work;
- void *msm_fb_backup;
+ struct task_struct *disp_thread;
+ atomic_t commits_pending;
+ wait_queue_head_t commit_wait_q;
+ wait_queue_head_t idle_wait_q;
+
+ struct msm_fb_backup_type msm_fb_backup;
struct completion power_set_comp;
u32 is_power_setting;
@@ -173,11 +180,6 @@ struct msm_fb_data_type {
struct list_head proc_list;
};
-struct msm_fb_backup_type {
- struct fb_info info;
- struct mdp_display_commit disp_commit;
-};
-
static inline void mdss_fb_update_notify_update(struct msm_fb_data_type *mfd)
{
int needs_complete = 0;
@@ -200,7 +202,7 @@ static inline void mdss_fb_update_notify_update(struct msm_fb_data_type *mfd)
int mdss_fb_get_phys_info(dma_addr_t *start, unsigned long *len, int fb_num);
void mdss_fb_set_backlight(struct msm_fb_data_type *mfd, u32 bkl_lvl);
void mdss_fb_update_backlight(struct msm_fb_data_type *mfd);
-void mdss_fb_wait_for_fence(struct msm_sync_pt_data *sync_pt_data);
+int mdss_fb_wait_for_fence(struct msm_sync_pt_data *sync_pt_data);
void mdss_fb_signal_timeline(struct msm_sync_pt_data *sync_pt_data);
int mdss_fb_register_mdp_instance(struct msm_mdp_interface *mdp);
int mdss_fb_dcm(struct msm_fb_data_type *mfd, int req_state);
diff --git a/drivers/video/fbdev/msm/mdss_mdp_rotator.c b/drivers/video/fbdev/msm/mdss_mdp_rotator.c
index c6d5bc21484f..6ce8f924bc72 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_rotator.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_rotator.c
@@ -277,12 +277,12 @@ static void mdss_mdp_rotator_commit_wq_handler(struct work_struct *work)
int ret;
rot = container_of(work, struct mdss_mdp_rotator_session, commit_work);
- ret = mdss_mdp_rotator_queue_helper(rot);
- if (ret) {
+ atomic_inc(&rot->rot_sync_pt_data->commit_cnt);
+
+ ret = mdss_mdp_rotator_queue_helper(rot);
+ if (ret)
pr_err("rotator queue failed\n");
- return;
- }
if (rot->rot_sync_pt_data)
mdss_fb_signal_timeline(rot->rot_sync_pt_data);