summaryrefslogtreecommitdiff
path: root/drivers/video/tegra/dc/dc.c
diff options
context:
space:
mode:
authorKevin Huang <kevinh@nvidia.com>2012-06-06 10:48:18 -0700
committerSimone Willett <swillett@nvidia.com>2012-06-11 17:31:24 -0700
commitb901b56e0c0573ce30393836e4078ca78beffca0 (patch)
tree6941d2d4cbd9719d26f2d3840735cca6c31bec4d /drivers/video/tegra/dc/dc.c
parentb08927a712005ae3f6941e59f530b7896ac5f407 (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/tegra/dc/dc.c')
-rw-r--r--drivers/video/tegra/dc/dc.c55
1 files changed, 49 insertions, 6 deletions
diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c
index f4844f1..f1bf5d9 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);
}