diff options
-rw-r--r-- | arch/arm/mach-tegra/include/mach/dc.h | 1 | ||||
-rw-r--r-- | drivers/video/tegra/dc/dc.c | 1 | ||||
-rw-r--r-- | drivers/video/tegra/fb.c | 31 |
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, }; |