[U-Boot] [PATCH 01/11] arm: add MMU/d-cache support for Faraday cores

Kuo-Jung Su dantesu at gmail.com
Fri Mar 29 08:06:18 CET 2013


From: Kuo-Jung Su <dantesu at faraday-tech.com>

This patch would enable MMU for Faraday ARMv5TE cores.

Here is the abstract of the MMU design.

Assume SDRAM memory region starts at 0x10000000, and its size = 0x800000.

0x00000000 +-------------------+
           |                   |
           |     UN-CACHED     |
           |                   |
           |                   |
0x10000000 +-------------------+
           |  CACHED (SDRAM)   | <- It's where data/bss/stack lived.
           |                   |
           |                   |
0x10800000 +-------------------+
           |                   |
           |                   |
           |     UN-CACHED     |
           |                   |
           |                   |
0xFF800000 +-------------------+
           | UN-CACHED (SDRAM) | <- An un-cached shadow of the SDRAM.
           |                   |    dma_alloc_coherent() always returns
           |                   |    an address in this region.
0xFFFFFFFF +-------------------+

Signed-off-by: Kuo-Jung Su <dantesu at faraday-tech.com>
---
 arch/arm/include/asm/dma-mapping.h |   55 ++++++++++++++++++++++++--
 arch/arm/include/asm/global_data.h |    4 ++
 arch/arm/include/asm/io.h          |   75 ++++++++++++++++++++++++++++++++++++
 arch/arm/lib/cache-cp15.c          |   44 +++++++++++++++++++++
 common/cmd_boot.c                  |    4 ++
 5 files changed, 179 insertions(+), 3 deletions(-)

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

+#include <asm/io.h>
+#include <malloc.h>
+
 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);
-	return (void *)*handle;
+	void *va = memalign(ARCH_DMA_MINALIGN, len);
+	if (va && handle)
+		*handle = virt_to_phys(va);
+
+#ifdef CONFIG_FARADAY
+# ifndef CONFIG_SYS_DCACHE_OFF
+#include <asm/u-boot.h> /* boot information for Linux kernel */
+#include <asm/global_data.h>	/* global data used for startup functions */
+	DECLARE_GLOBAL_DATA_PTR;
+
+	if (gd->arch.cpu_mmu) {
+		/* invalidate the buffer, and change to un-cached memory address */
+		if (va != NULL) {
+			invalidate_dcache_range((ulong)va, (ulong)va + len);
+			va = __uncached(va);
+		}
+	}
+# endif
+#endif	/* CONFIG_FARADAY */
+
+	return va;
+}
+
+static inline void dma_free_coherent(void *va)
+{
+	free(__cached(va));
 }

 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)
+#include <asm/u-boot.h> /* boot information for Linux kernel */
+#include <asm/global_data.h>	/* global data used for startup functions */
+	DECLARE_GLOBAL_DATA_PTR;
+
+	if (gd->arch.cpu_mmu) {
+		switch (dir) {
+		case DMA_BIDIRECTIONAL:
+		case DMA_TO_DEVICE:
+			flush_dcache_range((unsigned long)vaddr, (unsigned long)vaddr + len);
+			break;
+
+		case DMA_FROM_DEVICE:
+			invalidate_dcache_range((unsigned long)vaddr, (unsigned long)vaddr + len);
+			break;
+		}
+	}
+	return virt_to_phys((void *)vaddr);
+#else
 	return (unsigned long)vaddr;
+#endif
 }

 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..4659439 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 at 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
@@ -57,9 +58,83 @@ static inline void unmap_physmem(void *vaddr, unsigned long flags)

 }

+#if defined(CONFIG_FARADAY)
+
+#include <asm/u-boot.h> /* boot information for Linux kernel */
+#include <asm/global_data.h>
+
+static inline void *__cached(void *va)
+{
+# if !defined(CONFIG_SYS_DCACHE_OFF)
+	DECLARE_GLOBAL_DATA_PTR;
+	unsigned long base = (4096 - (gd->ram_size >> 20)) << 20;	/* un-cached base address */
+
+	if (!gd->arch.cpu_mmu)
+		return va;
+
+	if ((unsigned long)va >= base &&
+		(unsigned long)va < (base + gd->ram_size))
+		va = (void *)((unsigned long)va - base + CONFIG_SYS_SDRAM_BASE);
+# endif	/* !CONFIG_SYS_DCACHE_OFF */
+
+	return va;
+}
+
+static inline void *__uncached(void *va)
+{
+# if !defined(CONFIG_SYS_DCACHE_OFF)
+	DECLARE_GLOBAL_DATA_PTR;
+	unsigned long base = (4096 - (gd->ram_size >> 20)) << 20;	/* un-cached base address */
+
+	if (!gd->arch.cpu_mmu)
+		return va;
+
+# ifdef CONFIG_USE_IRQ
+	if ((unsigned long)va < SZ_1M)
+		return (void *)(base + (unsigned long)va);
+# endif
+
+	if ((unsigned long)va >= CONFIG_SYS_SDRAM_BASE &&
+		(unsigned long)va < (CONFIG_SYS_SDRAM_BASE + gd->ram_size))
+		return (void *)(base + ((unsigned long)va - CONFIG_SYS_SDRAM_BASE));
+# endif	/* !CONFIG_SYS_DCACHE_OFF */
+
+	return va;
+}
+
+#endif	/* CONFIG_FARADAY */
+
 static inline phys_addr_t virt_to_phys(void * vaddr)
 {
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+
+	DECLARE_GLOBAL_DATA_PTR;
+	bd_t *bd = gd->bd;
+	unsigned long base = (4096 - (gd->ram_size >> 20)) << 20;	/* un-cached base address */
+	unsigned long phys = (unsigned long)(vaddr);
+
+	if (!gd->arch.cpu_mmu)
+		return (phys_addr_t)phys;
+
+	if (phys >= base) {
+		unsigned long bank;
+		unsigned long off = phys - base;
+		for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; ++bank) {
+			if (bd->bi_dram[bank].size > off)
+				break;
+			off -= bd->bi_dram[bank].size;
+		}
+		phys = bd->bi_dram[bank].start + off;
+	}
+# ifdef CONFIG_USE_IRQ
+	else if (phys < SZ_1M && bd->bi_dram[0].start != 0)
+		phys = bd->bi_dram[0].start + phys;
+# endif
+
+	return (phys_addr_t)phys;
+#else
 	return (phys_addr_t)(vaddr);
+#endif
 }

 /*
diff --git a/arch/arm/lib/cache-cp15.c b/arch/arm/lib/cache-cp15.c
index b6e5e95..cf45d31 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 at denx.de.
+ * (C) Copyright 2010
+ * Dante Su <dantesu at faraday-tech.com>
  *
  * See file CREDITS for list of people who contributed to this
  * project.
@@ -81,6 +83,10 @@ static inline void dram_bank_mmu_setup(int bank)
 {
 	bd_t *bd = gd->bd;
 	int	i;
+#ifdef CONFIG_FARADAY
+	ulong ubase, off;
+	u32 *page_table = (u32 *)gd->arch.tlb_addr;
+#endif

 	debug("%s: bank: %d\n", __func__, bank);
 	for (i = bd->bi_dram[bank].start >> 20;
@@ -92,6 +98,32 @@ static inline void dram_bank_mmu_setup(int bank)
 		set_section_dcache(i, DCACHE_WRITEBACK);
 #endif
 	}
+#ifdef CONFIG_FARADAY
+# ifdef CONFIG_USE_IRQ
+	/* map the exception table to 0x00000000 if necessary */
+	if (bank == 0 && bd->bi_dram[bank].start != 0) {
+		u32 pa = bd->bi_dram[bank].start;
+#if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH)
+		page_table[0] = pa | (3 << 10) | DCACHE_WRITETHROUGH;
+#else
+		page_table[0] = pa | (3 << 10) | DCACHE_WRITEBACK;
+#endif
+	}
+# endif
+	/* calculate address offset */
+	off  = 0;
+	for (i = 0; i < bank; ++i)
+		off += bd->bi_dram[bank].size;
+
+	/* create memory map */
+	ubase = (4096 - (gd->ram_size >> 20)) << 20;
+	for (i = 0; i < bd->bi_dram[bank].size >> 20; ++i) {
+		u32 pa = bd->bi_dram[bank].start + (i << 20);
+		/* create un-cached address map */
+		u32 va = ubase + off + (i << 20);
+		page_table[va >> 20] = pa | (3 << 10) | DCACHE_OFF;
+	}
+#endif
 }

 /* to activate the MMU we need to set up virtual memory: use 1M areas */
@@ -117,6 +149,12 @@ static inline void mmu_setup(void)
 		     : : "r" (~0));
 	/* and enable the mmu */
 	reg = get_cr();	/* get control reg. */
+#if !defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH)
+	reg |= CR_W;
+#endif
+#ifdef CONFIG_FARADAY
+	reg |= CR_Z;	/* Branch Prediction */
+#endif
 	cp_delay();
 	set_cr(reg | CR_M);
 }
@@ -131,9 +169,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/common/cmd_boot.c b/common/cmd_boot.c
index d3836fd..b2477e8 100644
--- a/common/cmd_boot.c
+++ b/common/cmd_boot.c
@@ -50,6 +50,10 @@ static int do_go(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])

 	printf ("## Starting application at 0x%08lX ...\n", addr);

+#if defined(__ARM__) && !defined(CONFIG_SYS_DCACHE_OFF)
+	cleanup_before_linux();
+#endif
+
 	/*
 	 * pass address parameter as argv[0] (aka command name),
 	 * and all remaining args
--
1.7.9.5



More information about the U-Boot mailing list