diff options
author | Zhi-zhou Zhang | 2012-10-16 15:02:08 +0200 |
---|---|---|
committer | Daniel Schwierzeck | 2012-10-16 15:02:08 +0200 |
commit | 32afad783eb5a372c276fcb9fb30dfb838615909 (patch) | |
tree | 814d29b73e53e414ad1b80f752d2566de4715aeb /arch/mips/cpu | |
parent | ff9b0cb8b4804ed372c09b8aad2a984b396596b2 (diff) |
MIPS: add board qemu-mips64 support
Both big-endian and little-endian are tested with below commands:
Rom version: (Default, Now we config it as rom version)
qemu-system-mips64el -M mips -bios u-boot.bin -cpu MIPS64R2-generic -nographic
qemu-system-mips64 -M mips -bios u-boot.bin -cpu MIPS64R2-generic -nographic
Ram version:
qemu-system-mips64el -M mips -cpu MIPS64R2-generic -kernel u-boot -nographic
qemu-system-mips64 -M mips -cpu MIPS64R2-generic -kernel u-boot -nographic
Signed-off-by: Zhizhou Zhang <etou.zh@gmail.com>
Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
Diffstat (limited to 'arch/mips/cpu')
-rw-r--r-- | arch/mips/cpu/mips64/Makefile | 45 | ||||
-rw-r--r-- | arch/mips/cpu/mips64/cache.S | 229 | ||||
-rw-r--r-- | arch/mips/cpu/mips64/config.mk | 40 | ||||
-rw-r--r-- | arch/mips/cpu/mips64/cpu.c | 111 | ||||
-rw-r--r-- | arch/mips/cpu/mips64/interrupts.c | 34 | ||||
-rw-r--r-- | arch/mips/cpu/mips64/start.S | 256 | ||||
-rw-r--r-- | arch/mips/cpu/mips64/time.c | 87 |
7 files changed, 802 insertions, 0 deletions
diff --git a/arch/mips/cpu/mips64/Makefile b/arch/mips/cpu/mips64/Makefile new file mode 100644 index 00000000000..be38664844d --- /dev/null +++ b/arch/mips/cpu/mips64/Makefile @@ -0,0 +1,45 @@ +# +# (C) Copyright 2003-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$(CPU).o + +START = start.o +COBJS-y = cpu.o interrupts.o time.o cache.o + +SRCS := $(START:.o=.S) $(SOBJS-y:.o=.S) $(COBJS-y:.o=.c) +OBJS := $(addprefix $(obj),$(SOBJS-y) $(COBJS-y)) +START := $(addprefix $(obj),$(START)) + +all: $(obj).depend $(START) $(LIB) + +$(LIB): $(OBJS) + $(call cmd_link_o_target, $(OBJS)) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend diff --git a/arch/mips/cpu/mips64/cache.S b/arch/mips/cpu/mips64/cache.S new file mode 100644 index 00000000000..036f035d961 --- /dev/null +++ b/arch/mips/cpu/mips64/cache.S @@ -0,0 +1,229 @@ +/* + * Cache-handling routined for MIPS CPUs + * + * Copyright (c) 2003 Wolfgang Denk <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 <asm-offsets.h> +#include <config.h> +#include <asm/asm.h> +#include <asm/regdef.h> +#include <asm/mipsregs.h> +#include <asm/addrspace.h> +#include <asm/cacheops.h> + +#define RA t9 + +/* + * 16kB is the maximum size of instruction and data caches on MIPS 4K, + * 64kB is on 4KE, 24K, 5K, etc. Set bigger size for convenience. + * + * Note that the above size is the maximum size of primary cache. U-Boot + * doesn't have L2 cache support for now. + */ +#define MIPS_MAX_CACHE_SIZE 0x10000 + +#define INDEX_BASE CKSEG0 + + .macro cache_op op addr + .set push + .set noreorder + .set mips3 + cache \op, 0(\addr) + .set pop + .endm + + .macro f_fill64 dst, offset, val + LONG_S \val, (\offset + 0 * LONGSIZE)(\dst) + LONG_S \val, (\offset + 1 * LONGSIZE)(\dst) + LONG_S \val, (\offset + 2 * LONGSIZE)(\dst) + LONG_S \val, (\offset + 3 * LONGSIZE)(\dst) + LONG_S \val, (\offset + 4 * LONGSIZE)(\dst) + LONG_S \val, (\offset + 5 * LONGSIZE)(\dst) + LONG_S \val, (\offset + 6 * LONGSIZE)(\dst) + LONG_S \val, (\offset + 7 * LONGSIZE)(\dst) +#if LONGSIZE == 4 + LONG_S \val, (\offset + 8 * LONGSIZE)(\dst) + LONG_S \val, (\offset + 9 * LONGSIZE)(\dst) + LONG_S \val, (\offset + 10 * LONGSIZE)(\dst) + LONG_S \val, (\offset + 11 * LONGSIZE)(\dst) + LONG_S \val, (\offset + 12 * LONGSIZE)(\dst) + LONG_S \val, (\offset + 13 * LONGSIZE)(\dst) + LONG_S \val, (\offset + 14 * LONGSIZE)(\dst) + LONG_S \val, (\offset + 15 * LONGSIZE)(\dst) +#endif + .endm + +/* + * mips_init_icache(uint PRId, ulong icache_size, unchar icache_linesz) + */ +LEAF(mips_init_icache) + blez a1, 9f + mtc0 zero, CP0_TAGLO + /* clear tag to invalidate */ + PTR_LI t0, INDEX_BASE + PTR_ADDU t1, t0, a1 +1: cache_op INDEX_STORE_TAG_I t0 + PTR_ADDU t0, a2 + bne t0, t1, 1b + /* fill once, so data field parity is correct */ + PTR_LI t0, INDEX_BASE +2: cache_op FILL t0 + PTR_ADDU t0, a2 + bne t0, t1, 2b + /* invalidate again - prudent but not strictly neccessary */ + PTR_LI t0, INDEX_BASE +1: cache_op INDEX_STORE_TAG_I t0 + PTR_ADDU t0, a2 + bne t0, t1, 1b +9: jr ra + END(mips_init_icache) + +/* + * mips_init_dcache(uint PRId, ulong dcache_size, unchar dcache_linesz) + */ +LEAF(mips_init_dcache) + blez a1, 9f + mtc0 zero, CP0_TAGLO + /* clear all tags */ + PTR_LI t0, INDEX_BASE + PTR_ADDU t1, t0, a1 +1: cache_op INDEX_STORE_TAG_D t0 + PTR_ADDU t0, a2 + bne t0, t1, 1b + /* load from each line (in cached space) */ + PTR_LI t0, INDEX_BASE +2: LONG_L zero, 0(t0) + PTR_ADDU t0, a2 + bne t0, t1, 2b + /* clear all tags */ + PTR_LI t0, INDEX_BASE +1: cache_op INDEX_STORE_TAG_D t0 + PTR_ADDU t0, a2 + bne t0, t1, 1b +9: jr ra + END(mips_init_dcache) + +/* + * mips_cache_reset - low level initialisation of the primary caches + * + * This routine initialises the primary caches to ensure that they have good + * parity. It must be called by the ROM before any cached locations are used + * to prevent the possibility of data with bad parity being written to memory. + * + * To initialise the instruction cache it is essential that a source of data + * with good parity is available. This routine will initialise an area of + * memory starting at location zero to be used as a source of parity. + * + * RETURNS: N/A + * + */ +NESTED(mips_cache_reset, 0, ra) + move RA, ra + li t2, CONFIG_SYS_ICACHE_SIZE + li t3, CONFIG_SYS_DCACHE_SIZE + li t8, CONFIG_SYS_CACHELINE_SIZE + + li v0, MIPS_MAX_CACHE_SIZE + + /* + * Now clear that much memory starting from zero. + */ + PTR_LI a0, CKSEG1 + PTR_ADDU a1, a0, v0 +2: PTR_ADDIU a0, 64 + f_fill64 a0, -64, zero + bne a0, a1, 2b + + /* + * The caches are probably in an indeterminate state, + * so we force good parity into them by doing an + * invalidate, load/fill, invalidate for each line. + */ + + /* + * Assume bottom of RAM will generate good parity for the cache. + */ + + /* + * Initialize the I-cache first, + */ + move a1, t2 + move a2, t8 + PTR_LA v1, mips_init_icache + jalr v1 + + /* + * then initialize D-cache. + */ + move a1, t3 + move a2, t8 + PTR_LA v1, mips_init_dcache + jalr v1 + + jr RA + END(mips_cache_reset) + +/* + * dcache_status - get cache status + * + * RETURNS: 0 - cache disabled; 1 - cache enabled + * + */ +LEAF(dcache_status) + mfc0 t0, CP0_CONFIG + li t1, CONF_CM_UNCACHED + andi t0, t0, CONF_CM_CMASK + move v0, zero + beq t0, t1, 2f + li v0, 1 +2: jr ra + END(dcache_status) + +/* + * dcache_disable - disable cache + * + * RETURNS: N/A + * + */ +LEAF(dcache_disable) + mfc0 t0, CP0_CONFIG + li t1, -8 + and t0, t0, t1 + ori t0, t0, CONF_CM_UNCACHED + mtc0 t0, CP0_CONFIG + jr ra + END(dcache_disable) + +/* + * dcache_enable - enable cache + * + * RETURNS: N/A + * + */ +LEAF(dcache_enable) + mfc0 t0, CP0_CONFIG + ori t0, CONF_CM_CMASK + xori t0, CONF_CM_CMASK + ori t0, CONF_CM_CACHABLE_NONCOHERENT + mtc0 t0, CP0_CONFIG + jr ra + END(dcache_enable) diff --git a/arch/mips/cpu/mips64/config.mk b/arch/mips/cpu/mips64/config.mk new file mode 100644 index 00000000000..ebc1ceb83bf --- /dev/null +++ b/arch/mips/cpu/mips64/config.mk @@ -0,0 +1,40 @@ +# +# (C) Copyright 2003 +# 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 +# + +# +# Default optimization level for MIPS64 +# +# Note: Toolchains with binutils prior to v2.16 +# are no longer supported by U-Boot MIPS tree! +# +MIPSFLAGS = -march=mips64 + +PLATFORM_CPPFLAGS += $(MIPSFLAGS) +PLATFORM_CPPFLAGS += -mabi=64 -DCONFIG_64BIT +ifdef CONFIG_SYS_BIG_ENDIAN +PLATFORM_LDFLAGS += -m elf64btsmip +else +PLATFORM_LDFLAGS += -m elf64ltsmip +endif + +CONFIG_STANDALONE_LOAD_ADDR ?= 0xffffffff80200000 -T mips64.lds diff --git a/arch/mips/cpu/mips64/cpu.c b/arch/mips/cpu/mips64/cpu.c new file mode 100644 index 00000000000..2a38d0c8d09 --- /dev/null +++ b/arch/mips/cpu/mips64/cpu.c @@ -0,0 +1,111 @@ +/* + * (C) Copyright 2003 + * 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 <common.h> +#include <command.h> +#include <netdev.h> +#include <asm/mipsregs.h> +#include <asm/cacheops.h> +#include <asm/reboot.h> + +#define cache_op(op, addr) \ + __asm__ __volatile__( \ + " .set push\n" \ + " .set noreorder\n" \ + " .set mips64\n" \ + " cache %0, %1\n" \ + " .set pop\n" \ + : \ + : "i" (op), "R" (*(unsigned char *)(addr))) + +void __attribute__((weak)) _machine_restart(void) +{ + fprintf(stderr, "*** reset failed ***\n"); + + while (1) + /* NOP */; +} + +int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + _machine_restart(); + + return 0; +} + +void flush_cache(ulong start_addr, ulong size) +{ + unsigned long lsize = CONFIG_SYS_CACHELINE_SIZE; + unsigned long addr = start_addr & ~(lsize - 1); + unsigned long aend = (start_addr + size - 1) & ~(lsize - 1); + + /* aend will be miscalculated when size is zero, so we return here */ + if (size == 0) + return; + + while (1) { + cache_op(HIT_WRITEBACK_INV_D, addr); + cache_op(HIT_INVALIDATE_I, addr); + if (addr == aend) + break; + addr += lsize; + } +} + +void flush_dcache_range(ulong start_addr, ulong stop) +{ + unsigned long lsize = CONFIG_SYS_CACHELINE_SIZE; + unsigned long addr = start_addr & ~(lsize - 1); + unsigned long aend = (stop - 1) & ~(lsize - 1); + + while (1) { + cache_op(HIT_WRITEBACK_INV_D, addr); + if (addr == aend) + break; + addr += lsize; + } +} + +void invalidate_dcache_range(ulong start_addr, ulong stop) +{ + unsigned long lsize = CONFIG_SYS_CACHELINE_SIZE; + unsigned long addr = start_addr & ~(lsize - 1); + unsigned long aend = (stop - 1) & ~(lsize - 1); + + while (1) { + cache_op(HIT_INVALIDATE_D, addr); + if (addr == aend) + break; + addr += lsize; + } +} + +void write_one_tlb(int index, u32 pagemask, u32 hi, u32 low0, u32 low1) +{ + write_c0_entrylo0(low0); + write_c0_pagemask(pagemask); + write_c0_entrylo1(low1); + write_c0_entryhi(hi); + write_c0_index(index); + tlb_write_indexed(); +} diff --git a/arch/mips/cpu/mips64/interrupts.c b/arch/mips/cpu/mips64/interrupts.c new file mode 100644 index 00000000000..e4e9aae0cae --- /dev/null +++ b/arch/mips/cpu/mips64/interrupts.c @@ -0,0 +1,34 @@ +/* + * (C) Copyright 2003 + * 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 <common.h> +#include <asm/mipsregs.h> + +void enable_interrupts(void) +{ +} + +int disable_interrupts(void) +{ + return 0; +} diff --git a/arch/mips/cpu/mips64/start.S b/arch/mips/cpu/mips64/start.S new file mode 100644 index 00000000000..4112de7026a --- /dev/null +++ b/arch/mips/cpu/mips64/start.S @@ -0,0 +1,256 @@ +/* + * Startup Code for MIPS64 CPU-core + * + * Copyright (c) 2003 Wolfgang Denk <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 dlater 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 PARTICUdlaR 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 Pdlace, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <asm-offsets.h> +#include <config.h> +#include <asm/regdef.h> +#include <asm/mipsregs.h> + +#ifndef CONFIG_SYS_MIPS_CACHE_MODE +#define CONFIG_SYS_MIPS_CACHE_MODE CONF_CM_CACHABLE_NONCOHERENT +#endif + + /* + * For the moment disable interrupts, mark the kernel mode and + * set ST0_KX so that the CPU does not spit fire when using + * 64-bit addresses. + */ + .macro setup_c0_status set clr + .set push + mfc0 t0, CP0_STATUS + or t0, ST0_CU0 | \set | 0x1f | \clr + xor t0, 0x1f | \clr + mtc0 t0, CP0_STATUS + .set noreorder + sll zero, 3 # ehb + .set pop + .endm + + .set noreorder + + .globl _start + .text +_start: + .org 0x000 + b reset + nop + .org 0x080 + b romReserved + nop + .org 0x100 + b romReserved + nop + .org 0x180 + b romReserved + nop + .org 0x200 + b romReserved + nop + .org 0x280 + b romReserved + nop + .org 0x300 + b romReserved + nop + .org 0x380 + b romReserved + nop + .org 0x480 + b romReserved + nop + + /* + * We hope there are no more reserved vectors! + * 128 * 8 == 1024 == 0x400 + * so this is address R_VEC+0x400 == 0xbfc00400 + */ + .org 0x500 + .align 4 +reset: + + /* Clear watch registers */ + dmtc0 zero, CP0_WATCHLO + dmtc0 zero, CP0_WATCHHI + + /* WP(Watch Pending), SW0/1 should be cleared */ + mtc0 zero, CP0_CAUSE + + setup_c0_status ST0_KX 0 + + /* Init Timer */ + mtc0 zero, CP0_COUNT + mtc0 zero, CP0_COMPARE + +#ifndef CONFIG_SKIP_LOWLEVEL_INIT + /* CONFIG0 register */ + dli t0, CONF_CM_UNCACHED + mtc0 t0, CP0_CONFIG +#endif + + /* Initialize $gp */ + bal 1f + nop + .dword _gp +1: + ld gp, 0(ra) + +#ifndef CONFIG_SKIP_LOWLEVEL_INIT + /* Initialize any external memory */ + dla t9, lowlevel_init + jalr t9 + nop + + /* Initialize caches... */ + dla t9, mips_cache_reset + jalr t9 + nop + + /* ... and enable them */ + dli t0, CONFIG_SYS_MIPS_CACHE_MODE + mtc0 t0, CP0_CONFIG +#endif + + /* Set up temporary stack */ + dli t0, CONFIG_SYS_SDRAM_BASE + CONFIG_SYS_INIT_SP_OFFSET + dla sp, 0(t0) + + dla t9, board_init_f + jr t9 + nop + +/* + * void relocate_code (addr_sp, gd, addr_moni) + * + * This "function" does not return, instead it continues in RAM + * after relocating the monitor code. + * + * a0 = addr_sp + * a1 = gd + * a2 = destination address + */ + .globl relocate_code + .ent relocate_code +relocate_code: + move sp, a0 # set new stack pointer + + dli t0, CONFIG_SYS_MONITOR_BASE + dla t3, in_ram + ld t2, -24(t3) # t2 <-- uboot_end_data + move t1, a2 + move s2, a2 # s2 <-- destination address + + /* + * Fix $gp: + * + * New $gp = (Old $gp - CONFIG_SYS_MONITOR_BASE) + Destination Address + */ + move t8, gp + dsub gp, CONFIG_SYS_MONITOR_BASE + dadd gp, a2 # gp now adjusted + dsub s1, gp, t8 # s1 <-- relocation offset + + /* + * t0 = source address + * t1 = target address + * t2 = source end address + */ + + /* + * Save destination address and size for dlater usage in flush_cache() + */ + move s0, a1 # save gd in s0 + move a0, t1 # a0 <-- destination addr + dsub a1, t2, t0 # a1 <-- size + +1: + lw t3, 0(t0) + sw t3, 0(t1) + daddu t0, 4 + ble t0, t2, 1b + daddu t1, 4 + + /* If caches were enabled, we would have to flush them here. */ + + /* a0 & a1 are already set up for flush_cache(start, size) */ + dla t9, flush_cache + jalr t9 + nop + + /* Jump to where we've relocated ourselves */ + daddi t0, s2, in_ram - _start + jr t0 + nop + + .dword _gp + .dword _GLOBAL_OFFSET_TABLE_ + .dword uboot_end_data + .dword uboot_end + .dword num_got_entries + +in_ram: + /* + * Now we want to update GOT. + * + * GOT[0] is reserved. GOT[1] is also reserved for the dynamic object + * generated by GNU ld. Skip these reserved entries from relocation. + */ + ld t3, -8(t0) # t3 <-- num_got_entries + ld t8, -32(t0) # t8 <-- _GLOBAL_OFFSET_TABLE_ + ld t9, -40(t0) # t9 <-- _gp + dsub t8, t9 # compute offset + dadd t8, t8, gp # t8 now holds relocated _G_O_T_ + daddi t8, t8, 16 # skipping first two entries + dli t2, 2 +1: + ld t1, 0(t8) + beqz t1, 2f + dadd t1, s1 + sd t1, 0(t8) +2: + daddi t2, 1 + blt t2, t3, 1b + daddi t8, 8 + + /* Clear BSS */ + ld t1, -24(t0) # t1 <-- uboot_end_data + ld t2, -16(t0) # t2 <-- uboot_end + dadd t1, s1 # adjust pointers + dadd t2, s1 + + dsub t1, 8 +1: + daddi t1, 8 + bltl t1, t2, 1b + sd zero, 0(t1) + + move a0, s0 # a0 <-- gd + dla t9, board_init_r + jr t9 + move a1, s2 + + .end relocate_code + + /* Exception handlers */ +romReserved: + b romReserved diff --git a/arch/mips/cpu/mips64/time.c b/arch/mips/cpu/mips64/time.c new file mode 100644 index 00000000000..51542808dd6 --- /dev/null +++ b/arch/mips/cpu/mips64/time.c @@ -0,0 +1,87 @@ +/* + * (C) Copyright 2003 + * 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 <common.h> +#include <asm/mipsregs.h> + +static unsigned long timestamp; + +/* how many counter cycles in a jiffy */ +#define CYCLES_PER_JIFFY \ + (CONFIG_SYS_MIPS_TIMER_FREQ + CONFIG_SYS_HZ / 2) / CONFIG_SYS_HZ + +/* + * timer without interrupts + */ + +int timer_init(void) +{ + /* Set up the timer for the first expiration. */ + timestamp = 0; + write_c0_compare(read_c0_count() + CYCLES_PER_JIFFY); + + return 0; +} + +ulong get_timer(ulong base) +{ + unsigned int count; + unsigned int expirelo = read_c0_compare(); + + /* Check to see if we have missed any timestamps. */ + count = read_c0_count(); + while ((count - expirelo) < 0x7fffffff) { + expirelo += CYCLES_PER_JIFFY; + timestamp++; + } + write_c0_compare(expirelo); + + return timestamp - base; +} + +void __udelay(unsigned long usec) +{ + unsigned int tmo; + + tmo = read_c0_count() + (usec * (CONFIG_SYS_MIPS_TIMER_FREQ / 1000000)); + while ((tmo - read_c0_count()) < 0x7fffffff) + /*NOP*/; +} + +/* + * This function is derived from PowerPC code (read timebase as long long). + * On MIPS it just returns the timer value. + */ +unsigned long long get_ticks(void) +{ + return get_timer(0); +} + +/* + * This function is derived from PowerPC code (timebase clock frequency). + * On MIPS it returns the number of timer ticks per second. + */ +ulong get_tbclk(void) +{ + return CONFIG_SYS_HZ; +} |