diff options
-rw-r--r-- | Documentation/fb/modedb.txt | 21 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_modes.c | 87 |
2 files changed, 78 insertions, 30 deletions
diff --git a/Documentation/fb/modedb.txt b/Documentation/fb/modedb.txt index ec4dee75a354..16aa08453911 100644 --- a/Documentation/fb/modedb.txt +++ b/Documentation/fb/modedb.txt | |||
@@ -20,7 +20,7 @@ in a video= option, fbmem considers that to be a global video mode option. | |||
20 | 20 | ||
21 | Valid mode specifiers (mode_option argument): | 21 | Valid mode specifiers (mode_option argument): |
22 | 22 | ||
23 | <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m] | 23 | <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd] |
24 | <name>[-<bpp>][@<refresh>] | 24 | <name>[-<bpp>][@<refresh>] |
25 | 25 | ||
26 | with <xres>, <yres>, <bpp> and <refresh> decimal numbers and <name> a string. | 26 | with <xres>, <yres>, <bpp> and <refresh> decimal numbers and <name> a string. |
@@ -36,6 +36,21 @@ pixels and 1.8% of yres). | |||
36 | 36 | ||
37 | Sample usage: 1024x768M@60m - CVT timing with margins | 37 | Sample usage: 1024x768M@60m - CVT timing with margins |
38 | 38 | ||
39 | DRM drivers also add options to enable or disable outputs: | ||
40 | |||
41 | 'e' will force the display to be enabled, i.e. it will override the detection | ||
42 | if a display is connected. 'D' will force the display to be enabled and use | ||
43 | digital output. This is useful for outputs that have both analog and digital | ||
44 | signals (e.g. HDMI and DVI-I). For other outputs it behaves like 'e'. If 'd' | ||
45 | is specified the output is disabled. | ||
46 | |||
47 | You can additionally specify which output the options matches to. | ||
48 | To force the VGA output to be enabled and drive a specific mode say: | ||
49 | video=VGA-1:1280x1024@60me | ||
50 | |||
51 | Specifying the option multiple times for different ports is possible, e.g.: | ||
52 | video=LVDS-1:d video=HDMI-1:D | ||
53 | |||
39 | ***** oOo ***** oOo ***** oOo ***** oOo ***** oOo ***** oOo ***** oOo ***** | 54 | ***** oOo ***** oOo ***** oOo ***** oOo ***** oOo ***** oOo ***** oOo ***** |
40 | 55 | ||
41 | What is the VESA(TM) Coordinated Video Timings (CVT)? | 56 | What is the VESA(TM) Coordinated Video Timings (CVT)? |
@@ -132,5 +147,5 @@ There may be more modes. | |||
132 | tridentfb - Trident (Cyber)blade chipset frame buffer | 147 | tridentfb - Trident (Cyber)blade chipset frame buffer |
133 | vt8623fb - VIA 8623 frame buffer | 148 | vt8623fb - VIA 8623 frame buffer |
134 | 149 | ||
135 | BTW, only a few drivers use this at the moment. Others are to follow | 150 | BTW, only a few fb drivers use this at the moment. Others are to follow |
136 | (feel free to send patches). | 151 | (feel free to send patches). The DRM drivers also support this. |
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index c2d32f20e2fb..ad74fb4dc542 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c | |||
@@ -994,9 +994,10 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option, | |||
994 | { | 994 | { |
995 | const char *name; | 995 | const char *name; |
996 | unsigned int namelen; | 996 | unsigned int namelen; |
997 | int res_specified = 0, bpp_specified = 0, refresh_specified = 0; | 997 | bool res_specified = false, bpp_specified = false, refresh_specified = false; |
998 | unsigned int xres = 0, yres = 0, bpp = 32, refresh = 0; | 998 | unsigned int xres = 0, yres = 0, bpp = 32, refresh = 0; |
999 | int yres_specified = 0, cvt = 0, rb = 0, interlace = 0, margins = 0; | 999 | bool yres_specified = false, cvt = false, rb = false; |
1000 | bool interlace = false, margins = false, was_digit = false; | ||
1000 | int i; | 1001 | int i; |
1001 | enum drm_connector_force force = DRM_FORCE_UNSPECIFIED; | 1002 | enum drm_connector_force force = DRM_FORCE_UNSPECIFIED; |
1002 | 1003 | ||
@@ -1015,54 +1016,65 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option, | |||
1015 | for (i = namelen-1; i >= 0; i--) { | 1016 | for (i = namelen-1; i >= 0; i--) { |
1016 | switch (name[i]) { | 1017 | switch (name[i]) { |
1017 | case '@': | 1018 | case '@': |
1018 | namelen = i; | ||
1019 | if (!refresh_specified && !bpp_specified && | 1019 | if (!refresh_specified && !bpp_specified && |
1020 | !yres_specified) { | 1020 | !yres_specified && !cvt && !rb && was_digit) { |
1021 | refresh = simple_strtol(&name[i+1], NULL, 10); | 1021 | refresh = simple_strtol(&name[i+1], NULL, 10); |
1022 | refresh_specified = 1; | 1022 | refresh_specified = true; |
1023 | if (cvt || rb) | 1023 | was_digit = false; |
1024 | cvt = 0; | ||
1025 | } else | 1024 | } else |
1026 | goto done; | 1025 | goto done; |
1027 | break; | 1026 | break; |
1028 | case '-': | 1027 | case '-': |
1029 | namelen = i; | 1028 | if (!bpp_specified && !yres_specified && !cvt && |
1030 | if (!bpp_specified && !yres_specified) { | 1029 | !rb && was_digit) { |
1031 | bpp = simple_strtol(&name[i+1], NULL, 10); | 1030 | bpp = simple_strtol(&name[i+1], NULL, 10); |
1032 | bpp_specified = 1; | 1031 | bpp_specified = true; |
1033 | if (cvt || rb) | 1032 | was_digit = false; |
1034 | cvt = 0; | ||
1035 | } else | 1033 | } else |
1036 | goto done; | 1034 | goto done; |
1037 | break; | 1035 | break; |
1038 | case 'x': | 1036 | case 'x': |
1039 | if (!yres_specified) { | 1037 | if (!yres_specified && was_digit) { |
1040 | yres = simple_strtol(&name[i+1], NULL, 10); | 1038 | yres = simple_strtol(&name[i+1], NULL, 10); |
1041 | yres_specified = 1; | 1039 | yres_specified = true; |
1040 | was_digit = false; | ||
1042 | } else | 1041 | } else |
1043 | goto done; | 1042 | goto done; |
1044 | case '0' ... '9': | 1043 | case '0' ... '9': |
1044 | was_digit = true; | ||
1045 | break; | 1045 | break; |
1046 | case 'M': | 1046 | case 'M': |
1047 | if (!yres_specified) | 1047 | if (yres_specified || cvt || was_digit) |
1048 | cvt = 1; | 1048 | goto done; |
1049 | cvt = true; | ||
1049 | break; | 1050 | break; |
1050 | case 'R': | 1051 | case 'R': |
1051 | if (cvt) | 1052 | if (yres_specified || cvt || rb || was_digit) |
1052 | rb = 1; | 1053 | goto done; |
1054 | rb = true; | ||
1053 | break; | 1055 | break; |
1054 | case 'm': | 1056 | case 'm': |
1055 | if (!cvt) | 1057 | if (cvt || yres_specified || was_digit) |
1056 | margins = 1; | 1058 | goto done; |
1059 | margins = true; | ||
1057 | break; | 1060 | break; |
1058 | case 'i': | 1061 | case 'i': |
1059 | if (!cvt) | 1062 | if (cvt || yres_specified || was_digit) |
1060 | interlace = 1; | 1063 | goto done; |
1064 | interlace = true; | ||
1061 | break; | 1065 | break; |
1062 | case 'e': | 1066 | case 'e': |
1067 | if (yres_specified || bpp_specified || refresh_specified || | ||
1068 | was_digit || (force != DRM_FORCE_UNSPECIFIED)) | ||
1069 | goto done; | ||
1070 | |||
1063 | force = DRM_FORCE_ON; | 1071 | force = DRM_FORCE_ON; |
1064 | break; | 1072 | break; |
1065 | case 'D': | 1073 | case 'D': |
1074 | if (yres_specified || bpp_specified || refresh_specified || | ||
1075 | was_digit || (force != DRM_FORCE_UNSPECIFIED)) | ||
1076 | goto done; | ||
1077 | |||
1066 | if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) && | 1078 | if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) && |
1067 | (connector->connector_type != DRM_MODE_CONNECTOR_HDMIB)) | 1079 | (connector->connector_type != DRM_MODE_CONNECTOR_HDMIB)) |
1068 | force = DRM_FORCE_ON; | 1080 | force = DRM_FORCE_ON; |
@@ -1070,17 +1082,37 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option, | |||
1070 | force = DRM_FORCE_ON_DIGITAL; | 1082 | force = DRM_FORCE_ON_DIGITAL; |
1071 | break; | 1083 | break; |
1072 | case 'd': | 1084 | case 'd': |
1085 | if (yres_specified || bpp_specified || refresh_specified || | ||
1086 | was_digit || (force != DRM_FORCE_UNSPECIFIED)) | ||
1087 | goto done; | ||
1088 | |||
1073 | force = DRM_FORCE_OFF; | 1089 | force = DRM_FORCE_OFF; |
1074 | break; | 1090 | break; |
1075 | default: | 1091 | default: |
1076 | goto done; | 1092 | goto done; |
1077 | } | 1093 | } |
1078 | } | 1094 | } |
1095 | |||
1079 | if (i < 0 && yres_specified) { | 1096 | if (i < 0 && yres_specified) { |
1080 | xres = simple_strtol(name, NULL, 10); | 1097 | char *ch; |
1081 | res_specified = 1; | 1098 | xres = simple_strtol(name, &ch, 10); |
1099 | if ((ch != NULL) && (*ch == 'x')) | ||
1100 | res_specified = true; | ||
1101 | else | ||
1102 | i = ch - name; | ||
1103 | } else if (!yres_specified && was_digit) { | ||
1104 | /* catch mode that begins with digits but has no 'x' */ | ||
1105 | i = 0; | ||
1082 | } | 1106 | } |
1083 | done: | 1107 | done: |
1108 | if (i >= 0) { | ||
1109 | printk(KERN_WARNING | ||
1110 | "parse error at position %i in video mode '%s'\n", | ||
1111 | i, name); | ||
1112 | mode->specified = false; | ||
1113 | return false; | ||
1114 | } | ||
1115 | |||
1084 | if (res_specified) { | 1116 | if (res_specified) { |
1085 | mode->specified = true; | 1117 | mode->specified = true; |
1086 | mode->xres = xres; | 1118 | mode->xres = xres; |
@@ -1096,9 +1128,10 @@ done: | |||
1096 | mode->bpp_specified = true; | 1128 | mode->bpp_specified = true; |
1097 | mode->bpp = bpp; | 1129 | mode->bpp = bpp; |
1098 | } | 1130 | } |
1099 | mode->rb = rb ? true : false; | 1131 | mode->rb = rb; |
1100 | mode->cvt = cvt ? true : false; | 1132 | mode->cvt = cvt; |
1101 | mode->interlace = interlace ? true : false; | 1133 | mode->interlace = interlace; |
1134 | mode->margins = margins; | ||
1102 | mode->force = force; | 1135 | mode->force = force; |
1103 | 1136 | ||
1104 | return true; | 1137 | return true; |