Patchwork [U-Boot,v4,1/7] arm: add MMU/D-Cache support for Faraday cores

login
register
mail settings
Submitter Kuo-Jung Su
Date May 7, 2013, 6:25 a.m.
Message ID <1367907913-11859-2-git-send-email-dantesu@gmail.com>
Download mbox | patch
Permalink /patch/242000/
State Changes Requested
Delegated to: Albert ARIBAUD
Headers show

Comments

Kuo-Jung Su - May 7, 2013, 6:25 a.m.
From: Kuo-Jung Su <dantesu@faraday-tech.com>

This patch updates the map_physmem()/unmap_physmem(), and use
them to implement dma_alloc_coherent(), dma_free_coherent().

It uses 1MB section for each mapping, and thus waste lots of
address space, however this should still be good enough for
tiny systems (i.e. u-boot).

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v4:
   - Coding Style cleanup.

Changes for v3:
   - Coding Style cleanup.
   - Always insert a blank line between declarations and code.
   - dma-mapping.h: Have the global data ptr declared outside functions.
   - dma-mapping.h: Add #if...#else...#endif to dma_free_coherent().
   - Drop static non-cached region, now we use map_physmem()/unmap_physmem()
     for dynamic mappings.

Changes for v2:
   - Coding Style cleanup.
   - cache-cp15: Enable write buffer in write-through mode.

 arch/arm/include/asm/dma-mapping.h |   61 +++++++++++++-
 arch/arm/include/asm/global_data.h |    4 +
 arch/arm/include/asm/io.h          |  160 ++++++++++++++++++++++++++++++++++--
 arch/arm/include/asm/system.h      |    7 +-
 arch/arm/lib/cache-cp15.c          |   30 +++++++
 drivers/mtd/cfi_flash.c            |    2 +-
 6 files changed, 250 insertions(+), 14 deletions(-)

--
1.7.9.5
Albert ARIBAUD - June 10, 2013, 5:59 p.m.
Hi Kuo-Jung,

On Tue,  7 May 2013 14:25:07 +0800, Kuo-Jung Su <dantesu@gmail.com>
wrote:

> diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
> index 5bbb0a0..5a13af5 100644
> --- a/arch/arm/include/asm/dma-mapping.h
> +++ b/arch/arm/include/asm/dma-mapping.h
> @@ -3,6 +3,9 @@
>   * Stelian Pop <stelian@popies.net>
>   * Lead Tech Design <www.leadtechdesign.com>
>   *
> + * (C) Copyright 2010
> + * Dante Su <dantesu@faraday-tech.com>

Fix Copyright notices (dates) throughout the patch (and series as
needed).

>   * See file CREDITS for list of people who contributed to this
>   * project.
>   *
> @@ -24,22 +27,76 @@
>  #ifndef __ASM_ARM_DMA_MAPPING_H
>  #define __ASM_ARM_DMA_MAPPING_H
> 
> +#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
> +#include <asm/u-boot.h>
> +#include <asm/global_data.h>
> +#include <asm/io.h>
> +#include <malloc.h>
> +
> +DECLARE_GLOBAL_DATA_PTR;
> +#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
> +
>  enum dma_data_direction {
>  	DMA_BIDIRECTIONAL	= 0,
>  	DMA_TO_DEVICE		= 1,
>  	DMA_FROM_DEVICE		= 2,
>  };
> 
> -static void *dma_alloc_coherent(size_t len, unsigned long *handle)
> +static inline void *dma_alloc_coherent(size_t len, unsigned long *handle)
>  {
> -	*handle = (unsigned long)malloc(len);
> +#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
> +	void *map, *va = memalign(ARCH_DMA_MINALIGN, len);
> +
> +	if (va && gd->arch.cpu_mmu) {
> +		invalidate_dcache_range((ulong)va, (ulong)va + len);
> +		map = map_physmem((phys_addr_t)va, len, MAP_NOCACHE);
> +		if (!map)
> +			free(va);
> +		va = map;
> +	}
> +
> +	if (handle)
> +		*handle = virt_to_phys(va);
> +
> +	return va;
> +#else  /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
> +	*handle = (unsigned long)memalign(ARCH_DMA_MINALIGN, len);
>  	return (void *)*handle;

This is not identical to what the code was before the patch. Why the
difference?

> 1.7.9.5

Amicalement,
Kuo-Jung Su - June 11, 2013, 3:09 a.m.
2013/6/11 Albert ARIBAUD <albert.u.boot@aribaud.net>:
> Hi Kuo-Jung,
>
> On Tue,  7 May 2013 14:25:07 +0800, Kuo-Jung Su <dantesu@gmail.com>
> wrote:
>
>> diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
>> index 5bbb0a0..5a13af5 100644
>> --- a/arch/arm/include/asm/dma-mapping.h
>> +++ b/arch/arm/include/asm/dma-mapping.h
>> @@ -3,6 +3,9 @@
>>   * Stelian Pop <stelian@popies.net>
>>   * Lead Tech Design <www.leadtechdesign.com>
>>   *
>> + * (C) Copyright 2010
>> + * Dante Su <dantesu@faraday-tech.com>
>
> Fix Copyright notices (dates) throughout the patch (and series as
> needed).
>

Got it, thanks.

>>   * See file CREDITS for list of people who contributed to this
>>   * project.
>>   *
>> @@ -24,22 +27,76 @@
>>  #ifndef __ASM_ARM_DMA_MAPPING_H
>>  #define __ASM_ARM_DMA_MAPPING_H
>>
>> +#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
>> +#include <asm/u-boot.h>
>> +#include <asm/global_data.h>
>> +#include <asm/io.h>
>> +#include <malloc.h>
>> +
>> +DECLARE_GLOBAL_DATA_PTR;
>> +#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
>> +
>>  enum dma_data_direction {
>>       DMA_BIDIRECTIONAL       = 0,
>>       DMA_TO_DEVICE           = 1,
>>       DMA_FROM_DEVICE         = 2,
>>  };
>>
>> -static void *dma_alloc_coherent(size_t len, unsigned long *handle)
>> +static inline void *dma_alloc_coherent(size_t len, unsigned long *handle)
>>  {
>> -     *handle = (unsigned long)malloc(len);
>> +#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
>> +     void *map, *va = memalign(ARCH_DMA_MINALIGN, len);
>> +
>> +     if (va && gd->arch.cpu_mmu) {
>> +             invalidate_dcache_range((ulong)va, (ulong)va + len);
>> +             map = map_physmem((phys_addr_t)va, len, MAP_NOCACHE);
>> +             if (!map)
>> +                     free(va);
>> +             va = map;
>> +     }
>> +
>> +     if (handle)
>> +             *handle = virt_to_phys(va);
>> +
>> +     return va;
>> +#else  /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
>> +     *handle = (unsigned long)memalign(ARCH_DMA_MINALIGN, len);
>>       return (void *)*handle;
>
> This is not identical to what the code was before the patch. Why the
> difference?
>

Yes, it's not identical to what the code was.

It was:
    *handle = (unsigned long)malloc(len);
But I think it should be
    *handle = (unsigned long)memalign(ARCH_DMA_MINALIGN, len);

Because even though the MMU/D-cache is off, some DMA engines still
requires strict address alignment.

For example, the Faraday FTMAC110 & FTGMAC100 ether-net controllers
expect the descriptors are always aligned to 16-bytes boundary.

--
Best wishes,
Kuo-Jung Su
Albert ARIBAUD - June 11, 2013, 3:28 p.m.
Hi Kuo-Jung,

On Tue, 11 Jun 2013 11:09:57 +0800, Kuo-Jung Su <dantesu@gmail.com>
wrote:

> 2013/6/11 Albert ARIBAUD <albert.u.boot@aribaud.net>:
> > Hi Kuo-Jung,
> >
> > On Tue,  7 May 2013 14:25:07 +0800, Kuo-Jung Su <dantesu@gmail.com>
> > wrote:
> >
> >> diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
> >> index 5bbb0a0..5a13af5 100644
> >> --- a/arch/arm/include/asm/dma-mapping.h
> >> +++ b/arch/arm/include/asm/dma-mapping.h
> >> @@ -3,6 +3,9 @@
> >>   * Stelian Pop <stelian@popies.net>
> >>   * Lead Tech Design <www.leadtechdesign.com>
> >>   *
> >> + * (C) Copyright 2010
> >> + * Dante Su <dantesu@faraday-tech.com>
> >
> > Fix Copyright notices (dates) throughout the patch (and series as
> > needed).
> >
> 
> Got it, thanks.
> 
> >>   * See file CREDITS for list of people who contributed to this
> >>   * project.
> >>   *
> >> @@ -24,22 +27,76 @@
> >>  #ifndef __ASM_ARM_DMA_MAPPING_H
> >>  #define __ASM_ARM_DMA_MAPPING_H
> >>
> >> +#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
> >> +#include <asm/u-boot.h>
> >> +#include <asm/global_data.h>
> >> +#include <asm/io.h>
> >> +#include <malloc.h>
> >> +
> >> +DECLARE_GLOBAL_DATA_PTR;
> >> +#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
> >> +
> >>  enum dma_data_direction {
> >>       DMA_BIDIRECTIONAL       = 0,
> >>       DMA_TO_DEVICE           = 1,
> >>       DMA_FROM_DEVICE         = 2,
> >>  };
> >>
> >> -static void *dma_alloc_coherent(size_t len, unsigned long *handle)
> >> +static inline void *dma_alloc_coherent(size_t len, unsigned long *handle)
> >>  {
> >> -     *handle = (unsigned long)malloc(len);
> >> +#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
> >> +     void *map, *va = memalign(ARCH_DMA_MINALIGN, len);
> >> +
> >> +     if (va && gd->arch.cpu_mmu) {
> >> +             invalidate_dcache_range((ulong)va, (ulong)va + len);
> >> +             map = map_physmem((phys_addr_t)va, len, MAP_NOCACHE);
> >> +             if (!map)
> >> +                     free(va);
> >> +             va = map;
> >> +     }
> >> +
> >> +     if (handle)
> >> +             *handle = virt_to_phys(va);
> >> +
> >> +     return va;
> >> +#else  /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
> >> +     *handle = (unsigned long)memalign(ARCH_DMA_MINALIGN, len);
> >>       return (void *)*handle;
> >
> > This is not identical to what the code was before the patch. Why the
> > difference?
> >
> 
> Yes, it's not identical to what the code was.
> 
> It was:
>     *handle = (unsigned long)malloc(len);
> But I think it should be
>     *handle = (unsigned long)memalign(ARCH_DMA_MINALIGN, len);
> 
> Because even though the MMU/D-cache is off, some DMA engines still
> requires strict address alignment.
> 
> For example, the Faraday FTMAC110 & FTGMAC100 ether-net controllers
> expect the descriptors are always aligned to 16-bytes boundary.

Unless there exists an actual case where the current form causes an
issue, please leave it unchanged. And if it is needed, then please make
it a separate patch.

> Best wishes,
> Kuo-Jung Su

Amicalement,
Kuo-Jung Su - June 14, 2013, 5:44 a.m.
2013/6/11 Albert ARIBAUD <albert.u.boot@aribaud.net>:
> Hi Kuo-Jung,
>
> On Tue, 11 Jun 2013 11:09:57 +0800, Kuo-Jung Su <dantesu@gmail.com>
> wrote:
>
>> 2013/6/11 Albert ARIBAUD <albert.u.boot@aribaud.net>:
>> > Hi Kuo-Jung,
>> >
>> > On Tue,  7 May 2013 14:25:07 +0800, Kuo-Jung Su <dantesu@gmail.com>
>> > wrote:
>> >
>> >> diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
>> >> index 5bbb0a0..5a13af5 100644
>> >> --- a/arch/arm/include/asm/dma-mapping.h
>> >> +++ b/arch/arm/include/asm/dma-mapping.h
>> >> @@ -3,6 +3,9 @@
>> >>   * Stelian Pop <stelian@popies.net>
>> >>   * Lead Tech Design <www.leadtechdesign.com>
>> >>   *
>> >> + * (C) Copyright 2010
>> >> + * Dante Su <dantesu@faraday-tech.com>
>> >
>> > Fix Copyright notices (dates) throughout the patch (and series as
>> > needed).
>> >
>>
>> Got it, thanks.
>>
>> >>   * See file CREDITS for list of people who contributed to this
>> >>   * project.
>> >>   *
>> >> @@ -24,22 +27,76 @@
>> >>  #ifndef __ASM_ARM_DMA_MAPPING_H
>> >>  #define __ASM_ARM_DMA_MAPPING_H
>> >>
>> >> +#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
>> >> +#include <asm/u-boot.h>
>> >> +#include <asm/global_data.h>
>> >> +#include <asm/io.h>
>> >> +#include <malloc.h>
>> >> +
>> >> +DECLARE_GLOBAL_DATA_PTR;
>> >> +#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
>> >> +
>> >>  enum dma_data_direction {
>> >>       DMA_BIDIRECTIONAL       = 0,
>> >>       DMA_TO_DEVICE           = 1,
>> >>       DMA_FROM_DEVICE         = 2,
>> >>  };
>> >>
>> >> -static void *dma_alloc_coherent(size_t len, unsigned long *handle)
>> >> +static inline void *dma_alloc_coherent(size_t len, unsigned long *handle)
>> >>  {
>> >> -     *handle = (unsigned long)malloc(len);
>> >> +#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
>> >> +     void *map, *va = memalign(ARCH_DMA_MINALIGN, len);
>> >> +
>> >> +     if (va && gd->arch.cpu_mmu) {
>> >> +             invalidate_dcache_range((ulong)va, (ulong)va + len);
>> >> +             map = map_physmem((phys_addr_t)va, len, MAP_NOCACHE);
>> >> +             if (!map)
>> >> +                     free(va);
>> >> +             va = map;
>> >> +     }
>> >> +
>> >> +     if (handle)
>> >> +             *handle = virt_to_phys(va);
>> >> +
>> >> +     return va;
>> >> +#else  /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
>> >> +     *handle = (unsigned long)memalign(ARCH_DMA_MINALIGN, len);
>> >>       return (void *)*handle;
>> >
>> > This is not identical to what the code was before the patch. Why the
>> > difference?
>> >
>>
>> Yes, it's not identical to what the code was.
>>
>> It was:
>>     *handle = (unsigned long)malloc(len);
>> But I think it should be
>>     *handle = (unsigned long)memalign(ARCH_DMA_MINALIGN, len);
>>
>> Because even though the MMU/D-cache is off, some DMA engines still
>> requires strict address alignment.
>>
>> For example, the Faraday FTMAC110 & FTGMAC100 ether-net controllers
>> expect the descriptors are always aligned to 16-bytes boundary.
>
> Unless there exists an actual case where the current form causes an
> issue, please leave it unchanged. And if it is needed, then please make
> it a separate patch.
>

Got it, thanks.
I'll make it a separate patch.


--
Best wishes,
Kuo-Jung Su

Patch

diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
index 5bbb0a0..5a13af5 100644
--- a/arch/arm/include/asm/dma-mapping.h
+++ b/arch/arm/include/asm/dma-mapping.h
@@ -3,6 +3,9 @@ 
  * Stelian Pop <stelian@popies.net>
  * Lead Tech Design <www.leadtechdesign.com>
  *
+ * (C) Copyright 2010
+ * Dante Su <dantesu@faraday-tech.com>
+ *
  * See file CREDITS for list of people who contributed to this
  * project.
  *
@@ -24,22 +27,76 @@ 
 #ifndef __ASM_ARM_DMA_MAPPING_H
 #define __ASM_ARM_DMA_MAPPING_H

+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+#include <asm/u-boot.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <malloc.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
+
 enum dma_data_direction {
 	DMA_BIDIRECTIONAL	= 0,
 	DMA_TO_DEVICE		= 1,
 	DMA_FROM_DEVICE		= 2,
 };

-static void *dma_alloc_coherent(size_t len, unsigned long *handle)
+static inline void *dma_alloc_coherent(size_t len, unsigned long *handle)
 {
-	*handle = (unsigned long)malloc(len);
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+	void *map, *va = memalign(ARCH_DMA_MINALIGN, len);
+
+	if (va && gd->arch.cpu_mmu) {
+		invalidate_dcache_range((ulong)va, (ulong)va + len);
+		map = map_physmem((phys_addr_t)va, len, MAP_NOCACHE);
+		if (!map)
+			free(va);
+		va = map;
+	}
+
+	if (handle)
+		*handle = virt_to_phys(va);
+
+	return va;
+#else  /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
+	*handle = (unsigned long)memalign(ARCH_DMA_MINALIGN, len);
 	return (void *)*handle;
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
+}
+
+static inline void dma_free_coherent(void *vaddr, ulong len)
+{
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+	void *tmp = (void *)virt_to_phys(vaddr);
+	unmap_physmem(vaddr, len);
+	vaddr = tmp;
+#endif
+	free(vaddr);
 }

 static inline unsigned long dma_map_single(volatile void *vaddr, size_t len,
 					   enum dma_data_direction dir)
 {
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+	if (gd->arch.cpu_mmu) {
+		switch (dir) {
+		case DMA_BIDIRECTIONAL:
+		case DMA_TO_DEVICE:
+			flush_dcache_range((ulong)vaddr,
+				(ulong)vaddr + len);
+			break;
+
+		case DMA_FROM_DEVICE:
+			invalidate_dcache_range((ulong)vaddr,
+				(ulong)vaddr + len);
+			break;
+		}
+	}
+	return virt_to_phys((void *)vaddr);
+#else  /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
 	return (unsigned long)vaddr;
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
 }

 static inline void dma_unmap_single(volatile void *vaddr, size_t len,
diff --git a/arch/arm/include/asm/global_data.h b/arch/arm/include/asm/global_data.h
index 37ac0da..bd18ff7 100644
--- a/arch/arm/include/asm/global_data.h
+++ b/arch/arm/include/asm/global_data.h
@@ -38,6 +38,10 @@  struct arch_global_data {
 	unsigned long	pllb_rate_hz;
 	unsigned long	at91_pllb_usb_init;
 #endif
+#ifdef CONFIG_FARADAY
+	unsigned long   cpu_id;
+	unsigned long   cpu_mmu;	/* has mmu */
+#endif
 	/* "static data" needed by most of timer.c on ARM platforms */
 	unsigned long timer_rate_hz;
 	unsigned long tbu;
diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h
index 1fbc531..37c737e 100644
--- a/arch/arm/include/asm/io.h
+++ b/arch/arm/include/asm/io.h
@@ -2,6 +2,7 @@ 
  *  linux/include/asm-arm/io.h
  *
  *  Copyright (C) 1996-2000 Russell King
+ *  Copyright (C) 2009-2010 Dante Su <dantesu@faraday-tech.com>
  *
  * 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
@@ -28,9 +29,36 @@ 
 #if 0	/* XXX###XXX */
 #include <asm/arch/hardware.h>
 #endif	/* XXX###XXX */
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+#include <asm/system.h>
+#include <asm/u-boot.h>
+#include <asm/global_data.h>
+
+#ifndef CONFIG_MMAP_START
+#define CONFIG_MMAP_START   0xd0000000
+#endif
+
+#ifndef CONFIG_MMAP_END
+#define CONFIG_MMAP_END     0xfff00000
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
+
+/* arch/$(ARCH)/lib/cache.c */
+void invalidate_icache_all(void);
+void flush_dcache_all(void);
+void flush_dcache_range(ulong start, ulong stop);

 static inline void sync(void)
 {
+#ifndef CONFIG_SYS_DCACHE_OFF
+	flush_dcache_all();
+#endif
+#ifndef CONFIG_SYS_ICACHE_OFF
+	invalidate_icache_all();
+#endif
 }

 /*
@@ -39,27 +67,143 @@  static inline void sync(void)
  * properties specified by "flags".
  */
 #define MAP_NOCACHE	(0)
-#define MAP_WRCOMBINE	(0)
-#define MAP_WRBACK	(0)
-#define MAP_WRTHROUGH	(0)
+#define MAP_WRCOMBINE	(1)
+#define MAP_WRBACK	(2)
+#define MAP_WRTHROUGH	(3)
+
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+static inline void map_flush(ulong start, ulong end)
+{
+	flush_dcache_range(start, end);
+
+	/* invalidate D-TLB */
+	start &= 0xfff00000;
+	end = (end + 0x000fffff) & 0xfff00000;
+	__asm__ __volatile__ (
+		"mov r3, %0\n"
+		"1:\n"
+		"mcr p15, 0, r3, c8, c6, 1\n"
+		"add r3, r3, #4096\n"
+		"cmp r3, %1\n"
+		"blo 1b\n"
+		: /* output */
+		: "r"(start), "r"(end) /* input */
+		: "r3" /* clobber list */
+	);
+}
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */

 static inline void *
-map_physmem(phys_addr_t paddr, unsigned long len, unsigned long flags)
+map_physmem(phys_addr_t paddr, ulong len, ulong flags)
 {
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+	u32 *page_table = (u32 *)gd->arch.tlb_addr;
+	u32 vaddr, nattr, oattr, addr, size, end;
+
+	/* 1. check if we have to create a mapping for it */
+	vaddr = paddr;
+	addr  = page_table[vaddr >> 20] & 0xfff00000;
+	oattr = page_table[vaddr >> 20] & 0x1f;
+	switch (flags) {
+	case MAP_WRCOMBINE:
+		nattr = DCACHE_WRITECOMBINE;
+		break;
+	case MAP_WRTHROUGH:
+		nattr = DCACHE_WRITETHROUGH;
+		break;
+	case MAP_WRBACK:
+		nattr = DCACHE_WRITEBACK;
+		break;
+	default:
+		nattr = DCACHE_OFF;
+		break;
+	}
+	if ((nattr == oattr) && (vaddr == addr))
+		return (void *)paddr;
+
+	/* 2. find a contiguous region for it */
+	end = (paddr + len + 0x000fffff) & 0xfff00000;
+	len = end - (paddr & 0xfff00000);
+	size = 0;
+	addr = CONFIG_MMAP_START;
+	vaddr = addr;
+	while (addr < CONFIG_MMAP_END) {
+		/* if va == pa, then it's free to use */
+		if (addr == (page_table[addr >> 20] & 0xfff00000)) {
+			size += SZ_1M;
+		} else {
+			size = 0;
+			vaddr = addr + SZ_1M;
+		}
+		if (size >= len)
+			break;
+		addr += SZ_1M;
+	}
+	if (size < len)
+		return NULL;
+
+	/* 3. create the map */
+	map_flush(vaddr, vaddr + size);
+	addr = vaddr;
+	vaddr += paddr & 0x000fffff;
+	paddr &= 0xfff00000;
+	while (size) {
+		page_table[addr >> 20] = paddr | (3 << 10) | nattr;
+		size -= SZ_1M;
+		addr += SZ_1M;
+		paddr += SZ_1M;
+	}
+	return (void *)vaddr;
+#else  /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
 	return (void *)paddr;
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
 }

 /*
  * Take down a mapping set up by map_physmem().
  */
-static inline void unmap_physmem(void *vaddr, unsigned long flags)
+static inline void unmap_physmem(void *vaddr, ulong len)
 {
-
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+	u32 *page_table = (u32 *)gd->arch.tlb_addr;
+	u32 addr, end;
+
+	/* 1. skip on NULL pointer */
+	if (!vaddr)
+		return;
+
+	/* 2. check if it's the right address map */
+	addr = (u32)vaddr;
+	if ((page_table[addr >> 20] & 0xfff00000) == addr)
+		return;
+
+	/* 3. reset the map */
+	end = (addr + len + 0x000fffff) & 0xfff00000;
+	addr &= 0xfff00000;
+	map_flush(addr, end);
+	while (addr < end) {
+		page_table[addr >> 20] = addr | (3 << 10) | DCACHE_OFF;
+		addr += SZ_1M;
+	}
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
 }

-static inline phys_addr_t virt_to_phys(void * vaddr)
+static inline phys_addr_t virt_to_phys(void *vaddr)
 {
-	return (phys_addr_t)(vaddr);
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+	u32 *page_table = (u32 *)gd->arch.tlb_addr;
+	phys_addr_t phys = (phys_addr_t)vaddr;
+
+	if (!gd->arch.cpu_mmu || !vaddr)
+		return phys;
+
+	phys = page_table[(u32)vaddr >> 20] & 0xfff00000;
+	phys += (u32)vaddr & 0x000fffff;
+
+	return phys;
+#else  /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
+	return (phys_addr_t)vaddr;
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
 }

 /*
diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h
index 760345f..050b707 100644
--- a/arch/arm/include/asm/system.h
+++ b/arch/arm/include/asm/system.h
@@ -97,9 +97,10 @@  static inline void set_dacr(unsigned int val)

 /* options available for data cache on each page */
 enum dcache_option {
-	DCACHE_OFF = 0x12,
-	DCACHE_WRITETHROUGH = 0x1a,
-	DCACHE_WRITEBACK = 0x1e,
+	DCACHE_OFF = 0x12,          /* non-cached + non-buffered */
+	DCACHE_WRITECOMBINE = 0x16, /* non-cached + buffered */
+	DCACHE_WRITETHROUGH = 0x1a, /* cached + non-buffered */
+	DCACHE_WRITEBACK = 0x1e,    /* cached + buffered */
 };

 /* Size of an MMU section */
diff --git a/arch/arm/lib/cache-cp15.c b/arch/arm/lib/cache-cp15.c
index 4abe1cf..ea29e83 100644
--- a/arch/arm/lib/cache-cp15.c
+++ b/arch/arm/lib/cache-cp15.c
@@ -1,6 +1,8 @@ 
 /*
  * (C) Copyright 2002
  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ * (C) Copyright 2010
+ * Dante Su <dantesu@faraday-tech.com>
  *
  * See file CREDITS for list of people who contributed to this
  * project.
@@ -98,6 +100,24 @@  __weak void dram_bank_mmu_setup(int bank)
 		set_section_dcache(i, DCACHE_WRITEBACK);
 #endif
 	}
+
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+
+# ifdef CONFIG_USE_IRQ
+	/* make sure the exception table is at 0x00000000 */
+	if (!bank && bd->bi_dram[bank].start) {
+		u32 pa = bd->bi_dram[bank].start;
+		u32 *page_table = (u32 *)gd->arch.tlb_addr;
+
+#  ifdef CONFIG_SYS_ARM_CACHE_WRITETHROUGH
+		page_table[0] = pa | (3 << 10) | DCACHE_WRITETHROUGH;
+#  else
+		page_table[0] = pa | (3 << 10) | DCACHE_WRITEBACK;
+#  endif
+	}
+# endif /* # ifdef CONFIG_USE_IRQ */
+
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
 }

 /* to activate the MMU we need to set up virtual memory: use 1M areas */
@@ -126,6 +146,10 @@  static inline void mmu_setup(void)

 	/* and enable the mmu */
 	reg = get_cr();	/* get control reg. */
+#ifdef CONFIG_FARADAY
+	reg |= CR_W;	/* enable write buffer */
+	reg |= CR_Z;	/* enable branch prediction */
+#endif
 	cp_delay();
 	set_cr(reg | CR_M);
 }
@@ -140,9 +164,15 @@  static void cache_enable(uint32_t cache_bit)
 {
 	uint32_t reg;

+#ifdef CONFIG_FARADAY
+	if (!gd->arch.cpu_mmu && (cache_bit == CR_C))
+		return;
+#endif
+
 	/* The data cache is not active unless the mmu is enabled too */
 	if ((cache_bit == CR_C) && !mmu_enabled())
 		mmu_setup();
+
 	reg = get_cr();	/* get control reg. */
 	cp_delay();
 	set_cr(reg | cache_bit);
diff --git a/drivers/mtd/cfi_flash.c b/drivers/mtd/cfi_flash.c
index 22d8440..49bdcff 100644
--- a/drivers/mtd/cfi_flash.c
+++ b/drivers/mtd/cfi_flash.c
@@ -1818,7 +1818,7 @@  static int flash_detect_legacy(phys_addr_t base, int banknum)
 					break;
 				else
 					unmap_physmem((void *)info->start[0],
-						      MAP_NOCACHE);
+						      info->portwidth);
 			}
 		}