summaryrefslogtreecommitdiff
path: root/drivers/video
diff options
context:
space:
mode:
authorXue Dong <xdong@nvidia.com>2013-01-24 13:34:06 -0800
committerDan Willemsen <dwillemsen@nvidia.com>2013-09-14 01:29:26 -0700
commit46faf97bfd50b576a277c1ecbb29be6aa45f7af8 (patch)
treea63a077a6863df9d1ae56a8ceb01e01b94eb55bb /drivers/video
parent49f52b7e3f79c19650ea75f71d3eb508ce6cc464 (diff)
video: tegra: dc: flip API for more than 3 windows
add new ioctl that supports flip of an arbitrary number of windows. Change-Id: I6368129092921c665db5a8063f714d9f8fc14e63 Signed-off-by: Xue Dong <xdong@nvidia.com> Signed-off-by: Jon Mayo <jmayo@nvidia.com> Reviewed-on: http://git-master/r/193929 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Kevin Huang (Eng-SW) <kevinh@nvidia.com> Reviewed-by: Tuomas Kulve <tkulve@nvidia.com>
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/tegra/dc/bandwidth.c4
-rw-r--r--drivers/video/tegra/dc/ext/dev.c135
2 files changed, 87 insertions, 52 deletions
diff --git a/drivers/video/tegra/dc/bandwidth.c b/drivers/video/tegra/dc/bandwidth.c
index a494e71495f0..8d389aa85b23 100644
--- a/drivers/video/tegra/dc/bandwidth.c
+++ b/drivers/video/tegra/dc/bandwidth.c
@@ -1,7 +1,7 @@
/*
* drivers/video/tegra/dc/bandwidth.c
*
- * Copyright (c) 2010-2012, NVIDIA CORPORATION, All rights reserved.
+ * Copyright (c) 2010-2013, NVIDIA CORPORATION, All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -38,6 +38,7 @@ module_param_named(use_dynamic_emc, use_dynamic_emc, int, S_IRUGO | S_IWUSR);
static void tegra_dc_set_latency_allowance(struct tegra_dc *dc,
struct tegra_dc_win *w)
{
+ unsigned long bw;
/* windows A, B, C for first and second display */
static const enum tegra_la_id la_id_tab[2][DC_N_WINDOWS] = {
/* first display */
@@ -67,7 +68,6 @@ static void tegra_dc_set_latency_allowance(struct tegra_dc *dc,
TEGRA_LA_DISPLAY_1B, TEGRA_LA_DISPLAY_1BB,
};
#endif
- unsigned long bw;
BUG_ON(dc->ndev->id >= ARRAY_SIZE(la_id_tab));
#if defined(CONFIG_ARCH_TEGRA_2x_SOC) || defined(CONFIG_ARCH_TEGRA_3x_SOC)
diff --git a/drivers/video/tegra/dc/ext/dev.c b/drivers/video/tegra/dc/ext/dev.c
index df45bed651a8..a859221a3bb9 100644
--- a/drivers/video/tegra/dc/ext/dev.c
+++ b/drivers/video/tegra/dc/ext/dev.c
@@ -1,7 +1,7 @@
/*
* drivers/video/tegra/dc/dev.c
*
- * Copyright (c) 2011-2012, NVIDIA CORPORATION, All rights reserved.
+ * Copyright (c) 2011-2013, NVIDIA CORPORATION, All rights reserved.
*
* Author: Robert Morell <rmorell@nvidia.com>
* Some code based on fbdev extensions written by:
@@ -56,8 +56,9 @@ struct tegra_dc_ext_flip_win {
struct tegra_dc_ext_flip_data {
struct tegra_dc_ext *ext;
struct work_struct work;
- struct tegra_dc_ext_flip_win win[TEGRA_DC_EXT_FLIP_N_WINDOWS];
+ struct tegra_dc_ext_flip_win win[DC_N_WINDOWS];
struct list_head timestamp_node;
+ int act_window_num;
};
int tegra_dc_ext_get_num_outputs(void)
@@ -340,15 +341,16 @@ static void tegra_dc_ext_flip_worker(struct work_struct *work)
{
struct tegra_dc_ext_flip_data *data =
container_of(work, struct tegra_dc_ext_flip_data, work);
+ int win_num = data->act_window_num;
struct tegra_dc_ext *ext = data->ext;
- struct tegra_dc_win *wins[TEGRA_DC_EXT_FLIP_N_WINDOWS];
- struct nvmap_handle_ref *unpin_handles[TEGRA_DC_EXT_FLIP_N_WINDOWS *
+ struct tegra_dc_win *wins[DC_N_WINDOWS];
+ struct nvmap_handle_ref *unpin_handles[DC_N_WINDOWS *
TEGRA_DC_NUM_PLANES];
struct nvmap_handle_ref *old_handle;
int i, nr_unpin = 0, nr_win = 0;
bool skip_flip = false;
- for (i = 0; i < TEGRA_DC_EXT_FLIP_N_WINDOWS; i++) {
+ for (i = 0; i < win_num; i++) {
struct tegra_dc_ext_flip_win *flip_win = &data->win[i];
int index = flip_win->attr.index;
struct tegra_dc_win *win;
@@ -435,7 +437,7 @@ static void tegra_dc_ext_flip_worker(struct work_struct *work)
spin_unlock(&flip_callback_lock);
}
- for (i = 0; i < TEGRA_DC_EXT_FLIP_N_WINDOWS; i++) {
+ 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;
@@ -457,14 +459,15 @@ static void tegra_dc_ext_flip_worker(struct work_struct *work)
}
static int lock_windows_for_flip(struct tegra_dc_ext_user *user,
- struct tegra_dc_ext_flip *args)
+ struct tegra_dc_ext_flip_windowattr *win,
+ int win_num)
{
struct tegra_dc_ext *ext = user->ext;
u8 idx_mask = 0;
int i;
- for (i = 0; i < TEGRA_DC_EXT_FLIP_N_WINDOWS; i++) {
- int index = args->win[i].index;
+ for (i = 0; i < win_num; i++) {
+ int index = win[i].index;
if (index < 0)
continue;
@@ -472,7 +475,7 @@ static int lock_windows_for_flip(struct tegra_dc_ext_user *user,
idx_mask |= BIT(index);
}
- for (i = 0; i < TEGRA_DC_EXT_FLIP_N_WINDOWS; i++) {
+ for (i = 0; i < win_num; i++) {
struct tegra_dc_ext_win *win;
if (!(idx_mask & BIT(i)))
@@ -500,14 +503,16 @@ fail_unlock:
}
static void unlock_windows_for_flip(struct tegra_dc_ext_user *user,
- struct tegra_dc_ext_flip *args)
+ struct tegra_dc_ext_flip_windowattr *win,
+ int win_num)
{
struct tegra_dc_ext *ext = user->ext;
u8 idx_mask = 0;
int i;
- for (i = 0; i < TEGRA_DC_EXT_FLIP_N_WINDOWS; i++) {
- int index = args->win[i].index;
+
+ for (i = 0; i < win_num; i++) {
+ int index = win[i].index;
if (index < 0)
continue;
@@ -515,7 +520,7 @@ static void unlock_windows_for_flip(struct tegra_dc_ext_user *user,
idx_mask |= BIT(index);
}
- for (i = TEGRA_DC_EXT_FLIP_N_WINDOWS - 1; i >= 0; i--) {
+ for (i = win_num - 1; i >= 0; i--) {
if (!(idx_mask & BIT(i)))
continue;
@@ -524,12 +529,13 @@ static void unlock_windows_for_flip(struct tegra_dc_ext_user *user,
}
static int sanitize_flip_args(struct tegra_dc_ext_user *user,
- struct tegra_dc_ext_flip *args)
+ struct tegra_dc_ext_flip_windowattr *win,
+ int win_num)
{
int i, used_windows = 0;
- for (i = 0; i < TEGRA_DC_EXT_FLIP_N_WINDOWS; i++) {
- int index = args->win[i].index;
+ for (i = 0; i < win_num; i++) {
+ int index = win[i].index;
if (index < 0)
continue;
@@ -550,7 +556,9 @@ static int sanitize_flip_args(struct tegra_dc_ext_user *user,
}
static int tegra_dc_ext_flip(struct tegra_dc_ext_user *user,
- struct tegra_dc_ext_flip *args)
+ struct tegra_dc_ext_flip_windowattr *win,
+ int win_num,
+ __u32 *syncpt_id, __u32 *syncpt_val)
{
struct tegra_dc_ext *ext = user->ext;
struct tegra_dc_ext_flip_data *data;
@@ -558,15 +566,11 @@ static int tegra_dc_ext_flip(struct tegra_dc_ext_user *user,
int i, ret = 0;
bool has_timestamp = false;
-#ifdef CONFIG_ANDROID
- int index_check[TEGRA_DC_EXT_FLIP_N_WINDOWS] = {0, };
- int zero_index_id = 0;
-#endif
if (!user->nvmap)
return -EFAULT;
- ret = sanitize_flip_args(user, args);
+ ret = sanitize_flip_args(user, win, win_num);
if (ret)
return ret;
@@ -576,28 +580,14 @@ static int tegra_dc_ext_flip(struct tegra_dc_ext_user *user,
INIT_WORK(&data->work, tegra_dc_ext_flip_worker);
data->ext = ext;
+ data->act_window_num = win_num;
-#ifdef CONFIG_ANDROID
- for (i = 0; i < TEGRA_DC_EXT_FLIP_N_WINDOWS; i++) {
- index_check[i] = args->win[i].index;
- if (index_check[i] == 0)
- zero_index_id = i;
- }
-
- if (index_check[TEGRA_DC_EXT_FLIP_N_WINDOWS - 1] != 0) {
- struct tegra_dc_ext_flip_windowattr win_temp;
- win_temp = args->win[TEGRA_DC_EXT_FLIP_N_WINDOWS - 1];
- args->win[TEGRA_DC_EXT_FLIP_N_WINDOWS - 1] =
- args->win[zero_index_id];
- args->win[zero_index_id] = win_temp;
- }
-#endif
- for (i = 0; i < TEGRA_DC_EXT_FLIP_N_WINDOWS; i++) {
+ for (i = 0; i < win_num; i++) {
struct tegra_dc_ext_flip_win *flip_win = &data->win[i];
- int index = args->win[i].index;
+ int index = win[i].index;
- memcpy(&flip_win->attr, &args->win[i], sizeof(flip_win->attr));
+ memcpy(&flip_win->attr, &win[i], sizeof(flip_win->attr));
if (timespec_to_ns(&flip_win->attr.timestamp))
has_timestamp = true;
@@ -635,7 +625,7 @@ static int tegra_dc_ext_flip(struct tegra_dc_ext_user *user,
}
}
- ret = lock_windows_for_flip(user, args);
+ ret = lock_windows_for_flip(user, win, win_num);
if (ret)
goto fail_pin;
@@ -644,9 +634,10 @@ static int tegra_dc_ext_flip(struct tegra_dc_ext_user *user,
goto unlock;
}
- for (i = 0; i < TEGRA_DC_EXT_FLIP_N_WINDOWS; i++) {
+
+ for (i = 0; i < win_num; i++) {
u32 syncpt_max;
- int index = args->win[i].index;
+ int index = win[i].index;
struct tegra_dc_ext_win *ext_win;
if (index < 0)
@@ -662,8 +653,8 @@ static int tegra_dc_ext_flip(struct tegra_dc_ext_user *user,
* Any of these windows' syncpoints should be equivalent for
* the client, so we just send back an arbitrary one of them
*/
- args->post_syncpt_val = syncpt_max;
- args->post_syncpt_id = tegra_dc_get_syncpt_id(ext->dc, index);
+ *syncpt_val = syncpt_max;
+ *syncpt_id = tegra_dc_get_syncpt_id(ext->dc, index);
work_index = index;
atomic_inc(&ext->win[work_index].nr_pending_flips);
@@ -677,17 +668,21 @@ static int tegra_dc_ext_flip(struct tegra_dc_ext_user *user,
list_add_tail(&data->timestamp_node, &ext->win[work_index].timestamp_queue);
mutex_unlock(&ext->win[work_index].queue_lock);
}
+#ifdef CONFIG_ANDROID
+ work_index = 0;
+#endif
queue_work(ext->win[work_index].flip_wq, &data->work);
- unlock_windows_for_flip(user, args);
+ unlock_windows_for_flip(user, win, win_num);
return 0;
unlock:
- unlock_windows_for_flip(user, args);
+ unlock_windows_for_flip(user, win, win_num);
fail_pin:
- for (i = 0; i < TEGRA_DC_EXT_FLIP_N_WINDOWS; i++) {
+
+ for (i = 0; i < win_num; i++) {
int j;
for (j = 0; j < TEGRA_DC_NUM_PLANES; j++) {
if (!data->win[i].handle[j])
@@ -882,6 +877,7 @@ static long tegra_dc_ioctl(struct file *filp, unsigned int cmd,
{
void __user *user_arg = (void __user *)arg;
struct tegra_dc_ext_user *user = filp->private_data;
+ struct tegra_dc_ext_flip_2 args_new;
switch (cmd) {
case TEGRA_DC_EXT_SET_NVMAP_FD:
@@ -900,7 +896,10 @@ static long tegra_dc_ioctl(struct file *filp, unsigned int cmd,
if (copy_from_user(&args, user_arg, sizeof(args)))
return -EFAULT;
- ret = tegra_dc_ext_flip(user, &args);
+ ret = tegra_dc_ext_flip(user, args.win,
+ DC_N_WINDOWS,
+ &args.post_syncpt_id,
+ &args.post_syncpt_val);
if (copy_to_user(user_arg, &args, sizeof(args)))
return -EFAULT;
@@ -908,6 +907,42 @@ static long tegra_dc_ioctl(struct file *filp, unsigned int cmd,
return ret;
}
+ case TEGRA_DC_EXT_FLIP2:
+ {
+ int ret;
+ int num;
+ struct tegra_dc_ext_flip_windowattr *start;
+ struct tegra_dc_ext_flip_windowattr *temp;
+
+ if (copy_from_user(&args_new, user_arg, sizeof(args_new)))
+ return -EFAULT;
+
+ num = args_new.win_num;
+ start = args_new.win;
+
+ temp = kzalloc(sizeof(*start) * num, GFP_KERNEL);
+
+ if (copy_from_user(temp, start, sizeof(*start) * num))
+ return -EFAULT;
+
+ args_new.win = temp;
+
+ ret = tegra_dc_ext_flip(user, args_new.win,
+ args_new.win_num,
+ &args_new.post_syncpt_id,
+ &args_new.post_syncpt_val);
+
+ if (copy_to_user(start, temp, sizeof(*start) * num))
+ return -EFAULT;
+
+ args_new.win = start;
+
+ if (copy_to_user(user_arg, &args_new, sizeof(args_new)))
+ return -EFAULT;
+ kfree(temp);
+ return ret;
+ }
+
case TEGRA_DC_EXT_GET_CURSOR:
return tegra_dc_ext_get_cursor(user);
case TEGRA_DC_EXT_PUT_CURSOR: