From: David Feng <feng...@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 <feng...@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, w...@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 <feng...@phytium.com.cn>
+ *
+ * (C) Copyright 2002-2006
+ * Wolfgang Denk, DENX Software Engineering, w...@denx.de.
+ *
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroe...@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 <schw...@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 <mgroe...@sysgo.de>
+ *
+ * Copyright (C) 2001  Erik Mouw (j.a.k.m...@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 <feng...@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 <feng...@phytium.com.cn>
+ *
+ * Bsed on arm/lib/crt0.S by Albert ARIBAUD <albert.u.b...@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 <feng...@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 <feng...@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 <feng...@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 <feng...@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


_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to