From: Kuo-Jung Su <dant...@faraday-tech.com>

This 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 wastes lots of
address space, however this should still be good enough for
tiny systems (i.e. u-boot).

Signed-off-by: Kuo-Jung Su <dant...@faraday-tech.com>
CC: Albert Aribaud <albert.u.b...@aribaud.net>
---
Changes for v6:
   - Nothing updates

Changes for v5:
   - Add void dram_bank_mmu_setup() into 'arch/arm/cpu/faraday/cpu.c'
     to override the weak function in "cache-cp15.c".
   - Use small page (4KB) to map relocated exception table to 0x0000

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 |   59 ++++++++++++-
 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          |   12 +++
 5 files changed, 230 insertions(+), 12 deletions(-)

diff --git a/arch/arm/include/asm/dma-mapping.h 
b/arch/arm/include/asm/dma-mapping.h
index a11178f..5a13af5 100644
--- a/arch/arm/include/asm/dma-mapping.h
+++ b/arch/arm/include/asm/dma-mapping.h
@@ -3,6 +3,9 @@
  * Stelian Pop <stel...@popies.net>
  * Lead Tech Design <www.leadtechdesign.com>
  *
+ * (C) Copyright 2010
+ * Dante Su <dant...@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)
 {
+#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 7611d0a..fc78c6a 100644
--- a/arch/arm/include/asm/global_data.h
+++ b/arch/arm/include/asm/global_data.h
@@ -42,6 +42,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 <dant...@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..97436f6 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, w...@denx.de.
+ * (C) Copyright 2010
+ * Dante Su <dant...@faraday-tech.com>
  *
  * See file CREDITS for list of people who contributed to this
  * project.
@@ -126,6 +128,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 +146,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);
--
1.7.9.5

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to