video: tegra: dc: 1-shot bandwidth calculation
Jon Mayo [Wed, 11 Jan 2012 22:59:55 +0000 (14:59 -0800)]
In one-shot mode(DSI) report emc rate as disabled to reduce bandwidth in
this idle state. Use this same tegra_dc_clear_bandwidth() function to handle
display disable for all types of displays.

Bug 914917

Change-Id: I84ca1341d71999b3558f9dadb103b258a1a6ab6f
Signed-off-by: Jon Mayo <jmayo@nvidia.com>
Reviewed-on: http://git-master/r/74652
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Kevin Huang (Eng-SW) <kevinh@nvidia.com>
Tested-by: Xin Xie <xxie@nvidia.com>
Reviewed-on: http://git-master/r/75536
Reviewed-by: Rohan Somvanshi <rsomvanshi@nvidia.com>
Tested-by: Rohan Somvanshi <rsomvanshi@nvidia.com>

drivers/video/tegra/dc/dc.c
drivers/video/tegra/dc/dc_priv.h

index e6fc065..e542dd1 100644 (file)
@@ -977,11 +977,21 @@ unsigned long tegra_dc_get_bandwidth(struct tegra_dc_win *windows[], int n)
        return tegra_dc_find_max_bandwidth(windows, n);
 }
 
+/* to save power, call when display memory clients would be idle */
+static void tegra_dc_clear_bandwidth(struct tegra_dc *dc)
+{
+       if (dc->emc_clk_rate)
+               clk_disable(dc->emc_clk);
+       dc->emc_clk_rate = 0;
+}
+
 static void tegra_dc_program_bandwidth(struct tegra_dc *dc)
 {
        unsigned i;
 
        if (dc->emc_clk_rate != dc->new_emc_clk_rate) {
+               if (!dc->emc_clk_rate) /* going from 0 to non-zero */
+                       clk_enable(dc->emc_clk);
                dc->emc_clk_rate = dc->new_emc_clk_rate;
                clk_set_rate(dc->emc_clk, dc->emc_clk_rate);
        }
@@ -1253,6 +1263,9 @@ int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n)
        if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
                tegra_dc_writel(dc, NC_HOST_TRIG, DC_CMD_STATE_CONTROL);
 
+       /* update EMC clock if calculated bandwidth has changed */
+       tegra_dc_program_bandwidth(dc);
+
        mutex_unlock(&dc->lock);
 
        return 0;
@@ -1952,9 +1965,6 @@ static void tegra_dc_vblank(struct work_struct *work)
 
        mutex_lock(&dc->lock);
 
-       /* update EMC clock if calculated bandwidth has changed */
-       tegra_dc_program_bandwidth(dc);
-
        /* Update the SD brightness */
        if (dc->enabled && dc->out->sd_settings)
                nvsd_updated = nvsd_update_brightness(dc);
@@ -1972,6 +1982,13 @@ static void tegra_dc_vblank(struct work_struct *work)
        }
 }
 
+static void tegra_dc_one_shot_worker(struct work_struct *work)
+{
+       struct tegra_dc *dc = container_of(work, struct tegra_dc, one_shot_work);
+       /* memory client has gone idle */
+       tegra_dc_clear_bandwidth(dc);
+}
+
 /* return an arbitrarily large number if count overflow occurs.
  * make it a nice base-10 number to show up in stats output */
 static u64 tegra_dc_underflow_count(struct tegra_dc *dc, unsigned reg)
@@ -2075,6 +2092,8 @@ static void tegra_dc_one_shot_irq(struct tegra_dc *dc, unsigned long status)
        }
 
        if (status & FRAME_END_INT) {
+               schedule_work(&dc->one_shot_work);
+
                /* Mark the frame_end as complete. */
                if (!completion_done(&dc->frame_end_complete))
                        complete(&dc->frame_end_complete);
@@ -2334,7 +2353,6 @@ static bool _tegra_dc_controller_enable(struct tegra_dc *dc)
 
        tegra_dc_setup_clk(dc, dc->clk);
        clk_enable(dc->clk);
-       clk_enable(dc->emc_clk);
 
        /* do not accept interrupts during initialization */
        tegra_dc_writel(dc, 0, DC_CMD_INT_ENABLE);
@@ -2366,7 +2384,6 @@ static bool _tegra_dc_controller_reset_enable(struct tegra_dc *dc)
 
        tegra_dc_setup_clk(dc, dc->clk);
        clk_enable(dc->clk);
-       clk_enable(dc->emc_clk);
 
        if (dc->ndev->id == 0 && tegra_dcs[1] != NULL) {
                mutex_lock(&tegra_dcs[1]->lock);
@@ -2443,7 +2460,7 @@ static void _tegra_dc_controller_disable(struct tegra_dc *dc)
        if (dc->out_ops && dc->out_ops->disable)
                dc->out_ops->disable(dc);
 
-       clk_disable(dc->emc_clk);
+       tegra_dc_clear_bandwidth(dc);
        clk_disable(dc->clk);
        tegra_dvfs_set_rate(dc->clk, 0);
 
@@ -2716,6 +2733,7 @@ static int tegra_dc_probe(struct nvhost_device *ndev)
 #endif
        INIT_WORK(&dc->vblank_work, tegra_dc_vblank);
        INIT_DELAYED_WORK(&dc->underflow_work, tegra_dc_underflow_worker);
+       INIT_WORK(&dc->one_shot_work, tegra_dc_one_shot_worker);
 
        tegra_dc_init_lut_defaults(&dc->fb_lut);
 
index 1451db8..e516bfd 100644 (file)
@@ -138,6 +138,7 @@ struct tegra_dc {
 #endif
        struct tegra_dc_lut             fb_lut;
        struct delayed_work             underflow_work;
+       struct work_struct              one_shot_work;
 };
 
 static inline void tegra_dc_io_start(struct tegra_dc *dc)