diff options
author | Jon Mayo <jmayo@nvidia.com> | 2012-07-17 18:56:44 -0400 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2015-03-18 15:03:21 -0400 |
commit | 7ee8d237919e033682b67ffcbf74d484704bb664 (patch) | |
tree | 97cd32a7443b6aa41fa38bee2ac87468c40e6962 /drivers/video/tegra/dc/dsi.c | |
parent | d8e5a40e3591240043ab79d32fd6158f6dc791b5 (diff) |
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 <jmayo@nvidia.com>
Reviewed-on: http://git-master/r/146107
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Kevin Huang (Eng-SW) <kevinh@nvidia.com>
Rebase-Id: Rf3a400e426699cbd7bf2065691efe14d43c8a695
Diffstat (limited to 'drivers/video/tegra/dc/dsi.c')
-rw-r--r-- | drivers/video/tegra/dc/dsi.c | 47 |
1 files changed, 32 insertions, 15 deletions
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, | |||
1632 | reinit_completion(&dc->frame_end_complete); | 1632 | reinit_completion(&dc->frame_end_complete); |
1633 | 1633 | ||
1634 | /* unmask frame end interrupt */ | 1634 | /* unmask frame end interrupt */ |
1635 | val = tegra_dc_readl(dc, DC_CMD_INT_MASK); | 1635 | val = tegra_dc_unmask_interrupt(dc, FRAME_END_INT); |
1636 | tegra_dc_writel(dc, val | FRAME_END_INT, DC_CMD_INT_MASK); | ||
1637 | 1636 | ||
1638 | timeout = wait_for_completion_interruptible_timeout( | 1637 | timeout = wait_for_completion_interruptible_timeout( |
1639 | &dc->frame_end_complete, | 1638 | &dc->frame_end_complete, |
@@ -2548,15 +2547,13 @@ static void tegra_dc_dsi_idle_work(struct work_struct *work) | |||
2548 | tegra_dsi_host_suspend(dsi->dc); | 2547 | tegra_dsi_host_suspend(dsi->dc); |
2549 | } | 2548 | } |
2550 | 2549 | ||
2551 | int tegra_dsi_write_data(struct tegra_dc *dc, | 2550 | static int tegra_dsi_write_data_nosync(struct tegra_dc *dc, |
2552 | struct tegra_dc_dsi_data *dsi, | 2551 | struct tegra_dc_dsi_data *dsi, |
2553 | u8 *pdata, u8 data_id, u16 data_len) | 2552 | u8 *pdata, u8 data_id, u16 data_len) |
2554 | { | 2553 | { |
2555 | int err = 0; | 2554 | int err = 0; |
2556 | struct dsi_status *init_status; | 2555 | struct dsi_status *init_status; |
2557 | 2556 | ||
2558 | tegra_dc_io_start(dc); | ||
2559 | |||
2560 | init_status = tegra_dsi_prepare_host_transmission( | 2557 | init_status = tegra_dsi_prepare_host_transmission( |
2561 | dc, dsi, DSI_LP_OP_WRITE); | 2558 | dc, dsi, DSI_LP_OP_WRITE); |
2562 | if (IS_ERR_OR_NULL(init_status)) { | 2559 | if (IS_ERR_OR_NULL(init_status)) { |
@@ -2570,10 +2567,27 @@ fail: | |||
2570 | err = tegra_dsi_restore_state(dc, dsi, init_status); | 2567 | err = tegra_dsi_restore_state(dc, dsi, init_status); |
2571 | if (err < 0) | 2568 | if (err < 0) |
2572 | dev_err(&dc->ndev->dev, "Failed to restore prev state\n"); | 2569 | dev_err(&dc->ndev->dev, "Failed to restore prev state\n"); |
2570 | |||
2571 | return err; | ||
2572 | } | ||
2573 | |||
2574 | int tegra_dsi_write_data(struct tegra_dc *dc, | ||
2575 | struct tegra_dc_dsi_data *dsi, | ||
2576 | u8 *pdata, u8 data_id, u16 data_len) | ||
2577 | { | ||
2578 | int err; | ||
2579 | |||
2580 | tegra_dc_io_start(dc); | ||
2581 | tegra_dc_dsi_hold_host(dc); | ||
2582 | |||
2583 | err = tegra_dsi_write_data_nosync(dc, dsi, pdata, data_id, data_len); | ||
2584 | |||
2585 | tegra_dc_dsi_release_host(dc); | ||
2573 | tegra_dc_io_end(dc); | 2586 | tegra_dc_io_end(dc); |
2574 | 2587 | ||
2575 | return err; | 2588 | return err; |
2576 | } | 2589 | } |
2590 | |||
2577 | EXPORT_SYMBOL(tegra_dsi_write_data); | 2591 | EXPORT_SYMBOL(tegra_dsi_write_data); |
2578 | 2592 | ||
2579 | static int tegra_dsi_send_panel_cmd(struct tegra_dc *dc, | 2593 | 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, | |||
2598 | } else if (cur_cmd->cmd_type == TEGRA_DSI_DELAY_MS) { | 2612 | } else if (cur_cmd->cmd_type == TEGRA_DSI_DELAY_MS) { |
2599 | mdelay(cur_cmd->sp_len_dly.delay_ms); | 2613 | mdelay(cur_cmd->sp_len_dly.delay_ms); |
2600 | } else { | 2614 | } else { |
2601 | err = tegra_dsi_write_data(dc, dsi, | 2615 | err = tegra_dsi_write_data_nosync(dc, dsi, |
2602 | cur_cmd->pdata, | 2616 | cur_cmd->pdata, |
2603 | cur_cmd->data_id, | 2617 | cur_cmd->data_id, |
2604 | cur_cmd->sp_len_dly.data_len); | 2618 | 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, | |||
2724 | return -EINVAL; | 2738 | return -EINVAL; |
2725 | 2739 | ||
2726 | mutex_lock(&dsi->lock); | 2740 | mutex_lock(&dsi->lock); |
2727 | tegra_dc_dsi_hold_host(dc); | ||
2728 | |||
2729 | tegra_dc_io_start(dc); | 2741 | tegra_dc_io_start(dc); |
2742 | tegra_dc_dsi_hold_host(dc); | ||
2730 | 2743 | ||
2731 | #if DSI_USE_SYNC_POINTS | 2744 | #if DSI_USE_SYNC_POINTS |
2732 | atomic_set(&dsi_syncpt_rst, 1); | 2745 | 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, | |||
2750 | tegra_dsi_writel(dsi, val, DSI_INIT_SEQ_CONTROL); | 2763 | tegra_dsi_writel(dsi, val, DSI_INIT_SEQ_CONTROL); |
2751 | 2764 | ||
2752 | fail: | 2765 | fail: |
2753 | tegra_dc_io_end(dc); | ||
2754 | tegra_dc_dsi_release_host(dc); | 2766 | tegra_dc_dsi_release_host(dc); |
2767 | tegra_dc_io_end(dc); | ||
2755 | mutex_unlock(&dsi->lock); | 2768 | mutex_unlock(&dsi->lock); |
2756 | return err; | 2769 | return err; |
2757 | 2770 | ||
@@ -2766,9 +2779,8 @@ void tegra_dsi_stop_host_cmd_v_blank_dcs(struct tegra_dc_dsi_data * dsi) | |||
2766 | u32 cnt; | 2779 | u32 cnt; |
2767 | 2780 | ||
2768 | mutex_lock(&dsi->lock); | 2781 | mutex_lock(&dsi->lock); |
2769 | tegra_dc_dsi_hold_host(dc); | ||
2770 | |||
2771 | tegra_dc_io_start(dc); | 2782 | tegra_dc_io_start(dc); |
2783 | tegra_dc_dsi_hold_host(dc); | ||
2772 | 2784 | ||
2773 | if (atomic_read(&dsi_syncpt_rst)) { | 2785 | if (atomic_read(&dsi_syncpt_rst)) { |
2774 | tegra_dsi_wait_frame_end(dc, dsi, 2); | 2786 | 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) | |||
2782 | for (cnt = 0; cnt < 8; cnt++) | 2794 | for (cnt = 0; cnt < 8; cnt++) |
2783 | tegra_dsi_writel(dsi, 0, DSI_INIT_SEQ_DATA_0 + cnt); | 2795 | tegra_dsi_writel(dsi, 0, DSI_INIT_SEQ_DATA_0 + cnt); |
2784 | 2796 | ||
2797 | tegra_dc_dsi_release_host(dc); | ||
2785 | tegra_dc_io_end(dc); | 2798 | tegra_dc_io_end(dc); |
2786 | 2799 | ||
2787 | tegra_dc_dsi_release_host(dc); | ||
2788 | mutex_unlock(&dsi->lock); | 2800 | mutex_unlock(&dsi->lock); |
2789 | } | 2801 | } |
2790 | EXPORT_SYMBOL(tegra_dsi_stop_host_cmd_v_blank_dcs); | 2802 | EXPORT_SYMBOL(tegra_dsi_stop_host_cmd_v_blank_dcs); |
@@ -3189,9 +3201,14 @@ static void _tegra_dc_dsi_enable(struct tegra_dc *dc) | |||
3189 | u32 i; | 3201 | u32 i; |
3190 | 3202 | ||
3191 | mutex_lock(&dsi->lock); | 3203 | mutex_lock(&dsi->lock); |
3204 | tegra_dc_io_start(dc); | ||
3192 | tegra_dc_dsi_hold_host(dc); | 3205 | tegra_dc_dsi_hold_host(dc); |
3193 | 3206 | ||
3194 | tegra_dc_io_start(dc); | 3207 | /* Stop DC stream before configuring DSI registers |
3208 | * to avoid visible glitches on panel during transition | ||
3209 | * from bootloader to kernel driver | ||
3210 | */ | ||
3211 | tegra_dsi_stop_dc_stream(dc, dsi); | ||
3195 | 3212 | ||
3196 | if (dsi->enabled) { | 3213 | if (dsi->enabled) { |
3197 | if (dsi->ulpm) { | 3214 | if (dsi->ulpm) { |
@@ -3309,8 +3326,8 @@ static void _tegra_dc_dsi_enable(struct tegra_dc *dc) | |||
3309 | if (dsi->status.driven == DSI_DRIVEN_MODE_DC) | 3326 | if (dsi->status.driven == DSI_DRIVEN_MODE_DC) |
3310 | tegra_dsi_start_dc_stream(dc, dsi); | 3327 | tegra_dsi_start_dc_stream(dc, dsi); |
3311 | fail: | 3328 | fail: |
3312 | tegra_dc_io_end(dc); | ||
3313 | tegra_dc_dsi_release_host(dc); | 3329 | tegra_dc_dsi_release_host(dc); |
3330 | tegra_dc_io_end(dc); | ||
3314 | mutex_unlock(&dsi->lock); | 3331 | mutex_unlock(&dsi->lock); |
3315 | } | 3332 | } |
3316 | 3333 | ||
@@ -3856,8 +3873,8 @@ static void tegra_dc_dsi_disable(struct tegra_dc *dc) | |||
3856 | int err; | 3873 | int err; |
3857 | struct tegra_dc_dsi_data *dsi = tegra_dc_get_outdata(dc); | 3874 | struct tegra_dc_dsi_data *dsi = tegra_dc_get_outdata(dc); |
3858 | 3875 | ||
3859 | tegra_dc_io_start(dc); | ||
3860 | mutex_lock(&dsi->lock); | 3876 | mutex_lock(&dsi->lock); |
3877 | tegra_dc_io_start(dc); | ||
3861 | 3878 | ||
3862 | if (dsi->status.dc_stream == DSI_DC_STREAM_ENABLE) | 3879 | if (dsi->status.dc_stream == DSI_DC_STREAM_ENABLE) |
3863 | tegra_dsi_stop_dc_stream_at_frame_end(dc, dsi, 2); | 3880 | tegra_dsi_stop_dc_stream_at_frame_end(dc, dsi, 2); |