diff mbox

ping: Re: quirk for Samsung 2443BW

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

Commit Message

Baurzhan Ismagulov Aug. 11, 2012, 8:04 p.m. UTC
Hello Adam,

On Fri, Jul 20, 2012 at 12:34:21PM +1000, Dave Airlie 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.
...
> > This implementation matches the wrong mode by size. Other approaches are
> > possible.
> >
> > I'd appreciate feedback.
> 
> ajax, seem sane?

Ping?

With kind regards,
Baurzhan.
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