xref: /openbmc/u-boot/arch/arm/cpu/arm946es/start.S (revision 8ca78f2c)
1/*
2 *  armboot - Startup Code for ARM926EJS CPU-core
3 *
4 *  Copyright (c) 2003  Texas Instruments
5 *
6 *  ----- Adapted for OMAP1610 OMAP730 from ARM925t code ------
7 *
8 *  Copyright (c) 2001	Marius Gr�ger <mag@sysgo.de>
9 *  Copyright (c) 2002	Alex Z�pke <azu@sysgo.de>
10 *  Copyright (c) 2002	Gary Jennejohn <garyj@denx.de>
11 *  Copyright (c) 2003	Richard Woodruff <r-woodruff2@ti.com>
12 *  Copyright (c) 2003	Kshitij <kshitij@ti.com>
13 *
14 * See file CREDITS for list of people who contributed to this
15 * project.
16 *
17 * This program is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU General Public License as
19 * published by the Free Software Foundation; either version 2 of
20 * the License, or (at your option) any later version.
21 *
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25 * GNU General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
30 * MA 02111-1307 USA
31 */
32
33#include <asm-offsets.h>
34#include <config.h>
35#include <version.h>
36
37/*
38 *************************************************************************
39 *
40 * Jump vector table as in table 3.1 in [1]
41 *
42 *************************************************************************
43 */
44
45
46.globl _start
47_start:
48	b	reset
49	ldr	pc, _undefined_instruction
50	ldr	pc, _software_interrupt
51	ldr	pc, _prefetch_abort
52	ldr	pc, _data_abort
53	ldr	pc, _not_used
54	ldr	pc, _irq
55	ldr	pc, _fiq
56
57_undefined_instruction:
58	.word undefined_instruction
59_software_interrupt:
60	.word software_interrupt
61_prefetch_abort:
62	.word prefetch_abort
63_data_abort:
64	.word data_abort
65_not_used:
66	.word not_used
67_irq:
68	.word irq
69_fiq:
70	.word fiq
71
72	.balignl 16,0xdeadbeef
73
74
75/*
76 *************************************************************************
77 *
78 * Startup Code (reset vector)
79 *
80 * do important init only if we don't start from memory!
81 * setup Memory and board specific bits prior to relocation.
82 * relocate armboot to ram
83 * setup stack
84 *
85 *************************************************************************
86 */
87
88.globl _TEXT_BASE
89_TEXT_BASE:
90	.word	CONFIG_SYS_TEXT_BASE
91
92/*
93 * These are defined in the board-specific linker script.
94 */
95.globl _bss_start
96_bss_start:
97	.word __bss_start
98
99.globl _bss_end
100_bss_end:
101	.word _end
102
103#ifdef CONFIG_USE_IRQ
104/* IRQ stack memory (calculated at run-time) */
105.globl IRQ_STACK_START
106IRQ_STACK_START:
107	.word	0x0badc0de
108
109/* IRQ stack memory (calculated at run-time) */
110.globl FIQ_STACK_START
111FIQ_STACK_START:
112	.word 0x0badc0de
113#endif
114
115/* IRQ stack memory (calculated at run-time) + 8 bytes */
116.globl IRQ_STACK_START_IN
117IRQ_STACK_START_IN:
118	.word	0x0badc0de
119
120.globl _datarel_start
121_datarel_start:
122	.word __datarel_start
123
124.globl _datarelrolocal_start
125_datarelrolocal_start:
126	.word __datarelrolocal_start
127
128.globl _datarellocal_start
129_datarellocal_start:
130	.word __datarellocal_start
131
132.globl _datarelro_start
133_datarelro_start:
134	.word __datarelro_start
135
136.globl _got_start
137_got_start:
138	.word __got_start
139
140.globl _got_end
141_got_end:
142	.word __got_end
143
144/*
145 * the actual reset code
146 */
147
148reset:
149	/*
150	 * set the cpu to SVC32 mode
151	 */
152	mrs	r0,cpsr
153	bic	r0,r0,#0x1f
154	orr	r0,r0,#0xd3
155	msr	cpsr,r0
156
157	/*
158	 * we do sys-critical inits only at reboot,
159	 * not when booting from ram!
160	 */
161#ifndef CONFIG_SKIP_LOWLEVEL_INIT
162	bl	cpu_init_crit
163#endif
164
165/* Set stackpointer in internal RAM to call board_init_f */
166call_board_init_f:
167	ldr	sp, =(CONFIG_SYS_INIT_SP_ADDR)
168	ldr	r0,=0x00000000
169	bl	board_init_f
170
171/*------------------------------------------------------------------------------*/
172
173/*
174 * void relocate_code (addr_sp, gd, addr_moni)
175 *
176 * This "function" does not return, instead it continues in RAM
177 * after relocating the monitor code.
178 *
179 */
180	.globl	relocate_code
181relocate_code:
182	mov	r4, r0	/* save addr_sp */
183	mov	r5, r1	/* save addr of gd */
184	mov	r6, r2	/* save addr of destination */
185	mov	r7, r2	/* save addr of destination */
186
187	/* Set up the stack						    */
188stack_setup:
189	mov	sp, r4
190
191	adr	r0, _start
192	ldr	r2, _TEXT_BASE
193	ldr	r3, _bss_start
194	sub	r2, r3, r2		/* r2 <- size of armboot	    */
195	add	r2, r0, r2		/* r2 <- source end address	    */
196	cmp	r0, r6
197	beq	clear_bss
198
199copy_loop:
200	ldmia	r0!, {r9-r10}		/* copy from source address [r0]    */
201	stmia	r6!, {r9-r10}		/* copy to   target address [r1]    */
202	cmp	r0, r2			/* until source end address [r2]    */
203	blo	copy_loop
204
205#ifndef CONFIG_PRELOADER
206	/* fix got entries */
207	ldr	r1, _TEXT_BASE		/* Text base */
208	mov	r0, r7			/* reloc addr */
209	ldr	r2, _got_start		/* addr in Flash */
210	ldr	r3, _got_end		/* addr in Flash */
211	sub	r3, r3, r1
212	add	r3, r3, r0
213	sub	r2, r2, r1
214	add	r2, r2, r0
215
216fixloop:
217	ldr	r4, [r2]
218	sub	r4, r4, r1
219	add	r4, r4, r0
220	str	r4, [r2]
221	add	r2, r2, #4
222	cmp	r2, r3
223	blo	fixloop
224#endif
225
226clear_bss:
227#ifndef CONFIG_PRELOADER
228	ldr	r0, _bss_start
229	ldr	r1, _bss_end
230	ldr	r3, _TEXT_BASE		/* Text base */
231	mov	r4, r7			/* reloc addr */
232	sub	r0, r0, r3
233	add	r0, r0, r4
234	sub	r1, r1, r3
235	add	r1, r1, r4
236	mov	r2, #0x00000000		/* clear			    */
237
238clbss_l:str	r2, [r0]		/* clear loop...		    */
239	add	r0, r0, #4
240	cmp	r0, r1
241	bne	clbss_l
242#endif
243
244/*
245 * We are done. Do not return, instead branch to second part of board
246 * initialization, now running from RAM.
247 */
248#ifdef CONFIG_NAND_SPL
249	ldr     pc, _nand_boot
250
251_nand_boot: .word nand_boot
252#else
253	ldr	r0, _TEXT_BASE
254	ldr	r2, _board_init_r
255	sub	r2, r2, r0
256	add	r2, r2, r7	/* position from board_init_r in RAM */
257	/* setup parameters for board_init_r */
258	mov	r0, r5		/* gd_t */
259	mov	r1, r7		/* dest_addr */
260	/* jump to it ... */
261	mov	lr, r2
262	mov	pc, lr
263
264_board_init_r: .word board_init_r
265#endif
266
267/*
268 *************************************************************************
269 *
270 * CPU_init_critical registers
271 *
272 * setup important registers
273 * setup memory timing
274 *
275 *************************************************************************
276 */
277
278
279#ifndef CONFIG_SKIP_LOWLEVEL_INIT
280cpu_init_crit:
281	/*
282	 * flush v4 I/D caches
283	 */
284	mov	r0, #0
285	mcr	p15, 0, r0, c7, c5, 0	/* flush v4 I-cache */
286	mcr	p15, 0, r0, c7, c6, 0	/* flush v4 D-cache */
287
288	/*
289	 * disable MMU stuff and caches
290	 */
291	mrc	p15, 0, r0, c1, c0, 0
292	bic	r0, r0, #0x00002300	/* clear bits 13, 9:8 (--V- --RS) */
293	bic	r0, r0, #0x00000087	/* clear bits 7, 2:0 (B--- -CAM) */
294	orr	r0, r0, #0x00000002	/* set bit 2 (A) Align */
295	orr	r0, r0, #0x00001000	/* set bit 12 (I) I-Cache */
296	mcr	p15, 0, r0, c1, c0, 0
297
298	/*
299	 * Go setup Memory and board specific bits prior to relocation.
300	 */
301	mov	ip, lr		/* perserve link reg across call */
302	bl	lowlevel_init	/* go setup memory */
303	mov	lr, ip		/* restore link */
304	mov	pc, lr		/* back to my caller */
305#endif
306/*
307 *************************************************************************
308 *
309 * Interrupt handling
310 *
311 *************************************************************************
312 */
313
314@
315@ IRQ stack frame.
316@
317#define S_FRAME_SIZE	72
318
319#define S_OLD_R0	68
320#define S_PSR		64
321#define S_PC		60
322#define S_LR		56
323#define S_SP		52
324
325#define S_IP		48
326#define S_FP		44
327#define S_R10		40
328#define S_R9		36
329#define S_R8		32
330#define S_R7		28
331#define S_R6		24
332#define S_R5		20
333#define S_R4		16
334#define S_R3		12
335#define S_R2		8
336#define S_R1		4
337#define S_R0		0
338
339#define MODE_SVC 0x13
340#define I_BIT	 0x80
341
342/*
343 * use bad_save_user_regs for abort/prefetch/undef/swi ...
344 * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling
345 */
346
347	.macro	bad_save_user_regs
348	@ carve out a frame on current user stack
349	sub	sp, sp, #S_FRAME_SIZE
350	stmia	sp, {r0 - r12}	@ Save user registers (now in svc mode) r0-r12
351
352	ldr	r2, IRQ_STACK_START_IN
353	@ get values for "aborted" pc and cpsr (into parm regs)
354	ldmia	r2, {r2 - r3}
355	add	r0, sp, #S_FRAME_SIZE		@ grab pointer to old stack
356	add	r5, sp, #S_SP
357	mov	r1, lr
358	stmia	r5, {r0 - r3}	@ save sp_SVC, lr_SVC, pc, cpsr
359	mov	r0, sp		@ save current stack into r0 (param register)
360	.endm
361
362	.macro	irq_save_user_regs
363	sub	sp, sp, #S_FRAME_SIZE
364	stmia	sp, {r0 - r12}			@ Calling r0-r12
365	@ !!!! R8 NEEDS to be saved !!!! a reserved stack spot would be good.
366	add	r8, sp, #S_PC
367	stmdb	r8, {sp, lr}^		@ Calling SP, LR
368	str	lr, [r8, #0]		@ Save calling PC
369	mrs	r6, spsr
370	str	r6, [r8, #4]		@ Save CPSR
371	str	r0, [r8, #8]		@ Save OLD_R0
372	mov	r0, sp
373	.endm
374
375	.macro	irq_restore_user_regs
376	ldmia	sp, {r0 - lr}^			@ Calling r0 - lr
377	mov	r0, r0
378	ldr	lr, [sp, #S_PC]			@ Get PC
379	add	sp, sp, #S_FRAME_SIZE
380	subs	pc, lr, #4		@ return & move spsr_svc into cpsr
381	.endm
382
383	.macro get_bad_stack
384	ldr	r13, IRQ_STACK_START_IN		@ setup our mode stack
385
386	str	lr, [r13]	@ save caller lr in position 0 of saved stack
387	mrs	lr, spsr	@ get the spsr
388	str	lr, [r13, #4]	@ save spsr in position 1 of saved stack
389	mov	r13, #MODE_SVC	@ prepare SVC-Mode
390	@ msr	spsr_c, r13
391	msr	spsr, r13	@ switch modes, make sure moves will execute
392	mov	lr, pc		@ capture return pc
393	movs	pc, lr		@ jump to next instruction & switch modes.
394	.endm
395
396	.macro get_irq_stack			@ setup IRQ stack
397	ldr	sp, IRQ_STACK_START
398	.endm
399
400	.macro get_fiq_stack			@ setup FIQ stack
401	ldr	sp, FIQ_STACK_START
402	.endm
403
404/*
405 * exception handlers
406 */
407	.align  5
408undefined_instruction:
409	get_bad_stack
410	bad_save_user_regs
411	bl	do_undefined_instruction
412
413	.align	5
414software_interrupt:
415	get_bad_stack
416	bad_save_user_regs
417	bl	do_software_interrupt
418
419	.align	5
420prefetch_abort:
421	get_bad_stack
422	bad_save_user_regs
423	bl	do_prefetch_abort
424
425	.align	5
426data_abort:
427	get_bad_stack
428	bad_save_user_regs
429	bl	do_data_abort
430
431	.align	5
432not_used:
433	get_bad_stack
434	bad_save_user_regs
435	bl	do_not_used
436
437#ifdef CONFIG_USE_IRQ
438
439	.align	5
440irq:
441	get_irq_stack
442	irq_save_user_regs
443	bl	do_irq
444	irq_restore_user_regs
445
446	.align	5
447fiq:
448	get_fiq_stack
449	/* someone ought to write a more effiction fiq_save_user_regs */
450	irq_save_user_regs
451	bl	do_fiq
452	irq_restore_user_regs
453
454#else
455
456	.align	5
457irq:
458	get_bad_stack
459	bad_save_user_regs
460	bl	do_irq
461
462	.align	5
463fiq:
464	get_bad_stack
465	bad_save_user_regs
466	bl	do_fiq
467
468#endif
469
470# ifdef CONFIG_INTEGRATOR
471
472	/* Satisfied by general board level routine */
473
474#else
475
476	.align	5
477.globl reset_cpu
478reset_cpu:
479
480	ldr	r1, rstctl1	/* get clkm1 reset ctl */
481	mov	r3, #0x0
482	strh	r3, [r1]	/* clear it */
483	mov	r3, #0x8
484	strh	r3, [r1]	/* force dsp+arm reset */
485_loop_forever:
486	b	_loop_forever
487
488rstctl1:
489	.word	0xfffece10
490
491#endif	/* #ifdef CONFIG_INTEGRATOR */
492