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(-)
@@ -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