diff options
author | Elaine K. Tam <etam@nvidia.com> | 2011-07-20 15:51:09 -0700 |
---|---|---|
committer | Niket Sirsi <nsirsi@nvidia.com> | 2011-07-25 16:07:45 -0700 |
commit | 1f175000f1a2b00e8169205f3778717ca56bcb28 (patch) | |
tree | e29e48f1c1285b17fb84ecd37f7e15193d17770b | |
parent | a60b2ef0800ba3bebcc6908d3c471d7b0e97423f (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.c | 10 | ||||
-rw-r--r-- | drivers/video/tegra/dc/dc_priv.h | 1 | ||||
-rw-r--r-- | drivers/video/tegra/host/nvhost_syncpt.c | 36 |
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); } } |