xref: /openbmc/u-boot/arch/arm/cpu/arm1176/start.S (revision 8343f8a76434b7162cf5a4da5f456b014868853c)
1/*
2 *  armboot - Startup Code for ARM1176 CPU-core
3 *
4 * Copyright (c) 2007	Samsung Electronics
5 *
6 * Copyright (C) 2008
7 * Guennadi Liakhovetki, DENX Software Engineering, <lg@denx.de>
8 *
9 * See file CREDITS for list of people who contributed to this
10 * project.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License as
14 * published by the Free Software Foundation; either version 2 of
15 * the License, or (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
25 * MA 02111-1307 USA
26 *
27 * 2007-09-21 - Restructured codes by jsgood (jsgood.yang@samsung.com)
28 * 2007-09-21 - Added MoviNAND and OneNAND boot codes by
29 * jsgood (jsgood.yang@samsung.com)
30 * Base codes by scsuh (sc.suh)
31 */
32
33#include <asm-offsets.h>
34#include <config.h>
35#include <version.h>
36#ifdef CONFIG_ENABLE_MMU
37#include <asm/proc/domain.h>
38#endif
39
40#if !defined(CONFIG_ENABLE_MMU) && !defined(CONFIG_SYS_PHY_UBOOT_BASE)
41#define CONFIG_SYS_PHY_UBOOT_BASE	CONFIG_SYS_UBOOT_BASE
42#endif
43
44/*
45 *************************************************************************
46 *
47 * Jump vector table as in table 3.1 in [1]
48 *
49 *************************************************************************
50 */
51
52.globl _start
53_start: b	reset
54#ifndef CONFIG_NAND_SPL
55	ldr	pc, _undefined_instruction
56	ldr	pc, _software_interrupt
57	ldr	pc, _prefetch_abort
58	ldr	pc, _data_abort
59	ldr	pc, _not_used
60	ldr	pc, _irq
61	ldr	pc, _fiq
62
63_undefined_instruction:
64	.word undefined_instruction
65_software_interrupt:
66	.word software_interrupt
67_prefetch_abort:
68	.word prefetch_abort
69_data_abort:
70	.word data_abort
71_not_used:
72	.word not_used
73_irq:
74	.word irq
75_fiq:
76	.word fiq
77_pad:
78	.word 0x12345678 /* now 16*4=64 */
79#else
80	. = _start + 64
81#endif
82
83.global _end_vect
84_end_vect:
85	.balignl 16,0xdeadbeef
86/*
87 *************************************************************************
88 *
89 * Startup Code (reset vector)
90 *
91 * do important init only if we don't start from memory!
92 * setup Memory and board specific bits prior to relocation.
93 * relocate armboot to ram
94 * setup stack
95 *
96 *************************************************************************
97 */
98
99.globl _TEXT_BASE
100_TEXT_BASE:
101	.word	CONFIG_SYS_TEXT_BASE
102
103/*
104 * Below variable is very important because we use MMU in U-Boot.
105 * Without it, we cannot run code correctly before MMU is ON.
106 * by scsuh.
107 */
108_TEXT_PHY_BASE:
109	.word	CONFIG_SYS_PHY_UBOOT_BASE
110
111#if defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
112.globl _armboot_start
113_armboot_start:
114	.word _start
115#endif
116
117/*
118 * These are defined in the board-specific linker script.
119 * Subtracting _start from them lets the linker put their
120 * relative position in the executable instead of leaving
121 * them null.
122 */
123
124.globl _bss_start_ofs
125_bss_start_ofs:
126	.word __bss_start - _start
127
128.globl _bss_end_ofs
129_bss_end_ofs:
130	.word _end - _start
131
132.globl _datarel_start_ofs
133_datarel_start_ofs:
134	.word __datarel_start - _start
135
136.globl _datarelrolocal_start_ofs
137_datarelrolocal_start_ofs:
138	.word __datarelrolocal_start - _start
139
140.globl _datarellocal_start_ofs
141_datarellocal_start_ofs:
142	.word __datarellocal_start - _start
143
144.globl _datarelro_start_ofs
145_datarelro_start_ofs:
146	.word __datarelro_start - _start
147
148.globl _rel_dyn_start_ofs
149_rel_dyn_start_ofs:
150	.word __rel_dyn_start - _start
151
152.globl _rel_dyn_end_ofs
153_rel_dyn_end_ofs:
154	.word __rel_dyn_end - _start
155
156.globl _dynsym_start_ofs
157_dynsym_start_ofs:
158	.word __dynsym_start - _start
159
160#if !defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
161/* IRQ stack memory (calculated at run-time) + 8 bytes */
162.globl IRQ_STACK_START_IN
163IRQ_STACK_START_IN:
164	.word	0x0badc0de
165
166/*
167 * the actual reset code
168 */
169
170reset:
171	/*
172	 * set the cpu to SVC32 mode
173	 */
174	mrs	r0, cpsr
175	bic	r0, r0, #0x3f
176	orr	r0, r0, #0xd3
177	msr	cpsr, r0
178
179/*
180 *************************************************************************
181 *
182 * CPU_init_critical registers
183 *
184 * setup important registers
185 * setup memory timing
186 *
187 *************************************************************************
188 */
189	/*
190	 * we do sys-critical inits only at reboot,
191	 * not when booting from ram!
192	 */
193cpu_init_crit:
194	/*
195	 * When booting from NAND - it has definitely been a reset, so, no need
196	 * to flush caches and disable the MMU
197	 */
198#ifndef CONFIG_NAND_SPL
199	/*
200	 * flush v4 I/D caches
201	 */
202	mov	r0, #0
203	mcr	p15, 0, r0, c7, c7, 0	/* flush v3/v4 cache */
204	mcr	p15, 0, r0, c8, c7, 0	/* flush v4 TLB */
205
206	/*
207	 * disable MMU stuff and caches
208	 */
209	mrc	p15, 0, r0, c1, c0, 0
210	bic	r0, r0, #0x00002300	@ clear bits 13, 9:8 (--V- --RS)
211	bic	r0, r0, #0x00000087	@ clear bits 7, 2:0 (B--- -CAM)
212	orr	r0, r0, #0x00000002	@ set bit 2 (A) Align
213	orr	r0, r0, #0x00001000	@ set bit 12 (I) I-Cache
214
215	/* Prepare to disable the MMU */
216	adr	r2, mmu_disable_phys
217	sub	r2, r2, #(CONFIG_SYS_PHY_UBOOT_BASE - CONFIG_SYS_TEXT_BASE)
218	b	mmu_disable
219
220	.align 5
221	/* Run in a single cache-line */
222mmu_disable:
223	mcr	p15, 0, r0, c1, c0, 0
224	nop
225	nop
226	mov	pc, r2
227mmu_disable_phys:
228
229#ifdef CONFIG_DISABLE_TCM
230	/*
231	 * Disable the TCMs
232	 */
233	mrc	p15, 0, r0, c0, c0, 2	/* Return TCM details */
234	cmp	r0, #0
235	beq	skip_tcmdisable
236	mov	r1, #0
237	mov	r2, #1
238	tst	r0, r2
239	mcrne	p15, 0, r1, c9, c1, 1	/* Disable Instruction TCM if present*/
240	tst	r0, r2, LSL #16
241	mcrne	p15, 0, r1, c9, c1, 0	/* Disable Data TCM if present*/
242skip_tcmdisable:
243#endif
244#endif
245
246#ifdef CONFIG_PERIPORT_REMAP
247	/* Peri port setup */
248	ldr	r0, =CONFIG_PERIPORT_BASE
249	orr	r0, r0, #CONFIG_PERIPORT_SIZE
250	mcr	p15,0,r0,c15,c2,4
251#endif
252
253	/*
254	 * Go setup Memory and board specific bits prior to relocation.
255	 */
256	bl	lowlevel_init		/* go setup pll,mux,memory */
257
258/* Set stackpointer in internal RAM to call board_init_f */
259call_board_init_f:
260	ldr	sp, =(CONFIG_SYS_INIT_SP_ADDR)
261	ldr	r0,=0x00000000
262	bl	board_init_f
263
264/*------------------------------------------------------------------------------*/
265
266/*
267 * void relocate_code (addr_sp, gd, addr_moni)
268 *
269 * This "function" does not return, instead it continues in RAM
270 * after relocating the monitor code.
271 *
272 */
273	.globl	relocate_code
274relocate_code:
275	mov	r4, r0	/* save addr_sp */
276	mov	r5, r1	/* save addr of gd */
277	mov	r6, r2	/* save addr of destination */
278	mov	r7, r2	/* save addr of destination */
279
280	/* Set up the stack						    */
281stack_setup:
282	mov	sp, r4
283
284	adr	r0, _start
285	ldr	r2, _TEXT_BASE
286	ldr	r3, _bss_start_ofs
287	add	r2, r0, r3		/* r2 <- source end address	    */
288	cmp	r0, r6
289	beq	clear_bss
290
291#ifndef CONFIG_SKIP_RELOCATE_UBOOT
292copy_loop:
293	ldmia	r0!, {r9-r10}		/* copy from source address [r0]    */
294	stmia	r6!, {r9-r10}		/* copy to   target address [r1]    */
295	cmp	r0, r2			/* until source end address [r2]    */
296	blo	copy_loop
297
298#ifndef CONFIG_PRELOADER
299	/*
300	 * fix .rel.dyn relocations
301	 */
302	ldr	r0, _TEXT_BASE		/* r0 <- Text base */
303	sub	r9, r7, r0		/* r9 <- relocation offset */
304	ldr	r10, _dynsym_start_ofs	/* r10 <- sym table ofs */
305	add	r10, r10, r0		/* r10 <- sym table in FLASH */
306	ldr	r2, _rel_dyn_start_ofs	/* r2 <- rel dyn start ofs */
307	add	r2, r2, r0		/* r2 <- rel dyn start in FLASH */
308	ldr	r3, _rel_dyn_end_ofs	/* r3 <- rel dyn end ofs */
309	add	r3, r3, r0		/* r3 <- rel dyn end in FLASH */
310fixloop:
311	ldr	r0, [r2]	/* r0 <- location to fix up, IN FLASH! */
312	add	r0, r0, r9	/* r0 <- location to fix up in RAM */
313	ldr	r1, [r2, #4]
314	and	r8, r1, #0xff
315	cmp	r8, #23		/* relative fixup? */
316	beq	fixrel
317	cmp	r8, #2		/* absolute fixup? */
318	beq	fixabs
319	/* ignore unknown type of fixup */
320	b	fixnext
321fixabs:
322	/* absolute fix: set location to (offset) symbol value */
323	mov	r1, r1, LSR #4		/* r1 <- symbol index in .dynsym */
324	add	r1, r10, r1		/* r1 <- address of symbol in table */
325	ldr	r1, [r1, #4]		/* r1 <- symbol value */
326	add	r1, r1, r9		/* r1 <- relocated sym addr */
327	b	fixnext
328fixrel:
329	/* relative fix: increase location by offset */
330	ldr	r1, [r0]
331	add	r1, r1, r9
332fixnext:
333	str	r1, [r0]
334	add	r2, r2, #8	/* each rel.dyn entry is 8 bytes */
335	cmp	r2, r3
336	blo	fixloop
337#endif
338#endif	/* #ifndef CONFIG_SKIP_RELOCATE_UBOOT */
339
340#ifdef CONFIG_ENABLE_MMU
341enable_mmu:
342	/* enable domain access */
343	ldr	r5, =0x0000ffff
344	mcr	p15, 0, r5, c3, c0, 0	/* load domain access register */
345
346	/* Set the TTB register */
347	ldr	r0, _mmu_table_base
348	ldr	r1, =CONFIG_SYS_PHY_UBOOT_BASE
349	ldr	r2, =0xfff00000
350	bic	r0, r0, r2
351	orr	r1, r0, r1
352	mcr	p15, 0, r1, c2, c0, 0
353
354	/* Enable the MMU */
355	mrc	p15, 0, r0, c1, c0, 0
356	orr	r0, r0, #1		/* Set CR_M to enable MMU */
357
358	/* Prepare to enable the MMU */
359	adr	r1, skip_hw_init
360	and	r1, r1, #0x3fc
361	ldr	r2, _TEXT_BASE
362	ldr	r3, =0xfff00000
363	and	r2, r2, r3
364	orr	r2, r2, r1
365	b	mmu_enable
366
367	.align 5
368	/* Run in a single cache-line */
369mmu_enable:
370
371	mcr	p15, 0, r0, c1, c0, 0
372	nop
373	nop
374	mov	pc, r2
375skip_hw_init:
376#endif
377
378clear_bss:
379#ifndef CONFIG_PRELOADER
380	ldr	r0, _bss_start_ofs
381	ldr	r1, _bss_end_ofs
382	ldr	r3, _TEXT_BASE		/* Text base */
383	mov	r4, r7			/* reloc addr */
384	add	r0, r0, r4
385	add	r1, r1, r4
386	mov	r2, #0x00000000		/* clear			    */
387
388clbss_l:str	r2, [r0]		/* clear loop...		    */
389	add	r0, r0, #4
390	cmp	r0, r1
391	bne	clbss_l
392
393	bl coloured_LED_init
394	bl red_LED_on
395#endif
396
397/*
398 * We are done. Do not return, instead branch to second part of board
399 * initialization, now running from RAM.
400 */
401#ifdef CONFIG_NAND_SPL
402	ldr     pc, _nand_boot
403
404_nand_boot: .word nand_boot
405#else
406	ldr	r0, _board_init_r_ofs
407	adr	r1, _start
408	add	lr, r0, r1
409#ifndef CONFIG_SKIP_RELOCATE_UBOOT
410	add     lr, lr, r9
411#endif
412	/* setup parameters for board_init_r */
413	mov	r0, r5		/* gd_t */
414	mov	r1, r7		/* dest_addr */
415	/* jump to it ... */
416	mov	pc, lr
417
418_board_init_r_ofs:
419	.word board_init_r - _start
420#endif
421
422#else /* #if !defined(CONFIG_SYS_ARM_WITHOUT_RELOC) */
423
424/*
425 * the actual reset code
426 */
427
428reset:
429	/*
430	 * set the cpu to SVC32 mode
431	 */
432	mrs	r0, cpsr
433	bic	r0, r0, #0x3f
434	orr	r0, r0, #0xd3
435	msr	cpsr, r0
436
437/*
438 *************************************************************************
439 *
440 * CPU_init_critical registers
441 *
442 * setup important registers
443 * setup memory timing
444 *
445 *************************************************************************
446 */
447	/*
448	 * we do sys-critical inits only at reboot,
449	 * not when booting from ram!
450	 */
451cpu_init_crit:
452	/*
453	 * When booting from NAND - it has definitely been a reset, so, no need
454	 * to flush caches and disable the MMU
455	 */
456#ifndef CONFIG_NAND_SPL
457	/*
458	 * flush v4 I/D caches
459	 */
460	mov	r0, #0
461	mcr	p15, 0, r0, c7, c7, 0	/* flush v3/v4 cache */
462	mcr	p15, 0, r0, c8, c7, 0	/* flush v4 TLB */
463
464	/*
465	 * disable MMU stuff and caches
466	 */
467	mrc	p15, 0, r0, c1, c0, 0
468	bic	r0, r0, #0x00002300	@ clear bits 13, 9:8 (--V- --RS)
469	bic	r0, r0, #0x00000087	@ clear bits 7, 2:0 (B--- -CAM)
470	orr	r0, r0, #0x00000002	@ set bit 2 (A) Align
471	orr	r0, r0, #0x00001000	@ set bit 12 (I) I-Cache
472
473	/* Prepare to disable the MMU */
474	adr	r2, mmu_disable_phys
475	sub	r2, r2, #(CONFIG_SYS_PHY_UBOOT_BASE - CONFIG_SYS_TEXT_BASE)
476	b	mmu_disable
477
478	.align 5
479	/* Run in a single cache-line */
480mmu_disable:
481	mcr	p15, 0, r0, c1, c0, 0
482	nop
483	nop
484	mov	pc, r2
485mmu_disable_phys:
486
487#ifdef CONFIG_DISABLE_TCM
488	/*
489	 * Disable the TCMs
490	 */
491	mrc	p15, 0, r0, c0, c0, 2	/* Return TCM details */
492	cmp	r0, #0
493	beq	skip_tcmdisable
494	mov	r1, #0
495	mov	r2, #1
496	tst	r0, r2
497	mcrne	p15, 0, r1, c9, c1, 1	/* Disable Instruction TCM if present*/
498	tst	r0, r2, LSL #16
499	mcrne	p15, 0, r1, c9, c1, 0	/* Disable Data TCM if present*/
500skip_tcmdisable:
501#endif
502#endif
503
504#ifdef CONFIG_PERIPORT_REMAP
505	/* Peri port setup */
506	ldr	r0, =CONFIG_PERIPORT_BASE
507	orr	r0, r0, #CONFIG_PERIPORT_SIZE
508	mcr	p15,0,r0,c15,c2,4
509#endif
510
511	/*
512	 * Go setup Memory and board specific bits prior to relocation.
513	 */
514	bl	lowlevel_init		/* go setup pll,mux,memory */
515
516#ifndef CONFIG_SKIP_RELOCATE_UBOOT
517relocate:				/* relocate U-Boot to RAM	    */
518	adr	r0, _start		/* r0 <- current position of code   */
519	ldr	r1, _TEXT_BASE		/* test if we run from flash or RAM */
520	cmp     r0, r1                  /* don't reloc during debug         */
521	beq     stack_setup
522
523	ldr	r2, _armboot_start
524	ldr	r3, _bss_start
525	sub	r2, r3, r2		/* r2 <- size of armboot            */
526	add	r2, r0, r2		/* r2 <- source end address         */
527
528copy_loop:
529	ldmia	r0!, {r3-r10}		/* copy from source address [r0]    */
530	stmia	r1!, {r3-r10}		/* copy to   target address [r1]    */
531	cmp	r0, r2			/* until source end address [r2]    */
532	blo	copy_loop
533#endif	/* CONFIG_SKIP_RELOCATE_UBOOT */
534
535#ifdef CONFIG_ENABLE_MMU
536enable_mmu:
537	/* enable domain access */
538	ldr	r5, =0x0000ffff
539	mcr	p15, 0, r5, c3, c0, 0	/* load domain access register */
540
541	/* Set the TTB register */
542	ldr	r0, _mmu_table_base
543	ldr	r1, =CONFIG_SYS_PHY_UBOOT_BASE
544	ldr	r2, =0xfff00000
545	bic	r0, r0, r2
546	orr	r1, r0, r1
547	mcr	p15, 0, r1, c2, c0, 0
548
549	/* Enable the MMU */
550	mrc	p15, 0, r0, c1, c0, 0
551	orr	r0, r0, #1		/* Set CR_M to enable MMU */
552
553	/* Prepare to enable the MMU */
554	adr	r1, skip_hw_init
555	and	r1, r1, #0x3fc
556	ldr	r2, _TEXT_BASE
557	ldr	r3, =0xfff00000
558	and	r2, r2, r3
559	orr	r2, r2, r1
560	b	mmu_enable
561
562	.align 5
563	/* Run in a single cache-line */
564mmu_enable:
565
566	mcr	p15, 0, r0, c1, c0, 0
567	nop
568	nop
569	mov	pc, r2
570skip_hw_init:
571#endif
572
573	/* Set up the stack						    */
574stack_setup:
575	ldr	r0, =CONFIG_SYS_UBOOT_BASE	/* base of copy in DRAM	    */
576	sub	r0, r0, #CONFIG_SYS_MALLOC_LEN	/* malloc area                      */
577	sub	r0, r0, #GENERATED_GBL_DATA_SIZE /* bdinfo                        */
578	sub	sp, r0, #12		/* leave 3 words for abort-stack    */
579	bic	sp, sp, #7		/* 8-byte alignment for ABI compliance */
580
581clear_bss:
582	ldr	r0, _bss_start		/* find start of bss segment        */
583	ldr	r1, _bss_end		/* stop here                        */
584	mov 	r2, #0			/* clear                            */
585
586clbss_l:
587	str	r2, [r0]		/* clear loop...                    */
588	add	r0, r0, #4
589	cmp	r0, r1
590	blo	clbss_l
591
592#ifndef CONFIG_NAND_SPL
593	ldr	pc, _start_armboot
594
595_start_armboot:
596	.word start_armboot
597#else
598	b	nand_boot
599/*	.word nand_boot*/
600#endif
601
602#endif /* #if !defined(CONFIG_SYS_ARM_WITHOUT_RELOC) */
603
604#ifdef CONFIG_ENABLE_MMU
605_mmu_table_base:
606	.word mmu_table
607#endif
608
609#ifndef CONFIG_NAND_SPL
610/*
611 * we assume that cache operation is done before. (eg. cleanup_before_linux())
612 * actually, we don't need to do anything about cache if not use d-cache in
613 * U-Boot. So, in this function we clean only MMU. by scsuh
614 *
615 * void	theLastJump(void *kernel, int arch_num, uint boot_params);
616 */
617#ifdef CONFIG_ENABLE_MMU
618	.globl theLastJump
619theLastJump:
620	mov	r9, r0
621	ldr	r3, =0xfff00000
622	ldr	r4, _TEXT_PHY_BASE
623	adr	r5, phy_last_jump
624	bic	r5, r5, r3
625	orr	r5, r5, r4
626	mov	pc, r5
627phy_last_jump:
628	/*
629	 * disable MMU stuff
630	 */
631	mrc	p15, 0, r0, c1, c0, 0
632	bic	r0, r0, #0x00002300	/* clear bits 13, 9:8 (--V- --RS) */
633	bic	r0, r0, #0x00000087	/* clear bits 7, 2:0 (B--- -CAM) */
634	orr	r0, r0, #0x00000002	/* set bit 2 (A) Align */
635	orr	r0, r0, #0x00001000	/* set bit 12 (I) I-Cache */
636	mcr	p15, 0, r0, c1, c0, 0
637
638	mcr	p15, 0, r0, c8, c7, 0	/* flush v4 TLB */
639
640	mov	r0, #0
641	mov	pc, r9
642#endif
643
644
645/*
646 *************************************************************************
647 *
648 * Interrupt handling
649 *
650 *************************************************************************
651 */
652@
653@ IRQ stack frame.
654@
655#define S_FRAME_SIZE	72
656
657#define S_OLD_R0	68
658#define S_PSR		64
659#define S_PC		60
660#define S_LR		56
661#define S_SP		52
662
663#define S_IP		48
664#define S_FP		44
665#define S_R10		40
666#define S_R9		36
667#define S_R8		32
668#define S_R7		28
669#define S_R6		24
670#define S_R5		20
671#define S_R4		16
672#define S_R3		12
673#define S_R2		8
674#define S_R1		4
675#define S_R0		0
676
677#define MODE_SVC 0x13
678#define I_BIT	 0x80
679
680/*
681 * use bad_save_user_regs for abort/prefetch/undef/swi ...
682 */
683
684	.macro	bad_save_user_regs
685	/* carve out a frame on current user stack */
686	sub	sp, sp, #S_FRAME_SIZE
687	/* Save user registers (now in svc mode) r0-r12 */
688	stmia	sp, {r0 - r12}
689
690#if defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
691	ldr	r2, _armboot_start
692	sub	r2, r2, #(CONFIG_SYS_MALLOC_LEN)
693	/* set base 2 words into abort stack */
694	sub	r2, r2, #(GENERATED_GBL_DATA_SIZE+8)
695#else
696	ldr	r2, IRQ_STACK_START_IN
697#endif
698	/* get values for "aborted" pc and cpsr (into parm regs) */
699	ldmia	r2, {r2 - r3}
700	/* grab pointer to old stack */
701	add	r0, sp, #S_FRAME_SIZE
702
703	add	r5, sp, #S_SP
704	mov	r1, lr
705	/* save sp_SVC, lr_SVC, pc, cpsr */
706	stmia	r5, {r0 - r3}
707	/* save current stack into r0 (param register) */
708	mov	r0, sp
709	.endm
710
711	.macro get_bad_stack
712#if defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
713	/* setup our mode stack (enter in banked mode) */
714	ldr	r13, _armboot_start
715	/* move past malloc pool */
716	sub	r13, r13, #(CONFIG_SYS_MALLOC_LEN)
717	/* move to reserved a couple spots for abort stack */
718	sub	r13, r13, #(GENERATED_GBL_DATA_SIZE + 8)
719#else
720	ldr	r13, IRQ_STACK_START_IN		@ setup our mode stack
721#endif
722
723	/* save caller lr in position 0 of saved stack */
724	str	lr, [r13]
725	/* get the spsr */
726	mrs	lr, spsr
727	/* save spsr in position 1 of saved stack */
728	str	lr, [r13, #4]
729
730	/* prepare SVC-Mode */
731	mov	r13, #MODE_SVC
732	@ msr	spsr_c, r13
733	/* switch modes, make sure moves will execute */
734	msr	spsr, r13
735	/* capture return pc */
736	mov	lr, pc
737	/* jump to next instruction & switch modes. */
738	movs	pc, lr
739	.endm
740
741	.macro get_bad_stack_swi
742	/* space on current stack for scratch reg. */
743	sub	r13, r13, #4
744	/* save R0's value. */
745	str	r0, [r13]
746#if defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
747	/* get data regions start */
748	ldr	r0, _armboot_start
749	/* move past malloc pool */
750	sub	r0, r0, #(CONFIG_SYS_MALLOC_LEN)
751	/* move past gbl and a couple spots for abort stack */
752	sub	r0, r0, #(GENERATED_GBL_DATA_SIZE + 8)
753#else
754	ldr	r13, IRQ_STACK_START_IN		@ setup our mode stack
755#endif
756	/* save caller lr in position 0 of saved stack */
757	str	lr, [r0]
758	/* get the spsr */
759	mrs	r0, spsr
760	/* save spsr in position 1 of saved stack */
761	str	lr, [r0, #4]
762	/* restore r0 */
763	ldr	r0, [r13]
764	/* pop stack entry */
765	add	r13, r13, #4
766	.endm
767
768/*
769 * exception handlers
770 */
771	.align	5
772undefined_instruction:
773	get_bad_stack
774	bad_save_user_regs
775	bl	do_undefined_instruction
776
777	.align	5
778software_interrupt:
779	get_bad_stack_swi
780	bad_save_user_regs
781	bl	do_software_interrupt
782
783	.align	5
784prefetch_abort:
785	get_bad_stack
786	bad_save_user_regs
787	bl	do_prefetch_abort
788
789	.align	5
790data_abort:
791	get_bad_stack
792	bad_save_user_regs
793	bl	do_data_abort
794
795	.align	5
796not_used:
797	get_bad_stack
798	bad_save_user_regs
799	bl	do_not_used
800
801	.align	5
802irq:
803	get_bad_stack
804	bad_save_user_regs
805	bl	do_irq
806
807	.align	5
808fiq:
809	get_bad_stack
810	bad_save_user_regs
811	bl	do_fiq
812#endif /* CONFIG_NAND_SPL */
813