Commit 1794d257fa7bab3ea5162f8abdca749996b65343

Authored by Chris Wilson
Committed by Dave Airlie
1 parent bbb0aef5cf

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);
... ... @@ -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 {