Merge "msm: mdss: Add rotator sync point support in mdss"
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 5c4974d..e3e4509 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -1100,6 +1100,12 @@
 
 	flgs = rot->flags & MDP_SECURE_OVERLAY_SESSION;
 
+	ret = mdss_mdp_rotator_busy_wait_ex(rot);
+	if (ret) {
+		pr_err("rotator busy wait error\n");
+		return ret;
+	}
+
 	mdss_mdp_overlay_free_buf(&rot->src_buf);
 	ret = mdss_mdp_overlay_get_buf(mfd, &rot->src_buf, &req->data, 1, flgs);
 	if (ret) {
@@ -1115,7 +1121,7 @@
 		goto dst_buf_fail;
 	}
 
-	ret = mdss_mdp_rotator_queue(rot, &rot->src_buf, &rot->dst_buf);
+	ret = mdss_mdp_rotator_queue(rot);
 	if (ret)
 		pr_err("rotator queue error session id=%x\n", req->id);
 
@@ -2336,7 +2342,7 @@
 	mdp5_interface->ioctl_handler = mdss_mdp_overlay_ioctl_handler;
 	mdp5_interface->panel_register_done = mdss_panel_register_done;
 	mdp5_interface->kickoff_fnc = mdss_mdp_overlay_kickoff;
-	mdp5_interface->get_sync_fnc = NULL;
+	mdp5_interface->get_sync_fnc = mdss_mdp_rotator_sync_pt_get;
 
 	mdp5_data = kmalloc(sizeof(struct mdss_overlay_private), GFP_KERNEL);
 	if (!mdp5_data) {
diff --git a/drivers/video/msm/mdss/mdss_mdp_rotator.c b/drivers/video/msm/mdss/mdss_mdp_rotator.c
index 8381c5b..44734f8 100644
--- a/drivers/video/msm/mdss/mdss_mdp_rotator.c
+++ b/drivers/video/msm/mdss/mdss_mdp_rotator.c
@@ -17,9 +17,12 @@
 #include <linux/list.h>
 #include <linux/mutex.h>
 #include <linux/types.h>
+#include <linux/sync.h>
+#include <linux/sw_sync.h>
 
 #include "mdss_mdp.h"
 #include "mdss_mdp_rotator.h"
+#include "mdss_fb.h"
 
 #define MAX_ROTATOR_SESSIONS 8
 
@@ -28,6 +31,11 @@
 static LIST_HEAD(rotator_queue);
 
 static int mdss_mdp_rotator_finish(struct mdss_mdp_rotator_session *rot);
+static void mdss_mdp_rotator_commit_wq_handler(struct work_struct *work);
+static int mdss_mdp_rotator_busy_wait(struct mdss_mdp_rotator_session *rot);
+static int mdss_mdp_rotator_queue_helper(struct mdss_mdp_rotator_session *rot);
+static struct msm_sync_pt_data *mdss_mdp_rotator_sync_pt_create(
+			struct mdss_mdp_rotator_session *rot);
 
 struct mdss_mdp_rotator_session *mdss_mdp_rotator_session_alloc(void)
 {
@@ -67,6 +75,22 @@
 	return NULL;
 }
 
+struct msm_sync_pt_data *mdss_mdp_rotator_sync_pt_get(
+	struct msm_fb_data_type *mfd, const struct mdp_buf_sync *buf_sync)
+{
+	struct mdss_mdp_rotator_session *rot;
+
+	rot = mdss_mdp_rotator_session_get(buf_sync->session_id);
+	if (!rot)
+		return NULL;
+	if (!rot->rot_sync_pt_data)
+		rot->rot_sync_pt_data = mdss_mdp_rotator_sync_pt_create(rot);
+	if (rot->rot_sync_pt_data)
+		rot->use_sync_pt = true;
+
+	return rot->rot_sync_pt_data;
+}
+
 static struct mdss_mdp_pipe *mdss_mdp_rotator_pipe_alloc(void)
 {
 	struct mdss_mdp_mixer *mixer;
@@ -246,21 +270,84 @@
 	return ret;
 }
 
-int mdss_mdp_rotator_queue(struct mdss_mdp_rotator_session *rot,
-			   struct mdss_mdp_data *src_data,
-			   struct mdss_mdp_data *dst_data)
+static void mdss_mdp_rotator_commit_wq_handler(struct work_struct *work)
+{
+	struct mdss_mdp_rotator_session *rot;
+	int ret;
+
+	rot = container_of(work, struct mdss_mdp_rotator_session, commit_work);
+	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);
+	else
+		pr_err("rot_sync_pt_data is NULL\n");
+}
+
+static struct msm_sync_pt_data *mdss_mdp_rotator_sync_pt_create(
+				struct mdss_mdp_rotator_session *rot)
+{
+	struct msm_sync_pt_data *sync_pt_data;
+	char timeline_name[16];
+
+	rot->rot_sync_pt_data = kzalloc(
+		sizeof(struct msm_sync_pt_data), GFP_KERNEL);
+	sync_pt_data = rot->rot_sync_pt_data;
+	if (!sync_pt_data)
+		return NULL;
+	sync_pt_data->fence_name = "rot-fence";
+	sync_pt_data->threshold = 1;
+	snprintf(timeline_name, sizeof(timeline_name),
+					"mdss_rot_%d", rot->session_id);
+	sync_pt_data->timeline = sw_sync_timeline_create(timeline_name);
+	if (sync_pt_data->timeline == NULL) {
+		kfree(rot->rot_sync_pt_data);
+		pr_err("%s: cannot create time line", __func__);
+		return NULL;
+	} else {
+		sync_pt_data->timeline_value = 0;
+	}
+	INIT_WORK(&rot->commit_work,
+				mdss_mdp_rotator_commit_wq_handler);
+	mutex_init(&sync_pt_data->sync_mutex);
+	return sync_pt_data;
+}
+
+int mdss_mdp_rotator_busy_wait_ex(struct mdss_mdp_rotator_session *rot)
+{
+
+	struct mdss_mdp_rotator_session *tmp;
+
+	for (tmp = rot; tmp; tmp = tmp->next)
+		mdss_mdp_rotator_busy_wait(tmp);
+
+	if (rot->use_sync_pt)
+		mdss_fb_wait_for_fence(rot->rot_sync_pt_data);
+
+	return 0;
+}
+
+static int mdss_mdp_rotator_queue_helper(struct mdss_mdp_rotator_session *rot)
 {
 	int ret;
-	struct mdss_mdp_rotator_session *tmp = rot;
+	struct mdss_mdp_rotator_session *tmp;
 
 	ret = mutex_lock_interruptible(&rotator_lock);
-	if (ret)
+	if (ret) {
+		pr_err("mutex lock on rotator_lock failed\n");
 		return ret;
+	}
 
 	pr_debug("rotator session=%x start\n", rot->session_id);
 
 	for (ret = 0, tmp = rot; ret == 0 && tmp; tmp = tmp->next)
-		ret = mdss_mdp_rotator_queue_sub(tmp, src_data, dst_data);
+		ret = mdss_mdp_rotator_queue_sub(tmp,
+				&rot->src_buf, &rot->dst_buf);
 
 	mutex_unlock(&rotator_lock);
 
@@ -272,6 +359,18 @@
 	for (tmp = rot; tmp; tmp = tmp->next)
 		mdss_mdp_rotator_busy_wait(tmp);
 
+	return ret;
+}
+
+int mdss_mdp_rotator_queue(struct mdss_mdp_rotator_session *rot)
+{
+	int ret = 0;
+
+	if (rot->use_sync_pt)
+		schedule_work(&rot->commit_work);
+	else
+		ret = mdss_mdp_rotator_queue_helper(rot);
+
 	pr_debug("rotator session=%x queue done\n", rot->session_id);
 
 	return ret;
@@ -370,6 +469,8 @@
 	struct mdss_mdp_pipe *rot_pipe;
 	struct mdss_mdp_ctl *tmp;
 	int ret = 0;
+	struct msm_sync_pt_data *rot_sync_pt_data;
+	struct work_struct commit_work;
 
 	if (!rot)
 		return -ENODEV;
@@ -384,7 +485,13 @@
 		mdss_mdp_rotator_busy_wait(rot);
 		list_del(&rot->head);
 	}
+
+	rot_sync_pt_data = rot->rot_sync_pt_data;
+	commit_work = rot->commit_work;
 	memset(rot, 0, sizeof(*rot));
+	rot->rot_sync_pt_data = rot_sync_pt_data;
+	rot->commit_work = commit_work;
+
 	if (rot_pipe) {
 		struct mdss_mdp_mixer *mixer = rot_pipe->mixer;
 		mdss_mdp_pipe_unmap(rot_pipe);
diff --git a/drivers/video/msm/mdss/mdss_mdp_rotator.h b/drivers/video/msm/mdss/mdss_mdp_rotator.h
index 74eeeeb..43e77cc 100644
--- a/drivers/video/msm/mdss/mdss_mdp_rotator.h
+++ b/drivers/video/msm/mdss/mdss_mdp_rotator.h
@@ -43,9 +43,12 @@
 	struct mdss_mdp_data src_buf;
 	struct mdss_mdp_data dst_buf;
 
+	bool use_sync_pt;
 	struct list_head head;
 	struct list_head list;
 	struct mdss_mdp_rotator_session *next;
+	struct msm_sync_pt_data *rot_sync_pt_data;
+	struct work_struct commit_work;
 };
 
 static inline u32 mdss_mdp_get_rotator_dst_format(u32 in_format)
@@ -68,11 +71,10 @@
 struct mdss_mdp_rotator_session *mdss_mdp_rotator_session_get(u32 session_id);
 
 int mdss_mdp_rotator_setup(struct mdss_mdp_rotator_session *rot);
-int mdss_mdp_rotator_queue(struct mdss_mdp_rotator_session *rot,
-			   struct mdss_mdp_data *src_data,
-			   struct mdss_mdp_data *dst_data);
-
+int mdss_mdp_rotator_queue(struct mdss_mdp_rotator_session *rot);
 int mdss_mdp_rotator_release(struct mdss_mdp_rotator_session *rot);
 int mdss_mdp_rotator_release_all(void);
-
+int mdss_mdp_rotator_busy_wait_ex(struct mdss_mdp_rotator_session *rot);
+struct msm_sync_pt_data *mdss_mdp_rotator_sync_pt_get(
+	struct msm_fb_data_type *mfd, const struct mdp_buf_sync *buf_sync);
 #endif /* MDSS_MDP_ROTATOR_H */
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 9b21dca..077b204 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -838,6 +838,7 @@
 struct mdp_buf_sync {
 	uint32_t flags;
 	uint32_t acq_fen_fd_cnt;
+	uint32_t session_id;
 	int *acq_fen_fd;
 	int *rel_fen_fd;
 };