summaryrefslogtreecommitdiff
path: root/drivers/video/tegra/dc/dsi.c
diff options
context:
space:
mode:
authorAnimesh Kishore <ankishore@nvidia.com>2012-02-22 21:07:00 +0530
committerSimone Willett <swillett@nvidia.com>2012-02-23 21:19:54 -0800
commit2e11ad144a36c2fe438bae13ca3259c1b5dbff6b (patch)
tree083a9fb96f62dc6ea203d58475ae4905c146fea4 /drivers/video/tegra/dc/dsi.c
parent97d4143b0c92d5e34ddce226c9fe35c16c87017b (diff)
video: tegra: dsi: Fix dsi phy timing
Corrected the formulas to calculate phy timing. Added mipi d-phy constraints. Bug 938043 Change-Id: Ie1f2dd45e7e39f83735fe28e21a62dc0415c7c00 Signed-off-by: Animesh Kishore <ankishore@nvidia.com> Reviewed-on: http://git-master/r/85217 Reviewed-by: Jon Mayo <jmayo@nvidia.com> Reviewed-by: Krishna Yarlagadda <kyarlagadda@nvidia.com> Reviewed-by: Laxman Dewangan <ldewangan@nvidia.com>
Diffstat (limited to 'drivers/video/tegra/dc/dsi.c')
-rw-r--r--drivers/video/tegra/dc/dsi.c330
1 files changed, 293 insertions, 37 deletions
diff --git a/drivers/video/tegra/dc/dsi.c b/drivers/video/tegra/dc/dsi.c
index 18670cca9f4d..92d9d9a17e9e 100644
--- a/drivers/video/tegra/dc/dsi.c
+++ b/drivers/video/tegra/dc/dsi.c
@@ -116,6 +116,8 @@ struct tegra_dc_dsi_data {
struct dsi_status status;
+ struct dsi_phy_timing_inclk phy_timing;
+
u8 driven_mode;
u8 controller_index;
@@ -508,63 +510,313 @@ static void tegra_dsi_init_sw(struct tegra_dc *dc,
}
+#define SELECT_T_PHY(platform_t_phy_ns, default_phy, clk_ns) ( \
+ (platform_t_phy_ns) ? ( \
+ ((DSI_CONVERT_T_PHY_NS_TO_T_PHY(platform_t_phy_ns, clk_ns)) < 0 ? 0 : \
+ (DSI_CONVERT_T_PHY_NS_TO_T_PHY(platform_t_phy_ns, clk_ns)))) : \
+ ((default_phy) < 0 ? 0 : (default_phy)))
+
+static void tegra_dsi_get_clk_phy_timing(struct tegra_dc_dsi_data *dsi,
+ struct dsi_phy_timing_inclk *phy_timing_clk, u32 clk_ns)
+{
+ phy_timing_clk->t_tlpx = SELECT_T_PHY(
+ dsi->info.phy_timing.t_tlpx_ns,
+ T_TLPX_DEFAULT(clk_ns), clk_ns);
+
+ phy_timing_clk->t_clktrail = SELECT_T_PHY(
+ dsi->info.phy_timing.t_clktrail_ns,
+ T_CLKTRAIL_DEFAULT(clk_ns), clk_ns);
+
+ phy_timing_clk->t_clkpost = SELECT_T_PHY(
+ dsi->info.phy_timing.t_clkpost_ns,
+ T_CLKPOST_DEFAULT(clk_ns), clk_ns);
+
+ phy_timing_clk->t_clkzero = SELECT_T_PHY(
+ dsi->info.phy_timing.t_clkzero_ns,
+ T_CLKZERO_DEFAULT(clk_ns), clk_ns);
+
+ phy_timing_clk->t_clkprepare = SELECT_T_PHY(
+ dsi->info.phy_timing.t_clkprepare_ns,
+ T_CLKPREPARE_DEFAULT(clk_ns), clk_ns);
+
+ phy_timing_clk->t_clkpre = SELECT_T_PHY(
+ dsi->info.phy_timing.t_clkpre_ns,
+ T_CLKPRE_DEFAULT, clk_ns);
+}
+
+static void tegra_dsi_get_hs_phy_timing(struct tegra_dc_dsi_data *dsi,
+ struct dsi_phy_timing_inclk *phy_timing_clk, u32 clk_ns)
+{
+ phy_timing_clk->t_tlpx = SELECT_T_PHY(
+ dsi->info.phy_timing.t_tlpx_ns,
+ T_TLPX_DEFAULT(clk_ns), clk_ns);
+
+ phy_timing_clk->t_hsdexit = SELECT_T_PHY(
+ dsi->info.phy_timing.t_hsdexit_ns,
+ T_HSEXIT_DEFAULT(clk_ns), clk_ns);
+
+ phy_timing_clk->t_hstrail = SELECT_T_PHY(
+ dsi->info.phy_timing.t_hstrail_ns,
+ T_HSTRAIL_DEFAULT(clk_ns), clk_ns);
+
+ phy_timing_clk->t_datzero = SELECT_T_PHY(
+ dsi->info.phy_timing.t_datzero_ns,
+ T_DATZERO_DEFAULT(clk_ns), clk_ns);
+
+ phy_timing_clk->t_hsprepare = SELECT_T_PHY(
+ dsi->info.phy_timing.t_hsprepare_ns,
+ T_HSPREPARE_DEFAULT(clk_ns), clk_ns);
+}
+
+static void tegra_dsi_get_escape_phy_timing(struct tegra_dc_dsi_data *dsi,
+ struct dsi_phy_timing_inclk *phy_timing_clk, u32 clk_ns)
+{
+ phy_timing_clk->t_tlpx = SELECT_T_PHY(
+ dsi->info.phy_timing.t_tlpx_ns,
+ T_TLPX_DEFAULT(clk_ns), clk_ns);
+}
+
+static void tegra_dsi_get_bta_phy_timing(struct tegra_dc_dsi_data *dsi,
+ struct dsi_phy_timing_inclk *phy_timing_clk, u32 clk_ns)
+{
+ phy_timing_clk->t_tlpx = SELECT_T_PHY(
+ dsi->info.phy_timing.t_tlpx_ns,
+ T_TLPX_DEFAULT(clk_ns), clk_ns);
+
+ phy_timing_clk->t_taget = SELECT_T_PHY(
+ dsi->info.phy_timing.t_taget_ns,
+ T_TAGET_DEFAULT(clk_ns), clk_ns);
+
+ phy_timing_clk->t_tasure = SELECT_T_PHY(
+ dsi->info.phy_timing.t_tasure_ns,
+ T_TASURE_DEFAULT(clk_ns), clk_ns);
+
+ phy_timing_clk->t_tago = SELECT_T_PHY(
+ dsi->info.phy_timing.t_tago_ns,
+ T_TAGO_DEFAULT(clk_ns), clk_ns);
+}
+
+static void tegra_dsi_get_ulps_phy_timing(struct tegra_dc_dsi_data *dsi,
+ struct dsi_phy_timing_inclk *phy_timing_clk, u32 clk_ns)
+{
+ phy_timing_clk->t_tlpx = SELECT_T_PHY(
+ dsi->info.phy_timing.t_tlpx_ns,
+ T_TLPX_DEFAULT(clk_ns), clk_ns);
+
+ phy_timing_clk->t_wakeup = SELECT_T_PHY(
+ dsi->info.phy_timing.t_wakeup_ns,
+ T_WAKEUP_DEFAULT, clk_ns);
+}
+
+#undef SELECT_T_PHY
+
static void tegra_dsi_get_phy_timing(struct tegra_dc_dsi_data *dsi,
struct dsi_phy_timing_inclk *phy_timing_clk,
- u32 clk_ns)
+ u32 clk_ns, u8 lphs)
{
+ if (lphs == DSI_LPHS_IN_HS_MODE) {
+ tegra_dsi_get_clk_phy_timing(dsi, phy_timing_clk, clk_ns);
+ tegra_dsi_get_hs_phy_timing(dsi, phy_timing_clk, clk_ns);
+ } else {
+ /* default is LP mode */
+ tegra_dsi_get_escape_phy_timing(dsi, phy_timing_clk, clk_ns);
+ tegra_dsi_get_bta_phy_timing(dsi, phy_timing_clk, clk_ns);
+ tegra_dsi_get_ulps_phy_timing(dsi, phy_timing_clk, clk_ns);
+ if (dsi->info.enable_hs_clock_on_lp_cmd_mode)
+ tegra_dsi_get_clk_phy_timing
+ (dsi, phy_timing_clk, clk_ns);
+ }
+}
- phy_timing_clk->t_hsdexit = dsi->info.phy_timing.t_hsdexit_ns ?
- (dsi->info.phy_timing.t_hsdexit_ns / clk_ns) :
- (T_HSEXIT_DEFAULT(clk_ns));
+static int tegra_dsi_mipi_phy_timing_range(struct tegra_dc_dsi_data *dsi,
+ struct dsi_phy_timing_inclk *phy_timing,
+ u32 clk_ns, u8 lphs)
+{
+#define CHECK_RANGE(val, min, max) ( \
+ ((min) == NOT_DEFINED ? 0 : (val) < (min)) || \
+ ((max) == NOT_DEFINED ? 0 : (val) > (max)) ? -EINVAL : 0)
- phy_timing_clk->t_hstrail = dsi->info.phy_timing.t_hstrail_ns ?
- (dsi->info.phy_timing.t_hstrail_ns / clk_ns) :
- (T_HSTRAIL_DEFAULT(clk_ns));
+ int err = 0;
- phy_timing_clk->t_datzero = dsi->info.phy_timing.t_datzero_ns ?
- (dsi->info.phy_timing.t_datzero_ns / clk_ns) :
- (T_DATZERO_DEFAULT(clk_ns));
+ err = CHECK_RANGE(
+ DSI_CONVERT_T_PHY_TO_T_PHY_NS(phy_timing->t_tlpx, clk_ns),
+ MIPI_T_TLPX_NS_MIN, MIPI_T_TLPX_NS_MAX);
+ if (err < 0) {
+ dev_warn(&dsi->dc->ndev->dev,
+ "dsi: Tlpx mipi range violated\n");
+ goto fail;
+ }
- phy_timing_clk->t_hsprepr = dsi->info.phy_timing.t_hsprepr_ns ?
- (dsi->info.phy_timing.t_hsprepr_ns / clk_ns) :
- (T_HSPREPR_DEFAULT(clk_ns));
+ if (lphs == DSI_LPHS_IN_HS_MODE) {
+ err = CHECK_RANGE(
+ DSI_CONVERT_T_PHY_TO_T_PHY_NS(phy_timing->t_hsdexit, clk_ns),
+ MIPI_T_HSEXIT_NS_MIN, MIPI_T_HSEXIT_NS_MAX);
+ if (err < 0) {
+ dev_warn(&dsi->dc->ndev->dev,
+ "dsi: HsExit mipi range violated\n");
+ goto fail;
+ }
- phy_timing_clk->t_clktrail = dsi->info.phy_timing.t_clktrail_ns ?
- (dsi->info.phy_timing.t_clktrail_ns / clk_ns) :
- (T_CLKTRAIL_DEFAULT(clk_ns));
+ err = CHECK_RANGE(
+ DSI_CONVERT_T_PHY_TO_T_PHY_NS(phy_timing->t_hstrail, clk_ns),
+ MIPI_T_HSTRAIL_NS_MIN(clk_ns), MIPI_T_HSTRAIL_NS_MAX);
+ if (err < 0) {
+ dev_warn(&dsi->dc->ndev->dev,
+ "dsi: HsTrail mipi range violated\n");
+ goto fail;
+ }
- phy_timing_clk->t_clkpost = dsi->info.phy_timing.t_clkpost_ns ?
- (dsi->info.phy_timing.t_clkpost_ns / clk_ns) :
- (T_CLKPOST_DEFAULT(clk_ns));
+ err = CHECK_RANGE(
+ DSI_CONVERT_T_PHY_TO_T_PHY_NS(phy_timing->t_datzero, clk_ns),
+ MIPI_T_HSZERO_NS_MIN, MIPI_T_HSZERO_NS_MAX);
+ if (err < 0) {
+ dev_warn(&dsi->dc->ndev->dev,
+ "dsi: HsZero mipi range violated\n");
+ goto fail;
+ }
- phy_timing_clk->t_clkzero = dsi->info.phy_timing.t_clkzero_ns ?
- (dsi->info.phy_timing.t_clkzero_ns / clk_ns) :
- (T_CLKZERO_DEFAULT(clk_ns));
+ err = CHECK_RANGE(
+ DSI_CONVERT_T_PHY_TO_T_PHY_NS(phy_timing->t_hsprepare, clk_ns),
+ MIPI_T_HSPREPARE_NS_MIN(clk_ns),
+ MIPI_T_HSPREPARE_NS_MAX(clk_ns));
+ if (err < 0) {
+ dev_warn(&dsi->dc->ndev->dev,
+ "dsi: HsPrepare mipi range violated\n");
+ goto fail;
+ }
- phy_timing_clk->t_tlpx = dsi->info.phy_timing.t_tlpx_ns ?
- (dsi->info.phy_timing.t_tlpx_ns / clk_ns) :
- (T_TLPX_DEFAULT(clk_ns));
+ err = CHECK_RANGE(
+ DSI_CONVERT_T_PHY_TO_T_PHY_NS(
+ phy_timing->t_hsprepare, clk_ns) +
+ DSI_CONVERT_T_PHY_TO_T_PHY_NS(phy_timing->t_datzero, clk_ns),
+ MIPI_T_HSPREPARE_ADD_HSZERO_NS_MIN(clk_ns),
+ MIPI_T_HSPREPARE_ADD_HSZERO_NS_MAX);
+ if (err < 0) {
+ dev_warn(&dsi->dc->ndev->dev,
+ "dsi: HsPrepare + HsZero mipi range violated\n");
+ goto fail;
+ }
+ } else {
+ /* default is LP mode */
+ err = CHECK_RANGE(
+ DSI_CONVERT_T_PHY_TO_T_PHY_NS(phy_timing->t_wakeup, clk_ns),
+ MIPI_T_WAKEUP_NS_MIN, MIPI_T_WAKEUP_NS_MAX);
+ if (err < 0) {
+ dev_warn(&dsi->dc->ndev->dev,
+ "dsi: WakeUp mipi range violated\n");
+ goto fail;
+ }
+
+ err = CHECK_RANGE(
+ DSI_CONVERT_T_PHY_TO_T_PHY_NS(phy_timing->t_tasure, clk_ns),
+ MIPI_T_TASURE_NS_MIN(DSI_CONVERT_T_PHY_TO_T_PHY_NS(
+ phy_timing->t_tlpx, clk_ns)),
+ MIPI_T_TASURE_NS_MAX(DSI_CONVERT_T_PHY_TO_T_PHY_NS(
+ phy_timing->t_tlpx, clk_ns)));
+ if (err < 0) {
+ dev_warn(&dsi->dc->ndev->dev,
+ "dsi: TaSure mipi range violated\n");
+ goto fail;
+ }
+ }
+
+ if (lphs == DSI_LPHS_IN_HS_MODE ||
+ dsi->info.enable_hs_clock_on_lp_cmd_mode) {
+ err = CHECK_RANGE(
+ DSI_CONVERT_T_PHY_TO_T_PHY_NS(phy_timing->t_clktrail, clk_ns),
+ MIPI_T_CLKTRAIL_NS_MIN, MIPI_T_CLKTRAIL_NS_MAX);
+ if (err < 0) {
+ dev_warn(&dsi->dc->ndev->dev,
+ "dsi: ClkTrail mipi range violated\n");
+ goto fail;
+ }
+
+ err = CHECK_RANGE(
+ DSI_CONVERT_T_PHY_TO_T_PHY_NS(phy_timing->t_clkpost, clk_ns),
+ MIPI_T_CLKPOST_NS_MIN(clk_ns), MIPI_T_CLKPOST_NS_MAX);
+ if (err < 0) {
+ dev_warn(&dsi->dc->ndev->dev,
+ "dsi: ClkPost mipi range violated\n");
+ goto fail;
+ }
+
+ err = CHECK_RANGE(
+ DSI_CONVERT_T_PHY_TO_T_PHY_NS(phy_timing->t_clkzero, clk_ns),
+ MIPI_T_CLKZERO_NS_MIN, MIPI_T_CLKZERO_NS_MAX);
+ if (err < 0) {
+ dev_warn(&dsi->dc->ndev->dev,
+ "dsi: ClkZero mipi range violated\n");
+ goto fail;
+ }
+
+ err = CHECK_RANGE(
+ DSI_CONVERT_T_PHY_TO_T_PHY_NS
+ (phy_timing->t_clkprepare, clk_ns),
+ MIPI_T_CLKPREPARE_NS_MIN, MIPI_T_CLKPREPARE_NS_MAX);
+ if (err < 0) {
+ dev_warn(&dsi->dc->ndev->dev,
+ "dsi: ClkPrepare mipi range violated\n");
+ goto fail;
+ }
+
+ err = CHECK_RANGE(
+ DSI_CONVERT_T_PHY_TO_T_PHY_NS(phy_timing->t_clkpre, clk_ns),
+ MIPI_T_CLKPRE_NS_MIN, MIPI_T_CLKPRE_NS_MAX);
+ if (err < 0) {
+ dev_warn(&dsi->dc->ndev->dev,
+ "dsi: ClkPre mipi range violated\n");
+ goto fail;
+ }
+
+ err = CHECK_RANGE(
+ DSI_CONVERT_T_PHY_TO_T_PHY_NS(
+ phy_timing->t_clkprepare, clk_ns) +
+ DSI_CONVERT_T_PHY_TO_T_PHY_NS(phy_timing->t_clkzero, clk_ns),
+ MIPI_T_CLKPREPARE_ADD_CLKZERO_NS_MIN,
+ MIPI_T_CLKPREPARE_ADD_CLKZERO_NS_MAX);
+ if (err < 0) {
+ dev_warn(&dsi->dc->ndev->dev,
+ "dsi: ClkPrepare + ClkZero mipi range violated\n");
+ goto fail;
+ }
+ }
+fail:
+#undef CHECK_RANGE
+ return err;
+}
+
+static int tegra_dsi_constraint_phy_timing(struct tegra_dc_dsi_data *dsi,
+ struct dsi_phy_timing_inclk *phy_timing,
+ u32 clk_ns, u8 lphs)
+{
+ int err = 0;
- phy_timing_clk->t_clkpre = T_CLKPRE_DEFAULT(clk_ns);
- phy_timing_clk->t_clkprepare = T_CLKPREPARE_DEFAULT(clk_ns);
- phy_timing_clk->t_wakeup = T_WAKEUP_DEFAULT(clk_ns);
+ err = tegra_dsi_mipi_phy_timing_range(dsi, phy_timing, clk_ns, lphs);
+ if (err < 0) {
+ dev_warn(&dsi->dc->ndev->dev, "dsi: mipi range violated\n");
+ goto fail;
+ }
- phy_timing_clk->t_taget = 5 * phy_timing_clk->t_tlpx;
- phy_timing_clk->t_tasure = 2 * phy_timing_clk->t_tlpx;
- phy_timing_clk->t_tago = 4 * phy_timing_clk->t_tlpx;
+ /* TODO: add more contraints */
+fail:
+ return err;
}
-static void tegra_dsi_set_phy_timing(struct tegra_dc_dsi_data *dsi)
+static void tegra_dsi_set_phy_timing(struct tegra_dc_dsi_data *dsi, u8 lphs)
{
u32 val;
- struct dsi_phy_timing_inclk phy_timing;
+ struct dsi_phy_timing_inclk phy_timing = dsi->phy_timing;
- tegra_dsi_get_phy_timing(dsi, &phy_timing, dsi->current_bit_clk_ns);
+ tegra_dsi_get_phy_timing
+ (dsi, &phy_timing, dsi->current_bit_clk_ns, lphs);
+
+ tegra_dsi_constraint_phy_timing(dsi, &phy_timing,
+ dsi->current_bit_clk_ns, lphs);
val = DSI_PHY_TIMING_0_THSDEXIT(phy_timing.t_hsdexit) |
DSI_PHY_TIMING_0_THSTRAIL(phy_timing.t_hstrail) |
DSI_PHY_TIMING_0_TDATZERO(phy_timing.t_datzero) |
- DSI_PHY_TIMING_0_THSPREPR(phy_timing.t_hsprepr);
+ DSI_PHY_TIMING_0_THSPREPR(phy_timing.t_hsprepare);
tegra_dsi_writel(dsi, val, DSI_PHY_TIMING_0);
val = DSI_PHY_TIMING_1_TCLKTRAIL(phy_timing.t_clktrail) |
@@ -582,6 +834,8 @@ static void tegra_dsi_set_phy_timing(struct tegra_dc_dsi_data *dsi)
DSI_BTA_TIMING_TTASURE(phy_timing.t_tasure) |
DSI_BTA_TIMING_TTAGO(phy_timing.t_tago);
tegra_dsi_writel(dsi, val, DSI_BTA_TIMING);
+
+ dsi->phy_timing = phy_timing;
}
static u32 tegra_dsi_sol_delay_burst(struct tegra_dc *dc,
@@ -1149,7 +1403,7 @@ static int tegra_dsi_init_hw(struct tegra_dc *dc,
}
/* TODO: only need to change the timing for bta */
- tegra_dsi_set_phy_timing(dsi);
+ tegra_dsi_set_phy_timing(dsi, DSI_LPHS_IN_LP_MODE);
if (dsi->status.dc_stream == DSI_DC_STREAM_ENABLE)
tegra_dsi_stop_dc_stream_at_frame_end(dc, dsi);
@@ -1209,6 +1463,8 @@ static int tegra_dsi_set_to_lp_mode(struct tegra_dc *dc,
tegra_dsi_set_timeout(dsi);
}
+ tegra_dsi_set_phy_timing(dsi, DSI_LPHS_IN_LP_MODE);
+
tegra_dsi_set_control_reg_lp(dsi);
if ((dsi->status.clk_out == DSI_PHYCLK_OUT_DIS) &&
@@ -1248,7 +1504,7 @@ static int tegra_dsi_set_to_hs_mode(struct tegra_dc *dc,
tegra_dsi_set_timeout(dsi);
}
- tegra_dsi_set_phy_timing(dsi);
+ tegra_dsi_set_phy_timing(dsi, DSI_LPHS_IN_HS_MODE);
if (dsi->driven_mode == TEGRA_DSI_DRIVEN_BY_DC) {
tegra_dsi_set_pkt_seq(dc, dsi);