include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit...
[safe/jmp/linux-2.6] / drivers / gpu / drm / drm_edid.c
index dd35dc1..d196d7e 100644 (file)
@@ -27,6 +27,7 @@
  * DEALINGS IN THE SOFTWARE.
  */
 #include <linux/kernel.h>
+#include <linux/slab.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
 #include "drmP.h"
@@ -60,8 +61,7 @@
 #define EDID_QUIRK_FIRST_DETAILED_PREFERRED    (1 << 5)
 /* use +hsync +vsync for detailed mode */
 #define EDID_QUIRK_DETAILED_SYNC_PP            (1 << 6)
-/* define the number of Extension EDID block */
-#define MAX_EDID_EXT_NUM 4
+
 
 #define LEVEL_DMT      0
 #define LEVEL_GTF      1
@@ -114,27 +114,29 @@ static const u8 edid_header[] = {
 };
 
 /**
- * edid_is_valid - sanity check EDID data
+ * drm_edid_is_valid - sanity check EDID data
  * @edid: EDID data
  *
  * Sanity check the EDID block by looking at the header, the version number
  * and the checksum.  Return 0 if the EDID doesn't check out, or 1 if it's
  * valid.
  */
-static bool edid_is_valid(struct edid *edid)
+bool drm_edid_is_valid(struct edid *edid)
 {
-       int i;
+       int i, score = 0;
        u8 csum = 0;
        u8 *raw_edid = (u8 *)edid;
 
-       if (memcmp(edid->header, edid_header, sizeof(edid_header)))
-               goto bad;
-       if (edid->version != 1) {
-               DRM_ERROR("EDID has major version %d, instead of 1\n", edid->version);
+       for (i = 0; i < sizeof(edid_header); i++)
+               if (raw_edid[i] == edid_header[i])
+                       score++;
+
+       if (score == 8) ;
+       else if (score >= 6) {
+               DRM_DEBUG("Fixing EDID header, your hardware may be failing\n");
+               memcpy(raw_edid, edid_header, sizeof(edid_header));
+       } else
                goto bad;
-       }
-       if (edid->revision > 4)
-               DRM_DEBUG("EDID minor > 4, assuming backward compatibility\n");
 
        for (i = 0; i < EDID_LENGTH; i++)
                csum += raw_edid[i];
@@ -143,6 +145,14 @@ static bool edid_is_valid(struct edid *edid)
                goto bad;
        }
 
+       if (edid->version != 1) {
+               DRM_ERROR("EDID has major version %d, instead of 1\n", edid->version);
+               goto bad;
+       }
+
+       if (edid->revision > 4)
+               DRM_DEBUG("EDID minor > 4, assuming backward compatibility\n");
+
        return 1;
 
 bad:
@@ -153,6 +163,7 @@ bad:
        }
        return 0;
 }
+EXPORT_SYMBOL(drm_edid_is_valid);
 
 /**
  * edid_vendor - match a string against EDID's obfuscated vendor field
@@ -481,16 +492,17 @@ static struct drm_display_mode drm_dmt_modes[] = {
                   3048, 3536, 0, 1600, 1603, 1609, 1682, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
 };
+static const int drm_num_dmt_modes =
+       sizeof(drm_dmt_modes) / sizeof(struct drm_display_mode);
 
 static struct drm_display_mode *drm_find_dmt(struct drm_device *dev,
                        int hsize, int vsize, int fresh)
 {
-       int i, count;
+       int i;
        struct drm_display_mode *ptr, *mode;
 
-       count = sizeof(drm_dmt_modes) / sizeof(struct drm_display_mode);
        mode = NULL;
-       for (i = 0; i < count; i++) {
+       for (i = 0; i < drm_num_dmt_modes; i++) {
                ptr = &drm_dmt_modes[i];
                if (hsize == ptr->hdisplay &&
                        vsize == ptr->vdisplay &&
@@ -528,6 +540,7 @@ bad_std_timing(u8 a, u8 b)
  */
 struct drm_display_mode *drm_mode_std(struct drm_device *dev,
                                      struct std_timing *t,
+                                     int revision,
                                      int timing_level)
 {
        struct drm_display_mode *mode;
@@ -546,9 +559,12 @@ struct drm_display_mode *drm_mode_std(struct drm_device *dev,
        /* vrefresh_rate = vfreq + 60 */
        vrefresh_rate = vfreq + 60;
        /* the vdisplay is calculated based on the aspect ratio */
-       if (aspect_ratio == 0)
-               vsize = (hsize * 10) / 16;
-       else if (aspect_ratio == 1)
+       if (aspect_ratio == 0) {
+               if (revision < 3)
+                       vsize = hsize;
+               else
+                       vsize = (hsize * 10) / 16;
+       } else if (aspect_ratio == 1)
                vsize = (hsize * 3) / 4;
        else if (aspect_ratio == 2)
                vsize = (hsize * 4) / 5;
@@ -556,7 +572,8 @@ struct drm_display_mode *drm_mode_std(struct drm_device *dev,
                vsize = (hsize * 9) / 16;
        /* HDTV hack */
        if (hsize == 1360 && vsize == 765 && vrefresh_rate == 60) {
-               mode = drm_cvt_mode(dev, hsize, vsize, vrefresh_rate, 0, 0);
+               mode = drm_cvt_mode(dev, hsize, vsize, vrefresh_rate, 0, 0,
+                                   false);
                mode->hdisplay = 1366;
                mode->vsync_start = mode->vsync_start - 1;
                mode->vsync_end = mode->vsync_end - 1;
@@ -575,12 +592,57 @@ struct drm_display_mode *drm_mode_std(struct drm_device *dev,
                mode = drm_gtf_mode(dev, hsize, vsize, vrefresh_rate, 0, 0);
                break;
        case LEVEL_CVT:
-               mode = drm_cvt_mode(dev, hsize, vsize, vrefresh_rate, 0, 0);
+               mode = drm_cvt_mode(dev, hsize, vsize, vrefresh_rate, 0, 0,
+                                   false);
                break;
        }
        return mode;
 }
 
+/*
+ * EDID is delightfully ambiguous about how interlaced modes are to be
+ * encoded.  Our internal representation is of frame height, but some
+ * HDTV detailed timings are encoded as field height.
+ *
+ * The format list here is from CEA, in frame size.  Technically we
+ * should be checking refresh rate too.  Whatever.
+ */
+static void
+drm_mode_do_interlace_quirk(struct drm_display_mode *mode,
+                           struct detailed_pixel_timing *pt)
+{
+       int i;
+       static const struct {
+               int w, h;
+       } cea_interlaced[] = {
+               { 1920, 1080 },
+               {  720,  480 },
+               { 1440,  480 },
+               { 2880,  480 },
+               {  720,  576 },
+               { 1440,  576 },
+               { 2880,  576 },
+       };
+       static const int n_sizes =
+               sizeof(cea_interlaced)/sizeof(cea_interlaced[0]);
+
+       if (!(pt->misc & DRM_EDID_PT_INTERLACED))
+               return;
+
+       for (i = 0; i < n_sizes; i++) {
+               if ((mode->hdisplay == cea_interlaced[i].w) &&
+                   (mode->vdisplay == cea_interlaced[i].h / 2)) {
+                       mode->vdisplay *= 2;
+                       mode->vsync_start *= 2;
+                       mode->vsync_end *= 2;
+                       mode->vtotal *= 2;
+                       mode->vtotal |= 1;
+               }
+       }
+
+       mode->flags |= DRM_MODE_FLAG_INTERLACE;
+}
+
 /**
  * drm_mode_detailed - create a new mode from an EDID detailed timing section
  * @dev: DRM device (needed to create new mode)
@@ -616,10 +678,15 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev,
                return NULL;
        }
        if (!(pt->misc & DRM_EDID_PT_SEPARATE_SYNC)) {
-               printk(KERN_WARNING "integrated sync not supported\n");
-               return NULL;
+               printk(KERN_WARNING "composite sync not supported\n");
        }
 
+       /* it is incorrect if hsync/vsync width is zero */
+       if (!hsync_pulse_width || !vsync_pulse_width) {
+               DRM_DEBUG_KMS("Incorrect Detailed timing. "
+                               "Wrong Hsync/Vsync pulse width\n");
+               return NULL;
+       }
        mode = drm_mode_create(dev);
        if (!mode)
                return NULL;
@@ -641,10 +708,24 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev,
        mode->vsync_end = mode->vsync_start + vsync_pulse_width;
        mode->vtotal = mode->vdisplay + vblank;
 
+       /* perform the basic check for the detailed timing */
+       if (mode->hsync_end > mode->htotal ||
+               mode->vsync_end > mode->vtotal) {
+               drm_mode_destroy(dev, mode);
+               DRM_DEBUG_KMS("Incorrect detailed timing. "
+                               "Sync is beyond the blank.\n");
+               return NULL;
+       }
+
+       /* Some EDIDs have bogus h/vtotal values */
+       if (mode->hsync_end > mode->htotal)
+               mode->htotal = mode->hsync_end + 1;
+       if (mode->vsync_end > mode->vtotal)
+               mode->vtotal = mode->vsync_end + 1;
+
        drm_mode_set_name(mode);
 
-       if (pt->misc & DRM_EDID_PT_INTERLACED)
-               mode->flags |= DRM_MODE_FLAG_INTERLACE;
+       drm_mode_do_interlace_quirk(mode, pt);
 
        if (quirks & EDID_QUIRK_DETAILED_SYNC_PP) {
                pt->misc |= DRM_EDID_PT_HSYNC_POSITIVE | DRM_EDID_PT_VSYNC_POSITIVE;
@@ -797,7 +878,7 @@ static int add_standard_modes(struct drm_connector *connector, struct edid *edid
                        continue;
 
                newmode = drm_mode_std(dev, &edid->standard_timings[i],
-                                       timing_level);
+                                      edid->revision, timing_level);
                if (newmode) {
                        drm_mode_probed_add(connector, newmode);
                        modes++;
@@ -807,8 +888,169 @@ static int add_standard_modes(struct drm_connector *connector, struct edid *edid
        return modes;
 }
 
+/*
+ * XXX fix this for:
+ * - GTF secondary curve formula
+ * - EDID 1.4 range offsets
+ * - CVT extended bits
+ */
+static bool
+mode_in_range(struct drm_display_mode *mode, struct detailed_timing *timing)
+{
+       struct detailed_data_monitor_range *range;
+       int hsync, vrefresh;
+
+       range = &timing->data.other_data.data.range;
+
+       hsync = drm_mode_hsync(mode);
+       vrefresh = drm_mode_vrefresh(mode);
+
+       if (hsync < range->min_hfreq_khz || hsync > range->max_hfreq_khz)
+               return false;
+
+       if (vrefresh < range->min_vfreq || vrefresh > range->max_vfreq)
+               return false;
+
+       if (range->pixel_clock_mhz && range->pixel_clock_mhz != 0xff) {
+               /* be forgiving since it's in units of 10MHz */
+               int max_clock = range->pixel_clock_mhz * 10 + 9;
+               max_clock *= 1000;
+               if (mode->clock > max_clock)
+                       return false;
+       }
+
+       return true;
+}
+
+/*
+ * XXX If drm_dmt_modes ever regrows the CVT-R modes (and it will) this will
+ * need to account for them.
+ */
+static int drm_gtf_modes_for_range(struct drm_connector *connector,
+                                  struct detailed_timing *timing)
+{
+       int i, modes = 0;
+       struct drm_display_mode *newmode;
+       struct drm_device *dev = connector->dev;
+
+       for (i = 0; i < drm_num_dmt_modes; i++) {
+               if (mode_in_range(drm_dmt_modes + i, timing)) {
+                       newmode = drm_mode_duplicate(dev, &drm_dmt_modes[i]);
+                       if (newmode) {
+                               drm_mode_probed_add(connector, newmode);
+                               modes++;
+                       }
+               }
+       }
+
+       return modes;
+}
+
+static int drm_cvt_modes(struct drm_connector *connector,
+                        struct detailed_timing *timing)
+{
+       int i, j, modes = 0;
+       struct drm_display_mode *newmode;
+       struct drm_device *dev = connector->dev;
+       struct cvt_timing *cvt;
+       const int rates[] = { 60, 85, 75, 60, 50 };
+       const u8 empty[3] = { 0, 0, 0 };
+
+       for (i = 0; i < 4; i++) {
+               int uninitialized_var(width), height;
+               cvt = &(timing->data.other_data.data.cvt[i]);
+
+               if (!memcmp(cvt->code, empty, 3))
+                       continue;
+
+               height = (cvt->code[0] + ((cvt->code[1] & 0xf0) << 4) + 1) * 2;
+               switch (cvt->code[1] & 0x0c) {
+               case 0x00:
+                       width = height * 4 / 3;
+                       break;
+               case 0x04:
+                       width = height * 16 / 9;
+                       break;
+               case 0x08:
+                       width = height * 16 / 10;
+                       break;
+               case 0x0c:
+                       width = height * 15 / 9;
+                       break;
+               }
+
+               for (j = 1; j < 5; j++) {
+                       if (cvt->code[2] & (1 << j)) {
+                               newmode = drm_cvt_mode(dev, width, height,
+                                                      rates[j], j == 0,
+                                                      false, false);
+                               if (newmode) {
+                                       drm_mode_probed_add(connector, newmode);
+                                       modes++;
+                               }
+                       }
+               }
+       }
+
+       return modes;
+}
+
+static int add_detailed_modes(struct drm_connector *connector,
+                             struct detailed_timing *timing,
+                             struct edid *edid, u32 quirks, int preferred)
+{
+       int i, modes = 0;
+       struct detailed_non_pixel *data = &timing->data.other_data;
+       int timing_level = standard_timing_level(edid);
+       int gtf = (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF);
+       struct drm_display_mode *newmode;
+       struct drm_device *dev = connector->dev;
+
+       if (timing->pixel_clock) {
+               newmode = drm_mode_detailed(dev, edid, timing, quirks);
+               if (!newmode)
+                       return 0;
+
+               if (preferred)
+                       newmode->type |= DRM_MODE_TYPE_PREFERRED;
+
+               drm_mode_probed_add(connector, newmode);
+               return 1;
+       }
+
+       /* other timing types */
+       switch (data->type) {
+       case EDID_DETAIL_MONITOR_RANGE:
+               if (gtf)
+                       modes += drm_gtf_modes_for_range(connector, timing);
+               break;
+       case EDID_DETAIL_STD_MODES:
+               /* Six modes per detailed section */
+               for (i = 0; i < 6; i++) {
+                       struct std_timing *std;
+                       struct drm_display_mode *newmode;
+
+                       std = &data->data.timings[i];
+                       newmode = drm_mode_std(dev, std, edid->revision,
+                                              timing_level);
+                       if (newmode) {
+                               drm_mode_probed_add(connector, newmode);
+                               modes++;
+                       }
+               }
+               break;
+       case EDID_DETAIL_CVT_3BYTE:
+               modes += drm_cvt_modes(connector, timing);
+               break;
+       default:
+               break;
+       }
+
+       return modes;
+}
+
 /**
- * add_detailed_modes - get detailed mode info from EDID data
+ * add_detailed_info - get detailed mode info from EDID data
  * @connector: attached connector
  * @edid: EDID block to scan
  * @quirks: quirks to apply
@@ -819,67 +1061,24 @@ static int add_standard_modes(struct drm_connector *connector, struct edid *edid
 static int add_detailed_info(struct drm_connector *connector,
                             struct edid *edid, u32 quirks)
 {
-       struct drm_device *dev = connector->dev;
-       int i, j, modes = 0;
-       int timing_level;
-
-       timing_level = standard_timing_level(edid);
+       int i, modes = 0;
 
        for (i = 0; i < EDID_DETAILED_TIMINGS; i++) {
                struct detailed_timing *timing = &edid->detailed_timings[i];
-               struct detailed_non_pixel *data = &timing->data.other_data;
-               struct drm_display_mode *newmode;
+               int preferred = (i == 0) && (edid->features & DRM_EDID_FEATURE_PREFERRED_TIMING);
 
-               /* X server check is version 1.1 or higher */
-               if (edid->version == 1 && edid->revision >= 1 &&
-                   !timing->pixel_clock) {
-                       /* Other timing or info */
-                       switch (data->type) {
-                       case EDID_DETAIL_MONITOR_SERIAL:
-                               break;
-                       case EDID_DETAIL_MONITOR_STRING:
-                               break;
-                       case EDID_DETAIL_MONITOR_RANGE:
-                               /* Get monitor range data */
-                               break;
-                       case EDID_DETAIL_MONITOR_NAME:
-                               break;
-                       case EDID_DETAIL_MONITOR_CPDATA:
-                               break;
-                       case EDID_DETAIL_STD_MODES:
-                               /* Five modes per detailed section */
-                               for (j = 0; j < 5; i++) {
-                                       struct std_timing *std;
-                                       struct drm_display_mode *newmode;
-
-                                       std = &data->data.timings[j];
-                                       newmode = drm_mode_std(dev, std,
-                                                              timing_level);
-                                       if (newmode) {
-                                               drm_mode_probed_add(connector, newmode);
-                                               modes++;
-                                       }
-                               }
-                               break;
-                       default:
-                               break;
-                       }
-               } else {
-                       newmode = drm_mode_detailed(dev, edid, timing, quirks);
-                       if (!newmode)
-                               continue;
-
-                       /* First detailed mode is preferred */
-                       if (i == 0 && (edid->features & DRM_EDID_FEATURE_PREFERRED_TIMING))
-                               newmode->type |= DRM_MODE_TYPE_PREFERRED;
-                       drm_mode_probed_add(connector, newmode);
+               /* In 1.0, only timings are allowed */
+               if (!timing->pixel_clock && edid->version == 1 &&
+                       edid->revision == 0)
+                       continue;
 
-                       modes++;
-               }
+               modes += add_detailed_modes(connector, timing, edid, quirks,
+                                           preferred);
        }
 
        return modes;
 }
+
 /**
  * add_detailed_mode_eedid - get detailed mode info from addtional timing
  *                     EDID block
@@ -893,12 +1092,9 @@ static int add_detailed_info(struct drm_connector *connector,
 static int add_detailed_info_eedid(struct drm_connector *connector,
                             struct edid *edid, u32 quirks)
 {
-       struct drm_device *dev = connector->dev;
-       int i, j, modes = 0;
+       int i, modes = 0;
        char *edid_ext = NULL;
        struct detailed_timing *timing;
-       struct detailed_non_pixel *data;
-       struct drm_display_mode *newmode;
        int edid_ext_num;
        int start_offset, end_offset;
        int timing_level;
@@ -917,8 +1113,8 @@ static int add_detailed_info_eedid(struct drm_connector *connector,
        }
 
        /* Chose real EDID extension number */
-       edid_ext_num = edid->extensions > MAX_EDID_EXT_NUM ?
-                      MAX_EDID_EXT_NUM : edid->extensions;
+       edid_ext_num = edid->extensions > DRM_MAX_EDID_EXT_NUM ?
+               DRM_MAX_EDID_EXT_NUM : edid->extensions;
 
        /* Find CEA extension */
        for (i = 0; i < edid_ext_num; i++) {
@@ -949,49 +1145,7 @@ static int add_detailed_info_eedid(struct drm_connector *connector,
        for (i = start_offset; i < end_offset;
                        i += sizeof(struct detailed_timing)) {
                timing = (struct detailed_timing *)(edid_ext + i);
-               data = &timing->data.other_data;
-               /* Detailed mode timing */
-               if (timing->pixel_clock) {
-                       newmode = drm_mode_detailed(dev, edid, timing, quirks);
-                       if (!newmode)
-                               continue;
-
-                       drm_mode_probed_add(connector, newmode);
-
-                       modes++;
-                       continue;
-               }
-
-               /* Other timing or info */
-               switch (data->type) {
-               case EDID_DETAIL_MONITOR_SERIAL:
-                       break;
-               case EDID_DETAIL_MONITOR_STRING:
-                       break;
-               case EDID_DETAIL_MONITOR_RANGE:
-                       /* Get monitor range data */
-                       break;
-               case EDID_DETAIL_MONITOR_NAME:
-                       break;
-               case EDID_DETAIL_MONITOR_CPDATA:
-                       break;
-               case EDID_DETAIL_STD_MODES:
-                       /* Five modes per detailed section */
-                       for (j = 0; j < 5; i++) {
-                               struct std_timing *std;
-                               struct drm_display_mode *newmode;
-
-                               std = &data->data.timings[j];
-                               newmode = drm_mode_std(dev, std, timing_level);
-                               if (newmode) {
-                                       drm_mode_probed_add(connector, newmode);
-                                       modes++;
-                               }
-                       }
-                       break;
-               default:
-                       break;
-               }
+               modes += add_detailed_modes(connector, timing, edid, quirks, 0);
        }
 
        return modes;
@@ -1037,19 +1191,19 @@ static int drm_ddc_read_edid(struct drm_connector *connector,
                             struct i2c_adapter *adapter,
                             char *buf, int len)
 {
-       int ret;
+       int i;
 
-       ret = drm_do_probe_ddc_edid(adapter, buf, len);
-       if (ret != 0) {
-               goto end;
-       }
-       if (!edid_is_valid((struct edid *)buf)) {
-               dev_warn(&connector->dev->pdev->dev, "%s: EDID invalid.\n",
-                        drm_get_connector_name(connector));
-               ret = -1;
+       for (i = 0; i < 4; i++) {
+               if (drm_do_probe_ddc_edid(adapter, buf, len))
+                       return -1;
+               if (drm_edid_is_valid((struct edid *)buf))
+                       return 0;
        }
-end:
-       return ret;
+
+       /* repeated checksum failures; warn, but carry on */
+       dev_warn(&connector->dev->pdev->dev, "%s: EDID invalid.\n",
+                drm_get_connector_name(connector));
+       return -1;
 }
 
 /**
@@ -1067,7 +1221,7 @@ struct edid *drm_get_edid(struct drm_connector *connector,
        int ret;
        struct edid *edid;
 
-       edid = kmalloc(EDID_LENGTH * (MAX_EDID_EXT_NUM + 1),
+       edid = kmalloc(EDID_LENGTH * (DRM_MAX_EDID_EXT_NUM + 1),
                       GFP_KERNEL);
        if (edid == NULL) {
                dev_warn(&connector->dev->pdev->dev,
@@ -1085,14 +1239,14 @@ struct edid *drm_get_edid(struct drm_connector *connector,
        if (edid->extensions != 0) {
                int edid_ext_num = edid->extensions;
 
-               if (edid_ext_num > MAX_EDID_EXT_NUM) {
+               if (edid_ext_num > DRM_MAX_EDID_EXT_NUM) {
                        dev_warn(&connector->dev->pdev->dev,
                                 "The number of extension(%d) is "
                                 "over max (%d), actually read number (%d)\n",
-                                edid_ext_num, MAX_EDID_EXT_NUM,
-                                MAX_EDID_EXT_NUM);
+                                edid_ext_num, DRM_MAX_EDID_EXT_NUM,
+                                DRM_MAX_EDID_EXT_NUM);
                        /* Reset EDID extension number to be read */
-                       edid_ext_num = MAX_EDID_EXT_NUM;
+                       edid_ext_num = DRM_MAX_EDID_EXT_NUM;
                }
                /* Read EDID including extensions too */
                ret = drm_ddc_read_edid(connector, adapter, (char *)edid,
@@ -1135,8 +1289,8 @@ bool drm_detect_hdmi_monitor(struct edid *edid)
                goto end;
 
        /* Chose real EDID extension number */
-       edid_ext_num = edid->extensions > MAX_EDID_EXT_NUM ?
-                      MAX_EDID_EXT_NUM : edid->extensions;
+       edid_ext_num = edid->extensions > DRM_MAX_EDID_EXT_NUM ?
+                      DRM_MAX_EDID_EXT_NUM : edid->extensions;
 
        /* Find CEA extension */
        for (i = 0; i < edid_ext_num; i++) {
@@ -1193,7 +1347,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
        if (edid == NULL) {
                return 0;
        }
-       if (!edid_is_valid(edid)) {
+       if (!drm_edid_is_valid(edid)) {
                dev_warn(&connector->dev->pdev->dev, "%s: EDID invalid.\n",
                         drm_get_connector_name(connector));
                return 0;
@@ -1267,6 +1421,8 @@ int drm_add_modes_noedid(struct drm_connector *connector,
                                        ptr->vdisplay > vdisplay)
                                continue;
                }
+               if (drm_mode_vrefresh(ptr) > 61)
+                       continue;
                mode = drm_mode_duplicate(dev, ptr);
                if (mode) {
                        drm_mode_probed_add(connector, mode);