diff options
Diffstat (limited to 'drivers/gpu/drm/drm_edid.c')
| -rw-r--r-- | drivers/gpu/drm/drm_edid.c | 47 |
1 files changed, 45 insertions, 2 deletions
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index f665b05592f3..ab6c97330412 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c | |||
| @@ -598,6 +598,50 @@ struct drm_display_mode *drm_mode_std(struct drm_device *dev, | |||
| 598 | return mode; | 598 | return mode; |
| 599 | } | 599 | } |
| 600 | 600 | ||
| 601 | /* | ||
| 602 | * EDID is delightfully ambiguous about how interlaced modes are to be | ||
| 603 | * encoded. Our internal representation is of frame height, but some | ||
| 604 | * HDTV detailed timings are encoded as field height. | ||
| 605 | * | ||
| 606 | * The format list here is from CEA, in frame size. Technically we | ||
| 607 | * should be checking refresh rate too. Whatever. | ||
| 608 | */ | ||
| 609 | static void | ||
| 610 | drm_mode_do_interlace_quirk(struct drm_display_mode *mode, | ||
| 611 | struct detailed_pixel_timing *pt) | ||
| 612 | { | ||
| 613 | int i; | ||
| 614 | static const struct { | ||
| 615 | int w, h; | ||
| 616 | } cea_interlaced[] = { | ||
| 617 | { 1920, 1080 }, | ||
| 618 | { 720, 480 }, | ||
| 619 | { 1440, 480 }, | ||
| 620 | { 2880, 480 }, | ||
| 621 | { 720, 576 }, | ||
| 622 | { 1440, 576 }, | ||
| 623 | { 2880, 576 }, | ||
| 624 | }; | ||
| 625 | static const int n_sizes = | ||
| 626 | sizeof(cea_interlaced)/sizeof(cea_interlaced[0]); | ||
| 627 | |||
| 628 | if (!(pt->misc & DRM_EDID_PT_INTERLACED)) | ||
| 629 | return; | ||
| 630 | |||
| 631 | for (i = 0; i < n_sizes; i++) { | ||
| 632 | if ((mode->hdisplay == cea_interlaced[i].w) && | ||
| 633 | (mode->vdisplay == cea_interlaced[i].h / 2)) { | ||
| 634 | mode->vdisplay *= 2; | ||
| 635 | mode->vsync_start *= 2; | ||
| 636 | mode->vsync_end *= 2; | ||
| 637 | mode->vtotal *= 2; | ||
| 638 | mode->vtotal |= 1; | ||
| 639 | } | ||
| 640 | } | ||
| 641 | |||
| 642 | mode->flags |= DRM_MODE_FLAG_INTERLACE; | ||
| 643 | } | ||
| 644 | |||
| 601 | /** | 645 | /** |
| 602 | * drm_mode_detailed - create a new mode from an EDID detailed timing section | 646 | * drm_mode_detailed - create a new mode from an EDID detailed timing section |
| 603 | * @dev: DRM device (needed to create new mode) | 647 | * @dev: DRM device (needed to create new mode) |
| @@ -680,8 +724,7 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, | |||
| 680 | 724 | ||
| 681 | drm_mode_set_name(mode); | 725 | drm_mode_set_name(mode); |
| 682 | 726 | ||
| 683 | if (pt->misc & DRM_EDID_PT_INTERLACED) | 727 | drm_mode_do_interlace_quirk(mode, pt); |
| 684 | mode->flags |= DRM_MODE_FLAG_INTERLACE; | ||
| 685 | 728 | ||
| 686 | if (quirks & EDID_QUIRK_DETAILED_SYNC_PP) { | 729 | if (quirks & EDID_QUIRK_DETAILED_SYNC_PP) { |
| 687 | pt->misc |= DRM_EDID_PT_HSYNC_POSITIVE | DRM_EDID_PT_VSYNC_POSITIVE; | 730 | pt->misc |= DRM_EDID_PT_HSYNC_POSITIVE | DRM_EDID_PT_VSYNC_POSITIVE; |
