[DNI] video: tegra: dc: Fixes for seamless boot
Ankita Garg [Thu, 10 Dec 2015 04:02:27 +0000 (20:02 -0800)]
- Set vmode correctly
- Fix incorrect computation of pclk in dc

Bug 200158722

Change-Id: Ie2e120982ea866c27d4891110e52ed6589c9765b
Signed-off-by: Ankita Garg <ankitag@nvidia.com>
Reviewed-on: http://git-master/r/921522
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>

drivers/video/tegra/dc/dc.c
drivers/video/tegra/dc/edid.c
drivers/video/tegra/dc/mode.c

index 3d6a1d7..8e41cef 100644 (file)
@@ -2468,6 +2468,8 @@ void tegra_dc_set_out_pin_polars(struct tegra_dc *dc,
 
 static struct tegra_dc_mode *tegra_dc_get_override_mode(struct tegra_dc *dc)
 {
+       unsigned long refresh;
+
        if (dc->out->type == TEGRA_DC_OUT_HDMI &&
                        tegra_is_bl_display_initialized(dc->ndev->id)) {
 
@@ -2507,6 +2509,15 @@ static struct tegra_dc_mode *tegra_dc_get_override_mode(struct tegra_dc *dc)
                val = tegra_dc_readl(dc, DC_DISP_DISP_ACTIVE);
                mode->h_active = val & 0xffff;
                mode->v_active = (val >> 16) & 0xffff;
+
+               /* Check the freq setup by the BL, 59.94 or 60Hz
+                * If 59.94, vmode needs to be FB_VMODE_1000DIV1001
+                * for seamless
+                */
+               refresh = tegra_dc_calc_refresh(mode);
+               if (refresh % 1000)
+                       mode->vmode = FB_VMODE_1000DIV1001;
+
                tegra_dc_put(dc);
        }
 
index 794f593..1f3ad9a 100644 (file)
@@ -782,7 +782,7 @@ int tegra_edid_get_monspecs(struct tegra_edid *edid, struct fb_monspecs *specs)
                                    (rate > (60000 - 20) && rate < (60000 + 20))) &&
                                    frac_n < max_modes) {
                                        memcpy(&frac_modes[frac_n], &specs->modedb[j], sizeof(struct fb_videomode));
-                                       frac_modes[frac_n].pixclock = frac_modes[frac_n].pixclock * 1000 / 1001;
+                                       frac_modes[frac_n].pixclock = frac_modes[frac_n].pixclock * 1001 / 1000;
                                        frac_modes[frac_n].vmode |= FB_VMODE_1000DIV1001;
                                        frac_n++;
                                }
index 3450253..f1f3c0f 100644 (file)
@@ -759,6 +759,27 @@ int tegra_dc_set_drm_mode(struct tegra_dc *dc,
 }
 EXPORT_SYMBOL(tegra_dc_set_drm_mode);
 
+/* returns exact pixel clock in Hz */
+static long tegra_get_precise_pclk_from_mode(struct tegra_dc_mode *mode)
+{
+       long h_total, v_total;
+       long refresh, pclk;
+
+       h_total = mode->h_active + mode->h_front_porch + mode->h_back_porch +
+               mode->h_sync_width;
+       v_total = mode->v_active + mode->v_front_porch + mode->v_back_porch +
+               mode->v_sync_width;
+       refresh = tegra_dc_calc_refresh(mode);
+       refresh = DIV_ROUND_CLOSEST(refresh, 1000);
+
+       pclk = h_total * v_total * refresh;
+
+       if (mode->vmode & FB_VMODE_1000DIV1001)
+               pclk = pclk * 1000 / 1001;
+
+       return pclk;
+}
+
 int tegra_dc_set_fb_mode(struct tegra_dc *dc,
                const struct fb_videomode *fbmode, bool stereo_mode)
 {
@@ -768,6 +789,7 @@ int tegra_dc_set_fb_mode(struct tegra_dc *dc,
                return -EINVAL;
 
        memset(&mode, 0, sizeof(mode));
+
        mode.pclk = PICOS2KHZ(fbmode->pixclock) * 1000;
 
        mode.h_sync_width = fbmode->hsync_len;
@@ -816,6 +838,13 @@ int tegra_dc_set_fb_mode(struct tegra_dc *dc,
        if (!(fbmode->sync & FB_SYNC_VERT_HIGH_ACT))
                mode.flags |= TEGRA_DC_MODE_FLAG_NEG_V_SYNC;
 
+       /* In some cases, for instance in FB_VMODE_1000DIV1001
+        * mode, the pclk from the fb pixclock is imprecise
+        * due to the conversion between Hz -> ps. So compute
+        * the pclk from all the components for a precise value
+        */
+       mode.pclk = tegra_get_precise_pclk_from_mode(&mode);
+
        return _tegra_dc_set_mode(dc, &mode);
 }
 EXPORT_SYMBOL(tegra_dc_set_fb_mode);