aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/drm_edid.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/drm_edid.c')
-rw-r--r--drivers/gpu/drm/drm_edid.c64
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 */
609static void
610drm_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 }