summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnimesh Kishore <ankishore@nvidia.com>2011-09-06 18:03:35 +0530
committerVarun Colbert <vcolbert@nvidia.com>2011-09-06 16:47:04 -0700
commitfd5448995b73bb3e896765a2695d01699f2e7c99 (patch)
tree99f18431839ead821b67f55c04f968c0bfd64f75
parent4bbdf8764bbc262215ab33996e3a91473e7a7e68 (diff)
video: dsi: tegra: Use seperate LP freq for read
Recommended LP freq for read and write is sometimes different. Adding provision to use diff freq for read and write. Bug 863030 Change-Id: I49e883754bbe1ce38418d8c6ce6548f9a65152d4 Reviewed-on: http://git-master/r/49197 Reviewed-by: Varun Colbert <vcolbert@nvidia.com> Tested-by: Varun Colbert <vcolbert@nvidia.com>
-rw-r--r--arch/arm/mach-tegra/include/mach/dc.h1
-rw-r--r--drivers/video/tegra/dc/dsi.c66
2 files changed, 56 insertions, 11 deletions
diff --git a/arch/arm/mach-tegra/include/mach/dc.h b/arch/arm/mach-tegra/include/mach/dc.h
index cd6d3e374b7d..592f38d35a8e 100644
--- a/arch/arm/mach-tegra/include/mach/dc.h
+++ b/arch/arm/mach-tegra/include/mach/dc.h
@@ -162,6 +162,7 @@ struct tegra_dsi_out {
u32 max_panel_freq_khz;
u32 lp_cmd_mode_freq_khz;
+ u32 lp_read_cmd_mode_freq_khz;
u32 hs_clk_in_lp_cmd_mode_freq_khz;
u32 burst_mode_freq_khz;
diff --git a/drivers/video/tegra/dc/dsi.c b/drivers/video/tegra/dc/dsi.c
index fa0e73a4367c..a75ab3263e17 100644
--- a/drivers/video/tegra/dc/dsi.c
+++ b/drivers/video/tegra/dc/dsi.c
@@ -72,6 +72,10 @@
#define DSI_DC_STREAM_DISABLE 0x0
#define DSI_DC_STREAM_ENABLE 0x1
+#define DSI_LP_OP_NOT_INIT 0x0
+#define DSI_LP_OP_WRITE 0x1
+#define DSI_LP_OP_READ 0x2
+
struct dsi_status {
unsigned init:2;
@@ -85,6 +89,7 @@ struct dsi_status {
unsigned clk_burst:2;
unsigned dc_stream:1;
+ unsigned lp_op:1;
};
/* source of video data */
@@ -337,7 +342,7 @@ static u32 tegra_dsi_get_hs_clk_rate(struct tegra_dc_dsi_data *dsi)
return dsi_clock_rate_khz;
}
-static u32 tegra_dsi_get_lp_clk_rate(struct tegra_dc_dsi_data *dsi)
+static u32 tegra_dsi_get_lp_clk_rate(struct tegra_dc_dsi_data *dsi, u8 lp_op)
{
u32 dsi_clock_rate_khz;
@@ -348,7 +353,12 @@ static u32 tegra_dsi_get_lp_clk_rate(struct tegra_dc_dsi_data *dsi)
else
dsi_clock_rate_khz = tegra_dsi_get_hs_clk_rate(dsi);
else
- dsi_clock_rate_khz = dsi->info.lp_cmd_mode_freq_khz;
+ if (lp_op == DSI_LP_OP_READ)
+ dsi_clock_rate_khz =
+ dsi->info.lp_read_cmd_mode_freq_khz;
+ else
+ dsi_clock_rate_khz =
+ dsi->info.lp_cmd_mode_freq_khz;
return dsi_clock_rate_khz;
}
@@ -462,7 +472,7 @@ static void tegra_dsi_init_sw(struct tegra_dc *dc,
/* Get the actual shift_clk_div and clock rates. */
dsi->shift_clk_div = tegra_dsi_get_shift_clk_div(dsi);
- dsi->target_lp_clk_khz = tegra_dsi_get_lp_clk_rate(dsi);
+ dsi->target_lp_clk_khz = tegra_dsi_get_lp_clk_rate(dsi, DSI_LP_OP_WRITE);
dsi->target_hs_clk_khz = tegra_dsi_get_hs_clk_rate(dsi);
dev_info(&dc->ndev->dev, "DSI: HS clock rate is %d\n",
@@ -1134,12 +1144,14 @@ static int tegra_dsi_init_hw(struct tegra_dc *dc,
dsi->status.clk_mode = DSI_PHYCLK_NOT_INIT;
dsi->status.clk_burst = DSI_CLK_BURST_NOT_INIT;
dsi->status.dc_stream = DSI_DC_STREAM_DISABLE;
+ dsi->status.lp_op = DSI_LP_OP_NOT_INIT;
return 0;
}
static int tegra_dsi_set_to_lp_mode(struct tegra_dc *dc,
- struct tegra_dc_dsi_data *dsi)
+ struct tegra_dc_dsi_data *dsi,
+ u8 lp_op)
{
int err;
@@ -1148,7 +1160,8 @@ static int tegra_dsi_set_to_lp_mode(struct tegra_dc *dc,
goto fail;
}
- if (dsi->status.lphs == DSI_LPHS_IN_LP_MODE)
+ if (dsi->status.lphs == DSI_LPHS_IN_LP_MODE &&
+ dsi->status.lp_op == lp_op)
goto success;
if (dsi->status.dc_stream == DSI_DC_STREAM_ENABLE)
@@ -1159,6 +1172,7 @@ static int tegra_dsi_set_to_lp_mode(struct tegra_dc *dc,
(!dsi->info.enable_hs_clock_on_lp_cmd_mode))
tegra_dsi_hs_clk_out_disable(dc, dsi);
+ dsi->target_lp_clk_khz = tegra_dsi_get_lp_clk_rate(dsi, lp_op);
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);
@@ -1172,6 +1186,7 @@ static int tegra_dsi_set_to_lp_mode(struct tegra_dc *dc,
success:
dsi->status.lphs = DSI_LPHS_IN_LP_MODE;
+ dsi->status.lp_op = lp_op;
err = 0;
fail:
return err;
@@ -1340,7 +1355,7 @@ int tegra_dsi_write_data(struct tegra_dc *dc,
switch_back_to_dc_mode = true;
}
} else {
- tegra_dsi_set_to_lp_mode(dc, dsi);
+ tegra_dsi_set_to_lp_mode(dc, dsi, DSI_LP_OP_WRITE);
switch_back_to_hs_mode = true;
}
}
@@ -1526,6 +1541,8 @@ int tegra_dsi_read_data(struct tegra_dc *dc,
goto fail;
}
+ tegra_dc_io_start(dc);
+
val = tegra_dsi_readl(dsi, DSI_STATUS);
val &= DSI_STATUS_RD_FIFO_COUNT(0x1f);
if (val) {
@@ -1540,23 +1557,35 @@ int tegra_dsi_read_data(struct tegra_dc *dc,
goto fail;
}
+ val = tegra_dsi_readl(dsi, DSI_STATUS);
+ val &= (DSI_STATUS_LB_OVERFLOW(0x1) | DSI_STATUS_LB_UNDERFLOW(0x1));
+ if (val) {
+ dev_warn(&dc->ndev->dev, "Reset overflow/underflow\n");
+ val = tegra_dsi_readl(dsi, DSI_HOST_DSI_CONTROL);
+ val |= DSI_HOST_CONTROL_FIFO_STAT_RESET(0x1);
+ tegra_dsi_writel(dsi, val, DSI_HOST_DSI_CONTROL);
+ ndelay(200);
+ }
+
if (dsi->status.lphs == DSI_LPHS_IN_HS_MODE) {
if (dsi->status.driven == DSI_DRIVEN_MODE_DC) {
- if (dsi->status.dc_stream == DSI_DC_STREAM_ENABLE)
+ if (dsi->status.dc_stream == DSI_DC_STREAM_ENABLE) {
+ tegra_dsi_stop_dc_stream_at_frame_end(dc, dsi);
restart_dc_stream = true;
+ }
dsi->driven_mode = TEGRA_DSI_DRIVEN_BY_HOST;
switch_back_to_dc_mode = true;
if (dsi->info.hs_cmd_mode_supported) {
err = tegra_dsi_set_to_hs_mode(dc, dsi);
if (err < 0) {
dev_err(&dc->ndev->dev,
- "DSI failed to go to HS mode host driven\n");
+ "DSI failed to go to HS host driven mode\n");
goto fail;
}
}
}
if (!dsi->info.hs_cmd_mode_supported) {
- err = tegra_dsi_set_to_lp_mode(dc, dsi);
+ err = tegra_dsi_set_to_lp_mode(dc, dsi, DSI_LP_OP_WRITE);
if (err < 0) {
dev_err(&dc->ndev->dev,
"DSI failed to go to LP mode\n");
@@ -1586,6 +1615,15 @@ int tegra_dsi_read_data(struct tegra_dc *dc,
goto fail;
}
+ if (switch_back_to_hs_mode) {
+ err = tegra_dsi_set_to_lp_mode(dc, dsi, DSI_LP_OP_READ);
+ if (err < 0) {
+ dev_err(&dc->ndev->dev,
+ "DSI failed to go to LP mode\n");
+ goto fail;
+ }
+ }
+
err = tegra_dsi_bta(dsi);
if (err < 0) {
dev_err(&dc->ndev->dev,
@@ -1631,6 +1669,8 @@ fail:
if (restart_dc_stream)
tegra_dsi_start_dc_stream(dc, dsi);
+ tegra_dc_io_end(dc);
+
return err;
}
EXPORT_SYMBOL(tegra_dsi_read_data);
@@ -1760,7 +1800,7 @@ static void tegra_dc_dsi_enable(struct tegra_dc *dc)
}
}
- err = tegra_dsi_set_to_lp_mode(dc, dsi);
+ err = tegra_dsi_set_to_lp_mode(dc, dsi, DSI_LP_OP_WRITE);
if (err < 0) {
dev_err(&dc->ndev->dev,
"dsi: not able to set to lp mode\n");
@@ -1932,6 +1972,10 @@ static int tegra_dc_dsi_cp_info(struct tegra_dc_dsi_data *dsi,
if (!dsi->info.chip_id || !dsi->info.chip_rev)
printk(KERN_WARNING "DSI: Failed to get chip info\n");
+ if (!dsi->info.lp_read_cmd_mode_freq_khz)
+ dsi->info.lp_read_cmd_mode_freq_khz =
+ dsi->info.lp_cmd_mode_freq_khz;
+
/* host mode is for testing only*/
dsi->driven_mode = TEGRA_DSI_DRIVEN_BY_DC;
return 0;
@@ -2090,7 +2134,7 @@ static int tegra_dsi_deep_sleep(struct tegra_dc *dc,
goto fail;
}
- err = tegra_dsi_set_to_lp_mode(dc, dsi);
+ err = tegra_dsi_set_to_lp_mode(dc, dsi, DSI_LP_OP_WRITE);
if (err < 0) {
dev_err(&dc->ndev->dev,
"DSI failed to go to LP mode\n");