video: tegra: dc: synchronize dsi clock-gating
Rakesh Iyer [Thu, 19 Jul 2012 19:44:08 +0000 (12:44 -0700)]
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 <riyer@nvidia.com>
Reviewed-on: http://git-master/r/117137
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Jon Mayo <jmayo@nvidia.com>
GVS: Gerrit_Virtual_Submit
Reviewed-by: Animesh Kishore <ankishore@nvidia.com>
Reviewed-by: Yu-Huan Hsu <yhsu@nvidia.com>

arch/arm/mach-tegra/include/mach/dc.h
drivers/video/tegra/dc/csc.c
drivers/video/tegra/dc/dc.c
drivers/video/tegra/dc/dc_priv.h
drivers/video/tegra/dc/dsi.c
drivers/video/tegra/dc/nvsd.c
drivers/video/tegra/dc/window.c

index 97f02ce..161e376 100644 (file)
@@ -565,10 +565,6 @@ struct tegra_dc_pwm_params {
 void tegra_dc_config_pwm(struct tegra_dc *dc, struct tegra_dc_pwm_params *cfg);
 
 int tegra_dsi_send_panel_short_cmd(struct tegra_dc *dc, u8 *pdata, u8 data_len);
-void tegra_dc_host_suspend(struct tegra_dc *dc);
-void tegra_dc_host_resume(struct tegra_dc *dc);
-int tegra_dsi_host_suspend(struct tegra_dc *dc);
-int tegra_dsi_host_resume(struct tegra_dc *dc);
 
 int tegra_dc_update_csc(struct tegra_dc *dc, int win_index);
 
index 74fa900..09db5fe 100644 (file)
@@ -54,10 +54,12 @@ int tegra_dc_update_csc(struct tegra_dc *dc, int win_idx)
                return -EFAULT;
        }
 
+       tegra_dc_hold_dc_out(dc);
        tegra_dc_writel(dc, WINDOW_A_SELECT << win_idx,
                        DC_CMD_DISPLAY_WINDOW_HEADER);
 
        tegra_dc_set_csc(dc, &dc->windows[win_idx].csc);
+       tegra_dc_release_dc_out(dc);
 
        mutex_unlock(&dc->lock);
 
index 1f7e2ce..dc263fb 100644 (file)
@@ -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);
 }
 
index fb12435..332c80f 100644 (file)
@@ -75,6 +75,12 @@ struct tegra_dc_out_ops {
        void (*enable)(struct tegra_dc *dc);
        /* disable output.  dc clocks are on at this point */
        void (*disable)(struct tegra_dc *dc);
+       /* hold output.  keeps dc clocks on. */
+       void (*hold)(struct tegra_dc *dc);
+       /* release output.  dc clocks may turn off after this. */
+       void (*release)(struct tegra_dc *dc);
+       /* idle routine of output.  dc clocks may turn off after this. */
+       void (*idle)(struct tegra_dc *dc);
        /* suspend output.  dc clocks are on at this point */
        void (*suspend)(struct tegra_dc *dc);
        /* resume output.  dc clocks are on at this point */
@@ -369,6 +375,14 @@ void tegra_dc_set_out_pin_polars(struct tegra_dc *dc,
 /* defined in dc.c, used in bandwidth.c */
 unsigned int tegra_dc_has_multiple_dc(void);
 
+/* defined in dc.c, used in dsi.c */
+void tegra_dc_clk_enable(struct tegra_dc *dc);
+void tegra_dc_clk_disable(struct tegra_dc *dc);
+
+/* defined in dc.c, used in nvsd.c and dsi.c */
+void tegra_dc_hold_dc_out(struct tegra_dc *dc);
+void tegra_dc_release_dc_out(struct tegra_dc *dc);
+
 /* defined in bandwidth.c, used in dc.c */
 void tegra_dc_clear_bandwidth(struct tegra_dc *dc);
 void tegra_dc_program_bandwidth(struct tegra_dc *dc, bool use_new);
index ba8a451..935e98b 100644 (file)
@@ -294,6 +294,9 @@ const u32 init_reg[] = {
        DSI_PKT_LEN_6_7,
 };
 
+static int tegra_dsi_host_suspend(struct tegra_dc *dc);
+static int tegra_dsi_host_resume(struct tegra_dc *dc);
+
 inline unsigned long tegra_dsi_readl(struct tegra_dc_dsi_data *dsi, u32 reg)
 {
        unsigned long ret;
@@ -2118,6 +2121,39 @@ static int _tegra_dsi_write_data(struct tegra_dc_dsi_data *dsi,
        return err;
 }
 
+static void tegra_dc_dsi_hold_host(struct tegra_dc *dc)
+{
+       struct tegra_dc_dsi_data *dsi = tegra_dc_get_outdata(dc);
+
+       if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_LP_MODE) {
+               /*
+                * The reference count should never be more than 1.
+                */
+               BUG_ON(tegra_is_clk_enabled(dc->clk) > 1);
+
+               if (dsi->host_suspended)
+                       tegra_dsi_host_resume(dc);
+
+               /*
+                * Take an extra refrence to count for the clk_disable in
+                * tegra_dc_release_host.
+                */
+               clk_enable(dc->clk);
+       }
+}
+
+static void tegra_dc_dsi_release_host(struct tegra_dc *dc)
+{
+       if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_LP_MODE)
+               clk_disable(dc->clk);
+}
+
+static void tegra_dc_dsi_idle(struct tegra_dc *dc)
+{
+       if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_LP_MODE)
+               tegra_dsi_host_suspend(dc);
+}
+
 int tegra_dsi_write_data(struct tegra_dc *dc,
                        struct tegra_dc_dsi_data *dsi,
                        u8 *pdata, u8 data_id, u16 data_len)
@@ -2127,9 +2163,6 @@ int tegra_dsi_write_data(struct tegra_dc *dc,
 
        tegra_dc_io_start(dc);
 
-       if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_LP_MODE)
-               tegra_dc_host_resume(dc);
-
        init_status = tegra_dsi_prepare_host_transmission(
                                dc, dsi, DSI_LP_OP_WRITE);
        if (IS_ERR_OR_NULL(init_status)) {
@@ -2144,6 +2177,7 @@ fail:
        if (err < 0)
                dev_err(&dc->ndev->dev, "Failed to restore prev state\n");
        tegra_dc_io_end(dc);
+
        return err;
 }
 EXPORT_SYMBOL(tegra_dsi_write_data);
@@ -2289,10 +2323,10 @@ int tegra_dsi_start_host_cmd_v_blank_dcs(struct tegra_dc_dsi_data * dsi,
                return -EINVAL;
 
        mutex_lock(&dsi->lock);
+       tegra_dc_dsi_hold_host(dc);
+
        tegra_dc_io_start(dc);
 
-       if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_LP_MODE)
-               tegra_dc_host_resume(dc);
 
        err = tegra_dsi_dcs_pkt_seq_ctrl_init(dsi, cmd);
        if (err < 0) {
@@ -2313,6 +2347,7 @@ int tegra_dsi_start_host_cmd_v_blank_dcs(struct tegra_dc_dsi_data * dsi,
 
 fail:
        tegra_dc_io_end(dc);
+       tegra_dc_dsi_release_host(dc);
        mutex_unlock(&dsi->lock);
        return err;
 
@@ -2327,10 +2362,9 @@ void tegra_dsi_stop_host_cmd_v_blank_dcs(struct tegra_dc_dsi_data * dsi)
        u32 cnt;
 
        mutex_lock(&dsi->lock);
-       tegra_dc_io_start(dc);
+       tegra_dc_dsi_hold_host(dc);
 
-       if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_LP_MODE)
-               tegra_dc_host_resume(dc);
+       tegra_dc_io_start(dc);
 
        tegra_dsi_writel(dsi, TEGRA_DSI_DISABLE, DSI_INIT_SEQ_CONTROL);
 
@@ -2339,6 +2373,8 @@ void tegra_dsi_stop_host_cmd_v_blank_dcs(struct tegra_dc_dsi_data * dsi)
                tegra_dsi_writel(dsi, 0, DSI_INIT_SEQ_DATA_0 + cnt);
 
        tegra_dc_io_end(dc);
+
+       tegra_dc_dsi_release_host(dc);
        mutex_unlock(&dsi->lock);
 }
 EXPORT_SYMBOL(tegra_dsi_stop_host_cmd_v_blank_dcs);
@@ -2750,11 +2786,10 @@ static void tegra_dc_dsi_enable(struct tegra_dc *dc)
        int err;
        u32 val;
 
-       tegra_dc_io_start(dc);
        mutex_lock(&dsi->lock);
+       tegra_dc_dsi_hold_host(dc);
 
-       if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_LP_MODE)
-               tegra_dc_host_resume(dc);
+       tegra_dc_io_start(dc);
        /* Stop DC stream before configuring DSI registers
         * to avoid visible glitches on panel during transition
         * from bootloader to kernel driver
@@ -2866,8 +2901,9 @@ static void tegra_dc_dsi_enable(struct tegra_dc *dc)
        if (dsi->status.driven == DSI_DRIVEN_MODE_DC)
                tegra_dsi_start_dc_stream(dc, dsi);
 fail:
-       mutex_unlock(&dsi->lock);
        tegra_dc_io_end(dc);
+       tegra_dc_dsi_release_host(dc);
+       mutex_unlock(&dsi->lock);
 }
 
 static void _tegra_dc_dsi_init(struct tegra_dc *dc)
@@ -3261,8 +3297,7 @@ fail:
        return err;
 }
 
-
-int tegra_dsi_host_suspend(struct tegra_dc *dc)
+static int tegra_dsi_host_suspend(struct tegra_dc *dc)
 {
        int err = 0;
        struct tegra_dc_dsi_data *dsi = tegra_dc_get_outdata(dc);
@@ -3270,6 +3305,8 @@ int tegra_dsi_host_suspend(struct tegra_dc *dc)
        if (dsi->host_suspended)
                return 0;
 
+       dsi->host_suspended = true;
+
        tegra_dsi_stop_dc_stream(dc, dsi);
 
        err = tegra_dsi_deep_sleep(dc, dsi, dsi->info.suspend_aggr);
@@ -3277,13 +3314,12 @@ int tegra_dsi_host_suspend(struct tegra_dc *dc)
                dev_err(&dc->ndev->dev,
                        "DSI failed to enter deep sleep\n");
 
-       dsi->host_suspended = true;
+       tegra_dc_clk_disable(dc);
 
        return err;
 }
 
-
-int tegra_dsi_host_resume(struct tegra_dc *dc)
+static int tegra_dsi_host_resume(struct tegra_dc *dc)
 {
        int val = 0;
        int err = 0;
@@ -3292,6 +3328,7 @@ int tegra_dsi_host_resume(struct tegra_dc *dc)
        if (!dsi->host_suspended)
                return 0;
 
+       tegra_dc_clk_enable(dc);
        switch (dsi->info.suspend_aggr) {
        case DSI_HOST_SUSPEND_LV0:
                tegra_dsi_clk_enable(dsi);
@@ -3336,9 +3373,9 @@ int tegra_dsi_host_resume(struct tegra_dc *dc)
                                                "is not supported.\n");
        }
 
+       tegra_dsi_start_dc_stream(dc, dsi);
        dsi->enabled = true;
        dsi->host_suspended = false;
-       tegra_dsi_start_dc_stream(dc, dsi);
 fail:
        return err;
 }
@@ -3432,6 +3469,9 @@ struct tegra_dc_out_ops tegra_dc_dsi_ops = {
        .destroy = tegra_dc_dsi_destroy,
        .enable = tegra_dc_dsi_enable,
        .disable = tegra_dc_dsi_disable,
+       .hold = tegra_dc_dsi_hold_host,
+       .release = tegra_dc_dsi_release_host,
+       .idle = tegra_dc_dsi_idle,
 #ifdef CONFIG_PM
        .suspend = tegra_dc_dsi_suspend,
        .resume = tegra_dc_dsi_resume,
index e3058b5..6e76ee0 100644 (file)
@@ -809,9 +809,12 @@ static ssize_t nvsd_settings_store(struct kobject *kobj,
                                mutex_unlock(&dc->lock);
                                return -ENODEV;
                        }
-                       mutex_unlock(&dc->lock);
 
+                       tegra_dc_hold_dc_out(dc);
                        nvsd_init(dc, sd_settings);
+                       tegra_dc_release_dc_out(dc);
+
+                       mutex_unlock(&dc->lock);
 
                        /* Update backlight state IFF we're disabling! */
                        if (!sd_settings->enable && sd_settings->bl_device) {
index 5161dd4..0b4350d 100644 (file)
@@ -219,8 +219,7 @@ 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);
+       tegra_dc_hold_dc_out(dc);
 
        if (no_vsync)
                tegra_dc_writel(dc, WRITE_MUX_ACTIVE | READ_MUX_ACTIVE,
@@ -424,6 +423,7 @@ int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n)
        tegra_dc_writel(dc, update_mask, DC_CMD_STATE_CONTROL);
        trace_printk("%s:update_mask=%#lx\n", dc->ndev->name, update_mask);
 
+       tegra_dc_release_dc_out(dc);
        mutex_unlock(&dc->lock);
        if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
                mutex_unlock(&dc->one_shot_lock);