aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/pxafb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/pxafb.c')
-rw-r--r--drivers/video/pxafb.c306
1 files changed, 166 insertions, 140 deletions
diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c
index 757651954e6c..02787a43002f 100644
--- a/drivers/video/pxafb.c
+++ b/drivers/video/pxafb.c
@@ -1211,154 +1211,180 @@ static struct pxafb_info * __init pxafb_init_fbinfo(struct device *dev)
1211} 1211}
1212 1212
1213#ifdef CONFIG_FB_PXA_PARAMETERS 1213#ifdef CONFIG_FB_PXA_PARAMETERS
1214static int __init pxafb_parse_options(struct device *dev, char *options) 1214static int parse_opt_mode(struct device *dev, const char *this_opt)
1215{ 1215{
1216 struct pxafb_mach_info *inf = dev->platform_data; 1216 struct pxafb_mach_info *inf = dev->platform_data;
1217
1218 const char *name = this_opt+5;
1219 unsigned int namelen = strlen(name);
1220 int res_specified = 0, bpp_specified = 0;
1221 unsigned int xres = 0, yres = 0, bpp = 0;
1222 int yres_specified = 0;
1223 int i;
1224 for (i = namelen-1; i >= 0; i--) {
1225 switch (name[i]) {
1226 case '-':
1227 namelen = i;
1228 if (!bpp_specified && !yres_specified) {
1229 bpp = simple_strtoul(&name[i+1], NULL, 0);
1230 bpp_specified = 1;
1231 } else
1232 goto done;
1233 break;
1234 case 'x':
1235 if (!yres_specified) {
1236 yres = simple_strtoul(&name[i+1], NULL, 0);
1237 yres_specified = 1;
1238 } else
1239 goto done;
1240 break;
1241 case '0' ... '9':
1242 break;
1243 default:
1244 goto done;
1245 }
1246 }
1247 if (i < 0 && yres_specified) {
1248 xres = simple_strtoul(name, NULL, 0);
1249 res_specified = 1;
1250 }
1251done:
1252 if (res_specified) {
1253 dev_info(dev, "overriding resolution: %dx%d\n", xres, yres);
1254 inf->modes[0].xres = xres; inf->modes[0].yres = yres;
1255 }
1256 if (bpp_specified)
1257 switch (bpp) {
1258 case 1:
1259 case 2:
1260 case 4:
1261 case 8:
1262 case 16:
1263 inf->modes[0].bpp = bpp;
1264 dev_info(dev, "overriding bit depth: %d\n", bpp);
1265 break;
1266 default:
1267 dev_err(dev, "Depth %d is not valid\n", bpp);
1268 return -EINVAL;
1269 }
1270 return 0;
1271}
1272
1273static int parse_opt(struct device *dev, char *this_opt)
1274{
1275 struct pxafb_mach_info *inf = dev->platform_data;
1276 struct pxafb_mode_info *mode = &inf->modes[0];
1277 char s[64];
1278
1279 s[0] = '\0';
1280
1281 if (!strncmp(this_opt, "mode:", 5)) {
1282 return parse_opt_mode(dev, this_opt);
1283 } else if (!strncmp(this_opt, "pixclock:", 9)) {
1284 mode->pixclock = simple_strtoul(this_opt+9, NULL, 0);
1285 sprintf(s, "pixclock: %ld\n", mode->pixclock);
1286 } else if (!strncmp(this_opt, "left:", 5)) {
1287 mode->left_margin = simple_strtoul(this_opt+5, NULL, 0);
1288 sprintf(s, "left: %u\n", mode->left_margin);
1289 } else if (!strncmp(this_opt, "right:", 6)) {
1290 mode->right_margin = simple_strtoul(this_opt+6, NULL, 0);
1291 sprintf(s, "right: %u\n", mode->right_margin);
1292 } else if (!strncmp(this_opt, "upper:", 6)) {
1293 mode->upper_margin = simple_strtoul(this_opt+6, NULL, 0);
1294 sprintf(s, "upper: %u\n", mode->upper_margin);
1295 } else if (!strncmp(this_opt, "lower:", 6)) {
1296 mode->lower_margin = simple_strtoul(this_opt+6, NULL, 0);
1297 sprintf(s, "lower: %u\n", mode->lower_margin);
1298 } else if (!strncmp(this_opt, "hsynclen:", 9)) {
1299 mode->hsync_len = simple_strtoul(this_opt+9, NULL, 0);
1300 sprintf(s, "hsynclen: %u\n", mode->hsync_len);
1301 } else if (!strncmp(this_opt, "vsynclen:", 9)) {
1302 mode->vsync_len = simple_strtoul(this_opt+9, NULL, 0);
1303 sprintf(s, "vsynclen: %u\n", mode->vsync_len);
1304 } else if (!strncmp(this_opt, "hsync:", 6)) {
1305 if (simple_strtoul(this_opt+6, NULL, 0) == 0) {
1306 sprintf(s, "hsync: Active Low\n");
1307 mode->sync &= ~FB_SYNC_HOR_HIGH_ACT;
1308 } else {
1309 sprintf(s, "hsync: Active High\n");
1310 mode->sync |= FB_SYNC_HOR_HIGH_ACT;
1311 }
1312 } else if (!strncmp(this_opt, "vsync:", 6)) {
1313 if (simple_strtoul(this_opt+6, NULL, 0) == 0) {
1314 sprintf(s, "vsync: Active Low\n");
1315 mode->sync &= ~FB_SYNC_VERT_HIGH_ACT;
1316 } else {
1317 sprintf(s, "vsync: Active High\n");
1318 mode->sync |= FB_SYNC_VERT_HIGH_ACT;
1319 }
1320 } else if (!strncmp(this_opt, "dpc:", 4)) {
1321 if (simple_strtoul(this_opt+4, NULL, 0) == 0) {
1322 sprintf(s, "double pixel clock: false\n");
1323 inf->lccr3 &= ~LCCR3_DPC;
1324 } else {
1325 sprintf(s, "double pixel clock: true\n");
1326 inf->lccr3 |= LCCR3_DPC;
1327 }
1328 } else if (!strncmp(this_opt, "outputen:", 9)) {
1329 if (simple_strtoul(this_opt+9, NULL, 0) == 0) {
1330 sprintf(s, "output enable: active low\n");
1331 inf->lccr3 = (inf->lccr3 & ~LCCR3_OEP) | LCCR3_OutEnL;
1332 } else {
1333 sprintf(s, "output enable: active high\n");
1334 inf->lccr3 = (inf->lccr3 & ~LCCR3_OEP) | LCCR3_OutEnH;
1335 }
1336 } else if (!strncmp(this_opt, "pixclockpol:", 12)) {
1337 if (simple_strtoul(this_opt+12, NULL, 0) == 0) {
1338 sprintf(s, "pixel clock polarity: falling edge\n");
1339 inf->lccr3 = (inf->lccr3 & ~LCCR3_PCP) | LCCR3_PixFlEdg;
1340 } else {
1341 sprintf(s, "pixel clock polarity: rising edge\n");
1342 inf->lccr3 = (inf->lccr3 & ~LCCR3_PCP) | LCCR3_PixRsEdg;
1343 }
1344 } else if (!strncmp(this_opt, "color", 5)) {
1345 inf->lccr0 = (inf->lccr0 & ~LCCR0_CMS) | LCCR0_Color;
1346 } else if (!strncmp(this_opt, "mono", 4)) {
1347 inf->lccr0 = (inf->lccr0 & ~LCCR0_CMS) | LCCR0_Mono;
1348 } else if (!strncmp(this_opt, "active", 6)) {
1349 inf->lccr0 = (inf->lccr0 & ~LCCR0_PAS) | LCCR0_Act;
1350 } else if (!strncmp(this_opt, "passive", 7)) {
1351 inf->lccr0 = (inf->lccr0 & ~LCCR0_PAS) | LCCR0_Pas;
1352 } else if (!strncmp(this_opt, "single", 6)) {
1353 inf->lccr0 = (inf->lccr0 & ~LCCR0_SDS) | LCCR0_Sngl;
1354 } else if (!strncmp(this_opt, "dual", 4)) {
1355 inf->lccr0 = (inf->lccr0 & ~LCCR0_SDS) | LCCR0_Dual;
1356 } else if (!strncmp(this_opt, "4pix", 4)) {
1357 inf->lccr0 = (inf->lccr0 & ~LCCR0_DPD) | LCCR0_4PixMono;
1358 } else if (!strncmp(this_opt, "8pix", 4)) {
1359 inf->lccr0 = (inf->lccr0 & ~LCCR0_DPD) | LCCR0_8PixMono;
1360 } else {
1361 dev_err(dev, "unknown option: %s\n", this_opt);
1362 return -EINVAL;
1363 }
1364
1365 if (s[0] != '\0')
1366 dev_info(dev, "override %s", s);
1367
1368 return 0;
1369}
1370
1371static int __init pxafb_parse_options(struct device *dev, char *options)
1372{
1217 char *this_opt; 1373 char *this_opt;
1374 int ret;
1218 1375
1219 if (!options || !*options) 1376 if (!options || !*options)
1220 return 0; 1377 return 0;
1221 1378
1222 dev_dbg(dev, "options are \"%s\"\n", options ? options : "null"); 1379 dev_dbg(dev, "options are \"%s\"\n", options ? options : "null");
1223 1380
1224 /* could be made table driven or similar?... */ 1381 /* could be made table driven or similar?... */
1225 while ((this_opt = strsep(&options, ",")) != NULL) { 1382 while ((this_opt = strsep(&options, ",")) != NULL) {
1226 if (!strncmp(this_opt, "mode:", 5)) { 1383 ret = parse_opt(dev, this_opt);
1227 const char *name = this_opt+5; 1384 if (ret)
1228 unsigned int namelen = strlen(name); 1385 return ret;
1229 int res_specified = 0, bpp_specified = 0; 1386 }
1230 unsigned int xres = 0, yres = 0, bpp = 0; 1387 return 0;
1231 int yres_specified = 0;
1232 int i;
1233 for (i = namelen-1; i >= 0; i--) {
1234 switch (name[i]) {
1235 case '-':
1236 namelen = i;
1237 if (!bpp_specified && !yres_specified) {
1238 bpp = simple_strtoul(&name[i+1], NULL, 0);
1239 bpp_specified = 1;
1240 } else
1241 goto done;
1242 break;
1243 case 'x':
1244 if (!yres_specified) {
1245 yres = simple_strtoul(&name[i+1], NULL, 0);
1246 yres_specified = 1;
1247 } else
1248 goto done;
1249 break;
1250 case '0' ... '9':
1251 break;
1252 default:
1253 goto done;
1254 }
1255 }
1256 if (i < 0 && yres_specified) {
1257 xres = simple_strtoul(name, NULL, 0);
1258 res_specified = 1;
1259 }
1260 done:
1261 if (res_specified) {
1262 dev_info(dev, "overriding resolution: %dx%d\n", xres, yres);
1263 inf->modes[0].xres = xres; inf->modes[0].yres = yres;
1264 }
1265 if (bpp_specified)
1266 switch (bpp) {
1267 case 1:
1268 case 2:
1269 case 4:
1270 case 8:
1271 case 16:
1272 inf->modes[0].bpp = bpp;
1273 dev_info(dev, "overriding bit depth: %d\n", bpp);
1274 break;
1275 default:
1276 dev_err(dev, "Depth %d is not valid\n", bpp);
1277 }
1278 } else if (!strncmp(this_opt, "pixclock:", 9)) {
1279 inf->modes[0].pixclock = simple_strtoul(this_opt+9, NULL, 0);
1280 dev_info(dev, "override pixclock: %ld\n", inf->modes[0].pixclock);
1281 } else if (!strncmp(this_opt, "left:", 5)) {
1282 inf->modes[0].left_margin = simple_strtoul(this_opt+5, NULL, 0);
1283 dev_info(dev, "override left: %u\n", inf->modes[0].left_margin);
1284 } else if (!strncmp(this_opt, "right:", 6)) {
1285 inf->modes[0].right_margin = simple_strtoul(this_opt+6, NULL, 0);
1286 dev_info(dev, "override right: %u\n", inf->modes[0].right_margin);
1287 } else if (!strncmp(this_opt, "upper:", 6)) {
1288 inf->modes[0].upper_margin = simple_strtoul(this_opt+6, NULL, 0);
1289 dev_info(dev, "override upper: %u\n", inf->modes[0].upper_margin);
1290 } else if (!strncmp(this_opt, "lower:", 6)) {
1291 inf->modes[0].lower_margin = simple_strtoul(this_opt+6, NULL, 0);
1292 dev_info(dev, "override lower: %u\n", inf->modes[0].lower_margin);
1293 } else if (!strncmp(this_opt, "hsynclen:", 9)) {
1294 inf->modes[0].hsync_len = simple_strtoul(this_opt+9, NULL, 0);
1295 dev_info(dev, "override hsynclen: %u\n", inf->modes[0].hsync_len);
1296 } else if (!strncmp(this_opt, "vsynclen:", 9)) {
1297 inf->modes[0].vsync_len = simple_strtoul(this_opt+9, NULL, 0);
1298 dev_info(dev, "override vsynclen: %u\n", inf->modes[0].vsync_len);
1299 } else if (!strncmp(this_opt, "hsync:", 6)) {
1300 if (simple_strtoul(this_opt+6, NULL, 0) == 0) {
1301 dev_info(dev, "override hsync: Active Low\n");
1302 inf->modes[0].sync &= ~FB_SYNC_HOR_HIGH_ACT;
1303 } else {
1304 dev_info(dev, "override hsync: Active High\n");
1305 inf->modes[0].sync |= FB_SYNC_HOR_HIGH_ACT;
1306 }
1307 } else if (!strncmp(this_opt, "vsync:", 6)) {
1308 if (simple_strtoul(this_opt+6, NULL, 0) == 0) {
1309 dev_info(dev, "override vsync: Active Low\n");
1310 inf->modes[0].sync &= ~FB_SYNC_VERT_HIGH_ACT;
1311 } else {
1312 dev_info(dev, "override vsync: Active High\n");
1313 inf->modes[0].sync |= FB_SYNC_VERT_HIGH_ACT;
1314 }
1315 } else if (!strncmp(this_opt, "dpc:", 4)) {
1316 if (simple_strtoul(this_opt+4, NULL, 0) == 0) {
1317 dev_info(dev, "override double pixel clock: false\n");
1318 inf->lccr3 &= ~LCCR3_DPC;
1319 } else {
1320 dev_info(dev, "override double pixel clock: true\n");
1321 inf->lccr3 |= LCCR3_DPC;
1322 }
1323 } else if (!strncmp(this_opt, "outputen:", 9)) {
1324 if (simple_strtoul(this_opt+9, NULL, 0) == 0) {
1325 dev_info(dev, "override output enable: active low\n");
1326 inf->lccr3 = (inf->lccr3 & ~LCCR3_OEP) | LCCR3_OutEnL;
1327 } else {
1328 dev_info(dev, "override output enable: active high\n");
1329 inf->lccr3 = (inf->lccr3 & ~LCCR3_OEP) | LCCR3_OutEnH;
1330 }
1331 } else if (!strncmp(this_opt, "pixclockpol:", 12)) {
1332 if (simple_strtoul(this_opt+12, NULL, 0) == 0) {
1333 dev_info(dev, "override pixel clock polarity: falling edge\n");
1334 inf->lccr3 = (inf->lccr3 & ~LCCR3_PCP) | LCCR3_PixFlEdg;
1335 } else {
1336 dev_info(dev, "override pixel clock polarity: rising edge\n");
1337 inf->lccr3 = (inf->lccr3 & ~LCCR3_PCP) | LCCR3_PixRsEdg;
1338 }
1339 } else if (!strncmp(this_opt, "color", 5)) {
1340 inf->lccr0 = (inf->lccr0 & ~LCCR0_CMS) | LCCR0_Color;
1341 } else if (!strncmp(this_opt, "mono", 4)) {
1342 inf->lccr0 = (inf->lccr0 & ~LCCR0_CMS) | LCCR0_Mono;
1343 } else if (!strncmp(this_opt, "active", 6)) {
1344 inf->lccr0 = (inf->lccr0 & ~LCCR0_PAS) | LCCR0_Act;
1345 } else if (!strncmp(this_opt, "passive", 7)) {
1346 inf->lccr0 = (inf->lccr0 & ~LCCR0_PAS) | LCCR0_Pas;
1347 } else if (!strncmp(this_opt, "single", 6)) {
1348 inf->lccr0 = (inf->lccr0 & ~LCCR0_SDS) | LCCR0_Sngl;
1349 } else if (!strncmp(this_opt, "dual", 4)) {
1350 inf->lccr0 = (inf->lccr0 & ~LCCR0_SDS) | LCCR0_Dual;
1351 } else if (!strncmp(this_opt, "4pix", 4)) {
1352 inf->lccr0 = (inf->lccr0 & ~LCCR0_DPD) | LCCR0_4PixMono;
1353 } else if (!strncmp(this_opt, "8pix", 4)) {
1354 inf->lccr0 = (inf->lccr0 & ~LCCR0_DPD) | LCCR0_8PixMono;
1355 } else {
1356 dev_err(dev, "unknown option: %s\n", this_opt);
1357 return -EINVAL;
1358 }
1359 }
1360 return 0;
1361
1362} 1388}
1363#endif 1389#endif
1364 1390