Quantcast

[PATCH 0/1] EDID override support

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

[PATCH 0/1] EDID override support

Andy Whitcroft-3
We have an issue when the KMS EDID is either not valid or does not
accuratly describe the attached monitor.  This happens with broken monitors
and also with KVM devices which often lie about the attached monitor when
you request EDID and you are not being displayed.  In these situations
it would be nice to be able to take corrective action.  Before KMS took
over display initialisation the X server allowed the user to specifify
an alternative EDID which it would use instead of the one loaded from
the monitor.  The patch attempts to provide the kernel component of such
a mechanism in the KMS world.

This patch allows us to specify new EDID files which may then overwrite the
auto detected EDID in KMS.  As loading an EDID is potentially dangerous
(indeed with old monitors you might load up and EDID which causes us
to blow up the monitor) we do not allow arbitrary files to be loaded,
we limit the files to those found in the firmware directory edid/.
The load is triggered by echoing the name of a replacement edid file
into the existing edid file in /sys.  This will use the firmware loader
to load the new binary data, and then switch to it.

It is envisioned that this would be utilised by some udev support.
For example you could perhaps use system board ids to trigger automatic
loading, or perhaps the md5sum of the existing EDID where this is always
known to be wrong.  This patch is a prerequisite for this kind of support.

This fix is not yet upstream, I am going to be tackling that next.
However it is a very self contained change, and is primarily intended to be
used by userspace support which we will define such that if the interface
changes it will be hidden from the user; I do not intend to guarentee
this interface API.  I am considering this a bug fix for those broken
EDID scenarios which we used to be able to fix in X and no longer can.

Finally some history, I have taken this patch and sanitised it for
our use, particularly limiting its reach to the edid directory in the
firmware directories.  This is both for safety and also as it would allow
that directory to be shipped in a separate package from the X team in
the future.

Proposing for Precise (post Beta 2 please).

-apw

Carsten Emde (1):
  drm/edid: allow to load edid firmware

 drivers/gpu/drm/drm_crtc_helper.c |    7 ++++
 drivers/gpu/drm/drm_edid.c        |    5 +++
 drivers/gpu/drm/drm_sysfs.c       |   66 ++++++++++++++++++++++++++++++++++++-
 include/drm/drm_crtc.h            |    1 +
 4 files changed, 78 insertions(+), 1 deletions(-)

--
1.7.9.1


--
kernel-team mailing list
[hidden email]
https://lists.ubuntu.com/mailman/listinfo/kernel-team
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

[PATCH 1/1] drm/edid: allow to load edid firmware

Andy Whitcroft-3
From: Carsten Emde <[hidden email]>

Use the firmware interface to load binary EDID data from
a file and use them to assign monitor data to a video
connector.  EDID data is located in the edid/ directory within
the existing firmware directories.

[[hidden email]: follow the changes to the sysfs interfaces]
[[hidden email]: fix the memory allocation so we use the real buffer]
[[hidden email]: add a firware prefix edid/ to limit what may be loaded]
Signed-off-by: Carsten Emde <[hidden email]>
Signed-off-by: Andy Whitcroft <[hidden email]>
---
 drivers/gpu/drm/drm_crtc_helper.c |    7 ++++
 drivers/gpu/drm/drm_edid.c        |    5 +++
 drivers/gpu/drm/drm_sysfs.c       |   66 ++++++++++++++++++++++++++++++++++++-
 include/drm/drm_crtc.h            |    1 +
 4 files changed, 78 insertions(+), 1 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index d2619d7..8dd1680 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -94,6 +94,13 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
 
  DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id,
  drm_get_connector_name(connector));
+
+ if (connector->edid_pinned) {
+ list_for_each_entry(mode, &connector->modes, head)
+ count++;
+ return count;
+ }
+
  /* set all modes to the unverified state */
  list_for_each_entry_safe(mode, t, &connector->modes, head)
  mode->status = MODE_UNVERIFIED;
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index fb6c26c..1944fd5 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -385,6 +385,11 @@ struct edid *drm_get_edid(struct drm_connector *connector,
 {
  struct edid *edid = NULL;
 
+ if (connector->edid_pinned) {
+ edid = (struct edid *) connector->display_info.raw_edid;
+ return edid;
+ }
+
  if (drm_probe_ddc(adapter))
  edid = (struct edid *)drm_do_get_edid(connector, adapter);
 
diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c
index 0f9ef9b..c5c875d 100644
--- a/drivers/gpu/drm/drm_sysfs.c
+++ b/drivers/gpu/drm/drm_sysfs.c
@@ -17,9 +17,11 @@
 #include <linux/gfp.h>
 #include <linux/err.h>
 #include <linux/export.h>
+#include <linux/firmware.h>
 
 #include "drm_sysfs.h"
 #include "drm_core.h"
+#include "drm_edid.h"
 #include "drmP.h"
 
 #define to_drm_minor(d) container_of(d, struct drm_minor, kdev)
@@ -228,6 +230,67 @@ static ssize_t edid_show(struct file *filp, struct kobject *kobj,
  return count;
 }
 
+#define EDID_FIRMWARE_PREFIX "edid/"
+
+static ssize_t edid_store(struct file *file, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf, loff_t off, size_t count)
+{
+ struct device *connector_dev = container_of(kobj, struct device, kobj);
+ struct drm_connector *connector = to_drm_connector(connector_dev);
+ const struct firmware *fw;
+ unsigned char *edid;
+ size_t size = EDID_LENGTH;
+ int status;
+ char *filename, *cr;
+
+ if (count == 0 || *buf == '\n' || *buf == '\0') {
+ connector->edid_pinned = 0;
+ return count;
+ }
+
+ filename = kmalloc(sizeof(EDID_FIRMWARE_PREFIX) + count, GFP_KERNEL);
+ if (!filename)
+ return -ENOMEM;
+ strcpy(filename, EDID_FIRMWARE_PREFIX);
+ memcpy(filename + sizeof(EDID_FIRMWARE_PREFIX) - 1, buf, count);
+ filename[sizeof(EDID_FIRMWARE_PREFIX) + count] = '\0';
+
+ cr = strchr(filename, '\n');
+ if (cr)
+ *cr = '\0';
+
+ status = request_firmware(&fw, filename, connector_dev);
+ kfree(filename);
+ if (status)
+ return status;
+
+ if (fw->size != size) {
+ release_firmware(fw);
+ return -EINVAL;
+ }
+
+ edid = kmalloc(size, GFP_KERNEL);
+ if (edid == NULL) {
+ release_firmware(fw);
+ return -ENOMEM;
+ }
+
+ memcpy(edid, fw->data, size);
+
+ drm_mode_connector_update_edid_property(connector,
+    (struct edid *) edid);
+ drm_add_edid_modes(connector, (struct edid *) edid);
+ drm_mode_connector_list_update(connector);
+ drm_mode_sort(&connector->modes);
+
+ connector->display_info.raw_edid = edid;
+ connector->edid_pinned = 1;
+
+ release_firmware(fw);
+
+ return count;
+}
+
 static ssize_t modes_show(struct device *device,
    struct device_attribute *attr,
    char *buf)
@@ -341,9 +404,10 @@ static struct device_attribute connector_attrs_opt1[] = {
 
 static struct bin_attribute edid_attr = {
  .attr.name = "edid",
- .attr.mode = 0444,
+ .attr.mode = 0644,
  .size = 0,
  .read = edid_show,
+ .write = edid_store,
 };
 
 /**
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 8020798..96d6e18 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -509,6 +509,7 @@ struct drm_connector {
 
  struct list_head user_modes;
  struct drm_property_blob *edid_blob_ptr;
+ int edid_pinned;
  u32 property_ids[DRM_CONNECTOR_MAX_PROPERTY];
  uint64_t property_values[DRM_CONNECTOR_MAX_PROPERTY];
 
--
1.7.9.1


--
kernel-team mailing list
[hidden email]
https://lists.ubuntu.com/mailman/listinfo/kernel-team
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: [PATCH 0/1] EDID override support

Andy Whitcroft-3
In reply to this post by Andy Whitcroft-3
Ok IGNORE this for now, it seems upstream has _just_ merged an
alternative patch set for this very thing.  If we pull anything it needs
to be interface compatible with that.

-apw

--
kernel-team mailing list
[hidden email]
https://lists.ubuntu.com/mailman/listinfo/kernel-team
Loading...