summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin Huang <kevinh@nvidia.com>2011-06-22 18:32:23 -0700
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:47:09 -0800
commitba040048062317e4d3b770278806b63d88f5a03f (patch)
treea0f62616d81f09544816bf2a5c06707ed16dc69c
parenta75cc230abe52f2ce1afc1b45718acee3a70f2fe (diff)
video: tegra: dsi: Set dc and dsi clock for DSI burst mode.
Original-Change-Id: Ia631f7bae013f378c36fe05c665ef178bef12a46 Reviewed-on: http://git-master/r/31904 Reviewed-by: Kevin Huang <kevinh@nvidia.com> Tested-by: Kevin Huang <kevinh@nvidia.com> Reviewed-by: Jonathan Mayo <jmayo@nvidia.com> Reviewed-by: Animesh Kishore <ankishore@nvidia.com> Rebase-Id: R5b5d821365fce376a19a5527c5a9ecc9d2bfbb14
-rw-r--r--arch/arm/mach-tegra/include/mach/dc.h19
-rwxr-xr-xdrivers/video/tegra/dc/dsi.c138
2 files changed, 104 insertions, 53 deletions
diff --git a/arch/arm/mach-tegra/include/mach/dc.h b/arch/arm/mach-tegra/include/mach/dc.h
index 85e5c5015a32..4835326b346e 100644
--- a/arch/arm/mach-tegra/include/mach/dc.h
+++ b/arch/arm/mach-tegra/include/mach/dc.h
@@ -57,16 +57,17 @@ enum {
TEGRA_DSI_VIDEO_CLOCK_TX_ONLY,
};
-/* DSI burst mode setting in video mode */
+/* DSI burst mode setting in video mode. Each mode is assigned with a
+ * fixed value. The rationale behind this is to avoid change of these
+ * values, since the calculation of dsi clock depends on them. */
enum {
- TEGRA_DSI_VIDEO_NONE_BURST_MODE,
- TEGRA_DSI_VIDEO_NONE_BURST_MODE_WITH_SYNC_END,
- TEGRA_DSI_VIDEO_BURST_MODE_LOWEST_SPEED,
- TEGRA_DSI_VIDEO_BURST_MODE_LOW_SPEED,
- TEGRA_DSI_VIDEO_BURST_MODE_MEDIUM_SPEED,
- TEGRA_DSI_VIDEO_BURST_MODE_FAST_SPEED,
- TEGRA_DSI_VIDEO_BURST_MODE_FASTEST_SPEED,
- TEGRA_DSI_VIDEO_BURST_MODE_MANUAL,
+ TEGRA_DSI_VIDEO_NONE_BURST_MODE = 0,
+ TEGRA_DSI_VIDEO_NONE_BURST_MODE_WITH_SYNC_END = 1,
+ TEGRA_DSI_VIDEO_BURST_MODE_LOWEST_SPEED = 2,
+ TEGRA_DSI_VIDEO_BURST_MODE_LOW_SPEED = 3,
+ TEGRA_DSI_VIDEO_BURST_MODE_MEDIUM_SPEED = 4,
+ TEGRA_DSI_VIDEO_BURST_MODE_FAST_SPEED = 5,
+ TEGRA_DSI_VIDEO_BURST_MODE_FASTEST_SPEED = 6,
};
enum {
diff --git a/drivers/video/tegra/dc/dsi.c b/drivers/video/tegra/dc/dsi.c
index e8a2f3756226..3f4aa9411a71 100755
--- a/drivers/video/tegra/dc/dsi.c
+++ b/drivers/video/tegra/dc/dsi.c
@@ -111,9 +111,11 @@ struct tegra_dc_dsi_data {
u8 pixel_scaler_mul;
u8 pixel_scaler_div;
+ u32 default_shift_clk_div;
u32 default_pixel_clk_khz;
u32 default_hs_clk_khz;
+ u32 shift_clk_div;
u32 target_hs_clk_khz;
u32 target_lp_clk_khz;
@@ -316,17 +318,15 @@ static u32 tegra_dsi_get_hs_clk_rate(struct tegra_dc_dsi_data *dsi)
case TEGRA_DSI_VIDEO_BURST_MODE_MEDIUM_SPEED:
case TEGRA_DSI_VIDEO_BURST_MODE_FAST_SPEED:
case TEGRA_DSI_VIDEO_BURST_MODE_FASTEST_SPEED:
- /* TODO: implement algo for these speed rate */
-
- case TEGRA_DSI_VIDEO_BURST_MODE_MANUAL:
- if (dsi->info.burst_mode_freq_khz) {
- dsi_clock_rate_khz = dsi->info.burst_mode_freq_khz;
- break;
- }
+ /* Calculate DSI HS clock rate for DSI burst mode */
+ dsi_clock_rate_khz = dsi->default_pixel_clk_khz *
+ dsi->shift_clk_div;
+ break;
case TEGRA_DSI_VIDEO_NONE_BURST_MODE:
case TEGRA_DSI_VIDEO_NONE_BURST_MODE_WITH_SYNC_END:
case TEGRA_DSI_VIDEO_BURST_MODE_LOWEST_SPEED:
default:
+ /* Clock rate is default DSI clock rate for non-burst mode */
dsi_clock_rate_khz = dsi->default_hs_clk_khz;
break;
}
@@ -350,6 +350,40 @@ static u32 tegra_dsi_get_lp_clk_rate(struct tegra_dc_dsi_data *dsi)
return dsi_clock_rate_khz;
}
+static u32 tegra_dsi_get_shift_clk_div(struct tegra_dc_dsi_data *dsi)
+{
+ u32 shift_clk_div;
+ u32 max_shift_clk_div;
+ u32 burst_width;
+ u32 burst_width_max;
+
+ /* Get the real value of default shift_clk_div. default_shift_clk_div
+ * holds the real value of shift_clk_div. */
+ shift_clk_div = dsi->default_shift_clk_div;
+
+ /* Calculate shift_clk_div which can matche the video_burst_mode.*/
+ if (dsi->info.video_burst_mode >=
+ TEGRA_DSI_VIDEO_BURST_MODE_LOWEST_SPEED) {
+ /* The max_shift_clk_div is multiplied by 10 to save the
+ * fraction */
+ if (dsi->info.max_panel_freq_khz >= dsi->default_hs_clk_khz)
+ max_shift_clk_div = dsi->info.max_panel_freq_khz
+ * shift_clk_div * 10 / dsi->default_hs_clk_khz;
+ else
+ max_shift_clk_div = shift_clk_div * 10;
+
+ burst_width = dsi->info.video_burst_mode
+ - TEGRA_DSI_VIDEO_BURST_MODE_LOWEST_SPEED;
+ burst_width_max = TEGRA_DSI_VIDEO_BURST_MODE_FASTEST_SPEED
+ - TEGRA_DSI_VIDEO_BURST_MODE_LOWEST_SPEED;
+
+ shift_clk_div = (max_shift_clk_div - shift_clk_div * 10) *
+ burst_width / (burst_width_max * 10) + shift_clk_div;
+ }
+
+ return shift_clk_div;
+}
+
static void tegra_dsi_init_sw(struct tegra_dc *dc,
struct tegra_dc_dsi_data *dsi)
{
@@ -357,6 +391,7 @@ static void tegra_dsi_init_sw(struct tegra_dc *dc,
u32 v_width_lines;
u32 pixel_clk_hz;
u32 byte_clk_hz;
+ u32 plld_clk_mhz;
switch (dsi->info.pixel_format) {
case TEGRA_DSI_PIXEL_FORMAT_16BIT_P:
@@ -379,44 +414,57 @@ static void tegra_dsi_init_sw(struct tegra_dc *dc,
break;
}
+ dsi->controller_index = dc->ndev->id;
+ dsi->ulpm = false;
+ dsi->enabled = false;
+
+ dsi->dsi_control_val =
+ DSI_CONTROL_VIRTUAL_CHANNEL(dsi->info.virtual_channel) |
+ DSI_CONTROL_NUM_DATA_LANES(dsi->info.n_data_lanes - 1) |
+ DSI_CONTROL_VID_SOURCE(dsi->controller_index) |
+ DSI_CONTROL_DATA_FORMAT(dsi->info.pixel_format);
+
+ /* Below we are going to calculate dsi and dc clock rate.
+ * Calcuate the horizontal and vertical width. */
h_width_pixels = dc->mode.h_back_porch + dc->mode.h_front_porch +
dc->mode.h_sync_width + dc->mode.h_active;
v_width_lines = dc->mode.v_back_porch + dc->mode.v_front_porch +
dc->mode.v_sync_width + dc->mode.v_active;
- /* The slowest pixel rate that is required */
- /* for the given display timing */
+ /* Calculate minimum required pixel rate. */
pixel_clk_hz = h_width_pixels * v_width_lines * dsi->info.refresh_rate;
- /* Pixel byte rate on DSI interface */
- byte_clk_hz = (pixel_clk_hz * dsi->pixel_scaler_mul) /
+ /* Calculate minimum byte rate on DSI interface. */
+ byte_clk_hz = (pixel_clk_hz * dsi->pixel_scaler_mul) /
(dsi->pixel_scaler_div * dsi->info.n_data_lanes);
- dsi->default_pixel_clk_khz = pixel_clk_hz / 1000;
-
- printk("dsi: default pixel rate %d khz\n", dsi->default_pixel_clk_khz);
+ /* Round up to multiple of mega hz. */
+ plld_clk_mhz = DIV_ROUND_UP((byte_clk_hz * NUMOF_BIT_PER_BYTE),
+ 1000000);
- /*
- * Pixel bit rate on DSI. Since DSI interface is double data rate (
- * transferring data on both rising and falling edge of clk), div by 2
+ /* Calculate default real shift_clk_div. */
+ dsi->default_shift_clk_div = (NUMOF_BIT_PER_BYTE / 2) *
+ dsi->pixel_scaler_mul / (dsi->pixel_scaler_div *
+ dsi->info.n_data_lanes);
+ /* Calculate default DSI hs clock. DSI interface is double data rate.
+ * Data is transferred on both rising and falling edge of clk, div by 2
* to get the actual clock rate.
- */
- dsi->default_hs_clk_khz =
- (byte_clk_hz * NUMOF_BIT_PER_BYTE) / (1000 * 2);
-
- dsi->controller_index = dc->ndev->id;
- dsi->ulpm = false;
- dsi->enabled = false;
-
- dsi->dsi_control_val =
- DSI_CONTROL_VIRTUAL_CHANNEL(dsi->info.virtual_channel) |
- DSI_CONTROL_NUM_DATA_LANES(dsi->info.n_data_lanes - 1) |
- DSI_CONTROL_VID_SOURCE(dsi->controller_index) |
- DSI_CONTROL_DATA_FORMAT(dsi->info.pixel_format);
+ * */
+ dsi->default_hs_clk_khz = plld_clk_mhz * 1000 / 2;
+ dsi->default_pixel_clk_khz = plld_clk_mhz * 1000 / 2
+ / dsi->default_shift_clk_div;
+ /* 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_hs_clk_khz = tegra_dsi_get_hs_clk_rate(dsi);
+ dev_info(&dc->ndev->dev, "DSI: HS clock rate is %d\n",
+ dsi->target_hs_clk_khz);
+
+ dsi->controller_index = dc->ndev->id;
+ dsi->ulpm = false;
+
#if DSI_USE_SYNC_POINTS
dsi->syncpt_id = NVSYNCPT_DSI;
#endif
@@ -727,7 +775,6 @@ 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:
- case TEGRA_DSI_VIDEO_BURST_MODE_MANUAL:
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;
@@ -838,25 +885,19 @@ static void tegra_dsi_start_dc_stream(struct tegra_dc *dc,
static void tegra_dsi_set_dc_clk(struct tegra_dc *dc,
struct tegra_dc_dsi_data *dsi)
{
- u32 shift_clk_div;
+ u32 shift_clk_div_register;
u32 val;
- if (dsi->info.video_burst_mode == TEGRA_DSI_VIDEO_NONE_BURST_MODE ||
- dsi->info.video_burst_mode ==
- TEGRA_DSI_VIDEO_NONE_BURST_MODE_WITH_SYNC_END)
- shift_clk_div = NUMOF_BIT_PER_BYTE * dsi->pixel_scaler_mul /
- (dsi->pixel_scaler_div * dsi->info.n_data_lanes) - 2;
- else
- shift_clk_div = (dsi->current_dsi_clk_khz * 2 +
- dsi->default_hs_clk_khz - 1) /
- (dsi->default_hs_clk_khz) - 2;
+ /* Get the corresponding register value of shift_clk_div. */
+ shift_clk_div_register = dsi->shift_clk_div * 2 - 2;
#ifdef CONFIG_TEGRA_FPGA_PLATFORM
- shift_clk_div = 1;
+ shift_clk_div_register = 1;
#endif
/* TODO: find out if PCD3 option is required */
- val = PIXEL_CLK_DIVIDER_PCD1 | SHIFT_CLK_DIVIDER(shift_clk_div);
+ val = PIXEL_CLK_DIVIDER_PCD1 |
+ SHIFT_CLK_DIVIDER(shift_clk_div_register);
tegra_dc_writel(dc, val, DC_DISP_DISP_CLOCK_CONTROL);
clk_enable(dsi->dc_clk);
@@ -1780,9 +1821,18 @@ static int tegra_dc_dsi_cp_info(struct tegra_dc_dsi_data* dsi,
if (!dsi->info.panel_buffer_size_byte)
dsi->info.panel_buffer_size_byte = DEFAULT_PANEL_BUFFER_BYTE;
- if (!dsi->info.max_panel_freq_khz)
+ if (!dsi->info.max_panel_freq_khz) {
dsi->info.max_panel_freq_khz = DEFAULT_MAX_DSI_PHY_CLK_KHZ;
+ if (dsi->info.video_burst_mode >
+ TEGRA_DSI_VIDEO_NONE_BURST_MODE_WITH_SYNC_END){
+ dev_err(&dsi->dc->ndev->dev, "DSI: max_panel_freq_khz"
+ "is not set for DSI burst mode.\n");
+ dsi->info.video_burst_mode =
+ TEGRA_DSI_VIDEO_BURST_MODE_LOWEST_SPEED;
+ }
+ }
+
if (!dsi->info.lp_cmd_mode_freq_khz)
dsi->info.lp_cmd_mode_freq_khz = DEFAULT_LP_CMD_MODE_CLK_KHZ;