summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWill Deacon <will.deacon@arm.com>2013-01-28 12:06:58 (GMT)
committerChanho Park <chanho61.park@samsung.com>2014-04-16 12:36:52 (GMT)
commitbad744fb50877d3dce1505417685484efa437d0e (patch)
treed3e5e25a71457d2a9512e2a14cd1dc6bc6ba7211
parent4dd75ec77356a23b604be3116a7ea77e8e353627 (diff)
downloadlinux-3.10-bad744fb50877d3dce1505417685484efa437d0e.zip
linux-3.10-bad744fb50877d3dce1505417685484efa437d0e.tar.gz
linux-3.10-bad744fb50877d3dce1505417685484efa437d0e.tar.bz2
amba-clcd: separate ioremap framebuffer from DMA implementation
The amba-clcd device can be configured to use either DMA or, when this feature is not available, an ioremapped frambuffer in static ram. In the case of the latter, we must take care not to pass ioremapped addresses to dma_common_mmap, since this expects only addresses from dma_mmap_coherent, which reside in the kernel linear mapping. This patch reworks the fb initialisation code so that either DMA or IO implementations of the mmap/remove functions are chosen as appropriate. Signed-off-by: Will Deacon <will.deacon@arm.com> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
-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 432699b..3b1bb2d 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,29 +771,43 @@ 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);
if (memblock_remove(fb_base, fb_size) != 0)
return -EINVAL;
- 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 */
@@ -782,25 +818,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) {