diff options
Diffstat (limited to 'cpu')
| -rw-r--r-- | cpu/arm926ejs/Makefile | 43 | ||||
| -rw-r--r-- | cpu/arm926ejs/config.mk | 27 | ||||
| -rw-r--r-- | cpu/arm926ejs/cpu.c | 159 | ||||
| -rw-r--r-- | cpu/arm926ejs/interrupts.c | 293 | ||||
| -rw-r--r-- | cpu/arm926ejs/start.S | 426 | 
5 files changed, 948 insertions, 0 deletions
diff --git a/cpu/arm926ejs/Makefile b/cpu/arm926ejs/Makefile new file mode 100644 index 000000000..203278e9c --- /dev/null +++ b/cpu/arm926ejs/Makefile @@ -0,0 +1,43 @@ +# +# (C) Copyright 2000-2003 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +include $(TOPDIR)/config.mk + +LIB	= lib$(CPU).a + +START	= start.o +OBJS	= interrupts.o cpu.o + +all:	.depend $(START) $(LIB) + +$(LIB):	$(OBJS) +	$(AR) crv $@ $(OBJS) + +######################################################################### + +.depend:	Makefile $(START:.o=.S) $(OBJS:.o=.c) +		$(CC) -M $(CFLAGS) $(START:.o=.S) $(OBJS:.o=.c) > $@ + +sinclude .depend + +######################################################################### diff --git a/cpu/arm926ejs/config.mk b/cpu/arm926ejs/config.mk new file mode 100644 index 000000000..cef7d26f1 --- /dev/null +++ b/cpu/arm926ejs/config.mk @@ -0,0 +1,27 @@ +# +# (C) Copyright 2002 +# Gary Jennejohn, DENX Software Engineering, <gj@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 +# + +PLATFORM_RELFLAGS += -fno-strict-aliasing  -fno-common -ffixed-r8 \ +	-mshort-load-bytes -msoft-float + +PLATFORM_CPPFLAGS += -mapcs-32 -march=armv4 diff --git a/cpu/arm926ejs/cpu.c b/cpu/arm926ejs/cpu.c new file mode 100644 index 000000000..a91aa3782 --- /dev/null +++ b/cpu/arm926ejs/cpu.c @@ -0,0 +1,159 @@ +/* + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Marius Groeger <mgroeger@sysgo.de> + * + * (C) Copyright 2002 + * Gary Jennejohn, DENX Software Engineering, <gj@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 + */ + +/* + * CPU specific code + */ + +#include <common.h> +#include <command.h> +#include <arm926ejs.h> + +/* read co-processor 15, register #1 (control register) */ +static unsigned long read_p15_c1 (void) +{ +	unsigned long value; + +	__asm__ __volatile__( +		"mrc	p15, 0, %0, c1, c0, 0   @ read control reg\n" +		: "=r" (value) +		: +		: "memory"); + +#ifdef MMU_DEBUG +	printf ("p15/c1 is = %08lx\n", value); +#endif +	return value; +} + +/* write to co-processor 15, register #1 (control register) */ +static void write_p15_c1 (unsigned long value) +{ +#ifdef MMU_DEBUG +	printf ("write %08lx to p15/c1\n", value); +#endif +	__asm__ __volatile__( +		"mcr	p15, 0, %0, c1, c0, 0   @ write it back\n" +		: +		: "r" (value) +		: "memory"); + +	read_p15_c1 (); +} + +static void cp_delay (void) +{ +	volatile int i; + +	/* Many OMAP regs need at least 2 nops  */ +	for (i = 0; i < 100; i++); +} + +/* See also ARM Ref. Man. */ +#define C1_MMU		(1<<0)		/* mmu off/on */ +#define C1_ALIGN	(1<<1)		/* alignment faults off/on */ +#define C1_DC		(1<<2)		/* dcache off/on */ +#define C1_WB		(1<<3)		/* merging write buffer on/off */ +#define C1_BIG_ENDIAN	(1<<7)	/* big endian off/on */ +#define C1_SYS_PROT	(1<<8)		/* system protection */ +#define C1_ROM_PROT	(1<<9)		/* ROM protection */ +#define C1_IC		(1<<12)		/* icache off/on */ +#define C1_HIGH_VECTORS	(1<<13)	/* location of vectors: low/high addresses */ +#define RESERVED_1	(0xf << 3)	/* must be 111b for R/W */ + +int cpu_init (void) +{ +	/* +	 * setup up stack if necessary +	 */ +#ifdef CONFIG_USE_IRQ +	IRQ_STACK_START = _armboot_end + +			CONFIG_STACKSIZE + CONFIG_STACKSIZE_IRQ - 4; +	FIQ_STACK_START = IRQ_STACK_START + CONFIG_STACKSIZE_FIQ; +	_armboot_real_end = FIQ_STACK_START + 4; +#else +	_armboot_real_end = _armboot_end + CONFIG_STACKSIZE; +#endif	/* CONFIG_USE_IRQ */ +	return (0); +} + +int cleanup_before_linux (void) +{ +	/* +	 * this function is called just before we call linux +	 * it prepares the processor for linux +	 * +	 * we turn off caches etc ... +	 */ + +	unsigned long i; + +	disable_interrupts (); + +	/* turn off I/D-cache */ +	asm ("mrc p15, 0, %0, c1, c0, 0":"=r" (i)); +	i &= ~(C1_DC | C1_IC); +	asm ("mcr p15, 0, %0, c1, c0, 0": :"r" (i)); + +	/* flush I/D-cache */ +	i = 0; +	asm ("mcr p15, 0, %0, c7, c7, 0": :"r" (i)); +	return (0); +} + +int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ +	extern void reset_cpu (ulong addr); + +	disable_interrupts (); +	reset_cpu (0); +	/*NOTREACHED*/ +	return (0); +} + +void icache_enable (void) +{ +	ulong reg; + +	reg = read_p15_c1 ();		/* get control reg. */ +	cp_delay (); +	write_p15_c1 (reg | C1_IC); +} + +void icache_disable (void) +{ +	ulong reg; + +	reg = read_p15_c1 (); +	cp_delay (); +	write_p15_c1 (reg & ~C1_IC); +} + +int icache_status (void) +{ +	return (read_p15_c1 () & C1_IC) != 0; +} diff --git a/cpu/arm926ejs/interrupts.c b/cpu/arm926ejs/interrupts.c new file mode 100644 index 000000000..c0086dda9 --- /dev/null +++ b/cpu/arm926ejs/interrupts.c @@ -0,0 +1,293 @@ +/* + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Marius Groeger <mgroeger@sysgo.de> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Alex Zuepke <azu@sysgo.de> + * + * (C) Copyright 2002 + * Gary Jennejohn, DENX Software Engineering, <gj@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 <arm925t.h> +#include <configs/omap1510.h> + +#include <asm/proc-armv/ptrace.h> + +extern void reset_cpu(ulong addr); +#define TIMER_LOAD_VAL 0xffffffff + +/* macro to read the 32 bit timer */ +#define READ_TIMER (*(volatile ulong *)(CFG_TIMERBASE+8)) + +#ifdef CONFIG_USE_IRQ +/* enable IRQ interrupts */ +void enable_interrupts (void) +{ +	unsigned long temp; +	__asm__ __volatile__("mrs %0, cpsr\n" +		"bic %0, %0, #0x80\n" +		"msr cpsr_c, %0" +		: "=r" (temp) +		: "memory"); +} + +/* + * disable IRQ/FIQ interrupts + * returns true if interrupts had been enabled before we disabled them + */ +int disable_interrupts (void) +{ +	unsigned long old,temp; +	__asm__ __volatile__("mrs %0, cpsr\n" +		"orr %1, %0, #0xc0\n" +		"msr cpsr_c, %1" +		: "=r" (old), "=r" (temp) +		: "memory"); +	return (old & 0x80) == 0; +} +#else +void enable_interrupts (void) +{ +	return; +} +int disable_interrupts (void) +{ +	return 0; +} +#endif + + + +void bad_mode (void) +{ +	panic ("Resetting CPU ...\n"); +	reset_cpu (0); +} + +void show_regs (struct pt_regs *regs) +{ +	unsigned long flags; +	const char *processor_modes[] = { +	"USER_26",	"FIQ_26",	"IRQ_26",	"SVC_26", +	"UK4_26",	"UK5_26",	"UK6_26",	"UK7_26", +	"UK8_26",	"UK9_26",	"UK10_26",	"UK11_26", +	"UK12_26",	"UK13_26",	"UK14_26",	"UK15_26", +	"USER_32",	"FIQ_32",	"IRQ_32",	"SVC_32", +	"UK4_32",	"UK5_32",	"UK6_32",	"ABT_32", +	"UK8_32",	"UK9_32",	"UK10_32",	"UND_32", +	"UK12_32",	"UK13_32",	"UK14_32",	"SYS_32", +	}; + +	flags = condition_codes (regs); + +	printf ("pc : [<%08lx>]    lr : [<%08lx>]\n" +		"sp : %08lx  ip : %08lx  fp : %08lx\n", +		instruction_pointer (regs), +		regs->ARM_lr, regs->ARM_sp, regs->ARM_ip, regs->ARM_fp); +	printf ("r10: %08lx  r9 : %08lx  r8 : %08lx\n", +		regs->ARM_r10, regs->ARM_r9, regs->ARM_r8); +	printf ("r7 : %08lx  r6 : %08lx  r5 : %08lx  r4 : %08lx\n", +		regs->ARM_r7, regs->ARM_r6, regs->ARM_r5, regs->ARM_r4); +	printf ("r3 : %08lx  r2 : %08lx  r1 : %08lx  r0 : %08lx\n", +		regs->ARM_r3, regs->ARM_r2, regs->ARM_r1, regs->ARM_r0); +	printf ("Flags: %c%c%c%c", +		flags & CC_N_BIT ? 'N' : 'n', +		flags & CC_Z_BIT ? 'Z' : 'z', +		flags & CC_C_BIT ? 'C' : 'c', flags & CC_V_BIT ? 'V' : 'v'); +	printf ("  IRQs %s  FIQs %s  Mode %s%s\n", +		interrupts_enabled (regs) ? "on" : "off", +		fast_interrupts_enabled (regs) ? "on" : "off", +		processor_modes[processor_mode (regs)], +		thumb_mode (regs) ? " (T)" : ""); +} + +void do_undefined_instruction (struct pt_regs *pt_regs) +{ +	printf ("undefined instruction\n"); +	show_regs (pt_regs); +	bad_mode (); +} + +void do_software_interrupt (struct pt_regs *pt_regs) +{ +	printf ("software interrupt\n"); +	show_regs (pt_regs); +	bad_mode (); +} + +void do_prefetch_abort (struct pt_regs *pt_regs) +{ +	printf ("prefetch abort\n"); +	show_regs (pt_regs); +	bad_mode (); +} + +void do_data_abort (struct pt_regs *pt_regs) +{ +	printf ("data abort\n"); +	show_regs (pt_regs); +	bad_mode (); +} + +void do_not_used (struct pt_regs *pt_regs) +{ +	printf ("not used\n"); +	show_regs (pt_regs); +	bad_mode (); +} + +void do_fiq (struct pt_regs *pt_regs) +{ +	printf ("fast interrupt request\n"); +	show_regs (pt_regs); +	bad_mode (); +} + +void do_irq (struct pt_regs *pt_regs) +{ +	printf ("interrupt request\n"); +	show_regs (pt_regs); +	bad_mode (); +} + +static ulong timestamp; +static ulong lastdec; + +/* nothing really to do with interrupts, just starts up a counter. */ +int interrupt_init (void) +{ +	int32_t val; + +	*((int32_t *) (CFG_TIMERBASE + LOAD_TIM)) = TIMER_LOAD_VAL; +	val = MPUTIM_ST | MPUTIM_AR | MPUTIM_CLOCK_ENABLE | +			(CFG_PVT << MPUTIM_PTV_BIT); +	*((int32_t *) (CFG_TIMERBASE + CNTL_TIMER)) = val; +	return (0); +} + +/* + * timer without interrupts + */ + +void reset_timer (void) +{ +	reset_timer_masked (); +} + +ulong get_timer (ulong base) +{ +	return get_timer_masked () - base; +} + +void set_timer (ulong t) +{ +	timestamp = t; +} + +/* very rough timer... */ +void udelay (unsigned long usec) +{ +#ifdef CONFIG_INNOVATOROMAP1610 +#define LOOPS_PER_MSEC 100		/* tuned on omap1610 */ +	volatile int i, time_remaining = LOOPS_PER_MSEC * usec; + +	for (i = time_remaining; i > 0; i--) { +	} +#else + +	ulong tmo; +	tmo = usec / 1000; +	tmo *= CFG_HZ; +	tmo /= 1000; +	tmo += get_timer (0); +	while (get_timer_masked () < tmo) +		/*NOP*/; +#endif +} + +void reset_timer_masked (void) +{ +	/* reset time */ +	lastdec = READ_TIMER; +	timestamp = 0; +} + +ulong get_timer_masked (void) +{ +	ulong now = READ_TIMER;		/* current tick value */ + +	if (lastdec >= now) {		/* did I roll (rem decrementer) */ +		/* normal mode */ +		/* record amount of time since last check */ +		timestamp += lastdec - now; +	} else { +		/* we have an overflow ... */ +		timestamp += lastdec + TIMER_LOAD_VAL - now; +	} +	lastdec = now; + +	return timestamp; +} + +void udelay_masked (unsigned long usec) +{ +#ifdef CONFIG_INNOVATOROMAP1610 +	#define LOOPS_PER_MSEC 100 /* tuned on omap1610 */ +	volatile int i, time_remaining = LOOPS_PER_MSEC*usec; +	for (i=time_remaining; i>0; i--) { } +#else + +	ulong tmo; + +	tmo = usec / 1000; +	tmo *= CFG_HZ; +	tmo /= 1000; + +	reset_timer_masked (); + +	while (get_timer_masked () < tmo) +		/*NOP*/; +#endif +} + +/* + * This function is derived from PowerPC code (read timebase as long long). + * On ARM 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 ARM it returns the number of timer ticks per second. + */ +ulong get_tbclk (void) +{ +	ulong tbclk; +	tbclk = CFG_HZ; +	return tbclk; +} diff --git a/cpu/arm926ejs/start.S b/cpu/arm926ejs/start.S new file mode 100644 index 000000000..08b2bbcb2 --- /dev/null +++ b/cpu/arm926ejs/start.S @@ -0,0 +1,426 @@ +/* + *  armboot - Startup Code for ARM926EJS CPU-core + * + *  Copyright (c) 2003  Texas Instruments + * + *  ----- Adapted for OMAP1610 from ARM925t code ------ + * + *  Copyright (c) 2001	Marius Gröger <mag@sysgo.de> + *  Copyright (c) 2002	Alex Züpke <azu@sysgo.de> + *  Copyright (c) 2002	Gary Jennejohn <gj@denx.de> + *  Copyright (c) 2003	Richard Woodruff <r-woodruff2@ti.com> + *  Copyright (c) 2003	Kshitij <kshitij@ti.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 <config.h> +#include <version.h> + +#if defined(CONFIG_OMAP1610) +#include <./configs/omap1510.h> +#endif + +/* + ************************************************************************* + * + * Jump vector table as in table 3.1 in [1] + * + ************************************************************************* + */ + + +.globl _start +_start: +	b	reset +	ldr	pc, _undefined_instruction +	ldr	pc, _software_interrupt +	ldr	pc, _prefetch_abort +	ldr	pc, _data_abort +	ldr	pc, _not_used +	ldr	pc, _irq +	ldr	pc, _fiq + +_undefined_instruction: +	.word undefined_instruction +_software_interrupt: +	.word software_interrupt +_prefetch_abort: +	.word prefetch_abort +_data_abort: +	.word data_abort +_not_used: +	.word not_used +_irq: +	.word irq +_fiq: +	.word fiq + +	.balignl 16,0xdeadbeef + + +/* + ************************************************************************* + * + * Startup Code (reset vector) + * + * do important init only if we don't start from memory! + * setup Memory and board specific bits prior to relocation. + * relocate armboot to ram + * setup stack + * + ************************************************************************* + */ + +/* + * CFG_MEM_END is in the board dependent config-file (configs/config_BOARD.h) + */ +_TEXT_BASE: +	.word	TEXT_BASE + +.globl _armboot_start +_armboot_start: +	.word _start + +/* + * Note: _armboot_end_data and _armboot_end are defined + * by the (board-dependent) linker script. + * _armboot_end_data is the first usable FLASH address after armboot + */ +.globl _armboot_end_data +_armboot_end_data: +	.word armboot_end_data +.globl _armboot_end +_armboot_end: +	.word armboot_end + +/* + * _armboot_real_end is the first usable RAM address behind armboot + * and the various stacks + */ +.globl _armboot_real_end +_armboot_real_end: +	.word 0x0badc0de + +#ifdef CONFIG_USE_IRQ +/* IRQ stack memory (calculated at run-time) */ +.globl IRQ_STACK_START +IRQ_STACK_START: +	.word	0x0badc0de + +/* IRQ stack memory (calculated at run-time) */ +.globl FIQ_STACK_START +FIQ_STACK_START: +	.word 0x0badc0de +#endif + + +/* + * the actual reset code + */ + +reset: +	/* +	 * set the cpu to SVC32 mode +	 */ +	mrs	r0,cpsr +	bic	r0,r0,#0x1f +	orr	r0,r0,#0xd3 +	msr	cpsr,r0 + + +	/*  +	 * turn off the watchdog, unlock/diable sequence +	 */ +	mov	r1, #0xF5 +	ldr	r0, =WDTIM_MODE +	strh	r1, [r0] +	mov	r1, #0xA0 +	strh	r1, [r0] + + + + + +	/* +	 * mask all IRQs by setting all bits in the INTMR - default +	 */ + +	mov	r1, #0xffffffff +	ldr	r0, =REG_IHL1_MIR +	str	r1, [r0] +	ldr	r0, =REG_IHL2_MIR +	str	r1, [r0] +	bl	cpu_init_crit + +relocate: +	/* +	 * relocate armboot to RAM +	 */ +	adr	r0, _start		/* r0 <- current position of code */ +	ldr	r2, _armboot_start +	ldr	r3, _armboot_end +	sub	r2, r3, r2		/* r2 <- size of armboot */ +	ldr	r1, _TEXT_BASE		/* r1 <- destination address */ +	add	r2, r0, r2		/* r2 <- source end address */ + +	/* +	 * r0 = source address +	 * r1 = target address +	 * r2 = source end address +	 */ +copy_loop: +	ldmia	r0!, {r3-r10} +	stmia	r1!, {r3-r10} +	cmp	r0, r2 +	ble	copy_loop + +	/* set up the stack */ +	ldr	r0, _armboot_end +	add	r0, r0, #CONFIG_STACKSIZE +	sub	sp, r0, #12		/* leave 3 words for abort-stack */ + +	ldr	pc, _start_armboot + +_start_armboot: +	.word start_armboot + + +/* + ************************************************************************* + * + * CPU_init_critical registers + * + * setup important registers + * setup memory timing + * + ************************************************************************* + */ + + +cpu_init_crit: +	/* +	 * flush v4 I/D caches +	 */ +	mov	r0, #0 +	mcr	p15, 0, r0, c7, c7, 0	/* flush v3/v4 cache */ +	mcr	p15, 0, r0, c8, c7, 0	/* flush v4 TLB */ + +	/* +	 * disable MMU stuff and caches +	 */ +	mrc	p15, 0, r0, c1, c0, 0 +	bic	r0, r0, #0x00002300	/* clear bits 13, 9:8 (--V- --RS) */ +	bic	r0, r0, #0x00000087	/* clear bits 7, 2:0 (B--- -CAM) */ +	orr	r0, r0, #0x00000002	/* set bit 2 (A) Align */ +	orr	r0, r0, #0x00001000	/* set bit 12 (I) I-Cache */ +	mcr	p15, 0, r0, c1, c0, 0 + +	/* +	 * Go setup Memory and board specific bits prior to relocation. +	 */ +	mov	ip, lr		/* perserve link reg across call */ +	bl	platformsetup	/* go setup pll,mux,memory */ +	mov	lr, ip		/* restore link */ +	mov	pc, lr		/* back to my caller */ +/* + ************************************************************************* + * + * Interrupt handling + * + ************************************************************************* + */ + +@ +@ IRQ stack frame. +@ +#define S_FRAME_SIZE	72 + +#define S_OLD_R0	68 +#define S_PSR		64 +#define S_PC		60 +#define S_LR		56 +#define S_SP		52 + +#define S_IP		48 +#define S_FP		44 +#define S_R10		40 +#define S_R9		36 +#define S_R8		32 +#define S_R7		28 +#define S_R6		24 +#define S_R5		20 +#define S_R4		16 +#define S_R3		12 +#define S_R2		8 +#define S_R1		4 +#define S_R0		0 + +#define MODE_SVC 0x13 +#define I_BIT	 0x80 + +/* + * use bad_save_user_regs for abort/prefetch/undef/swi ... + * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling + */ + +	.macro	bad_save_user_regs +	@ carve out a frame on current user stack +	sub	sp, sp, #S_FRAME_SIZE +	stmia	sp, {r0 - r12}	@ Save user registers (now in svc mode) r0-r12 +	ldr	r2, _armboot_end	@ find top of stack +	add	r2, r2, #CONFIG_STACKSIZE	@ find base of normal stack +	sub	r2, r2, #8	@ set base 2 words into abort stack +	@ get values for "aborted" pc and cpsr (into parm regs) +	ldmia	r2, {r2 - r3} +	add	r0, sp, #S_FRAME_SIZE		@ grab pointer to old stack +	add	r5, sp, #S_SP +	mov	r1, lr +	stmia	r5, {r0 - r3}	@ save sp_SVC, lr_SVC, pc, cpsr +	mov	r0, sp		@ save current stack into r0 (param register) +	.endm + +	.macro	irq_save_user_regs +	sub	sp, sp, #S_FRAME_SIZE +	stmia	sp, {r0 - r12}			@ Calling r0-r12 +	@ !!!! R8 NEEDS to be saved !!!! a reserved stack spot would be good. +	add	r8, sp, #S_PC +	stmdb	r8, {sp, lr}^		@ Calling SP, LR +	str	lr, [r8, #0]		@ Save calling PC +	mrs	r6, spsr +	str	r6, [r8, #4]		@ Save CPSR +	str	r0, [r8, #8]		@ Save OLD_R0 +	mov	r0, sp +	.endm + +	.macro	irq_restore_user_regs +	ldmia	sp, {r0 - lr}^			@ Calling r0 - lr +	mov	r0, r0 +	ldr	lr, [sp, #S_PC]			@ Get PC +	add	sp, sp, #S_FRAME_SIZE +	subs	pc, lr, #4		@ return & move spsr_svc into cpsr +	.endm + +	.macro get_bad_stack +	@ get bottom of stack (into sp by by user stack pointer). +	ldr	r13, _armboot_end +	@ head to reserved words at the top of the stack +	add	r13, r13, #CONFIG_STACKSIZE +	sub	r13, r13, #8	@ reserved a couple spots in abort stack + +	str	lr, [r13]	@ save caller lr in position 0 of saved stack +	mrs	lr, spsr	@ get the spsr +	str	lr, [r13, #4]	@ save spsr in position 1 of saved stack +	mov	r13, #MODE_SVC	@ prepare SVC-Mode +	@ msr	spsr_c, r13 +	msr	spsr, r13	@ switch modes, make sure moves will execute +	mov	lr, pc		@ capture return pc +	movs	pc, lr		@ jump to next instruction & switch modes. +	.endm + +	.macro get_irq_stack			@ setup IRQ stack +	ldr	sp, IRQ_STACK_START +	.endm + +	.macro get_fiq_stack			@ setup FIQ stack +	ldr	sp, FIQ_STACK_START +	.endm + +/* + * exception handlers + */ +	.align  5 +undefined_instruction: +	get_bad_stack +	bad_save_user_regs +	bl	do_undefined_instruction + +	.align	5 +software_interrupt: +	get_bad_stack +	bad_save_user_regs +	bl	do_software_interrupt + +	.align	5 +prefetch_abort: +	get_bad_stack +	bad_save_user_regs +	bl	do_prefetch_abort + +	.align	5 +data_abort: +	get_bad_stack +	bad_save_user_regs +	bl	do_data_abort + +	.align	5 +not_used: +	get_bad_stack +	bad_save_user_regs +	bl	do_not_used + +#ifdef CONFIG_USE_IRQ + +	.align	5 +irq: +	get_irq_stack +	irq_save_user_regs +	bl 	do_irq +	irq_restore_user_regs + +	.align	5 +fiq: +	get_fiq_stack +	/* someone ought to write a more effiction fiq_save_user_regs */ +	irq_save_user_regs +	bl 	do_fiq +	irq_restore_user_regs + +#else + +	.align	5 +irq: +	get_bad_stack +	bad_save_user_regs +	bl	do_irq + +	.align	5 +fiq: +	get_bad_stack +	bad_save_user_regs +	bl	do_fiq + +#endif + +	.align	5 +.globl reset_cpu +reset_cpu: +	ldr	r1, rstctl1	/* get clkm1 reset ctl */ +	mov	r3, #0x0	 +	strh	r3, [r1]	/* clear it */ +	mov	r3, #0x8 +	strh	r3, [r1]	/* force dsp+arm reset */ +_loop_forever: +	b	_loop_forever + + +rstctl1: +	.word	0xfffece10  |