xref: /openbmc/u-boot/arch/arm/cpu/sa1100/start.S (revision 25ddd1fb)
1/*
2 *  armboot - Startup Code for SA1100 CPU
3 *
4 *  Copyright (C) 1998	Dan Malek <dmalek@jlc.net>
5 *  Copyright (C) 1999	Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se>
6 *  Copyright (C) 2000	Wolfgang Denk <wd@denx.de>
7 *  Copyright (c) 2001	Alex Z�pke <azu@sysgo.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
28#include <asm-offsets.h>
29#include <config.h>
30#include <version.h>
31
32/*
33 *************************************************************************
34 *
35 * Jump vector table as in table 3.1 in [1]
36 *
37 *************************************************************************
38 */
39
40
41.globl _start
42_start:	b       reset
43	ldr	pc, _undefined_instruction
44	ldr	pc, _software_interrupt
45	ldr	pc, _prefetch_abort
46	ldr	pc, _data_abort
47	ldr	pc, _not_used
48	ldr	pc, _irq
49	ldr	pc, _fiq
50
51_undefined_instruction:	.word undefined_instruction
52_software_interrupt:	.word software_interrupt
53_prefetch_abort:	.word prefetch_abort
54_data_abort:		.word data_abort
55_not_used:		.word not_used
56_irq:			.word irq
57_fiq:			.word fiq
58
59	.balignl 16,0xdeadbeef
60
61
62/*
63 *************************************************************************
64 *
65 * Startup Code (reset vector)
66 *
67 * do important init only if we don't start from memory!
68 * relocate armboot to ram
69 * setup stack
70 * jump to second stage
71 *
72 *************************************************************************
73 */
74
75.globl _TEXT_BASE
76_TEXT_BASE:
77	.word	CONFIG_SYS_TEXT_BASE
78
79#if defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
80.globl _armboot_start
81_armboot_start:
82	.word _start
83#endif
84
85/*
86 * These are defined in the board-specific linker script.
87 */
88.globl _bss_start
89_bss_start:
90	.word __bss_start
91
92.globl _bss_end
93_bss_end:
94	.word _end
95
96#ifdef CONFIG_USE_IRQ
97/* IRQ stack memory (calculated at run-time) */
98.globl IRQ_STACK_START
99IRQ_STACK_START:
100	.word	0x0badc0de
101
102/* IRQ stack memory (calculated at run-time) */
103.globl FIQ_STACK_START
104FIQ_STACK_START:
105	.word 0x0badc0de
106#endif
107
108#if !defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
109/* IRQ stack memory (calculated at run-time) + 8 bytes */
110.globl IRQ_STACK_START_IN
111IRQ_STACK_START_IN:
112	.word	0x0badc0de
113
114.globl _datarel_start
115_datarel_start:
116	.word __datarel_start
117
118.globl _datarelrolocal_start
119_datarelrolocal_start:
120	.word __datarelrolocal_start
121
122.globl _datarellocal_start
123_datarellocal_start:
124	.word __datarellocal_start
125
126.globl _datarelro_start
127_datarelro_start:
128	.word __datarelro_start
129
130.globl _got_start
131_got_start:
132	.word __got_start
133
134.globl _got_end
135_got_end:
136	.word __got_end
137
138/*
139 * the actual reset code
140 */
141
142reset:
143	/*
144	 * set the cpu to SVC32 mode
145	 */
146	mrs	r0,cpsr
147	bic	r0,r0,#0x1f
148	orr	r0,r0,#0xd3
149	msr	cpsr,r0
150
151	/*
152	 * we do sys-critical inits only at reboot,
153	 * not when booting from ram!
154	 */
155#ifndef CONFIG_SKIP_LOWLEVEL_INIT
156	bl	cpu_init_crit
157#endif
158
159/* Set stackpointer in internal RAM to call board_init_f */
160call_board_init_f:
161	ldr	sp, =(CONFIG_SYS_INIT_SP_ADDR)
162	ldr	r0,=0x00000000
163	bl	board_init_f
164
165/*------------------------------------------------------------------------------*/
166
167/*
168 * void relocate_code (addr_sp, gd, addr_moni)
169 *
170 * This "function" does not return, instead it continues in RAM
171 * after relocating the monitor code.
172 *
173 */
174	.globl	relocate_code
175relocate_code:
176	mov	r4, r0	/* save addr_sp */
177	mov	r5, r1	/* save addr of gd */
178	mov	r6, r2	/* save addr of destination */
179	mov	r7, r2	/* save addr of destination */
180
181	/* Set up the stack						    */
182stack_setup:
183	mov	sp, r4
184
185	adr	r0, _start
186	ldr	r2, _TEXT_BASE
187	ldr	r3, _bss_start
188	sub	r2, r3, r2		/* r2 <- size of armboot	    */
189	add	r2, r0, r2		/* r2 <- source end address	    */
190	cmp	r0, r6
191	beq	clear_bss
192
193#ifndef CONFIG_SKIP_RELOCATE_UBOOT
194copy_loop:
195	ldmia	r0!, {r9-r10}		/* copy from source address [r0]    */
196	stmia	r6!, {r9-r10}		/* copy to   target address [r1]    */
197	cmp	r0, r2			/* until source end address [r2]    */
198	blo	copy_loop
199
200#ifndef CONFIG_PRELOADER
201	/* fix got entries */
202	ldr	r1, _TEXT_BASE		/* Text base */
203	mov	r0, r7			/* reloc addr */
204	ldr	r2, _got_start		/* addr in Flash */
205	ldr	r3, _got_end		/* addr in Flash */
206	sub	r3, r3, r1
207	add	r3, r3, r0
208	sub	r2, r2, r1
209	add	r2, r2, r0
210
211fixloop:
212	ldr	r4, [r2]
213	sub	r4, r4, r1
214	add	r4, r4, r0
215	str	r4, [r2]
216	add	r2, r2, #4
217	cmp	r2, r3
218	bne	fixloop
219#endif
220#endif	/* #ifndef CONFIG_SKIP_RELOCATE_UBOOT */
221
222clear_bss:
223#ifndef CONFIG_PRELOADER
224	ldr	r0, _bss_start
225	ldr	r1, _bss_end
226	ldr	r3, _TEXT_BASE		/* Text base */
227	mov	r4, r7			/* reloc addr */
228	sub	r0, r0, r3
229	add	r0, r0, r4
230	sub	r1, r1, r3
231	add	r1, r1, r4
232	mov	r2, #0x00000000		/* clear			    */
233
234clbss_l:str	r2, [r0]		/* clear loop...		    */
235	add	r0, r0, #4
236	cmp	r0, r1
237	bne	clbss_l
238#endif
239
240/*
241 * We are done. Do not return, instead branch to second part of board
242 * initialization, now running from RAM.
243 */
244	ldr	r0, _TEXT_BASE
245	ldr	r2, _board_init_r
246	sub	r2, r2, r0
247	add	r2, r2, r7	/* position from board_init_r in RAM */
248	/* setup parameters for board_init_r */
249	mov	r0, r5		/* gd_t */
250	mov	r1, r7		/* dest_addr */
251	/* jump to it ... */
252	mov	lr, r2
253	mov	pc, lr
254
255_board_init_r: .word board_init_r
256
257#else /* #if !defined(CONFIG_SYS_ARM_WITHOUT_RELOC) */
258
259/*
260 * the actual reset code
261 */
262
263reset:
264	/*
265	 * set the cpu to SVC32 mode
266	 */
267	mrs	r0,cpsr
268	bic	r0,r0,#0x1f
269	orr	r0,r0,#0x13
270	msr	cpsr,r0
271
272	/*
273	 * we do sys-critical inits only at reboot,
274	 * not when booting from ram!
275	 */
276#ifndef CONFIG_SKIP_LOWLEVEL_INIT
277	bl	cpu_init_crit
278#endif
279
280#ifndef CONFIG_SKIP_RELOCATE_UBOOT
281relocate:				/* relocate U-Boot to RAM	    */
282	adr	r0, _start		/* r0 <- current position of code   */
283	ldr	r1, _TEXT_BASE		/* test if we run from flash or RAM */
284	cmp     r0, r1                  /* don't reloc during debug         */
285	beq     stack_setup
286
287	ldr	r2, _armboot_start
288	ldr	r3, _bss_start
289	sub	r2, r3, r2		/* r2 <- size of armboot            */
290	add	r2, r0, r2		/* r2 <- source end address         */
291
292copy_loop:
293	ldmia	r0!, {r3-r10}		/* copy from source address [r0]    */
294	stmia	r1!, {r3-r10}		/* copy to   target address [r1]    */
295	cmp	r0, r2			/* until source end address [r2]    */
296	blo	copy_loop
297#endif	/* CONFIG_SKIP_RELOCATE_UBOOT */
298
299	/* Set up the stack						    */
300stack_setup:
301	ldr	r0, _TEXT_BASE		/* upper 128 KiB: relocated uboot   */
302	sub	r0, r0, #CONFIG_SYS_MALLOC_LEN	/* malloc area                      */
303	sub	r0, r0, #GENERATED_GBL_DATA_SIZE /* bdinfo                        */
304#ifdef CONFIG_USE_IRQ
305	sub	r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
306#endif
307	sub	sp, r0, #12		/* leave 3 words for abort-stack    */
308	bic	sp, sp, #7		/* 8-byte alignment for ABI compliance */
309
310clear_bss:
311	ldr	r0, _bss_start		/* find start of bss segment        */
312	ldr	r1, _bss_end		/* stop here                        */
313	mov	r2, #0x00000000		/* clear                            */
314
315clbss_l:str	r2, [r0]		/* clear loop...                    */
316	add	r0, r0, #4
317	cmp	r0, r1
318	blo	clbss_l
319
320	ldr	pc, _start_armboot
321
322_start_armboot:	.word start_armboot
323
324#endif /* #if !defined(CONFIG_SYS_ARM_WITHOUT_RELOC) */
325
326/*
327 *************************************************************************
328 *
329 * CPU_init_critical registers
330 *
331 * setup important registers
332 * setup memory timing
333 *
334 *************************************************************************
335 */
336
337
338/* Interupt-Controller base address */
339IC_BASE:	.word	0x90050000
340#define ICMR	0x04
341
342
343/* Reset-Controller */
344RST_BASE:		.word   0x90030000
345#define RSRR	0x00
346#define RCSR	0x04
347
348
349/* PWR */
350PWR_BASE:		.word   0x90020000
351#define PSPR    0x08
352#define PPCR    0x14
353cpuspeed:		.word   CONFIG_SYS_CPUSPEED
354
355
356cpu_init_crit:
357	/*
358	 * mask all IRQs
359	 */
360	ldr	r0, IC_BASE
361	mov	r1, #0x00
362	str	r1, [r0, #ICMR]
363
364	/* set clock speed */
365	ldr	r0, PWR_BASE
366	ldr	r1, cpuspeed
367	str	r1, [r0, #PPCR]
368
369	/*
370	 * before relocating, we have to setup RAM timing
371	 * because memory timing is board-dependend, you will
372	 * find a lowlevel_init.S in your board directory.
373	 */
374	mov	ip,	lr
375	bl	lowlevel_init
376	mov	lr,	ip
377
378	/*
379	 * disable MMU stuff and enable I-cache
380	 */
381	mrc	p15,0,r0,c1,c0
382	bic	r0, r0, #0x00002000	@ clear bit 13 (X)
383	bic	r0, r0, #0x0000000f	@ clear bits 3-0 (WCAM)
384	orr	r0, r0, #0x00001000	@ set bit 12 (I) Icache
385	orr	r0, r0, #0x00000002	@ set bit 2 (A) Align
386	mcr	p15,0,r0,c1,c0
387
388	/*
389	 * flush v4 I/D caches
390	 */
391	mov	r0, #0
392	mcr	p15, 0, r0, c7, c7, 0	/* flush v3/v4 cache */
393	mcr	p15, 0, r0, c8, c7, 0	/* flush v4 TLB */
394
395	mov	pc, lr
396
397
398/*
399 *************************************************************************
400 *
401 * Interrupt handling
402 *
403 *************************************************************************
404 */
405
406@
407@ IRQ stack frame.
408@
409#define S_FRAME_SIZE	72
410
411#define S_OLD_R0	68
412#define S_PSR		64
413#define S_PC		60
414#define S_LR		56
415#define S_SP		52
416
417#define S_IP		48
418#define S_FP		44
419#define S_R10		40
420#define S_R9		36
421#define S_R8		32
422#define S_R7		28
423#define S_R6		24
424#define S_R5		20
425#define S_R4		16
426#define S_R3		12
427#define S_R2		8
428#define S_R1		4
429#define S_R0		0
430
431#define MODE_SVC 0x13
432#define I_BIT	 0x80
433
434/*
435 * use bad_save_user_regs for abort/prefetch/undef/swi ...
436 * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling
437 */
438
439	.macro	bad_save_user_regs
440	sub	sp, sp, #S_FRAME_SIZE
441	stmia	sp, {r0 - r12}			@ Calling r0-r12
442	add     r8, sp, #S_PC
443
444#if defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
445	ldr	r2, _armboot_start
446	sub	r2, r2, #(CONFIG_STACKSIZE+CONFIG_SYS_MALLOC_LEN)
447	sub	r2, r2, #(GENERATED_GBL_DATA_SIZE+8)  @ set base 2 words into abort stack
448#else
449	ldr	r2, IRQ_STACK_START_IN
450#endif
451	ldmia	r2, {r2 - r4}                   @ get pc, cpsr, old_r0
452	add	r0, sp, #S_FRAME_SIZE		@ restore sp_SVC
453
454	add	r5, sp, #S_SP
455	mov	r1, lr
456	stmia	r5, {r0 - r4}                   @ save sp_SVC, lr_SVC, pc, cpsr, old_r
457	mov	r0, sp
458	.endm
459
460	.macro	irq_save_user_regs
461	sub	sp, sp, #S_FRAME_SIZE
462	stmia	sp, {r0 - r12}			@ Calling r0-r12
463	add     r8, sp, #S_PC
464	stmdb   r8, {sp, lr}^                   @ Calling SP, LR
465	str     lr, [r8, #0]                    @ Save calling PC
466	mrs     r6, spsr
467	str     r6, [r8, #4]                    @ Save CPSR
468	str     r0, [r8, #8]                    @ Save OLD_R0
469	mov	r0, sp
470	.endm
471
472	.macro	irq_restore_user_regs
473	ldmia	sp, {r0 - lr}^			@ Calling r0 - lr
474	mov	r0, r0
475	ldr	lr, [sp, #S_PC]			@ Get PC
476	add	sp, sp, #S_FRAME_SIZE
477	subs	pc, lr, #4			@ return & move spsr_svc into cpsr
478	.endm
479
480	.macro get_bad_stack
481#if defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
482	ldr	r13, _armboot_start		@ setup our mode stack
483	sub	r13, r13, #(CONFIG_STACKSIZE+CONFIG_SYS_MALLOC_LEN)
484	sub	r13, r13, #(GENERATED_GBL_DATA_SIZE+8) @ reserved a couple spots in abort stack
485#else
486	ldr	r13, IRQ_STACK_START_IN		@ setup our mode stack
487#endif
488
489	str	lr, [r13]			@ save caller lr / spsr
490	mrs	lr, spsr
491	str     lr, [r13, #4]
492
493	mov	r13, #MODE_SVC			@ prepare SVC-Mode
494	msr	spsr_c, r13
495	mov	lr, pc
496	movs	pc, lr
497	.endm
498
499	.macro get_irq_stack			@ setup IRQ stack
500	ldr	sp, IRQ_STACK_START
501	.endm
502
503	.macro get_fiq_stack			@ setup FIQ stack
504	ldr	sp, FIQ_STACK_START
505	.endm
506
507/*
508 * exception handlers
509 */
510	.align  5
511undefined_instruction:
512	get_bad_stack
513	bad_save_user_regs
514	bl	do_undefined_instruction
515
516	.align	5
517software_interrupt:
518	get_bad_stack
519	bad_save_user_regs
520	bl	do_software_interrupt
521
522	.align	5
523prefetch_abort:
524	get_bad_stack
525	bad_save_user_regs
526	bl	do_prefetch_abort
527
528	.align	5
529data_abort:
530	get_bad_stack
531	bad_save_user_regs
532	bl	do_data_abort
533
534	.align	5
535not_used:
536	get_bad_stack
537	bad_save_user_regs
538	bl	do_not_used
539
540#ifdef CONFIG_USE_IRQ
541
542	.align	5
543irq:
544	get_irq_stack
545	irq_save_user_regs
546	bl	do_irq
547	irq_restore_user_regs
548
549	.align	5
550fiq:
551	get_fiq_stack
552	/* someone ought to write a more effiction fiq_save_user_regs */
553	irq_save_user_regs
554	bl	do_fiq
555	irq_restore_user_regs
556
557#else
558
559	.align	5
560irq:
561	get_bad_stack
562	bad_save_user_regs
563	bl	do_irq
564
565	.align	5
566fiq:
567	get_bad_stack
568	bad_save_user_regs
569	bl	do_fiq
570
571#endif
572
573	.align	5
574.globl reset_cpu
575reset_cpu:
576	ldr	r0, RST_BASE
577	mov	r1, #0x0			@ set bit 3-0 ...
578	str	r1, [r0, #RCSR]			@ ... to clear in RCSR
579	mov	r1, #0x1
580	str	r1, [r0, #RSRR]			@ and perform reset
581	b	reset_cpu			@ silly, but repeat endlessly
582