Commit 6ee22f53 authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://bk.arm.linux.org.uk/linux-2.6-dma

into ppc970.osdl.org:/home/torvalds/v2.6/linux
parents 04c73690 b0c8809e
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/mm.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/hardware/icst525.h> #include <asm/hardware/icst525.h>
...@@ -259,6 +260,17 @@ static int impd1fb_clcd_setup(struct clcd_fb *fb) ...@@ -259,6 +260,17 @@ static int impd1fb_clcd_setup(struct clcd_fb *fb)
return ret; return ret;
} }
static int impd1fb_clcd_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
{
unsigned long start, size;
start = vma->vm_pgoff + (fb->fb.fix.smem_start >> PAGE_SHIFT);
size = vma->vm_end - vma->vm_start;
return remap_pfn_range(vma, vma->vm_start, start, size,
vma->vm_page_prot);
}
static void impd1fb_clcd_remove(struct clcd_fb *fb) static void impd1fb_clcd_remove(struct clcd_fb *fb)
{ {
iounmap(fb->fb.screen_base); iounmap(fb->fb.screen_base);
...@@ -272,6 +284,7 @@ static struct clcd_board impd1_clcd_data = { ...@@ -272,6 +284,7 @@ static struct clcd_board impd1_clcd_data = {
.disable = impd1fb_clcd_disable, .disable = impd1fb_clcd_disable,
.enable = impd1fb_clcd_enable, .enable = impd1fb_clcd_enable,
.setup = impd1fb_clcd_setup, .setup = impd1fb_clcd_setup,
.mmap = impd1fb_clcd_mmap,
.remove = impd1fb_clcd_remove, .remove = impd1fb_clcd_remove,
}; };
......
...@@ -444,6 +444,14 @@ static int cp_clcd_setup(struct clcd_fb *fb) ...@@ -444,6 +444,14 @@ static int cp_clcd_setup(struct clcd_fb *fb)
return 0; return 0;
} }
static int cp_clcd_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
{
return dma_mmap_writecombine(&fb->dev->dev, vma,
fb->fb.screen_base,
fb->fb.fix.smem_start,
fb->fb.fix.smem_len);
}
static void cp_clcd_remove(struct clcd_fb *fb) static void cp_clcd_remove(struct clcd_fb *fb)
{ {
dma_free_writecombine(&fb->dev->dev, fb->fb.fix.smem_len, dma_free_writecombine(&fb->dev->dev, fb->fb.fix.smem_len,
...@@ -456,6 +464,7 @@ static struct clcd_board clcd_data = { ...@@ -456,6 +464,7 @@ static struct clcd_board clcd_data = {
.decode = clcdfb_decode, .decode = clcdfb_decode,
.enable = cp_clcd_enable, .enable = cp_clcd_enable,
.setup = cp_clcd_setup, .setup = cp_clcd_setup,
.mmap = cp_clcd_mmap,
.remove = cp_clcd_remove, .remove = cp_clcd_remove,
}; };
......
...@@ -597,6 +597,14 @@ static int versatile_clcd_setup(struct clcd_fb *fb) ...@@ -597,6 +597,14 @@ static int versatile_clcd_setup(struct clcd_fb *fb)
return 0; return 0;
} }
static int versatile_clcd_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
{
return dma_mmap_writecombine(&fb->dev->dev, vma,
fb->fb.screen_base,
fb->fb.fix.smem_start,
fb->fb.fix.smem_len);
}
static void versatile_clcd_remove(struct clcd_fb *fb) static void versatile_clcd_remove(struct clcd_fb *fb)
{ {
dma_free_writecombine(&fb->dev->dev, fb->fb.fix.smem_len, dma_free_writecombine(&fb->dev->dev, fb->fb.fix.smem_len,
...@@ -610,6 +618,7 @@ static struct clcd_board clcd_plat_data = { ...@@ -610,6 +618,7 @@ static struct clcd_board clcd_plat_data = {
.disable = versatile_clcd_disable, .disable = versatile_clcd_disable,
.enable = versatile_clcd_enable, .enable = versatile_clcd_enable,
.setup = versatile_clcd_setup, .setup = versatile_clcd_setup,
.mmap = versatile_clcd_mmap,
.remove = versatile_clcd_remove, .remove = versatile_clcd_remove,
}; };
......
/* /*
* linux/arch/arm/mm/consistent.c * linux/arch/arm/mm/consistent.c
* *
* Copyright (C) 2000-2002 Russell King * Copyright (C) 2000-2004 Russell King
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
...@@ -65,6 +65,7 @@ struct vm_region { ...@@ -65,6 +65,7 @@ struct vm_region {
struct list_head vm_list; struct list_head vm_list;
unsigned long vm_start; unsigned long vm_start;
unsigned long vm_end; unsigned long vm_end;
struct page *vm_pages;
}; };
static struct vm_region consistent_head = { static struct vm_region consistent_head = {
...@@ -206,6 +207,8 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, int gfp, ...@@ -206,6 +207,8 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, int gfp,
pte_t *pte = consistent_pte + CONSISTENT_OFFSET(c->vm_start); pte_t *pte = consistent_pte + CONSISTENT_OFFSET(c->vm_start);
struct page *end = page + (1 << order); struct page *end = page + (1 << order);
c->vm_pages = page;
/* /*
* Set the "dma handle" * Set the "dma handle"
*/ */
...@@ -215,6 +218,9 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, int gfp, ...@@ -215,6 +218,9 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, int gfp,
BUG_ON(!pte_none(*pte)); BUG_ON(!pte_none(*pte));
set_page_count(page, 1); set_page_count(page, 1);
/*
* x86 does not mark the pages reserved...
*/
SetPageReserved(page); SetPageReserved(page);
set_pte(pte, mk_pte(page, prot)); set_pte(pte, mk_pte(page, prot));
page++; page++;
...@@ -264,6 +270,50 @@ dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, int ...@@ -264,6 +270,50 @@ dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, int
} }
EXPORT_SYMBOL(dma_alloc_writecombine); EXPORT_SYMBOL(dma_alloc_writecombine);
static int dma_mmap(struct device *dev, struct vm_area_struct *vma,
void *cpu_addr, dma_addr_t dma_addr, size_t size)
{
unsigned long flags, user_size, kern_size;
struct vm_region *c;
int ret = -ENXIO;
user_size = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
spin_lock_irqsave(&consistent_lock, flags);
c = vm_region_find(&consistent_head, (unsigned long)cpu_addr);
spin_unlock_irqrestore(&consistent_lock, flags);
if (c) {
kern_size = (c->vm_end - c->vm_start) >> PAGE_SHIFT;
if (vma->vm_pgoff < kern_size ||
user_size <= (kern_size - vma->vm_pgoff)) {
vma->vm_flags |= VM_RESERVED;
ret = remap_pfn_range(vma, vma->vm_start,
page_to_pfn(c->vm_pages),
user_size, vma->vm_page_prot);
}
}
return ret;
}
int dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
void *cpu_addr, dma_addr_t dma_addr, size_t size)
{
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
return dma_mmap(dev, vma, cpu_addr, dma_addr, size);
}
EXPORT_SYMBOL(dma_mmap_coherent);
int dma_mmap_writecombine(struct device *dev, struct vm_area_struct *vma,
void *cpu_addr, dma_addr_t dma_addr, size_t size)
{
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
return dma_mmap(dev, vma, cpu_addr, dma_addr, size);
}
EXPORT_SYMBOL(dma_mmap_writecombine);
/* /*
* free a page as defined by the above mapping. * free a page as defined by the above mapping.
*/ */
...@@ -300,6 +350,10 @@ void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr ...@@ -300,6 +350,10 @@ void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr
if (pfn_valid(pfn)) { if (pfn_valid(pfn)) {
struct page *page = pfn_to_page(pfn); struct page *page = pfn_to_page(pfn);
/*
* x86 does not mark the pages reserved...
*/
ClearPageReserved(page); ClearPageReserved(page);
__free_page(page); __free_page(page);
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/string.h> #include <linux/string.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/mm.h>
#include <linux/fb.h> #include <linux/fb.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/ioport.h> #include <linux/ioport.h>
...@@ -300,6 +301,22 @@ static int clcdfb_blank(int blank_mode, struct fb_info *info) ...@@ -300,6 +301,22 @@ static int clcdfb_blank(int blank_mode, struct fb_info *info)
return 0; return 0;
} }
static int clcdfb_mmap(struct fb_info *info, struct file *file,
struct vm_area_struct *vma)
{
struct clcd_fb *fb = to_clcd(info);
unsigned long len, off = vma->vm_pgoff << PAGE_SHIFT;
int ret = -EINVAL;
len = info->fix.smem_len;
if (off <= len && vma->vm_end - vma->vm_start <= len - off &&
fb->board->mmap)
ret = fb->board->mmap(fb, vma);
return ret;
}
static struct fb_ops clcdfb_ops = { static struct fb_ops clcdfb_ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.fb_check_var = clcdfb_check_var, .fb_check_var = clcdfb_check_var,
...@@ -310,6 +327,7 @@ static struct fb_ops clcdfb_ops = { ...@@ -310,6 +327,7 @@ static struct fb_ops clcdfb_ops = {
.fb_copyarea = cfb_copyarea, .fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit, .fb_imageblit = cfb_imageblit,
.fb_cursor = soft_cursor, .fb_cursor = soft_cursor,
.fb_mmap = clcdfb_mmap,
}; };
static int clcdfb_register(struct clcd_fb *fb) static int clcdfb_register(struct clcd_fb *fb)
......
...@@ -394,6 +394,20 @@ static int pxafb_blank(int blank, struct fb_info *info) ...@@ -394,6 +394,20 @@ static int pxafb_blank(int blank, struct fb_info *info)
return 0; return 0;
} }
static int pxafb_mmap(struct fb_info *info, struct file *file,
struct vm_area_struct *vma)
{
struct pxafb_info *fbi = (struct pxafb_info *)info;
unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
if (off < info->fix.smem_len) {
vma->vm_pgoff += 1;
return dma_mmap_writecombine(fbi->dev, vma, fbi->map_cpu,
fbi->map_dma, fbi->map_size);
}
return -EINVAL;
}
static struct fb_ops pxafb_ops = { static struct fb_ops pxafb_ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.fb_check_var = pxafb_check_var, .fb_check_var = pxafb_check_var,
...@@ -404,6 +418,7 @@ static struct fb_ops pxafb_ops = { ...@@ -404,6 +418,7 @@ static struct fb_ops pxafb_ops = {
.fb_imageblit = cfb_imageblit, .fb_imageblit = cfb_imageblit,
.fb_blank = pxafb_blank, .fb_blank = pxafb_blank,
.fb_cursor = soft_cursor, .fb_cursor = soft_cursor,
.fb_mmap = pxafb_mmap,
}; };
/* /*
......
...@@ -393,7 +393,7 @@ static struct sa1100fb_mach_info shannon_info __initdata = { ...@@ -393,7 +393,7 @@ static struct sa1100fb_mach_info shannon_info __initdata = {
.left_margin = 2, .upper_margin = 0, .left_margin = 2, .upper_margin = 0,
.right_margin = 1, .lower_margin = 0, .right_margin = 1, .lower_margin = 0,
.sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
.lccr0 = LCCR0_Color | LCCR0_Dual | LCCR0_Pas, .lccr0 = LCCR0_Color | LCCR0_Dual | LCCR0_Pas,
.lccr3 = LCCR3_ACBsDiv(512), .lccr3 = LCCR3_ACBsDiv(512),
...@@ -814,6 +814,33 @@ static int sa1100fb_blank(int blank, struct fb_info *info) ...@@ -814,6 +814,33 @@ static int sa1100fb_blank(int blank, struct fb_info *info)
return 0; return 0;
} }
static int sa1100fb_mmap(struct fb_info *info, struct file *file,
struct vm_area_struct *vma)
{
struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
unsigned long start, len, off = vma->vm_pgoff << PAGE_SHIFT;
if (off < info->fix.smem_len) {
vma->vm_pgoff += 1; /* skip over the palette */
return dma_mmap_writecombine(fbi->dev, vma, fbi->map_cpu,
fbi->map_dma, fbi->map_size);
}
start = info->fix.mmio_start;
len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len);
if ((vma->vm_end - vma->vm_start + off) > len)
return -EINVAL;
off += start & PAGE_MASK;
vma->vm_pgoff = off >> PAGE_SHIFT;
vma->vm_flags |= VM_IO;
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
return io_remap_page_range(vma, vma->vm_start, off,
vma->vm_end - vma->vm_start,
vma->vm_page_prot);
}
static struct fb_ops sa1100fb_ops = { static struct fb_ops sa1100fb_ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.fb_check_var = sa1100fb_check_var, .fb_check_var = sa1100fb_check_var,
...@@ -825,6 +852,7 @@ static struct fb_ops sa1100fb_ops = { ...@@ -825,6 +852,7 @@ static struct fb_ops sa1100fb_ops = {
.fb_imageblit = cfb_imageblit, .fb_imageblit = cfb_imageblit,
.fb_blank = sa1100fb_blank, .fb_blank = sa1100fb_blank,
.fb_cursor = soft_cursor, .fb_cursor = soft_cursor,
.fb_mmap = sa1100fb_mmap,
}; };
/* /*
...@@ -1024,7 +1052,7 @@ static void sa1100fb_enable_controller(struct sa1100fb_info *fbi) ...@@ -1024,7 +1052,7 @@ static void sa1100fb_enable_controller(struct sa1100fb_info *fbi)
if (machine_is_shannon()) { if (machine_is_shannon()) {
GPDR |= SHANNON_GPIO_DISP_EN; GPDR |= SHANNON_GPIO_DISP_EN;
GPSR |= SHANNON_GPIO_DISP_EN; GPSR |= SHANNON_GPIO_DISP_EN;
} }
DPRINTK("DBAR1 = 0x%08x\n", DBAR1); DPRINTK("DBAR1 = 0x%08x\n", DBAR1);
DPRINTK("DBAR2 = 0x%08x\n", DBAR2); DPRINTK("DBAR2 = 0x%08x\n", DBAR2);
......
...@@ -86,6 +86,22 @@ extern void ...@@ -86,6 +86,22 @@ extern void
dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
dma_addr_t handle); dma_addr_t handle);
/**
* dma_mmap_coherent - map a coherent DMA allocation into user space
* @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
* @vma: vm_area_struct describing requested user mapping
* @cpu_addr: kernel CPU-view address returned from dma_alloc_coherent
* @handle: device-view address returned from dma_alloc_coherent
* @size: size of memory originally requested in dma_alloc_coherent
*
* Map a coherent DMA buffer previously allocated by dma_alloc_coherent
* into user space. The coherent DMA buffer must not be freed by the
* driver until the user space mapping has been released.
*/
int dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
void *cpu_addr, dma_addr_t handle, size_t size);
/** /**
* dma_alloc_writecombine - allocate writecombining memory for DMA * dma_alloc_writecombine - allocate writecombining memory for DMA
* @dev: valid struct device pointer, or NULL for ISA and EISA-like devices * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
...@@ -103,6 +119,9 @@ dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, int ...@@ -103,6 +119,9 @@ dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, int
#define dma_free_writecombine(dev,size,cpu_addr,handle) \ #define dma_free_writecombine(dev,size,cpu_addr,handle) \
dma_free_coherent(dev,size,cpu_addr,handle) dma_free_coherent(dev,size,cpu_addr,handle)
int dma_mmap_writecombine(struct device *dev, struct vm_area_struct *vma,
void *cpu_addr, dma_addr_t handle, size_t size);
/** /**
* dma_map_single - map a single buffer for streaming DMA * dma_map_single - map a single buffer for streaming DMA
......
...@@ -124,6 +124,11 @@ struct clcd_board { ...@@ -124,6 +124,11 @@ struct clcd_board {
*/ */
int (*setup)(struct clcd_fb *); int (*setup)(struct clcd_fb *);
/*
* mmap the framebuffer memory
*/
int (*mmap)(struct clcd_fb *, struct vm_area_struct *);
/* /*
* Remove platform specific parts of CLCD driver * Remove platform specific parts of CLCD driver
*/ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment