mirror of
https://github.com/torvalds/linux.git
synced 2026-06-10 15:42:19 +02:00
video: tegra: work around overlay corruption on underflows
Overlays can get their internal state corrupted during and underflow condition. The only way to fix this state is to reset the DC. If we get 4 consecutive frames with underflows, assume we're hosed and reset. Change-Id: Icdf61517837c8570b8de35f585075de08aa35fe7 Signed-off-by: Erik Gilling <konkers@android.com> Cc: Michael I. Gold <gold@nvidia.com>
This commit is contained in:
parent
8df53e4599
commit
4ce07d6140
|
|
@ -101,6 +101,7 @@ struct tegra_dc_win {
|
|||
unsigned z;
|
||||
|
||||
int dirty;
|
||||
int underflows;
|
||||
struct tegra_dc *dc;
|
||||
|
||||
struct nvmap_handle_ref *cur_handle;
|
||||
|
|
|
|||
|
|
@ -816,6 +816,7 @@ static irqreturn_t tegra_dc_irq(int irq, void *ptr)
|
|||
struct tegra_dc *dc = ptr;
|
||||
unsigned long status;
|
||||
unsigned long val;
|
||||
unsigned long underflow_mask;
|
||||
int i;
|
||||
|
||||
status = tegra_dc_readl(dc, DC_CMD_INT_STATUS);
|
||||
|
|
@ -845,6 +846,45 @@ static irqreturn_t tegra_dc_irq(int irq, void *ptr)
|
|||
wake_up(&dc->wq);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Overlays can get thier internal state corrupted during and underflow
|
||||
* condition. The only way to fix this state is to reset the DC.
|
||||
* if we get 4 consecutive frames with underflows, assume we're
|
||||
* hosed and reset.
|
||||
*/
|
||||
underflow_mask = status & (WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT);
|
||||
if (underflow_mask) {
|
||||
val = tegra_dc_readl(dc, DC_CMD_INT_ENABLE);
|
||||
val |= V_BLANK_INT;
|
||||
tegra_dc_writel(dc, val, DC_CMD_INT_ENABLE);
|
||||
dc->underflow_mask |= underflow_mask;
|
||||
}
|
||||
|
||||
if (status & V_BLANK_INT) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i< DC_N_WINDOWS; i++) {
|
||||
if (dc->underflow_mask & (WIN_A_UF_INT <<i)) {
|
||||
dc->windows[i].underflows++;
|
||||
|
||||
if (dc->windows[i].underflows > 4)
|
||||
schedule_work(&dc->reset_work);
|
||||
} else {
|
||||
dc->windows[i].underflows = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!dc->underflow_mask) {
|
||||
val = tegra_dc_readl(dc, DC_CMD_INT_ENABLE);
|
||||
val &= ~V_BLANK_INT;
|
||||
tegra_dc_writel(dc, val, DC_CMD_INT_ENABLE);
|
||||
}
|
||||
|
||||
dc->underflow_mask = 0;
|
||||
}
|
||||
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
|
@ -935,8 +975,14 @@ static void tegra_dc_init(struct tegra_dc *dc)
|
|||
tegra_dc_writel(dc, 0x00202020, DC_DISP_MEM_HIGH_PRIORITY);
|
||||
tegra_dc_writel(dc, 0x00010101, DC_DISP_MEM_HIGH_PRIORITY_TIMER);
|
||||
|
||||
tegra_dc_writel(dc, 0x00000002, DC_CMD_INT_MASK);
|
||||
tegra_dc_writel(dc, 0x00000000, DC_CMD_INT_ENABLE);
|
||||
tegra_dc_writel(dc, (FRAME_END_INT |
|
||||
V_BLANK_INT |
|
||||
WIN_A_UF_INT |
|
||||
WIN_B_UF_INT |
|
||||
WIN_C_UF_INT), DC_CMD_INT_MASK);
|
||||
tegra_dc_writel(dc, (WIN_A_UF_INT |
|
||||
WIN_B_UF_INT |
|
||||
WIN_C_UF_INT), DC_CMD_INT_ENABLE);
|
||||
|
||||
tegra_dc_writel(dc, 0x00000000, DC_DISP_BORDER_COLOR);
|
||||
|
||||
|
|
@ -1031,6 +1077,25 @@ void tegra_dc_disable(struct tegra_dc *dc)
|
|||
mutex_unlock(&dc->lock);
|
||||
}
|
||||
|
||||
static void tegra_dc_reset_worker(struct work_struct *work)
|
||||
{
|
||||
struct tegra_dc *dc =
|
||||
container_of(work, struct tegra_dc, reset_work);
|
||||
|
||||
dev_warn(&dc->ndev->dev, "overlay stuck in underflow state. resetting.\n");
|
||||
|
||||
mutex_lock(&dc->lock);
|
||||
_tegra_dc_disable(dc);
|
||||
|
||||
tegra_periph_reset_assert(dc->clk);
|
||||
msleep(10);
|
||||
tegra_periph_reset_deassert(dc->clk);
|
||||
|
||||
_tegra_dc_enable(dc);
|
||||
mutex_unlock(&dc->lock);
|
||||
}
|
||||
|
||||
|
||||
static int tegra_dc_probe(struct nvhost_device *ndev)
|
||||
{
|
||||
struct tegra_dc *dc;
|
||||
|
|
@ -1120,6 +1185,7 @@ static int tegra_dc_probe(struct nvhost_device *ndev)
|
|||
|
||||
mutex_init(&dc->lock);
|
||||
init_waitqueue_head(&dc->wq);
|
||||
INIT_WORK(&dc->reset_work, tegra_dc_reset_worker);
|
||||
|
||||
dc->n_windows = DC_N_WINDOWS;
|
||||
for (i = 0; i < dc->n_windows; i++) {
|
||||
|
|
|
|||
|
|
@ -84,6 +84,9 @@ struct tegra_dc {
|
|||
u32 syncpt_id;
|
||||
u32 syncpt_min;
|
||||
u32 syncpt_max;
|
||||
|
||||
unsigned long underflow_mask;
|
||||
struct work_struct reset_work;
|
||||
};
|
||||
|
||||
static inline void tegra_dc_io_start(struct tegra_dc *dc)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user