aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Jackson <ajax@redhat.com>2009-12-03 17:44:36 -0500
committerDave Airlie <airlied@redhat.com>2009-12-03 17:53:07 -0500
commit9cf00977da092096c7a983276dad8b3002d23a99 (patch)
tree1411812071df84b69cf731d9ebc2eb415457f5c9
parent9632b41f00cc2fb2846569cc99dbeef78e5c94a0 (diff)
drm/edid: Unify detailed block parsing between base and extension blocks
Also fix an embarassing bug in standard timing subblock parsing that would result in an infinite loop. Signed-off-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
-rw-r--r--drivers/gpu/drm/drm_edid.c163
1 files changed, 61 insertions, 102 deletions
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index bdea31308236..999571ab0b69 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -838,8 +838,57 @@ static int add_standard_modes(struct drm_connector *connector, struct edid *edid
838 return modes; 838 return modes;
839} 839}
840 840
841static int add_detailed_modes(struct drm_connector *connector,
842 struct detailed_timing *timing,
843 struct edid *edid, u32 quirks, int preferred)
844{
845 int i, modes = 0;
846 struct detailed_non_pixel *data = &timing->data.other_data;
847 int timing_level = standard_timing_level(edid);
848 struct drm_display_mode *newmode;
849 struct drm_device *dev = connector->dev;
850
851 if (timing->pixel_clock) {
852 newmode = drm_mode_detailed(dev, edid, timing, quirks);
853 if (!newmode)
854 return 0;
855
856 if (preferred)
857 newmode->type |= DRM_MODE_TYPE_PREFERRED;
858
859 drm_mode_probed_add(connector, newmode);
860 return 1;
861 }
862
863 /* other timing types */
864 switch (data->type) {
865 case EDID_DETAIL_MONITOR_RANGE:
866 /* Get monitor range data */
867 break;
868 case EDID_DETAIL_STD_MODES:
869 /* Six modes per detailed section */
870 for (i = 0; i < 6; i++) {
871 struct std_timing *std;
872 struct drm_display_mode *newmode;
873
874 std = &data->data.timings[i];
875 newmode = drm_mode_std(dev, std, edid->revision,
876 timing_level);
877 if (newmode) {
878 drm_mode_probed_add(connector, newmode);
879 modes++;
880 }
881 }
882 break;
883 default:
884 break;
885 }
886
887 return modes;
888}
889
841/** 890/**
842 * add_detailed_modes - get detailed mode info from EDID data 891 * add_detailed_info - get detailed mode info from EDID data
843 * @connector: attached connector 892 * @connector: attached connector
844 * @edid: EDID block to scan 893 * @edid: EDID block to scan
845 * @quirks: quirks to apply 894 * @quirks: quirks to apply
@@ -850,67 +899,24 @@ static int add_standard_modes(struct drm_connector *connector, struct edid *edid
850static int add_detailed_info(struct drm_connector *connector, 899static int add_detailed_info(struct drm_connector *connector,
851 struct edid *edid, u32 quirks) 900 struct edid *edid, u32 quirks)
852{ 901{
853 struct drm_device *dev = connector->dev; 902 int i, modes = 0;
854 int i, j, modes = 0;
855 int timing_level;
856
857 timing_level = standard_timing_level(edid);
858 903
859 for (i = 0; i < EDID_DETAILED_TIMINGS; i++) { 904 for (i = 0; i < EDID_DETAILED_TIMINGS; i++) {
860 struct detailed_timing *timing = &edid->detailed_timings[i]; 905 struct detailed_timing *timing = &edid->detailed_timings[i];
861 struct detailed_non_pixel *data = &timing->data.other_data; 906 int preferred = (i == 0) && (edid->features & DRM_EDID_FEATURE_PREFERRED_TIMING);
862 struct drm_display_mode *newmode;
863
864 /* X server check is version 1.1 or higher */
865 if (edid->version == 1 && edid->revision >= 1 &&
866 !timing->pixel_clock) {
867 /* Other timing or info */
868 switch (data->type) {
869 case EDID_DETAIL_MONITOR_SERIAL:
870 break;
871 case EDID_DETAIL_MONITOR_STRING:
872 break;
873 case EDID_DETAIL_MONITOR_RANGE:
874 /* Get monitor range data */
875 break;
876 case EDID_DETAIL_MONITOR_NAME:
877 break;
878 case EDID_DETAIL_MONITOR_CPDATA:
879 break;
880 case EDID_DETAIL_STD_MODES:
881 for (j = 0; j < 6; i++) {
882 struct std_timing *std;
883 struct drm_display_mode *newmode;
884
885 std = &data->data.timings[j];
886 newmode = drm_mode_std(dev, std,
887 edid->revision,
888 timing_level);
889 if (newmode) {
890 drm_mode_probed_add(connector, newmode);
891 modes++;
892 }
893 }
894 break;
895 default:
896 break;
897 }
898 } else {
899 newmode = drm_mode_detailed(dev, edid, timing, quirks);
900 if (!newmode)
901 continue;
902 907
903 /* First detailed mode is preferred */ 908 /* In 1.0, only timings are allowed */
904 if (i == 0 && (edid->features & DRM_EDID_FEATURE_PREFERRED_TIMING)) 909 if (!timing->pixel_clock && edid->version == 1 &&
905 newmode->type |= DRM_MODE_TYPE_PREFERRED; 910 edid->revision == 0)
906 drm_mode_probed_add(connector, newmode); 911 continue;
907 912
908 modes++; 913 modes += add_detailed_modes(connector, timing, edid, quirks,
909 } 914 preferred);
910 } 915 }
911 916
912 return modes; 917 return modes;
913} 918}
919
914/** 920/**
915 * add_detailed_mode_eedid - get detailed mode info from addtional timing 921 * add_detailed_mode_eedid - get detailed mode info from addtional timing
916 * EDID block 922 * EDID block
@@ -924,12 +930,9 @@ static int add_detailed_info(struct drm_connector *connector,
924static int add_detailed_info_eedid(struct drm_connector *connector, 930static int add_detailed_info_eedid(struct drm_connector *connector,
925 struct edid *edid, u32 quirks) 931 struct edid *edid, u32 quirks)
926{ 932{
927 struct drm_device *dev = connector->dev; 933 int i, modes = 0;
928 int i, j, modes = 0;
929 char *edid_ext = NULL; 934 char *edid_ext = NULL;
930 struct detailed_timing *timing; 935 struct detailed_timing *timing;
931 struct detailed_non_pixel *data;
932 struct drm_display_mode *newmode;
933 int edid_ext_num; 936 int edid_ext_num;
934 int start_offset, end_offset; 937 int start_offset, end_offset;
935 int timing_level; 938 int timing_level;
@@ -980,51 +983,7 @@ static int add_detailed_info_eedid(struct drm_connector *connector,
980 for (i = start_offset; i < end_offset; 983 for (i = start_offset; i < end_offset;
981 i += sizeof(struct detailed_timing)) { 984 i += sizeof(struct detailed_timing)) {
982 timing = (struct detailed_timing *)(edid_ext + i); 985 timing = (struct detailed_timing *)(edid_ext + i);
983 data = &timing->data.other_data; 986 modes += add_detailed_modes(connector, timing, edid, quirks, 0);
984 /* Detailed mode timing */
985 if (timing->pixel_clock) {
986 newmode = drm_mode_detailed(dev, edid, timing, quirks);
987 if (!newmode)
988 continue;
989
990 drm_mode_probed_add(connector, newmode);
991
992 modes++;
993 continue;
994 }
995
996 /* Other timing or info */
997 switch (data->type) {
998 case EDID_DETAIL_MONITOR_SERIAL:
999 break;
1000 case EDID_DETAIL_MONITOR_STRING:
1001 break;
1002 case EDID_DETAIL_MONITOR_RANGE:
1003 /* Get monitor range data */
1004 break;
1005 case EDID_DETAIL_MONITOR_NAME:
1006 break;
1007 case EDID_DETAIL_MONITOR_CPDATA:
1008 break;
1009 case EDID_DETAIL_STD_MODES:
1010 /* Five modes per detailed section */
1011 for (j = 0; j < 5; i++) {
1012 struct std_timing *std;
1013 struct drm_display_mode *newmode;
1014
1015 std = &data->data.timings[j];
1016 newmode = drm_mode_std(dev, std,
1017 edid->revision,
1018 timing_level);
1019 if (newmode) {
1020 drm_mode_probed_add(connector, newmode);
1021 modes++;
1022 }
1023 }
1024 break;
1025 default:
1026 break;
1027 }
1028 } 987 }
1029 988
1030 return modes; 989 return modes;