diff options
Diffstat (limited to 'drivers/video/omap2/omapfb/omapfb-main.c')
-rw-r--r-- | drivers/video/omap2/omapfb/omapfb-main.c | 204 |
1 files changed, 137 insertions, 67 deletions
diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index bc225e46fdd2..ca585ef37f25 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c | |||
@@ -31,7 +31,6 @@ | |||
31 | #include <linux/omapfb.h> | 31 | #include <linux/omapfb.h> |
32 | 32 | ||
33 | #include <video/omapdss.h> | 33 | #include <video/omapdss.h> |
34 | #include <plat/vram.h> | ||
35 | #include <video/omapvrfb.h> | 34 | #include <video/omapvrfb.h> |
36 | 35 | ||
37 | #include "omapfb.h" | 36 | #include "omapfb.h" |
@@ -1258,11 +1257,10 @@ static int omapfb_blank(int blank, struct fb_info *fbi) | |||
1258 | 1257 | ||
1259 | switch (blank) { | 1258 | switch (blank) { |
1260 | case FB_BLANK_UNBLANK: | 1259 | case FB_BLANK_UNBLANK: |
1261 | if (display->state != OMAP_DSS_DISPLAY_SUSPENDED) | 1260 | if (display->state == OMAP_DSS_DISPLAY_ACTIVE) |
1262 | goto exit; | 1261 | goto exit; |
1263 | 1262 | ||
1264 | if (display->driver->resume) | 1263 | r = display->driver->enable(display); |
1265 | r = display->driver->resume(display); | ||
1266 | 1264 | ||
1267 | if ((display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) && | 1265 | if ((display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) && |
1268 | d->update_mode == OMAPFB_AUTO_UPDATE && | 1266 | d->update_mode == OMAPFB_AUTO_UPDATE && |
@@ -1283,8 +1281,7 @@ static int omapfb_blank(int blank, struct fb_info *fbi) | |||
1283 | if (d->auto_update_work_enabled) | 1281 | if (d->auto_update_work_enabled) |
1284 | omapfb_stop_auto_update(fbdev, display); | 1282 | omapfb_stop_auto_update(fbdev, display); |
1285 | 1283 | ||
1286 | if (display->driver->suspend) | 1284 | display->driver->disable(display); |
1287 | r = display->driver->suspend(display); | ||
1288 | 1285 | ||
1289 | break; | 1286 | break; |
1290 | 1287 | ||
@@ -1335,24 +1332,25 @@ static void omapfb_free_fbmem(struct fb_info *fbi) | |||
1335 | 1332 | ||
1336 | rg = ofbi->region; | 1333 | rg = ofbi->region; |
1337 | 1334 | ||
1338 | WARN_ON(atomic_read(&rg->map_count)); | 1335 | if (rg->token == NULL) |
1339 | 1336 | return; | |
1340 | if (rg->paddr) | ||
1341 | if (omap_vram_free(rg->paddr, rg->size)) | ||
1342 | dev_err(fbdev->dev, "VRAM FREE failed\n"); | ||
1343 | 1337 | ||
1344 | if (rg->vaddr) | 1338 | WARN_ON(atomic_read(&rg->map_count)); |
1345 | iounmap(rg->vaddr); | ||
1346 | 1339 | ||
1347 | if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) { | 1340 | if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) { |
1348 | /* unmap the 0 angle rotation */ | 1341 | /* unmap the 0 angle rotation */ |
1349 | if (rg->vrfb.vaddr[0]) { | 1342 | if (rg->vrfb.vaddr[0]) { |
1350 | iounmap(rg->vrfb.vaddr[0]); | 1343 | iounmap(rg->vrfb.vaddr[0]); |
1351 | omap_vrfb_release_ctx(&rg->vrfb); | ||
1352 | rg->vrfb.vaddr[0] = NULL; | 1344 | rg->vrfb.vaddr[0] = NULL; |
1353 | } | 1345 | } |
1346 | |||
1347 | omap_vrfb_release_ctx(&rg->vrfb); | ||
1354 | } | 1348 | } |
1355 | 1349 | ||
1350 | dma_free_attrs(fbdev->dev, rg->size, rg->token, rg->dma_handle, | ||
1351 | &rg->attrs); | ||
1352 | |||
1353 | rg->token = NULL; | ||
1356 | rg->vaddr = NULL; | 1354 | rg->vaddr = NULL; |
1357 | rg->paddr = 0; | 1355 | rg->paddr = 0; |
1358 | rg->alloc = 0; | 1356 | rg->alloc = 0; |
@@ -1387,7 +1385,9 @@ static int omapfb_alloc_fbmem(struct fb_info *fbi, unsigned long size, | |||
1387 | struct omapfb_info *ofbi = FB2OFB(fbi); | 1385 | struct omapfb_info *ofbi = FB2OFB(fbi); |
1388 | struct omapfb2_device *fbdev = ofbi->fbdev; | 1386 | struct omapfb2_device *fbdev = ofbi->fbdev; |
1389 | struct omapfb2_mem_region *rg; | 1387 | struct omapfb2_mem_region *rg; |
1390 | void __iomem *vaddr; | 1388 | void *token; |
1389 | DEFINE_DMA_ATTRS(attrs); | ||
1390 | dma_addr_t dma_handle; | ||
1391 | int r; | 1391 | int r; |
1392 | 1392 | ||
1393 | rg = ofbi->region; | 1393 | rg = ofbi->region; |
@@ -1402,42 +1402,40 @@ static int omapfb_alloc_fbmem(struct fb_info *fbi, unsigned long size, | |||
1402 | 1402 | ||
1403 | size = PAGE_ALIGN(size); | 1403 | size = PAGE_ALIGN(size); |
1404 | 1404 | ||
1405 | if (!paddr) { | 1405 | dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs); |
1406 | DBG("allocating %lu bytes for fb %d\n", size, ofbi->id); | ||
1407 | r = omap_vram_alloc(size, &paddr); | ||
1408 | } else { | ||
1409 | DBG("reserving %lu bytes at %lx for fb %d\n", size, paddr, | ||
1410 | ofbi->id); | ||
1411 | r = omap_vram_reserve(paddr, size); | ||
1412 | } | ||
1413 | 1406 | ||
1414 | if (r) { | 1407 | if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) |
1408 | dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &attrs); | ||
1409 | |||
1410 | DBG("allocating %lu bytes for fb %d\n", size, ofbi->id); | ||
1411 | |||
1412 | token = dma_alloc_attrs(fbdev->dev, size, &dma_handle, | ||
1413 | GFP_KERNEL, &attrs); | ||
1414 | |||
1415 | if (token == NULL) { | ||
1415 | dev_err(fbdev->dev, "failed to allocate framebuffer\n"); | 1416 | dev_err(fbdev->dev, "failed to allocate framebuffer\n"); |
1416 | return -ENOMEM; | 1417 | return -ENOMEM; |
1417 | } | 1418 | } |
1418 | 1419 | ||
1419 | if (ofbi->rotation_type != OMAP_DSS_ROT_VRFB) { | 1420 | DBG("allocated VRAM paddr %lx, vaddr %p\n", |
1420 | vaddr = ioremap_wc(paddr, size); | 1421 | (unsigned long)dma_handle, token); |
1421 | |||
1422 | if (!vaddr) { | ||
1423 | dev_err(fbdev->dev, "failed to ioremap framebuffer\n"); | ||
1424 | omap_vram_free(paddr, size); | ||
1425 | return -ENOMEM; | ||
1426 | } | ||
1427 | 1422 | ||
1428 | DBG("allocated VRAM paddr %lx, vaddr %p\n", paddr, vaddr); | 1423 | if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) { |
1429 | } else { | ||
1430 | r = omap_vrfb_request_ctx(&rg->vrfb); | 1424 | r = omap_vrfb_request_ctx(&rg->vrfb); |
1431 | if (r) { | 1425 | if (r) { |
1426 | dma_free_attrs(fbdev->dev, size, token, dma_handle, | ||
1427 | &attrs); | ||
1432 | dev_err(fbdev->dev, "vrfb create ctx failed\n"); | 1428 | dev_err(fbdev->dev, "vrfb create ctx failed\n"); |
1433 | return r; | 1429 | return r; |
1434 | } | 1430 | } |
1435 | |||
1436 | vaddr = NULL; | ||
1437 | } | 1431 | } |
1438 | 1432 | ||
1439 | rg->paddr = paddr; | 1433 | rg->attrs = attrs; |
1440 | rg->vaddr = vaddr; | 1434 | rg->token = token; |
1435 | rg->dma_handle = dma_handle; | ||
1436 | |||
1437 | rg->paddr = (unsigned long)dma_handle; | ||
1438 | rg->vaddr = (void __iomem *)token; | ||
1441 | rg->size = size; | 1439 | rg->size = size; |
1442 | rg->alloc = 1; | 1440 | rg->alloc = 1; |
1443 | 1441 | ||
@@ -1531,6 +1529,9 @@ static int omapfb_parse_vram_param(const char *param, int max_entries, | |||
1531 | 1529 | ||
1532 | } | 1530 | } |
1533 | 1531 | ||
1532 | WARN_ONCE(paddr, | ||
1533 | "reserving memory at predefined address not supported\n"); | ||
1534 | |||
1534 | paddrs[fbnum] = paddr; | 1535 | paddrs[fbnum] = paddr; |
1535 | sizes[fbnum] = size; | 1536 | sizes[fbnum] = size; |
1536 | 1537 | ||
@@ -1610,7 +1611,6 @@ int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type) | |||
1610 | { | 1611 | { |
1611 | struct omapfb_info *ofbi = FB2OFB(fbi); | 1612 | struct omapfb_info *ofbi = FB2OFB(fbi); |
1612 | struct omapfb2_device *fbdev = ofbi->fbdev; | 1613 | struct omapfb2_device *fbdev = ofbi->fbdev; |
1613 | struct omap_dss_device *display = fb2display(fbi); | ||
1614 | struct omapfb2_mem_region *rg = ofbi->region; | 1614 | struct omapfb2_mem_region *rg = ofbi->region; |
1615 | unsigned long old_size = rg->size; | 1615 | unsigned long old_size = rg->size; |
1616 | unsigned long old_paddr = rg->paddr; | 1616 | unsigned long old_paddr = rg->paddr; |
@@ -1625,9 +1625,6 @@ int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type) | |||
1625 | if (old_size == size && old_type == type) | 1625 | if (old_size == size && old_type == type) |
1626 | return 0; | 1626 | return 0; |
1627 | 1627 | ||
1628 | if (display && display->driver->sync) | ||
1629 | display->driver->sync(display); | ||
1630 | |||
1631 | omapfb_free_fbmem(fbi); | 1628 | omapfb_free_fbmem(fbi); |
1632 | 1629 | ||
1633 | if (size == 0) { | 1630 | if (size == 0) { |
@@ -1882,7 +1879,6 @@ static void omapfb_free_resources(struct omapfb2_device *fbdev) | |||
1882 | } | 1879 | } |
1883 | 1880 | ||
1884 | dev_set_drvdata(fbdev->dev, NULL); | 1881 | dev_set_drvdata(fbdev->dev, NULL); |
1885 | kfree(fbdev); | ||
1886 | } | 1882 | } |
1887 | 1883 | ||
1888 | static int omapfb_create_framebuffers(struct omapfb2_device *fbdev) | 1884 | static int omapfb_create_framebuffers(struct omapfb2_device *fbdev) |
@@ -2258,26 +2254,28 @@ static int omapfb_find_best_mode(struct omap_dss_device *display, | |||
2258 | { | 2254 | { |
2259 | struct fb_monspecs *specs; | 2255 | struct fb_monspecs *specs; |
2260 | u8 *edid; | 2256 | u8 *edid; |
2261 | int r, i, best_xres, best_idx, len; | 2257 | int r, i, best_idx, len; |
2262 | 2258 | ||
2263 | if (!display->driver->read_edid) | 2259 | if (!display->driver->read_edid) |
2264 | return -ENODEV; | 2260 | return -ENODEV; |
2265 | 2261 | ||
2266 | len = 0x80 * 2; | 2262 | len = 0x80 * 2; |
2267 | edid = kmalloc(len, GFP_KERNEL); | 2263 | edid = kmalloc(len, GFP_KERNEL); |
2264 | if (edid == NULL) | ||
2265 | return -ENOMEM; | ||
2268 | 2266 | ||
2269 | r = display->driver->read_edid(display, edid, len); | 2267 | r = display->driver->read_edid(display, edid, len); |
2270 | if (r < 0) | 2268 | if (r < 0) |
2271 | goto err1; | 2269 | goto err1; |
2272 | 2270 | ||
2273 | specs = kzalloc(sizeof(*specs), GFP_KERNEL); | 2271 | specs = kzalloc(sizeof(*specs), GFP_KERNEL); |
2272 | if (specs == NULL) { | ||
2273 | r = -ENOMEM; | ||
2274 | goto err1; | ||
2275 | } | ||
2274 | 2276 | ||
2275 | fb_edid_to_monspecs(edid, specs); | 2277 | fb_edid_to_monspecs(edid, specs); |
2276 | 2278 | ||
2277 | if (edid[126] > 0) | ||
2278 | fb_edid_add_monspecs(edid + 0x80, specs); | ||
2279 | |||
2280 | best_xres = 0; | ||
2281 | best_idx = -1; | 2279 | best_idx = -1; |
2282 | 2280 | ||
2283 | for (i = 0; i < specs->modedb_len; ++i) { | 2281 | for (i = 0; i < specs->modedb_len; ++i) { |
@@ -2293,16 +2291,20 @@ static int omapfb_find_best_mode(struct omap_dss_device *display, | |||
2293 | if (m->xres == 2880 || m->xres == 1440) | 2291 | if (m->xres == 2880 || m->xres == 1440) |
2294 | continue; | 2292 | continue; |
2295 | 2293 | ||
2294 | if (m->vmode & FB_VMODE_INTERLACED || | ||
2295 | m->vmode & FB_VMODE_DOUBLE) | ||
2296 | continue; | ||
2297 | |||
2296 | fb_videomode_to_omap_timings(m, display, &t); | 2298 | fb_videomode_to_omap_timings(m, display, &t); |
2297 | 2299 | ||
2298 | r = display->driver->check_timings(display, &t); | 2300 | r = display->driver->check_timings(display, &t); |
2299 | if (r == 0 && best_xres < m->xres) { | 2301 | if (r == 0) { |
2300 | best_xres = m->xres; | ||
2301 | best_idx = i; | 2302 | best_idx = i; |
2303 | break; | ||
2302 | } | 2304 | } |
2303 | } | 2305 | } |
2304 | 2306 | ||
2305 | if (best_xres == 0) { | 2307 | if (best_idx == -1) { |
2306 | r = -ENOENT; | 2308 | r = -ENOENT; |
2307 | goto err2; | 2309 | goto err2; |
2308 | } | 2310 | } |
@@ -2371,15 +2373,62 @@ static int omapfb_init_display(struct omapfb2_device *fbdev, | |||
2371 | return 0; | 2373 | return 0; |
2372 | } | 2374 | } |
2373 | 2375 | ||
2376 | static int omapfb_init_connections(struct omapfb2_device *fbdev, | ||
2377 | struct omap_dss_device *def_dssdev) | ||
2378 | { | ||
2379 | int i, r; | ||
2380 | struct omap_overlay_manager *mgr; | ||
2381 | |||
2382 | if (!def_dssdev->output) { | ||
2383 | dev_err(fbdev->dev, "no output for the default display\n"); | ||
2384 | return -EINVAL; | ||
2385 | } | ||
2386 | |||
2387 | for (i = 0; i < fbdev->num_displays; ++i) { | ||
2388 | struct omap_dss_device *dssdev = fbdev->displays[i].dssdev; | ||
2389 | struct omap_dss_output *out = dssdev->output; | ||
2390 | |||
2391 | mgr = omap_dss_get_overlay_manager(dssdev->channel); | ||
2392 | |||
2393 | if (!mgr || !out) | ||
2394 | continue; | ||
2395 | |||
2396 | if (mgr->output) | ||
2397 | mgr->unset_output(mgr); | ||
2398 | |||
2399 | mgr->set_output(mgr, out); | ||
2400 | } | ||
2401 | |||
2402 | mgr = def_dssdev->output->manager; | ||
2403 | |||
2404 | if (!mgr) { | ||
2405 | dev_err(fbdev->dev, "no ovl manager for the default display\n"); | ||
2406 | return -EINVAL; | ||
2407 | } | ||
2408 | |||
2409 | for (i = 0; i < fbdev->num_overlays; i++) { | ||
2410 | struct omap_overlay *ovl = fbdev->overlays[i]; | ||
2411 | |||
2412 | if (ovl->manager) | ||
2413 | ovl->unset_manager(ovl); | ||
2414 | |||
2415 | r = ovl->set_manager(ovl, mgr); | ||
2416 | if (r) | ||
2417 | dev_warn(fbdev->dev, | ||
2418 | "failed to connect overlay %s to manager %s\n", | ||
2419 | ovl->name, mgr->name); | ||
2420 | } | ||
2421 | |||
2422 | return 0; | ||
2423 | } | ||
2424 | |||
2374 | static int __init omapfb_probe(struct platform_device *pdev) | 2425 | static int __init omapfb_probe(struct platform_device *pdev) |
2375 | { | 2426 | { |
2376 | struct omapfb2_device *fbdev = NULL; | 2427 | struct omapfb2_device *fbdev = NULL; |
2377 | int r = 0; | 2428 | int r = 0; |
2378 | int i; | 2429 | int i; |
2379 | struct omap_overlay *ovl; | ||
2380 | struct omap_dss_device *def_display; | 2430 | struct omap_dss_device *def_display; |
2381 | struct omap_dss_device *dssdev; | 2431 | struct omap_dss_device *dssdev; |
2382 | struct omap_dss_device *ovl_device; | ||
2383 | 2432 | ||
2384 | DBG("omapfb_probe\n"); | 2433 | DBG("omapfb_probe\n"); |
2385 | 2434 | ||
@@ -2389,7 +2438,8 @@ static int __init omapfb_probe(struct platform_device *pdev) | |||
2389 | goto err0; | 2438 | goto err0; |
2390 | } | 2439 | } |
2391 | 2440 | ||
2392 | fbdev = kzalloc(sizeof(struct omapfb2_device), GFP_KERNEL); | 2441 | fbdev = devm_kzalloc(&pdev->dev, sizeof(struct omapfb2_device), |
2442 | GFP_KERNEL); | ||
2393 | if (fbdev == NULL) { | 2443 | if (fbdev == NULL) { |
2394 | r = -ENOMEM; | 2444 | r = -ENOMEM; |
2395 | goto err0; | 2445 | goto err0; |
@@ -2401,13 +2451,15 @@ static int __init omapfb_probe(struct platform_device *pdev) | |||
2401 | "ignoring the module parameter vrfb=y\n"); | 2451 | "ignoring the module parameter vrfb=y\n"); |
2402 | } | 2452 | } |
2403 | 2453 | ||
2454 | r = omapdss_compat_init(); | ||
2455 | if (r) | ||
2456 | goto err0; | ||
2404 | 2457 | ||
2405 | mutex_init(&fbdev->mtx); | 2458 | mutex_init(&fbdev->mtx); |
2406 | 2459 | ||
2407 | fbdev->dev = &pdev->dev; | 2460 | fbdev->dev = &pdev->dev; |
2408 | platform_set_drvdata(pdev, fbdev); | 2461 | platform_set_drvdata(pdev, fbdev); |
2409 | 2462 | ||
2410 | r = 0; | ||
2411 | fbdev->num_displays = 0; | 2463 | fbdev->num_displays = 0; |
2412 | dssdev = NULL; | 2464 | dssdev = NULL; |
2413 | for_each_dss_dev(dssdev) { | 2465 | for_each_dss_dev(dssdev) { |
@@ -2430,9 +2482,6 @@ static int __init omapfb_probe(struct platform_device *pdev) | |||
2430 | d->update_mode = OMAPFB_AUTO_UPDATE; | 2482 | d->update_mode = OMAPFB_AUTO_UPDATE; |
2431 | } | 2483 | } |
2432 | 2484 | ||
2433 | if (r) | ||
2434 | goto cleanup; | ||
2435 | |||
2436 | if (fbdev->num_displays == 0) { | 2485 | if (fbdev->num_displays == 0) { |
2437 | dev_err(&pdev->dev, "no displays\n"); | 2486 | dev_err(&pdev->dev, "no displays\n"); |
2438 | r = -EINVAL; | 2487 | r = -EINVAL; |
@@ -2447,15 +2496,33 @@ static int __init omapfb_probe(struct platform_device *pdev) | |||
2447 | for (i = 0; i < fbdev->num_managers; i++) | 2496 | for (i = 0; i < fbdev->num_managers; i++) |
2448 | fbdev->managers[i] = omap_dss_get_overlay_manager(i); | 2497 | fbdev->managers[i] = omap_dss_get_overlay_manager(i); |
2449 | 2498 | ||
2450 | /* gfx overlay should be the default one. find a display | 2499 | def_display = NULL; |
2451 | * connected to that, and use it as default display */ | 2500 | |
2452 | ovl = omap_dss_get_overlay(0); | 2501 | for (i = 0; i < fbdev->num_displays; ++i) { |
2453 | ovl_device = ovl->get_device(ovl); | 2502 | struct omap_dss_device *dssdev; |
2454 | if (ovl_device) { | 2503 | const char *def_name; |
2455 | def_display = ovl_device; | 2504 | |
2456 | } else { | 2505 | def_name = omapdss_get_default_display_name(); |
2457 | dev_warn(&pdev->dev, "cannot find default display\n"); | 2506 | |
2458 | def_display = NULL; | 2507 | dssdev = fbdev->displays[i].dssdev; |
2508 | |||
2509 | if (def_name == NULL || | ||
2510 | (dssdev->name && strcmp(def_name, dssdev->name) == 0)) { | ||
2511 | def_display = dssdev; | ||
2512 | break; | ||
2513 | } | ||
2514 | } | ||
2515 | |||
2516 | if (def_display == NULL) { | ||
2517 | dev_err(fbdev->dev, "failed to find default display\n"); | ||
2518 | r = -EINVAL; | ||
2519 | goto cleanup; | ||
2520 | } | ||
2521 | |||
2522 | r = omapfb_init_connections(fbdev, def_display); | ||
2523 | if (r) { | ||
2524 | dev_err(fbdev->dev, "failed to init overlay connections\n"); | ||
2525 | goto cleanup; | ||
2459 | } | 2526 | } |
2460 | 2527 | ||
2461 | if (def_mode && strlen(def_mode) > 0) { | 2528 | if (def_mode && strlen(def_mode) > 0) { |
@@ -2506,6 +2573,7 @@ static int __init omapfb_probe(struct platform_device *pdev) | |||
2506 | 2573 | ||
2507 | cleanup: | 2574 | cleanup: |
2508 | omapfb_free_resources(fbdev); | 2575 | omapfb_free_resources(fbdev); |
2576 | omapdss_compat_uninit(); | ||
2509 | err0: | 2577 | err0: |
2510 | dev_err(&pdev->dev, "failed to setup omapfb\n"); | 2578 | dev_err(&pdev->dev, "failed to setup omapfb\n"); |
2511 | return r; | 2579 | return r; |
@@ -2521,6 +2589,8 @@ static int __exit omapfb_remove(struct platform_device *pdev) | |||
2521 | 2589 | ||
2522 | omapfb_free_resources(fbdev); | 2590 | omapfb_free_resources(fbdev); |
2523 | 2591 | ||
2592 | omapdss_compat_uninit(); | ||
2593 | |||
2524 | return 0; | 2594 | return 0; |
2525 | } | 2595 | } |
2526 | 2596 | ||