aboutsummaryrefslogtreecommitdiff
path: root/drivers/video
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/amba-clcd.c84
1 files changed, 56 insertions, 28 deletions
diff --git a/drivers/video/amba-clcd.c b/drivers/video/amba-clcd.c
index 76b1e6bc5ee..94a1998338d 100644
--- a/drivers/video/amba-clcd.c
+++ b/drivers/video/amba-clcd.c
@@ -404,21 +404,43 @@ static int clcdfb_blank(int blank_mode, struct fb_info *info)
}
return 0;
}
+
int clcdfb_mmap_dma(struct clcd_fb *fb, struct vm_area_struct *vma)
{
- return clcdfb_dma_mmap(&fb->dev->dev, vma, fb->fb.screen_base,
- fb->fb.fix.smem_start, fb->fb.fix.smem_len);
+ return clcdfb_dma_mmap(&fb->dev->dev, vma,
+ fb->fb.screen_base,
+ fb->fb.fix.smem_start,
+ fb->fb.fix.smem_len);
+}
+
+int clcdfb_mmap_io(struct clcd_fb *fb, struct vm_area_struct *vma)
+{
+ unsigned long user_count, count, pfn, off;
+
+ user_count = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+ count = PAGE_ALIGN(fb->fb.fix.smem_len) >> PAGE_SHIFT;
+ pfn = fb->fb.fix.smem_start >> PAGE_SHIFT;
+ off = vma->vm_pgoff;
+
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+ if (off < count && user_count <= (count - off))
+ return remap_pfn_range(vma, vma->vm_start, pfn + off,
+ user_count << PAGE_SHIFT,
+ vma->vm_page_prot);
+
+ return -ENXIO;
}
void clcdfb_remove_dma(struct clcd_fb *fb)
{
- struct device_node *node = fb->dev->dev.of_node;
- u32 use_dma = 0;
+ clcdfb_dma_free(&fb->dev->dev, fb->fb.fix.smem_len,
+ fb->fb.screen_base, fb->fb.fix.smem_start);
+}
- of_property_read_u32(node, "use_dma", &use_dma);
- if (use_dma)
- clcdfb_dma_free(&fb->dev->dev, fb->fb.fix.smem_len,
- fb->fb.screen_base, fb->fb.fix.smem_start);
+void clcdfb_remove_io(struct clcd_fb *fb)
+{
+ iounmap(fb->fb.screen_base);
}
static int clcdfb_mmap(struct fb_info *info,
@@ -749,26 +771,40 @@ static int clcdfb_dt_init(struct clcd_fb *fb)
return -EINVAL;
fb->fb.fix.smem_len = fb->panel->mode.xres * fb->panel->mode.yres * 2;
+ fb->board->name = "Device Tree CLCD PL111";
+ fb->board->caps = CLCD_CAP_5551 | CLCD_CAP_565;
+ fb->board->check = clcdfb_check;
+ fb->board->decode = clcdfb_decode;
+
if (of_property_read_u32(node, "use_dma", &use_dma))
use_dma = 0;
+
if (use_dma) {
fb->fb.screen_base = clcdfb_dma_alloc(&fb->dev->dev,
- fb->fb.fix.smem_len, &dma, GFP_KERNEL);
+ fb->fb.fix.smem_len,
+ &dma, GFP_KERNEL);
if (!fb->fb.screen_base) {
pr_err("CLCD: unable to map framebuffer\n");
- err = -ENOMEM;
- } else
- fb->fb.fix.smem_start = dma;
+ return -ENOMEM;
+ }
+
+ fb->fb.fix.smem_start = dma;
+ fb->board->mmap = clcdfb_mmap_dma;
+ fb->board->remove = clcdfb_remove_dma;
} else {
prop = of_get_property(node, "framebuffer", &len);
if (WARN_ON(!prop || len < (na + ns) * sizeof(*prop)))
return -EINVAL;
+
fb_base = of_read_number(prop, na);
fb_size = of_read_number(prop + na, ns);
- fb->fb.fix.smem_start = fb_base;
- fb->fb.screen_base = ioremap_wc(fb->fb.fix.smem_start, fb_size);
+ fb->fb.fix.smem_start = fb_base;
+ fb->fb.screen_base = ioremap_wc(fb_base, fb_size);
+ fb->board->mmap = clcdfb_mmap_io;
+ fb->board->remove = clcdfb_remove_io;
}
+
return err;
}
#endif /* CONFIG_OF */
@@ -779,25 +815,17 @@ static int clcdfb_probe(struct amba_device *dev, const struct amba_id *id)
struct clcd_fb *fb;
int ret;
+ if (!board) {
#ifdef CONFIG_OF
- if (dev->dev.of_node) {
- if (!board) {
+ if (dev->dev.of_node) {
board = kzalloc(sizeof(struct clcd_board), GFP_KERNEL);
if (!board)
- return -EINVAL;
- board->name = "Device Tree CLCD PL111";
- board->caps = CLCD_CAP_5551 | CLCD_CAP_565;
- board->check = clcdfb_check;
- board->decode = clcdfb_decode;
+ return -ENOMEM;
board->setup = clcdfb_dt_init;
- board->mmap = clcdfb_mmap_dma;
- board->remove = clcdfb_remove_dma;
- }
+ } else
+#endif
+ return -EINVAL;
}
-#endif /* CONFIG_OF */
-
- if (!board)
- return -EINVAL;
ret = amba_request_regions(dev, NULL);
if (ret) {