blob: b9c364bc67291b03b8d56cd2d97e7432604f96ea [file] [log] [blame]
wdenkfe8c2802002-11-03 00:38:21 +00001/*
2 * armboot - Startup Code for ARM920 CPU-core
3 *
4 * Copyright (c) 2001 Marius Gröger <mag@sysgo.de>
5 * Copyright (c) 2002 Alex Züpke <azu@sysgo.de>
6 * Copyright (c) 2002 Gary Jennejohn <gj@denx.de>
7 *
8 * See file CREDITS for list of people who contributed to this
9 * project.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License as
13 * published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
24 * MA 02111-1307 USA
25 */
26
27
wdenkfe8c2802002-11-03 00:38:21 +000028#include <config.h>
29#include <version.h>
Peter Pearsede5b02c2007-08-14 10:10:52 +010030#if defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK) || defined(CONFIG_AT91RM9200DF)
31#include <led.h>
32#endif
wdenkfe8c2802002-11-03 00:38:21 +000033
34/*
35 *************************************************************************
36 *
37 * Jump vector table as in table 3.1 in [1]
38 *
39 *************************************************************************
40 */
41
42
43.globl _start
44_start: b reset
45 ldr pc, _undefined_instruction
46 ldr pc, _software_interrupt
47 ldr pc, _prefetch_abort
48 ldr pc, _data_abort
49 ldr pc, _not_used
50 ldr pc, _irq
51 ldr pc, _fiq
52
53_undefined_instruction: .word undefined_instruction
54_software_interrupt: .word software_interrupt
55_prefetch_abort: .word prefetch_abort
56_data_abort: .word data_abort
57_not_used: .word not_used
58_irq: .word irq
59_fiq: .word fiq
60
61 .balignl 16,0xdeadbeef
62
63
64/*
65 *************************************************************************
66 *
67 * Startup Code (reset vector)
68 *
69 * do important init only if we don't start from memory!
70 * relocate armboot to ram
71 * setup stack
72 * jump to second stage
73 *
74 *************************************************************************
75 */
76
wdenkfe8c2802002-11-03 00:38:21 +000077_TEXT_BASE:
78 .word TEXT_BASE
79
80.globl _armboot_start
81_armboot_start:
82 .word _start
83
84/*
wdenk927034e2004-02-08 19:38:38 +000085 * These are defined in the board-specific linker script.
wdenkfe8c2802002-11-03 00:38:21 +000086 */
wdenk927034e2004-02-08 19:38:38 +000087.globl _bss_start
88_bss_start:
89 .word __bss_start
90
91.globl _bss_end
92_bss_end:
93 .word _end
wdenkfe8c2802002-11-03 00:38:21 +000094
wdenkfe8c2802002-11-03 00:38:21 +000095#ifdef CONFIG_USE_IRQ
96/* IRQ stack memory (calculated at run-time) */
97.globl IRQ_STACK_START
98IRQ_STACK_START:
99 .word 0x0badc0de
100
101/* IRQ stack memory (calculated at run-time) */
102.globl FIQ_STACK_START
103FIQ_STACK_START:
104 .word 0x0badc0de
105#endif
106
107
108/*
109 * the actual reset code
110 */
111
112reset:
113 /*
114 * set the cpu to SVC32 mode
115 */
116 mrs r0,cpsr
117 bic r0,r0,#0x1f
118 orr r0,r0,#0xd3
119 msr cpsr,r0
120
Peter Pearsede5b02c2007-08-14 10:10:52 +0100121#if CONFIG_AT91RM9200
122#if defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK) || defined(CONFIG_AT91RM9200DF)
123 bl LED_init
124 bl red_LED_on
125#endif
126
127#ifdef CONFIG_BOOTBINFUNC
128/* code based on entry.S from ATMEL */
129#define AT91C_BASE_CKGR 0xFFFFFC20
130#define CKGR_MOR 0
131 /* Get the CKGR Base Address */
132 ldr r1, =AT91C_BASE_CKGR
133
134/* Main oscillator Enable register APMC_MOR : Enable main oscillator , OSCOUNT = 0xFF */
135/* ldr r0, = AT91C_CKGR_MOSCEN:OR:AT91C_CKGR_OSCOUNT */
136 ldr r0, =0x0000FF01
137 str r0, [r1, #CKGR_MOR]
138 /* Add loop to compensate Main Oscillator startup time */
139 ldr r0, =0x00000010
140LoopOsc:
141 subs r0, r0, #1
142 bhi LoopOsc
143 /* scratch stack */
144 ldr r1, =0x00204000
145 /* Insure word alignment */
146 bic r1, r1, #3
147 /* Init stack SYS */
148 mov sp, r1
149 /*
150 * This does a lot more than just set up the memory, which
151 * is why it's called lowlevelinit
152 */
153 bl lowlevelinit /* in memsetup.S */
154 bl icache_enable;
155 /* ------------------------------------
156 * Read/modify/write CP15 control register
157 * -------------------------------------
158 * read cp15 control register (cp15 r1) in r0
159 * ------------------------------------
160 */
161 mrc p15, 0, r0, c1, c0, 0
162 /* Reset bit :Little Endian end fast bus mode */
163 ldr r3, =0xC0000080
164 /* Set bit :Asynchronous clock mode, Not Fast Bus */
165 ldr r4, =0xC0000000
166 bic r0, r0, r3
167 orr r0, r0, r4
168 /* write r0 in cp15 control register (cp15 r1) */
169 mcr p15, 0, r0, c1, c0, 0
170#endif /* CONFIG_BOOTBINFUNC */
171 /*
172 * relocate exeception table
173 */
174 ldr r0, =_start
175 ldr r1, =0x0
176 mov r2, #16
177copyex:
178 subs r2, r2, #1
179 ldr r3, [r0], #4
180 str r3, [r1], #4
181 bne copyex
182#endif
183
wdenkfe8c2802002-11-03 00:38:21 +0000184/* turn off the watchdog */
185#if defined(CONFIG_S3C2400)
wdenk7ac16102004-08-01 22:48:16 +0000186# define pWTCON 0x15300000
187# define INTMSK 0x14400008 /* Interupt-Controller base addresses */
188# define CLKDIVN 0x14800014 /* clock divisor register */
wdenkfe8c2802002-11-03 00:38:21 +0000189#elif defined(CONFIG_S3C2410)
wdenk7ac16102004-08-01 22:48:16 +0000190# define pWTCON 0x53000000
191# define INTMSK 0x4A000008 /* Interupt-Controller base addresses */
192# define INTSUBMSK 0x4A00001C
193# define CLKDIVN 0x4C000014 /* clock divisor register */
wdenkfe8c2802002-11-03 00:38:21 +0000194#endif
195
wdenk7ac16102004-08-01 22:48:16 +0000196#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)
wdenkfe8c2802002-11-03 00:38:21 +0000197 ldr r0, =pWTCON
198 mov r1, #0x0
199 str r1, [r0]
200
201 /*
202 * mask all IRQs by setting all bits in the INTMR - default
203 */
204 mov r1, #0xffffffff
205 ldr r0, =INTMSK
206 str r1, [r0]
wdenk7ac16102004-08-01 22:48:16 +0000207# if defined(CONFIG_S3C2410)
wdenkfe8c2802002-11-03 00:38:21 +0000208 ldr r1, =0x3ff
209 ldr r0, =INTSUBMSK
210 str r1, [r0]
wdenk7ac16102004-08-01 22:48:16 +0000211# endif
wdenkfe8c2802002-11-03 00:38:21 +0000212
213 /* FCLK:HCLK:PCLK = 1:2:4 */
214 /* default FCLK is 120 MHz ! */
215 ldr r0, =CLKDIVN
216 mov r1, #3
217 str r1, [r0]
wdenk7ac16102004-08-01 22:48:16 +0000218#endif /* CONFIG_S3C2400 || CONFIG_S3C2410 */
wdenkfe8c2802002-11-03 00:38:21 +0000219
220 /*
221 * we do sys-critical inits only at reboot,
222 * not when booting from ram!
223 */
wdenk3d3d99f2005-04-04 12:44:11 +0000224#ifndef CONFIG_SKIP_LOWLEVEL_INIT
wdenkfe8c2802002-11-03 00:38:21 +0000225 bl cpu_init_crit
226#endif
227
Peter Pearsede5b02c2007-08-14 10:10:52 +0100228#ifdef CONFIG_AT91RM9200
229#ifdef CONFIG_BOOTBINFUNC
230relocate: /* relocate U-Boot to RAM */
231 adr r0, _start /* r0 <- current position of code */
232 ldr r1, _TEXT_BASE /* test if we run from flash or RAM */
233 cmp r0, r1 /* don't reloc during debug */
234 beq stack_setup
235
236 ldr r2, _armboot_start
237 ldr r3, _bss_start
238 sub r2, r3, r2 /* r2 <- size of armboot */
239 add r2, r0, r2 /* r2 <- source end address */
240
241copy_loop:
242 ldmia r0!, {r3-r10} /* copy from source address [r0] */
243 stmia r1!, {r3-r10} /* copy to target address [r1] */
244 cmp r0, r2 /* until source end addreee [r2] */
245 ble copy_loop
246#endif /* CONFIG_BOOTBINFUNC */
247#else
wdenk3d3d99f2005-04-04 12:44:11 +0000248#ifndef CONFIG_SKIP_RELOCATE_UBOOT
wdenkc0aa5c52003-12-06 19:49:23 +0000249relocate: /* relocate U-Boot to RAM */
250 adr r0, _start /* r0 <- current position of code */
251 ldr r1, _TEXT_BASE /* test if we run from flash or RAM */
252 cmp r0, r1 /* don't reloc during debug */
253 beq stack_setup
254
wdenkfe8c2802002-11-03 00:38:21 +0000255 ldr r2, _armboot_start
wdenk927034e2004-02-08 19:38:38 +0000256 ldr r3, _bss_start
wdenkc0aa5c52003-12-06 19:49:23 +0000257 sub r2, r3, r2 /* r2 <- size of armboot */
258 add r2, r0, r2 /* r2 <- source end address */
wdenkfe8c2802002-11-03 00:38:21 +0000259
wdenkfe8c2802002-11-03 00:38:21 +0000260copy_loop:
wdenkc0aa5c52003-12-06 19:49:23 +0000261 ldmia r0!, {r3-r10} /* copy from source address [r0] */
262 stmia r1!, {r3-r10} /* copy to target address [r1] */
263 cmp r0, r2 /* until source end addreee [r2] */
wdenkfe8c2802002-11-03 00:38:21 +0000264 ble copy_loop
wdenk3d3d99f2005-04-04 12:44:11 +0000265#endif /* CONFIG_SKIP_RELOCATE_UBOOT */
Peter Pearsede5b02c2007-08-14 10:10:52 +0100266#endif
wdenkc0aa5c52003-12-06 19:49:23 +0000267 /* Set up the stack */
268stack_setup:
269 ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
270 sub r0, r0, #CFG_MALLOC_LEN /* malloc area */
271 sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */
272#ifdef CONFIG_USE_IRQ
273 sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
274#endif
275 sub sp, r0, #12 /* leave 3 words for abort-stack */
276
wdenk927034e2004-02-08 19:38:38 +0000277clear_bss:
278 ldr r0, _bss_start /* find start of bss segment */
wdenk927034e2004-02-08 19:38:38 +0000279 ldr r1, _bss_end /* stop here */
280 mov r2, #0x00000000 /* clear */
281
282clbss_l:str r2, [r0] /* clear loop... */
283 add r0, r0, #4
284 cmp r0, r1
wdenk26c58432005-01-09 17:12:27 +0000285 ble clbss_l
wdenk927034e2004-02-08 19:38:38 +0000286
wdenkfe8c2802002-11-03 00:38:21 +0000287#if 0
288 /* try doing this stuff after the relocation */
289 ldr r0, =pWTCON
290 mov r1, #0x0
291 str r1, [r0]
292
293 /*
294 * mask all IRQs by setting all bits in the INTMR - default
295 */
296 mov r1, #0xffffffff
297 ldr r0, =INTMR
298 str r1, [r0]
299
300 /* FCLK:HCLK:PCLK = 1:2:4 */
301 /* default FCLK is 120 MHz ! */
302 ldr r0, =CLKDIVN
303 mov r1, #3
304 str r1, [r0]
305 /* END stuff after relocation */
306#endif
307
wdenkfe8c2802002-11-03 00:38:21 +0000308 ldr pc, _start_armboot
309
310_start_armboot: .word start_armboot
311
312
313/*
314 *************************************************************************
315 *
316 * CPU_init_critical registers
317 *
318 * setup important registers
319 * setup memory timing
320 *
321 *************************************************************************
322 */
323
324
Wolfgang Denkf2e11a72006-04-03 15:46:10 +0200325#ifndef CONFIG_SKIP_LOWLEVEL_INIT
wdenkfe8c2802002-11-03 00:38:21 +0000326cpu_init_crit:
327 /*
328 * flush v4 I/D caches
329 */
330 mov r0, #0
331 mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */
332 mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */
333
334 /*
335 * disable MMU stuff and caches
336 */
337 mrc p15, 0, r0, c1, c0, 0
338 bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS)
339 bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM)
340 orr r0, r0, #0x00000002 @ set bit 2 (A) Align
341 orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache
342 mcr p15, 0, r0, c1, c0, 0
343
wdenkfe8c2802002-11-03 00:38:21 +0000344 /*
345 * before relocating, we have to setup RAM timing
346 * because memory timing is board-dependend, you will
wdenk336b2bc2005-04-02 23:52:25 +0000347 * find a lowlevel_init.S in your board directory.
wdenkfe8c2802002-11-03 00:38:21 +0000348 */
349 mov ip, lr
Peter Pearsede5b02c2007-08-14 10:10:52 +0100350#if defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK) || defined(CONFIG_AT91RM9200DF)
351
352#else
wdenk336b2bc2005-04-02 23:52:25 +0000353 bl lowlevel_init
Peter Pearsede5b02c2007-08-14 10:10:52 +0100354#endif
wdenkfe8c2802002-11-03 00:38:21 +0000355 mov lr, ip
wdenkfe8c2802002-11-03 00:38:21 +0000356 mov pc, lr
Wolfgang Denkf2e11a72006-04-03 15:46:10 +0200357#endif /* CONFIG_SKIP_LOWLEVEL_INIT */
wdenkfe8c2802002-11-03 00:38:21 +0000358
wdenkfe8c2802002-11-03 00:38:21 +0000359/*
360 *************************************************************************
361 *
362 * Interrupt handling
363 *
364 *************************************************************************
365 */
366
367@
368@ IRQ stack frame.
369@
370#define S_FRAME_SIZE 72
371
372#define S_OLD_R0 68
373#define S_PSR 64
374#define S_PC 60
375#define S_LR 56
376#define S_SP 52
377
378#define S_IP 48
379#define S_FP 44
380#define S_R10 40
381#define S_R9 36
382#define S_R8 32
383#define S_R7 28
384#define S_R6 24
385#define S_R5 20
386#define S_R4 16
387#define S_R3 12
388#define S_R2 8
389#define S_R1 4
390#define S_R0 0
391
392#define MODE_SVC 0x13
393#define I_BIT 0x80
394
395/*
396 * use bad_save_user_regs for abort/prefetch/undef/swi ...
397 * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling
398 */
399
400 .macro bad_save_user_regs
401 sub sp, sp, #S_FRAME_SIZE
402 stmia sp, {r0 - r12} @ Calling r0-r12
wdenk927034e2004-02-08 19:38:38 +0000403 ldr r2, _armboot_start
404 sub r2, r2, #(CONFIG_STACKSIZE+CFG_MALLOC_LEN)
405 sub r2, r2, #(CFG_GBL_DATA_SIZE+8) @ set base 2 words into abort stack
wdenkf4688a22003-05-28 08:06:31 +0000406 ldmia r2, {r2 - r3} @ get pc, cpsr
wdenkfe8c2802002-11-03 00:38:21 +0000407 add r0, sp, #S_FRAME_SIZE @ restore sp_SVC
408
409 add r5, sp, #S_SP
410 mov r1, lr
wdenkf4688a22003-05-28 08:06:31 +0000411 stmia r5, {r0 - r3} @ save sp_SVC, lr_SVC, pc, cpsr
wdenkfe8c2802002-11-03 00:38:21 +0000412 mov r0, sp
413 .endm
414
415 .macro irq_save_user_regs
416 sub sp, sp, #S_FRAME_SIZE
417 stmia sp, {r0 - r12} @ Calling r0-r12
418 add r8, sp, #S_PC
419 stmdb r8, {sp, lr}^ @ Calling SP, LR
420 str lr, [r8, #0] @ Save calling PC
421 mrs r6, spsr
422 str r6, [r8, #4] @ Save CPSR
423 str r0, [r8, #8] @ Save OLD_R0
424 mov r0, sp
425 .endm
426
427 .macro irq_restore_user_regs
428 ldmia sp, {r0 - lr}^ @ Calling r0 - lr
429 mov r0, r0
430 ldr lr, [sp, #S_PC] @ Get PC
431 add sp, sp, #S_FRAME_SIZE
432 subs pc, lr, #4 @ return & move spsr_svc into cpsr
433 .endm
434
435 .macro get_bad_stack
wdenk927034e2004-02-08 19:38:38 +0000436 ldr r13, _armboot_start @ setup our mode stack
437 sub r13, r13, #(CONFIG_STACKSIZE+CFG_MALLOC_LEN)
438 sub r13, r13, #(CFG_GBL_DATA_SIZE+8) @ reserved a couple spots in abort stack
wdenkfe8c2802002-11-03 00:38:21 +0000439
440 str lr, [r13] @ save caller lr / spsr
441 mrs lr, spsr
442 str lr, [r13, #4]
443
444 mov r13, #MODE_SVC @ prepare SVC-Mode
445 @ msr spsr_c, r13
446 msr spsr, r13
447 mov lr, pc
448 movs pc, lr
449 .endm
450
451 .macro get_irq_stack @ setup IRQ stack
452 ldr sp, IRQ_STACK_START
453 .endm
454
455 .macro get_fiq_stack @ setup FIQ stack
456 ldr sp, FIQ_STACK_START
457 .endm
458
459/*
460 * exception handlers
461 */
462 .align 5
463undefined_instruction:
464 get_bad_stack
465 bad_save_user_regs
466 bl do_undefined_instruction
467
468 .align 5
469software_interrupt:
470 get_bad_stack
471 bad_save_user_regs
472 bl do_software_interrupt
473
474 .align 5
475prefetch_abort:
476 get_bad_stack
477 bad_save_user_regs
478 bl do_prefetch_abort
479
480 .align 5
481data_abort:
482 get_bad_stack
483 bad_save_user_regs
484 bl do_data_abort
485
486 .align 5
487not_used:
488 get_bad_stack
489 bad_save_user_regs
490 bl do_not_used
491
492#ifdef CONFIG_USE_IRQ
493
494 .align 5
495irq:
496 get_irq_stack
497 irq_save_user_regs
498 bl do_irq
499 irq_restore_user_regs
500
501 .align 5
502fiq:
503 get_fiq_stack
504 /* someone ought to write a more effiction fiq_save_user_regs */
505 irq_save_user_regs
506 bl do_fiq
507 irq_restore_user_regs
508
509#else
510
511 .align 5
512irq:
513 get_bad_stack
514 bad_save_user_regs
515 bl do_irq
516
517 .align 5
518fiq:
519 get_bad_stack
520 bad_save_user_regs
521 bl do_fiq
522
523#endif