summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorElaine K. Tam <etam@nvidia.com>2011-07-20 15:51:09 -0700
committerNiket Sirsi <nsirsi@nvidia.com>2011-07-25 16:07:45 -0700
commit1f175000f1a2b00e8169205f3778717ca56bcb28 (patch)
treee29e48f1c1285b17fb84ecd37f7e15193d17770b
parenta60b2ef0800ba3bebcc6908d3c471d7b0e97423f (diff)
video: tegra: host: Force DC reset on stuck DISP syncpt
Call tegra_dc_schedule_reset when DISP syncpoint is stuck for >= STUCK_FIXUP_COUNT (currently 5) iterations in syncpt_wait_timeout. This causes display to blank off briefly, but subsequently recovers. Bug 834337 Change-Id: I564a34e238f5c954f62ecde902af9de22a4cb32f Reviewed-on: http://git-master/r/42416 Reviewed-by: Niket Sirsi <nsirsi@nvidia.com> Tested-by: Niket Sirsi <nsirsi@nvidia.com>
-rw-r--r--drivers/video/tegra/dc/dc.c10
-rw-r--r--drivers/video/tegra/dc/dc_priv.h1
-rw-r--r--drivers/video/tegra/host/nvhost_syncpt.c36
3 files changed, 44 insertions, 3 deletions
diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c
index 4e15e0a5d662..05760fe8d4ca 100644
--- a/drivers/video/tegra/dc/dc.c
+++ b/drivers/video/tegra/dc/dc.c
@@ -1731,6 +1731,16 @@ void tegra_dc_disable(struct tegra_dc *dc)
mutex_unlock(&dc->lock);
}
+void tegra_dc_schedule_reset(int dc_id)
+{
+ if (dc_id < TEGRA_MAX_DC) {
+ dev_warn(&tegra_dcs[dc_id]->ndev->dev,
+ "%s(%d)\n", __FUNCTION__, dc_id);
+ dump_regs(tegra_dcs[dc_id]);
+ schedule_work(&tegra_dcs[dc_id]->reset_work);
+ }
+}
+
static void tegra_dc_reset_worker(struct work_struct *work)
{
struct tegra_dc *dc =
diff --git a/drivers/video/tegra/dc/dc_priv.h b/drivers/video/tegra/dc/dc_priv.h
index 7ee19f69c05b..c5d77b338230 100644
--- a/drivers/video/tegra/dc/dc_priv.h
+++ b/drivers/video/tegra/dc/dc_priv.h
@@ -182,4 +182,5 @@ extern struct tegra_dc_out_ops tegra_dc_rgb_ops;
extern struct tegra_dc_out_ops tegra_dc_hdmi_ops;
extern struct tegra_dc_out_ops tegra_dc_dsi_ops;
+void tegra_dc_schedule_reset(int dc_id);
#endif
diff --git a/drivers/video/tegra/host/nvhost_syncpt.c b/drivers/video/tegra/host/nvhost_syncpt.c
index c99960381c63..5ec3f09fffc0 100644
--- a/drivers/video/tegra/host/nvhost_syncpt.c
+++ b/drivers/video/tegra/host/nvhost_syncpt.c
@@ -157,6 +157,15 @@ void nvhost_syncpt_incr(struct nvhost_syncpt *sp, u32 id)
nvhost_module_idle(&syncpt_to_dev(sp)->mod);
}
+#define MAX_STUCK_CHECK_COUNT 15 /* Maximum number of loops to check for stuck
+ * syncpoint (this is also affected by the
+ * wait timeout defined) */
+#define STUCK_FIXUP_COUNT 5 /* Number of stuck syncpoint loops to wait before
+ * attempting to reset module (if such support
+ * exists; for now, only DC can be reset) */
+void tegra_dc_schedule_reset(int dc_id);
+
+static u32 nvhost_syncpt_last_min[NV_HOST1X_SYNCPT_NB_PTS];
/**
* Main entrypoint for syncpoint value waits.
*/
@@ -165,7 +174,7 @@ int nvhost_syncpt_wait_timeout(struct nvhost_syncpt *sp, u32 id,
{
DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
void *ref;
- int err = 0;
+ int err = 0, debug_done = 0;
if (value)
*value = 0;
@@ -196,7 +205,6 @@ int nvhost_syncpt_wait_timeout(struct nvhost_syncpt *sp, u32 id,
err = -EAGAIN;
goto done;
}
-
/* schedule a wakeup when the syncpoint value is reached */
err = nvhost_intr_add_action(&(syncpt_to_dev(sp)->intr), id, thresh,
NVHOST_INTR_ACTION_WAKEUP_INTERRUPTIBLE, &wq, &ref);
@@ -223,10 +231,31 @@ int nvhost_syncpt_wait_timeout(struct nvhost_syncpt *sp, u32 id,
if (timeout != NVHOST_NO_TIMEOUT)
timeout -= check;
if (timeout) {
+ u32 min, dc_id;
dev_warn(&syncpt_to_dev(sp)->pdev->dev,
"syncpoint id %d (%s) stuck waiting %d\n",
id, nvhost_syncpt_name(id), thresh);
+ if (debug_done >= STUCK_FIXUP_COUNT) {
+ switch (id) {
+ case NVSYNCPT_DISP0:
+ case NVSYNCPT_DISP1:
+ min = nvhost_syncpt_update_min(sp, id);
+ if (nvhost_syncpt_last_min[id] != 0 &&
+ nvhost_syncpt_last_min[id] == min) {
+ dc_id = (id == NVSYNCPT_DISP0) ? 0 : 1;
+ /* Seems stuck; it probably hasn't
+ incremented in prior loops, either */
+ tegra_dc_schedule_reset(dc_id);
+ }
+ break;
+ }
+ }
nvhost_syncpt_debug(sp);
+ if (debug_done > MAX_STUCK_CHECK_COUNT) {
+ nvhost_debug_dump();
+ BUG_ON(1);
+ }
+ debug_done++;
}
};
nvhost_intr_put_ref(&(syncpt_to_dev(sp)->intr), ref);
@@ -258,10 +287,11 @@ void nvhost_syncpt_debug(struct nvhost_syncpt *sp)
u32 max = nvhost_syncpt_read_max(sp, i);
if (!max)
continue;
+ nvhost_syncpt_last_min[i] = nvhost_syncpt_update_min(sp, i);
dev_info(&syncpt_to_dev(sp)->pdev->dev,
"id %d (%s) min %d max %d\n",
i, nvhost_syncpt_name(i),
- nvhost_syncpt_update_min(sp, i), max);
+ nvhost_syncpt_last_min[i], max);
}
}