Commit 24c75d48 authored by Linus Torvalds's avatar Linus Torvalds

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

into ppc970.osdl.org:/home/torvalds/v2.6/linux
parents 18ccf569 ba3cfbd6
...@@ -601,12 +601,8 @@ source "arch/arm/oprofile/Kconfig" ...@@ -601,12 +601,8 @@ source "arch/arm/oprofile/Kconfig"
source "drivers/video/Kconfig" source "drivers/video/Kconfig"
if ARCH_ACORN || ARCH_CLPS7500 || ARCH_TBOX || ARCH_SHARK || ARCH_SA1100 || PCI
source "sound/Kconfig" source "sound/Kconfig"
endif
source "drivers/misc/Kconfig" source "drivers/misc/Kconfig"
source "drivers/usb/Kconfig" source "drivers/usb/Kconfig"
......
...@@ -76,34 +76,27 @@ static struct vm_region consistent_head = { ...@@ -76,34 +76,27 @@ static struct vm_region consistent_head = {
.vm_end = CONSISTENT_END, .vm_end = CONSISTENT_END,
}; };
#if 0 static struct vm_region *
static void vm_region_dump(struct vm_region *head, char *fn) vm_region_alloc(struct vm_region *head, size_t size, int gfp)
{ {
struct vm_region *c; unsigned long addr = head->vm_start, end = head->vm_end - size;
unsigned long flags;
struct vm_region *c, *new;
printk("Consistent Allocation Map (%s):\n", fn); new = kmalloc(sizeof(struct vm_region), gfp);
list_for_each_entry(c, &head->vm_list, vm_list) { if (!new)
printk(" %p: %08lx - %08lx (0x%08x)\n", c, goto out;
c->vm_start, c->vm_end, c->vm_end - c->vm_start);
}
}
#else
#define vm_region_dump(head,fn) do { } while(0)
#endif
static int vm_region_alloc(struct vm_region *head, struct vm_region *new, size_t size) spin_lock_irqsave(&consistent_lock, flags);
{
unsigned long addr = head->vm_start, end = head->vm_end - size;
struct vm_region *c;
list_for_each_entry(c, &head->vm_list, vm_list) { list_for_each_entry(c, &head->vm_list, vm_list) {
if ((addr + size) < addr) if ((addr + size) < addr)
goto out; goto nospc;
if ((addr + size) <= c->vm_start) if ((addr + size) <= c->vm_start)
goto found; goto found;
addr = c->vm_end; addr = c->vm_end;
if (addr > end) if (addr > end)
goto out; goto nospc;
} }
found: found:
...@@ -114,10 +107,14 @@ static int vm_region_alloc(struct vm_region *head, struct vm_region *new, size_t ...@@ -114,10 +107,14 @@ static int vm_region_alloc(struct vm_region *head, struct vm_region *new, size_t
new->vm_start = addr; new->vm_start = addr;
new->vm_end = addr + size; new->vm_end = addr + size;
return 0; spin_unlock_irqrestore(&consistent_lock, flags);
return new;
nospc:
spin_unlock_irqrestore(&consistent_lock, flags);
kfree(new);
out: out:
return -ENOMEM; return NULL;
} }
static struct vm_region *vm_region_find(struct vm_region *head, unsigned long addr) static struct vm_region *vm_region_find(struct vm_region *head, unsigned long addr)
...@@ -133,28 +130,46 @@ static struct vm_region *vm_region_find(struct vm_region *head, unsigned long ad ...@@ -133,28 +130,46 @@ static struct vm_region *vm_region_find(struct vm_region *head, unsigned long ad
return c; return c;
} }
/* #ifdef CONFIG_HUGETLB_PAGE
* This allocates one page of cache-coherent memory space and returns #error ARM Coherent DMA allocator does not (yet) support huge TLB
* both the virtual and a "dma" address to that space. #endif
*/
void *consistent_alloc(int gfp, size_t size, dma_addr_t *handle, static void *
unsigned long cache_flags) __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, int gfp,
pgprot_t prot)
{ {
struct page *page; struct page *page;
struct vm_region *c; struct vm_region *c;
unsigned long order, flags; unsigned long order;
void *ret = NULL; u64 mask = 0x00ffffff, limit; /* ISA default */
int res;
if (!consistent_pte) { if (!consistent_pte) {
printk(KERN_ERR "consistent_alloc: not initialised\n"); printk(KERN_ERR "%s: not initialised\n", __func__);
dump_stack(); dump_stack();
return NULL; return NULL;
} }
if (dev) {
mask = dev->coherent_dma_mask;
if (mask == 0) {
dev_warn(dev, "coherent DMA mask is unset\n");
return NULL;
}
}
size = PAGE_ALIGN(size); size = PAGE_ALIGN(size);
limit = (mask + 1) & ~mask;
if ((limit && size >= limit) || size >= (CONSISTENT_END - CONSISTENT_BASE)) {
printk(KERN_WARNING "coherent allocation too big (requested %#x mask %#Lx)\n",
size, mask);
return NULL;
}
order = get_order(size); order = get_order(size);
if (mask != 0xffffffff)
gfp |= GFP_DMA;
page = alloc_pages(gfp, order); page = alloc_pages(gfp, order);
if (!page) if (!page)
goto no_page; goto no_page;
...@@ -165,36 +180,18 @@ void *consistent_alloc(int gfp, size_t size, dma_addr_t *handle, ...@@ -165,36 +180,18 @@ void *consistent_alloc(int gfp, size_t size, dma_addr_t *handle,
*/ */
{ {
unsigned long kaddr = (unsigned long)page_address(page); unsigned long kaddr = (unsigned long)page_address(page);
dmac_inv_range(kaddr, kaddr + size); memset(page_address(page), 0, size);
dmac_flush_range(kaddr, kaddr + size);
} }
/* /*
* Our housekeeping doesn't need to come from DMA, * Allocate a virtual address in the consistent mapping region.
* but it must not come from highmem.
*/
c = kmalloc(sizeof(struct vm_region),
gfp & ~(__GFP_DMA | __GFP_HIGHMEM));
if (!c)
goto no_remap;
/*
* Attempt to allocate a virtual address in the
* consistent mapping region.
*/ */
spin_lock_irqsave(&consistent_lock, flags); c = vm_region_alloc(&consistent_head, size,
vm_region_dump(&consistent_head, "before alloc"); gfp & ~(__GFP_DMA | __GFP_HIGHMEM));
if (c) {
res = vm_region_alloc(&consistent_head, c, size);
vm_region_dump(&consistent_head, "after alloc");
spin_unlock_irqrestore(&consistent_lock, flags);
if (!res) {
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);
pgprot_t prot = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG |
L_PTE_DIRTY | L_PTE_WRITE |
cache_flags);
/* /*
* Set the "dma handle" * Set the "dma handle"
...@@ -220,38 +217,43 @@ void *consistent_alloc(int gfp, size_t size, dma_addr_t *handle, ...@@ -220,38 +217,43 @@ void *consistent_alloc(int gfp, size_t size, dma_addr_t *handle,
page++; page++;
} }
ret = (void *)c->vm_start; return (void *)c->vm_start;
} }
no_remap: if (page)
if (ret == NULL) {
kfree(c);
__free_pages(page, order); __free_pages(page, order);
}
no_page: no_page:
return ret; return NULL;
} }
EXPORT_SYMBOL(consistent_alloc);
/* /*
* Since we have the DMA mask available to us here, we could try to do * Allocate DMA-coherent memory space and return both the kernel remapped
* a normal allocation, and only fall back to a "DMA" allocation if the * virtual and bus address for that space.
* resulting bus address does not satisfy the dma_mask requirements.
*/ */
void * void *
dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, int gfp) dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, int gfp)
{ {
if (dev == NULL || *dev->dma_mask != 0xffffffff) return __dma_alloc(dev, size, handle, gfp,
gfp |= GFP_DMA; pgprot_noncached(pgprot_kernel));
return consistent_alloc(gfp, size, handle, 0);
} }
EXPORT_SYMBOL(dma_alloc_coherent); EXPORT_SYMBOL(dma_alloc_coherent);
/*
* Allocate a writecombining region, in much the same way as
* dma_alloc_coherent above.
*/
void *
dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, int gfp)
{
return __dma_alloc(dev, size, handle, gfp,
pgprot_writecombine(pgprot_kernel));
}
EXPORT_SYMBOL(dma_alloc_writecombine);
/* /*
* free a page as defined by the above mapping. * free a page as defined by the above mapping.
*/ */
void consistent_free(void *vaddr, size_t size, dma_addr_t handle) void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr_t handle)
{ {
struct vm_region *c; struct vm_region *c;
unsigned long flags; unsigned long flags;
...@@ -260,15 +262,14 @@ void consistent_free(void *vaddr, size_t size, dma_addr_t handle) ...@@ -260,15 +262,14 @@ void consistent_free(void *vaddr, size_t size, dma_addr_t handle)
size = PAGE_ALIGN(size); size = PAGE_ALIGN(size);
spin_lock_irqsave(&consistent_lock, flags); spin_lock_irqsave(&consistent_lock, flags);
vm_region_dump(&consistent_head, "before free");
c = vm_region_find(&consistent_head, (unsigned long)vaddr); c = vm_region_find(&consistent_head, (unsigned long)cpu_addr);
if (!c) if (!c)
goto no_area; goto no_area;
if ((c->vm_end - c->vm_start) != size) { if ((c->vm_end - c->vm_start) != size) {
printk(KERN_ERR "consistent_free: wrong size (%ld != %d)\n", printk(KERN_ERR "%s: freeing wrong coherent size (%ld != %d)\n",
c->vm_end - c->vm_start, size); __func__, c->vm_end - c->vm_start, size);
dump_stack(); dump_stack();
size = c->vm_end - c->vm_start; size = c->vm_end - c->vm_start;
} }
...@@ -292,15 +293,14 @@ void consistent_free(void *vaddr, size_t size, dma_addr_t handle) ...@@ -292,15 +293,14 @@ void consistent_free(void *vaddr, size_t size, dma_addr_t handle)
} }
} }
printk(KERN_CRIT "consistent_free: bad page in kernel page " printk(KERN_CRIT "%s: bad page in kernel page table\n",
"table\n"); __func__);
} while (size -= PAGE_SIZE); } while (size -= PAGE_SIZE);
flush_tlb_kernel_range(c->vm_start, c->vm_end); flush_tlb_kernel_range(c->vm_start, c->vm_end);
list_del(&c->vm_list); list_del(&c->vm_list);
vm_region_dump(&consistent_head, "after free");
spin_unlock_irqrestore(&consistent_lock, flags); spin_unlock_irqrestore(&consistent_lock, flags);
kfree(c); kfree(c);
...@@ -308,11 +308,11 @@ void consistent_free(void *vaddr, size_t size, dma_addr_t handle) ...@@ -308,11 +308,11 @@ void consistent_free(void *vaddr, size_t size, dma_addr_t handle)
no_area: no_area:
spin_unlock_irqrestore(&consistent_lock, flags); spin_unlock_irqrestore(&consistent_lock, flags);
printk(KERN_ERR "consistent_free: trying to free " printk(KERN_ERR "%s: trying to free invalid coherent area: %p\n",
"invalid area: %p\n", vaddr); __func__, cpu_addr);
dump_stack(); dump_stack();
} }
EXPORT_SYMBOL(consistent_free); EXPORT_SYMBOL(dma_free_coherent);
/* /*
* Initialise the consistent memory allocation. * Initialise the consistent memory allocation.
...@@ -330,7 +330,7 @@ static int __init consistent_init(void) ...@@ -330,7 +330,7 @@ static int __init consistent_init(void)
pgd = pgd_offset(&init_mm, CONSISTENT_BASE); pgd = pgd_offset(&init_mm, CONSISTENT_BASE);
pmd = pmd_alloc(&init_mm, pgd, CONSISTENT_BASE); pmd = pmd_alloc(&init_mm, pgd, CONSISTENT_BASE);
if (!pmd) { if (!pmd) {
printk(KERN_ERR "consistent_init: no pmd tables\n"); printk(KERN_ERR "%s: no pmd tables\n", __func__);
ret = -ENOMEM; ret = -ENOMEM;
break; break;
} }
...@@ -338,7 +338,7 @@ static int __init consistent_init(void) ...@@ -338,7 +338,7 @@ static int __init consistent_init(void)
pte = pte_alloc_kernel(&init_mm, pmd, CONSISTENT_BASE); pte = pte_alloc_kernel(&init_mm, pmd, CONSISTENT_BASE);
if (!pte) { if (!pte) {
printk(KERN_ERR "consistent_init: no pte tables\n"); printk(KERN_ERR "%s: no pte tables\n", __func__);
ret = -ENOMEM; ret = -ENOMEM;
break; break;
} }
......
...@@ -34,9 +34,13 @@ extern int (*set_rtc)(void); ...@@ -34,9 +34,13 @@ extern int (*set_rtc)(void);
static struct i2c_client *rtc_client; static struct i2c_client *rtc_client;
static const unsigned char days_in_mon[] = static const unsigned char days_in_mon[] =
{ 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
static unsigned int rtc_epoch = 1900;
#define CMOS_CHECKSUM (63) #define CMOS_CHECKSUM (63)
/*
* Acorn machines store the year in the static RAM at
* location 128.
*/
#define CMOS_YEAR (64 + 128) #define CMOS_YEAR (64 + 128)
static inline int rtc_command(int cmd, void *data) static inline int rtc_command(int cmd, void *data)
...@@ -49,6 +53,38 @@ static inline int rtc_command(int cmd, void *data) ...@@ -49,6 +53,38 @@ static inline int rtc_command(int cmd, void *data)
return ret; return ret;
} }
/*
* Update the century + year bytes in the CMOS RAM, ensuring
* that the check byte is correctly adjusted for the change.
*/
static int rtc_update_year(unsigned int new_year)
{
unsigned char yr[2], chk;
struct mem cmos_year = { CMOS_YEAR, sizeof(yr), yr };
struct mem cmos_check = { CMOS_CHECKSUM, 1, &chk };
int ret;
ret = rtc_command(MEM_READ, &cmos_check);
if (ret)
goto out;
ret = rtc_command(MEM_READ, &cmos_year);
if (ret)
goto out;
chk -= yr[1] + yr[0];
yr[1] = new_year / 100;
yr[0] = new_year % 100;
chk += yr[1] + yr[0];
ret = rtc_command(MEM_WRITE, &cmos_year);
if (ret == 0)
ret = rtc_command(MEM_WRITE, &cmos_check);
out:
return ret;
}
/* /*
* Read the current RTC time and date, and update xtime. * Read the current RTC time and date, and update xtime.
*/ */
...@@ -56,45 +92,51 @@ static void get_rtc_time(struct rtc_tm *rtctm, unsigned int *year) ...@@ -56,45 +92,51 @@ static void get_rtc_time(struct rtc_tm *rtctm, unsigned int *year)
{ {
unsigned char ctrl, yr[2]; unsigned char ctrl, yr[2];
struct mem rtcmem = { CMOS_YEAR, sizeof(yr), yr }; struct mem rtcmem = { CMOS_YEAR, sizeof(yr), yr };
int real_year, year_offset;
/* /*
* Ensure that the RTC is running. * Ensure that the RTC is running.
*/ */
rtc_command(RTC_GETCTRL, &ctrl); rtc_command(RTC_GETCTRL, &ctrl);
if (ctrl & 0xc0) { if (ctrl & 0xc0) {
unsigned char new_ctrl; unsigned char new_ctrl = ctrl & ~0xc0;
new_ctrl = ctrl & ~0xc0;
printk("RTC: resetting control %02X -> %02X\n", printk(KERN_WARNING "RTC: resetting control %02x -> %02x\n",
ctrl, new_ctrl); ctrl, new_ctrl);
rtc_command(RTC_SETCTRL, &new_ctrl); rtc_command(RTC_SETCTRL, &new_ctrl);
} }
/* if (rtc_command(RTC_GETDATETIME, rtctm) ||
* Acorn machines store the year in rtc_command(MEM_READ, &rtcmem))
* the static RAM at location 192.
*/
if (rtc_command(MEM_READ, &rtcmem))
return; return;
if (rtc_command(RTC_GETDATETIME, rtctm)) real_year = yr[0];
return;
*year = yr[1] * 100 + yr[0]; /*
* The RTC year holds the LSB two bits of the current
* year, which should reflect the LSB two bits of the
* CMOS copy of the year. Any difference indicates
* that we have to correct the CMOS version.
*/
year_offset = rtctm->year_off - (real_year & 3);
if (year_offset < 0)
/*
* RTC year wrapped. Adjust it appropriately.
*/
year_offset += 4;
*year = real_year + year_offset + yr[1] * 100;
} }
static int set_rtc_time(struct rtc_tm *rtctm, unsigned int year) static int set_rtc_time(struct rtc_tm *rtctm, unsigned int year)
{ {
unsigned char yr[2], leap, chk; unsigned char leap;
struct mem cmos_year = { CMOS_YEAR, sizeof(yr), yr };
struct mem cmos_check = { CMOS_CHECKSUM, 1, &chk };
int ret; int ret;
leap = (!(year % 4) && (year % 100)) || !(year % 400); leap = (!(year % 4) && (year % 100)) || !(year % 400);
if (rtctm->mon > 12 || rtctm->mday == 0) if (rtctm->mon > 12 || rtctm->mon == 0 || rtctm->mday == 0)
return -EINVAL; return -EINVAL;
if (rtctm->mday > (days_in_mon[rtctm->mon] + (rtctm->mon == 2 && leap))) if (rtctm->mday > (days_in_mon[rtctm->mon] + (rtctm->mon == 2 && leap)))
...@@ -103,21 +145,16 @@ static int set_rtc_time(struct rtc_tm *rtctm, unsigned int year) ...@@ -103,21 +145,16 @@ static int set_rtc_time(struct rtc_tm *rtctm, unsigned int year)
if (rtctm->hours >= 24 || rtctm->mins >= 60 || rtctm->secs >= 60) if (rtctm->hours >= 24 || rtctm->mins >= 60 || rtctm->secs >= 60)
return -EINVAL; return -EINVAL;
ret = rtc_command(RTC_SETDATETIME, rtctm); /*
if (ret == 0) { * The RTC's own 2-bit year must reflect the least
rtc_command(MEM_READ, &cmos_check); * significant two bits of the CMOS year.
rtc_command(MEM_READ, &cmos_year); */
rtctm->year_off = (year % 100) & 3;
chk -= yr[1] + yr[0];
yr[1] = year / 100;
yr[0] = year % 100;
chk += yr[1] + yr[0]; ret = rtc_command(RTC_SETDATETIME, rtctm);
if (ret == 0)
ret = rtc_update_year(year);
rtc_command(MEM_WRITE, &cmos_year);
rtc_command(MEM_WRITE, &cmos_check);
}
return ret; return ret;
} }
...@@ -189,13 +226,12 @@ static int rtc_ioctl(struct inode *inode, struct file *file, ...@@ -189,13 +226,12 @@ static int rtc_ioctl(struct inode *inode, struct file *file,
rtc_raw.hours = rtctm.tm_hour; rtc_raw.hours = rtctm.tm_hour;
rtc_raw.mday = rtctm.tm_mday; rtc_raw.mday = rtctm.tm_mday;
rtc_raw.mon = rtctm.tm_mon + 1; rtc_raw.mon = rtctm.tm_mon + 1;
rtc_raw.year_off = 2;
year = rtctm.tm_year + 1900; year = rtctm.tm_year + 1900;
return set_rtc_time(&rtc_raw, year); return set_rtc_time(&rtc_raw, year);
break; break;
case RTC_EPOCH_READ: case RTC_EPOCH_READ:
return put_user(rtc_epoch, (unsigned long *)arg); return put_user(1900, (unsigned long *)arg);
} }
return -EINVAL; return -EINVAL;
......
...@@ -29,6 +29,8 @@ ...@@ -29,6 +29,8 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/fb.h> #include <linux/fb.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/io.h> #include <asm/io.h>
...@@ -1254,6 +1256,11 @@ free_unused_pages(unsigned int virtual_start, unsigned int virtual_end) ...@@ -1254,6 +1256,11 @@ free_unused_pages(unsigned int virtual_start, unsigned int virtual_end)
printk("acornfb: freed %dK memory\n", mb_freed); printk("acornfb: freed %dK memory\n", mb_freed);
} }
static struct device acornfb_device = {
.bus_id = "acornfb",
.coherent_dma_mask = 0xffffffff,
};
int __init int __init
acornfb_init(void) acornfb_init(void)
{ {
...@@ -1263,6 +1270,8 @@ acornfb_init(void) ...@@ -1263,6 +1270,8 @@ acornfb_init(void)
acornfb_init_fbinfo(); acornfb_init_fbinfo();
current_par.dev = &acornfb_device;
if (current_par.montype == -1) if (current_par.montype == -1)
current_par.montype = acornfb_detect_monitortype(); current_par.montype = acornfb_detect_monitortype();
...@@ -1323,37 +1332,30 @@ acornfb_init(void) ...@@ -1323,37 +1332,30 @@ acornfb_init(void)
#if defined(HAS_VIDC20) #if defined(HAS_VIDC20)
if (!current_par.using_vram) { if (!current_par.using_vram) {
dma_addr_t handle;
void *base;
/* /*
* RiscPC needs to allocate the DRAM memory * RiscPC needs to allocate the DRAM memory
* for the framebuffer if we are not using * for the framebuffer if we are not using
* VRAM. Archimedes/A5000 machines use a * VRAM.
* fixed address for their framebuffers.
*/ */
unsigned long page, top, base; base = dma_alloc_writecombine(current_par.dev, size, &handle,
int order = get_order(size); GFP_KERNEL);
if (base == NULL) {
base = __get_free_pages(GFP_KERNEL, order);
if (base == 0) {
printk(KERN_ERR "acornfb: unable to allocate screen " printk(KERN_ERR "acornfb: unable to allocate screen "
"memory\n"); "memory\n");
return -ENOMEM; return -ENOMEM;
} }
top = base + (PAGE_SIZE << order);
/* Mark the framebuffer pages as reserved so mmap will work. */
for (page = base; page < PAGE_ALIGN(base + size); page += PAGE_SIZE)
SetPageReserved(virt_to_page(page));
/* Hand back any excess pages that we allocated. */
for (page = base + size; page < top; page += PAGE_SIZE)
free_page(page);
fb_info.screen_base = (char *)base; fb_info.screen_base = base;
fb_info.fix.smem_start = virt_to_phys(fb_info.screen_base); fb_info.fix.smem_start = handle;
} }
#endif #endif
#if defined(HAS_VIDC) #if defined(HAS_VIDC)
/* /*
* Free unused pages * Archimedes/A5000 machines use a fixed address for their
* framebuffers. Free unused pages
*/ */
free_unused_pages(PAGE_OFFSET + size, PAGE_OFFSET + MAX_SIZE); free_unused_pages(PAGE_OFFSET + size, PAGE_OFFSET + MAX_SIZE);
#endif #endif
......
...@@ -47,6 +47,7 @@ union palette { ...@@ -47,6 +47,7 @@ union palette {
}; };
struct acornfb_par { struct acornfb_par {
struct device *dev;
unsigned long screen_end; unsigned long screen_end;
unsigned int dram_size; unsigned int dram_size;
unsigned int vram_half_sam; unsigned int vram_half_sam;
......
...@@ -1595,12 +1595,18 @@ static int __init sa1100fb_map_video_memory(struct sa1100fb_info *fbi) ...@@ -1595,12 +1595,18 @@ static int __init sa1100fb_map_video_memory(struct sa1100fb_info *fbi)
* of the framebuffer. * of the framebuffer.
*/ */
fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE); fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE);
fbi->map_cpu = consistent_alloc(GFP_KERNEL, fbi->map_size, fbi->map_cpu = dma_alloc_writecombine(fbi->dev, fbi->map_size,
&fbi->map_dma, PTE_BUFFERABLE); &fbi->map_dma, GFP_KERNEL);
if (fbi->map_cpu) { if (fbi->map_cpu) {
fbi->fb.screen_base = fbi->map_cpu + PAGE_SIZE; fbi->fb.screen_base = fbi->map_cpu + PAGE_SIZE;
fbi->screen_dma = fbi->map_dma + PAGE_SIZE; fbi->screen_dma = fbi->map_dma + PAGE_SIZE;
/*
* FIXME: this is actually the wrong thing to place in
* smem_start. But fbdev suffers from the problem that
* it needs an API which doesn't exist (in this case,
* dma_writecombine_mmap)
*/
fbi->fb.fix.smem_start = fbi->screen_dma; fbi->fb.fix.smem_start = fbi->screen_dma;
} }
...@@ -1613,7 +1619,7 @@ static struct fb_monspecs monspecs __initdata = { ...@@ -1613,7 +1619,7 @@ static struct fb_monspecs monspecs __initdata = {
}; };
static struct sa1100fb_info * __init sa1100fb_init_fbinfo(void) static struct sa1100fb_info * __init sa1100fb_init_fbinfo(struct device *dev)
{ {
struct sa1100fb_mach_info *inf; struct sa1100fb_mach_info *inf;
struct sa1100fb_info *fbi; struct sa1100fb_info *fbi;
...@@ -1624,6 +1630,7 @@ static struct sa1100fb_info * __init sa1100fb_init_fbinfo(void) ...@@ -1624,6 +1630,7 @@ static struct sa1100fb_info * __init sa1100fb_init_fbinfo(void)
return NULL; return NULL;
memset(fbi, 0, sizeof(struct sa1100fb_info)); memset(fbi, 0, sizeof(struct sa1100fb_info));
fbi->dev = dev;
strcpy(fbi->fb.fix.id, SA1100_NAME); strcpy(fbi->fb.fix.id, SA1100_NAME);
...@@ -1703,7 +1710,7 @@ static int __init sa1100fb_probe(struct device *dev) ...@@ -1703,7 +1710,7 @@ static int __init sa1100fb_probe(struct device *dev)
if (!request_mem_region(0xb0100000, 0x10000, "LCD")) if (!request_mem_region(0xb0100000, 0x10000, "LCD"))
return -EBUSY; return -EBUSY;
fbi = sa1100fb_init_fbinfo(); fbi = sa1100fb_init_fbinfo(dev);
ret = -ENOMEM; ret = -ENOMEM;
if (!fbi) if (!fbi)
goto failed; goto failed;
......
...@@ -63,6 +63,7 @@ struct sa1100fb_lcd_reg { ...@@ -63,6 +63,7 @@ struct sa1100fb_lcd_reg {
struct sa1100fb_info { struct sa1100fb_info {
struct fb_info fb; struct fb_info fb;
struct device *dev;
struct sa1100fb_rgb *rgb[NR_RGB]; struct sa1100fb_rgb *rgb[NR_RGB];
u_int max_bpp; u_int max_bpp;
......
...@@ -14,8 +14,6 @@ ...@@ -14,8 +14,6 @@
* devices. This is the "generic" version. The PCI specific version * devices. This is the "generic" version. The PCI specific version
* is in pci.h * is in pci.h
*/ */
extern void *consistent_alloc(int gfp, size_t size, dma_addr_t *handle, unsigned long flags);
extern void consistent_free(void *vaddr, size_t size, dma_addr_t handle);
extern void consistent_sync(void *kaddr, size_t size, int rw); extern void consistent_sync(void *kaddr, size_t size, int rw);
/* /*
...@@ -99,12 +97,26 @@ dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, int gfp) ...@@ -99,12 +97,26 @@ dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, int gfp)
* References to memory and mappings associated with cpu_addr/handle * References to memory and mappings associated with cpu_addr/handle
* during and after this call executing are illegal. * during and after this call executing are illegal.
*/ */
static inline void 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);
{
consistent_free(cpu_addr, size, handle); /**
} * dma_alloc_writecombine - allocate writecombining memory for DMA
* @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
* @size: required memory size
* @handle: bus-specific DMA address
*
* Allocate some uncached, buffered memory for a device for
* performing DMA. This function allocates pages, and will
* return the CPU-viewed address, and sets @handle to be the
* device-viewed address.
*/
extern void *
dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, int gfp);
#define dma_free_writecombine(dev,size,cpu_addr,handle) \
dma_free_coherent(dev,size,cpu_addr,handle)
/** /**
* dma_map_single - map a single buffer for streaming DMA * dma_map_single - map a single buffer for streaming DMA
......
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