diff options
author | Paul Mundt <lethal@linux-sh.org> | 2010-11-16 02:25:03 -0500 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2010-11-16 02:25:03 -0500 |
commit | 936fc42831aa351974b707c00b9e67ac81cd530f (patch) | |
tree | 89b359227b4324b85ab66fa6ddb5dbbc0907c521 | |
parent | 12ddf37444eaaf67b147561141150e10a56d7742 (diff) | |
parent | 0ad83f6882c41df1a7fa387086029e162038c1f2 (diff) |
Merge branch 'fbdev/edid'
-rw-r--r-- | drivers/video/fbmon.c | 88 | ||||
-rw-r--r-- | drivers/video/modedb.c | 43 | ||||
-rw-r--r-- | include/linux/fb.h | 3 |
3 files changed, 134 insertions, 0 deletions
diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c index 563a98b88e9b..4f57485f8c54 100644 --- a/drivers/video/fbmon.c +++ b/drivers/video/fbmon.c | |||
@@ -973,6 +973,90 @@ void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs) | |||
973 | DPRINTK("========================================\n"); | 973 | DPRINTK("========================================\n"); |
974 | } | 974 | } |
975 | 975 | ||
976 | /** | ||
977 | * fb_edid_add_monspecs() - add monitor video modes from E-EDID data | ||
978 | * @edid: 128 byte array with an E-EDID block | ||
979 | * @spacs: monitor specs to be extended | ||
980 | */ | ||
981 | void fb_edid_add_monspecs(unsigned char *edid, struct fb_monspecs *specs) | ||
982 | { | ||
983 | unsigned char *block; | ||
984 | struct fb_videomode *m; | ||
985 | int num = 0, i; | ||
986 | u8 svd[64], edt[(128 - 4) / DETAILED_TIMING_DESCRIPTION_SIZE]; | ||
987 | u8 pos = 4, svd_n = 0; | ||
988 | |||
989 | if (!edid) | ||
990 | return; | ||
991 | |||
992 | if (!edid_checksum(edid)) | ||
993 | return; | ||
994 | |||
995 | if (edid[0] != 0x2 || | ||
996 | edid[2] < 4 || edid[2] > 128 - DETAILED_TIMING_DESCRIPTION_SIZE) | ||
997 | return; | ||
998 | |||
999 | DPRINTK(" Short Video Descriptors\n"); | ||
1000 | |||
1001 | while (pos < edid[2]) { | ||
1002 | u8 len = edid[pos] & 0x1f, type = (edid[pos] >> 5) & 7; | ||
1003 | pr_debug("Data block %u of %u bytes\n", type, len); | ||
1004 | if (type == 2) | ||
1005 | for (i = pos; i < pos + len; i++) { | ||
1006 | u8 idx = edid[pos + i] & 0x7f; | ||
1007 | svd[svd_n++] = idx; | ||
1008 | pr_debug("N%sative mode #%d\n", | ||
1009 | edid[pos + i] & 0x80 ? "" : "on-n", idx); | ||
1010 | } | ||
1011 | pos += len + 1; | ||
1012 | } | ||
1013 | |||
1014 | block = edid + edid[2]; | ||
1015 | |||
1016 | DPRINTK(" Extended Detailed Timings\n"); | ||
1017 | |||
1018 | for (i = 0; i < (128 - edid[2]) / DETAILED_TIMING_DESCRIPTION_SIZE; | ||
1019 | i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) | ||
1020 | if (PIXEL_CLOCK) | ||
1021 | edt[num++] = block - edid; | ||
1022 | |||
1023 | /* Yikes, EDID data is totally useless */ | ||
1024 | if (!(num + svd_n)) | ||
1025 | return; | ||
1026 | |||
1027 | m = kzalloc((specs->modedb_len + num + svd_n) * | ||
1028 | sizeof(struct fb_videomode), GFP_KERNEL); | ||
1029 | |||
1030 | if (!m) | ||
1031 | return; | ||
1032 | |||
1033 | memcpy(m, specs->modedb, specs->modedb_len * sizeof(struct fb_videomode)); | ||
1034 | |||
1035 | for (i = specs->modedb_len; i < specs->modedb_len + num; i++) { | ||
1036 | get_detailed_timing(edid + edt[i - specs->modedb_len], &m[i]); | ||
1037 | if (i == specs->modedb_len) | ||
1038 | m[i].flag |= FB_MODE_IS_FIRST; | ||
1039 | pr_debug("Adding %ux%u@%u\n", m[i].xres, m[i].yres, m[i].refresh); | ||
1040 | } | ||
1041 | |||
1042 | for (i = specs->modedb_len + num; i < specs->modedb_len + num + svd_n; i++) { | ||
1043 | int idx = svd[i - specs->modedb_len - num]; | ||
1044 | if (!idx || idx > 63) { | ||
1045 | pr_warning("Reserved SVD code %d\n", idx); | ||
1046 | } else if (idx > ARRAY_SIZE(cea_modes) || !cea_modes[idx].xres) { | ||
1047 | pr_warning("Unimplemented SVD code %d\n", idx); | ||
1048 | } else { | ||
1049 | memcpy(&m[i], cea_modes + idx, sizeof(m[i])); | ||
1050 | pr_debug("Adding SVD #%d: %ux%u@%u\n", idx, | ||
1051 | m[i].xres, m[i].yres, m[i].refresh); | ||
1052 | } | ||
1053 | } | ||
1054 | |||
1055 | kfree(specs->modedb); | ||
1056 | specs->modedb = m; | ||
1057 | specs->modedb_len = specs->modedb_len + num + svd_n; | ||
1058 | } | ||
1059 | |||
976 | /* | 1060 | /* |
977 | * VESA Generalized Timing Formula (GTF) | 1061 | * VESA Generalized Timing Formula (GTF) |
978 | */ | 1062 | */ |
@@ -1289,6 +1373,9 @@ void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs) | |||
1289 | { | 1373 | { |
1290 | specs = NULL; | 1374 | specs = NULL; |
1291 | } | 1375 | } |
1376 | void fb_edid_add_monspecs(unsigned char *edid, struct fb_monspecs *specs) | ||
1377 | { | ||
1378 | } | ||
1292 | void fb_destroy_modedb(struct fb_videomode *modedb) | 1379 | void fb_destroy_modedb(struct fb_videomode *modedb) |
1293 | { | 1380 | { |
1294 | } | 1381 | } |
@@ -1396,6 +1483,7 @@ EXPORT_SYMBOL(fb_firmware_edid); | |||
1396 | 1483 | ||
1397 | EXPORT_SYMBOL(fb_parse_edid); | 1484 | EXPORT_SYMBOL(fb_parse_edid); |
1398 | EXPORT_SYMBOL(fb_edid_to_monspecs); | 1485 | EXPORT_SYMBOL(fb_edid_to_monspecs); |
1486 | EXPORT_SYMBOL(fb_edid_add_monspecs); | ||
1399 | EXPORT_SYMBOL(fb_get_mode); | 1487 | EXPORT_SYMBOL(fb_get_mode); |
1400 | EXPORT_SYMBOL(fb_validate_mode); | 1488 | EXPORT_SYMBOL(fb_validate_mode); |
1401 | EXPORT_SYMBOL(fb_destroy_modedb); | 1489 | EXPORT_SYMBOL(fb_destroy_modedb); |
diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c index 0a4dbdc1693a..9a0ae6ca5427 100644 --- a/drivers/video/modedb.c +++ b/drivers/video/modedb.c | |||
@@ -278,6 +278,49 @@ static const struct fb_videomode modedb[] = { | |||
278 | }; | 278 | }; |
279 | 279 | ||
280 | #ifdef CONFIG_FB_MODE_HELPERS | 280 | #ifdef CONFIG_FB_MODE_HELPERS |
281 | const struct fb_videomode cea_modes[64] = { | ||
282 | /* #1: 640x480p@59.94/60Hz */ | ||
283 | [1] = { | ||
284 | NULL, 60, 640, 480, 39722, 48, 16, 33, 10, 96, 2, 0, FB_VMODE_NONINTERLACED, 0, | ||
285 | }, | ||
286 | /* #3: 720x480p@59.94/60Hz */ | ||
287 | [3] = { | ||
288 | NULL, 60, 720, 480, 37037, 60, 16, 30, 9, 62, 6, 0, FB_VMODE_NONINTERLACED, 0, | ||
289 | }, | ||
290 | /* #5: 1920x1080i@59.94/60Hz */ | ||
291 | [5] = { | ||
292 | NULL, 60, 1920, 1080, 13763, 148, 88, 15, 2, 44, 5, 0, FB_VMODE_INTERLACED, 0, | ||
293 | }, | ||
294 | /* #7: 720(1440)x480iH@59.94/60Hz */ | ||
295 | [7] = { | ||
296 | NULL, 60, 1440, 480, 18554/*37108*/, 114, 38, 15, 4, 124, 3, 0, FB_VMODE_INTERLACED, 0, | ||
297 | }, | ||
298 | /* #9: 720(1440)x240pH@59.94/60Hz */ | ||
299 | [9] = { | ||
300 | NULL, 60, 1440, 240, 18554, 114, 38, 16, 4, 124, 3, 0, FB_VMODE_NONINTERLACED, 0, | ||
301 | }, | ||
302 | /* #18: 720x576pH@50Hz */ | ||
303 | [18] = { | ||
304 | NULL, 50, 720, 576, 37037, 68, 12, 39, 5, 64, 5, 0, FB_VMODE_NONINTERLACED, 0, | ||
305 | }, | ||
306 | /* #19: 1280x720p@50Hz */ | ||
307 | [19] = { | ||
308 | NULL, 50, 1280, 720, 13468, 220, 440, 20, 5, 40, 5, 0, FB_VMODE_NONINTERLACED, 0, | ||
309 | }, | ||
310 | /* #20: 1920x1080i@50Hz */ | ||
311 | [20] = { | ||
312 | NULL, 50, 1920, 1080, 13480, 148, 528, 15, 5, 528, 5, 0, FB_VMODE_INTERLACED, 0, | ||
313 | }, | ||
314 | /* #32: 1920x1080p@23.98/24Hz */ | ||
315 | [32] = { | ||
316 | NULL, 24, 1920, 1080, 13468, 148, 638, 36, 4, 44, 5, 0, FB_VMODE_NONINTERLACED, 0, | ||
317 | }, | ||
318 | /* #35: (2880)x480p4x@59.94/60Hz */ | ||
319 | [35] = { | ||
320 | NULL, 50, 2880, 480, 11100, 240, 64, 30, 9, 248, 6, 0, FB_VMODE_NONINTERLACED, 0, | ||
321 | }, | ||
322 | }; | ||
323 | |||
281 | const struct fb_videomode vesa_modes[] = { | 324 | const struct fb_videomode vesa_modes[] = { |
282 | /* 0 640x350-85 VESA */ | 325 | /* 0 640x350-85 VESA */ |
283 | { NULL, 85, 640, 350, 31746, 96, 32, 60, 32, 64, 3, | 326 | { NULL, 85, 640, 350, 31746, 96, 32, 60, 32, 64, 3, |
diff --git a/include/linux/fb.h b/include/linux/fb.h index 7fca3dc4e475..e154a79b8322 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h | |||
@@ -1092,6 +1092,8 @@ extern int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var); | |||
1092 | extern const unsigned char *fb_firmware_edid(struct device *device); | 1092 | extern const unsigned char *fb_firmware_edid(struct device *device); |
1093 | extern void fb_edid_to_monspecs(unsigned char *edid, | 1093 | extern void fb_edid_to_monspecs(unsigned char *edid, |
1094 | struct fb_monspecs *specs); | 1094 | struct fb_monspecs *specs); |
1095 | extern void fb_edid_add_monspecs(unsigned char *edid, | ||
1096 | struct fb_monspecs *specs); | ||
1095 | extern void fb_destroy_modedb(struct fb_videomode *modedb); | 1097 | extern void fb_destroy_modedb(struct fb_videomode *modedb); |
1096 | extern int fb_find_mode_cvt(struct fb_videomode *mode, int margins, int rb); | 1098 | extern int fb_find_mode_cvt(struct fb_videomode *mode, int margins, int rb); |
1097 | extern unsigned char *fb_ddc_read(struct i2c_adapter *adapter); | 1099 | extern unsigned char *fb_ddc_read(struct i2c_adapter *adapter); |
@@ -1149,6 +1151,7 @@ struct fb_videomode { | |||
1149 | 1151 | ||
1150 | extern const char *fb_mode_option; | 1152 | extern const char *fb_mode_option; |
1151 | extern const struct fb_videomode vesa_modes[]; | 1153 | extern const struct fb_videomode vesa_modes[]; |
1154 | extern const struct fb_videomode cea_modes[64]; | ||
1152 | 1155 | ||
1153 | struct fb_modelist { | 1156 | struct fb_modelist { |
1154 | struct list_head list; | 1157 | struct list_head list; |