From 19ca0279dd147b6036e289e41e81008edd385b2a Mon Sep 17 00:00:00 2001 From: Kevin Huang Date: Fri, 8 Jun 2012 16:15:55 -0700 Subject: video: tegra: dc: Use ref-count to mask vblank interrupt. Bug 990586 Change-Id: I63da2bd0aaae86070718e0d769b8c9555db18547 Signed-off-by: Kevin Huang Reviewed-on: http://git-master/r/107714 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Jon Mayo --- drivers/video/tegra/dc/dc.c | 82 ++++++++++++++++++++++++++------------------- 1 file changed, 47 insertions(+), 35 deletions(-) (limited to 'drivers/video/tegra/dc/dc.c') diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c index f1bf5d99cc29..095e44a1de28 100644 --- a/drivers/video/tegra/dc/dc.c +++ b/drivers/video/tegra/dc/dc.c @@ -1067,13 +1067,11 @@ int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n) tegra_dc_writel(dc, FRAME_END_INT | V_BLANK_INT, DC_CMD_INT_STATUS); if (!no_vsync) { - val = tegra_dc_readl(dc, DC_CMD_INT_MASK); - val |= (FRAME_END_INT | V_BLANK_INT | ALL_UF_INT); - tegra_dc_writel(dc, val, DC_CMD_INT_MASK); + set_bit(V_BLANK_FLIP, &dc->vblank_ref_count); + tegra_dc_unmask_interrupt(dc, FRAME_END_INT | V_BLANK_INT | ALL_UF_INT); } else { - val = tegra_dc_readl(dc, DC_CMD_INT_MASK); - val &= ~(FRAME_END_INT | V_BLANK_INT | ALL_UF_INT); - tegra_dc_writel(dc, val, DC_CMD_INT_MASK); + clear_bit(V_BLANK_FLIP, &dc->vblank_ref_count); + tegra_dc_mask_interrupt(dc, FRAME_END_INT | V_BLANK_INT | ALL_UF_INT); } if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) @@ -1459,6 +1457,24 @@ static inline void disable_dc_irq(unsigned int irq) disable_irq(irq); } +static inline void tegra_dc_unmask_interrupt(struct tegra_dc *dc, u32 int_val) +{ + u32 val; + + val = tegra_dc_readl(dc, DC_CMD_INT_MASK); + val |= int_val; + tegra_dc_writel(dc, val, DC_CMD_INT_MASK); +} + +static inline void tegra_dc_mask_interrupt(struct tegra_dc *dc, u32 int_val) +{ + u32 val; + + val = tegra_dc_readl(dc, DC_CMD_INT_MASK); + val &= ~int_val; + tegra_dc_writel(dc, val, DC_CMD_INT_MASK); +} + static int tegra_dc_program_mode(struct tegra_dc *dc, struct tegra_dc_mode *mode) { unsigned long val; @@ -1832,14 +1848,32 @@ static void tegra_dc_vblank(struct work_struct *work) bool nvsd_updated = false; mutex_lock(&dc->lock); + /* use the new frame's bandwidth setting instead of max(current, new), * skip this if we're using tegra_dc_one_shot_worker() */ if (!(dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)) tegra_dc_program_bandwidth(dc); + /* Clear the V_BLANK_FLIP bit of vblank ref-count if update is clean. */ + if (!tegra_dc_windows_are_dirty(dc)) + clear_bit(V_BLANK_FLIP, &dc->vblank_ref_count); + /* Update the SD brightness */ - if (dc->enabled && dc->out->sd_settings) + if (dc->enabled && dc->out->sd_settings) { nvsd_updated = nvsd_update_brightness(dc); + /* Ref-count vblank if nvsd is on-going. Otherwise, clean the + * V_BLANK_NVSD bit of vblank ref-count. */ + if (nvsd_updated) { + set_bit(V_BLANK_NVSD, &dc->vblank_ref_count); + tegra_dc_unmask_interrupt(dc, V_BLANK_INT); + } else { + clear_bit(V_BLANK_NVSD, &dc->vblank_ref_count); + } + } + + /* Mask vblank interrupt if ref-count is zero. */ + if (!dc->vblank_ref_count) + tegra_dc_mask_interrupt(dc, V_BLANK_INT); mutex_unlock(&dc->lock); @@ -1985,25 +2019,12 @@ static void tegra_dc_trigger_windows(struct tegra_dc *dc) } if (!dirty) { - val = tegra_dc_readl(dc, DC_CMD_INT_MASK); - if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) - val &= ~V_BLANK_INT; - else - val &= ~FRAME_END_INT; - tegra_dc_writel(dc, val, DC_CMD_INT_MASK); + if (!(dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)) + tegra_dc_mask_interrupt(dc, FRAME_END_INT); } - if (completed) { - if (!dirty) { - /* With the last completed window, go ahead - and enable the vblank interrupt for nvsd. */ - val = tegra_dc_readl(dc, DC_CMD_INT_MASK); - val |= V_BLANK_INT; - tegra_dc_writel(dc, val, DC_CMD_INT_MASK); - } - + if (completed) wake_up(&dc->wq); - } } static void tegra_dc_one_shot_irq(struct tegra_dc *dc, unsigned long status) @@ -2025,20 +2046,10 @@ static void tegra_dc_one_shot_irq(struct tegra_dc *dc, unsigned long status) static void tegra_dc_continuous_irq(struct tegra_dc *dc, unsigned long status) { - if (status & V_BLANK_INT) { - /* Schedule any additional bottom-half vblank actvities. */ + /* Schedule any additional bottom-half vblank actvities. */ + if (status & V_BLANK_INT) schedule_work(&dc->vblank_work); - /* All windows updated. Mask subsequent V_BLANK interrupts */ - if (!tegra_dc_windows_are_dirty(dc)) { - u32 val; - - val = tegra_dc_readl(dc, DC_CMD_INT_MASK); - val &= ~V_BLANK_INT; - tegra_dc_writel(dc, val, DC_CMD_INT_MASK); - } - } - if (status & FRAME_END_INT) { /* Mark the frame_end as complete. */ if (!completion_done(&dc->frame_end_complete)) @@ -2740,6 +2751,7 @@ static int tegra_dc_probe(struct nvhost_device *ndev, INIT_WORK(&dc->reset_work, tegra_dc_reset_worker); #endif INIT_WORK(&dc->vblank_work, tegra_dc_vblank); + dc->vblank_ref_count = 0; INIT_DELAYED_WORK(&dc->underflow_work, tegra_dc_underflow_worker); INIT_DELAYED_WORK(&dc->one_shot_work, tegra_dc_one_shot_worker); -- cgit v1.2.3