Commit 1794d257fa7bab3ea5162f8abdca749996b65343
Committed by
Dave Airlie
1 parent
bbb0aef5cf
Exists in
master
and in
39 other branches
drm: Export the command-line mode parser
In the absence of configuration data for providing the fixed mode for a panel, I would like to be able to pass such modes along a separate module paramenter. To do so, I then need to parse a modeline from a string, which drm is already capable of. Export that capability to the drivers. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Dave Airlie <airlied@redhat.com>
Showing 4 changed files with 216 additions and 186 deletions Side-by-side Diff
drivers/gpu/drm/drm_fb_helper.c
... | ... | @@ -70,174 +70,50 @@ |
70 | 70 | } |
71 | 71 | EXPORT_SYMBOL(drm_fb_helper_single_add_all_connectors); |
72 | 72 | |
73 | -/** | |
74 | - * drm_fb_helper_connector_parse_command_line - parse command line for connector | |
75 | - * @connector - connector to parse line for | |
76 | - * @mode_option - per connector mode option | |
77 | - * | |
78 | - * This parses the connector specific then generic command lines for | |
79 | - * modes and options to configure the connector. | |
80 | - * | |
81 | - * This uses the same parameters as the fb modedb.c, except for extra | |
82 | - * <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd] | |
83 | - * | |
84 | - * enable/enable Digital/disable bit at the end | |
85 | - */ | |
86 | -static bool drm_fb_helper_connector_parse_command_line(struct drm_fb_helper_connector *fb_helper_conn, | |
87 | - const char *mode_option) | |
88 | -{ | |
89 | - const char *name; | |
90 | - unsigned int namelen; | |
91 | - int res_specified = 0, bpp_specified = 0, refresh_specified = 0; | |
92 | - unsigned int xres = 0, yres = 0, bpp = 32, refresh = 0; | |
93 | - int yres_specified = 0, cvt = 0, rb = 0, interlace = 0, margins = 0; | |
94 | - int i; | |
95 | - enum drm_connector_force force = DRM_FORCE_UNSPECIFIED; | |
96 | - struct drm_fb_helper_cmdline_mode *cmdline_mode; | |
97 | - struct drm_connector *connector; | |
98 | - | |
99 | - if (!fb_helper_conn) | |
100 | - return false; | |
101 | - connector = fb_helper_conn->connector; | |
102 | - | |
103 | - cmdline_mode = &fb_helper_conn->cmdline_mode; | |
104 | - if (!mode_option) | |
105 | - mode_option = fb_mode_option; | |
106 | - | |
107 | - if (!mode_option) { | |
108 | - cmdline_mode->specified = false; | |
109 | - return false; | |
110 | - } | |
111 | - | |
112 | - name = mode_option; | |
113 | - namelen = strlen(name); | |
114 | - for (i = namelen-1; i >= 0; i--) { | |
115 | - switch (name[i]) { | |
116 | - case '@': | |
117 | - namelen = i; | |
118 | - if (!refresh_specified && !bpp_specified && | |
119 | - !yres_specified) { | |
120 | - refresh = simple_strtol(&name[i+1], NULL, 10); | |
121 | - refresh_specified = 1; | |
122 | - if (cvt || rb) | |
123 | - cvt = 0; | |
124 | - } else | |
125 | - goto done; | |
126 | - break; | |
127 | - case '-': | |
128 | - namelen = i; | |
129 | - if (!bpp_specified && !yres_specified) { | |
130 | - bpp = simple_strtol(&name[i+1], NULL, 10); | |
131 | - bpp_specified = 1; | |
132 | - if (cvt || rb) | |
133 | - cvt = 0; | |
134 | - } else | |
135 | - goto done; | |
136 | - break; | |
137 | - case 'x': | |
138 | - if (!yres_specified) { | |
139 | - yres = simple_strtol(&name[i+1], NULL, 10); | |
140 | - yres_specified = 1; | |
141 | - } else | |
142 | - goto done; | |
143 | - case '0' ... '9': | |
144 | - break; | |
145 | - case 'M': | |
146 | - if (!yres_specified) | |
147 | - cvt = 1; | |
148 | - break; | |
149 | - case 'R': | |
150 | - if (cvt) | |
151 | - rb = 1; | |
152 | - break; | |
153 | - case 'm': | |
154 | - if (!cvt) | |
155 | - margins = 1; | |
156 | - break; | |
157 | - case 'i': | |
158 | - if (!cvt) | |
159 | - interlace = 1; | |
160 | - break; | |
161 | - case 'e': | |
162 | - force = DRM_FORCE_ON; | |
163 | - break; | |
164 | - case 'D': | |
165 | - if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) && | |
166 | - (connector->connector_type != DRM_MODE_CONNECTOR_HDMIB)) | |
167 | - force = DRM_FORCE_ON; | |
168 | - else | |
169 | - force = DRM_FORCE_ON_DIGITAL; | |
170 | - break; | |
171 | - case 'd': | |
172 | - force = DRM_FORCE_OFF; | |
173 | - break; | |
174 | - default: | |
175 | - goto done; | |
176 | - } | |
177 | - } | |
178 | - if (i < 0 && yres_specified) { | |
179 | - xres = simple_strtol(name, NULL, 10); | |
180 | - res_specified = 1; | |
181 | - } | |
182 | -done: | |
183 | - | |
184 | - DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n", | |
185 | - drm_get_connector_name(connector), xres, yres, | |
186 | - (refresh) ? refresh : 60, (rb) ? " reduced blanking" : | |
187 | - "", (margins) ? " with margins" : "", (interlace) ? | |
188 | - " interlaced" : ""); | |
189 | - | |
190 | - if (force) { | |
191 | - const char *s; | |
192 | - switch (force) { | |
193 | - case DRM_FORCE_OFF: s = "OFF"; break; | |
194 | - case DRM_FORCE_ON_DIGITAL: s = "ON - dig"; break; | |
195 | - default: | |
196 | - case DRM_FORCE_ON: s = "ON"; break; | |
197 | - } | |
198 | - | |
199 | - DRM_INFO("forcing %s connector %s\n", | |
200 | - drm_get_connector_name(connector), s); | |
201 | - connector->force = force; | |
202 | - } | |
203 | - | |
204 | - if (res_specified) { | |
205 | - cmdline_mode->specified = true; | |
206 | - cmdline_mode->xres = xres; | |
207 | - cmdline_mode->yres = yres; | |
208 | - } | |
209 | - | |
210 | - if (refresh_specified) { | |
211 | - cmdline_mode->refresh_specified = true; | |
212 | - cmdline_mode->refresh = refresh; | |
213 | - } | |
214 | - | |
215 | - if (bpp_specified) { | |
216 | - cmdline_mode->bpp_specified = true; | |
217 | - cmdline_mode->bpp = bpp; | |
218 | - } | |
219 | - cmdline_mode->rb = rb ? true : false; | |
220 | - cmdline_mode->cvt = cvt ? true : false; | |
221 | - cmdline_mode->interlace = interlace ? true : false; | |
222 | - | |
223 | - return true; | |
224 | -} | |
225 | - | |
226 | 73 | static int drm_fb_helper_parse_command_line(struct drm_fb_helper *fb_helper) |
227 | 74 | { |
228 | 75 | struct drm_fb_helper_connector *fb_helper_conn; |
229 | 76 | int i; |
230 | 77 | |
231 | 78 | for (i = 0; i < fb_helper->connector_count; i++) { |
79 | + struct drm_cmdline_mode *mode; | |
80 | + struct drm_connector *connector; | |
232 | 81 | char *option = NULL; |
233 | 82 | |
234 | 83 | fb_helper_conn = fb_helper->connector_info[i]; |
84 | + connector = fb_helper_conn->connector; | |
85 | + mode = &fb_helper_conn->cmdline_mode; | |
235 | 86 | |
236 | 87 | /* do something on return - turn off connector maybe */ |
237 | - if (fb_get_options(drm_get_connector_name(fb_helper_conn->connector), &option)) | |
88 | + if (fb_get_options(drm_get_connector_name(connector), &option)) | |
238 | 89 | continue; |
239 | 90 | |
240 | - drm_fb_helper_connector_parse_command_line(fb_helper_conn, option); | |
91 | + if (drm_mode_parse_command_line_for_connector(option, | |
92 | + connector, | |
93 | + mode)) { | |
94 | + if (mode->force) { | |
95 | + const char *s; | |
96 | + switch (mode->force) { | |
97 | + case DRM_FORCE_OFF: s = "OFF"; break; | |
98 | + case DRM_FORCE_ON_DIGITAL: s = "ON - dig"; break; | |
99 | + default: | |
100 | + case DRM_FORCE_ON: s = "ON"; break; | |
101 | + } | |
102 | + | |
103 | + DRM_INFO("forcing %s connector %s\n", | |
104 | + drm_get_connector_name(connector), s); | |
105 | + connector->force = mode->force; | |
106 | + } | |
107 | + | |
108 | + DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n", | |
109 | + drm_get_connector_name(connector), | |
110 | + mode->xres, mode->yres, | |
111 | + mode->refresh_specified ? mode->refresh : 60, | |
112 | + mode->rb ? " reduced blanking" : "", | |
113 | + mode->margins ? " with margins" : "", | |
114 | + mode->interlace ? " interlaced" : ""); | |
115 | + } | |
116 | + | |
241 | 117 | } |
242 | 118 | return 0; |
243 | 119 | } |
... | ... | @@ -901,7 +777,7 @@ |
901 | 777 | /* first up get a count of crtcs now in use and new min/maxes width/heights */ |
902 | 778 | for (i = 0; i < fb_helper->connector_count; i++) { |
903 | 779 | struct drm_fb_helper_connector *fb_helper_conn = fb_helper->connector_info[i]; |
904 | - struct drm_fb_helper_cmdline_mode *cmdline_mode; | |
780 | + struct drm_cmdline_mode *cmdline_mode; | |
905 | 781 | |
906 | 782 | cmdline_mode = &fb_helper_conn->cmdline_mode; |
907 | 783 | |
... | ... | @@ -1123,7 +999,7 @@ |
1123 | 999 | |
1124 | 1000 | static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector) |
1125 | 1001 | { |
1126 | - struct drm_fb_helper_cmdline_mode *cmdline_mode; | |
1002 | + struct drm_cmdline_mode *cmdline_mode; | |
1127 | 1003 | cmdline_mode = &fb_connector->cmdline_mode; |
1128 | 1004 | return cmdline_mode->specified; |
1129 | 1005 | } |
... | ... | @@ -1131,7 +1007,7 @@ |
1131 | 1007 | static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn, |
1132 | 1008 | int width, int height) |
1133 | 1009 | { |
1134 | - struct drm_fb_helper_cmdline_mode *cmdline_mode; | |
1010 | + struct drm_cmdline_mode *cmdline_mode; | |
1135 | 1011 | struct drm_display_mode *mode = NULL; |
1136 | 1012 | |
1137 | 1013 | cmdline_mode = &fb_helper_conn->cmdline_mode; |
... | ... | @@ -1163,19 +1039,8 @@ |
1163 | 1039 | } |
1164 | 1040 | |
1165 | 1041 | create_mode: |
1166 | - if (cmdline_mode->cvt) | |
1167 | - mode = drm_cvt_mode(fb_helper_conn->connector->dev, | |
1168 | - cmdline_mode->xres, cmdline_mode->yres, | |
1169 | - cmdline_mode->refresh_specified ? cmdline_mode->refresh : 60, | |
1170 | - cmdline_mode->rb, cmdline_mode->interlace, | |
1171 | - cmdline_mode->margins); | |
1172 | - else | |
1173 | - mode = drm_gtf_mode(fb_helper_conn->connector->dev, | |
1174 | - cmdline_mode->xres, cmdline_mode->yres, | |
1175 | - cmdline_mode->refresh_specified ? cmdline_mode->refresh : 60, | |
1176 | - cmdline_mode->interlace, | |
1177 | - cmdline_mode->margins); | |
1178 | - drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); | |
1042 | + mode = drm_mode_create_from_cmdline_mode(fb_helper_conn->connector->dev, | |
1043 | + cmdline_mode); | |
1179 | 1044 | list_add(&mode->head, &fb_helper_conn->connector->modes); |
1180 | 1045 | return mode; |
1181 | 1046 | } |
drivers/gpu/drm/drm_modes.c
... | ... | @@ -974,4 +974,158 @@ |
974 | 974 | } |
975 | 975 | } |
976 | 976 | EXPORT_SYMBOL(drm_mode_connector_list_update); |
977 | + | |
978 | +/** | |
979 | + * drm_mode_parse_command_line_for_connector - parse command line for connector | |
980 | + * @mode_option - per connector mode option | |
981 | + * @connector - connector to parse line for | |
982 | + * | |
983 | + * This parses the connector specific then generic command lines for | |
984 | + * modes and options to configure the connector. | |
985 | + * | |
986 | + * This uses the same parameters as the fb modedb.c, except for extra | |
987 | + * <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd] | |
988 | + * | |
989 | + * enable/enable Digital/disable bit at the end | |
990 | + */ | |
991 | +bool drm_mode_parse_command_line_for_connector(const char *mode_option, | |
992 | + struct drm_connector *connector, | |
993 | + struct drm_cmdline_mode *mode) | |
994 | +{ | |
995 | + const char *name; | |
996 | + unsigned int namelen; | |
997 | + int res_specified = 0, bpp_specified = 0, refresh_specified = 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; | |
1000 | + int i; | |
1001 | + enum drm_connector_force force = DRM_FORCE_UNSPECIFIED; | |
1002 | + | |
1003 | + if (!mode_option) | |
1004 | + mode_option = fb_mode_option; | |
1005 | + | |
1006 | + if (!mode_option) { | |
1007 | + mode->specified = false; | |
1008 | + return false; | |
1009 | + } | |
1010 | + | |
1011 | + name = mode_option; | |
1012 | + namelen = strlen(name); | |
1013 | + for (i = namelen-1; i >= 0; i--) { | |
1014 | + switch (name[i]) { | |
1015 | + case '@': | |
1016 | + namelen = i; | |
1017 | + if (!refresh_specified && !bpp_specified && | |
1018 | + !yres_specified) { | |
1019 | + refresh = simple_strtol(&name[i+1], NULL, 10); | |
1020 | + refresh_specified = 1; | |
1021 | + if (cvt || rb) | |
1022 | + cvt = 0; | |
1023 | + } else | |
1024 | + goto done; | |
1025 | + break; | |
1026 | + case '-': | |
1027 | + namelen = i; | |
1028 | + if (!bpp_specified && !yres_specified) { | |
1029 | + bpp = simple_strtol(&name[i+1], NULL, 10); | |
1030 | + bpp_specified = 1; | |
1031 | + if (cvt || rb) | |
1032 | + cvt = 0; | |
1033 | + } else | |
1034 | + goto done; | |
1035 | + break; | |
1036 | + case 'x': | |
1037 | + if (!yres_specified) { | |
1038 | + yres = simple_strtol(&name[i+1], NULL, 10); | |
1039 | + yres_specified = 1; | |
1040 | + } else | |
1041 | + goto done; | |
1042 | + case '0' ... '9': | |
1043 | + break; | |
1044 | + case 'M': | |
1045 | + if (!yres_specified) | |
1046 | + cvt = 1; | |
1047 | + break; | |
1048 | + case 'R': | |
1049 | + if (cvt) | |
1050 | + rb = 1; | |
1051 | + break; | |
1052 | + case 'm': | |
1053 | + if (!cvt) | |
1054 | + margins = 1; | |
1055 | + break; | |
1056 | + case 'i': | |
1057 | + if (!cvt) | |
1058 | + interlace = 1; | |
1059 | + break; | |
1060 | + case 'e': | |
1061 | + force = DRM_FORCE_ON; | |
1062 | + break; | |
1063 | + case 'D': | |
1064 | + if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) && | |
1065 | + (connector->connector_type != DRM_MODE_CONNECTOR_HDMIB)) | |
1066 | + force = DRM_FORCE_ON; | |
1067 | + else | |
1068 | + force = DRM_FORCE_ON_DIGITAL; | |
1069 | + break; | |
1070 | + case 'd': | |
1071 | + force = DRM_FORCE_OFF; | |
1072 | + break; | |
1073 | + default: | |
1074 | + goto done; | |
1075 | + } | |
1076 | + } | |
1077 | + if (i < 0 && yres_specified) { | |
1078 | + xres = simple_strtol(name, NULL, 10); | |
1079 | + res_specified = 1; | |
1080 | + } | |
1081 | +done: | |
1082 | + if (res_specified) { | |
1083 | + mode->specified = true; | |
1084 | + mode->xres = xres; | |
1085 | + mode->yres = yres; | |
1086 | + } | |
1087 | + | |
1088 | + if (refresh_specified) { | |
1089 | + mode->refresh_specified = true; | |
1090 | + mode->refresh = refresh; | |
1091 | + } | |
1092 | + | |
1093 | + if (bpp_specified) { | |
1094 | + mode->bpp_specified = true; | |
1095 | + mode->bpp = bpp; | |
1096 | + } | |
1097 | + mode->rb = rb ? true : false; | |
1098 | + mode->cvt = cvt ? true : false; | |
1099 | + mode->interlace = interlace ? true : false; | |
1100 | + mode->force = force; | |
1101 | + | |
1102 | + return true; | |
1103 | +} | |
1104 | +EXPORT_SYMBOL(drm_mode_parse_command_line_for_connector); | |
1105 | + | |
1106 | +struct drm_display_mode * | |
1107 | +drm_mode_create_from_cmdline_mode(struct drm_device *dev, | |
1108 | + struct drm_cmdline_mode *cmd) | |
1109 | +{ | |
1110 | + struct drm_display_mode *mode; | |
1111 | + | |
1112 | + if (cmd->cvt) | |
1113 | + mode = drm_cvt_mode(dev, | |
1114 | + cmd->xres, cmd->yres, | |
1115 | + cmd->refresh_specified ? cmd->refresh : 60, | |
1116 | + cmd->rb, cmd->interlace, | |
1117 | + cmd->margins); | |
1118 | + else | |
1119 | + mode = drm_gtf_mode(dev, | |
1120 | + cmd->xres, cmd->yres, | |
1121 | + cmd->refresh_specified ? cmd->refresh : 60, | |
1122 | + cmd->interlace, | |
1123 | + cmd->margins); | |
1124 | + if (!mode) | |
1125 | + return NULL; | |
1126 | + | |
1127 | + drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); | |
1128 | + return mode; | |
1129 | +} | |
1130 | +EXPORT_SYMBOL(drm_mode_create_from_cmdline_mode); |
include/drm/drmP.h
... | ... | @@ -994,6 +994,22 @@ |
994 | 994 | struct drm_mode_group mode_group; |
995 | 995 | }; |
996 | 996 | |
997 | +/* mode specified on the command line */ | |
998 | +struct drm_cmdline_mode { | |
999 | + bool specified; | |
1000 | + bool refresh_specified; | |
1001 | + bool bpp_specified; | |
1002 | + int xres, yres; | |
1003 | + int bpp; | |
1004 | + int refresh; | |
1005 | + bool rb; | |
1006 | + bool interlace; | |
1007 | + bool cvt; | |
1008 | + bool margins; | |
1009 | + enum drm_connector_force force; | |
1010 | +}; | |
1011 | + | |
1012 | + | |
997 | 1013 | struct drm_pending_vblank_event { |
998 | 1014 | struct drm_pending_event base; |
999 | 1015 | int pipe; |
... | ... | @@ -1388,6 +1404,15 @@ |
1388 | 1404 | unsigned flags, |
1389 | 1405 | struct drm_crtc *refcrtc); |
1390 | 1406 | extern void drm_calc_timestamping_constants(struct drm_crtc *crtc); |
1407 | + | |
1408 | +extern bool | |
1409 | +drm_mode_parse_command_line_for_connector(const char *mode_option, | |
1410 | + struct drm_connector *connector, | |
1411 | + struct drm_cmdline_mode *mode); | |
1412 | + | |
1413 | +extern struct drm_display_mode * | |
1414 | +drm_mode_create_from_cmdline_mode(struct drm_device *dev, | |
1415 | + struct drm_cmdline_mode *cmd); | |
1391 | 1416 | |
1392 | 1417 | /* Modesetting support */ |
1393 | 1418 | extern void drm_vblank_pre_modeset(struct drm_device *dev, int crtc); |
include/drm/drm_fb_helper.h
... | ... | @@ -40,20 +40,6 @@ |
40 | 40 | struct drm_display_mode *desired_mode; |
41 | 41 | }; |
42 | 42 | |
43 | -/* mode specified on the command line */ | |
44 | -struct drm_fb_helper_cmdline_mode { | |
45 | - bool specified; | |
46 | - bool refresh_specified; | |
47 | - bool bpp_specified; | |
48 | - int xres, yres; | |
49 | - int bpp; | |
50 | - int refresh; | |
51 | - bool rb; | |
52 | - bool interlace; | |
53 | - bool cvt; | |
54 | - bool margins; | |
55 | -}; | |
56 | - | |
57 | 43 | struct drm_fb_helper_surface_size { |
58 | 44 | u32 fb_width; |
59 | 45 | u32 fb_height; |
60 | 46 | |
... | ... | @@ -74,8 +60,8 @@ |
74 | 60 | }; |
75 | 61 | |
76 | 62 | struct drm_fb_helper_connector { |
77 | - struct drm_fb_helper_cmdline_mode cmdline_mode; | |
78 | 63 | struct drm_connector *connector; |
64 | + struct drm_cmdline_mode cmdline_mode; | |
79 | 65 | }; |
80 | 66 | |
81 | 67 | struct drm_fb_helper { |