summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin Huang <kevinh@nvidia.com>2011-08-05 15:50:55 -0700
committerVarun Colbert <vcolbert@nvidia.com>2011-08-08 11:09:22 -0700
commit0520abff1fbb026cb7959204bfa9b1d6ecbf1d9c (patch)
tree8ef08238f498f55b092a338e03d61793b2906b7a
parentd5919c8c936620c36d6e2e1be046f253f889d05c (diff)
video: tegra: dsi: Optimize DSI suspend flow.
- Added power saving mode to reduce power consumption. It supports disable whole dsi module, source clock and panel in early suspend. - Fixed synpt error in DSI resume. Bug 859593 Bug 858500 Change-Id: I9a734db2192776a2a66ecf2b9075b3d50356e4e8 Reviewed-on: http://git-master/r/45681 Reviewed-by: Chih-Lung Huang <lhuang@nvidia.com> Tested-by: Chih-Lung Huang <lhuang@nvidia.com> Reviewed-by: Jonathan Mayo <jmayo@nvidia.com>
-rw-r--r--arch/arm/mach-tegra/include/mach/dc.h1
-rw-r--r--drivers/video/tegra/dc/dc.c2
-rw-r--r--drivers/video/tegra/dc/dsi.c302
3 files changed, 175 insertions, 130 deletions
diff --git a/arch/arm/mach-tegra/include/mach/dc.h b/arch/arm/mach-tegra/include/mach/dc.h
index 21e08ea36ffe..a622efac1fce 100644
--- a/arch/arm/mach-tegra/include/mach/dc.h
+++ b/arch/arm/mach-tegra/include/mach/dc.h
@@ -155,6 +155,7 @@ struct tegra_dsi_out {
* support eot. Don't set it for
* most panels. */
bool te_polarity_low;
+ bool power_saving_suspend;
u32 max_panel_freq_khz;
u32 lp_cmd_mode_freq_khz;
diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c
index 757370636f89..d8995ddd32a4 100644
--- a/drivers/video/tegra/dc/dc.c
+++ b/drivers/video/tegra/dc/dc.c
@@ -1163,6 +1163,8 @@ void tegra_dc_setup_clk(struct tegra_dc *dc, struct clk *clk)
parent_clk = clk_get_sys(NULL,
dc->out->parent_clk ? : "pll_d_out0");
base_clk = clk_get_parent(parent_clk);
+ tegra_clk_cfg_ex(base_clk,
+ TEGRA_CLK_PLLD_DSI_OUT_ENB, 1);
}
}
diff --git a/drivers/video/tegra/dc/dsi.c b/drivers/video/tegra/dc/dsi.c
index a4cee94de855..e332ac6f79ec 100644
--- a/drivers/video/tegra/dc/dsi.c
+++ b/drivers/video/tegra/dc/dsi.c
@@ -220,7 +220,7 @@ static const u32 dsi_pkt_seq_video_burst_no_eot[NUMOF_PKT_SEQ] = {
};
/* TODO: verify with hw about this format */
-const u32 dsi_pkt_seq_cmd_mode [NUMOF_PKT_SEQ] = {
+const u32 dsi_pkt_seq_cmd_mode[NUMOF_PKT_SEQ] = {
0,
0,
0,
@@ -236,7 +236,6 @@ const u32 dsi_pkt_seq_cmd_mode [NUMOF_PKT_SEQ] = {
};
const u32 init_reg[] = {
- DSI_WR_DATA,
DSI_INT_ENABLE,
DSI_INT_STATUS,
DSI_INT_MASK,
@@ -272,15 +271,13 @@ const u32 init_reg[] = {
DSI_PKT_LEN_6_7,
};
-inline unsigned long tegra_dsi_readl(struct tegra_dc_dsi_data *dsi,
- u32 reg)
+inline unsigned long tegra_dsi_readl(struct tegra_dc_dsi_data *dsi, u32 reg)
{
return readl(dsi->base + reg * 4);
}
EXPORT_SYMBOL(tegra_dsi_readl);
-inline void tegra_dsi_writel(struct tegra_dc_dsi_data *dsi,u32 val,
- u32 reg)
+inline void tegra_dsi_writel(struct tegra_dc_dsi_data *dsi, u32 val, u32 reg)
{
writel(val, dsi->base + reg * 4);
}
@@ -399,24 +396,24 @@ static void tegra_dsi_init_sw(struct tegra_dc *dc,
u32 plld_clk_mhz;
switch (dsi->info.pixel_format) {
- case TEGRA_DSI_PIXEL_FORMAT_16BIT_P:
- /* 2 bytes per pixel */
- dsi->pixel_scaler_mul = 2;
- dsi->pixel_scaler_div = 1;
- break;
- case TEGRA_DSI_PIXEL_FORMAT_18BIT_P:
- /* 2.25 bytes per pixel */
- dsi->pixel_scaler_mul = 9;
- dsi->pixel_scaler_div = 4;
- break;
- case TEGRA_DSI_PIXEL_FORMAT_18BIT_NP:
- case TEGRA_DSI_PIXEL_FORMAT_24BIT_P:
- /* 3 bytes per pixel */
- dsi->pixel_scaler_mul = 3;
- dsi->pixel_scaler_div = 1;
- break;
- default:
- break;
+ case TEGRA_DSI_PIXEL_FORMAT_16BIT_P:
+ /* 2 bytes per pixel */
+ dsi->pixel_scaler_mul = 2;
+ dsi->pixel_scaler_div = 1;
+ break;
+ case TEGRA_DSI_PIXEL_FORMAT_18BIT_P:
+ /* 2.25 bytes per pixel */
+ dsi->pixel_scaler_mul = 9;
+ dsi->pixel_scaler_div = 4;
+ break;
+ case TEGRA_DSI_PIXEL_FORMAT_18BIT_NP:
+ case TEGRA_DSI_PIXEL_FORMAT_24BIT_P:
+ /* 3 bytes per pixel */
+ dsi->pixel_scaler_mul = 3;
+ dsi->pixel_scaler_div = 1;
+ break;
+ default:
+ break;
}
dsi->controller_index = dc->ndev->id;
@@ -481,7 +478,8 @@ static void tegra_dsi_init_sw(struct tegra_dc *dc,
* enable_hs_clock_on_lp_cmd_mode is set
*/
if (dsi->info.enable_hs_clock_on_lp_cmd_mode) {
- if (dsi->info.video_clock_mode != TEGRA_DSI_VIDEO_CLOCK_CONTINUOUS)
+ if (dsi->info.video_clock_mode !=
+ TEGRA_DSI_VIDEO_CLOCK_CONTINUOUS)
printk("Force to clock continuous mode\n");
dsi->info.video_clock_mode = TEGRA_DSI_VIDEO_CLOCK_CONTINUOUS;
@@ -555,7 +553,7 @@ static void tegra_dsi_set_phy_timing(struct tegra_dc_dsi_data *dsi)
tegra_dsi_writel(dsi, val, DSI_PHY_TIMING_1);
val = DSI_PHY_TIMING_2_TCLKPREPARE(phy_timing.t_clkprepare) |
- DSI_PHY_TIMING_2_TCLKPRE(phy_timing.t_clkpre) |
+ DSI_PHY_TIMING_2_TCLKPRE(phy_timing.t_clkpre) |
DSI_PHY_TIMING_2_TWAKEUP(phy_timing.t_wakeup);
tegra_dsi_writel(dsi, val, DSI_PHY_TIMING_2);
@@ -693,14 +691,16 @@ static void tegra_dsi_setup_video_mode_pkt_length(struct tegra_dc *dc,
hbp_pkt_len -= DSI_HBACK_PORCH_PKT_OVERHEAD;
hfp_pkt_len -= DSI_HFRONT_PORCH_PKT_OVERHEAD;
- val = DSI_PKT_LEN_0_1_LENGTH_0(0) | DSI_PKT_LEN_0_1_LENGTH_1(hsa_pkt_len);
+ val = DSI_PKT_LEN_0_1_LENGTH_0(0) |
+ DSI_PKT_LEN_0_1_LENGTH_1(hsa_pkt_len);
tegra_dsi_writel(dsi, val, DSI_PKT_LEN_0_1);
val = DSI_PKT_LEN_2_3_LENGTH_2(hbp_pkt_len) |
DSI_PKT_LEN_2_3_LENGTH_3(hact_pkt_len);
tegra_dsi_writel(dsi, val, DSI_PKT_LEN_2_3);
- val = DSI_PKT_LEN_4_5_LENGTH_4(hfp_pkt_len) | DSI_PKT_LEN_4_5_LENGTH_5(0);
+ val = DSI_PKT_LEN_4_5_LENGTH_4(hfp_pkt_len) |
+ DSI_PKT_LEN_4_5_LENGTH_5(0);
tegra_dsi_writel(dsi, val, DSI_PKT_LEN_4_5);
val = DSI_PKT_LEN_6_7_LENGTH_6(0) | DSI_PKT_LEN_6_7_LENGTH_7(0);
@@ -755,7 +755,7 @@ static void tegra_dsi_set_pkt_seq(struct tegra_dc *dc,
if (dsi->driven_mode == TEGRA_DSI_DRIVEN_BY_HOST)
return;
- switch(dsi->info.pixel_format) {
+ switch (dsi->info.pixel_format) {
case TEGRA_DSI_PIXEL_FORMAT_16BIT_P:
rgb_info = CMD_RGB_16BPP;
break;
@@ -782,19 +782,22 @@ static void tegra_dsi_set_pkt_seq(struct tegra_dc *dc,
case TEGRA_DSI_VIDEO_BURST_MODE_MEDIUM_SPEED:
case TEGRA_DSI_VIDEO_BURST_MODE_FAST_SPEED:
case TEGRA_DSI_VIDEO_BURST_MODE_FASTEST_SPEED:
- pkt_seq_3_5_rgb_lo = DSI_PKT_SEQ_3_LO_PKT_32_ID(rgb_info);
- if(!dsi->info.no_pkt_seq_eot)
+ pkt_seq_3_5_rgb_lo =
+ DSI_PKT_SEQ_3_LO_PKT_32_ID(rgb_info);
+ if (!dsi->info.no_pkt_seq_eot)
pkt_seq = dsi_pkt_seq_video_burst;
else
pkt_seq = dsi_pkt_seq_video_burst_no_eot;
break;
case TEGRA_DSI_VIDEO_NONE_BURST_MODE_WITH_SYNC_END:
- pkt_seq_3_5_rgb_hi = DSI_PKT_SEQ_3_HI_PKT_34_ID(rgb_info);
+ pkt_seq_3_5_rgb_hi =
+ DSI_PKT_SEQ_3_HI_PKT_34_ID(rgb_info);
pkt_seq = dsi_pkt_seq_video_non_burst_syne;
break;
case TEGRA_DSI_VIDEO_NONE_BURST_MODE:
default:
- pkt_seq_3_5_rgb_lo = DSI_PKT_SEQ_3_LO_PKT_32_ID(rgb_info);
+ pkt_seq_3_5_rgb_lo =
+ DSI_PKT_SEQ_3_LO_PKT_32_ID(rgb_info);
pkt_seq = dsi_pkt_seq_video_non_burst;
break;
}
@@ -821,7 +824,8 @@ static void tegra_dsi_stop_dc_stream(struct tegra_dc *dc,
dsi->status.dc_stream = DSI_DC_STREAM_DISABLE;
}
-void tegra_dsi_stop_dc_stream_at_frame_end(struct tegra_dc *dc, struct tegra_dc_dsi_data *dsi)
+void tegra_dsi_stop_dc_stream_at_frame_end(struct tegra_dc *dc,
+ struct tegra_dc_dsi_data *dsi)
{
int val;
long timeout;
@@ -847,7 +851,7 @@ void tegra_dsi_stop_dc_stream_at_frame_end(struct tegra_dc *dc, struct tegra_dc_
val &= ~V_BLANK_INT;
tegra_dc_writel(dc, val, DC_CMD_INT_ENABLE);
- if(timeout == 0)
+ if (timeout == 0)
printk("Warning: dc dosen't stop at the end of the frame.\n");
}
@@ -922,8 +926,10 @@ static void tegra_dsi_set_dsi_clk(struct tegra_dc *dc,
if (rm != 0)
clk -= rm;
- clk *= 2; /* Value for PLLD routine is required to be twice as */
- /* the desired clock rate */
+ clk *= 2; /*
+ * Value for PLLD routine is required to be twice as
+ * the desired clock rate
+ */
dc->mode.pclk = clk*1000;
tegra_dc_setup_clk(dc, dsi->dsi_clk);
@@ -944,12 +950,6 @@ static void tegra_dsi_hs_clk_out_enable(struct tegra_dc_dsi_data *dsi)
u32 val;
struct clk *base_clk;
- /* Enable PHY clock */
- base_clk = clk_get_parent(dsi->dsi_clk);
- tegra_clk_cfg_ex(base_clk, TEGRA_CLK_PLLD_DSI_OUT_ENB, 1);
- if (dsi->info.dsi_instance)
- tegra_clk_cfg_ex(base_clk, TEGRA_CLK_PLLD_CSI_OUT_ENB, 1);
-
val = tegra_dsi_readl(dsi, DSI_CONTROL);
val &= ~DSI_CONTROL_HS_CLK_CTRL(1);
@@ -1002,12 +1002,6 @@ static void tegra_dsi_hs_clk_out_disable(struct tegra_dc *dc,
val |= DSI_HOST_DSI_CONTROL_HIGH_SPEED_TRANS(TEGRA_DSI_LOW);
tegra_dsi_writel(dsi, val, DSI_HOST_DSI_CONTROL);
- /* Disable PHY clock */
- base_clk = clk_get_parent(dsi->dsi_clk);
- tegra_clk_cfg_ex(base_clk, TEGRA_CLK_PLLD_DSI_OUT_ENB, 0);
- if (dsi->info.dsi_instance)
- tegra_clk_cfg_ex(base_clk, TEGRA_CLK_PLLD_CSI_OUT_ENB, 0);
-
dsi->status.clk_mode = DSI_PHYCLK_NOT_INIT;
dsi->status.clk_out = DSI_PHYCLK_OUT_DIS;
}
@@ -1048,12 +1042,14 @@ static void tegra_dsi_set_control_reg_hs(struct tegra_dc_dsi_data *dsi)
if (dsi->driven_mode == TEGRA_DSI_DRIVEN_BY_HOST) {
dsi_control |= DSI_CTRL_HOST_DRIVEN;
host_dsi_control |= HOST_DSI_CTRL_HOST_DRIVEN;
- max_threshold = DSI_MAX_THRESHOLD_MAX_THRESHOLD(DSI_HOST_FIFO_DEPTH);
+ max_threshold =
+ DSI_MAX_THRESHOLD_MAX_THRESHOLD(DSI_HOST_FIFO_DEPTH);
dsi->status.driven = DSI_DRIVEN_MODE_HOST;
} else {
dsi_control |= DSI_CTRL_DC_DRIVEN;
host_dsi_control |= HOST_DSI_CTRL_DC_DRIVEN;
- max_threshold = DSI_MAX_THRESHOLD_MAX_THRESHOLD(DSI_VIDEO_FIFO_DEPTH);
+ max_threshold =
+ DSI_MAX_THRESHOLD_MAX_THRESHOLD(DSI_VIDEO_FIFO_DEPTH);
dsi->status.driven = DSI_DRIVEN_MODE_DC;
}
@@ -1061,7 +1057,7 @@ static void tegra_dsi_set_control_reg_hs(struct tegra_dc_dsi_data *dsi)
dsi_control |= DSI_CTRL_CMD_MODE;
host_dsi_control |= HOST_DSI_CTRL_CMD_MODE;
dcs_cmd = DSI_DCS_CMDS_LT5_DCS_CMD(DSI_WRITE_MEMORY_START)|
- DSI_DCS_CMDS_LT3_DCS_CMD(DSI_WRITE_MEMORY_CONTINUE);
+ DSI_DCS_CMDS_LT3_DCS_CMD(DSI_WRITE_MEMORY_CONTINUE);
dsi->status.vtype = DSI_VIDEO_TYPE_CMD_MODE;
} else {
@@ -1094,17 +1090,17 @@ static int tegra_dsi_init_hw(struct tegra_dc *dc,
tegra_dsi_stop_dc_stream(dc, dsi);
/* Initializing DSI registers */
- for (i = 0; i < ARRAY_SIZE(init_reg); i++) {
+ for (i = 0; i < ARRAY_SIZE(init_reg); i++)
tegra_dsi_writel(dsi, 0, init_reg[i]);
- }
- tegra_dsi_writel(dsi, dsi->dsi_control_val, DSI_CONTROL);
+ tegra_dsi_writel(dsi, dsi->dsi_control_val, DSI_CONTROL);
/* Initialize DSI_PAD_CONTROL register. */
val = DSI_PAD_CONTROL_PAD_LPUPADJ(0x1) |
DSI_PAD_CONTROL_PAD_LPDNADJ(0x1) |
DSI_PAD_CONTROL_PAD_PREEMP_EN(0x1) |
DSI_PAD_CONTROL_PAD_SLEWDNADJ(0x6) |
DSI_PAD_CONTROL_PAD_SLEWUPADJ(0x6);
+
if (!dsi->ulpm) {
val |= DSI_PAD_CONTROL_PAD_PDIO(0) |
DSI_PAD_CONTROL_PAD_PDIO_CLK(0) |
@@ -1119,9 +1115,8 @@ static int tegra_dsi_init_hw(struct tegra_dc *dc,
val = DSI_POWER_CONTROL_LEG_DSI_ENABLE(TEGRA_DSI_ENABLE);
tegra_dsi_writel(dsi, val, DSI_POWER_CONTROL);
- while (tegra_dsi_readl(dsi, DSI_POWER_CONTROL) != val) {
+ while (tegra_dsi_readl(dsi, DSI_POWER_CONTROL) != val)
tegra_dsi_writel(dsi, val, DSI_POWER_CONTROL);
- }
dsi->status.init = DSI_MODULE_INIT;
dsi->status.lphs = DSI_LPHS_NOT_INIT;
@@ -1138,7 +1133,7 @@ static int tegra_dsi_init_hw(struct tegra_dc *dc,
static int tegra_dsi_set_to_lp_mode(struct tegra_dc *dc,
struct tegra_dc_dsi_data *dsi)
{
- int err;
+ int err;
if (dsi->status.init != DSI_MODULE_INIT) {
err = -EPERM;
@@ -1151,12 +1146,12 @@ static int tegra_dsi_set_to_lp_mode(struct tegra_dc *dc,
if (dsi->status.dc_stream == DSI_DC_STREAM_ENABLE)
tegra_dsi_stop_dc_stream_at_frame_end(dc, dsi);
- /* disable/enable hs clock according to enable_hs_clock_on_lp_cmd_mode */
+ /* disable/enable hs clk according to enable_hs_clock_on_lp_cmd_mode */
if ((dsi->status.clk_out == DSI_PHYCLK_OUT_EN) &&
(!dsi->info.enable_hs_clock_on_lp_cmd_mode))
tegra_dsi_hs_clk_out_disable(dc, dsi);
- if (dsi->current_dsi_clk_khz != dsi->target_lp_clk_khz){
+ if (dsi->current_dsi_clk_khz != dsi->target_lp_clk_khz) {
tegra_dsi_set_dsi_clk(dc, dsi, dsi->target_lp_clk_khz);
tegra_dsi_set_timeout(dsi);
}
@@ -1198,7 +1193,7 @@ static int tegra_dsi_set_to_hs_mode(struct tegra_dc *dc,
tegra_dsi_set_phy_timing(dsi);
- if (dsi->driven_mode == TEGRA_DSI_DRIVEN_BY_DC){
+ if (dsi->driven_mode == TEGRA_DSI_DRIVEN_BY_DC) {
tegra_dsi_set_pkt_seq(dc, dsi);
tegra_dsi_set_pkt_length(dc, dsi);
tegra_dsi_set_sol_delay(dc, dsi);
@@ -1262,7 +1257,7 @@ fail:
}
static int _tegra_dsi_write_data(struct tegra_dc_dsi_data *dsi,
- u8* pdata, u8 data_id, u16 data_len)
+ u8 *pdata, u8 data_id, u16 data_len)
{
u8 virtual_channel;
u8 *pval;
@@ -1271,7 +1266,8 @@ static int _tegra_dsi_write_data(struct tegra_dc_dsi_data *dsi,
err = 0;
- virtual_channel = dsi->info.virtual_channel << DSI_VIR_CHANNEL_BIT_POSITION;
+ virtual_channel = dsi->info.virtual_channel <<
+ DSI_VIR_CHANNEL_BIT_POSITION;
/* always use hw for ecc */
val = (virtual_channel | data_id) << 0 |
@@ -1282,15 +1278,15 @@ static int _tegra_dsi_write_data(struct tegra_dc_dsi_data *dsi,
if (pdata != NULL) {
while (data_len) {
if (data_len >= 4) {
- val = ((u32*) pdata)[0];
+ val = ((u32 *) pdata)[0];
data_len -= 4;
pdata += 4;
} else {
val = 0;
- pval = (u8*) &val;
+ pval = (u8 *) &val;
do
*pval++ = *pdata++;
- while(--data_len);
+ while (--data_len);
}
tegra_dsi_writel(dsi, val, DSI_WR_DATA);
}
@@ -1305,7 +1301,7 @@ static int _tegra_dsi_write_data(struct tegra_dc_dsi_data *dsi,
int tegra_dsi_write_data(struct tegra_dc *dc,
struct tegra_dc_dsi_data *dsi,
- u8* pdata, u8 data_id, u16 data_len)
+ u8 *pdata, u8 data_id, u16 data_len)
{
bool switch_back_to_hs_mode;
bool switch_back_to_dc_mode;
@@ -1733,13 +1729,6 @@ static void tegra_dc_dsi_enable(struct tegra_dc *dc)
goto fail;
}
}
-
- err = tegra_dsi_set_to_hs_mode(dc, dsi);
- if (err < 0) {
- dev_err(&dc->ndev->dev,
- "dsi: not able to set to hs mode\n");
- goto fail;
- }
} else {
err = tegra_dsi_init_hw(dc, dsi);
if (err < 0) {
@@ -1803,8 +1792,8 @@ static void _tegra_dc_dsi_init(struct tegra_dc *dc)
/* TODO: Configure the CSI pad configuration */
}
-static int tegra_dc_dsi_cp_p_cmd(struct tegra_dsi_cmd* src,
- struct tegra_dsi_cmd* dst, u16 n_cmd)
+static int tegra_dc_dsi_cp_p_cmd(struct tegra_dsi_cmd *src,
+ struct tegra_dsi_cmd *dst, u16 n_cmd)
{
u16 i;
u16 len;
@@ -1813,7 +1802,8 @@ static int tegra_dc_dsi_cp_p_cmd(struct tegra_dsi_cmd* src,
for (i = 0; i < n_cmd; i++)
if (src[i].pdata) {
- len = sizeof(*src[i].pdata) * src[i].sp_len_dly.data_len;
+ len = sizeof(*src[i].pdata) *
+ src[i].sp_len_dly.data_len;
dst[i].pdata = kzalloc(len, GFP_KERNEL);
if (!dst[i].pdata)
goto free_cmd_pdata;
@@ -1823,14 +1813,14 @@ static int tegra_dc_dsi_cp_p_cmd(struct tegra_dsi_cmd* src,
return 0;
free_cmd_pdata:
- for (--i; i >=0; i--)
+ for (--i; i >= 0; i--)
if (dst[i].pdata)
kfree(dst[i].pdata);
return -ENOMEM;
}
-static int tegra_dc_dsi_cp_info(struct tegra_dc_dsi_data* dsi,
- struct tegra_dsi_out* p_dsi)
+static int tegra_dc_dsi_cp_info(struct tegra_dc_dsi_data *dsi,
+ struct tegra_dsi_out *p_dsi)
{
struct tegra_dsi_cmd *p_init_cmd;
struct tegra_dsi_cmd *p_early_suspend_cmd;
@@ -1910,7 +1900,8 @@ static int tegra_dc_dsi_cp_info(struct tegra_dc_dsi_data* dsi,
dsi->info.dsi_suspend_cmd = p_suspend_cmd;
if (!dsi->info.panel_reset_timeout_msec)
- dsi->info.panel_reset_timeout_msec = DEFAULT_PANEL_RESET_TIMEOUT;
+ dsi->info.panel_reset_timeout_msec =
+ DEFAULT_PANEL_RESET_TIMEOUT;
if (!dsi->info.panel_buffer_size_byte)
dsi->info.panel_buffer_size_byte = DEFAULT_PANEL_BUFFER_BYTE;
@@ -2047,18 +2038,18 @@ static void tegra_dc_dsi_destroy(struct tegra_dc *dc)
mutex_lock(&dsi->lock);
/* free up the pdata*/
- for(i = 0; i < dsi->info.n_init_cmd; i++){
- if(dsi->info.dsi_init_cmd[i].pdata)
+ for (i = 0; i < dsi->info.n_init_cmd; i++) {
+ if (dsi->info.dsi_init_cmd[i].pdata)
kfree(dsi->info.dsi_init_cmd[i].pdata);
}
kfree(dsi->info.dsi_init_cmd);
/* Disable dc stream*/
- if(dsi->status.dc_stream == DSI_DC_STREAM_ENABLE)
+ if (dsi->status.dc_stream == DSI_DC_STREAM_ENABLE)
tegra_dsi_stop_dc_stream(dc, dsi);
/* Disable dsi phy clock*/
- if(dsi->status.clk_out == DSI_PHYCLK_OUT_EN)
+ if (dsi->status.clk_out == DSI_PHYCLK_OUT_EN)
tegra_dsi_hs_clk_out_disable(dc, dsi);
val = DSI_POWER_CONTROL_LEG_DSI_ENABLE(TEGRA_DSI_DISABLE);
@@ -2079,36 +2070,85 @@ static void tegra_dc_dsi_destroy(struct tegra_dc *dc)
static void tegra_dc_dsi_disable(struct tegra_dc *dc)
{
int err;
+ u32 val;
+ struct clk *base_clk;
struct tegra_dc_dsi_data *dsi = tegra_dc_get_outdata(dc);
tegra_dc_io_start(dc);
mutex_lock(&dsi->lock);
if (dsi->status.dc_stream == DSI_DC_STREAM_ENABLE)
- tegra_dsi_stop_dc_stream(dc, dsi);
+ tegra_dsi_stop_dc_stream_at_frame_end(dc, dsi);
+
+ if (dsi->info.power_saving_suspend) {
+ if (!dsi->enabled)
+ goto fail;
+
+ err = tegra_dsi_set_to_lp_mode(dc, dsi);
+ if (err < 0) {
+ dev_err(&dc->ndev->dev,
+ "DSI failed to go to LP mode\n");
+ goto fail;
+ }
- if (dsi->info.dsi_early_suspend_cmd) {
err = tegra_dsi_send_panel_cmd(dc, dsi,
- dsi->info.dsi_early_suspend_cmd,
- dsi->info.n_early_suspend_cmd);
+ dsi->info.dsi_suspend_cmd,
+ dsi->info.n_suspend_cmd);
if (err < 0) {
dev_err(&dc->ndev->dev,
- "dsi: Error sending early suspend cmd\n");
+ "dsi: Error sending suspend cmd\n");
goto fail;
}
- }
- err = tegra_dsi_set_to_lp_mode(dc, dsi);
- if (err < 0) {
- dev_err(&dc->ndev->dev,
- "dsi: not able to set to lp mode\n");
- goto fail;
- }
+ if (!dsi->ulpm) {
+ if (tegra_dsi_enter_ulpm(dsi) < 0)
+ printk(KERN_ERR "DSI failed to enter ulpm\n");
+ }
- if (!dsi->ulpm) {
- if (tegra_dsi_enter_ulpm(dsi) < 0)
- printk(KERN_ERR "DSI failed to enter ulpm\n");
+ /* Suspend pad */
+ val = tegra_dsi_readl(dsi, DSI_PAD_CONTROL);
+ val = DSI_PAD_CONTROL_PAD_PDIO(0x3) |
+ DSI_PAD_CONTROL_PAD_PDIO_CLK(0x1) |
+ DSI_PAD_CONTROL_PAD_PULLDN_ENAB(TEGRA_DSI_ENABLE);
+ tegra_dsi_writel(dsi, val, DSI_PAD_CONTROL);
+
+ /* Suspend core-logic */
+ val = DSI_POWER_CONTROL_LEG_DSI_ENABLE(TEGRA_DSI_DISABLE);
+ tegra_dsi_writel(dsi, val, DSI_POWER_CONTROL);
+
+ /* Disable phy clock */
+ base_clk = clk_get_parent(dsi->dsi_clk);
+ if (dsi->info.dsi_instance)
+ tegra_clk_cfg_ex(base_clk,
+ TEGRA_CLK_PLLD_CSI_OUT_ENB,
+ 0);
+ else
+ tegra_clk_cfg_ex(base_clk,
+ TEGRA_CLK_PLLD_DSI_OUT_ENB,
+ 0);
+
+ /* Disable DSI source clock */
+ clk_disable(dsi->dsi_clk);
+ dsi->clk_ref = false;
+ dsi->enabled = false;
+ } else {
+ if (dsi->info.dsi_early_suspend_cmd) {
+ err = tegra_dsi_send_panel_cmd(dc, dsi,
+ dsi->info.dsi_early_suspend_cmd,
+ dsi->info.n_early_suspend_cmd);
+ if (err < 0) {
+ dev_err(&dc->ndev->dev,
+ "dsi: Error sending early suspend cmd\n");
+ goto fail;
+ }
+ }
+
+ if (!dsi->ulpm) {
+ if (tegra_dsi_enter_ulpm(dsi) < 0)
+ printk(KERN_ERR "DSI failed to enter ulpm\n");
+ }
}
+
fail:
mutex_unlock(&dsi->lock);
tegra_dc_io_end(dc);
@@ -2129,44 +2169,46 @@ static void tegra_dc_dsi_suspend(struct tegra_dc *dc)
if (!dsi->enabled)
goto fail;
- if (dsi->ulpm) {
- if (tegra_dsi_exit_ulpm(dsi) < 0) {
- printk(KERN_ERR "DSI failed to exit ulpm");
- goto fail;
+ if (!dsi->info.power_saving_suspend) {
+ if (dsi->ulpm) {
+ if (tegra_dsi_exit_ulpm(dsi) < 0) {
+ printk(KERN_ERR "DSI failed to exit ulpm");
+ goto fail;
+ }
}
- }
- /* Suspend Panel */
- err = tegra_dsi_send_panel_cmd(dc, dsi,
- dsi->info.dsi_suspend_cmd,
- dsi->info.n_suspend_cmd);
- if (err < 0) {
- dev_err(&dc->ndev->dev,
- "dsi: Error sending suspend cmd\n");
- goto fail;
- }
- if (!dsi->ulpm) {
- if (tegra_dsi_enter_ulpm(dsi) < 0) {
- printk(KERN_ERR "DSI failed to enter ulpm\n");
+ /* Suspend Panel */
+ err = tegra_dsi_send_panel_cmd(dc, dsi,
+ dsi->info.dsi_suspend_cmd,
+ dsi->info.n_suspend_cmd);
+ if (err < 0) {
+ dev_err(&dc->ndev->dev,
+ "dsi: Error sending suspend cmd\n");
goto fail;
}
- }
+ if (!dsi->ulpm) {
+ if (tegra_dsi_enter_ulpm(dsi) < 0) {
+ printk(KERN_ERR "DSI failed to enter ulpm\n");
+ goto fail;
+ }
+ }
- /* Suspend pad */
- val = tegra_dsi_readl(dsi, DSI_PAD_CONTROL);
- val = DSI_PAD_CONTROL_PAD_PDIO(0x3) |
- DSI_PAD_CONTROL_PAD_PDIO_CLK(0x1) |
- DSI_PAD_CONTROL_PAD_PULLDN_ENAB(TEGRA_DSI_ENABLE);
- tegra_dsi_writel(dsi, val, DSI_PAD_CONTROL);
+ /* Suspend pad */
+ val = tegra_dsi_readl(dsi, DSI_PAD_CONTROL);
+ val = DSI_PAD_CONTROL_PAD_PDIO(0x3) |
+ DSI_PAD_CONTROL_PAD_PDIO_CLK(0x1) |
+ DSI_PAD_CONTROL_PAD_PULLDN_ENAB(TEGRA_DSI_ENABLE);
+ tegra_dsi_writel(dsi, val, DSI_PAD_CONTROL);
- /* Suspend core-logic */
- val = DSI_POWER_CONTROL_LEG_DSI_ENABLE(TEGRA_DSI_DISABLE);
- tegra_dsi_writel(dsi, val, DSI_POWER_CONTROL);
+ /* Suspend core-logic */
+ val = DSI_POWER_CONTROL_LEG_DSI_ENABLE(TEGRA_DSI_DISABLE);
+ tegra_dsi_writel(dsi, val, DSI_POWER_CONTROL);
- dsi->enabled = false;
+ dsi->enabled = false;
- clk_disable(dsi->dsi_clk);
- dsi->clk_ref = false;
+ clk_disable(dsi->dsi_clk);
+ dsi->clk_ref = false;
+ }
fail:
mutex_unlock(&dsi->lock);
tegra_dc_io_end(dc);