diff mbox

[U-Boot,3/9] openrisc: Add cpu files

Message ID 1321680098-31121-4-git-send-email-stefan.kristiansson@saunalahti.fi
State Superseded
Headers show

Commit Message

Stefan Kristiansson Nov. 19, 2011, 5:21 a.m. UTC
Signed-off-by: Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
---
 arch/openrisc/config.mk        |   27 ++++
 arch/openrisc/cpu/Makefile     |   47 ++++++
 arch/openrisc/cpu/cache.c      |  157 +++++++++++++++++++
 arch/openrisc/cpu/cpu.c        |  157 +++++++++++++++++++
 arch/openrisc/cpu/exceptions.c |  109 +++++++++++++
 arch/openrisc/cpu/interrupts.c |  120 ++++++++++++++
 arch/openrisc/cpu/start.S      |  335 ++++++++++++++++++++++++++++++++++++++++
 7 files changed, 952 insertions(+), 0 deletions(-)
 create mode 100644 arch/openrisc/config.mk
 create mode 100644 arch/openrisc/cpu/Makefile
 create mode 100644 arch/openrisc/cpu/cache.c
 create mode 100644 arch/openrisc/cpu/cpu.c
 create mode 100644 arch/openrisc/cpu/exceptions.c
 create mode 100644 arch/openrisc/cpu/interrupts.c
 create mode 100644 arch/openrisc/cpu/start.S

Comments

Mike Frysinger Nov. 19, 2011, 5:59 a.m. UTC | #1
On Saturday 19 November 2011 00:21:32 Stefan Kristiansson wrote:
> --- /dev/null
> +++ b/arch/openrisc/config.mk
>
> \ No newline at end of file

might want to fix that

> --- /dev/null
> +++ b/arch/openrisc/cpu/cache.c
>
> +int checkicache(void)
> +int checkdcache(void)

these should be static

> +void dcache_enable(void)
> +{
> +	mtspr(SPR_SR, mfspr(SPR_SR) | SPR_SR_DCE);
> +	asm("l.nop");
> +	asm("l.nop");
> +	asm("l.nop");
> +	asm("l.nop");
> +	asm("l.nop");
> +	asm("l.nop");
> +	asm("l.nop");
> +	asm("l.nop");
> +}
> +
> +void icache_enable(void)
> +{
> +	mtspr(SPR_SR, mfspr(SPR_SR) | SPR_SR_ICE);
> +	asm("l.nop");
> +	asm("l.nop");
> +	asm("l.nop");
> +	asm("l.nop");
> +	asm("l.nop");
> +	asm("l.nop");
> +	asm("l.nop");
> +	asm("l.nop");
> +}

the lack of volatile and the lack of any sort of constraints means gcc is free 
to throw that away ...

> --- /dev/null
> +++ b/arch/openrisc/cpu/cpu.c
>
> +void illegal_instruction_handler(void)
> +void checkinstructions(void)
> +int checkcpu(void)

looks like these should be static

> +extern void __reset(void);
> +
> +int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
> +{
> +	disable_interrupts();
> +	__reset();
> +	return 0;
> +}

__reset() should not return

> --- /dev/null
> +++ b/arch/openrisc/cpu/exceptions.c
>
> +extern void hang(void);

common.h already has a prototype for this; delete it.

> +static void exception_hang(int vect)
> +{
> +	printf("Unhandled exception at 0x%x ", vect & 0xff00);
> +	switch (vect & 0xff00) {
> +	case 0x100:
> +		puts("(Reset)\n");
> +		break;
> +	case 0x200:
> +		puts("(Bus Error)\n");
> +		break;
> +	case 0x300:
> +		puts("(Data Page Fault)\n");
> +		break;
> +	case 0x400:
> +		puts("(Instruction Page Fault)\n");
> +		break;
> +	case 0x500:
> +		puts("(Tick Timer)\n");
> +		break;
> +	case 0x600:
> +		puts("(Alignment)\n");
> +		break;
> +	case 0x700:
> +		puts("(Illegal Instruction)\n");
> +		break;
> +	case 0x800:
> +		puts("(External Interrupt)\n");
> +		break;
> +	case 0x900:
> +		puts("(D-TLB Miss)\n");
> +		break;
> +	case 0xa00:
> +		puts("(I-TLB Miss)\n");
> +		break;
> +	case 0xb00:
> +		puts("(Range)\n");
> +		break;
> +	case 0xc00:
> +		puts("(System Call)\n");
> +		break;
> +	case 0xd00:
> +		puts("(Floating Point)\n");
> +		break;
> +	case 0xe00:
> +		puts("(Trap)\n");
> +		break;
> +	default:
> +		puts("(Unknown exception)\n");
> +		break;
> +	}

looks like this could easily be a table string lookup:
static const char * const excp_table[] = {
	"Reset",
	"Bus Error",
	...
};
printf("(%s)\n", excp_table[(vect >> 16) & 0xff]);

> --- /dev/null
> +++ b/arch/openrisc/cpu/interrupts.c
>
> +#include <asm/types.h>
> +#include <asm/ptrace.h>
> +#include <asm/system.h>
> +#include <asm/openrisc_exc.h>
> +#include <common.h>

asm/ includes should come after non-asm/ includes
-mike
Stefan Kristiansson Nov. 20, 2011, 4:27 a.m. UTC | #2
On Sat, Nov 19, 2011 at 12:59:05AM -0500, Mike Frysinger wrote:
> On Saturday 19 November 2011 00:21:32 Stefan Kristiansson wrote:
> > --- /dev/null
> > +++ b/arch/openrisc/cpu/cache.c
> >
> > +int checkicache(void)
> > +int checkdcache(void)
> 
> these should be static
> 
> > --- /dev/null
> > +++ b/arch/openrisc/cpu/cpu.c
> >
> > +int checkcpu(void)
> 
> looks like these should be static
> 

They are declared in common.h and are used outside their file scope.

Stefan
Mike Frysinger Nov. 20, 2011, 5:27 a.m. UTC | #3
On Saturday 19 November 2011 23:27:34 Stefan Kristiansson wrote:
> On Sat, Nov 19, 2011 at 12:59:05AM -0500, Mike Frysinger wrote:
> > On Saturday 19 November 2011 00:21:32 Stefan Kristiansson wrote:
> > > --- /dev/null
> > > +++ b/arch/openrisc/cpu/cache.c
> > > 
> > > +int checkicache(void)
> > > +int checkdcache(void)
> > 
> > these should be static
> > 
> > > --- /dev/null
> > > +++ b/arch/openrisc/cpu/cpu.c
> > > 
> > > +int checkcpu(void)
> > 
> > looks like these should be static
> 
> They are declared in common.h and are used outside their file scope.

indeed.  looks like ppc warts that infected common code.
-mike
Marek Vasut Nov. 21, 2011, 10:50 p.m. UTC | #4
> Signed-off-by: Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
> ---
>  arch/openrisc/config.mk        |   27 ++++
>  arch/openrisc/cpu/Makefile     |   47 ++++++
>  arch/openrisc/cpu/cache.c      |  157 +++++++++++++++++++
>  arch/openrisc/cpu/cpu.c        |  157 +++++++++++++++++++
>  arch/openrisc/cpu/exceptions.c |  109 +++++++++++++
>  arch/openrisc/cpu/interrupts.c |  120 ++++++++++++++
>  arch/openrisc/cpu/start.S      |  335
> ++++++++++++++++++++++++++++++++++++++++ 7 files changed, 952
> insertions(+), 0 deletions(-)
>  create mode 100644 arch/openrisc/config.mk
>  create mode 100644 arch/openrisc/cpu/Makefile
>  create mode 100644 arch/openrisc/cpu/cache.c
>  create mode 100644 arch/openrisc/cpu/cpu.c
>  create mode 100644 arch/openrisc/cpu/exceptions.c
>  create mode 100644 arch/openrisc/cpu/interrupts.c
>  create mode 100644 arch/openrisc/cpu/start.S
> 
> diff --git a/arch/openrisc/config.mk b/arch/openrisc/config.mk
> new file mode 100644
> index 0000000..bea3d12
> --- /dev/null
> +++ b/arch/openrisc/config.mk
> @@ -0,0 +1,27 @@
> +#
> +# (C) Copyright 2011
> +# Julius Baxter <julius@opencores.org>
> +#
> +# 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
> +#
> +
> +CROSS_COMPILE ?= or32-elf-
> +
> +# r10 used for global object pointer, already set in OR32 GCC but just to
> be +# clear
> +PLATFORM_CPPFLAGS += -DCONFIG_OPENRISC -D__OR1K__ -ffixed-r10
> +
> +CONFIG_STANDALONE_LOAD_ADDR ?= 0x40000
> \ No newline at end of file
> diff --git a/arch/openrisc/cpu/Makefile b/arch/openrisc/cpu/Makefile
> new file mode 100644
> index 0000000..b3b1a24
> --- /dev/null
> +++ b/arch/openrisc/cpu/Makefile
> @@ -0,0 +1,47 @@
> +#
> +# (C) Copyright 2011
> +# Julius Baxter <julius@opencores.org>
> +#
> +# 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	= cache.o cpu.o exceptions.o interrupts.o
> +
> +SRCS	:= $(START:.o=.S) $(COBJS-y:.o=.c)
> +OBJS	:= $(addprefix $(obj),$(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/openrisc/cpu/cache.c b/arch/openrisc/cpu/cache.c
> new file mode 100644
> index 0000000..9dd627f
> --- /dev/null
> +++ b/arch/openrisc/cpu/cache.c
> @@ -0,0 +1,157 @@
> +/*
> + * (C) Copyright 2011, Stefan Kristiansson
> <stefan.kristiansson@saunalahti.fi> + * (C) Copyright 2011, Julius Baxter
> <julius@opencores.org>
> + *
> + * 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/system.h>
> +#include <common.h>
> +
> +/* cache line size can be either 16 or 32 bytes */
> +static inline unsigned long get_linesize(void)
> +{
> +	return (mfspr(SPR_ICCFGR) & SPR_ICCFGR_CBS) ? 32 : 16;

What's mfspr ... if it's some register, then maybe mfspr_read() ?

> +}
> +
> +void flush_dcache_range(unsigned long addr, unsigned long stop)
> +{
> +	unsigned long linesize = get_linesize();
> +
> +	while (addr < stop) {
> +		mtspr(SPR_DCBFR, addr);
> +		addr += linesize;
> +	}
> +}
> +
> +void invalidate_dcache_range(unsigned long addr, unsigned long stop)
> +{
> +	unsigned long linesize = get_linesize();
> +
> +	while (addr < stop) {
> +		mtspr(SPR_DCBIR, addr);
> +		addr += linesize;
> +	}
> +}
> +
> +static void invalidate_icache_range(unsigned long addr, unsigned long
> stop) +{
> +	unsigned long linesize = get_linesize();
> +
> +	while (addr < stop) {
> +		mtspr(SPR_ICBIR, addr);
> +		addr += linesize;
> +	}
> +}
> +
> +void flush_cache(unsigned long addr, unsigned long size)
> +{
> +	flush_dcache_range(addr, addr + size);
> +	invalidate_icache_range(addr, addr + size);
> +}
> +
> +int icache_status(void)
> +{
> +	return mfspr(SPR_SR) & SPR_SR_ICE;
> +}
> +
> +int checkicache(void)
> +{
> +	unsigned long iccfgr;
> +	unsigned long cache_set_size;
> +	unsigned long cache_ways;
> +	unsigned long cache_block_size;
> +
> +	iccfgr = mfspr(SPR_ICCFGR);
> +	cache_ways = 1 << (iccfgr & SPR_ICCFGR_NCW);
> +	cache_set_size = 1 << ((iccfgr & SPR_ICCFGR_NCS) >> 3);
> +	cache_block_size = (iccfgr & SPR_ICCFGR_CBS) ? 32 : 16;
> +
> +	return cache_set_size * cache_ways * cache_block_size;
> +}
> +
> +int dcache_status(void)
> +{
> +	return mfspr(SPR_SR) & SPR_SR_DCE;
> +}
> +
> +int checkdcache(void)
> +{
> +	unsigned long dccfgr;
> +	unsigned long cache_set_size;
> +	unsigned long cache_ways;
> +	unsigned long cache_block_size;
> +
> +	dccfgr = mfspr(SPR_DCCFGR);
> +	cache_ways = 1 << (dccfgr & SPR_DCCFGR_NCW);
> +	cache_set_size = 1 << ((dccfgr & SPR_DCCFGR_NCS) >> 3);
> +	cache_block_size = (dccfgr & SPR_DCCFGR_CBS) ? 32 : 16;
> +
> +	return cache_set_size * cache_ways * cache_block_size;
> +}
> +
> +void dcache_enable(void)
> +{
> +	mtspr(SPR_SR, mfspr(SPR_SR) | SPR_SR_DCE);
> +	asm("l.nop");
> +	asm("l.nop");
> +	asm("l.nop");
> +	asm("l.nop");
> +	asm("l.nop");
> +	asm("l.nop");
> +	asm("l.nop");
> +	asm("l.nop");
> +}
> +
> +void dcache_disable(void)
> +{
> +	mtspr(SPR_SR, mfspr(SPR_SR) & ~SPR_SR_DCE);
> +}
> +
> +void icache_enable(void)
> +{
> +	mtspr(SPR_SR, mfspr(SPR_SR) | SPR_SR_ICE);
> +	asm("l.nop");
> +	asm("l.nop");
> +	asm("l.nop");
> +	asm("l.nop");
> +	asm("l.nop");
> +	asm("l.nop");
> +	asm("l.nop");
> +	asm("l.nop");

Hm, maybe mtspr and those nops together need some ordering ?

> +}
> +
> +void icache_disable(void)
> +{
> +	mtspr(SPR_SR, mfspr(SPR_SR) & ~SPR_SR_ICE);
> +}
> +
> +int cache_init(void)
> +{
> +	if (mfspr(SPR_UPR) & SPR_UPR_ICP) {
> +		icache_disable();
> +		invalidate_icache_range(0, checkicache());
> +		icache_enable();
> +	}
> +
> +	if (mfspr(SPR_UPR) & SPR_UPR_DCP) {
> +		dcache_disable();
> +		invalidate_dcache_range(0, checkdcache());
> +		dcache_enable();
> +	}
> +
> +	return 0;
> +}
> diff --git a/arch/openrisc/cpu/cpu.c b/arch/openrisc/cpu/cpu.c
> new file mode 100644
> index 0000000..3b69285
> --- /dev/null
> +++ b/arch/openrisc/cpu/cpu.c
> @@ -0,0 +1,157 @@
> +/*
> + * (C) Copyright 2011, Stefan Kristiansson
> <stefan.kristiansson@saunalahti.fi> + * (C) Copyright 2011, Julius Baxter
> <julius@opencores.org>
> + *
> + * 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/system.h>
> +#include <asm/openrisc_exc.h>
> +#include <common.h>
> +
> +static volatile int illegal_instruction;
> +
> +void illegal_instruction_handler(void)
> +{
> +	ulong *epcr = (ulong *)mfspr(SPR_EPCR_BASE);
> +
> +	/* skip over the illegal instruction */
> +	mtspr(SPR_EPCR_BASE, (ulong)(++epcr));
> +	illegal_instruction = 1;
> +}
> +
> +void checkinstructions(void)
> +{
> +	ulong ra = 1, rb = 1, rc;
> +
> +	exception_install_handler(EXC_ILLEGAL_INSTR,
> +				illegal_instruction_handler);
> +
> +	illegal_instruction = 0;
> +	asm volatile("l.mul %0,%1,%2" : "=r" (rc) : "r" (ra), "r" (rb));
> +	printf("           Hardware multiplier: %s\n",
> +		illegal_instruction ? "no" : "yes");
> +
> +	illegal_instruction = 0;
> +	asm volatile("l.div %0,%1,%2" : "=r" (rc) : "r" (ra), "r" (rb));
> +	printf("           Hardware divider: %s\n",
> +		illegal_instruction ? "no" : "yes");
> +
> +	exception_free_handler(EXC_ILLEGAL_INSTR);
> +
> +}
> +
> +int checkcpu(void)
> +{
> +	ulong upr = mfspr(SPR_UPR);
> +	ulong vr = mfspr(SPR_VR);
> +	ulong iccfgr = mfspr(SPR_ICCFGR);
> +	ulong dccfgr = mfspr(SPR_DCCFGR);
> +	ulong immucfgr = mfspr(SPR_IMMUCFGR);
> +	ulong dmmucfgr = mfspr(SPR_DMMUCFGR);
> +	ulong cpucfgr = mfspr(SPR_CPUCFGR);
> +	uint ver = (vr & SPR_VR_VER) >> 24;
> +	uint rev = vr & SPR_VR_REV;
> +	uint block_size;
> +	uint ways;
> +	uint sets;
> +
> +	printf("CPU:   OpenRISC-%x00 (rev %d) @ %d MHz\n",
> +		ver, rev, (CONFIG_SYS_CLK_FREQ / 1000000));

The CPU won't tell you it's speed ?

> +
> +	if (upr & SPR_UPR_DCP) {
> +		block_size = (dccfgr & SPR_DCCFGR_CBS) ? 32 : 16;
> +		ways = 1 << (dccfgr & SPR_DCCFGR_NCW);
> +		printf("       D-Cache: %d bytes, %d bytes/line, %d way(s)\n",
> +		       checkdcache(), block_size, ways);
> +	} else {
> +		printf("       D-Cache: no\n");
> +	}
> +
> +	if (upr & SPR_UPR_ICP) {
> +		block_size = (iccfgr & SPR_ICCFGR_CBS) ? 32 : 16;
> +		ways = 1 << (iccfgr & SPR_ICCFGR_NCW);
> +		printf("       I-Cache: %d bytes, %d bytes/line, %d way(s)\n",
> +		       checkicache(), block_size, ways);
> +	} else {
> +		printf("       I-Cache: no\n");
> +	}
> +
> +	if (upr & SPR_UPR_DMP) {
> +		sets = 1 << ((dmmucfgr & SPR_DMMUCFGR_NTS) >> 2);
> +		ways = (dmmucfgr & SPR_DMMUCFGR_NTW) + 1;
> +		printf("       DMMU: %d sets, %d way(s)\n",
> +		       sets, ways);
> +	} else {
> +		printf("       DMMU: no\n");
> +	}
> +
> +	if (upr & SPR_UPR_IMP) {
> +		sets = 1 << ((immucfgr & SPR_IMMUCFGR_NTS) >> 2);
> +		ways = (immucfgr & SPR_IMMUCFGR_NTW) + 1;
> +		printf("       IMMU: %d sets, %d way(s)\n",
> +		       sets, ways);
> +	} else {
> +		printf("       IMMU: no\n");
> +	}
> +
> +	printf("       MAC unit: %s\n",
> +		(upr & SPR_UPR_MP) ? "yes" : "no");
> +	printf("       Debug unit: %s\n",
> +		(upr & SPR_UPR_DUP) ? "yes" : "no");
> +	printf("       Performance counters: %s\n",
> +		(upr & SPR_UPR_PCUP) ? "yes" : "no");
> +	printf("       Power management: %s\n",
> +		(upr & SPR_UPR_PMP) ? "yes" : "no");
> +	printf("       Interrupt controller: %s\n",
> +		(upr & SPR_UPR_PICP) ? "yes" : "no");
> +	printf("       Timer: %s\n",
> +		(upr & SPR_UPR_TTP) ? "yes" : "no");
> +	printf("       Custom unit(s): %s\n",
> +		(upr & SPR_UPR_CUP) ? "yes" : "no");
> +
> +	printf("       Supported instructions:\n");
> +	printf("           ORBIS32: %s\n",
> +		(cpucfgr & SPR_CPUCFGR_OB32S) ? "yes" : "no");
> +	printf("           ORBIS64: %s\n",
> +		(cpucfgr & SPR_CPUCFGR_OB64S) ? "yes" : "no");
> +	printf("           ORFPX32: %s\n",
> +		(cpucfgr & SPR_CPUCFGR_OF32S) ? "yes" : "no");
> +	printf("           ORFPX64: %s\n",
> +		(cpucfgr & SPR_CPUCFGR_OF64S) ? "yes" : "no");
> +
> +	checkinstructions();
> +
> +	return 0;
> +}
> +
> +int cleanup_before_linux(void)
> +{
> +	disable_interrupts();
> +	return 0;
> +}
> +
> +extern void __reset(void);
> +
> +int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
> +{
> +	disable_interrupts();
> +	__reset();
> +	return 0;
> +}
> diff --git a/arch/openrisc/cpu/exceptions.c
> b/arch/openrisc/cpu/exceptions.c new file mode 100644
> index 0000000..06935be
> --- /dev/null
> +++ b/arch/openrisc/cpu/exceptions.c
> @@ -0,0 +1,109 @@
> +/*
> + * (C) Copyright 2011, Stefan Kristiansson
> <stefan.kristiansson@saunalahti.fi> + * (C) Copyright 2011, Julius Baxter
> <julius@opencores.org>
> + *
> + * 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/system.h>
> +#include <common.h>
> +#include <stdio_dev.h>
> +
> +extern void hang(void);
> +
> +static void (*handlers[32])(void);
> +
> +void exception_install_handler(int exception, void (*handler)(void))
> +{
> +	if (exception < 0 || exception > 31)
> +		return;
> +
> +	handlers[exception] = handler;
> +}
> +
> +void exception_free_handler(int exception)
> +{
> +	if (exception < 0 || exception > 31)
> +		return;
> +
> +	handlers[exception] = 0;
> +}
> +
> +static void exception_hang(int vect)
> +{
> +	printf("Unhandled exception at 0x%x ", vect & 0xff00);
> +	switch (vect & 0xff00) {
> +	case 0x100:
> +		puts("(Reset)\n");
> +		break;
> +	case 0x200:
> +		puts("(Bus Error)\n");
> +		break;
> +	case 0x300:
> +		puts("(Data Page Fault)\n");
> +		break;
> +	case 0x400:
> +		puts("(Instruction Page Fault)\n");
> +		break;
> +	case 0x500:
> +		puts("(Tick Timer)\n");
> +		break;
> +	case 0x600:
> +		puts("(Alignment)\n");
> +		break;
> +	case 0x700:
> +		puts("(Illegal Instruction)\n");
> +		break;
> +	case 0x800:
> +		puts("(External Interrupt)\n");
> +		break;
> +	case 0x900:
> +		puts("(D-TLB Miss)\n");
> +		break;
> +	case 0xa00:
> +		puts("(I-TLB Miss)\n");
> +		break;
> +	case 0xb00:
> +		puts("(Range)\n");
> +		break;
> +	case 0xc00:
> +		puts("(System Call)\n");
> +		break;
> +	case 0xd00:
> +		puts("(Floating Point)\n");
> +		break;
> +	case 0xe00:
> +		puts("(Trap)\n");
> +		break;
> +	default:
> +		puts("(Unknown exception)\n");
> +		break;
> +	}
> +	printf("EPCR: 0x%08lx\n", mfspr(SPR_EPCR_BASE));
> +	printf("EEAR: 0x%08lx\n", mfspr(SPR_EEAR_BASE));
> +	printf("ESR:  0x%08lx\n", mfspr(SPR_ESR_BASE));
> +	hang();
> +}
> +
> +void exception_handler(int vect)
> +{
> +	int exception = vect >> 8;
> +
> +	if (handlers[exception])
> +		handlers[exception]();
> +	else
> +		exception_hang(vect);
> +}
> diff --git a/arch/openrisc/cpu/interrupts.c
> b/arch/openrisc/cpu/interrupts.c new file mode 100644
> index 0000000..62d266a
> --- /dev/null
> +++ b/arch/openrisc/cpu/interrupts.c
> @@ -0,0 +1,120 @@
> +/*
> + * (C) Copyright 2011, Stefan Kristiansson
> <stefan.kristiansson@saunalahti.fi> + * (C) Copyright 2011, Julius Baxter
> <julius@opencores.org>
> + *
> + * 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/types.h>
> +#include <asm/ptrace.h>
> +#include <asm/system.h>
> +#include <asm/openrisc_exc.h>
> +#include <common.h>
> +
> +struct irq_action {
> +	interrupt_handler_t *handler;
> +	void *arg;
> +	int count;
> +};
> +
> +static struct irq_action handlers[32];
> +
> +void interrupt_handler(void)
> +{
> +	int irq;
> +
> +	while ((irq = ffs(mfspr(SPR_PICSR)))) {
> +		if (handlers[--irq].handler) {
> +			handlers[irq].handler(handlers[irq].arg);
> +			handlers[irq].count++;
> +		} else {
> +			/* disable the interrupt */
> +			mtspr(SPR_PICMR, mfspr(SPR_PICMR) & ~(1 << irq));
> +			printf("Unhandled interrupt: %d\n", irq);
> +		}
> +		/* clear the interrupt */
> +		mtspr(SPR_PICSR, mfspr(SPR_PICSR) & ~(1 << irq));
> +	}
> +}
> +
> +int interrupt_init(void)
> +{
> +	/* install handler for external interrupt exception */
> +	exception_install_handler(EXC_EXT_IRQ, interrupt_handler);
> +	/* Enable interrupts in supervisor register */
> +	mtspr(SPR_SR, mfspr(SPR_SR) | SPR_SR_IEE);
> +
> +	return 0;
> +}
> +
> +void enable_interrupts(void)
> +{
> +	/* Set interrupt enable bit in supervisor register */
> +	mtspr(SPR_SR, mfspr(SPR_SR) | SPR_SR_IEE);
> +	/* Enable timer exception */
> +	mtspr(SPR_SR, mfspr(SPR_SR) | SPR_SR_TEE);
> +}
> +
> +int disable_interrupts(void)
> +{
> +	/* Clear interrupt enable bit in supervisor register */
> +	mtspr(SPR_SR, mfspr(SPR_SR) & ~SPR_SR_IEE);
> +	/* Disable timer exception */
> +	mtspr(SPR_SR, mfspr(SPR_SR) & ~SPR_SR_TEE);
> +	return 0;
> +}
> +
> +void irq_install_handler(int irq, interrupt_handler_t *handler, void *arg)
> +{
> +	if (irq < 0 || irq > 31)
> +		return;
> +
> +	handlers[irq].handler = handler;
> +	handlers[irq].arg = arg;
> +}
> +
> +void irq_free_handler(int irq)
> +{
> +	if (irq < 0 || irq > 31)
> +		return;
> +
> +	handlers[irq].handler = 0;
> +	handlers[irq].arg = 0;
> +}
> +
> +#if defined(CONFIG_CMD_IRQ)
> +int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
> +{
> +	int i;
> +
> +	printf("\nInterrupt-Information:\n\n");
> +	printf("Nr  Routine   Arg       Count\n");
> +	printf("-----------------------------\n");
> +
> +	for (i = 0; i < 32; i++) {
> +		if (handlers[i].handler) {
> +			printf("%02d  %08lx  %08lx  %d\n",
> +				i,
> +				(ulong)handlers[i].handler,
> +				(ulong)handlers[i].arg,
> +				handlers[i].count);
> +		}
> +	}
> +	printf("\n");
> +
> +	return 0;
> +}
> +#endif
> diff --git a/arch/openrisc/cpu/start.S b/arch/openrisc/cpu/start.S
> new file mode 100644
> index 0000000..03e6a8e
> --- /dev/null
> +++ b/arch/openrisc/cpu/start.S
> @@ -0,0 +1,335 @@
> +/*
> + * (C) Copyright 2011, Stefan Kristiansson
> <stefan.kristiansson@saunalahti.fi> + * (C) Copyright 2011, Julius Baxter
> <julius@opencores.org>
> + *
> + * 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 <asm/spr-defs.h>
> +#include <config.h>
> +
> +#define EXCEPTION_STACK_SIZE (128+128)
> +
> +#define HANDLE_EXCEPTION			\
> +	l.addi	r1, r1, -EXCEPTION_STACK_SIZE	;\
> +	l.sw	0x1c(r1), r9			;\
> +	l.jal	_exception_handler		;\
> +	 l.nop					;\
> +	l.lwz 	r9, 0x1c(r1)			;\
> +	l.addi	r1, r1, EXCEPTION_STACK_SIZE	;\
> +	l.rfe					;\
> +	 l.nop
> +
> +	.section .vectors, "ax"
> +	.global __reset
> +
> +	/* reset */
> +	.org	0x100
> +__reset:
> +	/* there is no guarantee r0 is hardwired to zero, clear it here */
> +	l.andi	r0, r0, 0
> +	/* reset stack and frame pointers */
> +	l.andi	r1, r0, 0
> +	l.andi	r2, r0, 0
> +
> +	/* set supervisor mode */
> +	l.ori	r3,r0,SPR_SR_SM
> +	l.mtspr	r0,r3,SPR_SR
> +
> +	/* Relocate u-boot */
> +	l.movhi	r3,hi(__start)		/* source start address */
> +	l.ori	r3,r3,lo(__start)
> +	l.movhi	r4,hi(_stext)		/* dest start address */
> +	l.ori	r4,r4,lo(_stext)
> +	l.movhi	r5,hi(__end)		/* dest end address */
> +	l.ori	r5,r5,lo(__end)
> +
> +.L_reloc:
> +	l.lwz	r6,0(r3)
> +	l.sw	0(r4),r6
> +	l.addi	r3,r3,4
> +	l.sfltu	r4,r5
> +	l.bf	.L_reloc
> +	 l.addi	r4,r4,4			/* delay slot */

The formating here doesn't seem right?

> +
> +#ifdef CONFIG_SYS_RELOCATE_VECTORS
> +	/* Relocate vectors from 0xf0000000 to 0x00000000 */
> +	l.movhi r4, 0xf000 /* source */
> +	l.movhi r5, 0      /* destination */
> +	l.addi	r6, r5, CONFIG_SYS_VECTORS_LEN /* length */
> +.L_relocvectors:
> +	l.lwz	r7, 0(r4)
> +	l.sw	0(r5), r7
> +	l.addi	r5, r5, 4
> +	l.sfeq	r5,r6
> +	l.bnf	.L_relocvectors
> +	 l.addi	r4,r4, 4
> +#endif
> +
> +	l.j	_start
> +	 l.nop

Please fix globally ?

> +
> +	/* bus error */
> +	.org	0x200
> +	HANDLE_EXCEPTION
> +
> +	/* data page fault */
> +	.org	0x300
> +	HANDLE_EXCEPTION
> +
> +	/* instruction page fault */
> +	.org	0x400
> +	HANDLE_EXCEPTION
> +
> +	/* tick timer */
> +	.org	0x500
> +	HANDLE_EXCEPTION
> +
> +	/* alignment */
> +	.org	0x600
> +	HANDLE_EXCEPTION
> +
> +	/* illegal instruction */
> +	.org	0x700
> +	HANDLE_EXCEPTION
> +
> +	/* external interrupt */
> +	.org	0x800
> +	HANDLE_EXCEPTION
> +
> +	/* D-TLB miss */
> +	.org	0x900
> +	HANDLE_EXCEPTION
> +
> +	/* I-TLB miss */
> +	.org	0xa00
> +	HANDLE_EXCEPTION
> +
> +	/* range */
> +	.org	0xb00
> +	HANDLE_EXCEPTION
> +
> +	/* system call */
> +	.org	0xc00
> +	HANDLE_EXCEPTION
> +
> +	/* floating point */
> +	.org	0xd00
> +	HANDLE_EXCEPTION
> +
> +	/* trap */
> +	.org	0xe00
> +	HANDLE_EXCEPTION
> +
> +	/* reserved */
> +	.org	0xf00
> +	HANDLE_EXCEPTION
> +
> +	/* reserved */
> +	.org	0x1100
> +	HANDLE_EXCEPTION
> +
> +	/* reserved */
> +	.org	0x1200
> +	HANDLE_EXCEPTION
> +
> +	/* reserved */
> +	.org	0x1300
> +	HANDLE_EXCEPTION
> +
> +	/* reserved */
> +	.org	0x1400
> +	HANDLE_EXCEPTION
> +
> +	/* reserved */
> +	.org	0x1500
> +	HANDLE_EXCEPTION
> +
> +	/* reserved */
> +	.org	0x1600
> +	HANDLE_EXCEPTION
> +
> +	/* reserved */
> +	.org	0x1700
> +	HANDLE_EXCEPTION
> +
> +	/* reserved */
> +	.org	0x1800
> +	HANDLE_EXCEPTION
> +
> +	/* reserved */
> +	.org	0x1900
> +	HANDLE_EXCEPTION
> +
> +	/* reserved */
> +	.org	0x1a00
> +	HANDLE_EXCEPTION
> +
> +	/* reserved */
> +	.org	0x1b00
> +	HANDLE_EXCEPTION
> +
> +	/* reserved */
> +	.org	0x1c00
> +	HANDLE_EXCEPTION
> +
> +	/* reserved */
> +	.org	0x1d00
> +	HANDLE_EXCEPTION
> +
> +	/* reserved */
> +	.org	0x1e00
> +	HANDLE_EXCEPTION
> +
> +	/* reserved */
> +	.org	0x1f00
> +	HANDLE_EXCEPTION
> +
> +	/* Startup routine */
> +	.text
> +	.global _start
> +_start:
> +	/* Init stack and frame pointers */
> +	l.movhi	r1, hi(CONFIG_SYS_INIT_SP_ADDR)
> +	l.ori	r1, r1, lo(CONFIG_SYS_INIT_SP_ADDR)
> +	l.or	r2, r0, r1
> +
> +	/* clear BSS segments */
> +	l.movhi	r4, hi(_bss_start)
> +	l.ori	r4, r4, lo(_bss_start)
> +	l.movhi	r5, hi(_bss_end)
> +	l.ori	r5, r5, lo(_bss_end)
> +.L_clear_bss:
> +	l.sw	0(r4), r0
> +	l.sfltu	r4,r5
> +	l.bf	.L_clear_bss
> +	 l.addi	r4,r4,4
> +
> +	/* Reset registers before jumping to board_init */
> +	l.andi	r3, r0, 0
> +	l.andi	r4, r0, 0
> +	l.andi	r5, r0, 0
> +	l.andi	r6, r0, 0
> +	l.andi	r7, r0, 0
> +	l.andi	r8, r0, 0
> +	l.andi	r9, r0, 0
> +	l.andi	r10, r0, 0
> +	l.andi	r11, r0, 0
> +	l.andi	r12, r0, 0
> +	l.andi	r13, r0, 0
> +	l.andi	r14, r0, 0
> +	l.andi	r15, r0, 0
> +	l.andi	r17, r0, 0
> +	l.andi	r18, r0, 0
> +	l.andi	r19, r0, 0
> +	l.andi	r20, r0, 0
> +	l.andi	r21, r0, 0
> +	l.andi	r22, r0, 0
> +	l.andi	r23, r0, 0
> +	l.andi	r24, r0, 0
> +	l.andi	r25, r0, 0
> +	l.andi	r26, r0, 0
> +	l.andi	r27, r0, 0
> +	l.andi	r28, r0, 0
> +	l.andi	r29, r0, 0
> +	l.andi	r30, r0, 0
> +	l.andi	r31, r0, 0
> +
> +	l.j	board_init
> +	 l.nop
> +
> +	.size	_start, .-_start
> +
> +/*
> + * Store state onto stack and call the real exception handler
> + */
> +	.section .text
> +	.extern	exception_handler
> +	.type	_exception_handler,@function
> +
> +_exception_handler:
> +	/* Store state (r9 already saved)*/
> +	l.sw	0x00(r1), r2
> +	l.sw	0x04(r1), r3
> +	l.sw	0x08(r1), r4
> +	l.sw	0x0c(r1), r5
> +	l.sw	0x10(r1), r6
> +	l.sw	0x14(r1), r7
> +	l.sw	0x18(r1), r8
> +	l.sw	0x20(r1), r10
> +	l.sw	0x24(r1), r11
> +	l.sw	0x28(r1), r12
> +	l.sw	0x2c(r1), r13
> +	l.sw	0x30(r1), r14
> +	l.sw	0x34(r1), r15
> +	l.sw	0x38(r1), r16
> +	l.sw	0x3c(r1), r17
> +	l.sw	0x40(r1), r18
> +	l.sw	0x44(r1), r19
> +	l.sw	0x48(r1), r20
> +	l.sw	0x4c(r1), r21
> +	l.sw	0x50(r1), r22
> +	l.sw	0x54(r1), r23
> +	l.sw	0x58(r1), r24
> +	l.sw	0x5c(r1), r25
> +	l.sw	0x60(r1), r26
> +	l.sw	0x64(r1), r27
> +	l.sw	0x68(r1), r28
> +	l.sw	0x6c(r1), r29
> +	l.sw	0x70(r1), r30
> +	l.sw	0x74(r1), r31
> +
> +	/* Save return address */
> +	l.or	r14, r0, r9
> +	/* Call exception handler with the link address as argument */
> +	l.jal	exception_handler
> +	 l.or	r3, r0, r14
> +	/* Load return address */
> +	l.or	r9, r0, r14
> +
> +	/* Restore state */
> +	l.lwz	r2, 0x00(r1)
> +	l.lwz	r3, 0x04(r1)
> +	l.lwz	r4, 0x08(r1)
> +	l.lwz	r5, 0x0c(r1)
> +	l.lwz	r6, 0x10(r1)
> +	l.lwz	r7, 0x14(r1)
> +	l.lwz	r8, 0x18(r1)
> +	l.lwz	r10, 0x20(r1)
> +	l.lwz	r11, 0x24(r1)
> +	l.lwz	r12, 0x28(r1)
> +	l.lwz	r13, 0x2c(r1)
> +	l.lwz	r14, 0x30(r1)
> +	l.lwz	r15, 0x34(r1)
> +	l.lwz	r16, 0x38(r1)
> +	l.lwz	r17, 0x3c(r1)
> +	l.lwz	r18, 0x40(r1)
> +	l.lwz	r19, 0x44(r1)
> +	l.lwz	r20, 0x48(r1)
> +	l.lwz	r21, 0x4c(r1)
> +	l.lwz	r22, 0x50(r1)
> +	l.lwz	r23, 0x54(r1)
> +	l.lwz	r24, 0x58(r1)
> +	l.lwz	r25, 0x5c(r1)
> +	l.lwz	r26, 0x60(r1)
> +	l.lwz	r27, 0x64(r1)
> +	l.lwz	r28, 0x68(r1)
> +	l.lwz	r29, 0x6c(r1)
> +	l.lwz	r30, 0x70(r1)
> +	l.lwz	r31, 0x74(r1)
> +	l.jr	r9
> +	 l.nop

M
Stefan Kristiansson Nov. 22, 2011, 3:51 a.m. UTC | #5
On Mon, Nov 21, 2011 at 11:50:17PM +0100, Marek Vasut wrote:
> > +	return (mfspr(SPR_ICCFGR) & SPR_ICCFGR_CBS) ? 32 : 16;
> 
> What's mfspr ... if it's some register, then maybe mfspr_read() ?
> 

It's an instruction, "move from special register",
so I don't think the _read would be appropriate in this case.

> > +	printf("CPU:   OpenRISC-%x00 (rev %d) @ %d MHz\n",
> > +		ver, rev, (CONFIG_SYS_CLK_FREQ / 1000000));
> 
> The CPU won't tell you it's speed ?
> 

Nope.

> > +	l.addi	r3,r3,4
> > +	l.sfltu	r4,r5
> > +	l.bf	.L_reloc
> > +	 l.addi	r4,r4,4			/* delay slot */
> 
> The formating here doesn't seem right?
> 

The extra space there is to denote that the instruction is
in a delay slot.
I think it brings more readability to the code, but if it
meets too much resistance I'll remove them.

Stefan
Marek Vasut Nov. 22, 2011, 4:46 a.m. UTC | #6
> On Mon, Nov 21, 2011 at 11:50:17PM +0100, Marek Vasut wrote:
> > > +	return (mfspr(SPR_ICCFGR) & SPR_ICCFGR_CBS) ? 32 : 16;
> > 
> > What's mfspr ... if it's some register, then maybe mfspr_read() ?
> 
> It's an instruction, "move from special register",
> so I don't think the _read would be appropriate in this case.
> 
> > > +	printf("CPU:   OpenRISC-%x00 (rev %d) @ %d MHz\n",
> > > +		ver, rev, (CONFIG_SYS_CLK_FREQ / 1000000));
> > 
> > The CPU won't tell you it's speed ?
> 
> Nope.

That's weird, how do you calibrate delay then, using static setup ?

> 
> > > +	l.addi	r3,r3,4
> > > +	l.sfltu	r4,r5
> > > +	l.bf	.L_reloc
> > > +	 l.addi	r4,r4,4			/* delay slot */
> > 
> > The formating here doesn't seem right?
> 
> The extra space there is to denote that the instruction is
> in a delay slot.
> I think it brings more readability to the code, but if it
> meets too much resistance I'll remove them.

You already have comment there, but let's see what the others think.
> 
> Stefan
Stefan Kristiansson Nov. 22, 2011, 7:17 a.m. UTC | #7
On Tue, Nov 22, 2011 at 05:46:41AM +0100, Marek Vasut wrote:
> > On Mon, Nov 21, 2011 at 11:50:17PM +0100, Marek Vasut wrote:
> > > > +	printf("CPU:   OpenRISC-%x00 (rev %d) @ %d MHz\n",
> > > > +		ver, rev, (CONFIG_SYS_CLK_FREQ / 1000000));
> > > 
> > > The CPU won't tell you it's speed ?
> > 
> > Nope.
> 
> That's weird, how do you calibrate delay then, using static setup ?
> 

You mean in Linux? CPU freq is passed in via the device tree.

Stefan
Marek Vasut Nov. 22, 2011, 2:07 p.m. UTC | #8
> On Tue, Nov 22, 2011 at 05:46:41AM +0100, Marek Vasut wrote:
> > > On Mon, Nov 21, 2011 at 11:50:17PM +0100, Marek Vasut wrote:
> > > > > +	printf("CPU:   OpenRISC-%x00 (rev %d) @ %d MHz\n",
> > > > > +		ver, rev, (CONFIG_SYS_CLK_FREQ / 1000000));
> > > > 
> > > > The CPU won't tell you it's speed ?
> > > 
> > > Nope.
> > 
> > That's weird, how do you calibrate delay then, using static setup ?
> 
> You mean in Linux? CPU freq is passed in via the device tree.

I mean in u-boot, it seems weird for the CPU to be unable to tell you how fast 
it runs.

M
Scott Wood Nov. 22, 2011, 8:29 p.m. UTC | #9
On 11/22/2011 08:07 AM, Marek Vasut wrote:
>> On Tue, Nov 22, 2011 at 05:46:41AM +0100, Marek Vasut wrote:
>>>> On Mon, Nov 21, 2011 at 11:50:17PM +0100, Marek Vasut wrote:
>>>>>> +	printf("CPU:   OpenRISC-%x00 (rev %d) @ %d MHz\n",
>>>>>> +		ver, rev, (CONFIG_SYS_CLK_FREQ / 1000000));
>>>>>
>>>>> The CPU won't tell you it's speed ?
>>>>
>>>> Nope.
>>>
>>> That's weird, how do you calibrate delay then, using static setup ?
>>
>> You mean in Linux? CPU freq is passed in via the device tree.
> 
> I mean in u-boot, it seems weird for the CPU to be unable to tell you how fast 
> it runs.

You need some fixed reference, whether it be the crystal that is used to
generate the CPU clock, or some other clock on the board that you
measure the CPU clock against.  The CPU might be able to tell you what
multiplier it's using, or which of several input pins it's taking the
clock from, but not the base input frequency.

Look in include/config, you'll find lots of hardcoded CONFIG_SYS_CLK_FREQ.

-Scott
Mike Frysinger Nov. 22, 2011, 8:54 p.m. UTC | #10
On Monday 21 November 2011 23:46:41 Marek Vasut wrote:
> > On Mon, Nov 21, 2011 at 11:50:17PM +0100, Marek Vasut wrote:
> > > > +	l.addi	r3,r3,4
> > > > +	l.sfltu	r4,r5
> > > > +	l.bf	.L_reloc
> > > > +	 l.addi	r4,r4,4			/* delay slot */
> > > 
> > > The formating here doesn't seem right?
> > 
> > The extra space there is to denote that the instruction is
> > in a delay slot.
> > I think it brings more readability to the code, but if it
> > meets too much resistance I'll remove them.
> 
> You already have comment there, but let's see what the others think.

i think it's fine.  delay slots are a pita enough to deal with, so slight style 
tweaks that make this easier are a good thing.
-mike
diff mbox

Patch

diff --git a/arch/openrisc/config.mk b/arch/openrisc/config.mk
new file mode 100644
index 0000000..bea3d12
--- /dev/null
+++ b/arch/openrisc/config.mk
@@ -0,0 +1,27 @@ 
+#
+# (C) Copyright 2011
+# Julius Baxter <julius@opencores.org>
+#
+# 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
+#
+
+CROSS_COMPILE ?= or32-elf-
+
+# r10 used for global object pointer, already set in OR32 GCC but just to be
+# clear
+PLATFORM_CPPFLAGS += -DCONFIG_OPENRISC -D__OR1K__ -ffixed-r10
+
+CONFIG_STANDALONE_LOAD_ADDR ?= 0x40000
\ No newline at end of file
diff --git a/arch/openrisc/cpu/Makefile b/arch/openrisc/cpu/Makefile
new file mode 100644
index 0000000..b3b1a24
--- /dev/null
+++ b/arch/openrisc/cpu/Makefile
@@ -0,0 +1,47 @@ 
+#
+# (C) Copyright 2011
+# Julius Baxter <julius@opencores.org>
+#
+# 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	= cache.o cpu.o exceptions.o interrupts.o
+
+SRCS	:= $(START:.o=.S) $(COBJS-y:.o=.c)
+OBJS	:= $(addprefix $(obj),$(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/openrisc/cpu/cache.c b/arch/openrisc/cpu/cache.c
new file mode 100644
index 0000000..9dd627f
--- /dev/null
+++ b/arch/openrisc/cpu/cache.c
@@ -0,0 +1,157 @@ 
+/*
+ * (C) Copyright 2011, Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
+ * (C) Copyright 2011, Julius Baxter <julius@opencores.org>
+ *
+ * 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/system.h>
+#include <common.h>
+
+/* cache line size can be either 16 or 32 bytes */
+static inline unsigned long get_linesize(void)
+{
+	return (mfspr(SPR_ICCFGR) & SPR_ICCFGR_CBS) ? 32 : 16;
+}
+
+void flush_dcache_range(unsigned long addr, unsigned long stop)
+{
+	unsigned long linesize = get_linesize();
+
+	while (addr < stop) {
+		mtspr(SPR_DCBFR, addr);
+		addr += linesize;
+	}
+}
+
+void invalidate_dcache_range(unsigned long addr, unsigned long stop)
+{
+	unsigned long linesize = get_linesize();
+
+	while (addr < stop) {
+		mtspr(SPR_DCBIR, addr);
+		addr += linesize;
+	}
+}
+
+static void invalidate_icache_range(unsigned long addr, unsigned long stop)
+{
+	unsigned long linesize = get_linesize();
+
+	while (addr < stop) {
+		mtspr(SPR_ICBIR, addr);
+		addr += linesize;
+	}
+}
+
+void flush_cache(unsigned long addr, unsigned long size)
+{
+	flush_dcache_range(addr, addr + size);
+	invalidate_icache_range(addr, addr + size);
+}
+
+int icache_status(void)
+{
+	return mfspr(SPR_SR) & SPR_SR_ICE;
+}
+
+int checkicache(void)
+{
+	unsigned long iccfgr;
+	unsigned long cache_set_size;
+	unsigned long cache_ways;
+	unsigned long cache_block_size;
+
+	iccfgr = mfspr(SPR_ICCFGR);
+	cache_ways = 1 << (iccfgr & SPR_ICCFGR_NCW);
+	cache_set_size = 1 << ((iccfgr & SPR_ICCFGR_NCS) >> 3);
+	cache_block_size = (iccfgr & SPR_ICCFGR_CBS) ? 32 : 16;
+
+	return cache_set_size * cache_ways * cache_block_size;
+}
+
+int dcache_status(void)
+{
+	return mfspr(SPR_SR) & SPR_SR_DCE;
+}
+
+int checkdcache(void)
+{
+	unsigned long dccfgr;
+	unsigned long cache_set_size;
+	unsigned long cache_ways;
+	unsigned long cache_block_size;
+
+	dccfgr = mfspr(SPR_DCCFGR);
+	cache_ways = 1 << (dccfgr & SPR_DCCFGR_NCW);
+	cache_set_size = 1 << ((dccfgr & SPR_DCCFGR_NCS) >> 3);
+	cache_block_size = (dccfgr & SPR_DCCFGR_CBS) ? 32 : 16;
+
+	return cache_set_size * cache_ways * cache_block_size;
+}
+
+void dcache_enable(void)
+{
+	mtspr(SPR_SR, mfspr(SPR_SR) | SPR_SR_DCE);
+	asm("l.nop");
+	asm("l.nop");
+	asm("l.nop");
+	asm("l.nop");
+	asm("l.nop");
+	asm("l.nop");
+	asm("l.nop");
+	asm("l.nop");
+}
+
+void dcache_disable(void)
+{
+	mtspr(SPR_SR, mfspr(SPR_SR) & ~SPR_SR_DCE);
+}
+
+void icache_enable(void)
+{
+	mtspr(SPR_SR, mfspr(SPR_SR) | SPR_SR_ICE);
+	asm("l.nop");
+	asm("l.nop");
+	asm("l.nop");
+	asm("l.nop");
+	asm("l.nop");
+	asm("l.nop");
+	asm("l.nop");
+	asm("l.nop");
+}
+
+void icache_disable(void)
+{
+	mtspr(SPR_SR, mfspr(SPR_SR) & ~SPR_SR_ICE);
+}
+
+int cache_init(void)
+{
+	if (mfspr(SPR_UPR) & SPR_UPR_ICP) {
+		icache_disable();
+		invalidate_icache_range(0, checkicache());
+		icache_enable();
+	}
+
+	if (mfspr(SPR_UPR) & SPR_UPR_DCP) {
+		dcache_disable();
+		invalidate_dcache_range(0, checkdcache());
+		dcache_enable();
+	}
+
+	return 0;
+}
diff --git a/arch/openrisc/cpu/cpu.c b/arch/openrisc/cpu/cpu.c
new file mode 100644
index 0000000..3b69285
--- /dev/null
+++ b/arch/openrisc/cpu/cpu.c
@@ -0,0 +1,157 @@ 
+/*
+ * (C) Copyright 2011, Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
+ * (C) Copyright 2011, Julius Baxter <julius@opencores.org>
+ *
+ * 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/system.h>
+#include <asm/openrisc_exc.h>
+#include <common.h>
+
+static volatile int illegal_instruction;
+
+void illegal_instruction_handler(void)
+{
+	ulong *epcr = (ulong *)mfspr(SPR_EPCR_BASE);
+
+	/* skip over the illegal instruction */
+	mtspr(SPR_EPCR_BASE, (ulong)(++epcr));
+	illegal_instruction = 1;
+}
+
+void checkinstructions(void)
+{
+	ulong ra = 1, rb = 1, rc;
+
+	exception_install_handler(EXC_ILLEGAL_INSTR,
+				illegal_instruction_handler);
+
+	illegal_instruction = 0;
+	asm volatile("l.mul %0,%1,%2" : "=r" (rc) : "r" (ra), "r" (rb));
+	printf("           Hardware multiplier: %s\n",
+		illegal_instruction ? "no" : "yes");
+
+	illegal_instruction = 0;
+	asm volatile("l.div %0,%1,%2" : "=r" (rc) : "r" (ra), "r" (rb));
+	printf("           Hardware divider: %s\n",
+		illegal_instruction ? "no" : "yes");
+
+	exception_free_handler(EXC_ILLEGAL_INSTR);
+
+}
+
+int checkcpu(void)
+{
+	ulong upr = mfspr(SPR_UPR);
+	ulong vr = mfspr(SPR_VR);
+	ulong iccfgr = mfspr(SPR_ICCFGR);
+	ulong dccfgr = mfspr(SPR_DCCFGR);
+	ulong immucfgr = mfspr(SPR_IMMUCFGR);
+	ulong dmmucfgr = mfspr(SPR_DMMUCFGR);
+	ulong cpucfgr = mfspr(SPR_CPUCFGR);
+	uint ver = (vr & SPR_VR_VER) >> 24;
+	uint rev = vr & SPR_VR_REV;
+	uint block_size;
+	uint ways;
+	uint sets;
+
+	printf("CPU:   OpenRISC-%x00 (rev %d) @ %d MHz\n",
+		ver, rev, (CONFIG_SYS_CLK_FREQ / 1000000));
+
+	if (upr & SPR_UPR_DCP) {
+		block_size = (dccfgr & SPR_DCCFGR_CBS) ? 32 : 16;
+		ways = 1 << (dccfgr & SPR_DCCFGR_NCW);
+		printf("       D-Cache: %d bytes, %d bytes/line, %d way(s)\n",
+		       checkdcache(), block_size, ways);
+	} else {
+		printf("       D-Cache: no\n");
+	}
+
+	if (upr & SPR_UPR_ICP) {
+		block_size = (iccfgr & SPR_ICCFGR_CBS) ? 32 : 16;
+		ways = 1 << (iccfgr & SPR_ICCFGR_NCW);
+		printf("       I-Cache: %d bytes, %d bytes/line, %d way(s)\n",
+		       checkicache(), block_size, ways);
+	} else {
+		printf("       I-Cache: no\n");
+	}
+
+	if (upr & SPR_UPR_DMP) {
+		sets = 1 << ((dmmucfgr & SPR_DMMUCFGR_NTS) >> 2);
+		ways = (dmmucfgr & SPR_DMMUCFGR_NTW) + 1;
+		printf("       DMMU: %d sets, %d way(s)\n",
+		       sets, ways);
+	} else {
+		printf("       DMMU: no\n");
+	}
+
+	if (upr & SPR_UPR_IMP) {
+		sets = 1 << ((immucfgr & SPR_IMMUCFGR_NTS) >> 2);
+		ways = (immucfgr & SPR_IMMUCFGR_NTW) + 1;
+		printf("       IMMU: %d sets, %d way(s)\n",
+		       sets, ways);
+	} else {
+		printf("       IMMU: no\n");
+	}
+
+	printf("       MAC unit: %s\n",
+		(upr & SPR_UPR_MP) ? "yes" : "no");
+	printf("       Debug unit: %s\n",
+		(upr & SPR_UPR_DUP) ? "yes" : "no");
+	printf("       Performance counters: %s\n",
+		(upr & SPR_UPR_PCUP) ? "yes" : "no");
+	printf("       Power management: %s\n",
+		(upr & SPR_UPR_PMP) ? "yes" : "no");
+	printf("       Interrupt controller: %s\n",
+		(upr & SPR_UPR_PICP) ? "yes" : "no");
+	printf("       Timer: %s\n",
+		(upr & SPR_UPR_TTP) ? "yes" : "no");
+	printf("       Custom unit(s): %s\n",
+		(upr & SPR_UPR_CUP) ? "yes" : "no");
+
+	printf("       Supported instructions:\n");
+	printf("           ORBIS32: %s\n",
+		(cpucfgr & SPR_CPUCFGR_OB32S) ? "yes" : "no");
+	printf("           ORBIS64: %s\n",
+		(cpucfgr & SPR_CPUCFGR_OB64S) ? "yes" : "no");
+	printf("           ORFPX32: %s\n",
+		(cpucfgr & SPR_CPUCFGR_OF32S) ? "yes" : "no");
+	printf("           ORFPX64: %s\n",
+		(cpucfgr & SPR_CPUCFGR_OF64S) ? "yes" : "no");
+
+	checkinstructions();
+
+	return 0;
+}
+
+int cleanup_before_linux(void)
+{
+	disable_interrupts();
+	return 0;
+}
+
+extern void __reset(void);
+
+int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	disable_interrupts();
+	__reset();
+	return 0;
+}
diff --git a/arch/openrisc/cpu/exceptions.c b/arch/openrisc/cpu/exceptions.c
new file mode 100644
index 0000000..06935be
--- /dev/null
+++ b/arch/openrisc/cpu/exceptions.c
@@ -0,0 +1,109 @@ 
+/*
+ * (C) Copyright 2011, Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
+ * (C) Copyright 2011, Julius Baxter <julius@opencores.org>
+ *
+ * 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/system.h>
+#include <common.h>
+#include <stdio_dev.h>
+
+extern void hang(void);
+
+static void (*handlers[32])(void);
+
+void exception_install_handler(int exception, void (*handler)(void))
+{
+	if (exception < 0 || exception > 31)
+		return;
+
+	handlers[exception] = handler;
+}
+
+void exception_free_handler(int exception)
+{
+	if (exception < 0 || exception > 31)
+		return;
+
+	handlers[exception] = 0;
+}
+
+static void exception_hang(int vect)
+{
+	printf("Unhandled exception at 0x%x ", vect & 0xff00);
+	switch (vect & 0xff00) {
+	case 0x100:
+		puts("(Reset)\n");
+		break;
+	case 0x200:
+		puts("(Bus Error)\n");
+		break;
+	case 0x300:
+		puts("(Data Page Fault)\n");
+		break;
+	case 0x400:
+		puts("(Instruction Page Fault)\n");
+		break;
+	case 0x500:
+		puts("(Tick Timer)\n");
+		break;
+	case 0x600:
+		puts("(Alignment)\n");
+		break;
+	case 0x700:
+		puts("(Illegal Instruction)\n");
+		break;
+	case 0x800:
+		puts("(External Interrupt)\n");
+		break;
+	case 0x900:
+		puts("(D-TLB Miss)\n");
+		break;
+	case 0xa00:
+		puts("(I-TLB Miss)\n");
+		break;
+	case 0xb00:
+		puts("(Range)\n");
+		break;
+	case 0xc00:
+		puts("(System Call)\n");
+		break;
+	case 0xd00:
+		puts("(Floating Point)\n");
+		break;
+	case 0xe00:
+		puts("(Trap)\n");
+		break;
+	default:
+		puts("(Unknown exception)\n");
+		break;
+	}
+	printf("EPCR: 0x%08lx\n", mfspr(SPR_EPCR_BASE));
+	printf("EEAR: 0x%08lx\n", mfspr(SPR_EEAR_BASE));
+	printf("ESR:  0x%08lx\n", mfspr(SPR_ESR_BASE));
+	hang();
+}
+
+void exception_handler(int vect)
+{
+	int exception = vect >> 8;
+
+	if (handlers[exception])
+		handlers[exception]();
+	else
+		exception_hang(vect);
+}
diff --git a/arch/openrisc/cpu/interrupts.c b/arch/openrisc/cpu/interrupts.c
new file mode 100644
index 0000000..62d266a
--- /dev/null
+++ b/arch/openrisc/cpu/interrupts.c
@@ -0,0 +1,120 @@ 
+/*
+ * (C) Copyright 2011, Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
+ * (C) Copyright 2011, Julius Baxter <julius@opencores.org>
+ *
+ * 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/types.h>
+#include <asm/ptrace.h>
+#include <asm/system.h>
+#include <asm/openrisc_exc.h>
+#include <common.h>
+
+struct irq_action {
+	interrupt_handler_t *handler;
+	void *arg;
+	int count;
+};
+
+static struct irq_action handlers[32];
+
+void interrupt_handler(void)
+{
+	int irq;
+
+	while ((irq = ffs(mfspr(SPR_PICSR)))) {
+		if (handlers[--irq].handler) {
+			handlers[irq].handler(handlers[irq].arg);
+			handlers[irq].count++;
+		} else {
+			/* disable the interrupt */
+			mtspr(SPR_PICMR, mfspr(SPR_PICMR) & ~(1 << irq));
+			printf("Unhandled interrupt: %d\n", irq);
+		}
+		/* clear the interrupt */
+		mtspr(SPR_PICSR, mfspr(SPR_PICSR) & ~(1 << irq));
+	}
+}
+
+int interrupt_init(void)
+{
+	/* install handler for external interrupt exception */
+	exception_install_handler(EXC_EXT_IRQ, interrupt_handler);
+	/* Enable interrupts in supervisor register */
+	mtspr(SPR_SR, mfspr(SPR_SR) | SPR_SR_IEE);
+
+	return 0;
+}
+
+void enable_interrupts(void)
+{
+	/* Set interrupt enable bit in supervisor register */
+	mtspr(SPR_SR, mfspr(SPR_SR) | SPR_SR_IEE);
+	/* Enable timer exception */
+	mtspr(SPR_SR, mfspr(SPR_SR) | SPR_SR_TEE);
+}
+
+int disable_interrupts(void)
+{
+	/* Clear interrupt enable bit in supervisor register */
+	mtspr(SPR_SR, mfspr(SPR_SR) & ~SPR_SR_IEE);
+	/* Disable timer exception */
+	mtspr(SPR_SR, mfspr(SPR_SR) & ~SPR_SR_TEE);
+	return 0;
+}
+
+void irq_install_handler(int irq, interrupt_handler_t *handler, void *arg)
+{
+	if (irq < 0 || irq > 31)
+		return;
+
+	handlers[irq].handler = handler;
+	handlers[irq].arg = arg;
+}
+
+void irq_free_handler(int irq)
+{
+	if (irq < 0 || irq > 31)
+		return;
+
+	handlers[irq].handler = 0;
+	handlers[irq].arg = 0;
+}
+
+#if defined(CONFIG_CMD_IRQ)
+int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	int i;
+
+	printf("\nInterrupt-Information:\n\n");
+	printf("Nr  Routine   Arg       Count\n");
+	printf("-----------------------------\n");
+
+	for (i = 0; i < 32; i++) {
+		if (handlers[i].handler) {
+			printf("%02d  %08lx  %08lx  %d\n",
+				i,
+				(ulong)handlers[i].handler,
+				(ulong)handlers[i].arg,
+				handlers[i].count);
+		}
+	}
+	printf("\n");
+
+	return 0;
+}
+#endif
diff --git a/arch/openrisc/cpu/start.S b/arch/openrisc/cpu/start.S
new file mode 100644
index 0000000..03e6a8e
--- /dev/null
+++ b/arch/openrisc/cpu/start.S
@@ -0,0 +1,335 @@ 
+/*
+ * (C) Copyright 2011, Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
+ * (C) Copyright 2011, Julius Baxter <julius@opencores.org>
+ *
+ * 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 <asm/spr-defs.h>
+#include <config.h>
+
+#define EXCEPTION_STACK_SIZE (128+128)
+
+#define HANDLE_EXCEPTION			\
+	l.addi	r1, r1, -EXCEPTION_STACK_SIZE	;\
+	l.sw	0x1c(r1), r9			;\
+	l.jal	_exception_handler		;\
+	 l.nop					;\
+	l.lwz 	r9, 0x1c(r1)			;\
+	l.addi	r1, r1, EXCEPTION_STACK_SIZE	;\
+	l.rfe					;\
+	 l.nop
+
+	.section .vectors, "ax"
+	.global __reset
+
+	/* reset */
+	.org	0x100
+__reset:
+	/* there is no guarantee r0 is hardwired to zero, clear it here */
+	l.andi	r0, r0, 0
+	/* reset stack and frame pointers */
+	l.andi	r1, r0, 0
+	l.andi	r2, r0, 0
+
+	/* set supervisor mode */
+	l.ori	r3,r0,SPR_SR_SM
+	l.mtspr	r0,r3,SPR_SR
+
+	/* Relocate u-boot */
+	l.movhi	r3,hi(__start)		/* source start address */
+	l.ori	r3,r3,lo(__start)
+	l.movhi	r4,hi(_stext)		/* dest start address */
+	l.ori	r4,r4,lo(_stext)
+	l.movhi	r5,hi(__end)		/* dest end address */
+	l.ori	r5,r5,lo(__end)
+
+.L_reloc:
+	l.lwz	r6,0(r3)
+	l.sw	0(r4),r6
+	l.addi	r3,r3,4
+	l.sfltu	r4,r5
+	l.bf	.L_reloc
+	 l.addi	r4,r4,4			/* delay slot */
+
+#ifdef CONFIG_SYS_RELOCATE_VECTORS
+	/* Relocate vectors from 0xf0000000 to 0x00000000 */
+	l.movhi r4, 0xf000 /* source */
+	l.movhi r5, 0      /* destination */
+	l.addi	r6, r5, CONFIG_SYS_VECTORS_LEN /* length */
+.L_relocvectors:
+	l.lwz	r7, 0(r4)
+	l.sw	0(r5), r7
+	l.addi	r5, r5, 4
+	l.sfeq	r5,r6
+	l.bnf	.L_relocvectors
+	 l.addi	r4,r4, 4
+#endif
+
+	l.j	_start
+	 l.nop
+
+	/* bus error */
+	.org	0x200
+	HANDLE_EXCEPTION
+
+	/* data page fault */
+	.org	0x300
+	HANDLE_EXCEPTION
+
+	/* instruction page fault */
+	.org	0x400
+	HANDLE_EXCEPTION
+
+	/* tick timer */
+	.org	0x500
+	HANDLE_EXCEPTION
+
+	/* alignment */
+	.org	0x600
+	HANDLE_EXCEPTION
+
+	/* illegal instruction */
+	.org	0x700
+	HANDLE_EXCEPTION
+
+	/* external interrupt */
+	.org	0x800
+	HANDLE_EXCEPTION
+
+	/* D-TLB miss */
+	.org	0x900
+	HANDLE_EXCEPTION
+
+	/* I-TLB miss */
+	.org	0xa00
+	HANDLE_EXCEPTION
+
+	/* range */
+	.org	0xb00
+	HANDLE_EXCEPTION
+
+	/* system call */
+	.org	0xc00
+	HANDLE_EXCEPTION
+
+	/* floating point */
+	.org	0xd00
+	HANDLE_EXCEPTION
+
+	/* trap */
+	.org	0xe00
+	HANDLE_EXCEPTION
+
+	/* reserved */
+	.org	0xf00
+	HANDLE_EXCEPTION
+
+	/* reserved */
+	.org	0x1100
+	HANDLE_EXCEPTION
+
+	/* reserved */
+	.org	0x1200
+	HANDLE_EXCEPTION
+
+	/* reserved */
+	.org	0x1300
+	HANDLE_EXCEPTION
+
+	/* reserved */
+	.org	0x1400
+	HANDLE_EXCEPTION
+
+	/* reserved */
+	.org	0x1500
+	HANDLE_EXCEPTION
+
+	/* reserved */
+	.org	0x1600
+	HANDLE_EXCEPTION
+
+	/* reserved */
+	.org	0x1700
+	HANDLE_EXCEPTION
+
+	/* reserved */
+	.org	0x1800
+	HANDLE_EXCEPTION
+
+	/* reserved */
+	.org	0x1900
+	HANDLE_EXCEPTION
+
+	/* reserved */
+	.org	0x1a00
+	HANDLE_EXCEPTION
+
+	/* reserved */
+	.org	0x1b00
+	HANDLE_EXCEPTION
+
+	/* reserved */
+	.org	0x1c00
+	HANDLE_EXCEPTION
+
+	/* reserved */
+	.org	0x1d00
+	HANDLE_EXCEPTION
+
+	/* reserved */
+	.org	0x1e00
+	HANDLE_EXCEPTION
+
+	/* reserved */
+	.org	0x1f00
+	HANDLE_EXCEPTION
+
+	/* Startup routine */
+	.text
+	.global _start
+_start:
+	/* Init stack and frame pointers */
+	l.movhi	r1, hi(CONFIG_SYS_INIT_SP_ADDR)
+	l.ori	r1, r1, lo(CONFIG_SYS_INIT_SP_ADDR)
+	l.or	r2, r0, r1
+
+	/* clear BSS segments */
+	l.movhi	r4, hi(_bss_start)
+	l.ori	r4, r4, lo(_bss_start)
+	l.movhi	r5, hi(_bss_end)
+	l.ori	r5, r5, lo(_bss_end)
+.L_clear_bss:
+	l.sw	0(r4), r0
+	l.sfltu	r4,r5
+	l.bf	.L_clear_bss
+	 l.addi	r4,r4,4
+
+	/* Reset registers before jumping to board_init */
+	l.andi	r3, r0, 0
+	l.andi	r4, r0, 0
+	l.andi	r5, r0, 0
+	l.andi	r6, r0, 0
+	l.andi	r7, r0, 0
+	l.andi	r8, r0, 0
+	l.andi	r9, r0, 0
+	l.andi	r10, r0, 0
+	l.andi	r11, r0, 0
+	l.andi	r12, r0, 0
+	l.andi	r13, r0, 0
+	l.andi	r14, r0, 0
+	l.andi	r15, r0, 0
+	l.andi	r17, r0, 0
+	l.andi	r18, r0, 0
+	l.andi	r19, r0, 0
+	l.andi	r20, r0, 0
+	l.andi	r21, r0, 0
+	l.andi	r22, r0, 0
+	l.andi	r23, r0, 0
+	l.andi	r24, r0, 0
+	l.andi	r25, r0, 0
+	l.andi	r26, r0, 0
+	l.andi	r27, r0, 0
+	l.andi	r28, r0, 0
+	l.andi	r29, r0, 0
+	l.andi	r30, r0, 0
+	l.andi	r31, r0, 0
+
+	l.j	board_init
+	 l.nop
+
+	.size	_start, .-_start
+
+/*
+ * Store state onto stack and call the real exception handler
+ */
+	.section .text
+	.extern	exception_handler
+	.type	_exception_handler,@function
+
+_exception_handler:
+	/* Store state (r9 already saved)*/
+	l.sw	0x00(r1), r2
+	l.sw	0x04(r1), r3
+	l.sw	0x08(r1), r4
+	l.sw	0x0c(r1), r5
+	l.sw	0x10(r1), r6
+	l.sw	0x14(r1), r7
+	l.sw	0x18(r1), r8
+	l.sw	0x20(r1), r10
+	l.sw	0x24(r1), r11
+	l.sw	0x28(r1), r12
+	l.sw	0x2c(r1), r13
+	l.sw	0x30(r1), r14
+	l.sw	0x34(r1), r15
+	l.sw	0x38(r1), r16
+	l.sw	0x3c(r1), r17
+	l.sw	0x40(r1), r18
+	l.sw	0x44(r1), r19
+	l.sw	0x48(r1), r20
+	l.sw	0x4c(r1), r21
+	l.sw	0x50(r1), r22
+	l.sw	0x54(r1), r23
+	l.sw	0x58(r1), r24
+	l.sw	0x5c(r1), r25
+	l.sw	0x60(r1), r26
+	l.sw	0x64(r1), r27
+	l.sw	0x68(r1), r28
+	l.sw	0x6c(r1), r29
+	l.sw	0x70(r1), r30
+	l.sw	0x74(r1), r31
+
+	/* Save return address */
+	l.or	r14, r0, r9
+	/* Call exception handler with the link address as argument */
+	l.jal	exception_handler
+	 l.or	r3, r0, r14
+	/* Load return address */
+	l.or	r9, r0, r14
+
+	/* Restore state */
+	l.lwz	r2, 0x00(r1)
+	l.lwz	r3, 0x04(r1)
+	l.lwz	r4, 0x08(r1)
+	l.lwz	r5, 0x0c(r1)
+	l.lwz	r6, 0x10(r1)
+	l.lwz	r7, 0x14(r1)
+	l.lwz	r8, 0x18(r1)
+	l.lwz	r10, 0x20(r1)
+	l.lwz	r11, 0x24(r1)
+	l.lwz	r12, 0x28(r1)
+	l.lwz	r13, 0x2c(r1)
+	l.lwz	r14, 0x30(r1)
+	l.lwz	r15, 0x34(r1)
+	l.lwz	r16, 0x38(r1)
+	l.lwz	r17, 0x3c(r1)
+	l.lwz	r18, 0x40(r1)
+	l.lwz	r19, 0x44(r1)
+	l.lwz	r20, 0x48(r1)
+	l.lwz	r21, 0x4c(r1)
+	l.lwz	r22, 0x50(r1)
+	l.lwz	r23, 0x54(r1)
+	l.lwz	r24, 0x58(r1)
+	l.lwz	r25, 0x5c(r1)
+	l.lwz	r26, 0x60(r1)
+	l.lwz	r27, 0x64(r1)
+	l.lwz	r28, 0x68(r1)
+	l.lwz	r29, 0x6c(r1)
+	l.lwz	r30, 0x70(r1)
+	l.lwz	r31, 0x74(r1)
+	l.jr	r9
+	 l.nop