summaryrefslogtreecommitdiff
path: root/drivers/video/tegra
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
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')
-rw-r--r--drivers/video/tegra/dc/dc.c87
-rw-r--r--drivers/video/tegra/dc/dc_priv.h8
-rw-r--r--drivers/video/tegra/dc/ext/dev.c91
-rw-r--r--drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h6
-rw-r--r--drivers/video/tegra/dc/overlay.c6
-rw-r--r--drivers/video/tegra/host/t20/channel_t20.c4
-rw-r--r--drivers/video/tegra/host/t20/syncpt_t20.h13
7 files changed, 158 insertions, 57 deletions
diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c
index 3d26d2c633d0..36834743a9db 100644
--- a/drivers/video/tegra/dc/dc.c
+++ b/drivers/video/tegra/dc/dc.c
@@ -1024,33 +1024,33 @@ int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n)
}
EXPORT_SYMBOL(tegra_dc_update_windows);
-u32 tegra_dc_get_syncpt_id(const struct tegra_dc *dc)
+u32 tegra_dc_get_syncpt_id(const struct tegra_dc *dc, int i)
{
- return dc->syncpt_id;
+ return dc->syncpt[i].id;
}
EXPORT_SYMBOL(tegra_dc_get_syncpt_id);
-u32 tegra_dc_incr_syncpt_max(struct tegra_dc *dc)
+u32 tegra_dc_incr_syncpt_max(struct tegra_dc *dc, int i)
{
u32 max;
mutex_lock(&dc->lock);
- max = nvhost_syncpt_incr_max(&dc->ndev->host->syncpt, dc->syncpt_id,
- ((dc->enabled) ? 1 : 0) );
- dc->syncpt_max = max;
+ max = nvhost_syncpt_incr_max(&dc->ndev->host->syncpt,
+ dc->syncpt[i].id, ((dc->enabled) ? 1 : 0));
+ dc->syncpt[i].max = max;
mutex_unlock(&dc->lock);
return max;
}
-void tegra_dc_incr_syncpt_min(struct tegra_dc *dc, u32 val)
+void tegra_dc_incr_syncpt_min(struct tegra_dc *dc, int i, u32 val)
{
mutex_lock(&dc->lock);
if ( dc->enabled )
- while (dc->syncpt_min < val) {
- dc->syncpt_min++;
+ while (dc->syncpt[i].min < val) {
+ dc->syncpt[i].min++;
nvhost_syncpt_cpu_incr(&dc->ndev->host->syncpt,
- dc->syncpt_id);
+ dc->syncpt[i].id);
}
mutex_unlock(&dc->lock);
}
@@ -1902,15 +1902,58 @@ static void tegra_dc_set_color_control(struct tegra_dc *dc)
tegra_dc_writel(dc, color_control, DC_DISP_DISP_COLOR_CONTROL);
}
+static u32 get_syncpt(struct tegra_dc *dc, int idx)
+{
+ u32 syncpt_id;
+
+ switch (dc->ndev->id) {
+ case 0:
+ switch (idx) {
+ case 0:
+ syncpt_id = NVSYNCPT_DISP0_A;
+ break;
+ case 1:
+ syncpt_id = NVSYNCPT_DISP0_B;
+ break;
+ case 2:
+ syncpt_id = NVSYNCPT_DISP0_C;
+ break;
+ default:
+ BUG();
+ break;
+ }
+ break;
+ case 1:
+ switch (idx) {
+ case 0:
+ syncpt_id = NVSYNCPT_DISP1_A;
+ break;
+ case 1:
+ syncpt_id = NVSYNCPT_DISP1_B;
+ break;
+ case 2:
+ syncpt_id = NVSYNCPT_DISP1_C;
+ break;
+ default:
+ BUG();
+ break;
+ }
+ break;
+ default:
+ BUG();
+ break;
+ }
+
+ return syncpt_id;
+}
+
static void tegra_dc_init(struct tegra_dc *dc)
{
- u32 disp_syncpt = 0;
u32 vblank_syncpt = 0;
int i;
tegra_dc_writel(dc, 0x00000100, DC_CMD_GENERAL_INCR_SYNCPT_CNTRL);
if (dc->ndev->id == 0) {
- disp_syncpt = NVSYNCPT_DISP0;
vblank_syncpt = NVSYNCPT_VBLANK0;
tegra_mc_set_priority(TEGRA_MC_CLIENT_DISPLAY0A,
@@ -1924,7 +1967,6 @@ static void tegra_dc_init(struct tegra_dc *dc)
tegra_mc_set_priority(TEGRA_MC_CLIENT_DISPLAYHC,
TEGRA_MC_PRIO_HIGH);
} else if (dc->ndev->id == 1) {
- disp_syncpt = NVSYNCPT_DISP1;
vblank_syncpt = NVSYNCPT_VBLANK1;
tegra_mc_set_priority(TEGRA_MC_CLIENT_DISPLAY0AB,
@@ -1960,10 +2002,14 @@ static void tegra_dc_init(struct tegra_dc *dc)
}
- dc->syncpt_id = disp_syncpt;
+ for (i = 0; i < dc->n_windows; i++) {
+ u32 syncpt = get_syncpt(dc, i);
+
+ dc->syncpt[i].id = syncpt;
- dc->syncpt_min = dc->syncpt_max =
- nvhost_syncpt_read(&dc->ndev->host->syncpt, disp_syncpt);
+ dc->syncpt[i].min = dc->syncpt[i].max =
+ nvhost_syncpt_read(&dc->ndev->host->syncpt, syncpt);
+ }
print_mode(dc, &dc->mode, __func__);
@@ -2105,9 +2151,12 @@ static void _tegra_dc_controller_disable(struct tegra_dc *dc)
dc->out->disable();
/* flush any pending syncpt waits */
- while (dc->syncpt_min < dc->syncpt_max) {
- dc->syncpt_min++;
- nvhost_syncpt_cpu_incr(&dc->ndev->host->syncpt, dc->syncpt_id);
+ for (i = 0; i < dc->n_windows; i++) {
+ while (dc->syncpt[i].min < dc->syncpt[i].max) {
+ dc->syncpt[i].min++;
+ nvhost_syncpt_cpu_incr(&dc->ndev->host->syncpt,
+ dc->syncpt[i].id);
+ }
}
}
diff --git a/drivers/video/tegra/dc/dc_priv.h b/drivers/video/tegra/dc/dc_priv.h
index 4bf429f7e68c..e7e86cc9f11f 100644
--- a/drivers/video/tegra/dc/dc_priv.h
+++ b/drivers/video/tegra/dc/dc_priv.h
@@ -105,9 +105,11 @@ struct tegra_dc {
struct tegra_overlay_info *overlay;
- u32 syncpt_id;
- u32 syncpt_min;
- u32 syncpt_max;
+ struct {
+ u32 id;
+ u32 min;
+ u32 max;
+ } syncpt[DC_N_WINDOWS];
unsigned long underflow_mask;
struct work_struct reset_work;
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 */
diff --git a/drivers/video/tegra/dc/overlay.c b/drivers/video/tegra/dc/overlay.c
index 7879100be8e1..3444b2f9fa34 100644
--- a/drivers/video/tegra/dc/overlay.c
+++ b/drivers/video/tegra/dc/overlay.c
@@ -318,7 +318,7 @@ static void tegra_overlay_flip_worker(struct work_struct *work)
tegra_dc_sync_windows(wins, nr_win);
}
- tegra_dc_incr_syncpt_min(overlay->dc, data->syncpt_max);
+ tegra_dc_incr_syncpt_min(overlay->dc, 0, data->syncpt_max);
/* unpin and deref previous front buffers */
for (i = 0; i < nr_unpin; i++) {
@@ -378,13 +378,13 @@ static int tegra_overlay_flip(struct tegra_overlay_info *overlay,
}
}
- syncpt_max = tegra_dc_incr_syncpt_max(overlay->dc);
+ syncpt_max = tegra_dc_incr_syncpt_max(overlay->dc, 0);
data->syncpt_max = syncpt_max;
queue_work(overlay->flip_wq, &data->work);
args->post_syncpt_val = syncpt_max;
- args->post_syncpt_id = tegra_dc_get_syncpt_id(overlay->dc);
+ args->post_syncpt_id = tegra_dc_get_syncpt_id(overlay->dc, 0);
mutex_unlock(&tegra_flip_lock);
return 0;
diff --git a/drivers/video/tegra/host/t20/channel_t20.c b/drivers/video/tegra/host/t20/channel_t20.c
index 480dacf374f6..ad6a02e16f8c 100644
--- a/drivers/video/tegra/host/t20/channel_t20.c
+++ b/drivers/video/tegra/host/t20/channel_t20.c
@@ -52,7 +52,9 @@ static const struct nvhost_channeldesc channelmap[] = {
{
/* channel 0 */
.name = "display",
- .syncpts = BIT(NVSYNCPT_DISP0) | BIT(NVSYNCPT_DISP1) |
+ .syncpts = BIT(NVSYNCPT_DISP0_A) | BIT(NVSYNCPT_DISP1_A) |
+ BIT(NVSYNCPT_DISP0_B) | BIT(NVSYNCPT_DISP1_B) |
+ BIT(NVSYNCPT_DISP0_C) | BIT(NVSYNCPT_DISP1_C) |
BIT(NVSYNCPT_VBLANK0) | BIT(NVSYNCPT_VBLANK1),
.modulemutexes = BIT(NVMODMUTEX_DISPLAYA) | BIT(NVMODMUTEX_DISPLAYB),
},
diff --git a/drivers/video/tegra/host/t20/syncpt_t20.h b/drivers/video/tegra/host/t20/syncpt_t20.h
index 0f80367eab43..5e0c978ef7aa 100644
--- a/drivers/video/tegra/host/t20/syncpt_t20.h
+++ b/drivers/video/tegra/host/t20/syncpt_t20.h
@@ -23,6 +23,8 @@
#ifndef __NVHOST_SYNCPT_T20_H
#define __NVHOST_SYNCPT_T20_H
+#define NVSYNCPT_DISP0_A (8)
+#define NVSYNCPT_DISP1_A (9)
#define NVSYNCPT_AVP_0 (10)
#define NVSYNCPT_CSI_VI_0 (11)
#define NVSYNCPT_CSI_VI_1 (12)
@@ -33,10 +35,12 @@
#define NVSYNCPT_VI_ISP_4 (17)
#define NVSYNCPT_2D_0 (18)
#define NVSYNCPT_2D_1 (19)
+#define NVSYNCPT_DISP0_B (20)
+#define NVSYNCPT_DISP1_B (21)
#define NVSYNCPT_3D (22)
#define NVSYNCPT_MPE (23)
-#define NVSYNCPT_DISP0 (24)
-#define NVSYNCPT_DISP1 (25)
+#define NVSYNCPT_DISP0_C (24)
+#define NVSYNCPT_DISP1_C (25)
#define NVSYNCPT_VBLANK0 (26)
#define NVSYNCPT_VBLANK1 (27)
#define NVSYNCPT_MPE_EBM_EOF (28)
@@ -51,7 +55,10 @@
/* sync points that are wholly managed by the client */
#define NVSYNCPTS_CLIENT_MANAGED ( \
- BIT(NVSYNCPT_DISP0) | BIT(NVSYNCPT_DISP1) | BIT(NVSYNCPT_DSI) | \
+ BIT(NVSYNCPT_DISP0_A) | BIT(NVSYNCPT_DISP1_A) | \
+ BIT(NVSYNCPT_DISP0_B) | BIT(NVSYNCPT_DISP1_B) | \
+ BIT(NVSYNCPT_DISP0_C) | BIT(NVSYNCPT_DISP1_C) | \
+ BIT(NVSYNCPT_DSI) | \
BIT(NVSYNCPT_CSI_VI_0) | BIT(NVSYNCPT_CSI_VI_1) | \
BIT(NVSYNCPT_VI_ISP_1) | BIT(NVSYNCPT_VI_ISP_2) | \
BIT(NVSYNCPT_VI_ISP_3) | BIT(NVSYNCPT_VI_ISP_4) | \