diff mbox

[07/11] drm/edid: allow patching the EDID to report monster mode

Message ID 1410244096-9854-8-git-send-email-airlied@gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Dave Airlie Sept. 9, 2014, 6:28 a.m. UTC
From: Dave Airlie <airlied@redhat.com>

This patches the EDID to add the special mode.

TODO make this more generic.

Signed-off-by: Dave Airlie <airlied@redhat.com>
---
 drivers/gpu/drm/drm_dp_mst_topology.c | 13 ++++++++++---
 drivers/gpu/drm/drm_edid.c            | 36 +++++++++++++++++++++++++++++++++++
 include/drm/drm_edid.h                |  5 ++++-
 3 files changed, 50 insertions(+), 4 deletions(-)
diff mbox

Patch

diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c
index 1f15d85..08b7140 100644
--- a/drivers/gpu/drm/drm_dp_mst_topology.c
+++ b/drivers/gpu/drm/drm_dp_mst_topology.c
@@ -31,6 +31,7 @@ 
 #include <drm/drmP.h>
 
 #include <drm/drm_fixed.h>
+#include <drm/drm_edid.h>
 
 /**
  * DOC: dp mst helper
@@ -2225,9 +2226,15 @@  struct edid *drm_dp_mst_get_edid(struct drm_connector *connector, struct drm_dp_
 			goto out;
 		}
 	}
-	if (port->cached_edid)
-		edid = drm_edid_duplicate(port->cached_edid);
-	else
+	if (port->cached_edid) {
+		if (connector->has_tile && connector->tile_is_single_monitor) {
+			edid = drm_patch_edid_detailed_mode(connector->dev,
+							    port->cached_edid,
+							    3840, 2160, 60);
+		} else {
+			edid = drm_edid_duplicate(port->cached_edid);
+		}
+	} else
 		edid = drm_get_edid(connector, &port->aux.ddc);
  out:
 	drm_dp_put_port(port);
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 94e8a57..3ccc2c6 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -3892,3 +3892,39 @@  void drm_get_displayid(struct drm_connector *connector,
 	return;
 }
 EXPORT_SYMBOL(drm_get_displayid);
+
+static void drm_patch_edid_reset_csum(struct edid *edid)
+{
+	unsigned i, sum = 0;
+	unsigned char *p = (unsigned char *)edid;
+
+	for (i = 0; i < EDID_LENGTH - 1; i++)
+		sum += p[i];
+	edid->checksum = (0x100 - (sum & 0xff)) & 0xff;
+}
+
+struct edid *drm_patch_edid_detailed_mode(struct drm_device *dev,
+					      struct edid *orig_edid,
+					      int hdisplay, int vdisplay, int vrefresh)
+{
+	struct edid *edid = drm_edid_duplicate(orig_edid);
+	struct drm_display_mode *mode = drm_cvt_mode(dev, hdisplay, vdisplay, vrefresh, true, false, false);
+
+	int hblank = mode->htotal - mode->hdisplay;
+	int vblank = mode->vtotal - mode->vdisplay;
+
+	DRM_DEBUG_KMS("mode->clock is %d, %d\n", mode->clock, cpu_to_le16(mode->clock / 10));
+	edid->detailed_timings[1] = edid->detailed_timings[0];
+	edid->detailed_timings[0].pixel_clock = cpu_to_le16(mode->clock / 10);
+	edid->detailed_timings[0].data.pixel_data.hactive_lo = mode->hdisplay & 0xff;
+	edid->detailed_timings[0].data.pixel_data.hblank_lo = hblank & 0xff;
+	edid->detailed_timings[0].data.pixel_data.hactive_hblank_hi = (mode->hdisplay >> 4 & 0xf0) | ((hblank >> 8) & 0xf);
+	edid->detailed_timings[0].data.pixel_data.vactive_lo = mode->vdisplay & 0xff;
+	edid->detailed_timings[0].data.pixel_data.vblank_lo = vblank & 0xff;
+	edid->detailed_timings[0].data.pixel_data.vactive_vblank_hi = (mode->vdisplay >> 4 & 0xf0) | ((vblank >> 8) & 0xf);
+
+	drm_patch_edid_reset_csum(edid);
+
+	return edid;
+}
+EXPORT_SYMBOL(drm_patch_edid_detailed_mode);
diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h
index 3e87f5a..17eb503 100644
--- a/include/drm/drm_edid.h
+++ b/include/drm/drm_edid.h
@@ -280,5 +280,8 @@  drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame,
 int
 drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame,
 					    const struct drm_display_mode *mode);
-
+struct drm_device;
+struct edid *drm_patch_edid_detailed_mode(struct drm_device *dev,
+					      struct edid *orig_edid,
+					      int hdisplay, int vdisplay, int vrefresh);
 #endif /* __DRM_EDID_H__ */