aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2011-04-17 02:43:32 -0400
committerDave Airlie <airlied@redhat.com>2011-04-28 00:56:23 -0400
commit1794d257fa7bab3ea5162f8abdca749996b65343 (patch)
treeea8d035a218a0cb0ee83443b3c25bd8df25567e2 /drivers/gpu
parentbbb0aef5cfe95fe9b51a7eeba4a440b69037b01f (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.c207
-rw-r--r--drivers/gpu/drm/drm_modes.c154
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}
71EXPORT_SYMBOL(drm_fb_helper_single_add_all_connectors); 71EXPORT_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 */
86static 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 }
182done:
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
226static int drm_fb_helper_parse_command_line(struct drm_fb_helper *fb_helper) 73static 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
1124static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector) 1000static 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)
1131static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn, 1007static 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
1165create_mode: 1041create_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}
976EXPORT_SYMBOL(drm_mode_connector_list_update); 976EXPORT_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 */
991bool 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 }
1081done:
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}
1104EXPORT_SYMBOL(drm_mode_parse_command_line_for_connector);
1105
1106struct drm_display_mode *
1107drm_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}
1130EXPORT_SYMBOL(drm_mode_create_from_cmdline_mode);