[U-Boot] [Patch V3 1/4] [MIPS] Add support for MIPS64 cpus
Zhizhou Zhang
etou.zh at gmail.com
Mon Aug 20 16:22:23 CEST 2012
These files are derived from arch/mips/cpu/mips32/*. Howerver some
Changes are made:
*.S: changes ABI o32 to n64
config.mk: add mips64 building cflags
cpu.c: add cache size probe
interrupts.c: implement enable_interrupts and disable_interrupts
Signed-off-by: Zhizhou Zhang <etou.zh at gmail.com>
---
arch/mips/cpu/mips64/Makefile | 47 +++++++
arch/mips/cpu/mips64/config.mk | 39 ++++++
arch/mips/cpu/mips64/cpu.c | 124 ++++++++++++++++++
arch/mips/cpu/mips64/interrupts.c | 39 ++++++
arch/mips/cpu/mips64/start.S | 256 +++++++++++++++++++++++++++++++++++++
arch/mips/cpu/mips64/time.c | 86 +++++++++++++
6 files changed, 591 insertions(+)
create mode 100644 arch/mips/cpu/mips64/Makefile
create mode 100644 arch/mips/cpu/mips64/config.mk
create mode 100644 arch/mips/cpu/mips64/cpu.c
create mode 100644 arch/mips/cpu/mips64/interrupts.c
create mode 100644 arch/mips/cpu/mips64/start.S
create mode 100644 arch/mips/cpu/mips64/time.c
diff --git a/arch/mips/cpu/mips64/Makefile b/arch/mips/cpu/mips64/Makefile
new file mode 100644
index 0000000..335fe88
--- /dev/null
+++ b/arch/mips/cpu/mips64/Makefile
@@ -0,0 +1,47 @@
+#
+# (C) Copyright 2003-2006
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB = $(obj)lib$(CPU).o
+
+START = start.o
+COBJS-y = cpu.o interrupts.o time.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/config.mk b/arch/mips/cpu/mips64/config.mk
new file mode 100644
index 0000000..26f79e6
--- /dev/null
+++ b/arch/mips/cpu/mips64/config.mk
@@ -0,0 +1,39 @@
+#
+# (C) Copyright 2003
+# Wolfgang Denk, DENX Software Engineering, <wd at denx.de>
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+#
+# 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
+
+ENDIANNESS = -EL
+
+MIPSFLAGS += $(ENDIANNESS)
+
+PLATFORM_CPPFLAGS += $(MIPSFLAGS)
+PLATFORM_CPPFLAGS += -mabi=64 -DCONFIG_64BIT
+PLATFORM_LDFLAGS += -m elf64ltsmip
+
diff --git a/arch/mips/cpu/mips64/cpu.c b/arch/mips/cpu/mips64/cpu.c
new file mode 100644
index 0000000..348ccfe
--- /dev/null
+++ b/arch/mips/cpu/mips64/cpu.c
@@ -0,0 +1,124 @@
+/*
+ * (C) Copyright 2003
+ * Wolfgang Denk, DENX Software Engineering, <wd at denx.de>
+ * Zhi-zhou Zhang <etou.zh at gmail.com>
+ *
+ * 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>
+#include <linux/compiler.h>
+
+void __weak _machine_restart(void)
+{
+}
+
+int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ _machine_restart();
+
+ fprintf(stderr, "*** reset failed ***\n");
+ return 0;
+}
+
+static struct cache_desc icache, dcache;
+
+void cache_probe(void)
+{
+ int config, lsize;
+
+ config = read_c0_config1();
+ lsize = (config >> 19) & 7;
+ if (lsize) { /* icache present */
+ icache.linesz = 2 << lsize;
+ icache.sets = 32 << (((config >> 22) + 1) & 7);
+ icache.ways = 1 + ((config >> 16) & 7);
+ icache.size = icache.sets *
+ icache.ways *
+ icache.linesz;
+ }
+
+ lsize = (config >> 10) & 7;
+ if (lsize) { /* dcache present */
+ dcache.linesz = 2 << lsize;
+ dcache.sets = 32 << (((config >> 13) + 1) & 7);
+ dcache.ways = 1 + ((config >> 7) & 7);
+ dcache.size = dcache.sets *
+ dcache.ways *
+ dcache.linesz;
+ }
+}
+
+void flush_cache(ulong start_addr, ulong size)
+{
+ unsigned long addr, aend;
+
+ /* aend will be miscalculated when size is zero, so we return here */
+ if (size == 0)
+ return;
+
+ addr = start_addr & ~(icache.linesz - 1);
+ aend = (start_addr + size - 1) & ~(icache.linesz - 1);
+ while (1) {
+ cache_op(Hit_Invalidate_I, addr);
+ if (addr == aend)
+ break;
+ addr += icache.linesz;
+ }
+
+ addr = start_addr & ~(dcache.linesz - 1);
+ aend = (start_addr + size - 1) & ~(dcache.linesz - 1);
+ while (1) {
+ cache_op(Hit_Writeback_Inv_D, addr);
+ if (addr == aend)
+ break;
+ addr += dcache.linesz;
+ }
+}
+
+void flush_dcache_range(ulong start_addr, ulong stop)
+{
+ unsigned long addr = start_addr & ~(dcache.linesz - 1);
+ unsigned long aend = (stop - 1) & ~(dcache.linesz - 1);
+
+ while (1) {
+ cache_op(Hit_Writeback_Inv_D, addr);
+ if (addr == aend)
+ break;
+ addr += dcache.linesz;
+ }
+}
+
+void invalidate_dcache_range(ulong start_addr, ulong stop)
+{
+ unsigned long addr = start_addr & ~(dcache.linesz - 1);
+ unsigned long aend = (stop - 1) & ~(dcache.linesz - 1);
+
+ while (1) {
+ cache_op(Hit_Invalidate_D, addr);
+ if (addr == aend)
+ break;
+ addr += dcache.linesz;
+ }
+}
diff --git a/arch/mips/cpu/mips64/interrupts.c b/arch/mips/cpu/mips64/interrupts.c
new file mode 100644
index 0000000..f661fb0
--- /dev/null
+++ b/arch/mips/cpu/mips64/interrupts.c
@@ -0,0 +1,39 @@
+/*
+ * (C) Copyright 2003
+ * Wolfgang Denk, DENX Software Engineering, <wd at denx.de>
+ * Zhi-zhou Zhang <etou.zh at gmail.com>
+ *
+ * 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 status = read_c0_status();
+ write_c0_status(status | ST0_IE);
+}
+
+int disable_interrupts(void)
+{
+ int status = read_c0_status();
+ write_c0_status(status & ~ST0_IE);
+ return status | ST0_IE;
+}
diff --git a/arch/mips/cpu/mips64/start.S b/arch/mips/cpu/mips64/start.S
new file mode 100644
index 0000000..b8585e7
--- /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 at denx.de>
+ * Copyright (c) 2012 Zhi-zhou Zhang <etou.zh at gmail.com>
+ *
+ * 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 */
+ li t0, CONF_CM_UNCACHED
+ mtc0 t0, CP0_CONFIG
+#endif
+
+ /* Initialize $gp */
+ bal 1f
+ nop
+ .dword _gp
+1:
+ ld gp, 0(ra)
+
+ dla t9, cache_probe
+ jalr t9
+ nop
+
+#ifndef CONFIG_SKIP_LOWLEVEL_INIT
+ /* Initialize any external memory */
+ dla t9, lowlevel_init
+ jalr t9
+ nop
+
+ /* ... and enable them */
+ li t0, CONFIG_SYS_MIPS_CACHE_MODE
+ mtc0 t0, CP0_CONFIG
+#endif
+
+ /* Set up temporary stack */
+ li 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
+
+ li 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
+ li 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 0000000..350896a
--- /dev/null
+++ b/arch/mips/cpu/mips64/time.c
@@ -0,0 +1,86 @@
+/*
+ * (C) Copyright 2003
+ * Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <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;
+}
--
1.7.9.5
More information about the U-Boot
mailing list