From 7ee8d237919e033682b67ffcbf74d484704bb664 Mon Sep 17 00:00:00 2001 From: Jon Mayo Date: Tue, 17 Jul 2012 15:56:44 -0700 Subject: video: tegra: dc: power optimize DC and host1x clk Use threaded IRQ to support enabling clocks in interrupt handling. Use io_start and io_end to hold and release host1x clock. Disable IRQ after it is first requested to balance enable/disable. Use disable_irq_nosync() anywhere dc->lock is held to avoid deadlock. Change tegra_dc_update_windows() to always be balanced with tegra_dc_sync_windows(). Sync points (from host1x) are potentially lost if clock gated after update, generally this only affects applications that update at a slow frame rate. To balance update and sync calls, Colormap/LUT code now performs a sync_windows on a LUT change, this makes LUT changes slower and take effect immediately. Add a nosync version of tegra_dc_dsi_write_data to be used within dsi module. Bug 1036025 Bug 1031933 Bug 1030415 Bug 1029041 Bug 1028716 Bug 1025621 Bug 1020592 Bug 1013506 Bug 1002768 Bug 955184 Bug 929609 Bug 899059 Bug 887342 Change-Id: Idc9b4c2922ad3d476d57fdf760acae76f0c837e2 Signed-off-by: Jon Mayo Reviewed-on: http://git-master/r/146107 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Kevin Huang (Eng-SW) Rebase-Id: Rf3a400e426699cbd7bf2065691efe14d43c8a695 --- drivers/video/tegra/dc/dsi.c | 47 ++++++++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 15 deletions(-) (limited to 'drivers/video/tegra/dc/dsi.c') diff --git a/drivers/video/tegra/dc/dsi.c b/drivers/video/tegra/dc/dsi.c index adfa05385..552489ef1 100644 --- a/drivers/video/tegra/dc/dsi.c +++ b/drivers/video/tegra/dc/dsi.c @@ -1632,8 +1632,7 @@ static int tegra_dsi_wait_frame_end(struct tegra_dc *dc, reinit_completion(&dc->frame_end_complete); /* unmask frame end interrupt */ - val = tegra_dc_readl(dc, DC_CMD_INT_MASK); - tegra_dc_writel(dc, val | FRAME_END_INT, DC_CMD_INT_MASK); + val = tegra_dc_unmask_interrupt(dc, FRAME_END_INT); timeout = wait_for_completion_interruptible_timeout( &dc->frame_end_complete, @@ -2548,15 +2547,13 @@ static void tegra_dc_dsi_idle_work(struct work_struct *work) tegra_dsi_host_suspend(dsi->dc); } -int tegra_dsi_write_data(struct tegra_dc *dc, +static int tegra_dsi_write_data_nosync(struct tegra_dc *dc, struct tegra_dc_dsi_data *dsi, u8 *pdata, u8 data_id, u16 data_len) { int err = 0; struct dsi_status *init_status; - tegra_dc_io_start(dc); - init_status = tegra_dsi_prepare_host_transmission( dc, dsi, DSI_LP_OP_WRITE); if (IS_ERR_OR_NULL(init_status)) { @@ -2570,10 +2567,27 @@ fail: err = tegra_dsi_restore_state(dc, dsi, init_status); if (err < 0) dev_err(&dc->ndev->dev, "Failed to restore prev state\n"); + + return err; +} + +int tegra_dsi_write_data(struct tegra_dc *dc, + struct tegra_dc_dsi_data *dsi, + u8 *pdata, u8 data_id, u16 data_len) +{ + int err; + + tegra_dc_io_start(dc); + tegra_dc_dsi_hold_host(dc); + + err = tegra_dsi_write_data_nosync(dc, dsi, pdata, data_id, data_len); + + tegra_dc_dsi_release_host(dc); tegra_dc_io_end(dc); return err; } + EXPORT_SYMBOL(tegra_dsi_write_data); static int tegra_dsi_send_panel_cmd(struct tegra_dc *dc, @@ -2598,7 +2612,7 @@ static int tegra_dsi_send_panel_cmd(struct tegra_dc *dc, } else if (cur_cmd->cmd_type == TEGRA_DSI_DELAY_MS) { mdelay(cur_cmd->sp_len_dly.delay_ms); } else { - err = tegra_dsi_write_data(dc, dsi, + err = tegra_dsi_write_data_nosync(dc, dsi, cur_cmd->pdata, cur_cmd->data_id, cur_cmd->sp_len_dly.data_len); @@ -2724,9 +2738,8 @@ 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); + tegra_dc_dsi_hold_host(dc); #if DSI_USE_SYNC_POINTS atomic_set(&dsi_syncpt_rst, 1); @@ -2750,8 +2763,8 @@ int tegra_dsi_start_host_cmd_v_blank_dcs(struct tegra_dc_dsi_data * dsi, tegra_dsi_writel(dsi, val, DSI_INIT_SEQ_CONTROL); fail: - tegra_dc_io_end(dc); tegra_dc_dsi_release_host(dc); + tegra_dc_io_end(dc); mutex_unlock(&dsi->lock); return err; @@ -2766,9 +2779,8 @@ void tegra_dsi_stop_host_cmd_v_blank_dcs(struct tegra_dc_dsi_data * dsi) u32 cnt; mutex_lock(&dsi->lock); - tegra_dc_dsi_hold_host(dc); - tegra_dc_io_start(dc); + tegra_dc_dsi_hold_host(dc); if (atomic_read(&dsi_syncpt_rst)) { tegra_dsi_wait_frame_end(dc, dsi, 2); @@ -2782,9 +2794,9 @@ void tegra_dsi_stop_host_cmd_v_blank_dcs(struct tegra_dc_dsi_data * dsi) for (cnt = 0; cnt < 8; cnt++) tegra_dsi_writel(dsi, 0, DSI_INIT_SEQ_DATA_0 + cnt); + tegra_dc_dsi_release_host(dc); 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); @@ -3189,9 +3201,14 @@ static void _tegra_dc_dsi_enable(struct tegra_dc *dc) u32 i; mutex_lock(&dsi->lock); + tegra_dc_io_start(dc); tegra_dc_dsi_hold_host(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 + */ + tegra_dsi_stop_dc_stream(dc, dsi); if (dsi->enabled) { if (dsi->ulpm) { @@ -3309,8 +3326,8 @@ 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: - tegra_dc_io_end(dc); tegra_dc_dsi_release_host(dc); + tegra_dc_io_end(dc); mutex_unlock(&dsi->lock); } @@ -3856,8 +3873,8 @@ static void tegra_dc_dsi_disable(struct tegra_dc *dc) int err; struct tegra_dc_dsi_data *dsi = tegra_dc_get_outdata(dc); - tegra_dc_io_start(dc); mutex_lock(&dsi->lock); + tegra_dc_io_start(dc); if (dsi->status.dc_stream == DSI_DC_STREAM_ENABLE) tegra_dsi_stop_dc_stream_at_frame_end(dc, dsi, 2); -- cgit v1.2.2