diff options
Diffstat (limited to 'drivers/gpu/drm/drm_edid.c')
-rw-r--r-- | drivers/gpu/drm/drm_edid.c | 64 |
1 files changed, 55 insertions, 9 deletions
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 5c9f79877cb..ab6c9733041 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) |
@@ -633,8 +677,7 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, | |||
633 | return NULL; | 677 | return NULL; |
634 | } | 678 | } |
635 | if (!(pt->misc & DRM_EDID_PT_SEPARATE_SYNC)) { | 679 | if (!(pt->misc & DRM_EDID_PT_SEPARATE_SYNC)) { |
636 | printk(KERN_WARNING "integrated sync not supported\n"); | 680 | printk(KERN_WARNING "composite sync not supported\n"); |
637 | return NULL; | ||
638 | } | 681 | } |
639 | 682 | ||
640 | /* it is incorrect if hsync/vsync width is zero */ | 683 | /* it is incorrect if hsync/vsync width is zero */ |
@@ -681,8 +724,7 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, | |||
681 | 724 | ||
682 | drm_mode_set_name(mode); | 725 | drm_mode_set_name(mode); |
683 | 726 | ||
684 | if (pt->misc & DRM_EDID_PT_INTERLACED) | 727 | drm_mode_do_interlace_quirk(mode, pt); |
685 | mode->flags |= DRM_MODE_FLAG_INTERLACE; | ||
686 | 728 | ||
687 | if (quirks & EDID_QUIRK_DETAILED_SYNC_PP) { | 729 | if (quirks & EDID_QUIRK_DETAILED_SYNC_PP) { |
688 | 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; |
@@ -911,23 +953,27 @@ static int drm_cvt_modes(struct drm_connector *connector, | |||
911 | struct drm_device *dev = connector->dev; | 953 | struct drm_device *dev = connector->dev; |
912 | struct cvt_timing *cvt; | 954 | struct cvt_timing *cvt; |
913 | const int rates[] = { 60, 85, 75, 60, 50 }; | 955 | const int rates[] = { 60, 85, 75, 60, 50 }; |
956 | const u8 empty[3] = { 0, 0, 0 }; | ||
914 | 957 | ||
915 | for (i = 0; i < 4; i++) { | 958 | for (i = 0; i < 4; i++) { |
916 | int uninitialized_var(width), height; | 959 | int uninitialized_var(width), height; |
917 | cvt = &(timing->data.other_data.data.cvt[i]); | 960 | cvt = &(timing->data.other_data.data.cvt[i]); |
918 | 961 | ||
919 | height = (cvt->code[0] + ((cvt->code[1] & 0xf0) << 8) + 1) * 2; | 962 | if (!memcmp(cvt->code, empty, 3)) |
920 | switch (cvt->code[1] & 0xc0) { | 963 | continue; |
964 | |||
965 | height = (cvt->code[0] + ((cvt->code[1] & 0xf0) << 4) + 1) * 2; | ||
966 | switch (cvt->code[1] & 0x0c) { | ||
921 | case 0x00: | 967 | case 0x00: |
922 | width = height * 4 / 3; | 968 | width = height * 4 / 3; |
923 | break; | 969 | break; |
924 | case 0x40: | 970 | case 0x04: |
925 | width = height * 16 / 9; | 971 | width = height * 16 / 9; |
926 | break; | 972 | break; |
927 | case 0x80: | 973 | case 0x08: |
928 | width = height * 16 / 10; | 974 | width = height * 16 / 10; |
929 | break; | 975 | break; |
930 | case 0xc0: | 976 | case 0x0c: |
931 | width = height * 15 / 9; | 977 | width = height * 15 / 9; |
932 | break; | 978 | break; |
933 | } | 979 | } |