diff options
author | Kevin Huang <kevinh@nvidia.com> | 2012-06-06 10:48:18 -0700 |
---|---|---|
committer | Simone Willett <swillett@nvidia.com> | 2012-06-11 17:31:24 -0700 |
commit | b901b56e0c0573ce30393836e4078ca78beffca0 (patch) | |
tree | 6941d2d4cbd9719d26f2d3840735cca6c31bec4d /drivers/video | |
parent | b08927a712005ae3f6941e59f530b7896ac5f407 (diff) |
video: tegra: dc: Clock-gate display modules dynamically.
Bug 936337
Bug 899053
Change-Id: I2b3d8cfc8a00881338c1e17d03f2844d15ba7d3e
Signed-off-by: Kevin Huang <kevinh@nvidia.com>
Reviewed-on: http://git-master/r/106313
Reviewed-by: Simone Willett <swillett@nvidia.com>
Tested-by: Simone Willett <swillett@nvidia.com>
Diffstat (limited to 'drivers/video')
-rw-r--r-- | drivers/video/tegra/dc/bandwidth.c | 3 | ||||
-rw-r--r-- | drivers/video/tegra/dc/dc.c | 55 | ||||
-rw-r--r-- | drivers/video/tegra/dc/dc_priv.h | 7 | ||||
-rw-r--r-- | drivers/video/tegra/dc/dsi.c | 53 |
4 files changed, 102 insertions, 16 deletions
diff --git a/drivers/video/tegra/dc/bandwidth.c b/drivers/video/tegra/dc/bandwidth.c index a1da7ef0a995..ed5bf6e06948 100644 --- a/drivers/video/tegra/dc/bandwidth.c +++ b/drivers/video/tegra/dc/bandwidth.c @@ -234,7 +234,8 @@ void tegra_dc_program_bandwidth(struct tegra_dc *dc) max(dc->emc_clk_rate, dc->new_emc_clk_rate)); dc->emc_clk_rate = dc->new_emc_clk_rate; - if (!dc->new_emc_clk_rate) /* going from non-zero to 0 */ + /* going from non-zero to 0 */ + if (!dc->new_emc_clk_rate && tegra_is_clk_enabled(dc->emc_clk)) clk_disable(dc->emc_clk); } diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c index f4844f1eecfc..f1bf5d99cc29 100644 --- a/drivers/video/tegra/dc/dc.c +++ b/drivers/video/tegra/dc/dc.c @@ -90,6 +90,22 @@ 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) +{ + if (!tegra_is_clk_enabled(dc->clk)) { + clk_enable(dc->clk); + tegra_dvfs_set_rate(dc->clk, dc->mode.pclk); + } +} + +static inline void tegra_dc_clk_disable(struct tegra_dc *dc) +{ + if (tegra_is_clk_enabled(dc->clk)) { + clk_disable(dc->clk); + tegra_dvfs_set_rate(dc->clk, 0); + } +} + #define DUMP_REG(a) do { \ snprintf(buff, sizeof(buff), "%-32s\t%03x\t%08lx\n", \ #a, a, tegra_dc_readl(dc, a)); \ @@ -131,7 +147,7 @@ static void _dump_regs(struct tegra_dc *dc, void *data, char buff[256]; tegra_dc_io_start(dc); - clk_enable(dc->clk); + tegra_dc_clk_enable(dc); DUMP_REG(DC_CMD_DISPLAY_COMMAND_OPTION0); DUMP_REG(DC_CMD_DISPLAY_COMMAND); @@ -281,7 +297,7 @@ static void _dump_regs(struct tegra_dc *dc, void *data, DUMP_REG(DC_COM_PM1_DUTY_CYCLE); DUMP_REG(DC_DISP_SD_CONTROL); - clk_disable(dc->clk); + tegra_dc_clk_disable(dc->clk); tegra_dc_io_end(dc); } @@ -787,6 +803,17 @@ 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 u32 compute_dda_inc(fixed20_12 in, unsigned out_int, bool v, unsigned Bpp) { @@ -861,6 +888,9 @@ int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n) return -EFAULT; } + if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_LP_MODE) + tegra_dc_host_resume(dc); + if (no_vsync) tegra_dc_writel(dc, WRITE_MUX_ACTIVE | READ_MUX_ACTIVE, DC_CMD_STATE_ACCESS); else @@ -1590,6 +1620,9 @@ 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); + ctrl = ((cfg->period << PM_PERIOD_SHIFT) | (cfg->clk_div << PM_CLK_DIVIDER_SHIFT) | cfg->clk_select); @@ -1826,8 +1859,13 @@ static void tegra_dc_one_shot_worker(struct work_struct *work) struct tegra_dc *dc = container_of( to_delayed_work(work), struct tegra_dc, one_shot_work); mutex_lock(&dc->lock); + /* 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); + mutex_unlock(&dc->lock); } @@ -2254,7 +2292,7 @@ static bool _tegra_dc_controller_enable(struct tegra_dc *dc) dc->out->enable(); tegra_dc_setup_clk(dc, dc->clk); - clk_enable(dc->clk); + tegra_dc_clk_enable(dc); /* do not accept interrupts during initialization */ tegra_dc_writel(dc, 0, DC_CMD_INT_ENABLE); @@ -2292,7 +2330,7 @@ static bool _tegra_dc_controller_reset_enable(struct tegra_dc *dc) dc->out->enable(); tegra_dc_setup_clk(dc, dc->clk); - clk_enable(dc->clk); + tegra_dc_clk_enable(dc); if (dc->ndev->id == 0 && tegra_dcs[1] != NULL) { mutex_lock(&tegra_dcs[1]->lock); @@ -2407,8 +2445,7 @@ static void _tegra_dc_controller_disable(struct tegra_dc *dc) disable_irq(dc->irq); tegra_dc_clear_bandwidth(dc); - clk_disable(dc->clk); - tegra_dvfs_set_rate(dc->clk, 0); + tegra_dc_clk_disable(dc); if (dc->out && dc->out->disable) dc->out->disable(); @@ -2504,6 +2541,9 @@ void tegra_dc_disable(struct tegra_dc *dc) 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; @@ -2582,6 +2622,9 @@ 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); + if (dc->enabled) { tegra_dc_underflow_handler(dc); } diff --git a/drivers/video/tegra/dc/dc_priv.h b/drivers/video/tegra/dc/dc_priv.h index 4f53f60f2599..06f2a6061bf6 100644 --- a/drivers/video/tegra/dc/dc_priv.h +++ b/drivers/video/tegra/dc/dc_priv.h @@ -32,6 +32,7 @@ #include "../host/host1x/host1x_syncpt.h" #include <mach/tegra_dc_ext.h> +#include <mach/clk.h> #define WIN_IS_TILED(win) ((win)->flags & TEGRA_WIN_FLAG_TILED) #define WIN_IS_ENABLED(win) ((win)->flags & TEGRA_WIN_FLAG_ENABLED) @@ -164,6 +165,9 @@ static inline unsigned long tegra_dc_readl(struct tegra_dc *dc, unsigned long ret; BUG_ON(!nvhost_module_powered(nvhost_get_host(dc->ndev)->dev)); + if (!tegra_is_clk_enabled(dc->clk)) + WARN(1, "DC is clock-gated.\n"); + ret = readl(dc->base + reg * 4); trace_printk("readl %p=%#08lx\n", dc->base + reg * 4, ret); return ret; @@ -173,6 +177,9 @@ static inline void tegra_dc_writel(struct tegra_dc *dc, unsigned long val, unsigned long reg) { BUG_ON(!nvhost_module_powered(nvhost_get_host(dc->ndev)->dev)); + if (!tegra_is_clk_enabled(dc->clk)) + WARN(1, "DC is clock-gated.\n"); + trace_printk("writel %p=%#08lx\n", dc->base + reg * 4, val); writel(val, dc->base + reg * 4); } diff --git a/drivers/video/tegra/dc/dsi.c b/drivers/video/tegra/dc/dsi.c index 6624a8e8f52c..0ea3947176fe 100644 --- a/drivers/video/tegra/dc/dsi.c +++ b/drivers/video/tegra/dc/dsi.c @@ -416,6 +416,22 @@ static inline void tegra_dc_dsi_debug_create(struct tegra_dc_dsi_data *dsi) { } #endif +static inline void tegra_dsi_clk_enable(struct tegra_dc_dsi_data *dsi) +{ + if (!tegra_is_clk_enabled(dsi->dsi_clk)) { + clk_enable(dsi->dsi_clk); + clk_enable(dsi->dsi_fixed_clk); + } +} + +static inline void tegra_dsi_clk_disable(struct tegra_dc_dsi_data *dsi) +{ + if (tegra_is_clk_enabled(dsi->dsi_clk)) { + clk_disable(dsi->dsi_clk); + clk_disable(dsi->dsi_fixed_clk); + } +} + static int tegra_dsi_syncpt(struct tegra_dc_dsi_data *dsi) { u32 val; @@ -1455,12 +1471,9 @@ static void tegra_dsi_set_dsi_clk(struct tegra_dc *dc, /* Enable DSI clock */ tegra_dc_setup_clk(dc, dsi->dsi_clk); - if (!dsi->clk_ref) { - dsi->clk_ref = true; - clk_enable(dsi->dsi_clk); - clk_enable(dsi->dsi_fixed_clk); - tegra_periph_reset_deassert(dsi->dsi_clk); - } + tegra_dsi_clk_enable(dsi); + tegra_periph_reset_deassert(dsi->dsi_clk); + dsi->current_dsi_clk_khz = clk_get_rate(dsi->dsi_clk) / 1000; dsi->current_bit_clk_ns = 1000*1000 / (dsi->current_dsi_clk_khz * 2); } @@ -2193,6 +2206,9 @@ int tegra_dsi_send_panel_short_cmd(struct tegra_dc *dc, u8 *pdata, u8 data_len) int err = 0, count = 0; struct tegra_dc_dsi_data *dsi = tegra_dc_get_outdata(dc); + if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_LP_MODE) + tegra_dc_host_resume(dc); + data_len_orig = data_len; if (pdata != NULL) { while (data_len) { @@ -2610,6 +2626,8 @@ static void tegra_dc_dsi_enable(struct tegra_dc *dc) tegra_dc_io_start(dc); mutex_lock(&dsi->lock); + if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_LP_MODE) + tegra_dc_host_resume(dc); /* Stop DC stream before configuring DSI registers * to avoid visible glitches on panel during transition * from bootloader to kernel driver @@ -3072,10 +3090,8 @@ static int tegra_dsi_deep_sleep(struct tegra_dc *dc, 0); /* Disable dsi source clock */ - clk_disable(dsi->dsi_clk); - clk_disable(dsi->dsi_fixed_clk); + tegra_dsi_clk_disable(dsi); - dsi->clk_ref = false; dsi->enabled = false; return 0; @@ -3083,6 +3099,25 @@ fail: return err; } + +int tegra_dsi_host_suspend(struct tegra_dc *dc) +{ + struct tegra_dc_dsi_data *dsi = tegra_dc_get_outdata(dc); + + tegra_dsi_stop_dc_stream(dc, dsi); + + tegra_dsi_clk_disable(dsi); +} + +void tegra_dsi_host_resume(struct tegra_dc *dc) +{ + struct tegra_dc_dsi_data *dsi = tegra_dc_get_outdata(dc); + + tegra_dsi_clk_enable(dsi); + + tegra_dsi_start_dc_stream(dc, dsi); +} + static void tegra_dc_dsi_disable(struct tegra_dc *dc) { int err; |