summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin Huang <kevinh@nvidia.com>2011-08-18 13:41:46 -0700
committerNiket Sirsi <nsirsi@nvidia.com>2011-08-22 17:30:39 -0700
commitce4f84dc7022ced7c888b9ae2babebad2b987a38 (patch)
tree95aef4ceeff04f90807fe3f2723023913e69724a
parent24d6d42fd0e853fb6ca8dc961e42a3eebde1a0d7 (diff)
video: tegra: overlay: Add support in DSI one-shot mode for DIDIM
Bug 849780 Change-Id: I9e704d5d03a253655acd209e6c0815bb6bef3551 Reviewed-on: http://git-master/r/47149 Reviewed-by: Kevin Huang <kevinh@nvidia.com> Tested-by: Kevin Huang <kevinh@nvidia.com> Reviewed-by: Phillip Smith <psmith@nvidia.com> Reviewed-by: Yu-Huan Hsu <yhsu@nvidia.com>
-rw-r--r--arch/arm/mach-tegra/include/mach/dc.h1
-rw-r--r--drivers/video/tegra/dc/overlay.c124
2 files changed, 114 insertions, 11 deletions
diff --git a/arch/arm/mach-tegra/include/mach/dc.h b/arch/arm/mach-tegra/include/mach/dc.h
index 1e257eea00d6..397e9d147721 100644
--- a/arch/arm/mach-tegra/include/mach/dc.h
+++ b/arch/arm/mach-tegra/include/mach/dc.h
@@ -341,6 +341,7 @@ struct tegra_dc_out {
#define TEGRA_DC_OUT_NVHDCP_POLICY_MASK (1 << 2)
#define TEGRA_DC_OUT_CONTINUOUS_MODE (0 << 3)
#define TEGRA_DC_OUT_ONE_SHOT_MODE (1 << 3)
+#define TEGRA_DC_OUT_N_SHOT_MODE (1 << 4)
#define TEGRA_DC_ALIGN_MSB 0
#define TEGRA_DC_ALIGN_LSB 1
diff --git a/drivers/video/tegra/dc/overlay.c b/drivers/video/tegra/dc/overlay.c
index c8a49c8ed3b3..623c26ae98d4 100644
--- a/drivers/video/tegra/dc/overlay.c
+++ b/drivers/video/tegra/dc/overlay.c
@@ -39,6 +39,9 @@
#include "../nvmap/nvmap.h"
#include "overlay.h"
+/* Minimum extra shot for DIDIM if n shot is enabled. */
+#define TEGRA_DC_DIDIM_MIN_SHOT 1
+
DEFINE_MUTEX(tegra_flip_lock);
struct overlay_client;
@@ -64,6 +67,9 @@ struct tegra_overlay_info {
struct tegra_dc_blend blend;
+ u32 n_shot;
+ u32 overlay_ref;
+ struct mutex lock;
struct workqueue_struct *flip_wq;
/* Big enough for tegra_dc%u when %u < 10 */
@@ -84,13 +90,18 @@ struct tegra_overlay_flip_win {
};
struct tegra_overlay_flip_data {
+ bool didim_work;
+ u32 flags;
+ u32 nr_unpin;
+ u32 syncpt_max;
struct work_struct work;
struct tegra_overlay_info *overlay;
+ struct nvmap_handle_ref *unpin_handles[TEGRA_FB_FLIP_N_WINDOWS];
struct tegra_overlay_flip_win win[TEGRA_FB_FLIP_N_WINDOWS];
- u32 syncpt_max;
- u32 flags;
};
+static void tegra_overlay_flip_worker(struct work_struct *work);
+
/* Overlay window manipulation */
static int tegra_overlay_pin_window(struct tegra_overlay_info *overlay,
struct tegra_overlay_flip_win *flip_win,
@@ -263,6 +274,77 @@ static void tegra_overlay_blend_reorder(struct tegra_dc_blend *blend,
windows[below]->flags |= blend->flags[idx];
}
+static int tegra_overlay_flip_didim(struct tegra_overlay_flip_data *data)
+{
+ mutex_lock(&tegra_flip_lock);
+ INIT_WORK(&data->work, tegra_overlay_flip_worker);
+
+ queue_work(data->overlay->flip_wq, &data->work);
+
+ mutex_unlock(&tegra_flip_lock);
+
+ return 0;
+}
+
+static void tegra_overlay_n_shot(struct tegra_overlay_flip_data *data,
+ struct nvmap_handle_ref **unpin_handles, int *nr_unpin)
+{
+ int i;
+ struct tegra_overlay_info *overlay = data->overlay;
+ u32 didim_delay = overlay->dc->out->sd_settings->hw_update_delay;
+ u32 didim_enable = overlay->dc->out->sd_settings->enable;
+
+ mutex_lock(&overlay->lock);
+
+ if (data->didim_work) {
+ /* Increment sync point if we finish n shot;
+ * otherwise send overlay flip request. */
+ if (overlay->n_shot)
+ overlay->n_shot--;
+
+ if (overlay->n_shot && didim_enable) {
+ tegra_overlay_flip_didim(data);
+ mutex_unlock(&overlay->lock);
+ return;
+ } else {
+ *nr_unpin = data->nr_unpin;
+ for (i = 0; i < *nr_unpin; i++)
+ unpin_handles[i] = data->unpin_handles[i];
+ tegra_dc_incr_syncpt_min(overlay->dc, 0,
+ data->syncpt_max);
+ }
+ } else {
+ overlay->overlay_ref--;
+ /* If no new flip request in the queue, we will send
+ * the last frame n times for DIDIM */
+ if (!overlay->overlay_ref && didim_enable)
+ overlay->n_shot = TEGRA_DC_DIDIM_MIN_SHOT + didim_delay;
+
+ if (overlay->n_shot && didim_enable) {
+ data->nr_unpin = *nr_unpin;
+ data->didim_work = true;
+ for (i = 0; i < *nr_unpin; i++)
+ data->unpin_handles[i] = unpin_handles[i];
+ tegra_overlay_flip_didim(data);
+ mutex_unlock(&overlay->lock);
+ return;
+ } else {
+ tegra_dc_incr_syncpt_min(overlay->dc, 0,
+ data->syncpt_max);
+ }
+ }
+
+ mutex_unlock(&overlay->lock);
+
+ /* unpin and deref previous front buffers */
+ for (i = 0; i < *nr_unpin; i++) {
+ nvmap_unpin(overlay->overlay_nvmap, unpin_handles[i]);
+ nvmap_free(overlay->overlay_nvmap, unpin_handles[i]);
+ }
+
+ kfree(data);
+}
+
static void tegra_overlay_flip_worker(struct work_struct *work)
{
struct tegra_overlay_flip_data *data =
@@ -287,8 +369,8 @@ static void tegra_overlay_flip_worker(struct work_struct *work)
if (!win)
continue;
- if (win->flags && win->cur_handle)
- unpin_handles[nr_unpin++] = win->cur_handle;
+ if (win->flags && win->cur_handle && !data->didim_work)
+ unpin_handles[nr_unpin++] = win->cur_handle;
tegra_overlay_set_windowattr(overlay, win, &data->win[i]);
@@ -323,15 +405,20 @@ static void tegra_overlay_flip_worker(struct work_struct *work)
tegra_dc_sync_windows(wins, nr_win);
}
- tegra_dc_incr_syncpt_min(overlay->dc, 0, data->syncpt_max);
+ if ((overlay->dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) &&
+ (overlay->dc->out->flags & TEGRA_DC_OUT_N_SHOT_MODE)) {
+ tegra_overlay_n_shot(data, unpin_handles, &nr_unpin);
+ } else {
+ tegra_dc_incr_syncpt_min(overlay->dc, 0, data->syncpt_max);
- /* unpin and deref previous front buffers */
- for (i = 0; i < nr_unpin; i++) {
- nvmap_unpin(overlay->overlay_nvmap, unpin_handles[i]);
- nvmap_free(overlay->overlay_nvmap, unpin_handles[i]);
- }
+ /* unpin and deref previous front buffers */
+ for (i = 0; i < nr_unpin; i++) {
+ nvmap_unpin(overlay->overlay_nvmap, unpin_handles[i]);
+ nvmap_free(overlay->overlay_nvmap, unpin_handles[i]);
+ }
- kfree(data);
+ kfree(data);
+ }
}
static int tegra_overlay_flip(struct tegra_overlay_info *overlay,
@@ -366,6 +453,15 @@ static int tegra_overlay_flip(struct tegra_overlay_info *overlay,
INIT_WORK(&data->work, tegra_overlay_flip_worker);
data->overlay = overlay;
data->flags = args->flags;
+ data->didim_work = false;
+
+ if ((overlay->dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) &&
+ (overlay->dc->out->flags & TEGRA_DC_OUT_N_SHOT_MODE)) {
+ mutex_lock(&overlay->lock);
+ overlay->overlay_ref++;
+ overlay->n_shot = 0;
+ mutex_unlock(&overlay->lock);
+ }
for (i = 0; i < TEGRA_FB_FLIP_N_WINDOWS; i++) {
flip_win = &data->win[i];
@@ -757,6 +853,9 @@ struct tegra_overlay_info *tegra_overlay_register(struct nvhost_device *ndev,
e = -ENOMEM;
goto err_delete_wq;
}
+ mutex_init(&dev->lock);
+ dev->overlay_ref = 0;
+ dev->n_shot = 0;
dev->dc = dc;
@@ -783,6 +882,9 @@ void tegra_overlay_unregister(struct tegra_overlay_info *info)
void tegra_overlay_disable(struct tegra_overlay_info *overlay_info)
{
mutex_lock(&tegra_flip_lock);
+ mutex_lock(&overlay_info->lock);
+ overlay_info->n_shot = 0;
flush_workqueue(overlay_info->flip_wq);
+ mutex_unlock(&overlay_info->lock);
mutex_unlock(&tegra_flip_lock);
}