summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMin-wuk Lee <mlee@nvidia.com>2011-03-08 17:21:46 +0900
committerVarun Colbert <vcolbert@nvidia.com>2011-03-08 17:41:23 -0800
commitb817b18821e2c4bb5fe2a4e25c7d45739dfdd4b3 (patch)
tree4a512014aeb4cd5fa00e33ca04f80803ef8774be
parent6bca49c6ad55fe25e4e0917a7b9c4d59410bae56 (diff)
video: tegra: dc: Fix hang in dc reset
When DC(Display controller) meets underflow, DC needs to be reset to recover this, but in several resets, it hangs. To avoid this, - Set DC STOP mode ahead of DC reset assert - Off read host bus by DC ahead of DC reset - In DC0 reset period, to avoid DC1 access and vice versa - In reset worker, do not try to off host1x Bug 785529 Bug 789567 Change-Id: I24b242425ba6d7e59ec649fe8f10b41ac3d0c091 Reviewed-on: http://git-master/r/22028 Reviewed-by: Min-wuk Lee <mlee@nvidia.com> Tested-by: Min-wuk Lee <mlee@nvidia.com> Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
-rwxr-xr-x[-rw-r--r--]drivers/video/tegra/dc/dc.c83
1 files changed, 68 insertions, 15 deletions
diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c
index fe6150f6aabf..6b5f6c02a13a 100644..100755
--- a/drivers/video/tegra/dc/dc.c
+++ b/drivers/video/tegra/dc/dc.c
@@ -49,6 +49,7 @@ module_param_named(no_vsync, no_vsync, int, S_IRUGO | S_IWUSR);
struct tegra_dc *tegra_dcs[TEGRA_MAX_DC];
DEFINE_MUTEX(tegra_dc_lock);
+DEFINE_MUTEX(shared_lock);
static inline int tegra_dc_fmt_bpp(int fmt)
{
@@ -1153,16 +1154,8 @@ static void tegra_dc_init(struct tegra_dc *dc)
tegra_dc_program_mode(dc, &dc->mode);
}
-static bool _tegra_dc_enable(struct tegra_dc *dc)
+static bool _tegra_dc_controller_enable(struct tegra_dc *dc)
{
- if (dc->mode.pclk == 0)
- return false;
-
- if (!dc->out)
- return false;
-
- tegra_dc_io_start(dc);
-
if (dc->out->enable)
dc->out->enable();
@@ -1190,6 +1183,19 @@ static bool _tegra_dc_enable(struct tegra_dc *dc)
return true;
}
+static bool _tegra_dc_enable(struct tegra_dc *dc)
+{
+ if (dc->mode.pclk == 0)
+ return false;
+
+ if (!dc->out)
+ return false;
+
+ tegra_dc_io_start(dc);
+
+ return _tegra_dc_controller_enable(dc);
+}
+
void tegra_dc_enable(struct tegra_dc *dc)
{
mutex_lock(&dc->lock);
@@ -1200,7 +1206,7 @@ void tegra_dc_enable(struct tegra_dc *dc)
mutex_unlock(&dc->lock);
}
-static void _tegra_dc_disable(struct tegra_dc *dc)
+static void _tegra_dc_controller_disable(struct tegra_dc *dc)
{
disable_irq(dc->irq);
@@ -1219,11 +1225,14 @@ static void _tegra_dc_disable(struct tegra_dc *dc)
dc->syncpt_min++;
nvhost_syncpt_cpu_incr(&dc->ndev->host->syncpt, dc->syncpt_id);
}
+}
+static void _tegra_dc_disable(struct tegra_dc *dc)
+{
+ _tegra_dc_controller_disable(dc);
tegra_dc_io_end(dc);
}
-
void tegra_dc_disable(struct tegra_dc *dc)
{
mutex_lock(&dc->lock);
@@ -1243,18 +1252,62 @@ static void tegra_dc_reset_worker(struct work_struct *work)
struct tegra_dc *dc =
container_of(work, struct tegra_dc, reset_work);
+ unsigned long val = 0;
+
dev_warn(&dc->ndev->dev, "overlay stuck in underflow state. resetting.\n");
+ mutex_lock(&shared_lock);
mutex_lock(&dc->lock);
- _tegra_dc_disable(dc);
- msleep(100);
+ if (dc->enabled == false)
+ return;
+
+ dc->enabled = false;
+
+ /*
+ * off host read bus
+ */
+ val = tegra_dc_readl(dc, DC_CMD_CONT_SYNCPT_VSYNC);
+ val &= ~(0x00000100);
+ tegra_dc_writel(dc, val, DC_CMD_CONT_SYNCPT_VSYNC);
+
+ /*
+ * set DC to STOP mode
+ */
+ tegra_dc_writel(dc, DISP_CTRL_MODE_STOP, DC_CMD_DISPLAY_COMMAND);
+
+ msleep(10);
+
+ _tegra_dc_controller_disable(dc);
+
+ if (dc->ndev->id == 0 && tegra_dcs[1] != NULL) {
+ mutex_lock(&tegra_dcs[1]->lock);
+ disable_irq(tegra_dcs[1]->irq);
+ } else if (dc->ndev->id == 1 && tegra_dcs[0] != NULL) {
+ mutex_lock(&tegra_dcs[0]->lock);
+ disable_irq(tegra_dcs[0]->irq);
+ }
+
+ msleep(5);
+
tegra_periph_reset_assert(dc->clk);
- msleep(100);
+ udelay(100);
tegra_periph_reset_deassert(dc->clk);
+ msleep(2);
+
+ if (dc->ndev->id == 0 && tegra_dcs[1] != NULL) {
+ enable_irq(tegra_dcs[1]->irq);
+ mutex_unlock(&tegra_dcs[1]->lock);
+ } else if (dc->ndev->id == 1 && tegra_dcs[0] != NULL) {
+ enable_irq(tegra_dcs[0]->irq);
+ mutex_unlock(&tegra_dcs[0]->lock);
+ }
+
+ _tegra_dc_controller_enable(dc);
- _tegra_dc_enable(dc);
+ dc->enabled = true;
mutex_unlock(&dc->lock);
+ mutex_unlock(&shared_lock);
}
static ssize_t switch_modeset_print_mode(struct switch_dev *sdev, char *buf)