diff mbox

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

Message ID 1388395391-1560-5-git-send-email-dantesu@gmail.com
State Superseded
Delegated to: Albert ARIBAUD
Headers show

Commit Message

Kuo-Jung Su Dec. 30, 2013, 9:23 a.m. UTC
From: Kuo-Jung Su <dantesu@faraday-tech.com>

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(-)

--
1.7.9.5
diff mbox

Patch

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 */
 }

 /*