From bf132a4184143d5780ca747d024768e021b590d5 Mon Sep 17 00:00:00 2001 From: Rakesh Iyer Date: Thu, 19 Jul 2012 12:44:08 -0700 Subject: video: tegra: dc: synchronize dsi clock-gating The one shot thread will clock gate the modules periodically. This will ensure relevant paths in dc driver have an active dc clock and dsi host. Bug 1013172 Change-Id: Ibb505e35044f31405c06cb9fa0d6fdf78aafd4a6 Signed-off-by: Rakesh Iyer Reviewed-on: http://git-master/r/117137 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Jon Mayo GVS: Gerrit_Virtual_Submit Reviewed-by: Animesh Kishore Reviewed-by: Yu-Huan Hsu --- drivers/video/tegra/dc/dc.c | 92 ++++++++++++++++++++++++++++++--------------- 1 file changed, 61 insertions(+), 31 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 1f7e2ce67682..dc263fbc301e 100644 --- a/drivers/video/tegra/dc/dc.c +++ b/drivers/video/tegra/dc/dc.c @@ -82,7 +82,7 @@ struct tegra_dc *tegra_dcs[TEGRA_MAX_DC]; DEFINE_MUTEX(tegra_dc_lock); DEFINE_MUTEX(shared_lock); -static inline void tegra_dc_clk_enable(struct tegra_dc *dc) +void tegra_dc_clk_enable(struct tegra_dc *dc) { if (!tegra_is_clk_enabled(dc->clk)) { clk_enable(dc->clk); @@ -90,7 +90,7 @@ static inline void tegra_dc_clk_enable(struct tegra_dc *dc) } } -static inline void tegra_dc_clk_disable(struct tegra_dc *dc) +void tegra_dc_clk_disable(struct tegra_dc *dc) { if (tegra_is_clk_enabled(dc->clk)) { clk_disable(dc->clk); @@ -98,6 +98,18 @@ static inline void tegra_dc_clk_disable(struct tegra_dc *dc) } } +void tegra_dc_hold_dc_out(struct tegra_dc *dc) +{ + if (dc->out_ops->hold) + dc->out_ops->hold(dc); +} + +void tegra_dc_release_dc_out(struct tegra_dc *dc) +{ + if (dc->out_ops->release) + dc->out_ops->release(dc); +} + #define DUMP_REG(a) do { \ snprintf(buff, sizeof(buff), "%-32s\t%03x\t%08lx\n", \ #a, a, tegra_dc_readl(dc, a)); \ @@ -121,8 +133,9 @@ static void _dump_regs(struct tegra_dc *dc, void *data, int i; char buff[256]; + mutex_lock(&dc->lock); + tegra_dc_hold_dc_out(dc); tegra_dc_io_start(dc); - tegra_dc_clk_enable(dc); DUMP_REG(DC_CMD_DISPLAY_COMMAND_OPTION0); DUMP_REG(DC_CMD_DISPLAY_COMMAND); @@ -272,8 +285,9 @@ static void _dump_regs(struct tegra_dc *dc, void *data, DUMP_REG(DC_COM_PM1_DUTY_CYCLE); DUMP_REG(DC_DISP_SD_CONTROL); - tegra_dc_clk_disable(dc); tegra_dc_io_end(dc); + tegra_dc_release_dc_out(dc); + mutex_unlock(&dc->lock); } #undef DUMP_REG @@ -488,9 +502,13 @@ int tegra_dc_get_stride(struct tegra_dc *dc, unsigned win) if (!dc->enabled) return 0; BUG_ON(win > DC_N_WINDOWS); + mutex_lock(&dc->lock); + tegra_dc_hold_dc_out(dc); tegra_dc_writel(dc, WINDOW_A_SELECT << win, DC_CMD_DISPLAY_WINDOW_HEADER); stride = tegra_dc_readl(dc, DC_WIN_LINE_STRIDE); + tegra_dc_release_dc_out(dc); + mutex_unlock(&dc->lock); return GET_LINE_STRIDE(stride); } EXPORT_SYMBOL(tegra_dc_get_stride); @@ -550,17 +568,6 @@ static void tegra_dc_set_scaling_filter(struct tegra_dc *dc) } } -void tegra_dc_host_suspend(struct tegra_dc *dc) -{ - tegra_dsi_host_suspend(dc); - tegra_dc_clk_disable(dc); -} - -void tegra_dc_host_resume(struct tegra_dc *dc) { - tegra_dc_clk_enable(dc); - tegra_dsi_host_resume(dc); -} - static inline void disable_dc_irq(unsigned int irq) { disable_irq(irq); @@ -577,9 +584,11 @@ u32 tegra_dc_incr_syncpt_max(struct tegra_dc *dc, int i) u32 max; mutex_lock(&dc->lock); + tegra_dc_hold_dc_out(dc); max = nvhost_syncpt_incr_max_ext(dc->ndev, dc->syncpt[i].id, ((dc->enabled) ? 1 : 0)); dc->syncpt[i].max = max; + tegra_dc_release_dc_out(dc); mutex_unlock(&dc->lock); return max; @@ -588,11 +597,14 @@ u32 tegra_dc_incr_syncpt_max(struct tegra_dc *dc, int i) void tegra_dc_incr_syncpt_min(struct tegra_dc *dc, int i, u32 val) { mutex_lock(&dc->lock); - if ( dc->enabled ) + if (dc->enabled) { + tegra_dc_hold_dc_out(dc); while (dc->syncpt[i].min < val) { dc->syncpt[i].min++; nvhost_syncpt_cpu_incr_ext(dc->ndev, dc->syncpt[i].id); } + tegra_dc_release_dc_out(dc); + } mutex_unlock(&dc->lock); } @@ -609,8 +621,7 @@ tegra_dc_config_pwm(struct tegra_dc *dc, struct tegra_dc_pwm_params *cfg) return; } - if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_LP_MODE) - tegra_dc_host_resume(dc); + tegra_dc_hold_dc_out(dc); ctrl = ((cfg->period << PM_PERIOD_SHIFT) | (cfg->clk_div << PM_CLK_DIVIDER_SHIFT) | @@ -644,6 +655,7 @@ tegra_dc_config_pwm(struct tegra_dc *dc, struct tegra_dc_pwm_params *cfg) break; } tegra_dc_writel(dc, cmd_state, DC_CMD_STATE_ACCESS); + tegra_dc_release_dc_out(dc); mutex_unlock(&dc->lock); } EXPORT_SYMBOL(tegra_dc_config_pwm); @@ -790,6 +802,9 @@ EXPORT_SYMBOL(tegra_dc_get_out_max_pixclock); void tegra_dc_enable_crc(struct tegra_dc *dc) { u32 val; + + mutex_lock(&dc->lock); + tegra_dc_hold_dc_out(dc); tegra_dc_io_start(dc); val = CRC_ALWAYS_ENABLE | CRC_INPUT_DATA_ACTIVE_DATA | @@ -797,15 +812,21 @@ void tegra_dc_enable_crc(struct tegra_dc *dc) tegra_dc_writel(dc, val, DC_COM_CRC_CONTROL); tegra_dc_writel(dc, GENERAL_UPDATE, DC_CMD_STATE_CONTROL); tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL); + tegra_dc_release_dc_out(dc); + mutex_unlock(&dc->lock); } void tegra_dc_disable_crc(struct tegra_dc *dc) { + mutex_lock(&dc->lock); + tegra_dc_hold_dc_out(dc); tegra_dc_writel(dc, 0x0, DC_COM_CRC_CONTROL); tegra_dc_writel(dc, GENERAL_UPDATE, DC_CMD_STATE_CONTROL); tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL); tegra_dc_io_end(dc); + tegra_dc_release_dc_out(dc); + mutex_unlock(&dc->lock); } u32 tegra_dc_read_checksum_latched(struct tegra_dc *dc) @@ -821,7 +842,11 @@ u32 tegra_dc_read_checksum_latched(struct tegra_dc *dc) * DC_COM_CRC_CHECKSUM_LATCHED is available after VBLANK */ mdelay(TEGRA_CRC_LATCHED_DELAY); + mutex_lock(&dc->lock); + tegra_dc_hold_dc_out(dc); crc = tegra_dc_readl(dc, DC_COM_CRC_CHECKSUM_LATCHED); + tegra_dc_release_dc_out(dc); + mutex_unlock(&dc->lock); crc_error: return crc; } @@ -860,6 +885,7 @@ static void tegra_dc_vblank(struct work_struct *work) return; } + tegra_dc_hold_dc_out(dc); /* 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)) @@ -886,6 +912,7 @@ static void tegra_dc_vblank(struct work_struct *work) if (!dc->vblank_ref_count) tegra_dc_mask_interrupt(dc, V_BLANK_INT); + tegra_dc_release_dc_out(dc); mutex_unlock(&dc->lock); /* Do the actual brightness update outside of the mutex */ @@ -908,8 +935,8 @@ static void tegra_dc_one_shot_worker(struct work_struct *work) /* memory client has gone idle */ tegra_dc_clear_bandwidth(dc); - if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_LP_MODE) - tegra_dc_host_suspend(dc); + if (dc->out_ops->idle) + dc->out_ops->idle(dc); mutex_unlock(&dc->lock); } @@ -1505,8 +1532,20 @@ void tegra_dc_blank(struct tegra_dc *dc) static void _tegra_dc_disable(struct tegra_dc *dc) { + if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) { + mutex_lock(&dc->one_shot_lock); + cancel_delayed_work_sync(&dc->one_shot_work); + } + + tegra_dc_hold_dc_out(dc); + _tegra_dc_controller_disable(dc); tegra_dc_io_end(dc); + + tegra_dc_release_dc_out(dc); + + if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) + mutex_unlock(&dc->one_shot_lock); } void tegra_dc_disable(struct tegra_dc *dc) @@ -1516,16 +1555,9 @@ void tegra_dc_disable(struct tegra_dc *dc) /* it's important that new underflow work isn't scheduled before the * lock is acquired. */ cancel_delayed_work_sync(&dc->underflow_work); - if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) { - mutex_lock(&dc->one_shot_lock); - cancel_delayed_work_sync(&dc->one_shot_work); - } mutex_lock(&dc->lock); - if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_LP_MODE) - tegra_dc_host_resume(dc); - if (dc->enabled) { dc->enabled = false; @@ -1538,8 +1570,6 @@ void tegra_dc_disable(struct tegra_dc *dc) #endif mutex_unlock(&dc->lock); - if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) - mutex_unlock(&dc->one_shot_lock); print_mode_info(dc, dc->mode); } @@ -1605,12 +1635,12 @@ static void tegra_dc_underflow_worker(struct work_struct *work) to_delayed_work(work), struct tegra_dc, underflow_work); mutex_lock(&dc->lock); - if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_LP_MODE) - tegra_dc_host_resume(dc); + tegra_dc_hold_dc_out(dc); if (dc->enabled) { tegra_dc_underflow_handler(dc); } + tegra_dc_release_dc_out(dc); mutex_unlock(&dc->lock); } -- cgit v1.2.3