aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/drm_edid.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2010-08-12 12:21:39 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-08-12 12:21:39 -0400
commitaa9f56b66d278aba2f278c75761b7e19fbaca97a (patch)
treef1a9a0e68b07a3a1a0643389cb5ff838366a2d32 /drivers/gpu/drm/drm_edid.c
parent58d4ea65b98f154f3326b038eecda32f90b46ea8 (diff)
parent31ce4bfdfd10bf5db9bf85c92bbe0cf2edbdcad8 (diff)
Merge branch 'drm-core-next' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6
* 'drm-core-next' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6: (55 commits) io-mapping: move asm include inside the config option vgaarb: drop vga.h include drm/radeon: Add probing of clocks from device-tree drm/radeon: drop old and broken mesa warning drm/radeon: Fix pci_map_page() error checking drm: Remove count_lock for calling lastclose() after 58474713 (v2) drm/radeon/kms: allow FG_ALPHA_VALUE on r5xx drm/radeon/kms: another r6xx/r7xx CS checker fix DRM: Replace kmalloc/memset combos with kzalloc drm: expand gamma_set drm/edid: Split mode lists out to their own header for readability drm/edid: Rewrite mode parse to use the generic detailed block walk drm/edid: Add detailed block walk for VTB extensions drm/edid: Add detailed block walk for CEA extensions drm: Remove unused fields from drm_display_info drm: Use ENOENT consistently for the error return for an unmatched handle. drm/radeon/kms: mark 3D power states as performance drm: Only set DPMS once on the CRTC not after every encoder. drm/radeon/kms: add additional quirk for Acer rv620 laptop drm: Propagate error code from fb_create() ... Fix up trivial conflicts in drivers/gpu/drm/drm_edid.c
Diffstat (limited to 'drivers/gpu/drm/drm_edid.c')
-rw-r--r--drivers/gpu/drm/drm_edid.c840
1 files changed, 273 insertions, 567 deletions
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index dce5c4a97f8d..96e963108225 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -33,6 +33,11 @@
33#include <linux/i2c-algo-bit.h> 33#include <linux/i2c-algo-bit.h>
34#include "drmP.h" 34#include "drmP.h"
35#include "drm_edid.h" 35#include "drm_edid.h"
36#include "drm_edid_modes.h"
37
38#define version_greater(edid, maj, min) \
39 (((edid)->version > (maj)) || \
40 ((edid)->version == (maj) && (edid)->revision > (min)))
36 41
37#define EDID_EST_TIMINGS 16 42#define EDID_EST_TIMINGS 16
38#define EDID_STD_TIMINGS 8 43#define EDID_STD_TIMINGS 8
@@ -62,6 +67,13 @@
62/* use +hsync +vsync for detailed mode */ 67/* use +hsync +vsync for detailed mode */
63#define EDID_QUIRK_DETAILED_SYNC_PP (1 << 6) 68#define EDID_QUIRK_DETAILED_SYNC_PP (1 << 6)
64 69
70struct detailed_mode_closure {
71 struct drm_connector *connector;
72 struct edid *edid;
73 bool preferred;
74 u32 quirks;
75 int modes;
76};
65 77
66#define LEVEL_DMT 0 78#define LEVEL_DMT 0
67#define LEVEL_GTF 1 79#define LEVEL_GTF 1
@@ -375,7 +387,6 @@ static u32 edid_get_quirks(struct edid *edid)
375#define MODE_SIZE(m) ((m)->hdisplay * (m)->vdisplay) 387#define MODE_SIZE(m) ((m)->hdisplay * (m)->vdisplay)
376#define MODE_REFRESH_DIFF(m,r) (abs((m)->vrefresh - target_refresh)) 388#define MODE_REFRESH_DIFF(m,r) (abs((m)->vrefresh - target_refresh))
377 389
378
379/** 390/**
380 * edid_fixup_preferred - set preferred modes based on quirk list 391 * edid_fixup_preferred - set preferred modes based on quirk list
381 * @connector: has mode list to fix up 392 * @connector: has mode list to fix up
@@ -422,245 +433,6 @@ static void edid_fixup_preferred(struct drm_connector *connector,
422 preferred_mode->type |= DRM_MODE_TYPE_PREFERRED; 433 preferred_mode->type |= DRM_MODE_TYPE_PREFERRED;
423} 434}
424 435
425/*
426 * Add the Autogenerated from the DMT spec.
427 * This table is copied from xfree86/modes/xf86EdidModes.c.
428 * But the mode with Reduced blank feature is deleted.
429 */
430static struct drm_display_mode drm_dmt_modes[] = {
431 /* 640x350@85Hz */
432 { DRM_MODE("640x350", DRM_MODE_TYPE_DRIVER, 31500, 640, 672,
433 736, 832, 0, 350, 382, 385, 445, 0,
434 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
435 /* 640x400@85Hz */
436 { DRM_MODE("640x400", DRM_MODE_TYPE_DRIVER, 31500, 640, 672,
437 736, 832, 0, 400, 401, 404, 445, 0,
438 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
439 /* 720x400@85Hz */
440 { DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 35500, 720, 756,
441 828, 936, 0, 400, 401, 404, 446, 0,
442 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
443 /* 640x480@60Hz */
444 { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656,
445 752, 800, 0, 480, 489, 492, 525, 0,
446 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
447 /* 640x480@72Hz */
448 { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 664,
449 704, 832, 0, 480, 489, 492, 520, 0,
450 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
451 /* 640x480@75Hz */
452 { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 656,
453 720, 840, 0, 480, 481, 484, 500, 0,
454 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
455 /* 640x480@85Hz */
456 { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 36000, 640, 696,
457 752, 832, 0, 480, 481, 484, 509, 0,
458 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
459 /* 800x600@56Hz */
460 { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 36000, 800, 824,
461 896, 1024, 0, 600, 601, 603, 625, 0,
462 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
463 /* 800x600@60Hz */
464 { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840,
465 968, 1056, 0, 600, 601, 605, 628, 0,
466 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
467 /* 800x600@72Hz */
468 { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 50000, 800, 856,
469 976, 1040, 0, 600, 637, 643, 666, 0,
470 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
471 /* 800x600@75Hz */
472 { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 49500, 800, 816,
473 896, 1056, 0, 600, 601, 604, 625, 0,
474 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
475 /* 800x600@85Hz */
476 { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 56250, 800, 832,
477 896, 1048, 0, 600, 601, 604, 631, 0,
478 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
479 /* 848x480@60Hz */
480 { DRM_MODE("848x480", DRM_MODE_TYPE_DRIVER, 33750, 848, 864,
481 976, 1088, 0, 480, 486, 494, 517, 0,
482 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
483 /* 1024x768@43Hz, interlace */
484 { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 44900, 1024, 1032,
485 1208, 1264, 0, 768, 768, 772, 817, 0,
486 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
487 DRM_MODE_FLAG_INTERLACE) },
488 /* 1024x768@60Hz */
489 { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048,
490 1184, 1344, 0, 768, 771, 777, 806, 0,
491 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
492 /* 1024x768@70Hz */
493 { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 75000, 1024, 1048,
494 1184, 1328, 0, 768, 771, 777, 806, 0,
495 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
496 /* 1024x768@75Hz */
497 { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 78750, 1024, 1040,
498 1136, 1312, 0, 768, 769, 772, 800, 0,
499 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
500 /* 1024x768@85Hz */
501 { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 94500, 1024, 1072,
502 1168, 1376, 0, 768, 769, 772, 808, 0,
503 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
504 /* 1152x864@75Hz */
505 { DRM_MODE("1152x864", DRM_MODE_TYPE_DRIVER, 108000, 1152, 1216,
506 1344, 1600, 0, 864, 865, 868, 900, 0,
507 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
508 /* 1280x768@60Hz */
509 { DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 79500, 1280, 1344,
510 1472, 1664, 0, 768, 771, 778, 798, 0,
511 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
512 /* 1280x768@75Hz */
513 { DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 102250, 1280, 1360,
514 1488, 1696, 0, 768, 771, 778, 805, 0,
515 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
516 /* 1280x768@85Hz */
517 { DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 117500, 1280, 1360,
518 1496, 1712, 0, 768, 771, 778, 809, 0,
519 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
520 /* 1280x800@60Hz */
521 { DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 83500, 1280, 1352,
522 1480, 1680, 0, 800, 803, 809, 831, 0,
523 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
524 /* 1280x800@75Hz */
525 { DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 106500, 1280, 1360,
526 1488, 1696, 0, 800, 803, 809, 838, 0,
527 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
528 /* 1280x800@85Hz */
529 { DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 122500, 1280, 1360,
530 1496, 1712, 0, 800, 803, 809, 843, 0,
531 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
532 /* 1280x960@60Hz */
533 { DRM_MODE("1280x960", DRM_MODE_TYPE_DRIVER, 108000, 1280, 1376,
534 1488, 1800, 0, 960, 961, 964, 1000, 0,
535 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
536 /* 1280x960@85Hz */
537 { DRM_MODE("1280x960", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1344,
538 1504, 1728, 0, 960, 961, 964, 1011, 0,
539 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
540 /* 1280x1024@60Hz */
541 { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 108000, 1280, 1328,
542 1440, 1688, 0, 1024, 1025, 1028, 1066, 0,
543 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
544 /* 1280x1024@75Hz */
545 { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 135000, 1280, 1296,
546 1440, 1688, 0, 1024, 1025, 1028, 1066, 0,
547 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
548 /* 1280x1024@85Hz */
549 { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 157500, 1280, 1344,
550 1504, 1728, 0, 1024, 1025, 1028, 1072, 0,
551 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
552 /* 1360x768@60Hz */
553 { DRM_MODE("1360x768", DRM_MODE_TYPE_DRIVER, 85500, 1360, 1424,
554 1536, 1792, 0, 768, 771, 777, 795, 0,
555 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
556 /* 1440x1050@60Hz */
557 { DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 121750, 1400, 1488,
558 1632, 1864, 0, 1050, 1053, 1057, 1089, 0,
559 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
560 /* 1440x1050@75Hz */
561 { DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 156000, 1400, 1504,
562 1648, 1896, 0, 1050, 1053, 1057, 1099, 0,
563 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
564 /* 1440x1050@85Hz */
565 { DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 179500, 1400, 1504,
566 1656, 1912, 0, 1050, 1053, 1057, 1105, 0,
567 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
568 /* 1440x900@60Hz */
569 { DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 106500, 1440, 1520,
570 1672, 1904, 0, 900, 903, 909, 934, 0,
571 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
572 /* 1440x900@75Hz */
573 { DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 136750, 1440, 1536,
574 1688, 1936, 0, 900, 903, 909, 942, 0,
575 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
576 /* 1440x900@85Hz */
577 { DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 157000, 1440, 1544,
578 1696, 1952, 0, 900, 903, 909, 948, 0,
579 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
580 /* 1600x1200@60Hz */
581 { DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 162000, 1600, 1664,
582 1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
583 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
584 /* 1600x1200@65Hz */
585 { DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 175500, 1600, 1664,
586 1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
587 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
588 /* 1600x1200@70Hz */
589 { DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 189000, 1600, 1664,
590 1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
591 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
592 /* 1600x1200@75Hz */
593 { DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 202500, 1600, 1664,
594 1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
595 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
596 /* 1600x1200@85Hz */
597 { DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 229500, 1600, 1664,
598 1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
599 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
600 /* 1680x1050@60Hz */
601 { DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 146250, 1680, 1784,
602 1960, 2240, 0, 1050, 1053, 1059, 1089, 0,
603 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
604 /* 1680x1050@75Hz */
605 { DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 187000, 1680, 1800,
606 1976, 2272, 0, 1050, 1053, 1059, 1099, 0,
607 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
608 /* 1680x1050@85Hz */
609 { DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 214750, 1680, 1808,
610 1984, 2288, 0, 1050, 1053, 1059, 1105, 0,
611 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
612 /* 1792x1344@60Hz */
613 { DRM_MODE("1792x1344", DRM_MODE_TYPE_DRIVER, 204750, 1792, 1920,
614 2120, 2448, 0, 1344, 1345, 1348, 1394, 0,
615 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
616 /* 1729x1344@75Hz */
617 { DRM_MODE("1792x1344", DRM_MODE_TYPE_DRIVER, 261000, 1792, 1888,
618 2104, 2456, 0, 1344, 1345, 1348, 1417, 0,
619 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
620 /* 1853x1392@60Hz */
621 { DRM_MODE("1856x1392", DRM_MODE_TYPE_DRIVER, 218250, 1856, 1952,
622 2176, 2528, 0, 1392, 1393, 1396, 1439, 0,
623 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
624 /* 1856x1392@75Hz */
625 { DRM_MODE("1856x1392", DRM_MODE_TYPE_DRIVER, 288000, 1856, 1984,
626 2208, 2560, 0, 1392, 1395, 1399, 1500, 0,
627 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
628 /* 1920x1200@60Hz */
629 { DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 193250, 1920, 2056,
630 2256, 2592, 0, 1200, 1203, 1209, 1245, 0,
631 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
632 /* 1920x1200@75Hz */
633 { DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 245250, 1920, 2056,
634 2264, 2608, 0, 1200, 1203, 1209, 1255, 0,
635 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
636 /* 1920x1200@85Hz */
637 { DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 281250, 1920, 2064,
638 2272, 2624, 0, 1200, 1203, 1209, 1262, 0,
639 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
640 /* 1920x1440@60Hz */
641 { DRM_MODE("1920x1440", DRM_MODE_TYPE_DRIVER, 234000, 1920, 2048,
642 2256, 2600, 0, 1440, 1441, 1444, 1500, 0,
643 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
644 /* 1920x1440@75Hz */
645 { DRM_MODE("1920x1440", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2064,
646 2288, 2640, 0, 1440, 1441, 1444, 1500, 0,
647 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
648 /* 2560x1600@60Hz */
649 { DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 348500, 2560, 2752,
650 3032, 3504, 0, 1600, 1603, 1609, 1658, 0,
651 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
652 /* 2560x1600@75HZ */
653 { DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 443250, 2560, 2768,
654 3048, 3536, 0, 1600, 1603, 1609, 1672, 0,
655 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
656 /* 2560x1600@85HZ */
657 { DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 505250, 2560, 2768,
658 3048, 3536, 0, 1600, 1603, 1609, 1682, 0,
659 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
660};
661static const int drm_num_dmt_modes =
662 sizeof(drm_dmt_modes) / sizeof(struct drm_display_mode);
663
664struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev, 436struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev,
665 int hsize, int vsize, int fresh) 437 int hsize, int vsize, int fresh)
666{ 438{
@@ -685,6 +457,46 @@ EXPORT_SYMBOL(drm_mode_find_dmt);
685typedef void detailed_cb(struct detailed_timing *timing, void *closure); 457typedef void detailed_cb(struct detailed_timing *timing, void *closure);
686 458
687static void 459static void
460cea_for_each_detailed_block(u8 *ext, detailed_cb *cb, void *closure)
461{
462 int i, n = 0;
463 u8 rev = ext[0x01], d = ext[0x02];
464 u8 *det_base = ext + d;
465
466 switch (rev) {
467 case 0:
468 /* can't happen */
469 return;
470 case 1:
471 /* have to infer how many blocks we have, check pixel clock */
472 for (i = 0; i < 6; i++)
473 if (det_base[18*i] || det_base[18*i+1])
474 n++;
475 break;
476 default:
477 /* explicit count */
478 n = min(ext[0x03] & 0x0f, 6);
479 break;
480 }
481
482 for (i = 0; i < n; i++)
483 cb((struct detailed_timing *)(det_base + 18 * i), closure);
484}
485
486static void
487vtb_for_each_detailed_block(u8 *ext, detailed_cb *cb, void *closure)
488{
489 unsigned int i, n = min((int)ext[0x02], 6);
490 u8 *det_base = ext + 5;
491
492 if (ext[0x01] != 1)
493 return; /* unknown version */
494
495 for (i = 0; i < n; i++)
496 cb((struct detailed_timing *)(det_base + 18 * i), closure);
497}
498
499static void
688drm_for_each_detailed_block(u8 *raw_edid, detailed_cb *cb, void *closure) 500drm_for_each_detailed_block(u8 *raw_edid, detailed_cb *cb, void *closure)
689{ 501{
690 int i; 502 int i;
@@ -696,7 +508,19 @@ drm_for_each_detailed_block(u8 *raw_edid, detailed_cb *cb, void *closure)
696 for (i = 0; i < EDID_DETAILED_TIMINGS; i++) 508 for (i = 0; i < EDID_DETAILED_TIMINGS; i++)
697 cb(&(edid->detailed_timings[i]), closure); 509 cb(&(edid->detailed_timings[i]), closure);
698 510
699 /* XXX extension block walk */ 511 for (i = 1; i <= raw_edid[0x7e]; i++) {
512 u8 *ext = raw_edid + (i * EDID_LENGTH);
513 switch (*ext) {
514 case CEA_EXT:
515 cea_for_each_detailed_block(ext, cb, closure);
516 break;
517 case VTB_EXT:
518 vtb_for_each_detailed_block(ext, cb, closure);
519 break;
520 default:
521 break;
522 }
523 }
700} 524}
701 525
702static void 526static void
@@ -1047,117 +871,6 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev,
1047 return mode; 871 return mode;
1048} 872}
1049 873
1050/*
1051 * Detailed mode info for the EDID "established modes" data to use.
1052 */
1053static struct drm_display_mode edid_est_modes[] = {
1054 { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840,
1055 968, 1056, 0, 600, 601, 605, 628, 0,
1056 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@60Hz */
1057 { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 36000, 800, 824,
1058 896, 1024, 0, 600, 601, 603, 625, 0,
1059 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@56Hz */
1060 { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 656,
1061 720, 840, 0, 480, 481, 484, 500, 0,
1062 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@75Hz */
1063 { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 664,
1064 704, 832, 0, 480, 489, 491, 520, 0,
1065 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@72Hz */
1066 { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 30240, 640, 704,
1067 768, 864, 0, 480, 483, 486, 525, 0,
1068 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@67Hz */
1069 { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25200, 640, 656,
1070 752, 800, 0, 480, 490, 492, 525, 0,
1071 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@60Hz */
1072 { DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 35500, 720, 738,
1073 846, 900, 0, 400, 421, 423, 449, 0,
1074 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 720x400@88Hz */
1075 { DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 28320, 720, 738,
1076 846, 900, 0, 400, 412, 414, 449, 0,
1077 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 720x400@70Hz */
1078 { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 135000, 1280, 1296,
1079 1440, 1688, 0, 1024, 1025, 1028, 1066, 0,
1080 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1280x1024@75Hz */
1081 { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 78800, 1024, 1040,
1082 1136, 1312, 0, 768, 769, 772, 800, 0,
1083 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1024x768@75Hz */
1084 { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 75000, 1024, 1048,
1085 1184, 1328, 0, 768, 771, 777, 806, 0,
1086 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 1024x768@70Hz */
1087 { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048,
1088 1184, 1344, 0, 768, 771, 777, 806, 0,
1089 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 1024x768@60Hz */
1090 { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER,44900, 1024, 1032,
1091 1208, 1264, 0, 768, 768, 776, 817, 0,
1092 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_INTERLACE) }, /* 1024x768@43Hz */
1093 { DRM_MODE("832x624", DRM_MODE_TYPE_DRIVER, 57284, 832, 864,
1094 928, 1152, 0, 624, 625, 628, 667, 0,
1095 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 832x624@75Hz */
1096 { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 49500, 800, 816,
1097 896, 1056, 0, 600, 601, 604, 625, 0,
1098 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@75Hz */
1099 { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 50000, 800, 856,
1100 976, 1040, 0, 600, 637, 643, 666, 0,
1101 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@72Hz */
1102 { DRM_MODE("1152x864", DRM_MODE_TYPE_DRIVER, 108000, 1152, 1216,
1103 1344, 1600, 0, 864, 865, 868, 900, 0,
1104 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1152x864@75Hz */
1105};
1106
1107/**
1108 * add_established_modes - get est. modes from EDID and add them
1109 * @edid: EDID block to scan
1110 *
1111 * Each EDID block contains a bitmap of the supported "established modes" list
1112 * (defined above). Tease them out and add them to the global modes list.
1113 */
1114static int add_established_modes(struct drm_connector *connector, struct edid *edid)
1115{
1116 struct drm_device *dev = connector->dev;
1117 unsigned long est_bits = edid->established_timings.t1 |
1118 (edid->established_timings.t2 << 8) |
1119 ((edid->established_timings.mfg_rsvd & 0x80) << 9);
1120 int i, modes = 0;
1121
1122 for (i = 0; i <= EDID_EST_TIMINGS; i++)
1123 if (est_bits & (1<<i)) {
1124 struct drm_display_mode *newmode;
1125 newmode = drm_mode_duplicate(dev, &edid_est_modes[i]);
1126 if (newmode) {
1127 drm_mode_probed_add(connector, newmode);
1128 modes++;
1129 }
1130 }
1131
1132 return modes;
1133}
1134
1135/**
1136 * add_standard_modes - get std. modes from EDID and add them
1137 * @edid: EDID block to scan
1138 *
1139 * Standard modes can be calculated using the CVT standard. Grab them from
1140 * @edid, calculate them, and add them to the list.
1141 */
1142static int add_standard_modes(struct drm_connector *connector, struct edid *edid)
1143{
1144 int i, modes = 0;
1145
1146 for (i = 0; i < EDID_STD_TIMINGS; i++) {
1147 struct drm_display_mode *newmode;
1148
1149 newmode = drm_mode_std(connector, edid,
1150 &edid->standard_timings[i],
1151 edid->revision);
1152 if (newmode) {
1153 drm_mode_probed_add(connector, newmode);
1154 modes++;
1155 }
1156 }
1157
1158 return modes;
1159}
1160
1161static bool 874static bool
1162mode_is_rb(struct drm_display_mode *mode) 875mode_is_rb(struct drm_display_mode *mode)
1163{ 876{
@@ -1267,113 +980,33 @@ drm_gtf_modes_for_range(struct drm_connector *connector, struct edid *edid,
1267 return modes; 980 return modes;
1268} 981}
1269 982
1270static int drm_cvt_modes(struct drm_connector *connector, 983static void
1271 struct detailed_timing *timing) 984do_inferred_modes(struct detailed_timing *timing, void *c)
1272{ 985{
1273 int i, j, modes = 0; 986 struct detailed_mode_closure *closure = c;
1274 struct drm_display_mode *newmode; 987 struct detailed_non_pixel *data = &timing->data.other_data;
1275 struct drm_device *dev = connector->dev; 988 int gtf = (closure->edid->features & DRM_EDID_FEATURE_DEFAULT_GTF);
1276 struct cvt_timing *cvt;
1277 const int rates[] = { 60, 85, 75, 60, 50 };
1278 const u8 empty[3] = { 0, 0, 0 };
1279
1280 for (i = 0; i < 4; i++) {
1281 int uninitialized_var(width), height;
1282 cvt = &(timing->data.other_data.data.cvt[i]);
1283 989
1284 if (!memcmp(cvt->code, empty, 3)) 990 if (gtf && data->type == EDID_DETAIL_MONITOR_RANGE)
1285 continue; 991 closure->modes += drm_gtf_modes_for_range(closure->connector,
992 closure->edid,
993 timing);
994}
1286 995
1287 height = (cvt->code[0] + ((cvt->code[1] & 0xf0) << 4) + 1) * 2; 996static int
1288 switch (cvt->code[1] & 0x0c) { 997add_inferred_modes(struct drm_connector *connector, struct edid *edid)
1289 case 0x00: 998{
1290 width = height * 4 / 3; 999 struct detailed_mode_closure closure = {
1291 break; 1000 connector, edid, 0, 0, 0
1292 case 0x04: 1001 };
1293 width = height * 16 / 9;
1294 break;
1295 case 0x08:
1296 width = height * 16 / 10;
1297 break;
1298 case 0x0c:
1299 width = height * 15 / 9;
1300 break;
1301 }
1302 1002
1303 for (j = 1; j < 5; j++) { 1003 if (version_greater(edid, 1, 0))
1304 if (cvt->code[2] & (1 << j)) { 1004 drm_for_each_detailed_block((u8 *)edid, do_inferred_modes,
1305 newmode = drm_cvt_mode(dev, width, height, 1005 &closure);
1306 rates[j], j == 0,
1307 false, false);
1308 if (newmode) {
1309 drm_mode_probed_add(connector, newmode);
1310 modes++;
1311 }
1312 }
1313 }
1314 }
1315 1006
1316 return modes; 1007 return closure.modes;
1317} 1008}
1318 1009
1319static const struct {
1320 short w;
1321 short h;
1322 short r;
1323 short rb;
1324} est3_modes[] = {
1325 /* byte 6 */
1326 { 640, 350, 85, 0 },
1327 { 640, 400, 85, 0 },
1328 { 720, 400, 85, 0 },
1329 { 640, 480, 85, 0 },
1330 { 848, 480, 60, 0 },
1331 { 800, 600, 85, 0 },
1332 { 1024, 768, 85, 0 },
1333 { 1152, 864, 75, 0 },
1334 /* byte 7 */
1335 { 1280, 768, 60, 1 },
1336 { 1280, 768, 60, 0 },
1337 { 1280, 768, 75, 0 },
1338 { 1280, 768, 85, 0 },
1339 { 1280, 960, 60, 0 },
1340 { 1280, 960, 85, 0 },
1341 { 1280, 1024, 60, 0 },
1342 { 1280, 1024, 85, 0 },
1343 /* byte 8 */
1344 { 1360, 768, 60, 0 },
1345 { 1440, 900, 60, 1 },
1346 { 1440, 900, 60, 0 },
1347 { 1440, 900, 75, 0 },
1348 { 1440, 900, 85, 0 },
1349 { 1400, 1050, 60, 1 },
1350 { 1400, 1050, 60, 0 },
1351 { 1400, 1050, 75, 0 },
1352 /* byte 9 */
1353 { 1400, 1050, 85, 0 },
1354 { 1680, 1050, 60, 1 },
1355 { 1680, 1050, 60, 0 },
1356 { 1680, 1050, 75, 0 },
1357 { 1680, 1050, 85, 0 },
1358 { 1600, 1200, 60, 0 },
1359 { 1600, 1200, 65, 0 },
1360 { 1600, 1200, 70, 0 },
1361 /* byte 10 */
1362 { 1600, 1200, 75, 0 },
1363 { 1600, 1200, 85, 0 },
1364 { 1792, 1344, 60, 0 },
1365 { 1792, 1344, 85, 0 },
1366 { 1856, 1392, 60, 0 },
1367 { 1856, 1392, 75, 0 },
1368 { 1920, 1200, 60, 1 },
1369 { 1920, 1200, 60, 0 },
1370 /* byte 11 */
1371 { 1920, 1200, 75, 0 },
1372 { 1920, 1200, 85, 0 },
1373 { 1920, 1440, 60, 0 },
1374 { 1920, 1440, 75, 0 },
1375};
1376
1377static int 1010static int
1378drm_est3_modes(struct drm_connector *connector, struct detailed_timing *timing) 1011drm_est3_modes(struct drm_connector *connector, struct detailed_timing *timing)
1379{ 1012{
@@ -1403,37 +1036,63 @@ drm_est3_modes(struct drm_connector *connector, struct detailed_timing *timing)
1403 return modes; 1036 return modes;
1404} 1037}
1405 1038
1406static int add_detailed_modes(struct drm_connector *connector, 1039static void
1407 struct detailed_timing *timing, 1040do_established_modes(struct detailed_timing *timing, void *c)
1408 struct edid *edid, u32 quirks, int preferred)
1409{ 1041{
1410 int i, modes = 0; 1042 struct detailed_mode_closure *closure = c;
1411 struct detailed_non_pixel *data = &timing->data.other_data; 1043 struct detailed_non_pixel *data = &timing->data.other_data;
1412 int gtf = (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF);
1413 struct drm_display_mode *newmode;
1414 struct drm_device *dev = connector->dev;
1415 1044
1416 if (timing->pixel_clock) { 1045 if (data->type == EDID_DETAIL_EST_TIMINGS)
1417 newmode = drm_mode_detailed(dev, edid, timing, quirks); 1046 closure->modes += drm_est3_modes(closure->connector, timing);
1418 if (!newmode) 1047}
1419 return 0;
1420 1048
1421 if (preferred) 1049/**
1422 newmode->type |= DRM_MODE_TYPE_PREFERRED; 1050 * add_established_modes - get est. modes from EDID and add them
1051 * @edid: EDID block to scan
1052 *
1053 * Each EDID block contains a bitmap of the supported "established modes" list
1054 * (defined above). Tease them out and add them to the global modes list.
1055 */
1056static int
1057add_established_modes(struct drm_connector *connector, struct edid *edid)
1058{
1059 struct drm_device *dev = connector->dev;
1060 unsigned long est_bits = edid->established_timings.t1 |
1061 (edid->established_timings.t2 << 8) |
1062 ((edid->established_timings.mfg_rsvd & 0x80) << 9);
1063 int i, modes = 0;
1064 struct detailed_mode_closure closure = {
1065 connector, edid, 0, 0, 0
1066 };
1423 1067
1424 drm_mode_probed_add(connector, newmode); 1068 for (i = 0; i <= EDID_EST_TIMINGS; i++) {
1425 return 1; 1069 if (est_bits & (1<<i)) {
1070 struct drm_display_mode *newmode;
1071 newmode = drm_mode_duplicate(dev, &edid_est_modes[i]);
1072 if (newmode) {
1073 drm_mode_probed_add(connector, newmode);
1074 modes++;
1075 }
1076 }
1426 } 1077 }
1427 1078
1428 /* other timing types */ 1079 if (version_greater(edid, 1, 0))
1429 switch (data->type) { 1080 drm_for_each_detailed_block((u8 *)edid,
1430 case EDID_DETAIL_MONITOR_RANGE: 1081 do_established_modes, &closure);
1431 if (gtf) 1082
1432 modes += drm_gtf_modes_for_range(connector, edid, 1083 return modes + closure.modes;
1433 timing); 1084}
1434 break; 1085
1435 case EDID_DETAIL_STD_MODES: 1086static void
1436 /* Six modes per detailed section */ 1087do_standard_modes(struct detailed_timing *timing, void *c)
1088{
1089 struct detailed_mode_closure *closure = c;
1090 struct detailed_non_pixel *data = &timing->data.other_data;
1091 struct drm_connector *connector = closure->connector;
1092 struct edid *edid = closure->edid;
1093
1094 if (data->type == EDID_DETAIL_STD_MODES) {
1095 int i;
1437 for (i = 0; i < 6; i++) { 1096 for (i = 0; i < 6; i++) {
1438 struct std_timing *std; 1097 struct std_timing *std;
1439 struct drm_display_mode *newmode; 1098 struct drm_display_mode *newmode;
@@ -1443,108 +1102,169 @@ static int add_detailed_modes(struct drm_connector *connector,
1443 edid->revision); 1102 edid->revision);
1444 if (newmode) { 1103 if (newmode) {
1445 drm_mode_probed_add(connector, newmode); 1104 drm_mode_probed_add(connector, newmode);
1446 modes++; 1105 closure->modes++;
1447 } 1106 }
1448 } 1107 }
1449 break;
1450 case EDID_DETAIL_CVT_3BYTE:
1451 modes += drm_cvt_modes(connector, timing);
1452 break;
1453 case EDID_DETAIL_EST_TIMINGS:
1454 modes += drm_est3_modes(connector, timing);
1455 break;
1456 default:
1457 break;
1458 } 1108 }
1459
1460 return modes;
1461} 1109}
1462 1110
1463/** 1111/**
1464 * add_detailed_info - get detailed mode info from EDID data 1112 * add_standard_modes - get std. modes from EDID and add them
1465 * @connector: attached connector
1466 * @edid: EDID block to scan 1113 * @edid: EDID block to scan
1467 * @quirks: quirks to apply
1468 * 1114 *
1469 * Some of the detailed timing sections may contain mode information. Grab 1115 * Standard modes can be calculated using the appropriate standard (DMT,
1470 * it and add it to the list. 1116 * GTF or CVT. Grab them from @edid and add them to the list.
1471 */ 1117 */
1472static int add_detailed_info(struct drm_connector *connector, 1118static int
1473 struct edid *edid, u32 quirks) 1119add_standard_modes(struct drm_connector *connector, struct edid *edid)
1474{ 1120{
1475 int i, modes = 0; 1121 int i, modes = 0;
1122 struct detailed_mode_closure closure = {
1123 connector, edid, 0, 0, 0
1124 };
1125
1126 for (i = 0; i < EDID_STD_TIMINGS; i++) {
1127 struct drm_display_mode *newmode;
1128
1129 newmode = drm_mode_std(connector, edid,
1130 &edid->standard_timings[i],
1131 edid->revision);
1132 if (newmode) {
1133 drm_mode_probed_add(connector, newmode);
1134 modes++;
1135 }
1136 }
1137
1138 if (version_greater(edid, 1, 0))
1139 drm_for_each_detailed_block((u8 *)edid, do_standard_modes,
1140 &closure);
1141
1142 /* XXX should also look for standard codes in VTB blocks */
1143
1144 return modes + closure.modes;
1145}
1476 1146
1477 for (i = 0; i < EDID_DETAILED_TIMINGS; i++) { 1147static int drm_cvt_modes(struct drm_connector *connector,
1478 struct detailed_timing *timing = &edid->detailed_timings[i]; 1148 struct detailed_timing *timing)
1479 int preferred = (i == 0); 1149{
1150 int i, j, modes = 0;
1151 struct drm_display_mode *newmode;
1152 struct drm_device *dev = connector->dev;
1153 struct cvt_timing *cvt;
1154 const int rates[] = { 60, 85, 75, 60, 50 };
1155 const u8 empty[3] = { 0, 0, 0 };
1480 1156
1481 if (preferred && edid->version == 1 && edid->revision < 4) 1157 for (i = 0; i < 4; i++) {
1482 preferred = (edid->features & DRM_EDID_FEATURE_PREFERRED_TIMING); 1158 int uninitialized_var(width), height;
1159 cvt = &(timing->data.other_data.data.cvt[i]);
1483 1160
1484 /* In 1.0, only timings are allowed */ 1161 if (!memcmp(cvt->code, empty, 3))
1485 if (!timing->pixel_clock && edid->version == 1 &&
1486 edid->revision == 0)
1487 continue; 1162 continue;
1488 1163
1489 modes += add_detailed_modes(connector, timing, edid, quirks, 1164 height = (cvt->code[0] + ((cvt->code[1] & 0xf0) << 4) + 1) * 2;
1490 preferred); 1165 switch (cvt->code[1] & 0x0c) {
1166 case 0x00:
1167 width = height * 4 / 3;
1168 break;
1169 case 0x04:
1170 width = height * 16 / 9;
1171 break;
1172 case 0x08:
1173 width = height * 16 / 10;
1174 break;
1175 case 0x0c:
1176 width = height * 15 / 9;
1177 break;
1178 }
1179
1180 for (j = 1; j < 5; j++) {
1181 if (cvt->code[2] & (1 << j)) {
1182 newmode = drm_cvt_mode(dev, width, height,
1183 rates[j], j == 0,
1184 false, false);
1185 if (newmode) {
1186 drm_mode_probed_add(connector, newmode);
1187 modes++;
1188 }
1189 }
1190 }
1491 } 1191 }
1492 1192
1493 return modes; 1193 return modes;
1494} 1194}
1495 1195
1496/** 1196static void
1497 * add_detailed_mode_eedid - get detailed mode info from addtional timing 1197do_cvt_mode(struct detailed_timing *timing, void *c)
1498 * EDID block
1499 * @connector: attached connector
1500 * @edid: EDID block to scan(It is only to get addtional timing EDID block)
1501 * @quirks: quirks to apply
1502 *
1503 * Some of the detailed timing sections may contain mode information. Grab
1504 * it and add it to the list.
1505 */
1506static int add_detailed_info_eedid(struct drm_connector *connector,
1507 struct edid *edid, u32 quirks)
1508{ 1198{
1509 int i, modes = 0; 1199 struct detailed_mode_closure *closure = c;
1510 char *edid_ext = NULL; 1200 struct detailed_non_pixel *data = &timing->data.other_data;
1511 struct detailed_timing *timing;
1512 int start_offset, end_offset;
1513 1201
1514 if (edid->version == 1 && edid->revision < 3) 1202 if (data->type == EDID_DETAIL_CVT_3BYTE)
1515 return 0; 1203 closure->modes += drm_cvt_modes(closure->connector, timing);
1516 if (!edid->extensions) 1204}
1517 return 0;
1518 1205
1519 /* Find CEA extension */ 1206static int
1520 for (i = 0; i < edid->extensions; i++) { 1207add_cvt_modes(struct drm_connector *connector, struct edid *edid)
1521 edid_ext = (char *)edid + EDID_LENGTH * (i + 1); 1208{
1522 if (edid_ext[0] == 0x02) 1209 struct detailed_mode_closure closure = {
1523 break; 1210 connector, edid, 0, 0, 0
1524 } 1211 };
1525 1212
1526 if (i == edid->extensions) 1213 if (version_greater(edid, 1, 2))
1527 return 0; 1214 drm_for_each_detailed_block((u8 *)edid, do_cvt_mode, &closure);
1528 1215
1529 /* Get the start offset of detailed timing block */ 1216 /* XXX should also look for CVT codes in VTB blocks */
1530 start_offset = edid_ext[2];
1531 if (start_offset == 0) {
1532 /* If the start_offset is zero, it means that neither detailed
1533 * info nor data block exist. In such case it is also
1534 * unnecessary to parse the detailed timing info.
1535 */
1536 return 0;
1537 }
1538 1217
1539 end_offset = EDID_LENGTH; 1218 return closure.modes;
1540 end_offset -= sizeof(struct detailed_timing); 1219}
1541 for (i = start_offset; i < end_offset; 1220
1542 i += sizeof(struct detailed_timing)) { 1221static void
1543 timing = (struct detailed_timing *)(edid_ext + i); 1222do_detailed_mode(struct detailed_timing *timing, void *c)
1544 modes += add_detailed_modes(connector, timing, edid, quirks, 0); 1223{
1224 struct detailed_mode_closure *closure = c;
1225 struct drm_display_mode *newmode;
1226
1227 if (timing->pixel_clock) {
1228 newmode = drm_mode_detailed(closure->connector->dev,
1229 closure->edid, timing,
1230 closure->quirks);
1231 if (!newmode)
1232 return;
1233
1234 if (closure->preferred)
1235 newmode->type |= DRM_MODE_TYPE_PREFERRED;
1236
1237 drm_mode_probed_add(closure->connector, newmode);
1238 closure->modes++;
1239 closure->preferred = 0;
1545 } 1240 }
1241}
1546 1242
1547 return modes; 1243/*
1244 * add_detailed_modes - Add modes from detailed timings
1245 * @connector: attached connector
1246 * @edid: EDID block to scan
1247 * @quirks: quirks to apply
1248 */
1249static int
1250add_detailed_modes(struct drm_connector *connector, struct edid *edid,
1251 u32 quirks)
1252{
1253 struct detailed_mode_closure closure = {
1254 connector,
1255 edid,
1256 1,
1257 quirks,
1258 0
1259 };
1260
1261 if (closure.preferred && !version_greater(edid, 1, 3))
1262 closure.preferred =
1263 (edid->features & DRM_EDID_FEATURE_PREFERRED_TIMING);
1264
1265 drm_for_each_detailed_block((u8 *)edid, do_detailed_mode, &closure);
1266
1267 return closure.modes;
1548} 1268}
1549 1269
1550#define HDMI_IDENTIFIER 0x000C03 1270#define HDMI_IDENTIFIER 0x000C03
@@ -1640,35 +1360,21 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
1640 * - established timing codes 1360 * - established timing codes
1641 * - modes inferred from GTF or CVT range information 1361 * - modes inferred from GTF or CVT range information
1642 * 1362 *
1643 * We don't quite implement this yet, but we're close. 1363 * We get this pretty much right.
1644 * 1364 *
1645 * XXX order for additional mode types in extension blocks? 1365 * XXX order for additional mode types in extension blocks?
1646 */ 1366 */
1647 num_modes += add_detailed_info(connector, edid, quirks); 1367 num_modes += add_detailed_modes(connector, edid, quirks);
1648 num_modes += add_detailed_info_eedid(connector, edid, quirks); 1368 num_modes += add_cvt_modes(connector, edid);
1649 num_modes += add_standard_modes(connector, edid); 1369 num_modes += add_standard_modes(connector, edid);
1650 num_modes += add_established_modes(connector, edid); 1370 num_modes += add_established_modes(connector, edid);
1371 num_modes += add_inferred_modes(connector, edid);
1651 1372
1652 if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75)) 1373 if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75))
1653 edid_fixup_preferred(connector, quirks); 1374 edid_fixup_preferred(connector, quirks);
1654 1375
1655 connector->display_info.serration_vsync = (edid->input & DRM_EDID_INPUT_SERRATION_VSYNC) ? 1 : 0;
1656 connector->display_info.sync_on_green = (edid->input & DRM_EDID_INPUT_SYNC_ON_GREEN) ? 1 : 0;
1657 connector->display_info.composite_sync = (edid->input & DRM_EDID_INPUT_COMPOSITE_SYNC) ? 1 : 0;
1658 connector->display_info.separate_syncs = (edid->input & DRM_EDID_INPUT_SEPARATE_SYNCS) ? 1 : 0;
1659 connector->display_info.blank_to_black = (edid->input & DRM_EDID_INPUT_BLANK_TO_BLACK) ? 1 : 0;
1660 connector->display_info.video_level = (edid->input & DRM_EDID_INPUT_VIDEO_LEVEL) >> 5;
1661 connector->display_info.digital = (edid->input & DRM_EDID_INPUT_DIGITAL) ? 1 : 0;
1662 connector->display_info.width_mm = edid->width_cm * 10; 1376 connector->display_info.width_mm = edid->width_cm * 10;
1663 connector->display_info.height_mm = edid->height_cm * 10; 1377 connector->display_info.height_mm = edid->height_cm * 10;
1664 connector->display_info.gamma = edid->gamma;
1665 connector->display_info.gtf_supported = (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF) ? 1 : 0;
1666 connector->display_info.standard_color = (edid->features & DRM_EDID_FEATURE_STANDARD_COLOR) ? 1 : 0;
1667 connector->display_info.display_type = (edid->features & DRM_EDID_FEATURE_DISPLAY_TYPE) >> 3;
1668 connector->display_info.active_off_supported = (edid->features & DRM_EDID_FEATURE_PM_ACTIVE_OFF) ? 1 : 0;
1669 connector->display_info.suspend_supported = (edid->features & DRM_EDID_FEATURE_PM_SUSPEND) ? 1 : 0;
1670 connector->display_info.standby_supported = (edid->features & DRM_EDID_FEATURE_PM_STANDBY) ? 1 : 0;
1671 connector->display_info.gamma = edid->gamma;
1672 1378
1673 return num_modes; 1379 return num_modes;
1674} 1380}