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

Dave Airlie
2014-09-09T06:28:12Z

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 --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__ */
--
1.9.3