summaryrefslogtreecommitdiff
path: root/drivers/video/tegra/dc/ext
diff options
context:
space:
mode:
authorRobert Morell <rmorell@nvidia.com>2011-03-03 14:58:06 -0800
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:48:11 -0800
commitc1c9c8660b49eb0b67ae02a3e21e07fe7135232a (patch)
tree8568972953eacb5c92323efc76a5445200df0065 /drivers/video/tegra/dc/ext
parent3517cb3da60dc94c158c7cf2b39ad83e387a55dd (diff)
video: tegra: nvhost: Use a syncpoint per window
Reserve one syncpoint per window per display controller instead of one for the entire display controller. This is necessary to allow multiple windows on a single display controller to flip asynchronously. bug 818525 Original-Change-Id: Ide1de2bf2ed0bfea7f6abe9aa93815efd0824db1 Signed-off-by: Robert Morell <rmorell@nvidia.com> Reviewed-on: http://git-master/r/40516 Reviewed-by: Varun Colbert <vcolbert@nvidia.com> Tested-by: Varun Colbert <vcolbert@nvidia.com> Rebase-Id: R49886938a74e71db0c8f53edc8ac45e5015ffe84
Diffstat (limited to 'drivers/video/tegra/dc/ext')
-rw-r--r--drivers/video/tegra/dc/ext/dev.c91
-rw-r--r--drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h6
2 files changed, 69 insertions, 28 deletions
diff --git a/drivers/video/tegra/dc/ext/dev.c b/drivers/video/tegra/dc/ext/dev.c
index 8905402954bf..b549f77222c8 100644
--- a/drivers/video/tegra/dc/ext/dev.c
+++ b/drivers/video/tegra/dc/ext/dev.c
@@ -46,13 +46,13 @@ struct tegra_dc_ext_flip_win {
struct nvmap_handle_ref *handle;
/* ugh. is this really necessary */
dma_addr_t phys_addr;
+ u32 syncpt_max;
};
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];
- u32 syncpt_max;
};
static int tegra_dc_ext_set_nvmap_fd(struct tegra_dc_ext_user *user,
@@ -112,10 +112,12 @@ static int tegra_dc_ext_put_window(struct tegra_dc_ext_user *user,
mutex_lock(&win->lock);
- if (win->user == user)
+ if (win->user == user) {
+ flush_workqueue(win->flip_wq);
win->user = 0;
- else
+ } else {
ret = -EACCES;
+ }
mutex_unlock(&win->lock);
@@ -124,7 +126,13 @@ static int tegra_dc_ext_put_window(struct tegra_dc_ext_user *user,
void tegra_dc_ext_suspend(struct tegra_dc_ext *ext)
{
- flush_workqueue(ext->flip_wq);
+ int i;
+
+ for (i = 0; i < ext->dc->n_windows; i++) {
+ struct tegra_dc_ext_win *win = &ext->win[i];
+
+ flush_workqueue(win->flip_wq);
+ }
}
static int tegra_dc_ext_set_windowattr(struct tegra_dc_ext *ext,
@@ -209,7 +217,16 @@ static void tegra_dc_ext_flip_worker(struct work_struct *work)
/* TODO: implement swapinterval here */
tegra_dc_sync_windows(wins, nr_win);
- tegra_dc_incr_syncpt_min(ext->dc, data->syncpt_max);
+ 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;
+
+ tegra_dc_incr_syncpt_min(ext->dc, index,
+ flip_win->syncpt_max);
+ }
/* unpin and deref previous front buffers */
for (i = 0; i < nr_unpin; i++) {
@@ -351,7 +368,7 @@ static int tegra_dc_ext_flip(struct tegra_dc_ext_user *user,
{
struct tegra_dc_ext *ext = user->ext;
struct tegra_dc_ext_flip_data *data;
- u32 syncpt_max;
+ int work_index;
int i, ret = 0;
if (!user->nvmap)
@@ -386,13 +403,26 @@ static int tegra_dc_ext_flip(struct tegra_dc_ext_user *user,
if (ret)
goto fail_pin;
- syncpt_max = tegra_dc_incr_syncpt_max(ext->dc);
- data->syncpt_max = syncpt_max;
+ for (i = 0; i < DC_N_WINDOWS; i++) {
+ u32 syncpt_max;
+ int index = args->win[i].index;
+
+ if (index < 0)
+ continue;
- args->post_syncpt_val = syncpt_max;
- args->post_syncpt_id = tegra_dc_get_syncpt_id(ext->dc);
+ syncpt_max = tegra_dc_incr_syncpt_max(ext->dc, index);
- queue_work(ext->flip_wq, &data->work);
+ data->win[i].syncpt_max = syncpt_max;
+
+ /*
+ * 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);
+ work_index = index;
+ }
+ queue_work(ext->win[work_index].flip_wq, &data->work);
unlock_windows_for_flip(user, args);
@@ -485,18 +515,35 @@ static int tegra_dc_release(struct inode *inode, struct file *filp)
static int tegra_dc_ext_setup_windows(struct tegra_dc_ext *ext)
{
- int i;
+ int i, ret;
for (i = 0; i < ext->dc->n_windows; i++) {
struct tegra_dc_ext_win *win = &ext->win[i];
+ char name[32];
win->ext = ext;
win->idx = i;
+ snprintf(name, sizeof(name), "tegradc.%d/%c",
+ ext->dc->ndev->id, 'a' + i);
+ win->flip_wq = create_singlethread_workqueue(name);
+ if (!win->flip_wq) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+
mutex_init(&win->lock);
}
return 0;
+
+cleanup:
+ while (i--) {
+ struct tegra_dc_ext_win *win = &ext->win[i];
+ destroy_workqueue(win->flip_wq);
+ }
+
+ return ret;
}
static const struct file_operations tegra_dc_devops = {
@@ -545,23 +592,14 @@ struct tegra_dc_ext *tegra_dc_ext_register(struct nvhost_device *ndev,
goto cleanup_device;
}
- ext->flip_wq = create_singlethread_workqueue(dev_name(&ndev->dev));
- if (!ext->flip_wq) {
- ret = -ENOMEM;
- goto cleanup_nvmap;
- }
-
ret = tegra_dc_ext_setup_windows(ext);
if (ret)
- goto cleanup_wq;
+ goto cleanup_nvmap;
tegra_dc_ext_devno++;
return ext;
-cleanup_wq:
- destroy_workqueue(ext->flip_wq);
-
cleanup_nvmap:
nvmap_client_put(ext->nvmap);
@@ -579,9 +617,14 @@ cleanup_alloc:
void tegra_dc_ext_unregister(struct tegra_dc_ext *ext)
{
+ int i;
- flush_workqueue(ext->flip_wq);
- destroy_workqueue(ext->flip_wq);
+ for (i = 0; i < ext->dc->n_windows; i++) {
+ struct tegra_dc_ext_win *win = &ext->win[i];
+
+ flush_workqueue(win->flip_wq);
+ destroy_workqueue(win->flip_wq);
+ }
nvmap_client_put(ext->nvmap);
device_del(ext->dev);
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 20018c9fbe20..b0a9bf65c6cd 100644
--- a/drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h
+++ b/drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h
@@ -40,9 +40,9 @@ struct tegra_dc_ext_win {
struct mutex lock;
- u32 syncpt_id;
-
struct nvmap_handle_ref *cur_handle;
+
+ struct workqueue_struct *flip_wq;
};
struct tegra_dc_ext {
@@ -54,8 +54,6 @@ struct tegra_dc_ext {
struct nvmap_client *nvmap;
struct tegra_dc_ext_win win[DC_N_WINDOWS];
-
- struct workqueue_struct *flip_wq;
};
#endif /* __TEGRA_DC_EXT_PRIV_H */