All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/3] Provide workarounds to use DRM/KMS with broken graphics hardware
@ 2012-03-10 20:20 Carsten Emde
  2012-03-10 20:20 ` [PATCH 1/3] drivers-gpu-drm-allow-to-load-edid-firmware.patch Carsten Emde
                   ` (2 more replies)
  0 siblings, 3 replies; 14+ messages in thread
From: Carsten Emde @ 2012-03-10 20:20 UTC (permalink / raw)
  To: David Airlie; +Cc: Thomas Gleixner, Carsten Emde, DRI, LKML

In the good old days when graphics parameters were configured explicitly
in a file called xorg.conf, even broken hardware could be managed.

Today, with the advent of Kernel Mode Setting, a graphics board is
either correctly working because all components follow the standards -
or the computer is unusable, because the screen remains dark after
booting or displays the wrong area. Cases when this happens are:
- The BIOS assumes that an LVDS is always connected, even if it isn't.
- The graphics board does not recognize the monitor.
- The graphics board is unable to detect any EDID data.
- The graphics board incorrectly forwards EDID data to the driver.
- The monitor sends bogus EDID data.
- A KVM sends its own EDID data instead of querying the connected monitor.
- The brightness setting of the panel backlight does not work.
- Any combination of the above.
Adding the kernel parameter "nomodeset" helps in most cases, but causes
restrictions later on.

The three patches of this series add module parameters to the
drm_kms_helper module that
1. allow to load an EDID data set via the firmware interface,
2. provide a module parameter to selectively enable or disable a
graphics port,
3. provide a module parameter to select inverted brightness.

EDID data sets along with source files are provided for commonly used
screen resolutions (1024x768, 1280x1024, 1680x1050, 1920x1080).

Please note that these patches neither fix a kernel bug nor provide any
extra functionality. They simply work around broken hardware that
otherwise would be either unusable or usable in a very restricted way.
The patches do not modify the current functionality of the related
components in any way, unless the kernel is configured accordingly
and/or the newly provided module parameters are set.

	-Carsten. 


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 1/3] drivers-gpu-drm-allow-to-load-edid-firmware.patch
  2012-03-10 20:20 [PATCH 0/3] Provide workarounds to use DRM/KMS with broken graphics hardware Carsten Emde
@ 2012-03-10 20:20 ` Carsten Emde
  2012-03-11 13:44     ` Alan Cox
  2012-03-12 17:14   ` Valdis.Kletnieks
  2012-03-10 20:20 ` [PATCH 2/3] drivers-gpu-drm-add-disable-enable-connector.patch Carsten Emde
  2012-03-10 20:20 ` [PATCH 3/3] drivers-gpu-drm-i915-invert-backlight-brightness Carsten Emde
  2 siblings, 2 replies; 14+ messages in thread
From: Carsten Emde @ 2012-03-10 20:20 UTC (permalink / raw)
  To: David Airlie; +Cc: Thomas Gleixner, Carsten Emde, DRI, LKML

[-- Attachment #1: drivers-gpu-drm-allow-to-load-edid-firmware.patch --]
[-- Type: text/plain, Size: 31005 bytes --]

Broken monitors and/or broken graphic boards may send erroneous or no
EDID data. This also applies to broken KVM devices that are unable to
correctly forward the EDID data of the connected monitor but invent
their own fantasy data.

This patch allows to load an EDID data set via the firmware interface.
It contains data sets of frequently used screen resolutions (1024x768,
1280x1024, 1680x1050 and 1920x1080). The requested EDID data are
specified as a module parameter of the drm_kms_helper module, e.g.
options drm_kms_helper edid_firmware=edid/1280x1024.bin or as kernel
command line parameter.

In addition, an EDID data set can be specified on-the-fly via the
/sys/module interface, e.g.
echo edid/myedid.bin >/sys/module/drm_kms_helper/parameters/edid_firmware
The new screen mode is considered when the related kernel function is
called for the first time after the change. Such calls are made when the
X server is started or when the display settings dialog is opened in an
already running X server.

EDID data source files are provided for documentation purpose and as a
template to create EDID data sets for other screen resolutions. Note
that source compilation is not part of the build process, but needs to
be done manually, e.g.

#!/bin/bash
cd firmware/edid
for i in [1-9]*.S
do
  base=`echo $i | sed "s/\.S$//"`
  cc -c $base.S
  objcopy -O ihex $base.o $base.bin.ihex
  dos2unix $base.bin.ihex 2>/dev/null
done

The EDID data sets are based on standard timings that may not apply to a
particular monitor and even crash it. Ideally, EDID data of the
connected monitor should be used. They may be obtained through the 
drm/cardX/cardX-<connector>/edid entry in the /sys/devices PCI directory
of a correctly working graphics adapter.

Signed-off-by: Carsten Emde <C.Emde@osadl.org>

---
 Documentation/kernel-parameters.txt |    6 
 drivers/gpu/drm/Kconfig             |   10 +
 drivers/gpu/drm/Makefile            |    3 
 drivers/gpu/drm/drm_crtc_helper.c   |    8 -
 drivers/gpu/drm/drm_edid.c          |    3 
 drivers/gpu/drm/drm_edid_load.c     |  147 ++++++++++++++++++++
 firmware/Makefile                   |    7 
 firmware/edid/1024x768.S            |   44 ++++++
 firmware/edid/1024x768.bin.ihex     |    9 +
 firmware/edid/1280x1024.S           |   44 ++++++
 firmware/edid/1280x1024.bin.ihex    |    9 +
 firmware/edid/1680x1050.S           |   44 ++++++
 firmware/edid/1680x1050.bin.ihex    |    9 +
 firmware/edid/1920x1080.S           |   44 ++++++
 firmware/edid/1920x1080.bin.ihex    |    9 +
 firmware/edid/edid.S                |  261 ++++++++++++++++++++++++++++++++++++
 include/drm/drm_crtc.h              |    1 
 include/drm/drm_edid.h              |    1 
 18 files changed, 657 insertions(+), 2 deletions(-)

Index: linux-3.3-rc6/Documentation/kernel-parameters.txt
===================================================================
--- linux-3.3-rc6.orig/Documentation/kernel-parameters.txt
+++ linux-3.3-rc6/Documentation/kernel-parameters.txt
@@ -713,6 +713,12 @@ bytes respectively. Such letter suffixes
 			The filter can be disabled or changed to another
 			driver later using sysfs.
 
+	drm_kms_helper.edid_firmware=<file>
+			Broken monitors, graphic adapters and KVMs may
+			send no or broken EDID data sets. This parameter
+			allows to specify an EDID data set in the
+			/lib/firmware directory that is used instead.
+
 	dscc4.setup=	[NET]
 
 	earlycon=	[KNL] Output early console device and options.
Index: linux-3.3-rc6/drivers/gpu/drm/Kconfig
===================================================================
--- linux-3.3-rc6.orig/drivers/gpu/drm/Kconfig
+++ linux-3.3-rc6/drivers/gpu/drm/Kconfig
@@ -27,6 +27,16 @@ config DRM_KMS_HELPER
 	help
 	  FB and CRTC helpers for KMS drivers.
 
+config DRM_LOAD_EDID_FIRMWARE
+	bool "Allow to load an EDID data set instead of probing it"
+	depends on DRM_KMS_HELPER
+	help
+	  Say Y here, if you want to specify an EDID data blob to be
+	  loaded from the /lib/firmware directory. This may be necessary,
+	  if the graphics adapter or monitor are unable to provide
+	  appropriate EDID data. Since this feature is provided as a
+	  workaround for broken hardware, the default case is N.
+
 config DRM_TTM
 	tristate
 	depends on DRM
Index: linux-3.3-rc6/drivers/gpu/drm/Makefile
===================================================================
--- linux-3.3-rc6.orig/drivers/gpu/drm/Makefile
+++ linux-3.3-rc6/drivers/gpu/drm/Makefile
@@ -17,6 +17,9 @@ drm-y       :=	drm_auth.o drm_buffer.o d
 drm-$(CONFIG_COMPAT) += drm_ioc32.o
 
 drm_kms_helper-y := drm_fb_helper.o drm_crtc_helper.o drm_dp_i2c_helper.o
+ifdef CONFIG_DRM_LOAD_EDID_FIRMWARE
+drm_kms_helper-y += drm_edid_load.o
+endif
 
 obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o
 
Index: linux-3.3-rc6/drivers/gpu/drm/drm_crtc_helper.c
===================================================================
--- linux-3.3-rc6.orig/drivers/gpu/drm/drm_crtc_helper.c
+++ linux-3.3-rc6/drivers/gpu/drm/drm_crtc_helper.c
@@ -37,6 +37,7 @@
 #include "drm_fourcc.h"
 #include "drm_crtc_helper.h"
 #include "drm_fb_helper.h"
+#include "drm_edid.h"
 
 static bool drm_kms_helper_poll = true;
 module_param_named(poll, drm_kms_helper_poll, bool, 0600);
@@ -118,7 +119,12 @@ int drm_helper_probe_single_connector_mo
 		goto prune;
 	}
 
-	count = (*connector_funcs->get_modes)(connector);
+#ifdef CONFIG_DRM_LOAD_EDID_FIRMWARE
+	count = load_edid_firmware(connector);
+	if (count == 0)
+#endif
+		count = (*connector_funcs->get_modes)(connector);
+
 	if (count == 0 && connector->status == connector_status_connected)
 		count = drm_add_modes_noedid(connector, 1024, 768);
 	if (count == 0)
Index: linux-3.3-rc6/drivers/gpu/drm/drm_edid.c
===================================================================
--- linux-3.3-rc6.orig/drivers/gpu/drm/drm_edid.c
+++ linux-3.3-rc6/drivers/gpu/drm/drm_edid.c
@@ -149,7 +149,7 @@ EXPORT_SYMBOL(drm_edid_header_is_valid);
  * Sanity check the EDID block (base or extension).  Return 0 if the block
  * doesn't check out, or 1 if it's valid.
  */
-static bool
+bool
 drm_edid_block_valid(u8 *raw_edid)
 {
 	int i;
@@ -203,6 +203,7 @@ bad:
 	}
 	return 0;
 }
+EXPORT_SYMBOL(drm_edid_block_valid);
 
 /**
  * drm_edid_is_valid - sanity check EDID data
Index: linux-3.3-rc6/drivers/gpu/drm/drm_edid_load.c
===================================================================
--- /dev/null
+++ linux-3.3-rc6/drivers/gpu/drm/drm_edid_load.c
@@ -0,0 +1,147 @@
+/*
+   drm_edid_load.c: load an EDID data set via the firmware interface
+
+   Copyright (C) 2012 Carsten Emde <C.Emde@osadl.org>
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License
+   as published by the Free Software Foundation; either version 2
+   of the License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
+*/
+
+#include <linux/module.h>
+#include <linux/firmware.h>
+#include "drmP.h"
+#include "drm_crtc.h"
+#include "drm_crtc_helper.h"
+#include "drm_edid.h"
+
+static char edid_firmware[PATH_MAX];
+module_param_string(edid_firmware, edid_firmware, sizeof(edid_firmware), 0644);
+MODULE_PARM_DESC(edid_firmware, "Do not probe monitor, use specified EDID blob "
+	"in /lib/firmware instead");
+
+MODULE_FIRMWARE("edid/1024x768.bin");
+MODULE_FIRMWARE("edid/1280x1024.bin");
+MODULE_FIRMWARE("edid/1680x1050.bin");
+MODULE_FIRMWARE("edid/1920x1080.bin");
+
+static int edid_load(struct drm_connector *connector, char *name,
+		     char *connector_name)
+{
+	const struct firmware *fw;
+	struct platform_device *pdev;
+	u8 *edid;
+	int expected;
+	int err = 0;
+	int i, valid_extensions = 0;
+
+	pdev = platform_device_register_simple(connector_name, -1, NULL, 0);
+	if (IS_ERR(pdev)) {
+		DRM_ERROR("Failed to register EDID firmware platform device "
+		    "for connector \"%s\"\n", connector_name);
+		err = -EINVAL;
+		goto out;
+	}
+
+	err = request_firmware(&fw, name, &pdev->dev);
+	platform_device_unregister(pdev);
+
+	if (err) {
+		DRM_ERROR("Requesting EDID firmware \"%s\" failed (err=%d)\n",
+		    name, err);
+		goto out;
+	}
+
+	expected = (fw->data[0x7e] + 1) * EDID_LENGTH;
+	if (expected != fw->size) {
+		DRM_ERROR("Size of loaded EDID firmware \"%s\" is invalid "
+		    "(expected %d, got %d)\n", name, expected, (int) fw->size);
+		err = -EINVAL;
+		goto relfw_out;
+	}
+
+	edid = kmalloc(fw->size, GFP_KERNEL);
+	if (edid == NULL) {
+		err = -ENOMEM;
+		goto relfw_out;
+	}
+	memcpy(edid, fw->data, fw->size);
+
+	if (!drm_edid_block_valid(edid)) {
+		DRM_ERROR("Base block of EDID firmware \"%s\" is invalid ",
+		    name);
+		kfree(edid);
+		err = -EINVAL;
+		goto relfw_out;
+	}
+
+	for (i = 1; i <= edid[0x7e]; i++) {
+		if (i != valid_extensions + 1)
+			memcpy(edid + (valid_extensions + 1) * EDID_LENGTH,
+			    edid + i * EDID_LENGTH, EDID_LENGTH);
+		if (drm_edid_block_valid(edid + i * EDID_LENGTH))
+			valid_extensions++;
+	}
+
+	if (valid_extensions != edid[0x7e]) {
+		edid[EDID_LENGTH-1] += edid[0x7e] - valid_extensions;
+		DRM_INFO("Found %d valid extensions instead of %d in EDID data "
+		    "\"%s\" for connector \"%s\"\n", valid_extensions,
+		    edid[0x7e], name, connector_name);
+		edid[0x7e] = valid_extensions;
+		edid = krealloc(edid, (valid_extensions + 1) * EDID_LENGTH,
+		    GFP_KERNEL);
+		if (edid == NULL) {
+			err = -ENOMEM;
+			goto relfw_out;
+		}
+	}
+
+	connector->display_info.raw_edid = edid;
+	DRM_INFO("Loaded EDID base block and %d extension%s from "
+	    "\"%s\" for connector \"%s\"\n", valid_extensions,
+	    valid_extensions == 1 ? "" : "s", name, connector_name);
+
+relfw_out:
+	release_firmware(fw);
+
+out:
+	return err;
+}
+
+int load_edid_firmware(struct drm_connector *connector)
+{
+	char *connector_name = drm_get_connector_name(connector);
+	char *last;
+	int ret = 0;
+
+	if (edid_firmware[0] == '\0')
+		return ret;
+
+	last = edid_firmware + strlen(edid_firmware) - 1;
+	if (*last == '\n')
+		*last = '\0';
+
+	DRM_INFO("Module parameter \"edid_firmware=%s\" found\n",
+	    edid_firmware);
+
+	ret = edid_load(connector, edid_firmware, connector_name);
+	if (ret)
+		return 0;
+
+	drm_mode_connector_update_edid_property(connector,
+	    (struct edid *) connector->display_info.raw_edid);
+
+	return drm_add_edid_modes(connector, (struct edid *)
+	    connector->display_info.raw_edid);
+}
Index: linux-3.3-rc6/firmware/Makefile
===================================================================
--- linux-3.3-rc6.orig/firmware/Makefile
+++ linux-3.3-rc6/firmware/Makefile
@@ -141,6 +141,13 @@ fw-shipped-$(CONFIG_USB_VICAM) += vicam/
 fw-shipped-$(CONFIG_VIDEO_CPIA2) += cpia2/stv0672_vp4.bin
 fw-shipped-$(CONFIG_YAM) += yam/1200.bin yam/9600.bin
 
+ifdef CONFIG_DRM_LOAD_EDID_FIRMWARE
+fw-shipped-$(CONFIG_DRM_KMS_HELPER) += edid/1024x768.bin
+fw-shipped-$(CONFIG_DRM_KMS_HELPER) += edid/1280x1024.bin
+fw-shipped-$(CONFIG_DRM_KMS_HELPER) += edid/1680x1050.bin
+fw-shipped-$(CONFIG_DRM_KMS_HELPER) += edid/1920x1080.bin
+endif
+
 fw-shipped-all := $(fw-shipped-y) $(fw-shipped-m) $(fw-shipped-)
 
 # Directories which we _might_ need to create, so we have a rule for them.
Index: linux-3.3-rc6/firmware/edid/1024x768.S
===================================================================
--- /dev/null
+++ linux-3.3-rc6/firmware/edid/1024x768.S
@@ -0,0 +1,44 @@
+/*
+   1024x768.S: EDID data set for standard 1024x768 60 Hz monitor
+
+   Copyright (C) 2011 Carsten Emde <C.Emde@osadl.org>
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License
+   as published by the Free Software Foundation; either version 2
+   of the License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
+*/
+
+/* EDID */
+#define VERSION 1
+#define REVISION 3
+
+/* Display */
+#define CLOCK 65000 /* kHz */
+#define XPIX 1024
+#define YPIX 768
+#define XY_RATIO XY_RATIO_4_3
+#define XBLANK 320
+#define YBLANK 38
+#define XOFFSET 8
+#define XPULSE 144
+#define YOFFSET (63+3)
+#define YPULSE (63+6)
+#define DPI 72
+#define VFREQ 60 /* Hz */
+#define TIMING_NAME "Linux XGA"
+#define ESTABLISHED_TIMINGS_BITS 0x08 /* Bit 3 -> 1024x768 @60 Hz */
+#define HSYNC_POL 0
+#define VSYNC_POL 0
+#define CRC 0x55
+
+#include "edid.S"
Index: linux-3.3-rc6/firmware/edid/1024x768.bin.ihex
===================================================================
--- /dev/null
+++ linux-3.3-rc6/firmware/edid/1024x768.bin.ihex
@@ -0,0 +1,9 @@
+:1000000000FFFFFFFFFFFF0031D8000000000000ED
+:10001000051601036D231A78EA5EC0A4594A982593
+:10002000205054000800614001010101010101015B
+:1000300001010101010164190040410026300890CE
+:100040003600630A11000018000000FF004C696EC2
+:1000500075782023300A20202020000000FD003B7E
+:100060003D2F3107000A202020202020000000FC26
+:10007000004C696E7578205847410A2020200055B1
+:00000001FF
Index: linux-3.3-rc6/firmware/edid/1280x1024.S
===================================================================
--- /dev/null
+++ linux-3.3-rc6/firmware/edid/1280x1024.S
@@ -0,0 +1,44 @@
+/*
+   1280x1024.S: EDID data set for standard 1280x1024 60 Hz monitor
+
+   Copyright (C) 2011 Carsten Emde <C.Emde@osadl.org>
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License
+   as published by the Free Software Foundation; either version 2
+   of the License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
+*/
+
+/* EDID */
+#define VERSION 1
+#define REVISION 3
+
+/* Display */
+#define CLOCK 108000 /* kHz */
+#define XPIX 1280
+#define YPIX 1024
+#define XY_RATIO XY_RATIO_5_4
+#define XBLANK 408
+#define YBLANK 42
+#define XOFFSET 48
+#define XPULSE 112
+#define YOFFSET (63+1)
+#define YPULSE (63+3)
+#define DPI 72
+#define VFREQ 60 /* Hz */
+#define TIMING_NAME "Linux SXGA"
+#define ESTABLISHED_TIMINGS_BITS 0x00 /* none */
+#define HSYNC_POL 1
+#define VSYNC_POL 1
+#define CRC 0xa0
+
+#include "edid.S"
Index: linux-3.3-rc6/firmware/edid/1280x1024.bin.ihex
===================================================================
--- /dev/null
+++ linux-3.3-rc6/firmware/edid/1280x1024.bin.ihex
@@ -0,0 +1,9 @@
+:1000000000FFFFFFFFFFFF0031D8000000000000ED
+:10001000051601036D2C2378EA5EC0A4594A982581
+:100020002050540000008180010101010101010103
+:10003000010101010101302A009851002A4030706D
+:100040001300BC631100001E000000FF004C696E2D
+:1000500075782023300A20202020000000FD003B7E
+:100060003D3E400B000A202020202020000000FC04
+:10007000004C696E757820535847410A202000A033
+:00000001FF
Index: linux-3.3-rc6/firmware/edid/1680x1050.S
===================================================================
--- /dev/null
+++ linux-3.3-rc6/firmware/edid/1680x1050.S
@@ -0,0 +1,44 @@
+/*
+   1680x1050.S: EDID data set for standard 1680x1050 60 Hz monitor
+
+   Copyright (C) 2012 Carsten Emde <C.Emde@osadl.org>
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License
+   as published by the Free Software Foundation; either version 2
+   of the License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
+*/
+
+/* EDID */
+#define VERSION 1
+#define REVISION 3
+
+/* Display */
+#define CLOCK 146250 /* kHz */
+#define XPIX 1680
+#define YPIX 1050
+#define XY_RATIO XY_RATIO_16_10
+#define XBLANK 560
+#define YBLANK 39
+#define XOFFSET 104
+#define XPULSE 176
+#define YOFFSET (63+3)
+#define YPULSE (63+6)
+#define DPI 96
+#define VFREQ 60 /* Hz */
+#define TIMING_NAME "Linux WSXGA"
+#define ESTABLISHED_TIMINGS_BITS 0x00 /* none */
+#define HSYNC_POL 1
+#define VSYNC_POL 1
+#define CRC 0x26
+
+#include "edid.S"
Index: linux-3.3-rc6/firmware/edid/1680x1050.bin.ihex
===================================================================
--- /dev/null
+++ linux-3.3-rc6/firmware/edid/1680x1050.bin.ihex
@@ -0,0 +1,9 @@
+:1000000000FFFFFFFFFFFF0031D8000000000000ED
+:10001000051601036D2B1B78EA5EC0A4594A98258A
+:10002000205054000000B300010101010101010151
+:1000300001010101010121399030621A274068B0A5
+:100040003600B5111100001E000000FF004C696E63
+:1000500075782023300A20202020000000FD003B7E
+:100060003D40420F000A202020202020000000FCFC
+:10007000004C696E75782057535847410A20002676
+:00000001FF
Index: linux-3.3-rc6/firmware/edid/1920x1080.S
===================================================================
--- /dev/null
+++ linux-3.3-rc6/firmware/edid/1920x1080.S
@@ -0,0 +1,44 @@
+/*
+   1920x1080.S: EDID data set for standard 1920x1080 60 Hz monitor
+
+   Copyright (C) 2012 Carsten Emde <C.Emde@osadl.org>
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License
+   as published by the Free Software Foundation; either version 2
+   of the License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
+*/
+
+/* EDID */
+#define VERSION 1
+#define REVISION 3
+
+/* Display */
+#define CLOCK 148500 /* kHz */
+#define XPIX 1920
+#define YPIX 1080
+#define XY_RATIO XY_RATIO_16_9
+#define XBLANK 280
+#define YBLANK 45
+#define XOFFSET 88
+#define XPULSE 44
+#define YOFFSET (63+4)
+#define YPULSE (63+5)
+#define DPI 96
+#define VFREQ 60 /* Hz */
+#define TIMING_NAME "Linux FHD"
+#define ESTABLISHED_TIMINGS_BITS 0x00 /* none */
+#define HSYNC_POL 1
+#define VSYNC_POL 1
+#define CRC 0x05
+
+#include "edid.S"
Index: linux-3.3-rc6/firmware/edid/1920x1080.bin.ihex
===================================================================
--- /dev/null
+++ linux-3.3-rc6/firmware/edid/1920x1080.bin.ihex
@@ -0,0 +1,9 @@
+:1000000000FFFFFFFFFFFF0031D8000000000000ED
+:10001000051601036D321C78EA5EC0A4594A982582
+:10002000205054000000D1C0010101010101010173
+:10003000010101010101023A801871382D40582C4C
+:100040004500F4191100001E000000FF004C696E0D
+:1000500075782023300A20202020000000FD003B7E
+:100060003D42440F000A202020202020000000FCF8
+:10007000004C696E7578204648440A20202000050F
+:00000001FF
Index: linux-3.3-rc6/firmware/edid/edid.S
===================================================================
--- /dev/null
+++ linux-3.3-rc6/firmware/edid/edid.S
@@ -0,0 +1,261 @@
+/*
+   edid.S: EDID data template
+
+   Copyright (C) 2012 Carsten Emde <C.Emde@osadl.org>
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License
+   as published by the Free Software Foundation; either version 2
+   of the License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
+*/
+
+
+/* Manufacturer */
+#define MFG_LNX1 'L'
+#define MFG_LNX2 'N'
+#define MFG_LNX3 'X'
+#define SERIAL 0
+#define YEAR 2012
+#define WEEK 5
+
+/* EDID 1.3 standard definitions */
+#define XY_RATIO_16_10	0b00
+#define XY_RATIO_4_3	0b01
+#define XY_RATIO_5_4	0b10
+#define XY_RATIO_16_9	0b11
+
+#define mfgname2id(v1,v2,v3) \
+	((((v1-'@')&0x1f)<<10)+(((v2-'@')&0x1f)<<5)+((v3-'@')&0x1f))
+#define swap16(v1) ((v1>>8)+((v1&0xff)<<8))
+#define msbs2(v1,v2) ((((v1>>8)&0x0f)<<4)+((v2>>8)&0x0f))
+#define msbs4(v1,v2,v3,v4) \
+	(((v1&0x03)>>2)+((v2&0x03)>>4)+((v3&0x03)>>6)+((v4&0x03)>>8))
+#define pixdpi2mm(pix,dpi) ((pix*25)/dpi)
+#define xsize pixdpi2mm(XPIX,DPI)
+#define ysize pixdpi2mm(YPIX,DPI)
+
+		.data
+
+/* Fixed header pattern */
+header:		.byte	0x00,0xff,0xff,0xff,0xff,0xff,0xff,0x00
+
+mfg_id:		.word	swap16(mfgname2id(MFG_LNX1, MFG_LNX2, MFG_LNX3))
+
+prod_code:	.word	0
+
+/* Serial number. 32 bits, little endian. */
+serial_number:	.long	SERIAL
+
+/* Week of manufacture */
+week:		.byte	WEEK
+
+/* Year of manufacture, less 1990. (1990-2245)
+   If week=255, it is the model year instead */
+year:		.byte	YEAR-1990
+
+version:	.byte	VERSION 	/* EDID version, usually 1 (for 1.3) */
+revision:	.byte	REVISION	/* EDID revision, usually 3 (for 1.3) */
+
+/* If Bit 7=1	Digital input. If set, the following bit definitions apply:
+     Bits 6-1	Reserved, must be 0
+     Bit 0	Signal is compatible with VESA DFP 1.x TMDS CRGB,
+		  1 pixel per clock, up to 8 bits per color, MSB aligned,
+   If Bit 7=0	Analog input. If clear, the following bit definitions apply:
+     Bits 6-5	Video white and sync levels, relative to blank
+		  00=+0.7/-0.3 V; 01=+0.714/-0.286 V;
+		  10=+1.0/-0.4 V; 11=+0.7/0 V
+   Bit 4	Blank-to-black setup (pedestal) expected
+   Bit 3	Separate sync supported
+   Bit 2	Composite sync (on HSync) supported
+   Bit 1	Sync on green supported
+   Bit 0	VSync pulse must be serrated when somposite or
+		  sync-on-green is used. */
+video_parms:	.byte	0x6d
+
+/* Maximum horizontal image size, in centimetres
+   (max 292 cm/115 in at 16:9 aspect ratio) */
+max_hor_size:	.byte	xsize/10
+
+/* Maximum vertical image size, in centimetres.
+   If either byte is 0, undefined (e.g. projector) */
+max_vert_size:	.byte	ysize/10
+
+/* Display gamma, minus 1, times 100 (range 1.00-3.5 */
+gamma:		.byte	120
+
+/* Bit 7	DPMS standby supported
+   Bit 6	DPMS suspend supported
+   Bit 5	DPMS active-off supported
+   Bits 4-3	Display type: 00=monochrome; 01=RGB colour;
+		  10=non-RGB multicolour; 11=undefined
+   Bit 2	Standard sRGB colour space. Bytes 25-34 must contain
+		  sRGB standard values.
+   Bit 1	Preferred timing mode specified in descriptor block 1.
+   Bit 0	GTF supported with default parameter values. */
+dsp_features:	.byte	0xea
+
+/* Chromaticity coordinates. */
+/* Red and green least-significant bits
+   Bits 7-6	Red x value least-significant 2 bits
+   Bits 5-4	Red y value least-significant 2 bits
+   Bits 3-2	Green x value lst-significant 2 bits
+   Bits 1-0	Green y value least-significant 2 bits */
+red_green_lsb:	.byte	0x5e
+
+/* Blue and white least-significant 2 bits */
+blue_white_lsb:	.byte	0xc0
+
+/* Red x value most significant 8 bits.
+   0-255 encodes 0-0.996 (255/256); 0-0.999 (1023/1024) with lsbits */
+red_x_msb:	.byte	0xa4
+
+/* Red y value most significant 8 bits */
+red_y_msb:	.byte	0x59
+
+/* Green x and y value most significant 8 bits */
+green_x_y_msb:	.byte	0x4a,0x98
+
+/* Blue x and y value most significant 8 bits */
+blue_x_y_msb:	.byte	0x25,0x20
+
+/* Default white point x and y value most significant 8 bits */
+white_x_y_msb:	.byte	0x50,0x54
+
+/* Established timings */
+/* Bit 7	720x400 @ 70 Hz
+   Bit 6	720x400 @ 88 Hz
+   Bit 5	640x480 @ 60 Hz
+   Bit 4	640x480 @ 67 Hz
+   Bit 3	640x480 @ 72 Hz
+   Bit 2	640x480 @ 75 Hz
+   Bit 1	800x600 @ 56 Hz
+   Bit 0	800x600 @ 60 Hz */
+estbl_timing1:	.byte	0x00
+
+/* Bit 7	800x600 @ 72 Hz
+   Bit 6	800x600 @ 75 Hz
+   Bit 5	832x624 @ 75 Hz
+   Bit 4	1024x768 @ 87 Hz, interlaced (1024x768)
+   Bit 3	1024x768 @ 60 Hz
+   Bit 2	1024x768 @ 72 Hz
+   Bit 1	1024x768 @ 75 Hz
+   Bit 0	1280x1024 @ 75 Hz */
+estbl_timing2:	.byte	ESTABLISHED_TIMINGS_BITS
+
+/* Bit 7	1152x870 @ 75 Hz (Apple Macintosh II)
+   Bits 6-0 	Other manufacturer-specific display mod */
+estbl_timing3:	.byte	0x00
+
+/* Standard timing */
+/* X resolution, less 31, divided by 8 (256-2288 pixels) */
+std_xres:	.byte	(XPIX/8)-31
+/* Y resolution, X:Y pixel ratio
+   Bits 7-6	X:Y pixel ratio: 00=16:10; 01=4:3; 10=5:4; 11=16:9.
+   Bits 5-0	Vertical frequency, less 60 (60-123 Hz) */
+std_vres:	.byte	(XY_RATIO<<6)+VFREQ-60
+		.fill	7,2,0x0101	/* Unused */
+
+descriptor1:
+/* Pixel clock in 10 kHz units. (0.-655.35 MHz, little-endian) */
+clock:		.word	CLOCK/10
+
+/* Horizontal active pixels 8 lsbits (0-4095) */
+x_act_lsb:	.byte	XPIX&0xff
+/* Horizontal blanking pixels 8 lsbits (0-4095)
+   End of active to start of next active. */
+x_blk_lsb:	.byte	XBLANK&0xff
+/* Bits 7-4 	Horizontal active pixels 4 msbits
+   Bits 3-0	Horizontal blanking pixels 4 msbits */
+x_msbs:		.byte	msbs2(XPIX,XBLANK)
+
+/* Vertical active lines 8 lsbits (0-4095) */
+y_act_lsb:	.byte	YPIX&0xff
+/* Vertical blanking lines 8 lsbits (0-4095) */
+y_blk_lsb:	.byte	YBLANK&0xff
+/* Bits 7-4 	Vertical active lines 4 msbits
+   Bits 3-0 	Vertical blanking lines 4 msbits */
+y_msbs:		.byte	msbs2(YPIX,YBLANK)
+
+/* Horizontal sync offset pixels 8 lsbits (0-1023) From blanking start */
+x_snc_off_lsb:	.byte	XOFFSET&0xff
+/* Horizontal sync pulse width pixels 8 lsbits (0-1023) */
+x_snc_pls_lsb:	.byte	XPULSE&0xff
+/* Bits 7-4 	Vertical sync offset lines 4 lsbits -63)
+   Bits 3-0 	Vertical sync pulse width lines 4 lsbits -63) */
+y_snc_lsb:	.byte	((YOFFSET-63)<<4)+(YPULSE-63)
+/* Bits 7-6 	Horizontal sync offset pixels 2 msbits
+   Bits 5-4 	Horizontal sync pulse width pixels 2 msbits
+   Bits 3-2 	Vertical sync offset lines 2 msbits
+   Bits 1-0 	Vertical sync pulse width lines 2 msbits */
+xy_snc_msbs:	.byte	msbs4(XOFFSET,XPULSE,YOFFSET,YPULSE)
+
+/* Horizontal display size, mm, 8 lsbits (0-4095 mm, 161 in) */
+x_dsp_size:	.byte	xsize&0xff
+
+/* Vertical display size, mm, 8 lsbits (0-4095 mm, 161 in) */
+y_dsp_size:	.byte	ysize&0xff
+
+/* Bits 7-4 	Horizontal display size, mm, 4 msbits
+   Bits 3-0 	Vertical display size, mm, 4 msbits */
+dsp_size_mbsb:	.byte	msbs2(xsize,ysize)
+
+/* Horizontal border pixels (each side; total is twice this) */
+x_border:	.byte	0
+/* Vertical border lines (each side; total is twice this) */
+y_border:	.byte	0
+
+/* Bit 7 	Interlaced
+   Bits 6-5 	Stereo mode: 00=No stereo; other values depend on bit 0:
+   Bit 0=0: 01=Field sequential, sync=1 during right; 10=similar,
+     sync=1 during left; 11=4-way interleaved stereo
+   Bit 0=1 2-way interleaved stereo: 01=Right image on even lines;
+     10=Left image on even lines; 11=side-by-side
+   Bits 4-3 	Sync type: 00=Analog composite; 01=Bipolar analog composite;
+     10=Digital composite (on HSync); 11=Digital separate
+   Bit 2 	If digital separate: Vertical sync polarity (1=positive)
+   Other types: VSync serrated (HSync during VSync)
+   Bit 1 	If analog sync: Sync on all 3 RGB lines (else green only)
+   Digital: HSync polarity (1=positive)
+   Bit 0 	2-way line-interleaved stereo, if bits 4-3 are not 00. */
+features:	.byte	0x18+(VSYNC_POL<<2)+(HSYNC_POL<<1)
+
+descriptor2:	.byte	0,0	/* Not a detailed timing descriptor */
+		.byte	0	/* Must be zero */
+		.byte	0xff	/* Descriptor is monitor serial number (text) */
+		.byte	0	/* Must be zero */
+start1:		.ascii	"Linux #0"
+end1:		.byte	0x0a	/* End marker */
+		.fill	12-(end1-start1), 1, 0x20 /* Padded spaces */
+descriptor3:	.byte	0,0	/* Not a detailed timing descriptor */
+		.byte	0	/* Must be zero */
+		.byte	0xfd	/* Descriptor is monitor range limits */
+		.byte	0	/* Must be zero */
+start2:		.byte	VFREQ-1	/* Minimum vertical field rate (1-255 Hz) */
+		.byte	VFREQ+1	/* Maximum vertical field rate (1-255 Hz) */
+		.byte	(CLOCK/(XPIX+XBLANK))-1 /* Minimum horizontal line rate
+						    (1-255 kHz) */
+		.byte	(CLOCK/(XPIX+XBLANK))+1 /* Maximum horizontal line rate
+						    (1-255 kHz) */
+		.byte	(CLOCK/10000)+1	/* Maximum pixel clock rate, rounded up
+					   to 10 MHz multiple (10-2550 MHz) */
+		.byte	0	/* No extended timing information type */
+end2:		.byte	0x0a	/* End marker */
+		.fill	12-(end2-start2), 1, 0x20 /* Padded spaces */
+descriptor4:	.byte	0,0	/* Not a detailed timing descriptor */
+		.byte	0	/* Must be zero */
+		.byte	0xfc	/* Descriptor is text */
+		.byte	0	/* Must be zero */
+start3:		.ascii	TIMING_NAME
+end3:		.byte	0x0a	/* End marker */
+		.fill	12-(end3-start3), 1, 0x20 /* Padded spaces */
+extensions:	.byte	0	/* Number of extensions to follow */
+checksum:	.byte	CRC	/* Sum of all bytes must be 0 */
Index: linux-3.3-rc6/include/drm/drm_crtc.h
===================================================================
--- linux-3.3-rc6.orig/include/drm/drm_crtc.h
+++ linux-3.3-rc6/include/drm/drm_crtc.h
@@ -995,6 +995,7 @@ extern int drm_add_modes_noedid(struct d
 				int hdisplay, int vdisplay);
 
 extern int drm_edid_header_is_valid(const u8 *raw_edid);
+extern bool drm_edid_block_valid(u8 *raw_edid);
 extern bool drm_edid_is_valid(struct edid *edid);
 struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev,
 					   int hsize, int vsize, int fresh);
Index: linux-3.3-rc6/include/drm/drm_edid.h
===================================================================
--- linux-3.3-rc6.orig/include/drm/drm_edid.h
+++ linux-3.3-rc6/include/drm/drm_edid.h
@@ -238,5 +238,6 @@ int drm_av_sync_delay(struct drm_connect
 		      struct drm_display_mode *mode);
 struct drm_connector *drm_select_eld(struct drm_encoder *encoder,
 				     struct drm_display_mode *mode);
+int load_edid_firmware(struct drm_connector *connector);
 
 #endif /* __DRM_EDID_H__ */


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 2/3] drivers-gpu-drm-add-disable-enable-connector.patch
  2012-03-10 20:20 [PATCH 0/3] Provide workarounds to use DRM/KMS with broken graphics hardware Carsten Emde
  2012-03-10 20:20 ` [PATCH 1/3] drivers-gpu-drm-allow-to-load-edid-firmware.patch Carsten Emde
@ 2012-03-10 20:20 ` Carsten Emde
  2012-03-11  7:20     ` Dave Airlie
  2012-03-10 20:20 ` [PATCH 3/3] drivers-gpu-drm-i915-invert-backlight-brightness Carsten Emde
  2 siblings, 1 reply; 14+ messages in thread
From: Carsten Emde @ 2012-03-10 20:20 UTC (permalink / raw)
  To: David Airlie; +Cc: Thomas Gleixner, Carsten Emde, DRI, LKML

[-- Attachment #1: drivers-gpu-drm-add-disable-enable-connector.patch --]
[-- Type: text/plain, Size: 9468 bytes --]

Some recent integrated graphics chipset, notably Intel's "Pineview", also
provide on-chip LVDS support. As an extra service, the LVDS interface supplies
EDID data - irrespective of whether an LVDS panel is connected or not. The
drm_mode_getresources() function, therefore, causes Xorg to always include
the LVDS panel into the display and initialize a separate screen for it. e.g.
(II) intel(0): Output LVDS1 connected
(II) intel(0): Output VGA1 connected
(II) intel(0): Using spanning desktop for initial modes
(II) intel(0): Output LVDS1 using initial mode 1024x768 +0+0
(II) intel(0): Output VGA1 using initial mode 1280x1024 +1024+0
which is not what you want, if the only connected screen is a VGA monitor.
One would assume that the BIOS settings of such systems would allow to
separately enable or disable LVDS support; unfortunately, systems have been
found in the wild that do not provide this feature.

This patch introduces the module parameter "disable_connector" of the
drm_kms_helper module that may specify the name of the connector to be
considered disabled, e.g.
  # cat /etc/modprobe.d/drm_kms_helper.conf 
  options drm_kms_helper disable_connector=LVDS-1
which lets Xorg correctly initialize the screen, e.g.
(II) intel(0): Output LVDS1 disconnected 
(II) intel(0): Output VGA1 connected
(II) intel(0): Using exact sizes for initial modes 
(II) intel(0): Output VGA1 using initial mode 1280x1024 +0+0

A second scenario applies to broken graphics adapters that are unable to
correctly detect connected monitors and end up in a situation where
the default screen resolution of 1024x768 is selected that may not be
appropriate, e.g.
(II) intel(0): Output VGA1 disconnected
(II) intel(0): Output HDMI1 disconnected
(II) intel(0): Output DP1 disconnected
(II) intel(0): Output HDMI2 disconnected
(II) intel(0): Output DP2 disconnected   
(WW) intel(0): No outputs definitely connected, trying again...
(II) intel(0): Output VGA1 disconnected
(II) intel(0): Output HDMI1 disconnected
(II) intel(0): Output DP1 disconnected
(II) intel(0): Output HDMI2 disconnected
(II) intel(0): Output DP2 disconnected
(WW) intel(0): Unable to find connected outputs - setting 1024x768 initial framebuffer 

This patch introduces a second module parameter "enable_connector" of the
drm_kms_helper module that may specify the name of the connector to be
taken as connected, e.g.
  # cat /etc/modprobe.d/drm_kms_helper.conf 
  options drm_kms_helper enable_connector=VGA-1
which lets Xorg correctly initialize the screen, e.g.
(II) intel(0): Output VGA1 connected
(II) intel(0): Output HDMI1 disconnected
(II) intel(0): Output DP1 disconnected
(II) intel(0): Output HDMI2 disconnected
(II) intel(0): Output DP2 disconnected
(II) intel(0): Using exact sizes for initial modes
(II) intel(0): Output VGA1 using initial mode 1280x1024 +0+0

Signed-off-by: Carsten Emde <C.Emde@osadl.org>

---
 Documentation/kernel-parameters.txt |   13 ++++++++++++
 drivers/gpu/drm/drm_crtc.c          |   15 ++++++++++---
 drivers/gpu/drm/drm_crtc_helper.c   |    3 ++
 drivers/gpu/drm/drm_fb_helper.c     |   39 ++++++++++++++++++++++++++++++++++--
 include/drm/drm_crtc.h              |    3 +-
 5 files changed, 66 insertions(+), 7 deletions(-)

Index: linux-3.3-rc6/Documentation/kernel-parameters.txt
===================================================================
--- linux-3.3-rc6.orig/Documentation/kernel-parameters.txt
+++ linux-3.3-rc6/Documentation/kernel-parameters.txt
@@ -713,12 +713,25 @@ bytes respectively. Such letter suffixes
 			The filter can be disabled or changed to another
 			driver later using sysfs.
 
+	drm_kms_helper.disable_connector=<connector>
+			The BIOS may always report that a panel is connected,
+			irrespective of whether it really is or not which may
+			lead to a bogus screen layout. This parameter is used
+			to explicitly disable a particular connector, e.g.
+			drm_kms_helper disable_connector=LVDS-1
+
 	drm_kms_helper.edid_firmware=<file>
 			Broken monitors, graphic adapters and KVMs may
 			send no or broken EDID data sets. This parameter
 			allows to specify an EDID data set in the
 			/lib/firmware directory that is used instead.
 
+	drm_kms_helper.enable_connector=<connector>
+			Broken hardware may be unable to correctly discover a
+			monitor. This parameter is used to let the drm subsystem
+			assume that a monitor is present at the specified
+			connector, e.g. drm_kms_helper enable_connector=VGA-1
+
 	dscc4.setup=	[NET]
 
 	earlycon=	[KNL] Output early console device and options.
Index: linux-3.3-rc6/drivers/gpu/drm/drm_crtc.c
===================================================================
--- linux-3.3-rc6.orig/drivers/gpu/drm/drm_crtc.c
+++ linux-3.3-rc6/drivers/gpu/drm/drm_crtc.c
@@ -204,6 +204,8 @@ char *drm_get_connector_status_name(enum
 		return "connected";
 	else if (status == connector_status_disconnected)
 		return "disconnected";
+	else if (status == connector_status_disabled)
+		return "disabled";
 	else
 		return "unknown";
 }
@@ -1172,8 +1174,11 @@ int drm_mode_getresources(struct drm_dev
 		list_for_each(lh, &dev->mode_config.crtc_list)
 			crtc_count++;
 
-		list_for_each(lh, &dev->mode_config.connector_list)
-			connector_count++;
+		list_for_each_entry(connector,
+		    &dev->mode_config.connector_list, head)
+			if (connector->status != connector_status_disabled)
+				connector_count++;
+
 
 		list_for_each(lh, &dev->mode_config.encoder_list)
 			encoder_count++;
@@ -1268,8 +1273,10 @@ int drm_mode_getresources(struct drm_dev
 		connector_id = (uint32_t __user *)(unsigned long)card_res->connector_id_ptr;
 		if (file_priv->master->minor->type == DRM_MINOR_CONTROL) {
 			list_for_each_entry(connector,
-					    &dev->mode_config.connector_list,
-					    head) {
+			    &dev->mode_config.connector_list, head) {
+				if (connector->status ==
+				    connector_status_disabled)
+					continue;
 				DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
 					connector->base.id,
 					drm_get_connector_name(connector));
Index: linux-3.3-rc6/drivers/gpu/drm/drm_crtc_helper.c
===================================================================
--- linux-3.3-rc6.orig/drivers/gpu/drm/drm_crtc_helper.c
+++ linux-3.3-rc6/drivers/gpu/drm/drm_crtc_helper.c
@@ -119,6 +119,9 @@ int drm_helper_probe_single_connector_mo
 		goto prune;
 	}
 
+	if (connector->status == connector_status_disabled)
+		return 0;
+
 #ifdef CONFIG_DRM_LOAD_EDID_FIRMWARE
 	count = load_edid_firmware(connector);
 	if (count == 0)
Index: linux-3.3-rc6/drivers/gpu/drm/drm_fb_helper.c
===================================================================
--- linux-3.3-rc6.orig/drivers/gpu/drm/drm_fb_helper.c
+++ linux-3.3-rc6/drivers/gpu/drm/drm_fb_helper.c
@@ -28,6 +28,7 @@
  *      Jesse Barnes <jesse.barnes@intel.com>
  */
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/sysrq.h>
 #include <linux/slab.h>
 #include <linux/fb.h>
@@ -1056,6 +1057,9 @@ static bool drm_connector_enabled(struct
 {
 	bool enable;
 
+	if (connector->status == connector_status_disabled)
+		return false;
+
 	if (strict) {
 		enable = connector->status == connector_status_connected;
 	} else {
@@ -1064,6 +1068,16 @@ static bool drm_connector_enabled(struct
 	return enable;
 }
 
+static char disable_connector[32];
+module_param_string(disable_connector, disable_connector,
+		    sizeof(disable_connector), 0644);
+MODULE_PARM_DESC(disable_connector,
+	"Do not use specified connector, even if monitor detected");
+static char enable_connector[32];
+module_param_string(enable_connector, enable_connector,
+		    sizeof(enable_connector), 0644);
+MODULE_PARM_DESC(enable_connector,
+	"Use specified connector, even if no monitor connected");
 static void drm_enable_connectors(struct drm_fb_helper *fb_helper,
 				  bool *enabled)
 {
@@ -1072,10 +1086,31 @@ static void drm_enable_connectors(struct
 	int i = 0;
 
 	for (i = 0; i < fb_helper->connector_count; i++) {
+		char *connector_name;
+
 		connector = fb_helper->connector_info[i]->connector;
+		connector_name = drm_get_connector_name(connector);
+
+		if (connector_name == NULL)
+			continue;
+		if (disable_connector[0] != '\0' &&
+		    !strcmp(connector_name, disable_connector)) {
+			connector->status = connector_status_disabled;
+			DRM_DEBUG_KMS("connector %d (\"%s\") disabled "
+			    "by module parameter\n", connector->base.id,
+			    connector_name);
+		}
+		if (enable_connector[0] != '\0' &&
+		    !strcmp(connector_name, enable_connector)) {
+			connector->status = connector_status_connected;
+			DRM_DEBUG_KMS("connector %d (\"%s\") enabled "
+			    "by module parameter\n", connector->base.id,
+			    connector_name);
+		}
 		enabled[i] = drm_connector_enabled(connector, true);
-		DRM_DEBUG_KMS("connector %d enabled? %s\n", connector->base.id,
-			  enabled[i] ? "yes" : "no");
+		DRM_DEBUG_KMS("connector %d (\"%s\") enabled? %s\n",
+		    connector->base.id, connector_name,
+		    enabled[i] ? "yes" : "no");
 		any_enabled |= enabled[i];
 	}
 
Index: linux-3.3-rc6/include/drm/drm_crtc.h
===================================================================
--- linux-3.3-rc6.orig/include/drm/drm_crtc.h
+++ linux-3.3-rc6/include/drm/drm_crtc.h
@@ -172,7 +172,8 @@ struct drm_display_mode {
 enum drm_connector_status {
 	connector_status_connected = 1,
 	connector_status_disconnected = 2,
-	connector_status_unknown = 3,
+	connector_status_disabled = 3,
+	connector_status_unknown = 4,
 };
 
 enum subpixel_order {


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 3/3] drivers-gpu-drm-i915-invert-backlight-brightness
  2012-03-10 20:20 [PATCH 0/3] Provide workarounds to use DRM/KMS with broken graphics hardware Carsten Emde
  2012-03-10 20:20 ` [PATCH 1/3] drivers-gpu-drm-allow-to-load-edid-firmware.patch Carsten Emde
  2012-03-10 20:20 ` [PATCH 2/3] drivers-gpu-drm-add-disable-enable-connector.patch Carsten Emde
@ 2012-03-10 20:20 ` Carsten Emde
  2 siblings, 0 replies; 14+ messages in thread
From: Carsten Emde @ 2012-03-10 20:20 UTC (permalink / raw)
  To: David Airlie; +Cc: Thomas Gleixner, Carsten Emde, DRI, LKML

[-- Attachment #1: drivers-gpu-drm-i915-invert-backlight-brightness.patch --]
[-- Type: text/plain, Size: 3406 bytes --]

Following the documentation of the Legacy Backlight Brightness (LBB)
Register in the configuration space of some Intel PCI graphics adapters,
setting the LBB register with the value 0x0 causes the backlight to be
turned off, and 0xFF causes the backlight to be set to 100% intensity
(http://download.intel.com/embedded/processors/Whitepaper/324567.pdf).
At least one of our test systems, however, turns the backlight off at
0xFF and sets it to maximum intensity at 0. In consequence, the screen
of this systems becomes dark at an early boot stage which makes it
unusable. The same inversion applies to the BLC_PWM_CTL I915 register.
This problem was introduced in kernel version 2.6.38 when the PCI device
of this system was first supported by the i915 KMS module.

This patch adds a module parameter to invert the backlight brightness
value before writing and after reading which makes the affected notebook
usable again.

Signed-off-by: Carsten Emde <C.Emde@osadl.org>

---
 Documentation/kernel-parameters.txt |    9 +++++++++
 drivers/gpu/drm/i915/intel_panel.c  |   14 ++++++++++++++
 2 files changed, 23 insertions(+)

Index: linux-3.3-rc6/Documentation/kernel-parameters.txt
===================================================================
--- linux-3.3-rc6.orig/Documentation/kernel-parameters.txt
+++ linux-3.3-rc6/Documentation/kernel-parameters.txt
@@ -975,6 +975,15 @@ bytes respectively. Such letter suffixes
 
 	i810=		[HW,DRM]
 
+	i915.invert_brightness
+			[DRM] Invert the sense of the variable that is used to
+			set the brightness of the panel backlight. Normally a
+			value of 0 indicates backlight switched off, and the
+			maximum value sets the backlight to maximum brightness.
+			If this parameter is specified, a value of 0 sets the
+			backlight to maximum brightness, and the maximum value
+			switches the backlight off.
+
 	i8k.ignore_dmi	[HW] Continue probing hardware even if DMI data
 			indicates that the driver is running on unsupported
 			hardware.
Index: linux-3.3-rc6/drivers/gpu/drm/i915/intel_panel.c
===================================================================
--- linux-3.3-rc6.orig/drivers/gpu/drm/i915/intel_panel.c
+++ linux-3.3-rc6/drivers/gpu/drm/i915/intel_panel.c
@@ -28,6 +28,7 @@
  *      Chris Wilson <chris@chris-wilson.co.uk>
  */
 
+#include <linux/moduleparam.h>
 #include "intel_drv.h"
 
 #define PCI_LBPC 0xf4 /* legacy/combination backlight modes */
@@ -191,6 +192,10 @@ u32 intel_panel_get_max_backlight(struct
 	return max;
 }
 
+static bool brightness_inverted;
+MODULE_PARM_DESC(brightness_inverted, "Backlight brightness value is inverted "
+	"(0 = max brightness, max value = dark)");
+module_param_named(brightness_inverted, brightness_inverted, bool, 0600);
 u32 intel_panel_get_backlight(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -212,6 +217,10 @@ u32 intel_panel_get_backlight(struct drm
 	}
 
 	DRM_DEBUG_DRIVER("get backlight PWM = %d\n", val);
+	if (brightness_inverted) {
+		u32 max = intel_panel_get_max_backlight(dev);
+		val = max - val;
+	}
 	return val;
 }
 
@@ -229,6 +238,11 @@ static void intel_panel_actually_set_bac
 
 	DRM_DEBUG_DRIVER("set backlight PWM = %d\n", level);
 
+	if (brightness_inverted) {
+		u32 max = intel_panel_get_max_backlight(dev);
+		level = max - level;
+	}
+
 	if (HAS_PCH_SPLIT(dev))
 		return intel_pch_panel_set_backlight(dev, level);
 


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 2/3] drivers-gpu-drm-add-disable-enable-connector.patch
  2012-03-10 20:20 ` [PATCH 2/3] drivers-gpu-drm-add-disable-enable-connector.patch Carsten Emde
@ 2012-03-11  7:20     ` Dave Airlie
  0 siblings, 0 replies; 14+ messages in thread
From: Dave Airlie @ 2012-03-11  7:20 UTC (permalink / raw)
  To: Carsten Emde; +Cc: David Airlie, Thomas Gleixner, DRI, LKML

On Sat, Mar 10, 2012 at 8:20 PM, Carsten Emde <C.Emde@osadl.org> wrote:
> Some recent integrated graphics chipset, notably Intel's "Pineview", also
> provide on-chip LVDS support. As an extra service, the LVDS interface supplies
> EDID data - irrespective of whether an LVDS panel is connected or not. The
> drm_mode_getresources() function, therefore, causes Xorg to always include
> the LVDS panel into the display and initialize a separate screen for it. e.g.
> (II) intel(0): Output LVDS1 connected
> (II) intel(0): Output VGA1 connected
> (II) intel(0): Using spanning desktop for initial modes
> (II) intel(0): Output LVDS1 using initial mode 1024x768 +0+0
> (II) intel(0): Output VGA1 using initial mode 1280x1024 +1024+0
> which is not what you want, if the only connected screen is a VGA monitor.
> One would assume that the BIOS settings of such systems would allow to
> separately enable or disable LVDS support; unfortunately, systems have been
> found in the wild that do not provide this feature.

So video=LVDS-1:d doesn't work for you?

Dave.

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 2/3] drivers-gpu-drm-add-disable-enable-connector.patch
@ 2012-03-11  7:20     ` Dave Airlie
  0 siblings, 0 replies; 14+ messages in thread
From: Dave Airlie @ 2012-03-11  7:20 UTC (permalink / raw)
  To: Carsten Emde; +Cc: Thomas Gleixner, LKML, DRI

On Sat, Mar 10, 2012 at 8:20 PM, Carsten Emde <C.Emde@osadl.org> wrote:
> Some recent integrated graphics chipset, notably Intel's "Pineview", also
> provide on-chip LVDS support. As an extra service, the LVDS interface supplies
> EDID data - irrespective of whether an LVDS panel is connected or not. The
> drm_mode_getresources() function, therefore, causes Xorg to always include
> the LVDS panel into the display and initialize a separate screen for it. e.g.
> (II) intel(0): Output LVDS1 connected
> (II) intel(0): Output VGA1 connected
> (II) intel(0): Using spanning desktop for initial modes
> (II) intel(0): Output LVDS1 using initial mode 1024x768 +0+0
> (II) intel(0): Output VGA1 using initial mode 1280x1024 +1024+0
> which is not what you want, if the only connected screen is a VGA monitor.
> One would assume that the BIOS settings of such systems would allow to
> separately enable or disable LVDS support; unfortunately, systems have been
> found in the wild that do not provide this feature.

So video=LVDS-1:d doesn't work for you?

Dave.

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 1/3] drivers-gpu-drm-allow-to-load-edid-firmware.patch
  2012-03-10 20:20 ` [PATCH 1/3] drivers-gpu-drm-allow-to-load-edid-firmware.patch Carsten Emde
@ 2012-03-11 13:44     ` Alan Cox
  2012-03-12 17:14   ` Valdis.Kletnieks
  1 sibling, 0 replies; 14+ messages in thread
From: Alan Cox @ 2012-03-11 13:44 UTC (permalink / raw)
  To: Carsten Emde; +Cc: David Airlie, Thomas Gleixner, DRI, LKML

> This patch allows to load an EDID data set via the firmware interface.
> It contains data sets of frequently used screen resolutions (1024x768,
> 1280x1024, 1680x1050 and 1920x1080). The requested EDID data are
> specified as a module parameter of the drm_kms_helper module, e.g.
> options drm_kms_helper edid_firmware=edid/1280x1024.bin or as kernel
> command line parameter.

What if the DRM layer and driver are compiled in. They'll come up as
console before the file system so the firmware request will hang ?


Given the EDID is tiny and is data not code wouldn't it be simpler (and
smaller) if this option compiled in a few generic EDIDs to use ?

Alan

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 1/3] drivers-gpu-drm-allow-to-load-edid-firmware.patch
@ 2012-03-11 13:44     ` Alan Cox
  0 siblings, 0 replies; 14+ messages in thread
From: Alan Cox @ 2012-03-11 13:44 UTC (permalink / raw)
  To: Carsten Emde; +Cc: Thomas Gleixner, LKML, DRI

> This patch allows to load an EDID data set via the firmware interface.
> It contains data sets of frequently used screen resolutions (1024x768,
> 1280x1024, 1680x1050 and 1920x1080). The requested EDID data are
> specified as a module parameter of the drm_kms_helper module, e.g.
> options drm_kms_helper edid_firmware=edid/1280x1024.bin or as kernel
> command line parameter.

What if the DRM layer and driver are compiled in. They'll come up as
console before the file system so the firmware request will hang ?


Given the EDID is tiny and is data not code wouldn't it be simpler (and
smaller) if this option compiled in a few generic EDIDs to use ?

Alan

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 2/3] drivers-gpu-drm-add-disable-enable-connector.patch
  2012-03-11  7:20     ` Dave Airlie
  (?)
@ 2012-03-11 20:46     ` Carsten Emde
  -1 siblings, 0 replies; 14+ messages in thread
From: Carsten Emde @ 2012-03-11 20:46 UTC (permalink / raw)
  To: Dave Airlie; +Cc: David Airlie, Thomas Gleixner, DRI, LKML

On 03/11/2012 08:20 AM, Dave Airlie wrote:
> On Sat, Mar 10, 2012 at 8:20 PM, Carsten Emde<C.Emde@osadl.org>  wrote:
>> Some recent integrated graphics chipset, notably Intel's "Pineview", also
>> provide on-chip LVDS support. As an extra service, the LVDS interface supplies
>> EDID data - irrespective of whether an LVDS panel is connected or not. The
>> drm_mode_getresources() function, therefore, causes Xorg to always include
>> the LVDS panel into the display and initialize a separate screen for it. e.g.
>> (II) intel(0): Output LVDS1 connected
>> (II) intel(0): Output VGA1 connected
>> (II) intel(0): Using spanning desktop for initial modes
>> (II) intel(0): Output LVDS1 using initial mode 1024x768 +0+0
>> (II) intel(0): Output VGA1 using initial mode 1280x1024 +1024+0
>> which is not what you want, if the only connected screen is a VGA monitor.
>> One would assume that the BIOS settings of such systems would allow to
>> separately enable or disable LVDS support; unfortunately, systems have been
>> found in the wild that do not provide this feature.
>
> So video=LVDS-1:d doesn't work for you?
Oops, yes, you are totally right. By some reason, I overlooked this 
option. I tried two systems that need forced disabling and enabling with
   video=LVDS-1:d video=VGA-1:e
which worked perfectly well.

So please skip this patch, sorry for the noise.

Thanks,
	-Carsten.

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 1/3] drivers-gpu-drm-allow-to-load-edid-firmware.patch
  2012-03-11 13:44     ` Alan Cox
  (?)
@ 2012-03-11 21:23     ` Carsten Emde
  2012-04-25  2:30       ` Michael Witten
  -1 siblings, 1 reply; 14+ messages in thread
From: Carsten Emde @ 2012-03-11 21:23 UTC (permalink / raw)
  To: Alan Cox; +Cc: David Airlie, Thomas Gleixner, DRI, LKML

On 03/11/2012 02:44 PM, Alan Cox wrote:
>> This patch allows to load an EDID data set via the firmware interface.
>> It contains data sets of frequently used screen resolutions (1024x768,
>> 1280x1024, 1680x1050 and 1920x1080). The requested EDID data are
>> specified as a module parameter of the drm_kms_helper module, e.g.
>> options drm_kms_helper edid_firmware=edid/1280x1024.bin or as kernel
>> command line parameter.
>
> What if the DRM layer and driver are compiled in. They'll come up as
> console before the file system so the firmware request will hang ?
Admittedly I did not try to compile the DRM layer and driver into the 
kernel. However, I created an error condition by specifying a 
non-existing EDID file. In this case, the function returns with error, 
the mode count remains 0, and the system continues to run as if the 
edid_firmware= parameter had not been specified.

Now that you were asking, I created a static kernel and did some more 
tests, but I couldn't find any problem. Everything worked as expected. I 
believe that the early console still runs in BIOS VGA mode, i.e. either 
using the BIOS default mode or the one that was specified using the vga= 
parameter, if any. DRM apparently comes into play at a later stage only, 
but I will do some more testing.

> Given the EDID is tiny and is data not code wouldn't it be simpler (and
> smaller) if this option compiled in a few generic EDIDs to use ?
Yes, this certainly would be possible. However, we would loose the 
flexibility to specify an individual EDID data set without recompiling 
the kernel. As an alternative, we could compile the four standard EDIDs 
into the DRM helper instead of providing them as a file, but still leave 
the option to load an individual EDID via the firmware interface. This 
would make the patch much smaller and avoid spamming the firmware 
directory. How about that?

Thanks,
	-Carsten.

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 1/3] drivers-gpu-drm-allow-to-load-edid-firmware.patch
  2012-03-11 13:44     ` Alan Cox
  (?)
  (?)
@ 2012-03-11 23:59     ` Carsten Emde
  -1 siblings, 0 replies; 14+ messages in thread
From: Carsten Emde @ 2012-03-11 23:59 UTC (permalink / raw)
  To: Alan Cox; +Cc: David Airlie, Thomas Gleixner, DRI, LKML

[-- Attachment #1: Type: text/plain, Size: 885 bytes --]

Alan,

>> This patch allows to load an EDID data set via the firmware interface.
>> It contains data sets of frequently used screen resolutions (1024x768,
>> 1280x1024, 1680x1050 and 1920x1080). The requested EDID data are
>> specified as a module parameter of the drm_kms_helper module, e.g.
>> options drm_kms_helper edid_firmware=edid/1280x1024.bin or as kernel
>> command line parameter.
> [..]
> Given the EDID is tiny and is data not code wouldn't it be simpler (and
> smaller) if this option compiled in a few generic EDIDs to use ?
I liked the idea so much that I gave it a try. The patch looks much 
better now, but has the same functionality as before. As the only 
disadvantage, the patch no longer contains the template to produce a 
particular EDID. But this code may be made available elsewhere - no need 
to have it in the kernel.

Hope you like it.

Thanks,
	-Carsten.

[-- Attachment #2: drivers-gpu-drm-allow-to-load-edid-firmware.patch --]
[-- Type: text/x-patch, Size: 15365 bytes --]

Broken monitors and/or broken graphic boards may send erroneous or no
EDID data. This also applies to broken KVM devices that are unable to
correctly forward the EDID data of the connected monitor but invent
their own fantasy data.

This patch allows to specify an EDID data set to be used instead of
probing the monitor for it. It contains built-in data sets of frequently
used screen resolutions. In addition, a particular EDID data set may be
provided in the /lib/firmware directory and loaded via the firmware
interface. The name is passed to the kernel as module parameter of the
drm_kms_helper module either when loaded
  options drm_kms_helper edid_firmware=edid/1280x1024.bin
or as kernel commandline parameter
  drm_kms_helper.edid_firmware=edid/1280x1024.bin  

The built-in data sets are
Resolution    Name
--------------------------------
1024x768      edid/1024x768.bin
1280x1024     edid/1280x1024.bin
1680x1050     edid/1680x1050.bin
1920x1080     edid/1920x1080.bin

They are ignored, if a file with the same name is available in the
/lib/firmware directory.

The built-in EDID data sets are based on standard timings that may not
apply to a particular monitor and even crash it. Ideally, EDID data of
the connected monitor should be used. They may be obtained through the 
drm/cardX/cardX-<connector>/edid entry in the /sys/devices PCI directory
of a correctly working graphics adapter.

It is also possible to specify the name of an EDID data set on-the-fly
via the /sys/module interface, e.g.
echo edid/myedid.bin >/sys/module/drm_kms_helper/parameters/edid_firmware
The new screen mode is considered when the related kernel function is
called for the first time after the change. Such calls are made when the
X server is started or when the display settings dialog is opened in an
already running X server.

Signed-off-by: Carsten Emde <C.Emde@osadl.org>

---
 Documentation/kernel-parameters.txt |   10 +
 drivers/gpu/drm/Kconfig             |   11 +
 drivers/gpu/drm/Makefile            |    3 
 drivers/gpu/drm/drm_crtc_helper.c   |    8 +
 drivers/gpu/drm/drm_edid.c          |    4 
 drivers/gpu/drm/drm_edid_load.c     |  241 ++++++++++++++++++++++++++++++++++++
 include/drm/drm_crtc.h              |    1 
 include/drm/drm_edid.h              |    1 
 8 files changed, 276 insertions(+), 3 deletions(-)

Index: linux-3.3-rc6/Documentation/kernel-parameters.txt
===================================================================
--- linux-3.3-rc6.orig/Documentation/kernel-parameters.txt
+++ linux-3.3-rc6/Documentation/kernel-parameters.txt
@@ -713,6 +713,16 @@ bytes respectively. Such letter suffixes
 			The filter can be disabled or changed to another
 			driver later using sysfs.
 
+	drm_kms_helper.edid_firmware=<file>
+			Broken monitors, graphic adapters and KVMs may
+			send no or broken EDID data sets. This parameter
+			allows to specify an EDID data set in the
+			/lib/firmware directory that is used instead.
+			Generic built-in EDID data sets are used, if one of
+			edid/1024x768.bin, edid/1280x1024.bin,
+			edid/1680x1050.bin, or edid/1920x1080.bin is given
+			and no file with the same name exists.
+
 	dscc4.setup=	[NET]
 
 	earlycon=	[KNL] Output early console device and options.
Index: linux-3.3-rc6/drivers/gpu/drm/Kconfig
===================================================================
--- linux-3.3-rc6.orig/drivers/gpu/drm/Kconfig
+++ linux-3.3-rc6/drivers/gpu/drm/Kconfig
@@ -27,6 +27,17 @@ config DRM_KMS_HELPER
 	help
 	  FB and CRTC helpers for KMS drivers.
 
+config DRM_LOAD_EDID_FIRMWARE
+	bool "Allow to specify an EDID data set instead of probing for it"
+	depends on DRM_KMS_HELPER
+	help
+	  Say Y here, if you want to use EDID data to be loaded from the
+	  /lib/firmware directory or one of the provided built-in
+	  data sets. This may be necessary, if the graphics adapter or
+	  monitor are unable to provide appropriate EDID data. Since this
+	  feature is provided as a workaround for broken hardware, the
+	  default case is N.
+
 config DRM_TTM
 	tristate
 	depends on DRM
Index: linux-3.3-rc6/drivers/gpu/drm/Makefile
===================================================================
--- linux-3.3-rc6.orig/drivers/gpu/drm/Makefile
+++ linux-3.3-rc6/drivers/gpu/drm/Makefile
@@ -17,6 +17,9 @@ drm-y       :=	drm_auth.o drm_buffer.o d
 drm-$(CONFIG_COMPAT) += drm_ioc32.o
 
 drm_kms_helper-y := drm_fb_helper.o drm_crtc_helper.o drm_dp_i2c_helper.o
+ifdef CONFIG_DRM_LOAD_EDID_FIRMWARE
+drm_kms_helper-y += drm_edid_load.o
+endif
 
 obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o
 
Index: linux-3.3-rc6/drivers/gpu/drm/drm_crtc_helper.c
===================================================================
--- linux-3.3-rc6.orig/drivers/gpu/drm/drm_crtc_helper.c
+++ linux-3.3-rc6/drivers/gpu/drm/drm_crtc_helper.c
@@ -37,6 +37,7 @@
 #include "drm_fourcc.h"
 #include "drm_crtc_helper.h"
 #include "drm_fb_helper.h"
+#include "drm_edid.h"
 
 static bool drm_kms_helper_poll = true;
 module_param_named(poll, drm_kms_helper_poll, bool, 0600);
@@ -118,7 +119,12 @@ int drm_helper_probe_single_connector_mo
 		goto prune;
 	}
 
-	count = (*connector_funcs->get_modes)(connector);
+#ifdef CONFIG_DRM_LOAD_EDID_FIRMWARE
+	count = load_edid_firmware(connector);
+	if (count == 0)
+#endif
+		count = (*connector_funcs->get_modes)(connector);
+
 	if (count == 0 && connector->status == connector_status_connected)
 		count = drm_add_modes_noedid(connector, 1024, 768);
 	if (count == 0)
Index: linux-3.3-rc6/drivers/gpu/drm/drm_edid.c
===================================================================
--- linux-3.3-rc6.orig/drivers/gpu/drm/drm_edid.c
+++ linux-3.3-rc6/drivers/gpu/drm/drm_edid.c
@@ -149,8 +149,7 @@ EXPORT_SYMBOL(drm_edid_header_is_valid);
  * Sanity check the EDID block (base or extension).  Return 0 if the block
  * doesn't check out, or 1 if it's valid.
  */
-static bool
-drm_edid_block_valid(u8 *raw_edid)
+bool drm_edid_block_valid(u8 *raw_edid)
 {
 	int i;
 	u8 csum = 0;
@@ -203,6 +202,7 @@ bad:
 	}
 	return 0;
 }
+EXPORT_SYMBOL(drm_edid_block_valid);
 
 /**
  * drm_edid_is_valid - sanity check EDID data
Index: linux-3.3-rc6/drivers/gpu/drm/drm_edid_load.c
===================================================================
--- /dev/null
+++ linux-3.3-rc6/drivers/gpu/drm/drm_edid_load.c
@@ -0,0 +1,241 @@
+/*
+   drm_edid_load.c: use a built-in EDID data set or load it via the firmware
+		    interface
+
+   Copyright (C) 2012 Carsten Emde <C.Emde@osadl.org>
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License
+   as published by the Free Software Foundation; either version 2
+   of the License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
+*/
+
+#include <linux/module.h>
+#include <linux/firmware.h>
+#include "drmP.h"
+#include "drm_crtc.h"
+#include "drm_crtc_helper.h"
+#include "drm_edid.h"
+
+static char edid_firmware[PATH_MAX];
+module_param_string(edid_firmware, edid_firmware, sizeof(edid_firmware), 0644);
+MODULE_PARM_DESC(edid_firmware, "Do not probe monitor, use specified EDID blob "
+	"from built-in data or /lib/firmware instead. ");
+
+#define GENERIC_EDIDS 4
+static char *generic_edid_name[GENERIC_EDIDS] = {
+	"edid/1024x768.bin",
+	"edid/1280x1024.bin",
+	"edid/1680x1050.bin",
+	"edid/1920x1080.bin",
+};
+
+static u8 generic_edid[GENERIC_EDIDS][128] = {
+	{
+	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x05, 0x16, 0x01, 0x03, 0x6d, 0x23, 0x1a, 0x78,
+	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
+	0x20, 0x50, 0x54, 0x00, 0x08, 0x00, 0x61, 0x40,
+	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x64, 0x19,
+	0x00, 0x40, 0x41, 0x00, 0x26, 0x30, 0x08, 0x90,
+	0x36, 0x00, 0x63, 0x0a, 0x11, 0x00, 0x00, 0x18,
+	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
+	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
+	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
+	0x3d, 0x2f, 0x31, 0x07, 0x00, 0x0a, 0x20, 0x20,
+	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
+	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x58,
+	0x47, 0x41, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x55,
+	},
+	{
+	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x05, 0x16, 0x01, 0x03, 0x6d, 0x2c, 0x23, 0x78,
+	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
+	0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0x81, 0x80,
+	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x30, 0x2a,
+	0x00, 0x98, 0x51, 0x00, 0x2a, 0x40, 0x30, 0x70,
+	0x13, 0x00, 0xbc, 0x63, 0x11, 0x00, 0x00, 0x1e,
+	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
+	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
+	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
+	0x3d, 0x3e, 0x40, 0x0b, 0x00, 0x0a, 0x20, 0x20,
+	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
+	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x53,
+	0x58, 0x47, 0x41, 0x0a, 0x20, 0x20, 0x00, 0xa0,
+	},
+	{
+	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x05, 0x16, 0x01, 0x03, 0x6d, 0x2b, 0x1b, 0x78,
+	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
+	0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0xb3, 0x00,
+	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x21, 0x39,
+	0x90, 0x30, 0x62, 0x1a, 0x27, 0x40, 0x68, 0xb0,
+	0x36, 0x00, 0xb5, 0x11, 0x11, 0x00, 0x00, 0x1e,
+	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
+	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
+	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
+	0x3d, 0x40, 0x42, 0x0f, 0x00, 0x0a, 0x20, 0x20,
+	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
+	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x57,
+	0x53, 0x58, 0x47, 0x41, 0x0a, 0x20, 0x00, 0x26,
+	},
+	{
+	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x05, 0x16, 0x01, 0x03, 0x6d, 0x32, 0x1c, 0x78,
+	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
+	0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0xd1, 0xc0,
+	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3a,
+	0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
+	0x45, 0x00, 0xf4, 0x19, 0x11, 0x00, 0x00, 0x1e,
+	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
+	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
+	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
+	0x3d, 0x42, 0x44, 0x0f, 0x00, 0x0a, 0x20, 0x20,
+	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
+	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x46,
+	0x48, 0x44, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x05,
+	},
+};
+
+static int edid_load(struct drm_connector *connector, char *name,
+		     char *connector_name)
+{
+	const struct firmware *fw;
+	struct platform_device *pdev;
+	u8 *fwdata = NULL, *edid;
+	int fwsize, expected;
+	int builtin = 0, err = 0;
+	int i, valid_extensions = 0;
+
+	pdev = platform_device_register_simple(connector_name, -1, NULL, 0);
+	if (IS_ERR(pdev)) {
+		DRM_ERROR("Failed to register EDID firmware platform device "
+		    "for connector \"%s\"\n", connector_name);
+		err = -EINVAL;
+		goto out;
+	}
+
+	err = request_firmware(&fw, name, &pdev->dev);
+	platform_device_unregister(pdev);
+
+	if (err) {
+		i = 0;
+		while (i < GENERIC_EDIDS && strcmp(name, generic_edid_name[i]))
+			i++;
+		if (i < GENERIC_EDIDS) {
+			err = 0;
+			builtin = 1;
+			fwdata = generic_edid[i];
+			fwsize = sizeof(generic_edid[i]);
+		}
+	}
+
+	if (err) {
+		DRM_ERROR("Requesting EDID firmware \"%s\" failed (err=%d)\n",
+		    name, err);
+		goto out;
+	}
+
+	if (fwdata == NULL) {
+		fwdata = (u8 *) fw->data;
+		fwsize = fw->size;
+	}
+
+	expected = (fwdata[0x7e] + 1) * EDID_LENGTH;
+	if (expected != fwsize) {
+		DRM_ERROR("Size of EDID firmware \"%s\" is invalid "
+		    "(expected %d, got %d)\n", name, expected, (int) fwsize);
+		err = -EINVAL;
+		goto relfw_out;
+	}
+
+	edid = kmalloc(fwsize, GFP_KERNEL);
+	if (edid == NULL) {
+		err = -ENOMEM;
+		goto relfw_out;
+	}
+	memcpy(edid, fwdata, fwsize);
+
+	if (!drm_edid_block_valid(edid)) {
+		DRM_ERROR("Base block of EDID firmware \"%s\" is invalid ",
+		    name);
+		kfree(edid);
+		err = -EINVAL;
+		goto relfw_out;
+	}
+
+	for (i = 1; i <= edid[0x7e]; i++) {
+		if (i != valid_extensions + 1)
+			memcpy(edid + (valid_extensions + 1) * EDID_LENGTH,
+			    edid + i * EDID_LENGTH, EDID_LENGTH);
+		if (drm_edid_block_valid(edid + i * EDID_LENGTH))
+			valid_extensions++;
+	}
+
+	if (valid_extensions != edid[0x7e]) {
+		edid[EDID_LENGTH-1] += edid[0x7e] - valid_extensions;
+		DRM_INFO("Found %d valid extensions instead of %d in EDID data "
+		    "\"%s\" for connector \"%s\"\n", valid_extensions,
+		    edid[0x7e], name, connector_name);
+		edid[0x7e] = valid_extensions;
+		edid = krealloc(edid, (valid_extensions + 1) * EDID_LENGTH,
+		    GFP_KERNEL);
+		if (edid == NULL) {
+			err = -ENOMEM;
+			goto relfw_out;
+		}
+	}
+
+	connector->display_info.raw_edid = edid;
+	DRM_INFO("Got %s EDID base block and %d extension%s from "
+	    "\"%s\" for connector \"%s\"\n", builtin ? "built-in" :
+	    "external", valid_extensions, valid_extensions == 1 ? "" : "s",
+	    name, connector_name);
+
+relfw_out:
+	release_firmware(fw);
+
+out:
+	return err;
+}
+
+int load_edid_firmware(struct drm_connector *connector)
+{
+	char *connector_name = drm_get_connector_name(connector);
+	char *last;
+	int ret = 0;
+
+	if (edid_firmware[0] == '\0')
+		return ret;
+
+	last = edid_firmware + strlen(edid_firmware) - 1;
+	if (*last == '\n')
+		*last = '\0';
+
+	ret = edid_load(connector, edid_firmware, connector_name);
+	if (ret)
+		return 0;
+
+	drm_mode_connector_update_edid_property(connector,
+	    (struct edid *) connector->display_info.raw_edid);
+
+	return drm_add_edid_modes(connector, (struct edid *)
+	    connector->display_info.raw_edid);
+}
Index: linux-3.3-rc6/include/drm/drm_crtc.h
===================================================================
--- linux-3.3-rc6.orig/include/drm/drm_crtc.h
+++ linux-3.3-rc6/include/drm/drm_crtc.h
@@ -995,6 +995,7 @@ extern int drm_add_modes_noedid(struct d
 				int hdisplay, int vdisplay);
 
 extern int drm_edid_header_is_valid(const u8 *raw_edid);
+extern bool drm_edid_block_valid(u8 *raw_edid);
 extern bool drm_edid_is_valid(struct edid *edid);
 struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev,
 					   int hsize, int vsize, int fresh);
Index: linux-3.3-rc6/include/drm/drm_edid.h
===================================================================
--- linux-3.3-rc6.orig/include/drm/drm_edid.h
+++ linux-3.3-rc6/include/drm/drm_edid.h
@@ -238,5 +238,6 @@ int drm_av_sync_delay(struct drm_connect
 		      struct drm_display_mode *mode);
 struct drm_connector *drm_select_eld(struct drm_encoder *encoder,
 				     struct drm_display_mode *mode);
+int load_edid_firmware(struct drm_connector *connector);
 
 #endif /* __DRM_EDID_H__ */

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 1/3] drivers-gpu-drm-allow-to-load-edid-firmware.patch
  2012-03-10 20:20 ` [PATCH 1/3] drivers-gpu-drm-allow-to-load-edid-firmware.patch Carsten Emde
  2012-03-11 13:44     ` Alan Cox
@ 2012-03-12 17:14   ` Valdis.Kletnieks
  1 sibling, 0 replies; 14+ messages in thread
From: Valdis.Kletnieks @ 2012-03-12 17:14 UTC (permalink / raw)
  To: Carsten Emde; +Cc: David Airlie, Thomas Gleixner, DRI, LKML

[-- Attachment #1: Type: text/plain, Size: 719 bytes --]

On Sat, 10 Mar 2012 21:20:15 +0100, Carsten Emde said:

> EDID data source files are provided for documentation purpose and as a
> template to create EDID data sets for other screen resolutions. Note
> that source compilation is not part of the build process, but needs to
> be done manually, e.g.
>
> #!/bin/bash
> cd firmware/edid
> for i in [1-9]*.S
> do

Would it be possible to include a version of this patch's Changelog as a file
under Documentation/fixing-broken-edid.txt or something, so people don't have
to go and find the git commit log to know things like "you need to run
dos2unix"?  Be a shame to have a changelog that does such a good job of
documenting what you need to do, and have it lost in git...


[-- Attachment #2: Type: application/pgp-signature, Size: 865 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 1/3] drivers-gpu-drm-allow-to-load-edid-firmware.patch
  2012-03-11 21:23     ` Carsten Emde
@ 2012-04-25  2:30       ` Michael Witten
  2012-04-25 22:46         ` Carsten Emde
  0 siblings, 1 reply; 14+ messages in thread
From: Michael Witten @ 2012-04-25  2:30 UTC (permalink / raw)
  To: Carsten Emde; +Cc: Alan Cox, David Airlie, Thomas Gleixner, DRI, LKML

On Sun, 11 Mar 2012 22:23:22 +0100, Carsten Emde wrote:

> On 03/11/2012 02:44 PM, Alan Cox wrote:
>
>>> This patch allows to load an EDID data set via the firmware interface.
>>> It contains data sets of frequently used screen resolutions (1024x768,
>>> 1280x1024, 1680x1050 and 1920x1080). The requested EDID data are
>>> specified as a module parameter of the drm_kms_helper module, e.g.
>>> options drm_kms_helper edid_firmware=edid/1280x1024.bin or as kernel
>>> command line parameter.
>>
>> What if the DRM layer and driver are compiled in. They'll come up as
>> console before the file system so the firmware request will hang ?
>
> Admittedly I did not try to compile the DRM layer and driver into the 
> kernel. However, I created an error condition by specifying a 
> non-existing EDID file. In this case, the function returns with error, 
> the mode count remains 0, and the system continues to run as if the 
> edid_firmware= parameter had not been specified.

Unfortunately, as of at least last month, my system hangs when I try to
use your feature (just as described by Alan Cox); the log shows that
during the boot process, there is a one-minute hang:

  [    0.175207] [drm] radeon: power management initialized
  [   60.896507] [drm:edid_load] *ERROR* Requesting EDID firmware "edid/1920x1200.bin" failed (err=-2)

Is there any way to make your feature smarter about its timing with
relation to file system accessibility?

Sincerely,
Michael Witten

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 1/3] drivers-gpu-drm-allow-to-load-edid-firmware.patch
  2012-04-25  2:30       ` Michael Witten
@ 2012-04-25 22:46         ` Carsten Emde
  0 siblings, 0 replies; 14+ messages in thread
From: Carsten Emde @ 2012-04-25 22:46 UTC (permalink / raw)
  To: Michael Witten; +Cc: Alan Cox, David Airlie, Thomas Gleixner, DRI, LKML

Michael,

> On Sun, 11 Mar 2012 22:23:22 +0100, Carsten Emde wrote:
>> On 03/11/2012 02:44 PM, Alan Cox wrote:
>>>> This patch allows to load an EDID data set via the firmware interface.
>>>> It contains data sets of frequently used screen resolutions (1024x768,
>>>> 1280x1024, 1680x1050 and 1920x1080). The requested EDID data are
>>>> specified as a module parameter of the drm_kms_helper module, e.g.
>>>> options drm_kms_helper edid_firmware=edid/1280x1024.bin or as kernel
>>>> command line parameter.
>>> What if the DRM layer and driver are compiled in. They'll come up as
>>> console before the file system so the firmware request will hang ?
>> Admittedly I did not try to compile the DRM layer and driver into the
>> kernel. However, I created an error condition by specifying a
>> non-existing EDID file. In this case, the function returns with error,
>> the mode count remains 0, and the system continues to run as if the
>> edid_firmware= parameter had not been specified.
> Unfortunately, as of at least last month, my system hangs when I try to
> use your feature (just as described by Alan Cox); the log shows that
> during the boot process, there is a one-minute hang:
>
>    [    0.175207] [drm] radeon: power management initialized
>    [   60.896507] [drm:edid_load] *ERROR* Requesting EDID firmware "edid/1920x1200.bin" failed (err=-2)
>
> Is there any way to make your feature smarter about its timing with
> relation to file system accessibility?
Sure.

Please copy your EDID data file to the directory "firmware/edid" of the 
kernel source tree, configure

CONFIG_EXTRA_FIRMWARE="edid/1920x1200.bin"
CONFIG_EXTRA_FIRMWARE_DIR="firmware"

and rebuild/reboot your kernel.

Does it work then?

	-Carsten.

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2012-04-25 23:11 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-03-10 20:20 [PATCH 0/3] Provide workarounds to use DRM/KMS with broken graphics hardware Carsten Emde
2012-03-10 20:20 ` [PATCH 1/3] drivers-gpu-drm-allow-to-load-edid-firmware.patch Carsten Emde
2012-03-11 13:44   ` Alan Cox
2012-03-11 13:44     ` Alan Cox
2012-03-11 21:23     ` Carsten Emde
2012-04-25  2:30       ` Michael Witten
2012-04-25 22:46         ` Carsten Emde
2012-03-11 23:59     ` Carsten Emde
2012-03-12 17:14   ` Valdis.Kletnieks
2012-03-10 20:20 ` [PATCH 2/3] drivers-gpu-drm-add-disable-enable-connector.patch Carsten Emde
2012-03-11  7:20   ` Dave Airlie
2012-03-11  7:20     ` Dave Airlie
2012-03-11 20:46     ` Carsten Emde
2012-03-10 20:20 ` [PATCH 3/3] drivers-gpu-drm-i915-invert-backlight-brightness Carsten Emde

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.