diff options
author | Min-wuk Lee <mlee@nvidia.com> | 2011-02-28 23:01:13 +0900 |
---|---|---|
committer | Varun Colbert <vcolbert@nvidia.com> | 2011-03-03 10:49:39 -0800 |
commit | 44fa12845e7d2ead892a69566aafce4745de4ba6 (patch) | |
tree | f9fe24c33fc3b9fa6b320cfcbc213b341c0cf40c /drivers | |
parent | 93e42ab68ea32f5722814d19aebe397f1df64690 (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: I26f40240cd60b83133309b36f61223336e9b3a41
Reviewed-on: http://git-master/r/20769
Reviewed-by: Varun Colbert <vcolbert@nvidia.com>
Tested-by: Varun Colbert <vcolbert@nvidia.com>
Diffstat (limited to 'drivers')
-rwxr-xr-x[-rw-r--r--] | drivers/video/tegra/dc/dc.c | 83 |
1 files changed, 68 insertions, 15 deletions
diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c index 2c6eaea9a561..ebd9f1830f53 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); @@ -1222,11 +1228,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); @@ -1246,18 +1255,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) |