xf86-video-intel: man/intel.man src/intel_options.c src/intel_options.h src/sna/sna_display.c

Chris Wilson ickle at kemper.freedesktop.org
Sat Jul 18 04:09:37 PDT 2015


 man/intel.man         |   10 +++
 src/intel_options.c   |    1 
 src/intel_options.h   |    1 
 src/sna/sna_display.c |  136 +++++++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 147 insertions(+), 1 deletion(-)

New commits:
commit 2cd7cb9e93767d8492bd4a72a973b18184730322
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Jul 18 11:56:57 2015 +0100

    sna: Allow user override of EDID for an output
    
    As a slightly more convenient approach than loading the EDID on the
    kernel command line, allow the user to specify the EDID path in the
    Device section of xorg.conf, e.g.
    
    Section "Device"
    	Identifier "igfx"
    	Option "CustomEDID" "DP1:/path/to/dp1.edid,DP2:/path/to/dp2.edid"
    EndSection
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
    Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=89945

diff --git a/man/intel.man b/man/intel.man
index 91fc6df..07ff1be 100644
--- a/man/intel.man
+++ b/man/intel.man
@@ -201,6 +201,16 @@ that choice by specifying the entry under /sys/class/backlight to use.
 .IP
 Default: Automatic selection.
 .TP
+.BI "Option \*qCustomEDID\*q \*q" string \*q
+Override the probed EDID on particular outputs. Sometimes the manufacturer
+supplied EDID is corrupt or lacking a few usable modes and supplying a
+corrected EDID may be easier than specifying every modeline. This option
+allows to pass the path to load an EDID from per output. The format is a
+comma separated string of output:path pairs, e.g.
+DP1:/path/to/dp1.edid,DP2:/path/to/dp2.edid
+.IP
+Default: No override, use manufacturer supplied EDIDs.
+.TP
 .BI "Option \*qFallbackDebug\*q \*q" boolean \*q
 Enable printing of debugging information on acceleration fallbacks to the
 server log.
diff --git a/src/intel_options.c b/src/intel_options.c
index 465f739..783de8a 100644
--- a/src/intel_options.c
+++ b/src/intel_options.c
@@ -12,6 +12,7 @@ const OptionInfoRec intel_options[] = {
 	{OPTION_ACCEL_DISABLE,	"NoAccel",	OPTV_BOOLEAN,	{0},	0},
 	{OPTION_ACCEL_METHOD,	"AccelMethod",	OPTV_STRING,	{0},	0},
 	{OPTION_BACKLIGHT,	"Backlight",	OPTV_STRING,	{0},	0},
+	{OPTION_EDID,		"CustomEDID",	OPTV_STRING,	{0},	0},
 	{OPTION_DRI,		"DRI",		OPTV_STRING,	{0},	0},
 	{OPTION_PRESENT,	"Present",	OPTV_BOOLEAN,	{0},	1},
 	{OPTION_COLOR_KEY,	"ColorKey",	OPTV_INTEGER,	{0},	0},
diff --git a/src/intel_options.h b/src/intel_options.h
index 492e03f..2941323 100644
--- a/src/intel_options.h
+++ b/src/intel_options.h
@@ -15,6 +15,7 @@ enum intel_options {
 	OPTION_ACCEL_DISABLE,
 	OPTION_ACCEL_METHOD,
 	OPTION_BACKLIGHT,
+	OPTION_EDID,
 	OPTION_DRI,
 	OPTION_PRESENT,
 	OPTION_VIDEO_KEY,
diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c
index 7b082f5..98411c3 100644
--- a/src/sna/sna_display.c
+++ b/src/sna/sna_display.c
@@ -214,6 +214,8 @@ struct sna_output {
 	uint32_t edid_blob_id;
 	uint32_t edid_len;
 	void *edid_raw;
+	xf86MonPtr fake_edid_mon;
+	void *fake_edid_raw;
 
 	bool has_panel_limits;
 	int panel_hdisplay;
@@ -3504,18 +3506,36 @@ sna_output_add_default_modes(xf86OutputPtr output, DisplayModePtr modes)
 }
 
 static DisplayModePtr
+sna_output_override_edid(xf86OutputPtr output)
+{
+	struct sna_output *sna_output = output->driver_private;
+
+	if (sna_output->fake_edid_mon == NULL)
+		return NULL;
+
+	xf86OutputSetEDID(output, sna_output->fake_edid_mon);
+	return xf86DDCGetModes(output->scrn->scrnIndex,
+			       sna_output->fake_edid_mon);
+}
+
+static DisplayModePtr
 sna_output_get_modes(xf86OutputPtr output)
 {
 	struct sna_output *sna_output = output->driver_private;
-	DisplayModePtr Modes = NULL, current = NULL;
+	DisplayModePtr Modes, current;
 	int i;
 
 	DBG(("%s(%s:%d)\n", __FUNCTION__, output->name, sna_output->id));
 	assert(sna_output->id);
 
+	Modes = sna_output_override_edid(output);
+	if (Modes)
+		return Modes;
+
 	sna_output_attach_edid(output);
 	sna_output_attach_tile(output);
 
+	current = NULL;
 	if (output->crtc) {
 		struct drm_mode_crtc mode;
 
@@ -3603,6 +3623,8 @@ sna_output_destroy(xf86OutputPtr output)
 		return;
 
 	free(sna_output->edid_raw);
+	free(sna_output->fake_edid_raw);
+
 	for (i = 0; i < sna_output->num_props; i++) {
 		if (sna_output->props[i].kprop == NULL)
 			continue;
@@ -4283,6 +4305,116 @@ static int name_from_path(struct sna *sna,
 	return 0;
 }
 
+static char *fake_edid_name(xf86OutputPtr output)
+{
+	struct sna *sna = to_sna(output->scrn);
+	const char *str, *colon;
+
+#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,99,901,0)
+	str = xf86GetOptValString(sna->Options, OPTION_EDID);
+#else
+	str = NULL;
+#endif
+	if (str == NULL)
+		return NULL;
+
+	do {
+		colon = strchr(str, ':');
+		if (colon == NULL)
+			return NULL;
+
+		if (strncmp(str, output->name, colon-str) == 0 &&
+		    output->name[colon-str] == '\0') {
+			char *path;
+			int len;
+
+			str = colon + 1;
+			colon = strchr(str, ',');
+			if (colon)
+				len = colon - str;
+			else
+				len = strlen(str) + 1;
+
+			path = malloc(len);
+			if (path == NULL)
+				return NULL;
+
+			memcpy(path, str, len - 1);
+			path[len] = '\0';
+			return path;
+		}
+
+		str = strchr(colon + 1, ',');
+		if (str == NULL)
+			return NULL;
+
+		str++;
+	} while (1);
+}
+
+static void
+sna_output_load_fake_edid(xf86OutputPtr output)
+{
+	struct sna_output *sna_output = output->driver_private;
+	const char *filename;
+	FILE *file;
+	void *raw;
+	int size;
+	xf86MonPtr mon;
+
+	filename = fake_edid_name(output);
+	if (filename == NULL)
+		return;
+
+	file = fopen(filename, "rb");
+	if (file == NULL)
+		goto err;
+
+	fseek(file, 0, SEEK_END);
+	size = ftell(file);
+	if (size % 128) {
+		fclose(file);
+		goto err;
+	}
+
+	raw = malloc(size);
+	if (raw == NULL) {
+		fclose(file);
+		free(raw);
+		goto err;
+	}
+
+	fseek(file, 0, SEEK_SET);
+	if (fread(raw, size, 1, file) != 1) {
+		fclose(file);
+		free(raw);
+		goto err;
+	}
+	fclose(file);
+
+	mon = xf86InterpretEDID(output->scrn->scrnIndex, raw);
+	if (mon == NULL) {
+		free(raw);
+		goto err;
+	}
+
+	if (mon && size > 128)
+		mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA;
+
+	sna_output->fake_edid_mon = mon;
+	sna_output->fake_edid_raw = raw;
+
+	xf86DrvMsg(output->scrn->scrnIndex, X_CONFIG,
+		   "Loading EDID from \"%s\" for output %s\n",
+		   filename, output->name);
+	return;
+
+err:
+	xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
+		   "Could not read EDID file \"%s\" for output %s\n",
+		   filename, output->name);
+}
+
 static int
 sna_output_add(struct sna *sna, unsigned id, unsigned serial)
 {
@@ -4520,6 +4652,8 @@ reset:
 	output->possible_crtcs = possible_crtcs & count_to_mask(sna->mode.num_real_crtc);
 	output->interlaceAllowed = TRUE;
 
+	sna_output_load_fake_edid(output);
+
 	if (serial) {
 		if (output->randr_output == NULL) {
 			output->randr_output = RROutputCreate(xf86ScrnToScreen(scrn), name, len, output);


More information about the xorg-commit mailing list