| Refresh |
This website lore-kernel.gnuweeb.org/all/jnuh5j$216$1@dough.gmane.org/ is currently offline. Cloudflare\'s Always Online™ shows a snapshot of this web page from the Internet Archive\'s Wayback Machine. To check for the live version, click Refresh. |
From: Ian Pilcher <arequipeno@gmail.com>
To: dri-devel@lists.freedesktop.org
Subject: Re: Enhancing EDID quirk functionality
Date: Thu, 03 May 2012 13:01:23 -0500 [thread overview]
Message-ID: <jnuh5j$216$1@dough.gmane.org> (raw)
In-Reply-To: <jn6t7o$5gs$1@dough.gmane.org>
[-- Attachment #1: Type: text/plain, Size: 1528 bytes --]
I just attached this patch to
https://bugzilla.redhat.com/show_bug.cgi?id=806091, along with the
following comments:
This is the "first draft" of an EDID quirk-based approach to solving
this problem. I intend to perform a bit of cleanup and break it up
into a series of separate patches, but I'm posting it here for any
comments about the approach.
The patch does the following:
* Changes the vendor field of struct edid_quirk to an array, rather
than a pointer. (This has already been sent to the dri-devel list.)
* Adds two new quirks EDID_QUIRK_DISABLE_INFOFRAMES and
EDID_QUIRK_NO_AUDIO. This first quirk causes drm_detect_hdmi_monitor
to return false; the second causes drm_detect_monitor_audio to
return false.
* Logs the EDID vendor and model of connected monitors.
* Adds an edid_quirks parameter to the drm module, for user-defined
quirks.
With this patch, my display works when I add
drm.edid_quirks=GSM:0x563f:0x180 to my kernel command line. (0x80,
EDID_QUIRK_DISABLE_INFOFRAMES, makes it work with the nouveau driver;
0x100, EDID_QUIRK_NO_AUDIO, makes it work with the i915 driver. I.e.,
the i915 driver is sending audio InfoFrames even when
drm_detect_hdmi_monitor returns false; bug?)
Thoughts?
--
========================================================================
Ian Pilcher arequipeno@gmail.com
"If you're going to shift my paradigm ... at least buy me dinner first."
========================================================================
[-- Attachment #2: edid_quirks_all.patch --]
[-- Type: text/x-patch, Size: 9610 bytes --]
diff -ur linux-3.3/drivers/gpu/drm/drm_drv.c linux-3.3-working/drivers/gpu/drm/drm_drv.c
--- linux-3.3/drivers/gpu/drm/drm_drv.c 2012-03-18 18:15:34.000000000 -0500
+++ linux-3.3-working/drivers/gpu/drm/drm_drv.c 2012-04-27 21:30:07.535452184 -0500
@@ -280,6 +280,8 @@
ret = -1;
goto err_p3;
}
+
+ drm_edid_xtra_quirks_parse();
DRM_INFO("Initialized %s %d.%d.%d %s\n",
CORE_NAME, CORE_MAJOR, CORE_MINOR, CORE_PATCHLEVEL, CORE_DATE);
@@ -304,6 +306,8 @@
idr_remove_all(&drm_minors_idr);
idr_destroy(&drm_minors_idr);
+
+ drm_edid_xtra_quirks_free();
}
module_init(drm_core_init);
diff -ur linux-3.3/drivers/gpu/drm/drm_edid.c linux-3.3-working/drivers/gpu/drm/drm_edid.c
--- linux-3.3/drivers/gpu/drm/drm_edid.c 2012-03-18 18:15:34.000000000 -0500
+++ linux-3.3-working/drivers/gpu/drm/drm_edid.c 2012-04-28 01:11:51.316839743 -0500
@@ -66,6 +66,10 @@
#define EDID_QUIRK_FIRST_DETAILED_PREFERRED (1 << 5)
/* use +hsync +vsync for detailed mode */
#define EDID_QUIRK_DETAILED_SYNC_PP (1 << 6)
+/* Display is confused by InfoFrames; don't send any. */
+#define EDID_QUIRK_DISABLE_INFOFRAMES (1 << 7)
+/* Display doesn't have any audio output */
+#define EDID_QUIRK_NO_AUDIO (1 << 8)
struct detailed_mode_closure {
struct drm_connector *connector;
@@ -81,7 +85,7 @@
#define LEVEL_CVT 3
static struct edid_quirk {
- char *vendor;
+ char vendor[4];
int product_id;
u32 quirks;
} edid_quirk_list[] = {
@@ -122,13 +126,100 @@
{ "SAM", 638, EDID_QUIRK_PREFER_LARGE_60 },
};
+/* Parsed extra quirks from the edid_quirks module parameter */
+static struct edid_quirk *edid_xtra_quirk_list;
+static int edid_num_xtra_quirks;
+
+/*
+ * Free the extra EDID quirks list.
+ */
+void drm_edid_xtra_quirks_free(void)
+{
+ kfree(edid_xtra_quirk_list);
+ edid_xtra_quirk_list = NULL;
+ edid_num_xtra_quirks = 0;
+}
+
+/*
+ * Parse the EDID quirk at s and store it a q. Returns 1 on success, 0 on error.
+ */
+static int drm_edid_parse_quirk(char *s, struct edid_quirk *q)
+{
+ char *c;
+
+ if (sscanf(s, "%3s:%i:%i",
+ q->vendor, &q->product_id, &q->quirks) == 3) {
+ DRM_DEBUG("Parsed EDID quirk: "
+ "mfr: %s, product: %d, quirks: %u\n",
+ q->vendor, q->product_id, q->quirks);
+ return 1;
+ } else {
+ if ((c = strchr(s, ',')) != NULL) {
+ *c = 0;
+ }
+ printk(KERN_WARNING "Invalid EDID quirk: '%s'\n", s);
+ if (c != NULL) {
+ *c = ',';
+ }
+ return 0;
+ }
+}
+
+/*
+ * Parse drm_edid_xtra_quirks and create the extra EDID quirks list.
+ */
+void drm_edid_xtra_quirks_parse(void)
+{
+ int num_quirks;
+ char *c;
+ if (drm_edid_xtra_quirks == NULL) {
+ edid_xtra_quirk_list = NULL;
+ edid_num_xtra_quirks = 0;
+ return;
+ }
+
+ /* Number of (potential) quirks = number of commas in param + 1 */
+ num_quirks = 1;
+ c = drm_edid_xtra_quirks;
+ while ((c = strchr(c, ',')) != NULL) {
+ ++num_quirks;
+ ++c;
+ }
+
+ if (num_quirks > DRM_EDID_XTRA_QUIRKS_MAX) {
+ printk(KERN_WARNING "Number of additional EDID quirks limited "
+ "to " __stringify(DRM_EDID_XTRA_QUIRKS_MAX) "\n");
+ num_quirks = DRM_EDID_XTRA_QUIRKS_MAX;
+ }
+
+ edid_xtra_quirk_list = kmalloc(sizeof(struct edid_quirk) * num_quirks,
+ GFP_KERNEL);
+ if (edid_xtra_quirk_list == NULL) {
+ printk(KERN_WARNING "Failed to allocate memory for additional "
+ "EDID quirks\n");
+ return;
+ }
+
+ edid_num_xtra_quirks = 0;
+ c = drm_edid_xtra_quirks;
+ while (1) {
+ edid_num_xtra_quirks += drm_edid_parse_quirk(c,
+ &edid_xtra_quirk_list[edid_num_xtra_quirks]);
+ if (edid_num_xtra_quirks == num_quirks ||
+ (c = strchr(c, ',')) == NULL) {
+ break;
+ }
+ ++c;
+ }
+}
+
/*** DDC fetch and block validation ***/
static const u8 edid_header[] = {
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00
};
- /*
+/*
* Sanity check the header of the base EDID block. Return 8 if the header
* is perfect, down to 0 if it's totally wrong.
*/
@@ -366,6 +457,24 @@
}
/**
+ * edid_vendor_string - decodes EDID vendor field
+ * @edid: EDID from which to extract the vendor field
+ * @edid_vendor: buffer in which to store the vendor string
+ *
+ * Returns a pointer to @edid_vendor
+ */
+static char *edid_vendor_string(const struct edid *edid, char edid_vendor[4])
+{
+ 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[1] & 0x1f) + '@';
+ edid_vendor[3] = 0;
+
+ return edid_vendor;
+}
+
+/**
* drm_get_edid - get EDID data, if available
* @connector: connector we're probing
* @adapter: i2c adapter to use for DDC
@@ -378,15 +487,31 @@
struct edid *drm_get_edid(struct drm_connector *connector,
struct i2c_adapter *adapter)
{
+ const struct edid *old_edid;
+ char edid_vendor[4];
struct edid *edid = NULL;
-
+
if (drm_probe_ddc(adapter))
edid = (struct edid *)drm_do_get_edid(connector, adapter);
+
+ /* Log if something has changed */
+ if (edid != NULL) {
+ old_edid = (struct edid *)connector->display_info.raw_edid;
+ /* memcmp call compares the mfg_id, prod_code, and serial
+ * fields of the two (packed) EDID structures for equality */
+ if (!old_edid || memcmp(&edid->mfg_id, &old_edid->mfg_id, 8)) {
+ DRM_INFO("Detected display on connector %s: "
+ "mfr: %s, product: %04hx, serial: %d\n",
+ drm_get_connector_name(connector),
+ edid_vendor_string(edid, edid_vendor),
+ le16_to_cpu(EDID_PRODUCT_ID(edid)),
+ le32_to_cpu(edid->serial));
+ }
+ }
connector->display_info.raw_edid = (char *)edid;
return edid;
-
}
EXPORT_SYMBOL(drm_get_edid);
@@ -401,13 +526,9 @@
*/
static bool edid_vendor(struct edid *edid, char *vendor)
{
- char edid_vendor[3];
-
- 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[1] & 0x1f) + '@';
+ char edid_vendor[4];
+ edid_vendor_string(edid, edid_vendor);
return !strncmp(edid_vendor, vendor, 3);
}
@@ -420,17 +541,34 @@
static u32 edid_get_quirks(struct edid *edid)
{
struct edid_quirk *quirk;
+ u32 quirks;
int i;
+
+ quirks = 0;
+ /* Check the built-in quirks first */
for (i = 0; i < ARRAY_SIZE(edid_quirk_list); i++) {
quirk = &edid_quirk_list[i];
if (edid_vendor(edid, quirk->vendor) &&
- (EDID_PRODUCT_ID(edid) == quirk->product_id))
- return quirk->quirks;
+ (EDID_PRODUCT_ID(edid) == quirk->product_id)) {
+ quirks = quirk->quirks;
+ break;
+ }
+ }
+
+ /* Extra quirks can override built-in ones */
+ for (i = 0; i < edid_num_xtra_quirks; ++i) {
+ quirk = &edid_xtra_quirk_list[i];
+
+ if (edid_vendor(edid, quirk->vendor) &&
+ EDID_PRODUCT_ID(edid) == quirk->product_id) {
+ quirks = quirk->quirks;
+ break;
+ }
}
- return 0;
+ return quirks;
}
#define MODE_SIZE(m) ((m)->hdisplay * (m)->vdisplay)
@@ -1562,6 +1700,11 @@
int i, hdmi_id;
int start_offset, end_offset;
bool is_hdmi = false;
+
+ if (edid_get_quirks(edid) & EDID_QUIRK_DISABLE_INFOFRAMES) {
+ DRM_DEBUG_KMS("Disabling HDMI InfoFrames due to EDID quirk\n");
+ goto end;
+ }
edid_ext = drm_find_cea_extension(edid);
if (!edid_ext)
@@ -1610,6 +1753,11 @@
int i, j;
bool has_audio = false;
int start_offset, end_offset;
+
+ if (edid_get_quirks(edid) & EDID_QUIRK_NO_AUDIO) {
+ DRM_DEBUG_KMS("Disabling HDMI audio due to EDID quirk\n");
+ goto end;
+ }
edid_ext = drm_find_cea_extension(edid);
if (!edid_ext)
diff -ur linux-3.3/drivers/gpu/drm/drm_stub.c linux-3.3-working/drivers/gpu/drm/drm_stub.c
--- linux-3.3/drivers/gpu/drm/drm_stub.c 2012-03-18 18:15:34.000000000 -0500
+++ linux-3.3-working/drivers/gpu/drm/drm_stub.c 2012-04-24 13:32:35.394132568 -0500
@@ -46,16 +46,22 @@
unsigned int drm_timestamp_precision = 20; /* Default to 20 usecs. */
EXPORT_SYMBOL(drm_timestamp_precision);
+char *drm_edid_xtra_quirks = NULL;
+EXPORT_SYMBOL(drm_edid_xtra_quirks);
+
MODULE_AUTHOR(CORE_AUTHOR);
MODULE_DESCRIPTION(CORE_DESC);
MODULE_LICENSE("GPL and additional rights");
MODULE_PARM_DESC(debug, "Enable debug output");
MODULE_PARM_DESC(vblankoffdelay, "Delay until vblank irq auto-disable [msecs]");
MODULE_PARM_DESC(timestamp_precision_usec, "Max. error on timestamps [usecs]");
+MODULE_PARM_DESC(edid_quirks, "Additional EDID quirks [up to "
+ __stringify(DRM_EDID_XTRA_QUIRKS_MAX) "]");
module_param_named(debug, drm_debug, int, 0600);
module_param_named(vblankoffdelay, drm_vblank_offdelay, int, 0600);
module_param_named(timestamp_precision_usec, drm_timestamp_precision, int, 0600);
+module_param_named(edid_quirks, drm_edid_xtra_quirks, charp, 0600);
struct idr drm_minors_idr;
diff -ur linux-3.3/include/drm/drmP.h linux-3.3-working/include/drm/drmP.h
--- linux-3.3/include/drm/drmP.h 2012-03-18 18:15:34.000000000 -0500
+++ linux-3.3-working/include/drm/drmP.h 2012-04-27 16:09:12.043494619 -0500
@@ -1468,6 +1468,7 @@
extern unsigned int drm_vblank_offdelay;
extern unsigned int drm_timestamp_precision;
+extern char *drm_edid_xtra_quirks;
extern struct class *drm_class;
extern struct proc_dir_entry *drm_proc_root;
@@ -1552,6 +1553,12 @@
void drm_gem_vm_close(struct vm_area_struct *vma);
int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma);
+ /* EDID support (drm_edid.c) */
+/* This gets stringified in drm_stub.c and drm_edid.c; don't add parentheses */
+#define DRM_EDID_XTRA_QUIRKS_MAX 10
+void drm_edid_xtra_quirks_parse(void);
+void drm_edid_xtra_quirks_free(void);
+
#include "drm_global.h"
static inline void
[-- Attachment #3: Type: text/plain, Size: 159 bytes --]
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel
next prev parent reply other threads:[~2012-05-03 18:01 UTC|newest] Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top 2012-04-19 19:16 Enhancing EDID quirk functionality Ian Pilcher 2012-04-24 9:07 ` Lars-Peter Clausen 2012-04-24 19:00 ` Ian Pilcher 2012-05-03 18:01 ` Ian Pilcher [this message] 2012-05-03 19:42 ` Adam Jackson 2012-05-07 19:50 ` Ian Pilcher 2012-05-07 21:38 ` Adam Jackson 2012-08-10 4:23 ` Ian Pilcher 2012-08-10 4:23 ` [PATCH] drm: EDID quirk improvements Ian Pilcher 2012-08-10 18:44 ` Ian Pilcher 2012-08-10 18:44 ` Ian Pilcher 2012-08-11 8:31 ` Paul Menzel 2012-08-11 15:38 ` Ian Pilcher 2012-08-11 19:52 ` Paul Menzel 2012-08-11 19:37 ` Paul Menzel 2012-08-12 4:30 ` [PATCH v3 0/2] Enhanced EDID quirk functionality Ian Pilcher 2012-08-12 4:30 ` [PATCH v3 1/2] drm: Add user-defined EDID quirks capability Ian Pilcher 2012-08-12 15:39 ` Paul Menzel 2012-08-12 4:30 ` [PATCH v3 2/2] drm: Add EDID quirks to disable HDMI audio and InfoFrames Ian Pilcher 2012-08-12 15:45 ` Paul Menzel 2012-08-12 6:58 ` [PATCH v3 0/2] Enhanced EDID quirk functionality Paul Menzel 2012-08-12 20:07 ` [PATCH v4 0/3] " Ian Pilcher 2012-08-12 20:07 ` [PATCH v4 1/3] drm: Add user-defined EDID quirks capability Ian Pilcher 2012-08-14 15:13 ` Paul Menzel 2012-08-14 15:45 ` Ian Pilcher 2012-08-15 6:41 ` Paul Menzel 2012-08-12 20:07 ` [PATCH v4 2/3] drm: Add EDID quirks to disable HDMI audio and InfoFrames Ian Pilcher 2012-08-12 20:08 ` [PATCH v4 3/3] drm: Add EDID quirk for LG L246WP Ian Pilcher 2012-09-04 14:52 ` Paul Menzel 2012-08-12 21:29 ` [PATCH v4 0/3] Enhanced EDID quirk functionality Christian König 2012-08-12 21:31 ` Paul Menzel 2012-08-13 14:39 ` Ian Pilcher
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='jnuh5j$216$1@dough.gmane.org' \
--to=arequipeno@gmail.com \
--cc=dri-devel@lists.freedesktop.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.