diff options
author | Ville Syrjälä <ville.syrjala@nokia.com> | 2010-03-17 19:36:51 +0100 |
---|---|---|
committer | Tomi Valkeinen <tomi.valkeinen@nokia.com> | 2010-08-03 14:18:46 +0200 |
commit | 078ff546a806b2c2ab74c25c8edd4c6d4680656a (patch) | |
tree | fe988343f6b0038423b637c32e372202a8e5d05a /drivers/video/omap2/omapfb/omapfb-ioctl.c | |
parent | OMAP: DSS2: OMAPFB: Skip unnecessary set_overlay_info() (diff) | |
download | linux-078ff546a806b2c2ab74c25c8edd4c6d4680656a.tar.xz linux-078ff546a806b2c2ab74c25c8edd4c6d4680656a.zip |
OMAP: DSS2: OMAPFB: Add support for switching memory regions
Separate the memory region from the framebuffer device a little bit.
It's now possible to select the memory region used by the framebuffer
device using the new mem_idx parameter of omapfb_plane_info. If the
mem_idx is specified it will be interpreted as an index into the
memory regions array, if it's not specified the framebuffer's index is
used instead. So by default each framebuffer keeps using it's own
memory region which preserves backwards compatibility.
This allows cloning the same memory region to several overlays and yet
each overlay can be controlled independently since they can be
associated with separate framebuffer devices.
Signed-off-by: Ville Syrjälä <ville.syrjala@nokia.com>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@nokia.com>
Diffstat (limited to 'drivers/video/omap2/omapfb/omapfb-ioctl.c')
-rw-r--r-- | drivers/video/omap2/omapfb/omapfb-ioctl.c | 125 |
1 files changed, 102 insertions, 23 deletions
diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c index 9c7361871d78..6635bd75affa 100644 --- a/drivers/video/omap2/omapfb/omapfb-ioctl.c +++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c @@ -34,12 +34,37 @@ #include "omapfb.h" +static u8 get_mem_idx(struct omapfb_info *ofbi) +{ + if (ofbi->id == ofbi->region->id) + return 0; + + return OMAPFB_MEM_IDX_ENABLED | ofbi->region->id; +} + +static struct omapfb2_mem_region *get_mem_region(struct omapfb_info *ofbi, + u8 mem_idx) +{ + struct omapfb2_device *fbdev = ofbi->fbdev; + + if (mem_idx & OMAPFB_MEM_IDX_ENABLED) + mem_idx &= OMAPFB_MEM_IDX_MASK; + else + mem_idx = ofbi->id; + + if (mem_idx >= fbdev->num_fbs) + return NULL; + + return &fbdev->regions[mem_idx]; +} + static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) { struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb2_device *fbdev = ofbi->fbdev; struct omap_overlay *ovl; - struct omap_overlay_info info; + struct omap_overlay_info old_info; + struct omapfb2_mem_region *old_rg, *new_rg; int r = 0; DBG("omapfb_setup_plane\n"); @@ -52,7 +77,14 @@ static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) /* XXX uses only the first overlay */ ovl = ofbi->overlays[0]; - if (pi->enabled && !ofbi->region.size) { + old_rg = ofbi->region; + new_rg = get_mem_region(ofbi, pi->mem_idx); + if (!new_rg) { + r = -EINVAL; + goto out; + } + + if (pi->enabled && !new_rg->size) { /* * This plane's memory was freed, can't enable it * until it's reallocated. @@ -61,27 +93,60 @@ static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) goto out; } - ovl->get_overlay_info(ovl, &info); + ovl->get_overlay_info(ovl, &old_info); - info.pos_x = pi->pos_x; - info.pos_y = pi->pos_y; - info.out_width = pi->out_width; - info.out_height = pi->out_height; - info.enabled = pi->enabled; + if (old_rg != new_rg) { + ofbi->region = new_rg; + set_fb_fix(fbi); + } - r = ovl->set_overlay_info(ovl, &info); - if (r) - goto out; + if (pi->enabled) { + struct omap_overlay_info info; + + r = omapfb_setup_overlay(fbi, ovl, pi->pos_x, pi->pos_y, + pi->out_width, pi->out_height); + if (r) + goto undo; - if (ovl->manager) { - r = ovl->manager->apply(ovl->manager); + ovl->get_overlay_info(ovl, &info); + + if (!info.enabled) { + info.enabled = pi->enabled; + r = ovl->set_overlay_info(ovl, &info); + if (r) + goto undo; + } + } else { + struct omap_overlay_info info; + + ovl->get_overlay_info(ovl, &info); + + info.enabled = pi->enabled; + info.pos_x = pi->pos_x; + info.pos_y = pi->pos_y; + info.out_width = pi->out_width; + info.out_height = pi->out_height; + + r = ovl->set_overlay_info(ovl, &info); if (r) - goto out; + goto undo; } -out: - if (r) - dev_err(fbdev->dev, "setup_plane failed\n"); + if (ovl->manager) + ovl->manager->apply(ovl->manager); + + return 0; + + undo: + if (old_rg != new_rg) { + ofbi->region = old_rg; + set_fb_fix(fbi); + } + + ovl->set_overlay_info(ovl, &old_info); + out: + dev_err(fbdev->dev, "setup_plane failed\n"); + return r; } @@ -92,8 +157,8 @@ static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) if (ofbi->num_overlays != 1) { memset(pi, 0, sizeof(*pi)); } else { - struct omap_overlay_info *ovli; struct omap_overlay *ovl; + struct omap_overlay_info *ovli; ovl = ofbi->overlays[0]; ovli = &ovl->info; @@ -103,6 +168,7 @@ static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) pi->enabled = ovli->enabled; pi->channel_out = 0; /* xxx */ pi->mirror = 0; + pi->mem_idx = get_mem_idx(ofbi); pi->out_width = ovli->out_width; pi->out_height = ovli->out_height; } @@ -123,11 +189,24 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) size = PAGE_ALIGN(mi->size); - rg = &ofbi->region; + rg = ofbi->region; - for (i = 0; i < ofbi->num_overlays; i++) { - if (ofbi->overlays[i]->info.enabled) - return -EBUSY; + if (atomic_read(&rg->map_count)) + return -EBUSY; + + for (i = 0; i < fbdev->num_fbs; i++) { + struct omapfb_info *ofbi2 = FB2OFB(fbdev->fbs[i]); + int j; + + if (ofbi2->region != rg) + continue; + + for (j = 0; j < ofbi2->num_overlays; j++) { + if (ofbi2->overlays[j]->info.enabled) { + r = -EBUSY; + return r; + } + } } if (rg->size != size || rg->type != mi->type) { @@ -146,7 +225,7 @@ static int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb2_mem_region *rg; - rg = &ofbi->region; + rg = ofbi->region; memset(mi, 0, sizeof(*mi)); mi->size = rg->size; |