[U-Boot] [Patch V3 1/4] [MIPS] Add support for MIPS64 cpus
Daniel Schwierzeck
daniel.schwierzeck at gmail.com
Fri Aug 24 02:22:25 CEST 2012
2012/8/20 Zhizhou Zhang <etou.zh at gmail.com>:
> 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)
with current master branch in git://git.denx.de/u-boot-mips.git you can drop the
endianess flags which are now handled in arch/mips/config.mk
> +
> +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;
> +}
currently we cannot use interrupts or setup any interrupt handlers in
u-boot-mips.
Please leave those functions empty.
> 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
calling a C function is not supposed to work here because no stack
pointer has been setup yet.
I checked with Sourcery 2011.09 and 2012.03. The stack is always
utilized in cache_probe.
Either you rewrite the cache_probe function in assembler or you use
the existing config options
and you could drop the cache probing.
> +
> +#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
>
--
Best regards,
Daniel
More information about the U-Boot
mailing list