diff options
| author | Paul Mundt <lethal@linux-sh.org> | 2010-11-15 00:57:49 -0500 |
|---|---|---|
| committer | Paul Mundt <lethal@linux-sh.org> | 2010-11-15 00:57:49 -0500 |
| commit | d8d776f3fb1ff19c37d43b600fc8c128ff172deb (patch) | |
| tree | 334b0d0273a6acc7d238e1cb492f1b23199d51bc | |
| parent | c724d07a56e60e91b0aa75193f86fb000545ffe4 (diff) | |
| parent | 0ad83f6882c41df1a7fa387086029e162038c1f2 (diff) | |
Merge branch 'fbdev/edid' of master.kernel.org:/pub/scm/linux/kernel/git/lethal/fbdev-2.6 into common/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; |
