diff options
Diffstat (limited to 'drivers/video/pxafb.c')
-rw-r--r-- | drivers/video/pxafb.c | 306 |
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 |
1214 | static int __init pxafb_parse_options(struct device *dev, char *options) | 1214 | static 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 | } | ||
1251 | done: | ||
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 | |||
1273 | static 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 | |||
1371 | static 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 | ||