Signed-off-by: Dylan Semler <dylan.sem...@gmail.com>
---
 drivers/gpu/drm/drm_edid.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 72 insertions(+)

diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index c194f4e..b1036b5 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -68,6 +68,8 @@
 #define EDID_QUIRK_DETAILED_SYNC_PP            (1 << 6)
 /* Force reduced-blanking timings for detailed modes */
 #define EDID_QUIRK_FORCE_REDUCED_BLANKING      (1 << 7)
+/* Force specific mode for monitors that don't report correct EDIDs */
+#define EDID_QUIRK_FORCE_MODE                  (1 << 8)
 
 struct detailed_mode_closure {
        struct drm_connector *connector;
@@ -127,6 +129,15 @@ static struct edid_quirk {
        { "VSC", 5020, EDID_QUIRK_FORCE_REDUCED_BLANKING },
 };
 
+static struct edid_quirk_force_mode {
+       char vendor[4];
+       int product_id;
+       int hdisplay;
+       int vdisplay;
+       int vrefresh;
+} edid_quirk_force_mode_list[] = {
+};
+
 /*
  * Autogenerated from the DMT spec.
  * This table is copied from xfree86/modes/xf86EdidModes.c.
@@ -2219,6 +2230,65 @@ add_detailed_modes(struct drm_connector *connector, 
struct edid *edid,
        return closure.modes;
 }
 
+/* Add an explicit mode based on a quirk
+ */
+static int
+do_force_quirk_modes(struct drm_connector *connector, int hdisplay,
+                    int vdisplay, int vrefresh)
+{
+       struct drm_display_mode *mode;
+       struct drm_device *dev = connector->dev;
+       int num_modes = 0;
+
+       /* sanity check display parameters */
+       if (hdisplay < 0)
+               return 0;
+       if (vdisplay < 0)
+               return 0;
+       if (vrefresh < 0)
+               return 0;
+
+       mode = drm_gtf_mode(dev, hdisplay, vdisplay, vrefresh, 0, 0);
+
+       if (mode) {
+               mode->type |= DRM_MODE_TYPE_PREFERRED;
+               drm_mode_probed_add(connector, mode);
+               num_modes++;
+       }
+       return num_modes;
+}
+
+/*
+ * add_force_quirk_modes - Add modes based on monitor's EDID quirks
+ * @connector: attached connector
+ * @edid: EDID block to scan
+ * @quirks: quirks to apply
+ *
+ * At least one monitor doesn't report its native resolution in its EDID block.
+ * Here we add the native mode according to this quirk
+ */
+static int
+add_force_quirk_modes(struct drm_connector *connector, struct edid *edid,
+                     u32 quirks)
+{
+       struct edid_quirk_force_mode *quirk_mode;
+       int i, num_modes = 0;
+
+       for (i = 0; i < ARRAY_SIZE(edid_quirk_force_mode_list); i++) {
+               quirk_mode = &edid_quirk_force_mode_list[i];
+
+               if (edid_vendor(edid, quirk_mode->vendor) &&
+                   (EDID_PRODUCT_ID(edid) == quirk_mode->product_id)) {
+                       num_modes = do_force_quirk_modes(connector,
+                                       quirk_mode->hdisplay,
+                                       quirk_mode->vdisplay,
+                                       quirk_mode->vrefresh);
+               }
+       }
+       return num_modes;
+
+}
+
 #define HDMI_IDENTIFIER 0x000C03
 #define AUDIO_BLOCK    0x01
 #define VIDEO_BLOCK     0x02
@@ -2803,6 +2873,8 @@ int drm_add_edid_modes(struct drm_connector *connector, 
struct edid *edid)
 
        if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75))
                edid_fixup_preferred(connector, quirks);
+       if (quirks & EDID_QUIRK_FORCE_MODE)
+               num_modes += add_force_quirk_modes(connector, edid, quirks);
 
        drm_add_display_info(edid, &connector->display_info);
 
-- 
1.7.11.7

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to