drivers: video: tegra: Fix VIC codes
Aly Hirani [Fri, 25 Dec 2015 01:58:09 +0000 (17:58 -0800)]
This should fix the VIC codes for a wide variety of pixclocks. Use a
+/- 0.5% range (VESA DMT spec guidelines) for VIC matching.

Change-Id: Ie62072011520555530a61fd2e1eedb7e25e672ce
Signed-off-by: Aly Hirani <ahirani@nvidia.com>
Reviewed-on: http://git-master/r/927192
Reviewed-by: Mandar Padmawar <mpadmawar@nvidia.com>

drivers/video/modedb.c
drivers/video/tegra/dc/hdmi2.0.c
include/linux/fb.h

index cc10343..7d719d5 100644 (file)
@@ -1933,6 +1933,39 @@ void fb_videomode_to_var(struct fb_var_screeninfo *var,
 }
 
 /**
+ * fb_mode_is_equal_tolerance - compare 2 videomodes with a tolerance in
+ * pixclock. Similar to fb_mode_is_equal
+ *
+ * RETURNS:
+ * 1 if equal, 0 if not
+ */
+int fb_mode_is_equal_tolerance(const struct fb_videomode *mode1,
+                              const struct fb_videomode *mode2,
+                              unsigned int tolerance)
+{
+       /*
+        * Note: this function intentionally doesn't check refresh and flags.
+        * refresh is an optional field and always has +1/-1 rounding errors
+        */
+
+       if (mode1->xres             == mode2->xres &&
+               mode1->yres         == mode2->yres &&
+               mode2->pixclock * (1000-tolerance) / 1000 <= mode1->pixclock &&
+               mode1->pixclock <= mode2->pixclock * (1000+tolerance) / 1000 &&
+               mode1->hsync_len    == mode2->hsync_len &&
+               mode1->vsync_len    == mode2->vsync_len &&
+               mode1->left_margin  == mode2->left_margin &&
+               mode1->right_margin == mode2->right_margin &&
+               mode1->upper_margin == mode2->upper_margin &&
+               mode1->lower_margin == mode2->lower_margin &&
+               mode1->sync         == mode2->sync &&
+               mode1->vmode        == mode2->vmode)
+               return 1;
+       else
+               return 0;
+}
+
+/**
  * fb_mode_is_equal - compare 2 videomodes, with the second one possibly
  * generated by a modeset operation. In this case, use special comparison
  * for the vmode flags. Do not compare special vmode flags related to
@@ -2263,6 +2296,7 @@ EXPORT_SYMBOL(fb_find_best_display);
 EXPORT_SYMBOL(fb_videomode_to_var);
 EXPORT_SYMBOL(fb_var_to_videomode);
 EXPORT_SYMBOL(fb_mode_is_equal);
+EXPORT_SYMBOL(fb_mode_is_equal_tolerance);
 EXPORT_SYMBOL(fb_add_videomode);
 EXPORT_SYMBOL(fb_match_mode);
 EXPORT_SYMBOL(fb_find_best_mode);
index 5bbf866..3421565 100644 (file)
@@ -1121,11 +1121,6 @@ static void tegra_hdmi_get_cea_fb_videomode(struct fb_videomode *m,
                dc_mode.pclk = (dc_mode.pclk / 5) * 8;
        }
 
-       if (dc_mode.vmode & FB_VMODE_1000DIV1001) {
-               dc_mode.pclk = DIV_ROUND_UP((u64)dc_mode.pclk * 1001,  1000);
-               dc_mode.vmode &= ~FB_VMODE_1000DIV1001;
-       }
-
        tegra_dc_to_fb_videomode(m, &dc_mode);
 
        /* only interlaced required for VIC identification */
@@ -1157,21 +1152,7 @@ static int tegra_hdmi_find_cea_vic(struct tegra_hdmi *hdmi)
        for (i = 1; i < modedb_size; i++) {
                const struct fb_videomode *curr = &cea_modes[i];
 
-               if (!((m.refresh == curr->refresh ||
-                      m.refresh + 1 == curr->refresh ||
-                      m.refresh == curr->refresh + 1) &&
-                     m.xres         == curr->xres &&
-                     m.yres         == curr->yres &&
-                     (m.pixclock    == curr->pixclock ||
-                     (m.pixclock * 1001 / 1000) == curr->pixclock) &&
-                     m.hsync_len    == curr->hsync_len &&
-                     m.vsync_len    == curr->vsync_len &&
-                     m.left_margin  == curr->left_margin &&
-                     m.right_margin == curr->right_margin &&
-                     m.upper_margin == curr->upper_margin &&
-                     m.lower_margin == curr->lower_margin &&
-                     m.sync         == curr->sync &&
-                     m.vmode        == curr->vmode))
+               if (!fb_mode_is_equal_tolerance(curr, &m, 5))
                        continue;
 
                if (!best)
@@ -1364,18 +1345,9 @@ static void tegra_hdmi_avi_infoframe(struct tegra_hdmi *hdmi)
 static int tegra_hdmi_get_extended_vic(const struct tegra_dc_mode *mode)
 {
        struct fb_videomode m;
-       struct tegra_dc_mode mode_fixed;
        unsigned i;
 
-       mode_fixed = *mode;
-
-       if (mode_fixed.vmode & FB_VMODE_1000DIV1001) {
-               mode_fixed.pclk = DIV_ROUND_UP((u64)mode_fixed.pclk * 1001,
-                                                       1000);
-               mode_fixed.vmode &= ~FB_VMODE_1000DIV1001;
-       }
-
-       tegra_dc_to_fb_videomode(&m, &mode_fixed);
+       tegra_dc_to_fb_videomode(&m, mode);
 
        /* only interlaced required for VIC identification */
        m.vmode &= FB_VMODE_INTERLACED;
@@ -1383,28 +1355,7 @@ static int tegra_hdmi_get_extended_vic(const struct tegra_dc_mode *mode)
        for (i = 1; i < HDMI_EXT_MODEDB_SIZE; i++) {
                const struct fb_videomode *curr = &hdmi_ext_modes[i];
 
-               /*
-                * We have to make sure we explicitly don't check m.refresh ==
-                * curr->refresh (or use the fb_mode_is_equal() which does this
-                * check). This is because of the lack of accuracy when going
-                * between fb_videomode -> tegra_dc_mode -> fb_videomode. For
-                * 1000/1001 modes, the calculated m->refresh is actually not
-                * accurate. This is honestly a hack and does need to be fixed,
-                * but is a WAR for now for HDMI certification
-                */
-               if ((m.refresh == curr->refresh ||
-                    m.refresh + 1 == curr->refresh) &&
-                   m.xres         == curr->xres &&
-                   m.yres         == curr->yres &&
-                   m.pixclock     == curr->pixclock &&
-                   m.hsync_len    == curr->hsync_len &&
-                   m.vsync_len    == curr->vsync_len &&
-                   m.left_margin  == curr->left_margin &&
-                   m.right_margin == curr->right_margin &&
-                   m.upper_margin == curr->upper_margin &&
-                   m.lower_margin == curr->lower_margin &&
-                   m.sync         == curr->sync &&
-                   m.vmode        == curr->vmode)
+               if (fb_mode_is_equal_tolerance(curr, &m, 5))
                        return i;
        }
        return 0;
index 2d9badb..4995da8 100644 (file)
@@ -742,6 +742,9 @@ extern void fb_videomode_to_var(struct fb_var_screeninfo *var,
                                const struct fb_videomode *mode);
 extern int fb_mode_is_equal(const struct fb_videomode *mode1,
                            const struct fb_videomode *mode2);
+extern int fb_mode_is_equal_tolerance(const struct fb_videomode *mode1,
+                                     const struct fb_videomode *mode2,
+                                     unsigned int tolerance);
 extern int fb_add_videomode(const struct fb_videomode *mode,
                            struct list_head *head);
 extern void fb_delete_videomode(const struct fb_videomode *mode,