diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2011-04-17 02:43:32 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2011-04-28 00:56:23 -0400 |
commit | 1794d257fa7bab3ea5162f8abdca749996b65343 (patch) | |
tree | ea8d035a218a0cb0ee83443b3c25bd8df25567e2 /drivers/gpu | |
parent | bbb0aef5cfe95fe9b51a7eeba4a440b69037b01f (diff) |
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>
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/drm/drm_fb_helper.c | 207 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_modes.c | 154 |
2 files changed, 190 insertions, 171 deletions
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 140b9525b48a..802b61ac3139 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c | |||
@@ -70,174 +70,50 @@ fail: | |||
70 | } | 70 | } |
71 | EXPORT_SYMBOL(drm_fb_helper_single_add_all_connectors); | 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 | static int drm_fb_helper_parse_command_line(struct drm_fb_helper *fb_helper) | 73 | static int drm_fb_helper_parse_command_line(struct drm_fb_helper *fb_helper) |
227 | { | 74 | { |
228 | struct drm_fb_helper_connector *fb_helper_conn; | 75 | struct drm_fb_helper_connector *fb_helper_conn; |
229 | int i; | 76 | int i; |
230 | 77 | ||
231 | for (i = 0; i < fb_helper->connector_count; i++) { | 78 | for (i = 0; i < fb_helper->connector_count; i++) { |
79 | struct drm_cmdline_mode *mode; | ||
80 | struct drm_connector *connector; | ||
232 | char *option = NULL; | 81 | char *option = NULL; |
233 | 82 | ||
234 | fb_helper_conn = fb_helper->connector_info[i]; | 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 | /* do something on return - turn off connector maybe */ | 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 | continue; | 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 | return 0; | 118 | return 0; |
243 | } | 119 | } |
@@ -901,7 +777,7 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, | |||
901 | /* first up get a count of crtcs now in use and new min/maxes width/heights */ | 777 | /* first up get a count of crtcs now in use and new min/maxes width/heights */ |
902 | for (i = 0; i < fb_helper->connector_count; i++) { | 778 | for (i = 0; i < fb_helper->connector_count; i++) { |
903 | struct drm_fb_helper_connector *fb_helper_conn = fb_helper->connector_info[i]; | 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 | cmdline_mode = &fb_helper_conn->cmdline_mode; | 782 | cmdline_mode = &fb_helper_conn->cmdline_mode; |
907 | 783 | ||
@@ -1123,7 +999,7 @@ static struct drm_display_mode *drm_has_preferred_mode(struct drm_fb_helper_conn | |||
1123 | 999 | ||
1124 | static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector) | 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 | cmdline_mode = &fb_connector->cmdline_mode; | 1003 | cmdline_mode = &fb_connector->cmdline_mode; |
1128 | return cmdline_mode->specified; | 1004 | return cmdline_mode->specified; |
1129 | } | 1005 | } |
@@ -1131,7 +1007,7 @@ static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector) | |||
1131 | static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn, | 1007 | static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn, |
1132 | int width, int height) | 1008 | int width, int height) |
1133 | { | 1009 | { |
1134 | struct drm_fb_helper_cmdline_mode *cmdline_mode; | 1010 | struct drm_cmdline_mode *cmdline_mode; |
1135 | struct drm_display_mode *mode = NULL; | 1011 | struct drm_display_mode *mode = NULL; |
1136 | 1012 | ||
1137 | cmdline_mode = &fb_helper_conn->cmdline_mode; | 1013 | cmdline_mode = &fb_helper_conn->cmdline_mode; |
@@ -1163,19 +1039,8 @@ static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_conne | |||
1163 | } | 1039 | } |
1164 | 1040 | ||
1165 | create_mode: | 1041 | create_mode: |
1166 | if (cmdline_mode->cvt) | 1042 | mode = drm_mode_create_from_cmdline_mode(fb_helper_conn->connector->dev, |
1167 | mode = drm_cvt_mode(fb_helper_conn->connector->dev, | 1043 | cmdline_mode); |
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); | ||
1179 | list_add(&mode->head, &fb_helper_conn->connector->modes); | 1044 | list_add(&mode->head, &fb_helper_conn->connector->modes); |
1180 | return mode; | 1045 | return mode; |
1181 | } | 1046 | } |
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index 25bf87390f53..207b7ebf8150 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c | |||
@@ -974,3 +974,157 @@ void drm_mode_connector_list_update(struct drm_connector *connector) | |||
974 | } | 974 | } |
975 | } | 975 | } |
976 | EXPORT_SYMBOL(drm_mode_connector_list_update); | 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); | ||