diff options
author | Dave Airlie <airlied@redhat.com> | 2009-12-07 22:52:41 -0500 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2009-12-07 22:52:41 -0500 |
commit | 1bd049fa895f9c6743f38b52ce14775f5a31ea63 (patch) | |
tree | cb9163ac1c20f7fbdbde42eaab8013d0c3734aed /drivers/gpu/drm/drm_edid.c | |
parent | 22763c5cf3690a681551162c15d34d935308c8d7 (diff) | |
parent | b0a007dc27d8d3ff3db07b3ea997323d9330f770 (diff) |
Merge branch 'drm-core-next' into drm-linus
Bring all core drm changes into 2.6.32 tree and resolve
the conflict that occurs.
Conflicts:
drivers/gpu/drm/drm_fb_helper.c
Diffstat (limited to 'drivers/gpu/drm/drm_edid.c')
-rw-r--r-- | drivers/gpu/drm/drm_edid.c | 328 |
1 files changed, 204 insertions, 124 deletions
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index b54ba63d506e..c39b26f1abed 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c | |||
@@ -123,18 +123,20 @@ static const u8 edid_header[] = { | |||
123 | */ | 123 | */ |
124 | static bool edid_is_valid(struct edid *edid) | 124 | static bool edid_is_valid(struct edid *edid) |
125 | { | 125 | { |
126 | int i; | 126 | int i, score = 0; |
127 | u8 csum = 0; | 127 | u8 csum = 0; |
128 | u8 *raw_edid = (u8 *)edid; | 128 | u8 *raw_edid = (u8 *)edid; |
129 | 129 | ||
130 | if (memcmp(edid->header, edid_header, sizeof(edid_header))) | 130 | for (i = 0; i < sizeof(edid_header); i++) |
131 | goto bad; | 131 | if (raw_edid[i] == edid_header[i]) |
132 | if (edid->version != 1) { | 132 | score++; |
133 | DRM_ERROR("EDID has major version %d, instead of 1\n", edid->version); | 133 | |
134 | if (score == 8) ; | ||
135 | else if (score >= 6) { | ||
136 | DRM_DEBUG("Fixing EDID header, your hardware may be failing\n"); | ||
137 | memcpy(raw_edid, edid_header, sizeof(edid_header)); | ||
138 | } else | ||
134 | goto bad; | 139 | goto bad; |
135 | } | ||
136 | if (edid->revision > 4) | ||
137 | DRM_DEBUG("EDID minor > 4, assuming backward compatibility\n"); | ||
138 | 140 | ||
139 | for (i = 0; i < EDID_LENGTH; i++) | 141 | for (i = 0; i < EDID_LENGTH; i++) |
140 | csum += raw_edid[i]; | 142 | csum += raw_edid[i]; |
@@ -143,6 +145,14 @@ static bool edid_is_valid(struct edid *edid) | |||
143 | goto bad; | 145 | goto bad; |
144 | } | 146 | } |
145 | 147 | ||
148 | if (edid->version != 1) { | ||
149 | DRM_ERROR("EDID has major version %d, instead of 1\n", edid->version); | ||
150 | goto bad; | ||
151 | } | ||
152 | |||
153 | if (edid->revision > 4) | ||
154 | DRM_DEBUG("EDID minor > 4, assuming backward compatibility\n"); | ||
155 | |||
146 | return 1; | 156 | return 1; |
147 | 157 | ||
148 | bad: | 158 | bad: |
@@ -481,16 +491,17 @@ static struct drm_display_mode drm_dmt_modes[] = { | |||
481 | 3048, 3536, 0, 1600, 1603, 1609, 1682, 0, | 491 | 3048, 3536, 0, 1600, 1603, 1609, 1682, 0, |
482 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, | 492 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
483 | }; | 493 | }; |
494 | static const int drm_num_dmt_modes = | ||
495 | sizeof(drm_dmt_modes) / sizeof(struct drm_display_mode); | ||
484 | 496 | ||
485 | static struct drm_display_mode *drm_find_dmt(struct drm_device *dev, | 497 | static struct drm_display_mode *drm_find_dmt(struct drm_device *dev, |
486 | int hsize, int vsize, int fresh) | 498 | int hsize, int vsize, int fresh) |
487 | { | 499 | { |
488 | int i, count; | 500 | int i; |
489 | struct drm_display_mode *ptr, *mode; | 501 | struct drm_display_mode *ptr, *mode; |
490 | 502 | ||
491 | count = sizeof(drm_dmt_modes) / sizeof(struct drm_display_mode); | ||
492 | mode = NULL; | 503 | mode = NULL; |
493 | for (i = 0; i < count; i++) { | 504 | for (i = 0; i < drm_num_dmt_modes; i++) { |
494 | ptr = &drm_dmt_modes[i]; | 505 | ptr = &drm_dmt_modes[i]; |
495 | if (hsize == ptr->hdisplay && | 506 | if (hsize == ptr->hdisplay && |
496 | vsize == ptr->vdisplay && | 507 | vsize == ptr->vdisplay && |
@@ -834,8 +845,165 @@ static int add_standard_modes(struct drm_connector *connector, struct edid *edid | |||
834 | return modes; | 845 | return modes; |
835 | } | 846 | } |
836 | 847 | ||
848 | /* | ||
849 | * XXX fix this for: | ||
850 | * - GTF secondary curve formula | ||
851 | * - EDID 1.4 range offsets | ||
852 | * - CVT extended bits | ||
853 | */ | ||
854 | static bool | ||
855 | mode_in_range(struct drm_display_mode *mode, struct detailed_timing *timing) | ||
856 | { | ||
857 | struct detailed_data_monitor_range *range; | ||
858 | int hsync, vrefresh; | ||
859 | |||
860 | range = &timing->data.other_data.data.range; | ||
861 | |||
862 | hsync = drm_mode_hsync(mode); | ||
863 | vrefresh = drm_mode_vrefresh(mode); | ||
864 | |||
865 | if (hsync < range->min_hfreq_khz || hsync > range->max_hfreq_khz) | ||
866 | return false; | ||
867 | |||
868 | if (vrefresh < range->min_vfreq || vrefresh > range->max_vfreq) | ||
869 | return false; | ||
870 | |||
871 | if (range->pixel_clock_mhz && range->pixel_clock_mhz != 0xff) { | ||
872 | /* be forgiving since it's in units of 10MHz */ | ||
873 | int max_clock = range->pixel_clock_mhz * 10 + 9; | ||
874 | max_clock *= 1000; | ||
875 | if (mode->clock > max_clock) | ||
876 | return false; | ||
877 | } | ||
878 | |||
879 | return true; | ||
880 | } | ||
881 | |||
882 | /* | ||
883 | * XXX If drm_dmt_modes ever regrows the CVT-R modes (and it will) this will | ||
884 | * need to account for them. | ||
885 | */ | ||
886 | static int drm_gtf_modes_for_range(struct drm_connector *connector, | ||
887 | struct detailed_timing *timing) | ||
888 | { | ||
889 | int i, modes = 0; | ||
890 | struct drm_display_mode *newmode; | ||
891 | struct drm_device *dev = connector->dev; | ||
892 | |||
893 | for (i = 0; i < drm_num_dmt_modes; i++) { | ||
894 | if (mode_in_range(drm_dmt_modes + i, timing)) { | ||
895 | newmode = drm_mode_duplicate(dev, &drm_dmt_modes[i]); | ||
896 | if (newmode) { | ||
897 | drm_mode_probed_add(connector, newmode); | ||
898 | modes++; | ||
899 | } | ||
900 | } | ||
901 | } | ||
902 | |||
903 | return modes; | ||
904 | } | ||
905 | |||
906 | static int drm_cvt_modes(struct drm_connector *connector, | ||
907 | struct detailed_timing *timing) | ||
908 | { | ||
909 | int i, j, modes = 0; | ||
910 | struct drm_display_mode *newmode; | ||
911 | struct drm_device *dev = connector->dev; | ||
912 | struct cvt_timing *cvt; | ||
913 | const int rates[] = { 60, 85, 75, 60, 50 }; | ||
914 | |||
915 | for (i = 0; i < 4; i++) { | ||
916 | int width, height; | ||
917 | cvt = &(timing->data.other_data.data.cvt[i]); | ||
918 | |||
919 | height = (cvt->code[0] + ((cvt->code[1] & 0xf0) << 8) + 1) * 2; | ||
920 | switch (cvt->code[1] & 0xc0) { | ||
921 | case 0x00: | ||
922 | width = height * 4 / 3; | ||
923 | break; | ||
924 | case 0x40: | ||
925 | width = height * 16 / 9; | ||
926 | break; | ||
927 | case 0x80: | ||
928 | width = height * 16 / 10; | ||
929 | break; | ||
930 | case 0xc0: | ||
931 | width = height * 15 / 9; | ||
932 | break; | ||
933 | } | ||
934 | |||
935 | for (j = 1; j < 5; j++) { | ||
936 | if (cvt->code[2] & (1 << j)) { | ||
937 | newmode = drm_cvt_mode(dev, width, height, | ||
938 | rates[j], j == 0, | ||
939 | false, false); | ||
940 | if (newmode) { | ||
941 | drm_mode_probed_add(connector, newmode); | ||
942 | modes++; | ||
943 | } | ||
944 | } | ||
945 | } | ||
946 | } | ||
947 | |||
948 | return modes; | ||
949 | } | ||
950 | |||
951 | static int add_detailed_modes(struct drm_connector *connector, | ||
952 | struct detailed_timing *timing, | ||
953 | struct edid *edid, u32 quirks, int preferred) | ||
954 | { | ||
955 | int i, modes = 0; | ||
956 | struct detailed_non_pixel *data = &timing->data.other_data; | ||
957 | int timing_level = standard_timing_level(edid); | ||
958 | int gtf = (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF); | ||
959 | struct drm_display_mode *newmode; | ||
960 | struct drm_device *dev = connector->dev; | ||
961 | |||
962 | if (timing->pixel_clock) { | ||
963 | newmode = drm_mode_detailed(dev, edid, timing, quirks); | ||
964 | if (!newmode) | ||
965 | return 0; | ||
966 | |||
967 | if (preferred) | ||
968 | newmode->type |= DRM_MODE_TYPE_PREFERRED; | ||
969 | |||
970 | drm_mode_probed_add(connector, newmode); | ||
971 | return 1; | ||
972 | } | ||
973 | |||
974 | /* other timing types */ | ||
975 | switch (data->type) { | ||
976 | case EDID_DETAIL_MONITOR_RANGE: | ||
977 | if (gtf) | ||
978 | modes += drm_gtf_modes_for_range(connector, timing); | ||
979 | break; | ||
980 | case EDID_DETAIL_STD_MODES: | ||
981 | /* Six modes per detailed section */ | ||
982 | for (i = 0; i < 6; i++) { | ||
983 | struct std_timing *std; | ||
984 | struct drm_display_mode *newmode; | ||
985 | |||
986 | std = &data->data.timings[i]; | ||
987 | newmode = drm_mode_std(dev, std, edid->revision, | ||
988 | timing_level); | ||
989 | if (newmode) { | ||
990 | drm_mode_probed_add(connector, newmode); | ||
991 | modes++; | ||
992 | } | ||
993 | } | ||
994 | break; | ||
995 | case EDID_DETAIL_CVT_3BYTE: | ||
996 | modes += drm_cvt_modes(connector, timing); | ||
997 | break; | ||
998 | default: | ||
999 | break; | ||
1000 | } | ||
1001 | |||
1002 | return modes; | ||
1003 | } | ||
1004 | |||
837 | /** | 1005 | /** |
838 | * add_detailed_modes - get detailed mode info from EDID data | 1006 | * add_detailed_info - get detailed mode info from EDID data |
839 | * @connector: attached connector | 1007 | * @connector: attached connector |
840 | * @edid: EDID block to scan | 1008 | * @edid: EDID block to scan |
841 | * @quirks: quirks to apply | 1009 | * @quirks: quirks to apply |
@@ -846,67 +1014,24 @@ static int add_standard_modes(struct drm_connector *connector, struct edid *edid | |||
846 | static int add_detailed_info(struct drm_connector *connector, | 1014 | static int add_detailed_info(struct drm_connector *connector, |
847 | struct edid *edid, u32 quirks) | 1015 | struct edid *edid, u32 quirks) |
848 | { | 1016 | { |
849 | struct drm_device *dev = connector->dev; | 1017 | int i, modes = 0; |
850 | int i, j, modes = 0; | ||
851 | int timing_level; | ||
852 | |||
853 | timing_level = standard_timing_level(edid); | ||
854 | 1018 | ||
855 | for (i = 0; i < EDID_DETAILED_TIMINGS; i++) { | 1019 | for (i = 0; i < EDID_DETAILED_TIMINGS; i++) { |
856 | struct detailed_timing *timing = &edid->detailed_timings[i]; | 1020 | struct detailed_timing *timing = &edid->detailed_timings[i]; |
857 | struct detailed_non_pixel *data = &timing->data.other_data; | 1021 | int preferred = (i == 0) && (edid->features & DRM_EDID_FEATURE_PREFERRED_TIMING); |
858 | struct drm_display_mode *newmode; | ||
859 | |||
860 | /* X server check is version 1.1 or higher */ | ||
861 | if (edid->version == 1 && edid->revision >= 1 && | ||
862 | !timing->pixel_clock) { | ||
863 | /* Other timing or info */ | ||
864 | switch (data->type) { | ||
865 | case EDID_DETAIL_MONITOR_SERIAL: | ||
866 | break; | ||
867 | case EDID_DETAIL_MONITOR_STRING: | ||
868 | break; | ||
869 | case EDID_DETAIL_MONITOR_RANGE: | ||
870 | /* Get monitor range data */ | ||
871 | break; | ||
872 | case EDID_DETAIL_MONITOR_NAME: | ||
873 | break; | ||
874 | case EDID_DETAIL_MONITOR_CPDATA: | ||
875 | break; | ||
876 | case EDID_DETAIL_STD_MODES: | ||
877 | for (j = 0; j < 6; i++) { | ||
878 | struct std_timing *std; | ||
879 | struct drm_display_mode *newmode; | ||
880 | |||
881 | std = &data->data.timings[j]; | ||
882 | newmode = drm_mode_std(dev, std, | ||
883 | edid->revision, | ||
884 | timing_level); | ||
885 | if (newmode) { | ||
886 | drm_mode_probed_add(connector, newmode); | ||
887 | modes++; | ||
888 | } | ||
889 | } | ||
890 | break; | ||
891 | default: | ||
892 | break; | ||
893 | } | ||
894 | } else { | ||
895 | newmode = drm_mode_detailed(dev, edid, timing, quirks); | ||
896 | if (!newmode) | ||
897 | continue; | ||
898 | 1022 | ||
899 | /* First detailed mode is preferred */ | 1023 | /* In 1.0, only timings are allowed */ |
900 | if (i == 0 && (edid->features & DRM_EDID_FEATURE_PREFERRED_TIMING)) | 1024 | if (!timing->pixel_clock && edid->version == 1 && |
901 | newmode->type |= DRM_MODE_TYPE_PREFERRED; | 1025 | edid->revision == 0) |
902 | drm_mode_probed_add(connector, newmode); | 1026 | continue; |
903 | 1027 | ||
904 | modes++; | 1028 | modes += add_detailed_modes(connector, timing, edid, quirks, |
905 | } | 1029 | preferred); |
906 | } | 1030 | } |
907 | 1031 | ||
908 | return modes; | 1032 | return modes; |
909 | } | 1033 | } |
1034 | |||
910 | /** | 1035 | /** |
911 | * add_detailed_mode_eedid - get detailed mode info from addtional timing | 1036 | * add_detailed_mode_eedid - get detailed mode info from addtional timing |
912 | * EDID block | 1037 | * EDID block |
@@ -920,12 +1045,9 @@ static int add_detailed_info(struct drm_connector *connector, | |||
920 | static int add_detailed_info_eedid(struct drm_connector *connector, | 1045 | static int add_detailed_info_eedid(struct drm_connector *connector, |
921 | struct edid *edid, u32 quirks) | 1046 | struct edid *edid, u32 quirks) |
922 | { | 1047 | { |
923 | struct drm_device *dev = connector->dev; | 1048 | int i, modes = 0; |
924 | int i, j, modes = 0; | ||
925 | char *edid_ext = NULL; | 1049 | char *edid_ext = NULL; |
926 | struct detailed_timing *timing; | 1050 | struct detailed_timing *timing; |
927 | struct detailed_non_pixel *data; | ||
928 | struct drm_display_mode *newmode; | ||
929 | int edid_ext_num; | 1051 | int edid_ext_num; |
930 | int start_offset, end_offset; | 1052 | int start_offset, end_offset; |
931 | int timing_level; | 1053 | int timing_level; |
@@ -976,51 +1098,7 @@ static int add_detailed_info_eedid(struct drm_connector *connector, | |||
976 | for (i = start_offset; i < end_offset; | 1098 | for (i = start_offset; i < end_offset; |
977 | i += sizeof(struct detailed_timing)) { | 1099 | i += sizeof(struct detailed_timing)) { |
978 | timing = (struct detailed_timing *)(edid_ext + i); | 1100 | timing = (struct detailed_timing *)(edid_ext + i); |
979 | data = &timing->data.other_data; | 1101 | modes += add_detailed_modes(connector, timing, edid, quirks, 0); |
980 | /* Detailed mode timing */ | ||
981 | if (timing->pixel_clock) { | ||
982 | newmode = drm_mode_detailed(dev, edid, timing, quirks); | ||
983 | if (!newmode) | ||
984 | continue; | ||
985 | |||
986 | drm_mode_probed_add(connector, newmode); | ||
987 | |||
988 | modes++; | ||
989 | continue; | ||
990 | } | ||
991 | |||
992 | /* Other timing or info */ | ||
993 | switch (data->type) { | ||
994 | case EDID_DETAIL_MONITOR_SERIAL: | ||
995 | break; | ||
996 | case EDID_DETAIL_MONITOR_STRING: | ||
997 | break; | ||
998 | case EDID_DETAIL_MONITOR_RANGE: | ||
999 | /* Get monitor range data */ | ||
1000 | break; | ||
1001 | case EDID_DETAIL_MONITOR_NAME: | ||
1002 | break; | ||
1003 | case EDID_DETAIL_MONITOR_CPDATA: | ||
1004 | break; | ||
1005 | case EDID_DETAIL_STD_MODES: | ||
1006 | /* Five modes per detailed section */ | ||
1007 | for (j = 0; j < 5; i++) { | ||
1008 | struct std_timing *std; | ||
1009 | struct drm_display_mode *newmode; | ||
1010 | |||
1011 | std = &data->data.timings[j]; | ||
1012 | newmode = drm_mode_std(dev, std, | ||
1013 | edid->revision, | ||
1014 | timing_level); | ||
1015 | if (newmode) { | ||
1016 | drm_mode_probed_add(connector, newmode); | ||
1017 | modes++; | ||
1018 | } | ||
1019 | } | ||
1020 | break; | ||
1021 | default: | ||
1022 | break; | ||
1023 | } | ||
1024 | } | 1102 | } |
1025 | 1103 | ||
1026 | return modes; | 1104 | return modes; |
@@ -1066,19 +1144,19 @@ static int drm_ddc_read_edid(struct drm_connector *connector, | |||
1066 | struct i2c_adapter *adapter, | 1144 | struct i2c_adapter *adapter, |
1067 | char *buf, int len) | 1145 | char *buf, int len) |
1068 | { | 1146 | { |
1069 | int ret; | 1147 | int i; |
1070 | 1148 | ||
1071 | ret = drm_do_probe_ddc_edid(adapter, buf, len); | 1149 | for (i = 0; i < 4; i++) { |
1072 | if (ret != 0) { | 1150 | if (drm_do_probe_ddc_edid(adapter, buf, len)) |
1073 | goto end; | 1151 | return -1; |
1074 | } | 1152 | if (edid_is_valid((struct edid *)buf)) |
1075 | if (!edid_is_valid((struct edid *)buf)) { | 1153 | return 0; |
1076 | dev_warn(&connector->dev->pdev->dev, "%s: EDID invalid.\n", | ||
1077 | drm_get_connector_name(connector)); | ||
1078 | ret = -1; | ||
1079 | } | 1154 | } |
1080 | end: | 1155 | |
1081 | return ret; | 1156 | /* repeated checksum failures; warn, but carry on */ |
1157 | dev_warn(&connector->dev->pdev->dev, "%s: EDID invalid.\n", | ||
1158 | drm_get_connector_name(connector)); | ||
1159 | return -1; | ||
1082 | } | 1160 | } |
1083 | 1161 | ||
1084 | /** | 1162 | /** |
@@ -1296,6 +1374,8 @@ int drm_add_modes_noedid(struct drm_connector *connector, | |||
1296 | ptr->vdisplay > vdisplay) | 1374 | ptr->vdisplay > vdisplay) |
1297 | continue; | 1375 | continue; |
1298 | } | 1376 | } |
1377 | if (drm_mode_vrefresh(ptr) > 61) | ||
1378 | continue; | ||
1299 | mode = drm_mode_duplicate(dev, ptr); | 1379 | mode = drm_mode_duplicate(dev, ptr); |
1300 | if (mode) { | 1380 | if (mode) { |
1301 | drm_mode_probed_add(connector, mode); | 1381 | drm_mode_probed_add(connector, mode); |