summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-tegra/include/mach/dc.h1
-rw-r--r--drivers/video/tegra/dc/dc.c1
-rw-r--r--drivers/video/tegra/fb.c31
3 files changed, 27 insertions, 6 deletions
diff --git a/arch/arm/mach-tegra/include/mach/dc.h b/arch/arm/mach-tegra/include/mach/dc.h
index 25cf8021215a..3719ad083ea4 100644
--- a/arch/arm/mach-tegra/include/mach/dc.h
+++ b/arch/arm/mach-tegra/include/mach/dc.h
@@ -284,6 +284,7 @@ struct tegra_dc_win {
unsigned out_w;
unsigned out_h;
unsigned z;
+ unsigned size;
int dirty;
int underflows;
diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c
index 57ca161f9765..3f8326e73245 100644
--- a/drivers/video/tegra/dc/dc.c
+++ b/drivers/video/tegra/dc/dc.c
@@ -544,6 +544,7 @@ int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n)
V_PRESCALED_SIZE(win->h) |
H_PRESCALED_SIZE(win->w * tegra_dc_fmt_bpp(win->fmt) / 8),
DC_WIN_PRESCALED_SIZE);
+ win->size = win->out_h * win->stride * tegra_dc_fmt_bpp(win->fmt) / 8;
h_dda = ((win->w - 1) * 0x1000) / max_t(int, win->out_w - 1, 1);
v_dda = ((win->h - 1) * 0x1000) / max_t(int, win->out_h - 1, 1);
diff --git a/drivers/video/tegra/fb.c b/drivers/video/tegra/fb.c
index a28ba561477c..9f5bd9a71e68 100644
--- a/drivers/video/tegra/fb.c
+++ b/drivers/video/tegra/fb.c
@@ -79,10 +79,7 @@ static int tegra_fb_open(struct fb_info *info, int user)
{
struct tegra_fb_info *tegra_fb = info->par;
- if (atomic_xchg(&tegra_fb->in_use, 1))
- return -EBUSY;
-
- tegra_fb->user_nvmap = NULL;
+ atomic_inc(&tegra_fb->in_use);
return 0;
}
@@ -92,6 +89,9 @@ static int tegra_fb_release(struct fb_info *info, int user)
struct tegra_fb_info *tegra_fb = info->par;
struct fb_var_screeninfo *var = &info->var;
+ if (atomic_dec_return(&tegra_fb->in_use))
+ return 0;
+
flush_workqueue(tegra_fb->flip_wq);
if (tegra_fb->win->cur_handle) {
@@ -116,8 +116,6 @@ static int tegra_fb_release(struct fb_info *info, int user)
tegra_fb->user_nvmap = NULL;
}
- WARN_ON(!atomic_xchg(&tegra_fb->in_use, 0));
-
return 0;
}
@@ -586,6 +584,26 @@ surf_err:
return err;
}
+static int tegra_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+ struct tegra_fb_info *tegra_fb = info->par;
+ struct tegra_dc_win *win = tegra_fb->win;
+ unsigned long size = vma->vm_end - vma->vm_start;
+ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+
+ if (offset + size > win->size)
+ return -EINVAL;
+
+ offset += win->phys_addr + win->offset;
+
+ if (remap_pfn_range(vma, vma->vm_start, offset >> PAGE_SHIFT,
+ size, PAGE_READONLY))
+ return -EAGAIN;
+
+ vma->vm_flags |= VM_RESERVED;
+ return 0;
+}
+
/* TODO: implement private window ioctls to set overlay x,y */
static int tegra_fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
@@ -674,6 +692,7 @@ static struct fb_ops tegra_fb_ops = {
.fb_fillrect = tegra_fb_fillrect,
.fb_copyarea = tegra_fb_copyarea,
.fb_imageblit = tegra_fb_imageblit,
+ .fb_mmap = tegra_fb_mmap,
.fb_ioctl = tegra_fb_ioctl,
};