[U-Boot] [PATCH v2 3/4] arm64/lib support of arm64

fenghua at phytium.com.cn fenghua at phytium.com.cn
Wed Aug 14 12:58:06 CEST 2013


From: David Feng <fenghua at phytium.com.cn>

This patch provide u-boot with arm64 support. Currently, it works on
Foundation Model for armv8 or Fast Model for armv8.

Signed-off-by: David Feng <fenghua at phytium.com.cn>
---
Changes for v2:
    - fix EXPORT_FUNC macro to use register x9 according to "Scott Wood" mail
    - redefine some copyright text
    - add declaration of cache related functions, remove some compiler warnnings

 arch/arm64/lib/Makefile     |   64 ++++++
 arch/arm64/lib/board.c      |  456 +++++++++++++++++++++++++++++++++++++++++++
 arch/arm64/lib/bootm.c      |  211 ++++++++++++++++++++
 arch/arm64/lib/cache.c      |  282 ++++++++++++++++++++++++++
 arch/arm64/lib/crt0.S       |  129 ++++++++++++
 arch/arm64/lib/interrupts.c |  109 +++++++++++
 arch/arm64/lib/relocate.S   |   72 +++++++
 arch/arm64/lib/reset.c      |   37 ++++
 arch/arm64/lib/timer.c      |   95 +++++++++
 9 files changed, 1455 insertions(+)
 create mode 100644 arch/arm64/lib/Makefile
 create mode 100644 arch/arm64/lib/board.c
 create mode 100644 arch/arm64/lib/bootm.c
 create mode 100644 arch/arm64/lib/cache.c
 create mode 100644 arch/arm64/lib/crt0.S
 create mode 100644 arch/arm64/lib/interrupts.c
 create mode 100644 arch/arm64/lib/relocate.S
 create mode 100644 arch/arm64/lib/reset.c
 create mode 100644 arch/arm64/lib/timer.c

diff --git a/arch/arm64/lib/Makefile b/arch/arm64/lib/Makefile
new file mode 100644
index 0000000..87fa803
--- /dev/null
+++ b/arch/arm64/lib/Makefile
@@ -0,0 +1,64 @@
+#
+# (C) Copyright 2002-2006
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(ARCH).o
+LIBGCC	= $(obj)libgcc.o
+
+COBJS-y	+= board.o
+COBJS-y	+= interrupts.o
+COBJS-y	+= reset.o
+COBJS-y	+= cache.o
+COBJS-y	+= timer.o
+
+COBJS-$(CONFIG_CMD_BOOTM) += bootm.o
+
+SOBJS-y += crt0.o
+SOBJS-y += relocate.o
+
+SRCS	:= $(GLSOBJS:.o=.S) $(GLCOBJS:.o=.c) \
+	   $(SOBJS-y:.o=.S) $(COBJS-y:.o=.c)
+OBJS	:= $(addprefix $(obj),$(SOBJS-y) $(COBJS-y))
+LGOBJS	:= $(addprefix $(obj),$(GLSOBJS)) \
+	   $(addprefix $(obj),$(GLCOBJS))
+
+# Always build libarm64.o
+TARGETS	:= $(LIB)
+
+all:	$(TARGETS)
+
+$(LIB):	$(obj).depend $(OBJS)
+	$(call cmd_link_o_target, $(OBJS))
+
+$(LIBGCC): $(obj).depend $(LGOBJS)
+	$(call cmd_link_o_target, $(LGOBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/arm64/lib/board.c b/arch/arm64/lib/board.c
new file mode 100644
index 0000000..a8147a5
--- /dev/null
+++ b/arch/arm64/lib/board.c
@@ -0,0 +1,456 @@
+/*
+ * (C) Copyright 2013
+ * David Feng, Phytium Technology <fenghua at phytium.com.cn>
+ *
+ * (C) Copyright 2002-2006
+ * Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+ *
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger at sysgo.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <command.h>
+#include <malloc.h>
+#include <stdio_dev.h>
+#include <version.h>
+#include <net.h>
+#include <serial.h>
+#include <nand.h>
+#include <onenand_uboot.h>
+#include <mmc.h>
+#include <libfdt.h>
+#include <fdtdec.h>
+#include <post.h>
+#include <logbuff.h>
+#include <pci.h>
+#include <fdt_support.h>
+#include <asm/arch/mmu.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+ulong monitor_flash_len;
+
+/* The following functions defined in platform code */
+extern int dram_init(void);
+extern int arch_cpu_init(void);
+
+/* for the following variables, see start.S */
+extern ulong _bss_start_ofs;	/* BSS start relative to _start */
+extern ulong _bss_end_ofs;	/* BSS end relative to _start */
+extern ulong _end_ofs;		/* end of image relative to _start */
+
+static int init_baudrate(void)
+{
+	gd->baudrate = getenv_ulong("baudrate", 10, CONFIG_BAUDRATE);
+	return 0;
+}
+
+static int display_banner(void)
+{
+	printf("\n\n%s\n\n", version_string);
+	debug("U-Boot code: %lx -> %lx  BSS: -> %lx\n",
+		(ulong)CONFIG_SYS_TEXT_BASE,
+		(ulong)(CONFIG_SYS_TEXT_BASE + _bss_start_ofs),
+		(ulong)(CONFIG_SYS_TEXT_BASE + _bss_end_ofs));
+
+	return (0);
+}
+
+/*
+ * Default implementation of display_cpuinfo()
+ * Real implementation should be in platform code
+ */
+int __display_cpuinfo(void)
+{
+	return 0;
+}
+int display_cpuinfo(void)
+	__attribute__((weak, alias("__display_cpuinfo")));
+
+/*
+ * Default implementation of display_boardinfo()
+ * Real implementation should be in platform code
+ */
+static int __display_boardinfo(void)
+{
+	return 0;
+}
+int display_boardinfo(void)
+	__attribute__((weak, alias("__display_boardinfo")));
+
+/*
+ * Default implementation of board_early_init_f()
+ * Real implementation should be in platform code
+ */
+static int __board_early_init_f(void)
+{
+	return 0;
+}
+int board_early_init_f(void)
+	__attribute__((weak, alias("__board_early_init_f")));
+
+/*
+ * Default implementation of board_late_init()
+ * Real implementation should be in platform code
+ */
+static int __board_late_init(void)
+{
+	return 0;
+}
+int board_late_init(void)
+	__attribute__((weak, alias("__board_late_init")));
+
+/*
+ * All attempts to come up with a "common" initialization sequence
+ * that works for all boards and architectures failed: some of the
+ * requirements are just _too_ different. To get rid of the resulting
+ * mess of board dependent #ifdef'ed code we now make the whole
+ * initialization sequence configurable to the user.
+ *
+ * The requirements for any new initalization function is simple: it
+ * receives a pointer to the "global data" structure as it's only
+ * argument, and returns an integer return code, where 0 means
+ * "continue" and != 0 means "fatal error, hang the system".
+ */
+typedef int (init_fnc_t) (void);
+
+init_fnc_t *init_sequence[] = {
+	arch_cpu_init,		/* basic arch cpu dependent setup */
+	board_early_init_f,
+#ifdef CONFIG_OF_CONTROL
+	fdtdec_check_fdt,
+#endif
+	env_init,		/* initialize environment */
+	init_baudrate,		/* initialze baudrate settings */
+	serial_init,		/* serial communications setup */
+	console_init_f,		/* stage 1 init of console */
+	display_banner,		/* say that we are here */
+	display_cpuinfo,	/* display cpu info (and speed) */
+	display_boardinfo,	/* display board info */
+	dram_init,		/* configure available RAM banks */
+	NULL,
+};
+
+void board_init_f(ulong bootflag)
+{
+	bd_t *bd;
+	init_fnc_t **init_fnc_ptr;
+	gd_t *id;
+	ulong addr, addr_sp;
+	void *new_fdt = NULL;
+	size_t fdt_size = 0;
+
+	bootstage_mark_name(BOOTSTAGE_ID_START_UBOOT_F, "board_init_f");
+
+	/* Pointer is writable since we allocated a register for it */
+	memset((void *)gd, 0, sizeof(gd_t));
+
+	gd->bd = (bd_t *)(gd + 1);
+	gd->mon_len = _bss_end_ofs;
+
+	/*
+	 * Device Tree file can be merged in uboot.bin or appended after
+	 * uboot.bin as a seperate file. The following code initialize 
+	 * fdt block base address.
+	 */
+#ifdef CONFIG_OF_EMBED
+	/* Get a pointer to the FDT */
+	gd->fdt_blob = _binary_dt_dtb_start;
+#elif defined(CONFIG_OF_SEPARATE)
+	/* FDT is at end of image */
+	gd->fdt_blob = (void *)(CONFIG_SYS_TEXT_BASE + _end_ofs);
+#endif
+	/* Allow the early environment to override the fdt address */
+	gd->fdt_blob = (void *)getenv_ulong("fdtcontroladdr", 16,
+						(uintptr_t)gd->fdt_blob);
+
+	/*
+	 * Calling system initialization functions in sequence.
+	 */
+	for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
+		if ((*init_fnc_ptr)() != 0) {
+			hang ();
+		}
+	}
+
+#if defined(CONFIG_OF_CONTROL) || defined(CONFIG_OF_LIBFDT)
+	/* For now, put this check after the console is ready */
+	if (fdtdec_prepare_fdt()) {
+		panic("** CONFIG_OF_CONTROL defined but no FDT - please see doc/README.fdt-control");
+	}
+#endif
+
+	/*
+	 * Console has beeb setup, output debug messages
+	 */
+	debug("U-Boot code len: %08lX\n", gd->mon_len);
+
+	addr = CONFIG_SYS_SDRAM_BASE + gd->ram_size;
+
+	debug("Top of RAM usable for U-Boot at: %08lx\n", addr);
+
+#ifdef CONFIG_LOGBUFFER
+#ifndef CONFIG_ALT_LB_ADDR
+	/* reserve kernel log buffer */
+	addr -= (LOGBUFF_RESERVE);
+	debug("Reserving %dk for kernel logbuffer at %08lx\n", LOGBUFF_LEN, addr);
+#endif
+#endif
+
+#ifndef CONFIG_SYS_DCACHE_OFF
+	/* reserve MMU table and align it to PAGE_SIZE */
+	addr -= PAGE_SIZE;
+	addr &= PAGE_MASK;
+	gd->arch.tlb_addr = addr;
+	gd->arch.tlb_size = PAGE_SIZE;
+	debug("MMU table at: %08lx\n", addr);
+#endif
+
+	/*
+	 * reserve memory for U-Boot code, data & bss
+	 * align it to PAGE_SIZE
+	 */
+	addr -= gd->mon_len;
+	addr &= PAGE_MASK;
+	debug("Reserving %ldk for U-Boot at: %08lx\n", gd->mon_len >> 10, addr);
+
+	/*
+	 * reserve memory for malloc() arena
+	 */
+	addr_sp = addr - TOTAL_MALLOC_LEN;
+	debug("Reserving %dk for malloc() at: %08lx\n", TOTAL_MALLOC_LEN >> 10, addr_sp);
+
+	/*
+	 * (permanently) allocate a Board Info struct
+	 */
+	addr_sp -= sizeof(bd_t);
+	bd = (bd_t *)addr_sp;
+	memcpy(bd, (void *)gd->bd, sizeof(bd_t));
+	gd->bd = bd;
+	gd->bd->bi_baudrate = gd->baudrate;
+	debug("Reserving %zu Bytes for Board Info at: %08lx\n", sizeof(bd_t), addr_sp);
+
+	/*
+	 * (permanently) allocate a Global Data struct
+	 */
+	addr_sp -= sizeof(gd_t);
+	id = (gd_t *)addr_sp;
+	debug("Reserving %zu Bytes for Global Data at: %08lx\n", sizeof(gd_t), addr_sp);
+
+#if defined(CONFIG_OF_CONTROL) || defined(CONFIG_OF_LIBFDT)
+	/*
+	 * If the device tree is sitting immediate above our image then we
+	 * must relocate it. If it is embedded in the data section, then it
+	 * will be relocated with other data.
+	 */
+	if (gd->fdt_blob) {
+		fdt_size = ALIGN(fdt_totalsize(gd->fdt_blob) + 0x1000, 32);
+
+		addr_sp -= fdt_size;
+		new_fdt = (void *)addr_sp;
+		debug("Reserving %zu Bytes for FDT at: %08lx\n", fdt_size, addr_sp);
+	}
+#endif
+
+	/* 16-byte alignment for ABI compliance */
+	addr_sp &= ~0xf;
+	debug("New Stack Pointer is: %08lx\n", addr_sp);
+
+	gd->relocaddr = addr;
+	gd->start_addr_sp = addr_sp;
+	gd->reloc_off = addr - CONFIG_SYS_TEXT_BASE;
+	debug("Relocation Offset: %08lx\n", gd->reloc_off);
+
+	if (new_fdt) {
+		memcpy(new_fdt, gd->fdt_blob, fdt_size);
+		gd->fdt_blob = new_fdt;
+	}
+
+	memcpy(id, (void *)gd, sizeof(gd_t));
+}
+
+
+/*
+ ************************************************************************
+ *
+ * This is the next part of the initialization sequence: we are now
+ * running from RAM and have a "normal" C environment, i. e. global
+ * data can be written, BSS has been cleared, the stack size in not
+ * that critical any more, etc.
+ *
+ ************************************************************************
+ */
+
+void board_init_r(gd_t *id, ulong dest_addr)
+{
+#ifndef CONFIG_SYS_NO_FLASH
+	ulong flash_size;
+#endif
+
+	gd = id;
+
+	gd->flags |= GD_FLG_RELOC;	/* tell others: relocation done */
+	bootstage_mark_name(BOOTSTAGE_ID_START_UBOOT_R, "board_init_r");
+
+	/* before here, printf can not be used */
+	serial_initialize();
+
+	debug("Now running in RAM - U-Boot at: %08lx\n", dest_addr);
+
+	monitor_flash_len = _end_ofs;
+
+	/* Enable caches */
+	enable_caches();
+
+#ifdef CONFIG_NEEDS_MANUAL_RELOC
+	/*
+	 * We have to relocate the command table manually
+	 */
+	fixup_cmdtable(ll_entry_start(cmd_tbl_t, cmd),
+			ll_entry_count(cmd_tbl_t, cmd));
+#endif /* CONFIG_NEEDS_MANUAL_RELOC */
+
+	/* there are some other pointer constants we must deal with */
+#ifndef CONFIG_ENV_IS_NOWHERE
+	env_name_spec += gd->reloc_off;
+#endif
+
+#ifdef CONFIG_LOGBUFFER
+	logbuff_init_ptrs();
+#endif
+
+	/* The Malloc area is immediately below the monitor copy in DRAM */
+	mem_malloc_init (dest_addr - TOTAL_MALLOC_LEN, TOTAL_MALLOC_LEN);
+
+#ifndef CONFIG_SYS_NO_FLASH
+	puts("Flash: ");
+
+	flash_size = flash_init();
+	if (flash_size > 0) {
+# ifdef CONFIG_SYS_FLASH_CHECKSUM
+		char *s = getenv("flashchecksum");
+
+		print_size(flash_size, "");
+		/*
+		 * Compute and print flash CRC if flashchecksum is set to 'y'
+		 *
+		 * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX
+		 */
+		if (s && (*s == 'y')) {
+			printf("  CRC: %08X", crc32(0,
+				(const unsigned char *) CONFIG_SYS_FLASH_BASE,
+				flash_size));
+		}
+		putc('\n');
+# else	/* !CONFIG_SYS_FLASH_CHECKSUM */
+		print_size(flash_size, "\n");
+# endif /* CONFIG_SYS_FLASH_CHECKSUM */
+	} else {
+		puts("*** failed ***\n");
+		hang();
+	}
+#endif
+
+#ifdef CONFIG_CMD_NAND
+	puts("NAND:  ");
+	nand_init();		/* go init the NAND */
+#endif
+
+#ifdef CONFIG_CMD_ONENAND
+	onenand_init();
+#endif
+
+#ifdef CONFIG_GENERIC_MMC
+	puts("MMC:   ");
+	mmc_initialize(gd->bd);
+#endif
+
+	/* initialize environment */
+	env_relocate();
+
+#if defined(CONFIG_CMD_PCI) || defined(CONFIG_PCI)
+	pci_init();
+#endif
+
+	stdio_init();	/* get the devices list going. */
+
+	jumptable_init();
+
+#if defined(CONFIG_API)
+	/* Initialize API */
+	api_init();
+#endif
+
+	console_init_r();	/* fully init console as a device */
+
+	/* set up and enable exceptions */
+	interrupt_init();
+	enable_interrupts();
+
+	/* Initialize from environment */
+	load_addr = getenv_ulong("loadaddr", 16, load_addr);
+
+	board_late_init();
+
+#if defined(CONFIG_CMD_NET)
+	puts("Net:   ");
+	eth_initialize(gd->bd);
+#if defined(CONFIG_RESET_PHY_R)
+	debug("Reset Ethernet PHY\n");
+	reset_phy();
+#endif
+#endif
+
+#ifdef CONFIG_POST
+	post_run(NULL, POST_RAM | post_bootmode_get(0));
+#endif
+
+#ifdef CONFIG_OF_LIBFDT
+	set_working_fdt_addr((void *)gd->fdt_blob);
+#endif
+
+#ifdef CONFIG_LOGBUFFER
+	/*
+	 * Export available size of memory for Linux,
+	 * taking into account the protected RAM at top of memory
+	 */
+	{
+		ulong pram = 0;
+		uchar memsz[32];
+
+#ifndef CONFIG_ALT_LB_ADDR
+		/* Also take the logbuffer into account (pram is in kB) */
+		pram += (LOGBUFF_LEN + LOGBUFF_OVERHEAD) / 1024;
+#endif
+		sprintf((char *)memsz, "%ldk", (gd->ram_size / 1024) - pram);
+		setenv("mem", (char *)memsz);
+	}
+#endif
+
+	/* main_loop() can return to retry autoboot, if so just run it again. */
+	for (;;) {
+		main_loop();
+	}
+
+	/* NOTREACHED - no way out of command loop except booting */
+}
diff --git a/arch/arm64/lib/bootm.c b/arch/arm64/lib/bootm.c
new file mode 100644
index 0000000..af3bc09
--- /dev/null
+++ b/arch/arm64/lib/bootm.c
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2011
+ * Corscience GmbH & Co. KG - Simon Schwarz <schwarz at corscience.de>
+ *  - Added prep subcommand support
+ *  - Reorganized source - modeled after powerpc version
+ *
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger at sysgo.de>
+ *
+ * Copyright (C) 2001  Erik Mouw (J.A.K.Mouw at its.tudelft.nl)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307	 USA
+ *
+ */
+
+#include <common.h>
+#include <command.h>
+#include <image.h>
+#include <u-boot/zlib.h>
+#include <asm/byteorder.h>
+#include <libfdt.h>
+#include <fdt_support.h>
+
+
+DECLARE_GLOBAL_DATA_PTR;
+
+extern int cleanup_before_linux(void);
+
+
+static ulong get_sp(void)
+{
+	ulong ret;
+
+	asm("mov %0, sp" : "=r"(ret) : );
+	return ret;
+}
+
+void arch_lmb_reserve(struct lmb *lmb)
+{
+	ulong sp;
+
+	/*
+	 * Booting a (Linux) kernel image
+	 *
+	 * Allocate space for command line and board info - the
+	 * address should be as high as possible within the reach of
+	 * the kernel (see CONFIG_SYS_BOOTMAPSZ settings), but in unused
+	 * memory, which means far enough below the current stack
+	 * pointer.
+	 */
+	sp = get_sp();
+	debug("## Current stack ends at 0x%08lx ", sp);
+
+	/* adjust sp by 4K to be safe */
+	sp -= 4096;
+	lmb_reserve(lmb, sp,
+		    gd->bd->bi_dram[0].start + gd->bd->bi_dram[0].size - sp);
+}
+
+#ifdef CONFIG_OF_LIBFDT
+int arch_fixup_memory_node(void *blob)
+{
+	bd_t	*bd = gd->bd;
+	int bank;
+	u64 start[CONFIG_NR_DRAM_BANKS];
+	u64 size[CONFIG_NR_DRAM_BANKS];
+
+	for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) {
+		start[bank] = bd->bi_dram[bank].start;
+		size[bank] = bd->bi_dram[bank].size;
+	}
+
+	return fdt_fixup_memory_banks(blob, start, size, CONFIG_NR_DRAM_BANKS);
+}
+#endif
+
+/**
+ * announce_and_cleanup() - Print message and prepare for kernel boot
+ *
+ * @fake: non-zero to do everything except actually boot
+ */
+static void announce_and_cleanup(int fake)
+{
+	printf("\nStarting kernel ...%s\n\n", fake ?
+		"(fake run for tracing)" : "");
+	bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel");
+#ifdef CONFIG_BOOTSTAGE_FDT
+	if (flag == BOOTM_STATE_OS_FAKE_GO)
+		bootstage_fdt_add_report();
+#endif
+#ifdef CONFIG_BOOTSTAGE_REPORT
+	bootstage_report();
+#endif
+
+#ifdef CONFIG_USB_DEVICE
+	udc_disconnect();
+#endif
+	cleanup_before_linux();
+}
+
+/* Subcommand: PREP */
+static void boot_prep_linux(bootm_headers_t *images)
+{
+	if (!images->ft_len && gd->fdt_blob) {
+		images->ft_addr = (void *)gd->fdt_blob;
+		images->ft_len = fdt_totalsize(gd->fdt_blob);
+	}
+
+	if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len) {
+#ifdef CONFIG_OF_LIBFDT
+		debug("using: FDT\n");
+		if (image_setup_linux(images)) {
+			printf("FDT creation failed! hanging...");
+			hang();
+		}
+#endif
+	} else {
+		printf("FDT support not compiled in - hanging\n");
+		hang();
+	}
+}
+
+/* Subcommand: GO */
+static void boot_jump_linux(bootm_headers_t *images, int flag)
+{
+	void (*kernel_entry)(void *fdt_addr);
+	int fake = (flag & BOOTM_STATE_OS_FAKE_GO);
+
+	kernel_entry = (void (*)(void *fdt_addr))images->ep;
+
+	debug("## Transferring control to Linux (at address %lx)" \
+		"...\n", (ulong)kernel_entry);
+	bootstage_mark(BOOTSTAGE_ID_RUN_OS);
+
+	announce_and_cleanup(fake);
+
+	if (!fake)
+		kernel_entry(images->ft_addr);
+}
+
+/* Main Entry point for arm bootm implementation
+ *
+ * Modeled after the powerpc implementation
+ * DIFFERENCE: Instead of calling prep and go at the end
+ * they are called if subcommand is equal 0.
+ */
+int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
+{
+	/* No need for those on ARM */
+	if (flag & BOOTM_STATE_OS_BD_T || flag & BOOTM_STATE_OS_CMDLINE)
+		return -1;
+
+	if (flag & BOOTM_STATE_OS_PREP) {
+		boot_prep_linux(images);
+		return 0;
+	}
+
+	if (flag & (BOOTM_STATE_OS_GO | BOOTM_STATE_OS_FAKE_GO)) {
+		boot_jump_linux(images, flag);
+		return 0;
+	}
+
+	boot_prep_linux(images);
+	boot_jump_linux(images, flag);
+	return 0;
+}
+
+#ifdef CONFIG_CMD_BOOTZ
+
+struct zimage_header {
+	uint32_t	code[9];
+	uint32_t	zi_magic;
+	uint32_t	zi_start;
+	uint32_t	zi_end;
+};
+
+#define	LINUX_ARM_ZIMAGE_MAGIC	0x016f2818
+
+int bootz_setup(ulong image, ulong *start, ulong *end)
+{
+	struct zimage_header *zi;
+
+	zi = (struct zimage_header *)map_sysmem(image, 0);
+	if (zi->zi_magic != LINUX_ARM_ZIMAGE_MAGIC) {
+		puts("Bad Linux ARM zImage magic!\n");
+		return 1;
+	}
+
+	*start = zi->zi_start;
+	*end = zi->zi_end;
+
+	printf("Kernel image @ %#08lx [ %#08lx - %#08lx ]\n", image, *start,
+	      *end);
+
+	return 0;
+}
+
+#endif	/* CONFIG_CMD_BOOTZ */
diff --git a/arch/arm64/lib/cache.c b/arch/arm64/lib/cache.c
new file mode 100644
index 0000000..29c1ab2
--- /dev/null
+++ b/arch/arm64/lib/cache.c
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 2013	David Feng <fenghua at phytium.com.cn>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/system.h>
+#include <asm/processor.h>
+#include <asm/arch/mmu.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/********************************************************************/
+
+/*
+ * Stub implementations for outer cache operations
+ */
+void __outer_cache_enable(void) {}
+void outer_cache_enable(void)
+	__attribute__((weak, alias("__outer_cache_enable")));
+
+void __outer_cache_disable(void) {}
+void outer_cache_disable(void)
+	__attribute__((weak, alias("__outer_cache_disable")));
+
+void __outer_cache_flush_all(void) {}
+void outer_cache_flush_all(void)
+ 	__attribute__((weak, alias("__outer_cache_flush_all")));
+
+void __outer_cache_inval_all(void) {}
+void outer_cache_inval_all(void)
+	__attribute__((weak, alias("__outer_cache_inval_all")));
+
+void __outer_cache_flush_range(unsigned long start, unsigned long end) {}
+void outer_cache_flush_range(unsigned long start, unsigned long end)
+	__attribute__((weak, alias("__outer_cache_flush_range")));
+
+void __outer_cache_inval_range(unsigned long start, unsigned long end) {}
+void outer_cache_inval_range(unsigned long start, unsigned long end)
+	__attribute__((weak, alias("__outer_cache_inval_range")));
+
+/********************************************************************/
+
+#ifndef CONFIG_SYS_DCACHE_OFF
+
+static void set_section_dcache(u64 section, u64 memory_type)
+{
+	u64 *page_table = (u64 *)gd->arch.tlb_addr;
+	u64 value;
+
+	value = (section << SECTION_SHIFT) | PMD_TYPE_SECT | PMD_SECT_AF;
+	value |= PMD_ATTRINDX(memory_type);
+	page_table[section] = value;
+}
+
+/* to activate the MMU we need to set up virtual memory */
+static inline void mmu_setup(void)
+{
+	int i, j;
+	bd_t *bd = gd->bd;
+	static int table_initialized = 0;
+
+	if (!table_initialized) {
+		/* Setup an identity-mapping for all spaces */
+		for (i = 0; i < (PAGE_SIZE >> 3); i++)
+			set_section_dcache(i, MT_DEVICE_nGnRnE);
+
+		/* Setup an identity-mapping for all RAM space */
+		for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
+			debug("%s: bank: %d\n", __func__, i);
+			for (j = bd->bi_dram[i].start >> SECTION_SHIFT;
+				 j < (bd->bi_dram[i].start + bd->bi_dram[i].size) >> SECTION_SHIFT;
+				 j++) {
+				set_section_dcache(i, MT_NORMAL);
+			}
+		}
+
+		/* load TTBR0 */
+		asm volatile("msr ttbr0_el2, %0" : : "r" (gd->arch.tlb_addr) : "memory");
+
+		table_initialized = 1;
+	}
+
+	/* and enable the mmu */
+	set_sctlr(get_sctlr() | CR_M);
+}
+
+/*
+ * Performs a invalidation of the entire data cache
+ * at all levels
+ */
+void invalidate_dcache_all(void)
+{
+	__flush_dcache_all();
+	outer_cache_inval_all();
+}
+
+/*
+ * Performs a clean & invalidation of the entire data cache
+ * at all levels
+ */
+void flush_dcache_all(void)
+{
+	__flush_dcache_all();
+	outer_cache_flush_all();
+}
+
+/*
+ * Invalidates range in all levels of D-cache/unified cache used:
+ * Affects the range [start, stop - 1]
+ */
+void invalidate_dcache_range(unsigned long start, unsigned long stop)
+{
+	__flush_dcache_range(start, stop);
+	outer_cache_inval_range(start, stop);
+}
+
+/*
+ * Flush range(clean & invalidate) from all levels of D-cache/unified
+ * cache used:
+ * Affects the range [start, stop - 1]
+ */
+void flush_dcache_range(unsigned long start, unsigned long stop)
+{
+	__flush_dcache_range(start, stop);
+	outer_cache_flush_range(start, stop);
+}
+
+void dcache_enable(void)
+{
+	uint32_t sctlr;
+
+	sctlr = get_sctlr();
+
+	/* The data cache is not active unless the mmu is enabled too */
+	if (!(sctlr & CR_M)) {
+		outer_cache_enable();
+		invalidate_dcache_all();
+		__invalidate_tlb_all();
+
+		mmu_setup();
+	}
+
+	set_sctlr(sctlr | CR_C);
+}
+
+void dcache_disable(void)
+{
+	uint32_t sctlr;
+
+	sctlr = get_sctlr();
+
+	/* if cache isn't enabled no need to disable */
+	if (!(sctlr & CR_C))
+		return;
+
+	set_sctlr(sctlr & ~(CR_C|CR_M));
+
+	flush_dcache_all();
+	__invalidate_tlb_all();
+}
+
+int dcache_status(void)
+{
+	return (get_sctlr() & CR_C) != 0;
+}
+
+#else
+
+void invalidate_dcache_all(void)
+{
+}
+
+void flush_dcache_all(void)
+{
+}
+
+void invalidate_dcache_range(unsigned long start, unsigned long stop)
+{
+}
+
+void flush_dcache_range(unsigned long start, unsigned long stop)
+{
+}
+
+void dcache_enable(void)
+{
+}
+
+void dcache_disable(void)
+{
+}
+
+int dcache_status(void)
+{
+	return 0;
+}
+
+#endif /* CONFIG_SYS_DCACHE_OFF */
+
+/********************************************************************/
+
+#ifndef CONFIG_SYS_ICACHE_OFF
+
+void icache_enable(void)
+{
+	set_sctlr(get_sctlr() | CR_I);
+}
+
+void icache_disable(void)
+{
+	set_sctlr(get_sctlr() & ~CR_I);
+}
+
+int icache_status(void)
+{
+	return (get_sctlr() & CR_I) != 0;
+}
+
+void invalidate_icache_all(void)
+{
+	__invalidate_icache_all();
+}
+
+#else
+
+void icache_enable(void)
+{
+}
+
+void icache_disable(void)
+{
+}
+
+int icache_status(void)
+{
+	return 0;
+}
+
+void invalidate_icache_all(void)
+{
+}
+
+#endif /* CONFIG_SYS_ICACHE_OFF */
+
+/********************************************************************/
+
+/*
+ * Enable dCache & iCache, whether cache is actually enabled
+ * depend on CONFIG_SYS_DCACHE_OFF and CONFIG_SYS_ICACHE_OFF
+ */
+void enable_caches(void)
+{
+	icache_enable();
+	dcache_enable();
+}
+
+/*
+ * Flush range from all levels of d-cache/unified-cache used:
+ * Affects the range [start, start + size - 1]
+ */
+void flush_cache(unsigned long start, unsigned long size)
+{
+	flush_dcache_range(start, start + size);
+}
diff --git a/arch/arm64/lib/crt0.S b/arch/arm64/lib/crt0.S
new file mode 100644
index 0000000..d18a2dd
--- /dev/null
+++ b/arch/arm64/lib/crt0.S
@@ -0,0 +1,129 @@
+/*
+ * crt0 - C-runtime startup Code for ARM64 U-Boot
+ *
+ * Copyright (c) 2013  David Feng <fenghua at phytium.com.cn>
+ *
+ * Bsed on arm/lib/crt0.S by Albert ARIBAUD <albert.u.boot at aribaud.net>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <asm-offsets.h>
+#include <linux/linkage.h>
+
+/*
+ * This file handles the target-independent stages of the U-Boot
+ * start-up where a C runtime environment is needed. Its entry point
+ * is _main and is branched into from the target's start.S file.
+ *
+ * _main execution sequence is:
+ *
+ * 1. Set up initial environment for calling board_init_f().
+ *    This environment only provides a stack and a place to store
+ *    the GD ('global data') structure, both located in some readily
+ *    available RAM (SRAM, locked cache...). In this context, VARIABLE
+ *    global data, initialized or not (BSS), are UNAVAILABLE; only
+ *    CONSTANT initialized data are available.
+ *
+ * 2. Call board_init_f(). This function prepares the hardware for
+ *    execution from system RAM (DRAM, DDR...) As system RAM may not
+ *    be available yet, , board_init_f() must use the current GD to
+ *    store any data which must be passed on to later stages. These
+ *    data include the relocation destination, the future stack, and
+ *    the future GD location.
+ *
+ * (the following applies only to non-SPL builds)
+ *
+ * 3. Set up intermediate environment where the stack and GD are the
+ *    ones allocated by board_init_f() in system RAM, but BSS and
+ *    initialized non-const data are still not available.
+ *
+ * 4. Call relocate_code(). This function relocates U-Boot from its
+ *    current location into the relocation destination computed by
+ *    board_init_f().
+ *
+ * 5. Set up final environment for calling board_init_r(). This
+ *    environment has BSS (initialized to 0), initialized non-const
+ *    data (initialized to their intended value), and stack in system
+ *    RAM. GD has retained values set by board_init_f(). Some CPUs
+ *    have some work left to do at this point regarding memory, so
+ *    call c_runtime_cpu_setup.
+ *
+ * 6. Branch to board_init_r().
+ */
+
+ENTRY(_main)
+
+/*
+ * Set up initial C runtime environment and call board_init_f(0).
+ */
+	ldr	x0, =(CONFIG_SYS_INIT_SP_ADDR)
+	sub	x0, x0, #GD_SIZE	/* allocate one GD above SP */
+	bic	sp, x0, #0xf		/* 16-byte alignment for ABI compliance */
+	mov	x18, sp			/* GD is above SP */
+	mov	x0, #0
+	bl	board_init_f
+
+/*
+ * Set up intermediate environment (new sp and gd) and call
+ * relocate_code(addr_moni). Trick here is that we'll return
+ * 'here' but relocated.
+ */
+	ldr	x0, [x18, #GD_START_ADDR_SP]	/* x0 = gd->start_addr_sp */
+	bic	sp, x0, #0xf			/* 16-byte alignment for ABI compliance */
+	ldr	x18, [x18, #GD_BD]		/* x18 = gd->bd */
+	sub	x18, x18, #GD_SIZE		/* new GD is below bd */
+
+	adr	lr, relocation_return
+	ldr	x9, [x18, #GD_RELOC_OFF]	/* x0 = gd->reloc_off */
+	add	lr, lr, x9			/* new return address after relocation */
+	ldr	x0, [x18, #GD_RELOCADDR]	/* x0 = gd->relocaddr */
+	b	relocate_code
+
+relocation_return:
+
+/*
+ * Set up final (full) environment
+ */
+	bl	c_runtime_cpu_setup		/* we still call old routine here */
+
+/*
+ * Clear BSS section
+ */
+	ldr	x9, [x18, #GD_RELOC_OFF]	/* x9 = gd->reloc_off */
+	ldr	x0, =__bss_start		/* x0 = __bss_start in FLASH */
+	add	x0, x0, x9			/* x0 = __bss_start in RAM */
+	ldr	x1, =__bss_end			/* x1 = __bss_end in FLASH */
+	add	x1, x1, x9			/* x1 = __bss_end in RAM */
+	mov	x2, #0
+clear_loop:
+	str	x2, [x0]
+	add	x0, x0, #8
+	cmp	x0, x1
+	b.lo	clear_loop
+
+	/* call board_init_r(gd_t *id, ulong dest_addr) */
+	mov	x0, x18				/* gd_t */
+	ldr	x1, [x18, #GD_RELOCADDR]	/* dest_addr */
+	b	board_init_r			/* PC relative jump */
+
+	/* NOTREACHED - board_init_r() does not return */
+
+ENDPROC(_main)
diff --git a/arch/arm64/lib/interrupts.c b/arch/arm64/lib/interrupts.c
new file mode 100644
index 0000000..b843785
--- /dev/null
+++ b/arch/arm64/lib/interrupts.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2013	David Feng <fenghua at phytium.com.cn>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static const char *handler[]= {
+	"Synchronous Abort",
+	"IRQ",
+	"FIQ",
+	"Error"
+};
+
+#ifdef CONFIG_USE_IRQ
+int interrupt_init (void)
+{
+	return 0;
+}
+
+/* enable IRQ interrupts */
+void enable_interrupts (void)
+{
+}
+
+/*
+ * disable IRQ/FIQ interrupts
+ * returns true if interrupts had been enabled before we disabled them
+ */
+int disable_interrupts (void)
+{
+	return 0;
+}
+#else
+int interrupt_init (void)
+{
+	return 0;
+}
+
+void enable_interrupts (void)
+{
+	return;
+}
+int disable_interrupts (void)
+{
+	return 0;
+}
+#endif /* CONFIG_USE_IRQ */
+
+
+void show_regs (struct pt_regs *regs)
+{
+	int i;
+
+	printf("PC is at %lx\n", regs->pc);
+	printf("LR is at %lx\n", regs->regs[30]);
+	printf("PSTATE: %08lx\n", regs->pstate);
+	printf("SP : %lx\n", regs->sp);
+	for (i = 29; i >= 0; i--) {
+		printf("x%-2d: %016lx ", i, regs->regs[i]);
+		if (i % 2 == 0)
+			printf("\n");
+	}
+	printf("\n");
+}
+
+/*
+ * bad_mode handles the impossible case in the exception vector.
+ */
+void bad_mode(struct pt_regs *pt_regs, int reason, unsigned int esr)
+{
+#ifdef CONFIG_NEEDS_MANUAL_RELOC
+	static int relocated = 0;
+
+	/* relocate boot function table */
+	if (!relocated) {
+		int i;
+		for (i = 0; i < ARRAY_SIZE(handler); i++)
+			handler[i] += gd->reloc_off;
+		relocated = 1;
+	}
+#endif
+
+	printf("Bad mode in \"%s\" handler detected, esr 0x%08x\n",
+		handler[reason], esr);
+
+	show_regs(pt_regs);
+
+	panic("Resetting CPU ...\n");
+}
diff --git a/arch/arm64/lib/relocate.S b/arch/arm64/lib/relocate.S
new file mode 100644
index 0000000..6bbcc2a
--- /dev/null
+++ b/arch/arm64/lib/relocate.S
@@ -0,0 +1,72 @@
+/*
+ * relocate - common relocation function for ARM64 U-Boot
+ *
+ * Copyright (c) 2013	David Feng <fenghua at phytium.com.cn>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <asm-offsets.h>
+#include <config.h>
+#include <linux/linkage.h>
+
+/*
+ * void relocate_code (addr_moni)
+ *
+ * This function relocates the monitor code.
+ *
+ * NOTE:
+ * Currently, ld with -pie produce errors. So, GOT is used
+ * and configuration CONFIG_NEEDS_MANUAL_RELOC is needed.
+ */
+ENTRY(relocate_code)
+	/*
+	 * Copy u-boot from flash to RAM
+	 */
+	ldr	x1, =__image_copy_start	/* x1 <- copy source */
+	cmp	x1, x0
+	b.eq	relocate_done		/* skip relocation */
+	mov	x2, x0			/* x2 <- copy destination */
+	ldr	x3, =__image_copy_end	/* x3 <- source end address */
+
+copy_loop:
+	ldp	x10, x11, [x1], #16	/* copy from source address [x1] */
+	stp	x10, x11, [x2], #16	/* copy to   target address [x2] */
+	cmp	x1, x3			/* until source end address [x3] */
+	b.lo	copy_loop
+
+	/*
+	 * Fix .reloc relocations
+	 */
+	ldr	x9, [x18, #GD_RELOC_OFF]/* x9 <- relocation offset */
+	ldr	x1, =__rel_got_start	/* x1 <- rel got start ofs */
+	add	x1, x1, x9		/* x1 <- rel got start in RAM */
+	ldr	x2, =__rel_got_end	/* x2 <- rel got end ofs */
+	add	x2, x2, x9		/* x2 <- rel got end in RAM */
+fixloop:
+	ldr	x10, [x1]		/* x10 <- address to be fixed up */
+	add	x10, x10, x9		/* x10 <- address to be fixed up in RAM*/
+	str	x10, [x1]
+	add	x1, x1, #8		/* each gotn entry is 8 bytes */
+	cmp	x1, x2
+	b.lo	fixloop
+
+relocate_done:
+	ret
+ENDPROC(relocate_code)
diff --git a/arch/arm64/lib/reset.c b/arch/arm64/lib/reset.c
new file mode 100644
index 0000000..32de7a3
--- /dev/null
+++ b/arch/arm64/lib/reset.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2013	David Feng <fenghua at phytium.com.cn>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+
+int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	puts("Resetting system ...\n");
+
+	udelay(50000);		/* wait 50 ms */
+
+	disable_interrupts();
+
+	reset_cpu(0);
+
+	/*NOTREACHED*/
+	return 0;
+}
diff --git a/arch/arm64/lib/timer.c b/arch/arm64/lib/timer.c
new file mode 100644
index 0000000..8c0cfcb
--- /dev/null
+++ b/arch/arm64/lib/timer.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2013	David Feng <fenghua at phytium.com.cn>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <div64.h>
+
+/*
+ * Genertic Timer implementation of __udelay/get_timer/get_ticks/get_tbclk
+ * functions. If any other timers used, another implementation should be
+ * placed in platform code.
+ */
+
+static inline unsigned long tick_to_time(unsigned long tick)
+{
+	tick *= CONFIG_SYS_HZ;
+	do_div(tick, CONFIG_SYS_CNTFRQ);
+	return tick;
+}
+
+static inline unsigned long time_to_tick(unsigned long time)
+{
+	time *= CONFIG_SYS_CNTFRQ;
+	do_div(time, CONFIG_SYS_HZ);
+	return time;
+}
+
+/*
+ * Generic timer implementation of get_tbclk()
+ */
+ulong __get_tbclk (void)
+{
+	return CONFIG_SYS_HZ;
+}
+ulong get_tbclk(void)
+	__attribute__((weak, alias("__get_tbclk")));
+
+/*
+ * Generic timer implementation of get_timer()
+ */
+ulong __get_timer(ulong base)
+{
+	u64 cval;
+
+	isb();
+	asm volatile("mrs %0, cntpct_el0" : "=r" (cval));
+
+	tick_to_time(cval);
+
+	return tick_to_time(cval) - base;
+}
+ulong get_timer(ulong base)
+	__attribute__((weak, alias("__get_timer")));
+
+/*
+ * Generic timer implementation of get_ticks()
+ */
+unsigned long long __get_ticks(void)
+{
+	return get_timer(0);
+}
+unsigned long long get_ticks(void)
+	__attribute__((weak, alias("__get_ticks")));
+
+/*
+ * Generic timer implementation of __udelay()
+ */
+void ___udelay(ulong usec)
+{
+	unsigned long tmp;
+
+	tmp = get_ticks() + usec/1000;
+
+	while (get_ticks() < tmp);
+}
+void __udelay(ulong usec)
+	__attribute__((weak, alias("___udelay")));
-- 
1.7.9.5




More information about the U-Boot mailing list