summaryrefslogtreecommitdiff
path: root/drivers/video/tegra/dc/ext
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/tegra/dc/ext')
-rw-r--r--drivers/video/tegra/dc/ext/dev.c73
-rw-r--r--drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h4
2 files changed, 66 insertions, 11 deletions
diff --git a/drivers/video/tegra/dc/ext/dev.c b/drivers/video/tegra/dc/ext/dev.c
index 8ec015cbde9b..88273e26c51c 100644
--- a/drivers/video/tegra/dc/ext/dev.c
+++ b/drivers/video/tegra/dc/ext/dev.c
@@ -56,6 +56,7 @@ struct tegra_dc_ext_flip_data {
struct tegra_dc_ext *ext;
struct work_struct work;
struct tegra_dc_ext_flip_win win[DC_N_WINDOWS];
+ struct list_head timestamp_node;
};
int tegra_dc_ext_get_num_outputs(void)
@@ -207,6 +208,7 @@ static int tegra_dc_ext_set_windowattr(struct tegra_dc_ext *ext,
{
int err = 0;
struct tegra_dc_ext_win *ext_win = &ext->win[win->idx];
+ s64 timestamp_ns;
if (flip_win->handle[TEGRA_DC_Y] == NULL) {
win->flags = 0;
@@ -270,8 +272,20 @@ static int tegra_dc_ext_set_windowattr(struct tegra_dc_ext *ext,
msecs_to_jiffies(500), NULL);
}
-
- return 0;
+#ifndef CONFIG_TEGRA_SIMULATION_PLATFORM
+ timestamp_ns = timespec_to_ns(&flip_win->attr.timestamp);
+
+ if (timestamp_ns) {
+ /* XXX: Should timestamping be overridden by "no_vsync" flag */
+ tegra_dc_config_frame_end_intr(win->dc, true);
+ trace_printk("%s:Before timestamp wait\n", win->dc->ndev->name);
+ err = wait_event_interruptible(win->dc->timestamp_wq,
+ tegra_dc_is_within_n_vsync(win->dc, timestamp_ns));
+ trace_printk("%s:After timestamp wait\n", win->dc->ndev->name);
+ tegra_dc_config_frame_end_intr(win->dc, false);
+ }
+#endif
+ return err;
}
static void (*flip_callback)(void);
@@ -323,9 +337,11 @@ static void tegra_dc_ext_flip_worker(struct work_struct *work)
for (i = 0; i < DC_N_WINDOWS; i++) {
struct tegra_dc_ext_flip_win *flip_win = &data->win[i];
- int index = flip_win->attr.index;
+ int j = 0, index = flip_win->attr.index;
struct tegra_dc_win *win;
struct tegra_dc_ext_win *ext_win;
+ struct tegra_dc_ext_flip_data *temp = NULL;
+ s64 head_timestamp = 0;
if (index < 0)
continue;
@@ -337,6 +353,31 @@ static void tegra_dc_ext_flip_worker(struct work_struct *work)
(flip_win->attr.flags & TEGRA_DC_EXT_FLIP_FLAG_CURSOR))
skip_flip = true;
+ mutex_lock(&ext_win->queue_lock);
+ list_for_each_entry(temp, &ext_win->timestamp_queue,
+ timestamp_node) {
+ if (j == 0) {
+ if (unlikely(temp != data))
+ dev_err(&win->dc->ndev->dev,
+ "work queue did NOT dequeue head!!!");
+ else
+ head_timestamp =
+ timespec_to_ns(&flip_win->attr.timestamp);
+ } else {
+ s64 timestamp =
+ timespec_to_ns(&temp->win[i].attr.timestamp);
+
+ skip_flip = !tegra_dc_does_vsync_separate(ext->dc,
+ timestamp, head_timestamp);
+ /* Look ahead only one flip */
+ break;
+ }
+ j++;
+ }
+ if (!list_empty(&ext_win->timestamp_queue))
+ list_del(&data->timestamp_node);
+ mutex_unlock(&ext_win->queue_lock);
+
if (win->flags & TEGRA_WIN_FLAG_ENABLED) {
int j;
for (j = 0; j < TEGRA_DC_NUM_PLANES; j++) {
@@ -368,17 +409,17 @@ static void tegra_dc_ext_flip_worker(struct work_struct *work)
flip_callback();
spin_unlock(&flip_callback_lock);
}
- }
- for (i = 0; i < DC_N_WINDOWS; i++) {
- struct tegra_dc_ext_flip_win *flip_win = &data->win[i];
- int index = flip_win->attr.index;
+ for (i = 0; i < DC_N_WINDOWS; i++) {
+ struct tegra_dc_ext_flip_win *flip_win = &data->win[i];
+ int index = flip_win->attr.index;
- if (index < 0)
- continue;
+ if (index < 0)
+ continue;
- tegra_dc_incr_syncpt_min(ext->dc, index,
- flip_win->syncpt_max);
+ tegra_dc_incr_syncpt_min(ext->dc, index,
+ flip_win->syncpt_max);
+ }
}
/* unpin and deref previous front buffers */
@@ -490,6 +531,7 @@ static int tegra_dc_ext_flip(struct tegra_dc_ext_user *user,
struct tegra_dc_ext_flip_data *data;
int work_index = -1;
int i, ret = 0;
+ bool has_timestamp = false;
#ifdef CONFIG_ANDROID
int index_check[DC_N_WINDOWS] = {0, };
@@ -530,6 +572,8 @@ static int tegra_dc_ext_flip(struct tegra_dc_ext_user *user,
int index = args->win[i].index;
memcpy(&flip_win->attr, &args->win[i], sizeof(flip_win->attr));
+ if (timespec_to_ns(&flip_win->attr.timestamp))
+ has_timestamp = true;
if (index < 0)
continue;
@@ -604,6 +648,11 @@ static int tegra_dc_ext_flip(struct tegra_dc_ext_user *user,
ret = -EINVAL;
goto unlock;
}
+ if (has_timestamp) {
+ mutex_lock(&ext->win[work_index].queue_lock);
+ list_add_tail(&data->timestamp_node, &ext->win[work_index].timestamp_queue);
+ mutex_unlock(&ext->win[work_index].queue_lock);
+ }
queue_work(ext->win[work_index].flip_wq, &data->work);
unlock_windows_for_flip(user, args);
@@ -944,6 +993,8 @@ static int tegra_dc_ext_setup_windows(struct tegra_dc_ext *ext)
}
mutex_init(&win->lock);
+ mutex_init(&win->queue_lock);
+ INIT_LIST_HEAD(&win->timestamp_queue);
}
return 0;
diff --git a/drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h b/drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h
index f68c7d5c93c2..ef7361d1d933 100644
--- a/drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h
+++ b/drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h
@@ -58,6 +58,10 @@ struct tegra_dc_ext_win {
struct workqueue_struct *flip_wq;
atomic_t nr_pending_flips;
+
+ struct mutex queue_lock;
+
+ struct list_head timestamp_queue;
};
struct tegra_dc_ext {