summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJon Mayo <jmayo@nvidia.com>2011-04-29 16:43:24 -0700
committerNiket Sirsi <nsirsi@nvidia.com>2011-05-23 16:12:04 -0700
commit4057fb4135f52eb27bfe21acbceb855d8eb1c7e0 (patch)
tree2cd5213d1feb463ff2f5954ae6d7e2ce6daf51d8
parent93d6594415d7375cafc860cae0881a7f9ac1973a (diff)
ARM: tegra: dc: fix h_ref_to_sync calculation
use smaller h_ref_to_sync values. removed old debug printks Bug 806009 (cherry picked from commit 8292b4988e6aa75c71f14cbf96dad8b5e931e681) Change-Id: Iae3e84ddd8c02be1a83f9ac255fc1152dc867f0b Reviewed-on: http://git-master/r/30585 Reviewed-by: Niket Sirsi <nsirsi@nvidia.com> Tested-by: Niket Sirsi <nsirsi@nvidia.com>
-rw-r--r--drivers/video/tegra/dc/dc.c168
1 files changed, 168 insertions, 0 deletions
diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c
index b17689fa3b86..1b91aaf9b361 100644
--- a/drivers/video/tegra/dc/dc.c
+++ b/drivers/video/tegra/dc/dc.c
@@ -744,6 +744,128 @@ void tegra_dc_setup_clk(struct tegra_dc *dc, struct clk *clk)
tegra_dvfs_set_rate(clk, pclk);
}
+/* return non-zero if constraint is violated */
+static int calc_h_ref_to_sync(const struct tegra_dc_mode *mode, int *href)
+{
+ long a, b;
+
+ /* Constraint 5: H_REF_TO_SYNC >= 0 */
+ a = 0;
+
+ /* Constraint 6: H_FRONT_PORT >= (H_REF_TO_SYNC + 1) */
+ b = mode->h_front_porch - 1;
+
+ /* Constraint 1: H_REF_TO_SYNC + H_SYNC_WIDTH + H_BACK_PORCH > 11 */
+ if (a + mode->h_sync_width + mode->h_back_porch <= 11)
+ a = 1 + 11 - mode->h_sync_width - mode->h_back_porch;
+ /* check Constraint 1 and 6 */
+ if (a > b)
+ return 1;
+
+ /* Constraint 4: H_SYNC_WIDTH >= 1 */
+ if (mode->h_sync_width < 1)
+ return 4;
+
+ /* Constraint 7: H_DISP_ACTIVE >= 16 */
+ if (mode->h_active < 16)
+ return 7;
+
+ if (href) {
+ if (b > a && a % 2)
+ *href = a + 1; /* use smallest even value */
+ else
+ *href = a; /* even or only possible value */
+ }
+
+ return 0;
+}
+
+static int calc_v_ref_to_sync(const struct tegra_dc_mode *mode, int *vref)
+{
+ long a;
+ a = 1; /* Constraint 5: V_REF_TO_SYNC >= 1 */
+
+ /* Constraint 2: V_REF_TO_SYNC + V_SYNC_WIDTH + V_BACK_PORCH > 1 */
+ if (a + mode->v_sync_width + mode->v_back_porch <= 1)
+ a = 1 + 1 - mode->v_sync_width - mode->v_back_porch;
+
+ /* Constraint 6 */
+ if (mode->v_front_porch < a + 1)
+ a = mode->v_front_porch - 1;
+
+ /* Constraint 4: V_SYNC_WIDTH >= 1 */
+ if (mode->v_sync_width < 1)
+ return 4;
+
+ /* Constraint 7: V_DISP_ACTIVE >= 16 */
+ if (mode->v_active < 16)
+ return 7;
+
+ if (vref)
+ *vref = a;
+ return 0;
+}
+
+static int calc_ref_to_sync(struct tegra_dc_mode *mode)
+{
+ int ret;
+ ret = calc_h_ref_to_sync(mode, &mode->h_ref_to_sync);
+ if (ret)
+ return ret;
+ ret = calc_v_ref_to_sync(mode, &mode->v_ref_to_sync);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+#ifdef DEBUG
+/* return in 1000ths of a Hertz */
+static int calc_refresh(const struct tegra_dc_mode *m)
+{
+ long h_total, v_total, refresh;
+ h_total = m->h_active + m->h_front_porch + m->h_back_porch +
+ m->h_sync_width;
+ v_total = m->v_active + m->v_front_porch + m->v_back_porch +
+ m->v_sync_width;
+ refresh = m->pclk / h_total;
+ refresh *= 1000;
+ refresh /= v_total;
+ return refresh;
+}
+
+static void print_mode(struct tegra_dc *dc,
+ const struct tegra_dc_mode *mode, const char *note)
+{
+ if (mode) {
+ int refresh = calc_refresh(mode);
+ dev_info(&dc->ndev->dev, "%s():MODE:%dx%d@%d.%03uHz pclk=%d\n",
+ note ? note : "",
+ mode->h_active, mode->v_active,
+ refresh / 1000, refresh % 1000,
+ mode->pclk);
+ }
+}
+#else
+static inline void print_mode(struct tegra_dc *dc,
+ const struct tegra_dc_mode *mode, const char *note) { }
+#endif
+
+static inline void enable_dc_irq(unsigned int irq)
+{
+#ifdef CONFIG_TEGRA_FPGA_PLATFORM
+ /* Always disable DC interrupts on FPGA. */
+ disable_irq(irq);
+#else
+ enable_irq(irq);
+#endif
+}
+
+static inline void disable_dc_irq(unsigned int irq)
+{
+ disable_irq(irq);
+}
+
static int tegra_dc_program_mode(struct tegra_dc *dc, struct tegra_dc_mode *mode)
{
unsigned long val;
@@ -829,6 +951,52 @@ int tegra_dc_set_mode(struct tegra_dc *dc, const struct tegra_dc_mode *mode)
}
EXPORT_SYMBOL(tegra_dc_set_mode);
+int tegra_dc_set_fb_mode(struct tegra_dc *dc,
+ const struct fb_videomode *fbmode, bool stereo_mode)
+{
+ struct tegra_dc_mode mode;
+
+ mode.pclk = PICOS2KHZ(fbmode->pixclock) * 1000;
+ mode.h_sync_width = fbmode->hsync_len;
+ mode.v_sync_width = fbmode->vsync_len;
+ mode.h_back_porch = fbmode->left_margin;
+ mode.v_back_porch = fbmode->upper_margin;
+ mode.h_active = fbmode->xres;
+ mode.v_active = fbmode->yres;
+ mode.h_front_porch = fbmode->right_margin;
+ mode.v_front_porch = fbmode->lower_margin;
+ mode.stereo_mode = stereo_mode;
+ if (calc_ref_to_sync(&mode)) {
+ dev_err(&dc->ndev->dev, "bad href/vref values, overriding.\n");
+ mode.h_ref_to_sync = 11;
+ mode.v_ref_to_sync = 1;
+ }
+ dev_info(&dc->ndev->dev, "Using mode %dx%d pclk=%d href=%d vref=%d\n",
+ mode.h_active, mode.v_active, mode.pclk,
+ mode.h_ref_to_sync, mode.v_ref_to_sync
+ );
+
+ if (mode.stereo_mode) {
+ mode.pclk *= 2;
+ /* total v_active = yres*2 + activespace */
+ mode.v_active = fbmode->yres*2 +
+ fbmode->vsync_len +
+ fbmode->upper_margin +
+ fbmode->lower_margin;
+ }
+
+ mode.flags = 0;
+
+ if (!(fbmode->sync & FB_SYNC_HOR_HIGH_ACT))
+ mode.flags |= TEGRA_DC_MODE_FLAG_NEG_H_SYNC;
+
+ if (!(fbmode->sync & FB_SYNC_VERT_HIGH_ACT))
+ mode.flags |= TEGRA_DC_MODE_FLAG_NEG_V_SYNC;
+
+ return tegra_dc_set_mode(dc, &mode);
+}
+EXPORT_SYMBOL(tegra_dc_set_fb_mode);
+
void
tegra_dc_config_pwm(struct tegra_dc *dc, struct tegra_dc_pwm_params *cfg)
{