From mboxrd@z Thu Jan 1 00:00:00 1970 From: Kuo-Jung Su Date: Mon, 30 Dec 2013 17:23:07 +0800 Subject: [U-Boot] [PATCH v8 4/8] arm: faraday: revise the DMA API In-Reply-To: <1388395391-1560-1-git-send-email-dantesu@gmail.com> References: <1388395391-1560-1-git-send-email-dantesu@gmail.com> Message-ID: <1388395391-1560-5-git-send-email-dantesu@gmail.com> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de From: Kuo-Jung Su 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 CC: Albert Aribaud --- 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 +#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 #endif /* XXX###XXX */ +#if defined(CONFIG_SOC_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF) +#include +#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