Merge remote branch 'origin/master' into drm-intel-next
[pandora-kernel.git] / drivers / gpu / drm / drm_edid.c
index d721438..7188674 100644 (file)
@@ -28,6 +28,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"
@@ -64,7 +65,8 @@
 
 #define LEVEL_DMT      0
 #define LEVEL_GTF      1
-#define LEVEL_CVT      2
+#define LEVEL_GTF2     2
+#define LEVEL_CVT      3
 
 static struct edid_quirk {
        char *vendor;
@@ -84,6 +86,8 @@ static struct edid_quirk {
 
        /* Envision Peripherals, Inc. EN-7100e */
        { "EPI", 59264, EDID_QUIRK_135_CLOCK_TOO_HIGH },
+       /* Envision EN2028 */
+       { "EPI", 8232, EDID_QUIRK_PREFER_LARGE_60 },
 
        /* Funai Electronics PM36B */
        { "FCM", 13600, EDID_QUIRK_PREFER_LARGE_75 |
@@ -713,6 +717,71 @@ drm_monitor_supports_rb(struct edid *edid)
        return ((edid->input & DRM_EDID_INPUT_DIGITAL) != 0);
 }
 
+static void
+find_gtf2(struct detailed_timing *t, void *data)
+{
+       u8 *r = (u8 *)t;
+       if (r[3] == EDID_DETAIL_MONITOR_RANGE && r[10] == 0x02)
+               *(u8 **)data = r;
+}
+
+/* Secondary GTF curve kicks in above some break frequency */
+static int
+drm_gtf2_hbreak(struct edid *edid)
+{
+       u8 *r = NULL;
+       drm_for_each_detailed_block((u8 *)edid, find_gtf2, &r);
+       return r ? (r[12] * 2) : 0;
+}
+
+static int
+drm_gtf2_2c(struct edid *edid)
+{
+       u8 *r = NULL;
+       drm_for_each_detailed_block((u8 *)edid, find_gtf2, &r);
+       return r ? r[13] : 0;
+}
+
+static int
+drm_gtf2_m(struct edid *edid)
+{
+       u8 *r = NULL;
+       drm_for_each_detailed_block((u8 *)edid, find_gtf2, &r);
+       return r ? (r[15] << 8) + r[14] : 0;
+}
+
+static int
+drm_gtf2_k(struct edid *edid)
+{
+       u8 *r = NULL;
+       drm_for_each_detailed_block((u8 *)edid, find_gtf2, &r);
+       return r ? r[16] : 0;
+}
+
+static int
+drm_gtf2_2j(struct edid *edid)
+{
+       u8 *r = NULL;
+       drm_for_each_detailed_block((u8 *)edid, find_gtf2, &r);
+       return r ? r[17] : 0;
+}
+
+/**
+ * standard_timing_level - get std. timing level(CVT/GTF/DMT)
+ * @edid: EDID block to scan
+ */
+static int standard_timing_level(struct edid *edid)
+{
+       if (edid->revision >= 2) {
+               if (edid->revision >= 4 && (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF))
+                       return LEVEL_CVT;
+               if (drm_gtf2_hbreak(edid))
+                       return LEVEL_GTF2;
+               return LEVEL_GTF;
+       }
+       return LEVEL_DMT;
+}
+
 /*
  * 0 is reserved.  The spec says 0x01 fill for unused timings.  Some old
  * monitors fill with ascii space (0x20) instead.
@@ -733,18 +802,19 @@ bad_std_timing(u8 a, u8 b)
  * Take the standard timing params (in this case width, aspect, and refresh)
  * and convert them into a real mode using CVT/GTF/DMT.
  */
-struct drm_display_mode *drm_mode_std(struct drm_device *dev,
-                                     struct std_timing *t,
-                                     int revision,
-                                     int timing_level)
+static struct drm_display_mode *
+drm_mode_std(struct drm_connector *connector, struct edid *edid,
+            struct std_timing *t, int revision)
 {
-       struct drm_display_mode *mode;
+       struct drm_device *dev = connector->dev;
+       struct drm_display_mode *m, *mode = NULL;
        int hsize, vsize;
        int vrefresh_rate;
        unsigned aspect_ratio = (t->vfreq_aspect & EDID_TIMING_ASPECT_MASK)
                >> EDID_TIMING_ASPECT_SHIFT;
        unsigned vfreq = (t->vfreq_aspect & EDID_TIMING_VFREQ_MASK)
                >> EDID_TIMING_VFREQ_SHIFT;
+       int timing_level = standard_timing_level(edid);
 
        if (bad_std_timing(t->hsize, t->vfreq_aspect))
                return NULL;
@@ -774,6 +844,17 @@ struct drm_display_mode *drm_mode_std(struct drm_device *dev,
                vsize = 768;
        }
 
+       /*
+        * If this connector already has a mode for this size and refresh
+        * rate (because it came from detailed or CVT info), use that
+        * instead.  This way we don't have to guess at interlace or
+        * reduced blanking.
+        */
+       list_for_each_entry(m, &connector->probed_modes, head)
+               if (m->hdisplay == hsize && m->vdisplay == vsize &&
+                   drm_mode_vrefresh(m) == vrefresh_rate)
+                       return NULL;
+
        /* HDTV hack, part 2 */
        if (hsize == 1366 && vsize == 768 && vrefresh_rate == 60) {
                mode = drm_cvt_mode(dev, 1366, 768, vrefresh_rate, 0, 0,
@@ -784,7 +865,6 @@ struct drm_display_mode *drm_mode_std(struct drm_device *dev,
                return mode;
        }
 
-       mode = NULL;
        /* check whether it can be found in default mode table */
        mode = drm_find_dmt(dev, hsize, vsize, vrefresh_rate);
        if (mode)
@@ -796,6 +876,23 @@ struct drm_display_mode *drm_mode_std(struct drm_device *dev,
        case LEVEL_GTF:
                mode = drm_gtf_mode(dev, hsize, vsize, vrefresh_rate, 0, 0);
                break;
+       case LEVEL_GTF2:
+               /*
+                * This is potentially wrong if there's ever a monitor with
+                * more than one ranges section, each claiming a different
+                * secondary GTF curve.  Please don't do that.
+                */
+               mode = drm_gtf_mode(dev, hsize, vsize, vrefresh_rate, 0, 0);
+               if (drm_mode_hsync(mode) > drm_gtf2_hbreak(edid)) {
+                       kfree(mode);
+                       mode = drm_gtf_mode_complex(dev, hsize, vsize,
+                                                   vrefresh_rate, 0, 0,
+                                                   drm_gtf2_m(edid),
+                                                   drm_gtf2_2c(edid),
+                                                   drm_gtf2_k(edid),
+                                                   drm_gtf2_2j(edid));
+               }
+               break;
        case LEVEL_CVT:
                mode = drm_cvt_mode(dev, hsize, vsize, vrefresh_rate, 0, 0,
                                    false);
@@ -919,10 +1016,10 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev,
        if (mode->vsync_end > mode->vtotal)
                mode->vtotal = mode->vsync_end + 1;
 
-       drm_mode_set_name(mode);
-
        drm_mode_do_interlace_quirk(mode, pt);
 
+       drm_mode_set_name(mode);
+
        if (quirks & EDID_QUIRK_DETAILED_SYNC_PP) {
                pt->misc |= DRM_EDID_PT_HSYNC_POSITIVE | DRM_EDID_PT_VSYNC_POSITIVE;
        }
@@ -1032,19 +1129,6 @@ static int add_established_modes(struct drm_connector *connector, struct edid *e
 
        return modes;
 }
-/**
- * stanard_timing_level - get std. timing level(CVT/GTF/DMT)
- * @edid: EDID block to scan
- */
-static int standard_timing_level(struct edid *edid)
-{
-       if (edid->revision >= 2) {
-               if (edid->revision >= 4 && (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF))
-                       return LEVEL_CVT;
-               return LEVEL_GTF;
-       }
-       return LEVEL_DMT;
-}
 
 /**
  * add_standard_modes - get std. modes from EDID and add them
@@ -1055,18 +1139,14 @@ static int standard_timing_level(struct edid *edid)
  */
 static int add_standard_modes(struct drm_connector *connector, struct edid *edid)
 {
-       struct drm_device *dev = connector->dev;
        int i, modes = 0;
-       int timing_level;
-
-       timing_level = standard_timing_level(edid);
 
        for (i = 0; i < EDID_STD_TIMINGS; i++) {
-               struct std_timing *t = &edid->standard_timings[i];
                struct drm_display_mode *newmode;
 
-               newmode = drm_mode_std(dev, &edid->standard_timings[i],
-                                      edid->revision, timing_level);
+               newmode = drm_mode_std(connector, edid,
+                                      &edid->standard_timings[i],
+                                      edid->revision);
                if (newmode) {
                        drm_mode_probed_add(connector, newmode);
                        modes++;
@@ -1132,9 +1212,6 @@ range_pixel_clock(struct edid *edid, u8 *t)
        return t[9] * 10000 + 5001;
 }
 
-/*
- * XXX fix this for GTF secondary curve formula
- */
 static bool
 mode_in_range(struct drm_display_mode *mode, struct edid *edid,
              struct detailed_timing *timing)
@@ -1331,7 +1408,6 @@ static int add_detailed_modes(struct drm_connector *connector,
 {
        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;
@@ -1362,8 +1438,8 @@ static int add_detailed_modes(struct drm_connector *connector,
                        struct drm_display_mode *newmode;
 
                        std = &data->data.timings[i];
-                       newmode = drm_mode_std(dev, std, edid->revision,
-                                              timing_level);
+                       newmode = drm_mode_std(connector, edid, std,
+                                              edid->revision);
                        if (newmode) {
                                drm_mode_probed_add(connector, newmode);
                                modes++;