diff options
author | Robert Morell <rmorell@nvidia.com> | 2011-03-03 14:58:06 -0800 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2011-11-30 21:48:11 -0800 |
commit | c1c9c8660b49eb0b67ae02a3e21e07fe7135232a (patch) | |
tree | 8568972953eacb5c92323efc76a5445200df0065 /drivers/video/tegra/dc/ext | |
parent | 3517cb3da60dc94c158c7cf2b39ad83e387a55dd (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.c | 91 | ||||
-rw-r--r-- | drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h | 6 |
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 */ |