diff options
Diffstat (limited to 'drivers/gpu/drm/drm_edid.c')
| -rw-r--r-- | drivers/gpu/drm/drm_edid.c | 840 |
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 | ||
| 70 | struct 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 | */ | ||
| 430 | static 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 | }; | ||
| 661 | static const int drm_num_dmt_modes = | ||
| 662 | sizeof(drm_dmt_modes) / sizeof(struct drm_display_mode); | ||
| 663 | |||
| 664 | struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev, | 436 | struct 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); | |||
| 685 | typedef void detailed_cb(struct detailed_timing *timing, void *closure); | 457 | typedef void detailed_cb(struct detailed_timing *timing, void *closure); |
| 686 | 458 | ||
| 687 | static void | 459 | static void |
| 460 | cea_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 | |||
| 486 | static void | ||
| 487 | vtb_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 | |||
| 499 | static void | ||
| 688 | drm_for_each_detailed_block(u8 *raw_edid, detailed_cb *cb, void *closure) | 500 | drm_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 | ||
| 702 | static void | 526 | static 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 | */ | ||
| 1053 | static 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 | */ | ||
| 1114 | static 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 | */ | ||
| 1142 | static 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 | |||
| 1161 | static bool | 874 | static bool |
| 1162 | mode_is_rb(struct drm_display_mode *mode) | 875 | mode_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 | ||
| 1270 | static int drm_cvt_modes(struct drm_connector *connector, | 983 | static void |
| 1271 | struct detailed_timing *timing) | 984 | do_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; | 996 | static int |
| 1288 | switch (cvt->code[1] & 0x0c) { | 997 | add_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 | ||
| 1319 | static 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 | |||
| 1377 | static int | 1010 | static int |
| 1378 | drm_est3_modes(struct drm_connector *connector, struct detailed_timing *timing) | 1011 | drm_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 | ||
| 1406 | static int add_detailed_modes(struct drm_connector *connector, | 1039 | static void |
| 1407 | struct detailed_timing *timing, | 1040 | do_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 | */ | ||
| 1056 | static int | ||
| 1057 | add_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: | 1086 | static void |
| 1436 | /* Six modes per detailed section */ | 1087 | do_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 | */ |
| 1472 | static int add_detailed_info(struct drm_connector *connector, | 1118 | static int |
| 1473 | struct edid *edid, u32 quirks) | 1119 | add_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++) { | 1147 | static 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 | /** | 1196 | static void |
| 1497 | * add_detailed_mode_eedid - get detailed mode info from addtional timing | 1197 | do_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 | */ | ||
| 1506 | static 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 */ | 1206 | static int |
| 1520 | for (i = 0; i < edid->extensions; i++) { | 1207 | add_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)) { | 1221 | static void |
| 1543 | timing = (struct detailed_timing *)(edid_ext + i); | 1222 | do_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 | */ | ||
| 1249 | static int | ||
| 1250 | add_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 | } |
