Samsung SPH-L720 (Sprint) source updates
/drivers/video/msm/mdp4_overlay_lcdc.c
blob:e47eba0839e844b7ad019d52507dab721cb593f7 -> blob:caea7e1c193acecc76d2f89d9a059a96a456b049
--- drivers/video/msm/mdp4_overlay_lcdc.c
+++ drivers/video/msm/mdp4_overlay_lcdc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -240,12 +240,6 @@ int mdp4_lcdc_pipe_commit(int cndx, int
/* pipe not unset */
mdp4_overlay_vsync_commit(pipe);
}
- /* free previous iommu to freelist
- * which will be freed at next
- * pipe_commit
- */
- mdp4_overlay_iommu_pipe_free(pipe->pipe_ndx, 0);
- pipe->pipe_used = 0; /* clear */
}
}
@@ -253,6 +247,33 @@ int mdp4_lcdc_pipe_commit(int cndx, int
/* start timing generator & mmu if they are not started yet */
mdp4_overlay_lcdc_start();
+ /*
+ * there has possibility that pipe commit come very close to next vsync
+ * this may cause two consecutive pie_commits happen within same vsync
+ * period which casue iommu page fault when previous iommu buffer
+ * freed. Set ION_IOMMU_UNMAP_DELAYED flag at ion_map_iommu() to
+ * add delay unmap iommu buffer to fix this problem.
+ * Also ion_unmap_iommu() may take as long as 9 ms to free an ion buffer.
+ * therefore mdp4_overlay_iommu_unmap_freelist(mixer) should be called
+ * ater stage_commit() to ensure pipe_commit (up to stage_commit)
+ * is completed within vsync period.
+ */
+
+ /* free previous committed iommu back to pool */
+ mdp4_overlay_iommu_unmap_freelist(mixer);
+
+ pipe = vp->plist;
+ for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) {
+ if (pipe->pipe_used) {
+ /* free previous iommu to freelist
+ * which will be freed at next
+ * pipe_commit
+ */
+ mdp4_overlay_iommu_pipe_free(pipe->pipe_ndx, 0);
+ pipe->pipe_used = 0; /* clear */
+ }
+ }
+
pipe = vctrl->base_pipe;
spin_lock_irqsave(&vctrl->spin_lock, flags);
@@ -406,6 +427,9 @@ ssize_t mdp4_lcdc_show_event(struct devi
ssize_t ret = 0;
unsigned long flags;
u64 vsync_tick;
+ ktime_t ctime;
+ u32 ctick, ptick;
+ int diff;
cndx = 0;
vctrl = &vsync_ctrl_db[0];
@@ -413,6 +437,28 @@ ssize_t mdp4_lcdc_show_event(struct devi
if (atomic_read(&vctrl->suspend) > 0 ||
atomic_read(&vctrl->vsync_resume) == 0)
return 0;
+ /*
+ * show_event thread keep spinning on vctrl->vsync_comp
+ * race condition on x.done if multiple thread blocked
+ * at wait_for_completion(&vctrl->vsync_comp)
+ *
+ * if show_event thread waked up first then it will come back
+ * and call INIT_COMPLETION(vctrl->vsync_comp) which set x.done = 0
+ * then second thread wakeed up which set x.done = 0x7ffffffd
+ * after that wait_for_completion will never wait.
+ * To avoid this, force show_event thread to sleep 5 ms here
+ * since it has full vsycn period (16.6 ms) to wait
+ */
+ ctime = ktime_get();
+ ctick = (u32)ktime_to_us(ctime);
+ ptick = (u32)ktime_to_us(vctrl->vsync_time);
+ ptick += 5000; /* 5ms */
+ diff = ptick - ctick;
+ if (diff > 0) {
+ if (diff > 1000) /* 1 ms */
+ diff = 1000;
+ usleep(diff);
+ }
spin_lock_irqsave(&vctrl->spin_lock, flags);
if (vctrl->wait_vsync_cnt == 0)
@@ -713,6 +759,7 @@ int mdp4_lcdc_off(struct platform_device
msleep(20); /* >= 17 ms */
complete_all(&vctrl->vsync_comp);
+ vctrl->wait_vsync_cnt = 0;
if (pipe == NULL)
return -EINVAL;
if (pipe->ov_blt_addr) {
@@ -831,11 +878,8 @@ void mdp4_primary_vsync_lcdc(void)
spin_lock(&vctrl->spin_lock);
vctrl->vsync_time = ktime_get();
- if (vctrl->wait_vsync_cnt) {
- complete_all(&vctrl->vsync_comp);
- vctrl->wait_vsync_cnt = 0;
- }
-
+ complete_all(&vctrl->vsync_comp);
+ vctrl->wait_vsync_cnt = 0;
spin_unlock(&vctrl->spin_lock);
}