[U-Boot] [PATCH v8 4/8] arm: faraday: revise the DMA API

Kuo-Jung Su
2013-12-30T09:23:07Z

The DMA API is revised as follow:

1. Create an un-cached shadow memory for malloc(),
the un-cached shadow memory is controlled by
CONFIG_CONSISTENT_DMA_START and CONFIG_CONSISTENT_DMA_END,
and initialized inside arch_early_init_r().

2. The virtual address returned by dma_alloc_coherent()
always points to the corresponding uncached shadow memory
initialized at step 1.

3. The dma_map_single() will now invalidate/flush caches.

4. The virt_to_phys() will now calculate the physical address
from the section tables.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v8:
- Revised to use a shadow uncached region for malloc().

Changes for v6, v7:
- 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/cpu/faraday/cpu.c | 30 +++++++++++++++++++++++++++++
arch/arm/include/asm/config.h | 12 ++++++++++++
arch/arm/include/asm/dma-mapping.h | 37 ++++++++++++++++++++++++++++++++++++
arch/arm/include/asm/io.h | 19 ++++++++++++++++--
4 files changed, 96 insertions(+), 2 deletions(-)

diff --git a/arch/arm/cpu/faraday/cpu.c b/arch/arm/cpu/faraday/cpu.c
index d3c8a9e..83bc7f7 100644
--- a/arch/arm/cpu/faraday/cpu.c
+++ b/arch/arm/cpu/faraday/cpu.c
@@ -101,6 +101,36 @@ int print_cpuinfo(void)
}
#endif /* CONFIG_DISPLAY_CPUINFO */

+#ifdef CONFIG_ARCH_EARLY_INIT_R
+int arch_early_init_r(void)
+{
+#ifndef CONFIG_SYS_DCACHE_OFF
+ uint32_t mask = ~(SZ_1M - 1);
+ uint32_t phys = mem_malloc_start & mask;
+ uint32_t stop = (mem_malloc_end + (SZ_1M - 1)) & mask;
+ uint32_t size = stop - phys;
+ uint32_t virt = CONFIG_CONSISTENT_DMA_START & mask;
+ uint32_t *sect_table = (uint32_t *)gd->arch.tlb_addr;
+
+ if (!mmu_enabled())
+ return 0;
+
+ if (size > (CONFIG_CONSISTENT_DMA_END - virt))
+ panic("malloc size is too large for dma buffer\n");
+
+ while (size > 0) {
+ sect_table[virt >> 20] = phys | (3 << 10) | DCACHE_OFF;
+ virt += SZ_1M;
+ phys += SZ_1M;
+ size -= SZ_1M;
+ }
+
+ mmu_page_table_flush(mem_malloc_start & mask, stop);
+#endif /* !CONFIG_SYS_DCACHE_OFF */
+ return 0;
+}
+#endif /* CONFIG_ARCH_EARLY_INIT_R */
+
int cleanup_before_linux(void)
{
/*
diff --git a/arch/arm/include/asm/config.h b/arch/arm/include/asm/config.h
index 99b703e..295907c 100644
--- a/arch/arm/include/asm/config.h
+++ b/arch/arm/include/asm/config.h
@@ -7,6 +7,18 @@
#ifndef _ASM_CONFIG_H_
#define _ASM_CONFIG_H_

+#if defined(CONFIG_SOC_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+#ifndef CONFIG_ARCH_EARLY_INIT_R
+#define CONFIG_ARCH_EARLY_INIT_R
+#endif
+#ifndef CONFIG_CONSISTENT_DMA_START
+#define CONFIG_CONSISTENT_DMA_START 0xff000000
+#endif
+#ifndef CONFIG_CONSISTENT_DMA_END
+#define CONFIG_CONSISTENT_DMA_END 0xfff00000
+#endif
+#endif /* CONFIG_SOC_FARADAY && !CONFIG_SYS_DCACHE_OFF */
+
#define CONFIG_LMB
#define CONFIG_SYS_BOOT_RAMDISK_HIGH
#endif
diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
index 55a4e26..3b76046 100644
--- a/arch/arm/include/asm/dma-mapping.h
+++ b/arch/arm/include/asm/dma-mapping.h
@@ -8,6 +8,10 @@
#ifndef __ASM_ARM_DMA_MAPPING_H
#define __ASM_ARM_DMA_MAPPING_H

+#if defined(CONFIG_SOC_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+#include <malloc.h>
+#endif /* CONFIG_SOC_FARADAY && !CONFIG_SYS_DCACHE_OFF */
+
enum dma_data_direction {
DMA_BIDIRECTIONAL = 0,
DMA_TO_DEVICE = 1,
@@ -16,13 +20,46 @@ enum dma_data_direction {

static void *dma_alloc_coherent(size_t len, unsigned long *handle)
{
+#if defined(CONFIG_SOC_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+ uint32_t ofs;
+ void *mem = memalign(ARCH_DMA_MINALIGN, len);
+
+ if (handle)
+ *handle = (unsigned long)mem;
+
+ if (mem && mmu_enabled()) {
+ invalidate_dcache_range((ulong)mem, (ulong)mem + len);
+ ofs = (uint32_t)mem - (mem_malloc_start & 0xfff00000);
+ mem = (void *)(CONFIG_CONSISTENT_DMA_START + ofs);
+ }
+
+ return mem;
+#else /* CONFIG_SOC_FARADAY && !CONFIG_SYS_DCACHE_OFF */
*handle = (unsigned long)memalign(ARCH_DMA_MINALIGN, len);
+#endif /* CONFIG_SOC_FARADAY && !CONFIG_SYS_DCACHE_OFF */
return (void *)*handle;
}

static inline unsigned long dma_map_single(volatile void *vaddr, size_t len,
enum dma_data_direction dir)
{
+#if defined(CONFIG_SOC_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+ if (mmu_enabled()) {
+ 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);
+ }
+#endif /* CONFIG_SOC_FARADAY && !CONFIG_SYS_DCACHE_OFF */
return (unsigned long)vaddr;
}

diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h
index 1fbc531..b55d9e1 100644
--- a/arch/arm/include/asm/io.h
+++ b/arch/arm/include/asm/io.h
@@ -28,6 +28,9 @@
#if 0 /* XXX###XXX */
#include <asm/arch/hardware.h>
#endif /* XXX###XXX */
+#if defined(CONFIG_SOC_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+#include <common.h>
+#endif

static inline void sync(void)
{
@@ -57,9 +60,21 @@ static inline void unmap_physmem(void *vaddr, unsigned long flags)

}

-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_SOC_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+ DECLARE_GLOBAL_DATA_PTR;
+ u32 *sect_table = (u32 *)gd->arch.tlb_addr;
+ phys_addr_t phys = (phys_addr_t)vaddr;
+
+ if (!vaddr || !mmu_enabled())
+ return phys;
+
+ phys = sect_table[(u32)vaddr >> 20] & 0xfff00000;
+ return phys + ((phys_addr_t)vaddr & 0x000fffff);
+#else /* CONFIG_SOC_FARADAY && !CONFIG_SYS_DCACHE_OFF */
+ return (phys_addr_t)vaddr;
+#endif /* CONFIG_SOC_FARADAY && !CONFIG_SYS_DCACHE_OFF */
}

/*
--
1.7.9.5