diff mbox

quirk for Samsung 2443BW

Message ID 20120714214231.GC3451@radix50.net (mailing list archive)
State New, archived
Headers show

Commit Message

Baurzhan Ismagulov July 14, 2012, 9:42 p.m. UTC
Hello David,

Samsung 2443BW is 1920x1200 but reports 1920x1080 in the EDID. Attached
is a proof-of-concept implementation of a quirk. It works on my i686 PC.

The patch is against the latest linux-2.6. An attempt to clone
git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6.git (as
listed in MAINTAINERS) resulted in "fatal: The remote end hung up
unexpectedly".

This implementation matches the wrong mode by size. Other approaches are
possible.

I'd appreciate feedback.

With kind regards,
Baurzhan.

Comments

Maarten Lankhorst July 16, 2012, 9:13 a.m. UTC | #1
Hey,

Op 14-07-12 23:42, Baurzhan Ismagulov schreef:
> Hello David,
>
> Samsung 2443BW is 1920x1200 but reports 1920x1080 in the EDID. Attached
> is a proof-of-concept implementation of a quirk. It works on my i686 PC.
>
> The patch is against the latest linux-2.6. An attempt to clone
> git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6.git (as
> listed in MAINTAINERS) resulted in "fatal: The remote end hung up
> unexpectedly".
>
I actually own a 2443BW and don't have the problem you're referring to?

~Maarten
Baurzhan Ismagulov July 16, 2012, 9:49 a.m. UTC | #2
On Mon, Jul 16, 2012 at 11:13:09AM +0200, Maarten Lankhorst wrote:
> > Samsung 2443BW is 1920x1200 but reports 1920x1080 in the EDID. Attached
> > is a proof-of-concept implementation of a quirk. It works on my i686 PC.
> >
> > The patch is against the latest linux-2.6. An attempt to clone
> > git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6.git (as
> > listed in MAINTAINERS) resulted in "fatal: The remote end hung up
> > unexpectedly".
> >
> I actually own a 2443BW and don't have the problem you're referring to?

Samsung might have fixed the data. If you care to send me your EDID
data, I can compare it with mine. Still, there are many users who have
broken monitors; it would be nice to provide a fix for them.

With kind regards,
Baurzhan.
Dave Airlie July 20, 2012, 2:34 a.m. UTC | #3
On Sun, Jul 15, 2012 at 7:42 AM, Baurzhan Ismagulov <ibr@radix50.net> wrote:
> Hello David,
>
> Samsung 2443BW is 1920x1200 but reports 1920x1080 in the EDID. Attached
> is a proof-of-concept implementation of a quirk. It works on my i686 PC.
>
> The patch is against the latest linux-2.6. An attempt to clone
> git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6.git (as
> listed in MAINTAINERS) resulted in "fatal: The remote end hung up
> unexpectedly".
>
> This implementation matches the wrong mode by size. Other approaches are
> possible.
>
> I'd appreciate feedback.

ajax, seem sane?

Dave.
diff mbox

Patch

From ea4ca18f607c3829239ad602b0cb8d319fbcd75e Mon Sep 17 00:00:00 2001
From: Baurzhan Ismagulov <ibr@radix50.net>
Date: Sat, 14 Jul 2012 22:23:33 +0200
Subject: [PATCH 2/2] drm: Add quirk for Samsung SyncMaster 2443BW

Signed-off-by: Baurzhan Ismagulov <ibr@radix50.net>
---
 drivers/gpu/drm/drm_edid.c |   64 ++++++++++++++++++++++++++++++-------------
 1 files changed, 44 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 09ff2bb..73dda54 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -68,12 +68,14 @@ 
 #define EDID_QUIRK_DETAILED_SYNC_PP		(1 << 6)
 /* Force reduced-blanking timings for detailed modes */
 #define EDID_QUIRK_FORCE_REDUCED_BLANKING	(1 << 7)
+/* Force size */
+#define EDID_QUIRK_FORCE_SIZE			(1 << 8)
 
 struct detailed_mode_closure {
 	struct drm_connector *connector;
 	struct edid *edid;
 	bool preferred;
-	u32 quirks;
+	const struct edid_quirk *quirk;
 	int modes;
 };
 
@@ -82,10 +84,23 @@  struct detailed_mode_closure {
 #define LEVEL_GTF2	2
 #define LEVEL_CVT	3
 
+struct size {
+	int x;
+	int y;
+};
+
+struct force_size {
+	struct size bad;
+	struct size good;
+};
+
 static struct edid_quirk {
 	char vendor[4];
 	int product_id;
 	u32 quirks;
+	union {
+		struct force_size size;
+	} u;
 } const edid_quirk_list[] = {
 	/* Acer AL1706 */
 	{ "ACR", 44358, EDID_QUIRK_PREFER_LARGE_60 },
@@ -122,6 +137,9 @@  static struct edid_quirk {
 	/* Samsung SyncMaster 22[5-6]BW */
 	{ "SAM", 596, EDID_QUIRK_PREFER_LARGE_60 },
 	{ "SAM", 638, EDID_QUIRK_PREFER_LARGE_60 },
+	/* Samsung SyncMaster 2443BW */
+	{ "SAM", 0x06b0, EDID_QUIRK_FORCE_SIZE,
+	  .u.size = { { 1920, 1080 }, { 1920, 1200 } } },
 
 	/* ViewSonic VA2026w */
 	{ "VSC", 5020, EDID_QUIRK_FORCE_REDUCED_BLANKING },
@@ -428,12 +446,12 @@  static bool edid_vendor(struct edid *edid, const char *vendor)
 }
 
 /**
- * edid_get_quirks - return quirk flags for a given EDID
+ * edid_get_quirk - return quirk data for a given EDID
  * @edid: EDID to process
  *
  * This tells subsequent routines what fixes they need to apply.
  */
-static u32 edid_get_quirks(struct edid *edid)
+static const struct edid_quirk *edid_get_quirk(struct edid *edid)
 {
 	const struct edid_quirk *quirk;
 	int i;
@@ -443,10 +461,10 @@  static u32 edid_get_quirks(struct edid *edid)
 
 		if (edid_vendor(edid, quirk->vendor) &&
 		    (EDID_PRODUCT_ID(edid) == quirk->product_id))
-			return quirk->quirks;
+			return quirk;
 	}
 
-	return 0;
+	return NULL;
 }
 
 #define MODE_SIZE(m) ((m)->hdisplay * (m)->vdisplay)
@@ -866,7 +884,7 @@  drm_mode_do_interlace_quirk(struct drm_display_mode *mode,
 static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev,
 						  struct edid *edid,
 						  struct detailed_timing *timing,
-						  u32 quirks)
+						  const struct edid_quirk *quirk)
 {
 	struct drm_display_mode *mode;
 	struct detailed_pixel_timing *pt = &timing->data.pixel_data;
@@ -898,7 +916,7 @@  static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev,
 		return NULL;
 	}
 
-	if (quirks & EDID_QUIRK_FORCE_REDUCED_BLANKING) {
+	if (quirk && quirk->quirks & EDID_QUIRK_FORCE_REDUCED_BLANKING) {
 		mode = drm_cvt_mode(dev, hactive, vactive, 60, true, false, false);
 		if (!mode)
 			return NULL;
@@ -906,11 +924,17 @@  static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev,
 		goto set_size;
 	}
 
+	if (quirk && quirk->quirks & EDID_QUIRK_FORCE_SIZE &&
+	    hactive == quirk->u.size.bad.x && vactive == quirk->u.size.bad.y) {
+		hactive = quirk->u.size.good.x;
+		vactive = quirk->u.size.good.y;
+	}
+
 	mode = drm_mode_create(dev);
 	if (!mode)
 		return NULL;
 
-	if (quirks & EDID_QUIRK_135_CLOCK_TOO_HIGH)
+	if (quirk && quirk->quirks & EDID_QUIRK_135_CLOCK_TOO_HIGH)
 		timing->pixel_clock = cpu_to_le16(1088);
 
 	mode->clock = le16_to_cpu(timing->pixel_clock) * 10;
@@ -933,9 +957,8 @@  static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev,
 
 	drm_mode_do_interlace_quirk(mode, pt);
 
-	if (quirks & EDID_QUIRK_DETAILED_SYNC_PP) {
+	if (quirk && quirk->quirks & EDID_QUIRK_DETAILED_SYNC_PP)
 		pt->misc |= DRM_EDID_PT_HSYNC_POSITIVE | DRM_EDID_PT_VSYNC_POSITIVE;
-	}
 
 	mode->flags |= (pt->misc & DRM_EDID_PT_HSYNC_POSITIVE) ?
 		DRM_MODE_FLAG_PHSYNC : DRM_MODE_FLAG_NHSYNC;
@@ -946,12 +969,12 @@  set_size:
 	mode->width_mm = pt->width_mm_lo | (pt->width_height_mm_hi & 0xf0) << 4;
 	mode->height_mm = pt->height_mm_lo | (pt->width_height_mm_hi & 0xf) << 8;
 
-	if (quirks & EDID_QUIRK_DETAILED_IN_CM) {
+	if (quirk && quirk->quirks & EDID_QUIRK_DETAILED_IN_CM) {
 		mode->width_mm *= 10;
 		mode->height_mm *= 10;
 	}
 
-	if (quirks & EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE) {
+	if (quirk && quirk->quirks & EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE) {
 		mode->width_mm = edid->width_cm * 10;
 		mode->height_mm = edid->height_cm * 10;
 	}
@@ -1421,7 +1444,7 @@  do_detailed_mode(struct detailed_timing *timing, void *c)
 	if (timing->pixel_clock) {
 		newmode = drm_mode_detailed(closure->connector->dev,
 					    closure->edid, timing,
-					    closure->quirks);
+					    closure->quirk);
 		if (!newmode)
 			return;
 
@@ -1442,13 +1465,13 @@  do_detailed_mode(struct detailed_timing *timing, void *c)
  */
 static int
 add_detailed_modes(struct drm_connector *connector, struct edid *edid,
-		   u32 quirks)
+		   const struct edid_quirk *quirk)
 {
 	struct detailed_mode_closure closure = {
 		connector,
 		edid,
 		1,
-		quirks,
+		quirk,
 		0
 	};
 
@@ -1890,7 +1913,7 @@  static void drm_add_display_info(struct edid *edid,
 int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
 {
 	int num_modes = 0;
-	u32 quirks;
+	const struct edid_quirk *quirk;
 
 	if (edid == NULL) {
 		return 0;
@@ -1901,7 +1924,7 @@  int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
 		return 0;
 	}
 
-	quirks = edid_get_quirks(edid);
+	quirk = edid_get_quirk(edid);
 
 	/*
 	 * EDID spec says modes should be preferred in this order:
@@ -1917,15 +1940,16 @@  int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
 	 *
 	 * XXX order for additional mode types in extension blocks?
 	 */
-	num_modes += add_detailed_modes(connector, edid, quirks);
+	num_modes += add_detailed_modes(connector, edid, quirk);
 	num_modes += add_cvt_modes(connector, edid);
 	num_modes += add_standard_modes(connector, edid);
 	num_modes += add_established_modes(connector, edid);
 	num_modes += add_inferred_modes(connector, edid);
 	num_modes += add_cea_modes(connector, edid);
 
-	if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75))
-		edid_fixup_preferred(connector, quirks);
+	if (quirk && quirk->quirks &
+	    (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75))
+		edid_fixup_preferred(connector, quirk->quirks);
 
 	drm_add_display_info(edid, &connector->display_info);
 
-- 
1.7.2.5