summaryrefslogtreecommitdiffstats
path: root/drivers/video/omap2/omapfb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/omap2/omapfb')
-rw-r--r--drivers/video/omap2/omapfb/Kconfig2
-rw-r--r--drivers/video/omap2/omapfb/omapfb-ioctl.c188
-rw-r--r--drivers/video/omap2/omapfb/omapfb-main.c255
-rw-r--r--drivers/video/omap2/omapfb/omapfb-sysfs.c70
-rw-r--r--drivers/video/omap2/omapfb/omapfb.h29
5 files changed, 417 insertions, 127 deletions
diff --git a/drivers/video/omap2/omapfb/Kconfig b/drivers/video/omap2/omapfb/Kconfig
index 43496d6c377f..65149b22cf37 100644
--- a/drivers/video/omap2/omapfb/Kconfig
+++ b/drivers/video/omap2/omapfb/Kconfig
@@ -3,7 +3,7 @@ menuconfig FB_OMAP2
depends on FB && OMAP2_DSS
select OMAP2_VRAM
- select OMAP2_VRFB
+ select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c
index 9c7361871d78..6f435450987e 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,36 +77,106 @@ 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;
+ }
+
+ /* Take the locks in a specific order to keep lockdep happy */
+ if (old_rg->id < new_rg->id) {
+ omapfb_get_mem_region(old_rg);
+ omapfb_get_mem_region(new_rg);
+ } else if (new_rg->id < old_rg->id) {
+ omapfb_get_mem_region(new_rg);
+ omapfb_get_mem_region(old_rg);
+ } else
+ omapfb_get_mem_region(old_rg);
+
+ if (pi->enabled && !new_rg->size) {
/*
* This plane's memory was freed, can't enable it
* until it's reallocated.
*/
r = -EINVAL;
- goto out;
+ goto put_mem;
}
- 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;
- if (ovl->manager) {
- r = ovl->manager->apply(ovl->manager);
+ r = omapfb_setup_overlay(fbi, ovl, pi->pos_x, pi->pos_y,
+ pi->out_width, pi->out_height);
if (r)
- goto out;
+ goto undo;
+
+ 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 undo;
}
-out:
- if (r)
- dev_err(fbdev->dev, "setup_plane failed\n");
+ if (ovl->manager)
+ ovl->manager->apply(ovl->manager);
+
+ /* Release the locks in a specific order to keep lockdep happy */
+ if (old_rg->id > new_rg->id) {
+ omapfb_put_mem_region(old_rg);
+ omapfb_put_mem_region(new_rg);
+ } else if (new_rg->id > old_rg->id) {
+ omapfb_put_mem_region(new_rg);
+ omapfb_put_mem_region(old_rg);
+ } else
+ omapfb_put_mem_region(old_rg);
+
+ return 0;
+
+ undo:
+ if (old_rg != new_rg) {
+ ofbi->region = old_rg;
+ set_fb_fix(fbi);
+ }
+
+ ovl->set_overlay_info(ovl, &old_info);
+ put_mem:
+ /* Release the locks in a specific order to keep lockdep happy */
+ if (old_rg->id > new_rg->id) {
+ omapfb_put_mem_region(old_rg);
+ omapfb_put_mem_region(new_rg);
+ } else if (new_rg->id > old_rg->id) {
+ omapfb_put_mem_region(new_rg);
+ omapfb_put_mem_region(old_rg);
+ } else
+ omapfb_put_mem_region(old_rg);
+ out:
+ dev_err(fbdev->dev, "setup_plane failed\n");
+
return r;
}
@@ -92,8 +187,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 +198,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;
}
@@ -115,7 +211,7 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
struct omapfb_info *ofbi = FB2OFB(fbi);
struct omapfb2_device *fbdev = ofbi->fbdev;
struct omapfb2_mem_region *rg;
- int r, i;
+ int r = 0, i;
size_t size;
if (mi->type > OMAPFB_MEMTYPE_MAX)
@@ -123,22 +219,44 @@ 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;
+ down_write_nested(&rg->lock, rg->id);
+ atomic_inc(&rg->lock_count);
+
+ if (atomic_read(&rg->map_count)) {
+ r = -EBUSY;
+ goto out;
+ }
+
+ 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;
+ goto out;
+ }
+ }
}
if (rg->size != size || rg->type != mi->type) {
r = omapfb_realloc_fbmem(fbi, size, mi->type);
if (r) {
dev_err(fbdev->dev, "realloc fbmem failed\n");
- return r;
+ goto out;
}
}
- return 0;
+ out:
+ atomic_dec(&rg->lock_count);
+ up_write(&rg->lock);
+
+ return r;
}
static int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
@@ -146,12 +264,14 @@ 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 = omapfb_get_mem_region(ofbi->region);
memset(mi, 0, sizeof(*mi));
mi->size = rg->size;
mi->type = rg->type;
+ omapfb_put_mem_region(rg);
+
return 0;
}
@@ -490,6 +610,7 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
struct omapfb_vram_info vram_info;
struct omapfb_tearsync_info tearsync_info;
struct omapfb_display_info display_info;
+ u32 crt;
} p;
int r = 0;
@@ -648,6 +769,17 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
r = -EFAULT;
break;
+ case FBIO_WAITFORVSYNC:
+ if (get_user(p.crt, (__u32 __user *)arg)) {
+ r = -EFAULT;
+ break;
+ }
+ if (p.crt != 0) {
+ r = -ENODEV;
+ break;
+ }
+ /* FALLTHROUGH */
+
case OMAPFB_WAITFORVSYNC:
DBG("ioctl WAITFORVSYNC\n");
if (!display) {
@@ -738,7 +870,7 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
break;
}
- if (!display->driver->enable_te) {
+ if (!display || !display->driver->enable_te) {
r = -ENODEV;
break;
}
diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c
index 4b4506da96da..6a704f176c22 100644
--- a/drivers/video/omap2/omapfb/omapfb-main.c
+++ b/drivers/video/omap2/omapfb/omapfb-main.c
@@ -157,7 +157,7 @@ static void fill_fb(struct fb_info *fbi)
static unsigned omapfb_get_vrfb_offset(const struct omapfb_info *ofbi, int rot)
{
- const struct vrfb *vrfb = &ofbi->region.vrfb;
+ const struct vrfb *vrfb = &ofbi->region->vrfb;
unsigned offset;
switch (rot) {
@@ -185,27 +185,27 @@ static unsigned omapfb_get_vrfb_offset(const struct omapfb_info *ofbi, int rot)
static u32 omapfb_get_region_rot_paddr(const struct omapfb_info *ofbi, int rot)
{
if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
- return ofbi->region.vrfb.paddr[rot]
+ return ofbi->region->vrfb.paddr[rot]
+ omapfb_get_vrfb_offset(ofbi, rot);
} else {
- return ofbi->region.paddr;
+ return ofbi->region->paddr;
}
}
static u32 omapfb_get_region_paddr(const struct omapfb_info *ofbi)
{
if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
- return ofbi->region.vrfb.paddr[0];
+ return ofbi->region->vrfb.paddr[0];
else
- return ofbi->region.paddr;
+ return ofbi->region->paddr;
}
static void __iomem *omapfb_get_region_vaddr(const struct omapfb_info *ofbi)
{
if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
- return ofbi->region.vrfb.vaddr[0];
+ return ofbi->region->vrfb.vaddr[0];
else
- return ofbi->region.vaddr;
+ return ofbi->region->vaddr;
}
static struct omapfb_colormode omapfb_colormodes[] = {
@@ -450,7 +450,7 @@ static int check_vrfb_fb_size(unsigned long region_size,
static int check_fb_size(const struct omapfb_info *ofbi,
struct fb_var_screeninfo *var)
{
- unsigned long max_frame_size = ofbi->region.size;
+ unsigned long max_frame_size = ofbi->region->size;
int bytespp = var->bits_per_pixel >> 3;
unsigned long line_size = var->xres_virtual * bytespp;
@@ -497,7 +497,7 @@ static int check_fb_size(const struct omapfb_info *ofbi,
static int setup_vrfb_rotation(struct fb_info *fbi)
{
struct omapfb_info *ofbi = FB2OFB(fbi);
- struct omapfb2_mem_region *rg = &ofbi->region;
+ struct omapfb2_mem_region *rg = ofbi->region;
struct vrfb *vrfb = &rg->vrfb;
struct fb_var_screeninfo *var = &fbi->var;
struct fb_fix_screeninfo *fix = &fbi->fix;
@@ -558,9 +558,9 @@ static int setup_vrfb_rotation(struct fb_info *fbi)
return r;
/* used by open/write in fbmem.c */
- fbi->screen_base = ofbi->region.vrfb.vaddr[0];
+ fbi->screen_base = ofbi->region->vrfb.vaddr[0];
- fix->smem_start = ofbi->region.vrfb.paddr[0];
+ fix->smem_start = ofbi->region->vrfb.paddr[0];
switch (var->nonstd) {
case OMAPFB_COLOR_YUV422:
@@ -599,7 +599,7 @@ void set_fb_fix(struct fb_info *fbi)
struct fb_fix_screeninfo *fix = &fbi->fix;
struct fb_var_screeninfo *var = &fbi->var;
struct omapfb_info *ofbi = FB2OFB(fbi);
- struct omapfb2_mem_region *rg = &ofbi->region;
+ struct omapfb2_mem_region *rg = ofbi->region;
DBG("set_fb_fix\n");
@@ -668,8 +668,7 @@ int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var)
DBG("check_fb_var %d\n", ofbi->id);
- if (ofbi->region.size == 0)
- return 0;
+ WARN_ON(!atomic_read(&ofbi->region->lock_count));
r = fb_mode_to_dss_mode(var, &mode);
if (r) {
@@ -684,13 +683,14 @@ int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var)
}
}
- if (var->rotate < 0 || var->rotate > 3)
+ if (var->rotate > 3)
return -EINVAL;
if (check_fb_res_bounds(var))
return -EINVAL;
- if (check_fb_size(ofbi, var))
+ /* When no memory is allocated ignore the size check */
+ if (ofbi->region->size != 0 && check_fb_size(ofbi, var))
return -EINVAL;
if (var->xres + var->xoffset > var->xres_virtual)
@@ -714,10 +714,10 @@ int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var)
var->pixclock = timings.pixel_clock != 0 ?
KHZ2PICOS(timings.pixel_clock) :
0;
- var->left_margin = timings.hfp;
- var->right_margin = timings.hbp;
- var->upper_margin = timings.vfp;
- var->lower_margin = timings.vbp;
+ var->left_margin = timings.hbp;
+ var->right_margin = timings.hfp;
+ var->upper_margin = timings.vbp;
+ var->lower_margin = timings.vfp;
var->hsync_len = timings.hsw;
var->vsync_len = timings.vsw;
} else {
@@ -822,9 +822,43 @@ static unsigned calc_rotation_offset_vrfb(const struct fb_var_screeninfo *var,
return offset;
}
+static void omapfb_calc_addr(const struct omapfb_info *ofbi,
+ const struct fb_var_screeninfo *var,
+ const struct fb_fix_screeninfo *fix,
+ int rotation, u32 *paddr, void __iomem **vaddr)
+{
+ u32 data_start_p;
+ void __iomem *data_start_v;
+ int offset;
+
+ if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
+ data_start_p = omapfb_get_region_rot_paddr(ofbi, rotation);
+ data_start_v = NULL;
+ } else {
+ data_start_p = omapfb_get_region_paddr(ofbi);
+ data_start_v = omapfb_get_region_vaddr(ofbi);
+ }
+
+ if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
+ offset = calc_rotation_offset_vrfb(var, fix, rotation);
+ else
+ offset = calc_rotation_offset_dma(var, fix, rotation);
+
+ data_start_p += offset;
+ data_start_v += offset;
+
+ if (offset)
+ DBG("offset %d, %d = %d\n",
+ var->xoffset, var->yoffset, offset);
+
+ DBG("paddr %x, vaddr %p\n", data_start_p, data_start_v);
+
+ *paddr = data_start_p;
+ *vaddr = data_start_v;
+}
/* setup overlay according to the fb */
-static int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl,
+int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl,
u16 posx, u16 posy, u16 outw, u16 outh)
{
int r = 0;
@@ -832,9 +866,8 @@ static int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl,
struct fb_var_screeninfo *var = &fbi->var;
struct fb_fix_screeninfo *fix = &fbi->fix;
enum omap_color_mode mode = 0;
- int offset;
- u32 data_start_p;
- void __iomem *data_start_v;
+ u32 data_start_p = 0;
+ void __iomem *data_start_v = NULL;
struct omap_overlay_info info;
int xres, yres;
int screen_width;
@@ -842,6 +875,8 @@ static int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl,
int rotation = var->rotate;
int i;
+ WARN_ON(!atomic_read(&ofbi->region->lock_count));
+
for (i = 0; i < ofbi->num_overlays; i++) {
if (ovl != ofbi->overlays[i])
continue;
@@ -861,28 +896,9 @@ static int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl,
yres = var->yres;
}
-
- if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
- data_start_p = omapfb_get_region_rot_paddr(ofbi, rotation);
- data_start_v = NULL;
- } else {
- data_start_p = omapfb_get_region_paddr(ofbi);
- data_start_v = omapfb_get_region_vaddr(ofbi);
- }
-
- if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
- offset = calc_rotation_offset_vrfb(var, fix, rotation);
- else
- offset = calc_rotation_offset_dma(var, fix, rotation);
-
- data_start_p += offset;
- data_start_v += offset;
-
- if (offset)
- DBG("offset %d, %d = %d\n",
- var->xoffset, var->yoffset, offset);
-
- DBG("paddr %x, vaddr %p\n", data_start_p, data_start_v);
+ if (ofbi->region->size)
+ omapfb_calc_addr(ofbi, var, fix, rotation,
+ &data_start_p, &data_start_v);
r = fb_mode_to_dss_mode(var, &mode);
if (r) {
@@ -954,12 +970,14 @@ int omapfb_apply_changes(struct fb_info *fbi, int init)
fill_fb(fbi);
#endif
+ WARN_ON(!atomic_read(&ofbi->region->lock_count));
+
for (i = 0; i < ofbi->num_overlays; i++) {
ovl = ofbi->overlays[i];
DBG("apply_changes, fb %d, ovl %d\n", ofbi->id, ovl->id);
- if (ofbi->region.size == 0) {
+ if (ofbi->region->size == 0) {
/* the fb is not available. disable the overlay */
omapfb_overlay_enable(ovl, 0);
if (!init && ovl->manager)
@@ -1007,36 +1025,48 @@ err:
* DO NOT MODIFY PAR */
static int omapfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi)
{
+ struct omapfb_info *ofbi = FB2OFB(fbi);
int r;
DBG("check_var(%d)\n", FB2OFB(fbi)->id);
+ omapfb_get_mem_region(ofbi->region);
+
r = check_fb_var(fbi, var);
+ omapfb_put_mem_region(ofbi->region);
+
return r;
}
/* set the video mode according to info->var */
static int omapfb_set_par(struct fb_info *fbi)
{
+ struct omapfb_info *ofbi = FB2OFB(fbi);
int r;
DBG("set_par(%d)\n", FB2OFB(fbi)->id);
+ omapfb_get_mem_region(ofbi->region);
+
set_fb_fix(fbi);
r = setup_vrfb_rotation(fbi);
if (r)
- return r;
+ goto out;
r = omapfb_apply_changes(fbi, 0);
+ out:
+ omapfb_put_mem_region(ofbi->region);
+
return r;
}
static int omapfb_pan_display(struct fb_var_screeninfo *var,
struct fb_info *fbi)
{
+ struct omapfb_info *ofbi = FB2OFB(fbi);
struct fb_var_screeninfo new_var;
int r;
@@ -1052,23 +1082,31 @@ static int omapfb_pan_display(struct fb_var_screeninfo *var,
fbi->var = new_var;
+ omapfb_get_mem_region(ofbi->region);
+
r = omapfb_apply_changes(fbi, 0);
+ omapfb_put_mem_region(ofbi->region);
+
return r;
}
static void mmap_user_open(struct vm_area_struct *vma)
{
- struct omapfb_info *ofbi = (struct omapfb_info *)vma->vm_private_data;
+ struct omapfb2_mem_region *rg = vma->vm_private_data;
- atomic_inc(&ofbi->map_count);
+ omapfb_get_mem_region(rg);
+ atomic_inc(&rg->map_count);
+ omapfb_put_mem_region(rg);
}
static void mmap_user_close(struct vm_area_struct *vma)
{
- struct omapfb_info *ofbi = (struct omapfb_info *)vma->vm_private_data;
+ struct omapfb2_mem_region *rg = vma->vm_private_data;
- atomic_dec(&ofbi->map_count);
+ omapfb_get_mem_region(rg);
+ atomic_dec(&rg->map_count);
+ omapfb_put_mem_region(rg);
}
static struct vm_operations_struct mmap_user_ops = {
@@ -1080,9 +1118,11 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
{
struct omapfb_info *ofbi = FB2OFB(fbi);
struct fb_fix_screeninfo *fix = &fbi->fix;
+ struct omapfb2_mem_region *rg;
unsigned long off;
unsigned long start;
u32 len;
+ int r = -EINVAL;
if (vma->vm_end - vma->vm_start == 0)
return 0;
@@ -1090,12 +1130,14 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
return -EINVAL;
off = vma->vm_pgoff << PAGE_SHIFT;
+ rg = omapfb_get_mem_region(ofbi->region);
+
start = omapfb_get_region_paddr(ofbi);
len = fix->smem_len;
if (off >= len)
- return -EINVAL;
+ goto error;
if ((vma->vm_end - vma->vm_start + off) > len)
- return -EINVAL;
+ goto error;
off += start;
@@ -1105,13 +1147,25 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
vma->vm_flags |= VM_IO | VM_RESERVED;
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
vma->vm_ops = &mmap_user_ops;
- vma->vm_private_data = ofbi;
+ vma->vm_private_data = rg;
if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
- vma->vm_end - vma->vm_start, vma->vm_page_prot))
- return -EAGAIN;
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot)) {
+ r = -EAGAIN;
+ goto error;
+ }
+
/* vm_ops.open won't be called for mmap itself. */
- atomic_inc(&ofbi->map_count);
+ atomic_inc(&rg->map_count);
+
+ omapfb_put_mem_region(rg);
+
return 0;
+
+ error:
+ omapfb_put_mem_region(ofbi->region);
+
+ return r;
}
/* Store a single color palette entry into a pseudo palette or the hardware
@@ -1154,11 +1208,6 @@ static int _setcolreg(struct fb_info *fbi, u_int regno, u_int red, u_int green,
if (r != 0)
break;
- if (regno < 0) {
- r = -EINVAL;
- break;
- }
-
if (regno < 16) {
u16 pal;
pal = ((red >> (16 - var->red.length)) <<
@@ -1217,6 +1266,9 @@ static int omapfb_blank(int blank, struct fb_info *fbi)
int do_update = 0;
int r = 0;
+ if (!display)
+ return -EINVAL;
+
omapfb_lock(fbdev);
switch (blank) {
@@ -1300,7 +1352,9 @@ static void omapfb_free_fbmem(struct fb_info *fbi)
struct omapfb2_device *fbdev = ofbi->fbdev;
struct omapfb2_mem_region *rg;
- rg = &ofbi->region;
+ rg = ofbi->region;
+
+ WARN_ON(atomic_read(&rg->map_count));
if (rg->paddr)
if (omap_vram_free(rg->paddr, rg->size))
@@ -1355,8 +1409,15 @@ static int omapfb_alloc_fbmem(struct fb_info *fbi, unsigned long size,
void __iomem *vaddr;
int r;
- rg = &ofbi->region;
- memset(rg, 0, sizeof(*rg));
+ rg = ofbi->region;
+
+ rg->paddr = 0;
+ rg->vaddr = NULL;
+ memset(&rg->vrfb, 0, sizeof rg->vrfb);
+ rg->size = 0;
+ rg->type = 0;
+ rg->alloc = false;
+ rg->map = false;
size = PAGE_ALIGN(size);
@@ -1609,7 +1670,7 @@ static int omapfb_allocate_all_fbs(struct omapfb2_device *fbdev)
for (i = 0; i < fbdev->num_fbs; i++) {
struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
struct omapfb2_mem_region *rg;
- rg = &ofbi->region;
+ rg = ofbi->region;
DBG("region%d phys %08x virt %p size=%lu\n",
i,
@@ -1626,7 +1687,7 @@ int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type)
struct omapfb_info *ofbi = FB2OFB(fbi);
struct omapfb2_device *fbdev = ofbi->fbdev;
struct omap_dss_device *display = fb2display(fbi);
- struct omapfb2_mem_region *rg = &ofbi->region;
+ struct omapfb2_mem_region *rg = ofbi->region;
unsigned long old_size = rg->size;
unsigned long old_paddr = rg->paddr;
int old_type = rg->type;
@@ -1709,7 +1770,7 @@ static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi)
fbi->flags = FBINFO_FLAG_DEFAULT;
fbi->pseudo_palette = fbdev->pseudo_palette;
- if (ofbi->region.size == 0) {
+ if (ofbi->region->size == 0) {
clear_fb_info(fbi);
return 0;
}
@@ -1871,6 +1932,10 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev)
ofbi->fbdev = fbdev;
ofbi->id = i;
+ ofbi->region = &fbdev->regions[i];
+ ofbi->region->id = i;
+ init_rwsem(&ofbi->region->lock);
+
/* assign these early, so that fb alloc can use them */
ofbi->rotation_type = def_vrfb ? OMAP_DSS_ROT_VRFB :
OMAP_DSS_ROT_DMA;
@@ -1900,7 +1965,13 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev)
/* setup fb_infos */
for (i = 0; i < fbdev->num_fbs; i++) {
- r = omapfb_fb_init(fbdev, fbdev->fbs[i]);
+ struct fb_info *fbi = fbdev->fbs[i];
+ struct omapfb_info *ofbi = FB2OFB(fbi);
+
+ omapfb_get_mem_region(ofbi->region);
+ r = omapfb_fb_init(fbdev, fbi);
+ omapfb_put_mem_region(ofbi->region);
+
if (r) {
dev_err(fbdev->dev, "failed to setup fb_info\n");
return r;
@@ -1921,20 +1992,19 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev)
DBG("framebuffers registered\n");
for (i = 0; i < fbdev->num_fbs; i++) {
- r = omapfb_apply_changes(fbdev->fbs[i], 1);
+ struct fb_info *fbi = fbdev->fbs[i];
+ struct omapfb_info *ofbi = FB2OFB(fbi);
+
+ omapfb_get_mem_region(ofbi->region);
+ r = omapfb_apply_changes(fbi, 1);
+ omapfb_put_mem_region(ofbi->region);
+
if (r) {
dev_err(fbdev->dev, "failed to change mode\n");
return r;
}
}
- DBG("create sysfs for fbs\n");
- r = omapfb_create_sysfs(fbdev);
- if (r) {
- dev_err(fbdev->dev, "failed to create sysfs entries\n");
- return r;
- }
-
/* Enable fb0 */
if (fbdev->num_fbs > 0) {
struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[0]);
@@ -1968,11 +2038,11 @@ static int omapfb_mode_to_timings(const char *mode_str,
#ifdef CONFIG_OMAP2_DSS_VENC
if (strcmp(mode_str, "pal") == 0) {
*timings = omap_dss_pal_timings;
- *bpp = 0;
+ *bpp = 24;
return 0;
} else if (strcmp(mode_str, "ntsc") == 0) {
*timings = omap_dss_ntsc_timings;
- *bpp = 0;
+ *bpp = 24;
return 0;
}
#endif
@@ -1989,10 +2059,10 @@ static int omapfb_mode_to_timings(const char *mode_str,
if (r != 0) {
timings->pixel_clock = PICOS2KHZ(var.pixclock);
- timings->hfp = var.left_margin;
- timings->hbp = var.right_margin;
- timings->vfp = var.upper_margin;
- timings->vbp = var.lower_margin;
+ timings->hbp = var.left_margin;
+ timings->hfp = var.right_margin;
+ timings->vbp = var.upper_margin;
+ timings->vfp = var.lower_margin;
timings->hsw = var.hsync_len;
timings->vsw = var.vsync_len;
timings->x_res = var.xres;
@@ -2128,6 +2198,16 @@ static int omapfb_probe(struct platform_device *pdev)
goto err0;
}
+ /* TODO : Replace cpu check with omap_has_vrfb once HAS_FEATURE
+ * available for OMAP2 and OMAP3
+ */
+ if (def_vrfb && !cpu_is_omap24xx() && !cpu_is_omap34xx()) {
+ def_vrfb = 0;
+ dev_warn(&pdev->dev, "VRFB is not supported on this hardware, "
+ "ignoring the module parameter vrfb=y\n");
+ }
+
+
mutex_init(&fbdev->mtx);
fbdev->dev = &pdev->dev;
@@ -2220,6 +2300,13 @@ static int omapfb_probe(struct platform_device *pdev)
}
}
+ DBG("create sysfs for fbs\n");
+ r = omapfb_create_sysfs(fbdev);
+ if (r) {
+ dev_err(fbdev->dev, "failed to create sysfs entries\n");
+ goto cleanup;
+ }
+
return 0;
cleanup:
diff --git a/drivers/video/omap2/omapfb/omapfb-sysfs.c b/drivers/video/omap2/omapfb/omapfb-sysfs.c
index 5179219128bd..6f9c72cd6bb0 100644
--- a/drivers/video/omap2/omapfb/omapfb-sysfs.c
+++ b/drivers/video/omap2/omapfb/omapfb-sysfs.c
@@ -49,6 +49,7 @@ static ssize_t store_rotate_type(struct device *dev,
{
struct fb_info *fbi = dev_get_drvdata(dev);
struct omapfb_info *ofbi = FB2OFB(fbi);
+ struct omapfb2_mem_region *rg;
enum omap_dss_rotation_type rot_type;
int r;
@@ -64,9 +65,11 @@ static ssize_t store_rotate_type(struct device *dev,
if (rot_type == ofbi->rotation_type)
goto out;
- if (ofbi->region.size) {
+ rg = omapfb_get_mem_region(ofbi->region);
+
+ if (rg->size) {
r = -EBUSY;
- goto out;
+ goto put_region;
}
ofbi->rotation_type = rot_type;
@@ -75,6 +78,8 @@ static ssize_t store_rotate_type(struct device *dev,
* Since the VRAM for this FB is not allocated at the moment we don't
* need to do any further parameter checking at this point.
*/
+put_region:
+ omapfb_put_mem_region(rg);
out:
unlock_fb_info(fbi);
@@ -97,7 +102,7 @@ static ssize_t store_mirror(struct device *dev,
{
struct fb_info *fbi = dev_get_drvdata(dev);
struct omapfb_info *ofbi = FB2OFB(fbi);
- bool mirror;
+ unsigned long mirror;
int r;
struct fb_var_screeninfo new_var;
@@ -111,6 +116,8 @@ static ssize_t store_mirror(struct device *dev,
ofbi->mirror = mirror;
+ omapfb_get_mem_region(ofbi->region);
+
memcpy(&new_var, &fbi->var, sizeof(new_var));
r = check_fb_var(fbi, &new_var);
if (r)
@@ -125,6 +132,8 @@ static ssize_t store_mirror(struct device *dev,
r = count;
out:
+ omapfb_put_mem_region(ofbi->region);
+
unlock_fb_info(fbi);
return r;
@@ -263,11 +272,15 @@ static ssize_t store_overlays(struct device *dev, struct device_attribute *attr,
DBG("detaching %d\n", ofbi->overlays[i]->id);
+ omapfb_get_mem_region(ofbi->region);
+
omapfb_overlay_enable(ovl, 0);
if (ovl->manager)
ovl->manager->apply(ovl->manager);
+ omapfb_put_mem_region(ofbi->region);
+
for (t = i + 1; t < ofbi->num_overlays; t++) {
ofbi->rotation[t-1] = ofbi->rotation[t];
ofbi->overlays[t-1] = ofbi->overlays[t];
@@ -300,7 +313,12 @@ static ssize_t store_overlays(struct device *dev, struct device_attribute *attr,
}
if (added) {
+ omapfb_get_mem_region(ofbi->region);
+
r = omapfb_apply_changes(fbi, 0);
+
+ omapfb_put_mem_region(ofbi->region);
+
if (r)
goto out;
}
@@ -388,7 +406,12 @@ static ssize_t store_overlays_rotate(struct device *dev,
for (i = 0; i < num_ovls; ++i)
ofbi->rotation[i] = rotation[i];
+ omapfb_get_mem_region(ofbi->region);
+
r = omapfb_apply_changes(fbi, 0);
+
+ omapfb_put_mem_region(ofbi->region);
+
if (r)
goto out;
@@ -408,7 +431,7 @@ static ssize_t show_size(struct device *dev,
struct fb_info *fbi = dev_get_drvdata(dev);
struct omapfb_info *ofbi = FB2OFB(fbi);
- return snprintf(buf, PAGE_SIZE, "%lu\n", ofbi->region.size);
+ return snprintf(buf, PAGE_SIZE, "%lu\n", ofbi->region->size);
}
static ssize_t store_size(struct device *dev, struct device_attribute *attr,
@@ -416,6 +439,8 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr,
{
struct fb_info *fbi = dev_get_drvdata(dev);
struct omapfb_info *ofbi = FB2OFB(fbi);
+ struct omapfb2_device *fbdev = ofbi->fbdev;
+ struct omapfb2_mem_region *rg;
unsigned long size;
int r;
int i;
@@ -425,15 +450,33 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr,
if (!lock_fb_info(fbi))
return -ENODEV;
- for (i = 0; i < ofbi->num_overlays; i++) {
- if (ofbi->overlays[i]->info.enabled) {
- r = -EBUSY;
- goto out;
+ rg = ofbi->region;
+
+ down_write_nested(&rg->lock, rg->id);
+ atomic_inc(&rg->lock_count);
+
+ if (atomic_read(&rg->map_count)) {
+ r = -EBUSY;
+ goto out;
+ }
+
+ 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;
+ goto out;
+ }
}
}
- if (size != ofbi->region.size) {
- r = omapfb_realloc_fbmem(fbi, size, ofbi->region.type);
+ if (size != ofbi->region->size) {
+ r = omapfb_realloc_fbmem(fbi, size, ofbi->region->type);
if (r) {
dev_err(dev, "realloc fbmem failed\n");
goto out;
@@ -442,6 +485,9 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr,
r = count;
out:
+ atomic_dec(&rg->lock_count);
+ up_write(&rg->lock);
+
unlock_fb_info(fbi);
return r;
@@ -453,7 +499,7 @@ static ssize_t show_phys(struct device *dev,
struct fb_info *fbi = dev_get_drvdata(dev);
struct omapfb_info *ofbi = FB2OFB(fbi);
- return snprintf(buf, PAGE_SIZE, "%0x\n", ofbi->region.paddr);
+ return snprintf(buf, PAGE_SIZE, "%0x\n", ofbi->region->paddr);
}
static ssize_t show_virt(struct device *dev,
@@ -462,7 +508,7 @@ static ssize_t show_virt(struct device *dev,
struct fb_info *fbi = dev_get_drvdata(dev);
struct omapfb_info *ofbi = FB2OFB(fbi);
- return snprintf(buf, PAGE_SIZE, "%p\n", ofbi->region.vaddr);
+ return snprintf(buf, PAGE_SIZE, "%p\n", ofbi->region->vaddr);
}
static struct device_attribute omapfb_attrs[] = {
diff --git a/drivers/video/omap2/omapfb/omapfb.h b/drivers/video/omap2/omapfb/omapfb.h
index cd54fdbfd8bb..1305fc9880ba 100644
--- a/drivers/video/omap2/omapfb/omapfb.h
+++ b/drivers/video/omap2/omapfb/omapfb.h
@@ -27,6 +27,8 @@
#define DEBUG
#endif
+#include <linux/rwsem.h>
+
#include <plat/display.h>
#ifdef DEBUG
@@ -44,6 +46,7 @@ extern unsigned int omapfb_debug;
#define OMAPFB_MAX_OVL_PER_FB 3
struct omapfb2_mem_region {
+ int id;
u32 paddr;
void __iomem *vaddr;
struct vrfb vrfb;
@@ -51,13 +54,15 @@ struct omapfb2_mem_region {
u8 type; /* OMAPFB_PLANE_MEM_* */
bool alloc; /* allocated by the driver */
bool map; /* kernel mapped by the driver */
+ atomic_t map_count;
+ struct rw_semaphore lock;
+ atomic_t lock_count;
};
/* appended to fb_info */
struct omapfb_info {
int id;
- struct omapfb2_mem_region region;
- atomic_t map_count;
+ struct omapfb2_mem_region *region;
int num_overlays;
struct omap_overlay *overlays[OMAPFB_MAX_OVL_PER_FB];
struct omapfb2_device *fbdev;
@@ -76,6 +81,7 @@ struct omapfb2_device {
unsigned num_fbs;
struct fb_info *fbs[10];
+ struct omapfb2_mem_region regions[10];
unsigned num_displays;
struct omap_dss_device *displays[10];
@@ -117,6 +123,9 @@ int omapfb_update_window(struct fb_info *fbi,
int dss_mode_to_fb_mode(enum omap_color_mode dssmode,
struct fb_var_screeninfo *var);
+int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl,
+ u16 posx, u16 posy, u16 outw, u16 outh);
+
/* find the display connected to this fb, if any */
static inline struct omap_dss_device *fb2display(struct fb_info *fbi)
{
@@ -148,8 +157,24 @@ static inline int omapfb_overlay_enable(struct omap_overlay *ovl,
struct omap_overlay_info info;
ovl->get_overlay_info(ovl, &info);
+ if (info.enabled == enable)
+ return 0;
info.enabled = enable;
return ovl->set_overlay_info(ovl, &info);
}
+static inline struct omapfb2_mem_region *
+omapfb_get_mem_region(struct omapfb2_mem_region *rg)
+{
+ down_read_nested(&rg->lock, rg->id);
+ atomic_inc(&rg->lock_count);
+ return rg;
+}
+
+static inline void omapfb_put_mem_region(struct omapfb2_mem_region *rg)
+{
+ atomic_dec(&rg->lock_count);
+ up_read(&rg->lock);
+}
+
#endif