Merge branch 'drm-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied...
[safe/jmp/linux-2.6] / drivers / gpu / drm / drm_edid.c
index fab2bdf..6f6b264 100644 (file)
@@ -125,10 +125,8 @@ static bool edid_is_valid(struct edid *edid)
                DRM_ERROR("EDID has major version %d, instead of 1\n", edid->version);
                goto bad;
        }
-       if (edid->revision > 3) {
-               DRM_ERROR("EDID has minor version %d, which is not between 0-3\n", edid->revision);
-               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];
@@ -162,7 +160,7 @@ static bool edid_vendor(struct edid *edid, char *vendor)
        edid_vendor[0] = ((edid->mfg_id[0] & 0x7c) >> 2) + '@';
        edid_vendor[1] = (((edid->mfg_id[0] & 0x3) << 3) |
                          ((edid->mfg_id[1] & 0xe0) >> 5)) + '@';
-       edid_vendor[2] = (edid->mfg_id[2] & 0x1f) + '@';
+       edid_vendor[2] = (edid->mfg_id[1] & 0x1f) + '@';
 
        return !strncmp(edid_vendor, vendor, 3);
 }
@@ -291,6 +289,11 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev,
        struct drm_display_mode *mode;
        struct detailed_pixel_timing *pt = &timing->data.pixel_data;
 
+       /* ignore tiny modes */
+       if (((pt->hactive_hi << 8) | pt->hactive_lo) < 64 ||
+           ((pt->vactive_hi << 8) | pt->hactive_lo) < 64)
+               return NULL;
+
        if (pt->stereo) {
                printk(KERN_WARNING "stereo mode not supported\n");
                return NULL;
@@ -742,6 +745,68 @@ end:
 }
 EXPORT_SYMBOL(drm_get_edid);
 
+#define HDMI_IDENTIFIER 0x000C03
+#define VENDOR_BLOCK    0x03
+/**
+ * drm_detect_hdmi_monitor - detect whether monitor is hdmi.
+ * @edid: monitor EDID information
+ *
+ * Parse the CEA extension according to CEA-861-B.
+ * Return true if HDMI, false if not or unknown.
+ */
+bool drm_detect_hdmi_monitor(struct edid *edid)
+{
+       char *edid_ext = NULL;
+       int i, hdmi_id, edid_ext_num;
+       int start_offset, end_offset;
+       bool is_hdmi = false;
+
+       /* No EDID or EDID extensions */
+       if (edid == NULL || edid->extensions == 0)
+               goto end;
+
+       /* Chose real EDID extension number */
+       edid_ext_num = edid->extensions > MAX_EDID_EXT_NUM ?
+                      MAX_EDID_EXT_NUM : edid->extensions;
+
+       /* Find CEA extension */
+       for (i = 0; i < edid_ext_num; i++) {
+               edid_ext = (char *)edid + EDID_LENGTH * (i + 1);
+               /* This block is CEA extension */
+               if (edid_ext[0] == 0x02)
+                       break;
+       }
+
+       if (i == edid_ext_num)
+               goto end;
+
+       /* Data block offset in CEA extension block */
+       start_offset = 4;
+       end_offset = edid_ext[2];
+
+       /*
+        * Because HDMI identifier is in Vendor Specific Block,
+        * search it from all data blocks of CEA extension.
+        */
+       for (i = start_offset; i < end_offset;
+               /* Increased by data block len */
+               i += ((edid_ext[i] & 0x1f) + 1)) {
+               /* Find vendor specific block */
+               if ((edid_ext[i] >> 5) == VENDOR_BLOCK) {
+                       hdmi_id = edid_ext[i + 1] | (edid_ext[i + 2] << 8) |
+                                 edid_ext[i + 3] << 16;
+                       /* Find HDMI identifier */
+                       if (hdmi_id == HDMI_IDENTIFIER)
+                               is_hdmi = true;
+                       break;
+               }
+       }
+
+end:
+       return is_hdmi;
+}
+EXPORT_SYMBOL(drm_detect_hdmi_monitor);
+
 /**
  * drm_add_edid_modes - add modes from EDID data, if available
  * @connector: connector we're probing