From patchwork Wed Aug 14 10:58:06 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: fenghua@phytium.com.cn X-Patchwork-Id: 267096 X-Patchwork-Delegate: albert.aribaud@free.fr Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id 661442C0106 for ; Wed, 14 Aug 2013 20:59:27 +1000 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id D28C74A125; Wed, 14 Aug 2013 12:59:11 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id jfjCPvpiX2GT; Wed, 14 Aug 2013 12:59:11 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id E25FA4A12C; Wed, 14 Aug 2013 12:58:52 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 4EFE64A10F for ; Wed, 14 Aug 2013 12:58:43 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id G09CX-+tcSjd for ; Wed, 14 Aug 2013 12:58:40 +0200 (CEST) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from APP8.CORPEASE.NET (APP8.CORPEASE.NET [61.145.121.10]) by theia.denx.de (Postfix) with ESMTP id 8B67B4A114 for ; Wed, 14 Aug 2013 12:58:25 +0200 (CEST) Received: from localhost (unknown [222.247.182.112]) by app8.corpease.net (Coremail) with SMTP id CgGowHAbdAjIYgtSrnEFAA--.2065S2; Wed, 14 Aug 2013 18:58:16 +0800 (CST) From: fenghua@phytium.com.cn To: u-boot@lists.denx.de Date: Wed, 14 Aug 2013 18:58:06 +0800 Message-Id: <1376477887-30406-4-git-send-email-fenghua@phytium.com.cn> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1376477887-30406-1-git-send-email-fenghua@phytium.com.cn> References: <1376477887-30406-1-git-send-email-fenghua@phytium.com.cn> X-CM-TRANSID: CgGowHAbdAjIYgtSrnEFAA--.2065S2 X-Coremail-Antispam: 1UD129KBjvAXoWDAry8Zry8GrWfuF13ZrykGrg_yoWrAF1xCo WfCF4DXr1kKr98Jrs5GryqqFWUZF1Sgr43Jr1YyFs8J3WkXF1DKr1UKwsxXFySvr15C3s7 Zay3X3WfZFW7KF95n29KB7ZKAUJUUUUU529EdanIXcx71UUUUU7v73VFW2AGmfu7bjvjm3 AaLaJ3UjIYCTnIWjp_UUUYf7kC6x804xWl14x267AKxVWUJVW8JwAFc2x0x2IEx4CE42xK 8VAvwI8IcIk0rVWrJVCq3wAFIxvE14AKwVWUJVWUGwA2ocxC64kIII0Yj41l84x0c7CEw4 AK67xGY2AK021l84ACjcxK6xIIjxv20xvE14v26r1j6r1xM28EF7xvwVC0I7IYx2IY6xkF 7I0E14v26r4j6F4UM28EF7xvwVC2z280aVAFwI0_Jr0_Gr1l84ACjcxK6I8E87Iv6xkF7I 0E14v26r4j6r4UJwAS0I0E0xvYzxvE52x082IY62kv0487Mc02F40EFcxC0VAKzVAqx4xG 6I80ewAv7VC0I7IYx2IY67AKxVWUXVWUAwAv7VC2z280aVAFwI0_Jr0_Gr1lOx8S6xCaFV Cjc4AY6r1j6r4UM4x0Y48IcxkI7VAKI48JM4x0x7Aq67IIx4CEVc8vx2IErcIFxwAKzVCY 07xG64k0F24lc2xSY4AK67AK6r4DMxAIw28IcxkI7VAKI48JMxC20s026xCaFVCjc4AY6r 1j6r4UMI8I3I0E5I8CrVAFwI0_Jr0_Jr4lx2IqxVCjr7xvwVAFwI0_JrI_JrWlx4CE17CE b7AF67AKxVWUAVWUtwCIc40Y0x0EwIxGrwCI42IY6xIIjxv20xvE14v26r1j6r1xMIIF0x vE2Ix0cI8IcVCY1x0267AKxVW8JVWxJwCI42IY6xAIw20EY4v20xvaj40_Jr0_JF4lIxAI cVC2z280aVAFwI0_Jr0_Gr1lIxAIcVC2z280aVCY1x0267AKxVW8JVW8JrUvcSsGvfC2Kf nxnUUI43ZEXa7xR_UUUUUUUUU== X-Originating-IP: [222.247.182.112] X-CM-SenderInfo: pihqwxdxd61x51wl3zoofrzhdfq/ Cc: trini@ti.com, David Feng Subject: [U-Boot] [PATCH v2 3/4] arm64/lib support of arm64 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.11 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de From: David Feng 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 --- 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@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 + * + * (C) Copyright 2002-2006 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH + * Marius Groeger + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 + * - Added prep subcommand support + * - Reorganized source - modeled after powerpc version + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH + * Marius Groeger + * + * Copyright (C) 2001 Erik Mouw (J.A.K.Mouw@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 +#include +#include +#include +#include +#include +#include + + +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 + * + * 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 +#include +#include +#include + +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 + * + * Bsed on arm/lib/crt0.S by Albert ARIBAUD + * + * 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 +#include +#include + +/* + * 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 + * + * 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 + +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 + * + * 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 +#include +#include + +/* + * 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 + * + * 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 + +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 + * + * 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 +#include + +/* + * 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")));