aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Jackson <ajax@redhat.com>2009-12-03 17:44:40 -0500
committerDave Airlie <airlied@redhat.com>2009-12-04 08:53:47 +1000
commit9340d8cfeacd16cef1cbe94527f7baaed7640669 (patch)
tree08739867be1f39978793dcdc34b606db81775975
parent2dbdc52c8162291aa7541b8ba6e1c1587f50c1dd (diff)
drm/edid: Decode 3-byte CVT codes from EDID 1.4
Signed-off-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
-rw-r--r--drivers/gpu/drm/drm_edid.c48
-rw-r--r--include/drm/drm_edid.h5
2 files changed, 53 insertions, 0 deletions
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index cc8e6968271..30af8f3e642 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -897,6 +897,51 @@ static int drm_gtf_modes_for_range(struct drm_connector *connector,
return modes;
}
+static int drm_cvt_modes(struct drm_connector *connector,
+ struct detailed_timing *timing)
+{
+ int i, j, modes = 0;
+ struct drm_display_mode *newmode;
+ struct drm_device *dev = connector->dev;
+ struct cvt_timing *cvt;
+ const int rates[] = { 60, 85, 75, 60, 50 };
+
+ for (i = 0; i < 4; i++) {
+ int width, height;
+ cvt = &(timing->data.other_data.data.cvt[i]);
+
+ height = (cvt->code[0] + ((cvt->code[1] & 0xf0) << 8) + 1) * 2;
+ switch (cvt->code[1] & 0xc0) {
+ case 0x00:
+ width = height * 4 / 3;
+ break;
+ case 0x40:
+ width = height * 16 / 9;
+ break;
+ case 0x80:
+ width = height * 16 / 10;
+ break;
+ case 0xc0:
+ width = height * 15 / 9;
+ break;
+ }
+
+ for (j = 1; j < 5; j++) {
+ if (cvt->code[2] & (1 << j)) {
+ newmode = drm_cvt_mode(dev, width, height,
+ rates[j], j == 0,
+ false, false);
+ if (newmode) {
+ drm_mode_probed_add(connector, newmode);
+ modes++;
+ }
+ }
+ }
+ }
+
+ return modes;
+}
+
static int add_detailed_modes(struct drm_connector *connector,
struct detailed_timing *timing,
struct edid *edid, u32 quirks, int preferred)
@@ -941,6 +986,9 @@ static int add_detailed_modes(struct drm_connector *connector,
}
}
break;
+ case EDID_DETAIL_CVT_3BYTE:
+ modes += drm_cvt_modes(connector, timing);
+ break;
default:
break;
}
diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h
index 9087557fd83..d33c3e03860 100644
--- a/include/drm/drm_edid.h
+++ b/include/drm/drm_edid.h
@@ -106,6 +106,10 @@ struct detailed_data_color_point {
u8 wpindex2[3];
} __attribute__((packed));
+struct cvt_timing {
+ u8 code[3];
+} __attribute__((packed));
+
struct detailed_non_pixel {
u8 pad1;
u8 type; /* ff=serial, fe=string, fd=monitor range, fc=monitor name
@@ -117,6 +121,7 @@ struct detailed_non_pixel {
struct detailed_data_monitor_range range;
struct detailed_data_wpindex color;
struct std_timing timings[5];
+ struct cvt_timing cvt[4];
} data;
} __attribute__((packed));