blob: 1bc6099b4ef170aa3cbf67c3a3a62131ad2f1fa5 [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 Pearse2c261ca2007-09-04 16:18:38 +010030#include <asm/led.h>
wdenkfe8c2802002-11-03 00:38:21 +000031
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
wdenkfe8c2802002-11-03 00:38:21 +000075_TEXT_BASE:
76 .word TEXT_BASE
77
78.globl _armboot_start
79_armboot_start:
80 .word _start
81
82/*
wdenk927034e2004-02-08 19:38:38 +000083 * These are defined in the board-specific linker script.
wdenkfe8c2802002-11-03 00:38:21 +000084 */
wdenk927034e2004-02-08 19:38:38 +000085.globl _bss_start
86_bss_start:
87 .word __bss_start
88
89.globl _bss_end
90_bss_end:
91 .word _end
wdenkfe8c2802002-11-03 00:38:21 +000092
wdenkfe8c2802002-11-03 00:38:21 +000093#ifdef CONFIG_USE_IRQ
94/* IRQ stack memory (calculated at run-time) */
95.globl IRQ_STACK_START
96IRQ_STACK_START:
97 .word 0x0badc0de
98
99/* IRQ stack memory (calculated at run-time) */
100.globl FIQ_STACK_START
101FIQ_STACK_START:
102 .word 0x0badc0de
103#endif
104
105
106/*
107 * the actual reset code
108 */
109
110reset:
111 /*
112 * set the cpu to SVC32 mode
113 */
114 mrs r0,cpsr
115 bic r0,r0,#0x1f
116 orr r0,r0,#0xd3
117 msr cpsr,r0
Peter Pearse2c261ca2007-09-04 16:18:38 +0100118 /*
119 * if board has a red led use it to show U-Boot is running
120 */
121 bl coloured_LED_init
Peter Pearsede5b02c2007-08-14 10:10:52 +0100122 bl red_LED_on
Peter Pearsede5b02c2007-08-14 10:10:52 +0100123
Peter Pearse2c261ca2007-09-04 16:18:38 +0100124#ifdef CONFIG_AT91RM9200
Peter Pearsede5b02c2007-08-14 10:10:52 +0100125#ifdef CONFIG_BOOTBINFUNC
126/* code based on entry.S from ATMEL */
127#define AT91C_BASE_CKGR 0xFFFFFC20
128#define CKGR_MOR 0
129 /* Get the CKGR Base Address */
130 ldr r1, =AT91C_BASE_CKGR
131
132/* Main oscillator Enable register APMC_MOR : Enable main oscillator , OSCOUNT = 0xFF */
133/* ldr r0, = AT91C_CKGR_MOSCEN:OR:AT91C_CKGR_OSCOUNT */
134 ldr r0, =0x0000FF01
135 str r0, [r1, #CKGR_MOR]
136 /* Add loop to compensate Main Oscillator startup time */
137 ldr r0, =0x00000010
138LoopOsc:
139 subs r0, r0, #1
140 bhi LoopOsc
141 /* scratch stack */
142 ldr r1, =0x00204000
143 /* Insure word alignment */
144 bic r1, r1, #3
145 /* Init stack SYS */
146 mov sp, r1
147 /*
148 * This does a lot more than just set up the memory, which
149 * is why it's called lowlevelinit
150 */
151 bl lowlevelinit /* in memsetup.S */
152 bl icache_enable;
153 /* ------------------------------------
154 * Read/modify/write CP15 control register
155 * -------------------------------------
156 * read cp15 control register (cp15 r1) in r0
157 * ------------------------------------
158 */
159 mrc p15, 0, r0, c1, c0, 0
160 /* Reset bit :Little Endian end fast bus mode */
161 ldr r3, =0xC0000080
162 /* Set bit :Asynchronous clock mode, Not Fast Bus */
163 ldr r4, =0xC0000000
164 bic r0, r0, r3
165 orr r0, r0, r4
166 /* write r0 in cp15 control register (cp15 r1) */
167 mcr p15, 0, r0, c1, c0, 0
168#endif /* CONFIG_BOOTBINFUNC */
169 /*
170 * relocate exeception table
171 */
172 ldr r0, =_start
173 ldr r1, =0x0
174 mov r2, #16
175copyex:
176 subs r2, r2, #1
177 ldr r3, [r0], #4
178 str r3, [r1], #4
179 bne copyex
180#endif
181
wdenkfe8c2802002-11-03 00:38:21 +0000182/* turn off the watchdog */
183#if defined(CONFIG_S3C2400)
wdenk7ac16102004-08-01 22:48:16 +0000184# define pWTCON 0x15300000
185# define INTMSK 0x14400008 /* Interupt-Controller base addresses */
186# define CLKDIVN 0x14800014 /* clock divisor register */
wdenkfe8c2802002-11-03 00:38:21 +0000187#elif defined(CONFIG_S3C2410)
wdenk7ac16102004-08-01 22:48:16 +0000188# define pWTCON 0x53000000
189# define INTMSK 0x4A000008 /* Interupt-Controller base addresses */
190# define INTSUBMSK 0x4A00001C
191# define CLKDIVN 0x4C000014 /* clock divisor register */
wdenkfe8c2802002-11-03 00:38:21 +0000192#endif
193
wdenk7ac16102004-08-01 22:48:16 +0000194#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)
wdenkfe8c2802002-11-03 00:38:21 +0000195 ldr r0, =pWTCON
196 mov r1, #0x0
197 str r1, [r0]
198
199 /*
200 * mask all IRQs by setting all bits in the INTMR - default
201 */
202 mov r1, #0xffffffff
203 ldr r0, =INTMSK
204 str r1, [r0]
wdenk7ac16102004-08-01 22:48:16 +0000205# if defined(CONFIG_S3C2410)
wdenkfe8c2802002-11-03 00:38:21 +0000206 ldr r1, =0x3ff
207 ldr r0, =INTSUBMSK
208 str r1, [r0]
wdenk7ac16102004-08-01 22:48:16 +0000209# endif
wdenkfe8c2802002-11-03 00:38:21 +0000210
211 /* FCLK:HCLK:PCLK = 1:2:4 */
212 /* default FCLK is 120 MHz ! */
213 ldr r0, =CLKDIVN
214 mov r1, #3
215 str r1, [r0]
wdenk7ac16102004-08-01 22:48:16 +0000216#endif /* CONFIG_S3C2400 || CONFIG_S3C2410 */
wdenkfe8c2802002-11-03 00:38:21 +0000217
218 /*
219 * we do sys-critical inits only at reboot,
220 * not when booting from ram!
221 */
wdenk3d3d99f2005-04-04 12:44:11 +0000222#ifndef CONFIG_SKIP_LOWLEVEL_INIT
wdenkfe8c2802002-11-03 00:38:21 +0000223 bl cpu_init_crit
224#endif
225
Peter Pearsede5b02c2007-08-14 10:10:52 +0100226#ifdef CONFIG_AT91RM9200
227#ifdef CONFIG_BOOTBINFUNC
228relocate: /* relocate U-Boot to RAM */
229 adr r0, _start /* r0 <- current position of code */
230 ldr r1, _TEXT_BASE /* test if we run from flash or RAM */
231 cmp r0, r1 /* don't reloc during debug */
232 beq stack_setup
233
234 ldr r2, _armboot_start
235 ldr r3, _bss_start
236 sub r2, r3, r2 /* r2 <- size of armboot */
237 add r2, r0, r2 /* r2 <- source end address */
238
239copy_loop:
240 ldmia r0!, {r3-r10} /* copy from source address [r0] */
241 stmia r1!, {r3-r10} /* copy to target address [r1] */
242 cmp r0, r2 /* until source end addreee [r2] */
243 ble copy_loop
244#endif /* CONFIG_BOOTBINFUNC */
245#else
wdenk3d3d99f2005-04-04 12:44:11 +0000246#ifndef CONFIG_SKIP_RELOCATE_UBOOT
wdenkc0aa5c52003-12-06 19:49:23 +0000247relocate: /* relocate U-Boot to RAM */
248 adr r0, _start /* r0 <- current position of code */
249 ldr r1, _TEXT_BASE /* test if we run from flash or RAM */
250 cmp r0, r1 /* don't reloc during debug */
251 beq stack_setup
252
wdenkfe8c2802002-11-03 00:38:21 +0000253 ldr r2, _armboot_start
wdenk927034e2004-02-08 19:38:38 +0000254 ldr r3, _bss_start
wdenkc0aa5c52003-12-06 19:49:23 +0000255 sub r2, r3, r2 /* r2 <- size of armboot */
256 add r2, r0, r2 /* r2 <- source end address */
wdenkfe8c2802002-11-03 00:38:21 +0000257
wdenkfe8c2802002-11-03 00:38:21 +0000258copy_loop:
wdenkc0aa5c52003-12-06 19:49:23 +0000259 ldmia r0!, {r3-r10} /* copy from source address [r0] */
260 stmia r1!, {r3-r10} /* copy to target address [r1] */
261 cmp r0, r2 /* until source end addreee [r2] */
wdenkfe8c2802002-11-03 00:38:21 +0000262 ble copy_loop
wdenk3d3d99f2005-04-04 12:44:11 +0000263#endif /* CONFIG_SKIP_RELOCATE_UBOOT */
Peter Pearsede5b02c2007-08-14 10:10:52 +0100264#endif
wdenkc0aa5c52003-12-06 19:49:23 +0000265 /* Set up the stack */
266stack_setup:
267 ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
268 sub r0, r0, #CFG_MALLOC_LEN /* malloc area */
269 sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */
270#ifdef CONFIG_USE_IRQ
271 sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
272#endif
273 sub sp, r0, #12 /* leave 3 words for abort-stack */
274
wdenk927034e2004-02-08 19:38:38 +0000275clear_bss:
276 ldr r0, _bss_start /* find start of bss segment */
wdenk927034e2004-02-08 19:38:38 +0000277 ldr r1, _bss_end /* stop here */
278 mov r2, #0x00000000 /* clear */
279
280clbss_l:str r2, [r0] /* clear loop... */
281 add r0, r0, #4
282 cmp r0, r1
wdenk26c58432005-01-09 17:12:27 +0000283 ble clbss_l
wdenk927034e2004-02-08 19:38:38 +0000284
wdenkfe8c2802002-11-03 00:38:21 +0000285#if 0
286 /* try doing this stuff after the relocation */
287 ldr r0, =pWTCON
288 mov r1, #0x0
289 str r1, [r0]
290
291 /*
292 * mask all IRQs by setting all bits in the INTMR - default
293 */
294 mov r1, #0xffffffff
295 ldr r0, =INTMR
296 str r1, [r0]
297
298 /* FCLK:HCLK:PCLK = 1:2:4 */
299 /* default FCLK is 120 MHz ! */
300 ldr r0, =CLKDIVN
301 mov r1, #3
302 str r1, [r0]
303 /* END stuff after relocation */
304#endif
305
wdenkfe8c2802002-11-03 00:38:21 +0000306 ldr pc, _start_armboot
307
308_start_armboot: .word start_armboot
309
310
311/*
312 *************************************************************************
313 *
314 * CPU_init_critical registers
315 *
316 * setup important registers
317 * setup memory timing
318 *
319 *************************************************************************
320 */
321
322
Wolfgang Denkf2e11a72006-04-03 15:46:10 +0200323#ifndef CONFIG_SKIP_LOWLEVEL_INIT
wdenkfe8c2802002-11-03 00:38:21 +0000324cpu_init_crit:
325 /*
326 * flush v4 I/D caches
327 */
328 mov r0, #0
329 mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */
330 mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */
331
332 /*
333 * disable MMU stuff and caches
334 */
335 mrc p15, 0, r0, c1, c0, 0
336 bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS)
337 bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM)
338 orr r0, r0, #0x00000002 @ set bit 2 (A) Align
339 orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache
340 mcr p15, 0, r0, c1, c0, 0
341
wdenkfe8c2802002-11-03 00:38:21 +0000342 /*
343 * before relocating, we have to setup RAM timing
344 * because memory timing is board-dependend, you will
wdenk336b2bc2005-04-02 23:52:25 +0000345 * find a lowlevel_init.S in your board directory.
wdenkfe8c2802002-11-03 00:38:21 +0000346 */
347 mov ip, lr
Peter Pearsede5b02c2007-08-14 10:10:52 +0100348#if defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK) || defined(CONFIG_AT91RM9200DF)
349
350#else
wdenk336b2bc2005-04-02 23:52:25 +0000351 bl lowlevel_init
Peter Pearsede5b02c2007-08-14 10:10:52 +0100352#endif
wdenkfe8c2802002-11-03 00:38:21 +0000353 mov lr, ip
wdenkfe8c2802002-11-03 00:38:21 +0000354 mov pc, lr
Wolfgang Denkf2e11a72006-04-03 15:46:10 +0200355#endif /* CONFIG_SKIP_LOWLEVEL_INIT */
wdenkfe8c2802002-11-03 00:38:21 +0000356
wdenkfe8c2802002-11-03 00:38:21 +0000357/*
358 *************************************************************************
359 *
360 * Interrupt handling
361 *
362 *************************************************************************
363 */
364
365@
366@ IRQ stack frame.
367@
368#define S_FRAME_SIZE 72
369
370#define S_OLD_R0 68
371#define S_PSR 64
372#define S_PC 60
373#define S_LR 56
374#define S_SP 52
375
376#define S_IP 48
377#define S_FP 44
378#define S_R10 40
379#define S_R9 36
380#define S_R8 32
381#define S_R7 28
382#define S_R6 24
383#define S_R5 20
384#define S_R4 16
385#define S_R3 12
386#define S_R2 8
387#define S_R1 4
388#define S_R0 0
389
390#define MODE_SVC 0x13
391#define I_BIT 0x80
392
393/*
394 * use bad_save_user_regs for abort/prefetch/undef/swi ...
395 * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling
396 */
397
398 .macro bad_save_user_regs
399 sub sp, sp, #S_FRAME_SIZE
400 stmia sp, {r0 - r12} @ Calling r0-r12
wdenk927034e2004-02-08 19:38:38 +0000401 ldr r2, _armboot_start
402 sub r2, r2, #(CONFIG_STACKSIZE+CFG_MALLOC_LEN)
403 sub r2, r2, #(CFG_GBL_DATA_SIZE+8) @ set base 2 words into abort stack
wdenkf4688a22003-05-28 08:06:31 +0000404 ldmia r2, {r2 - r3} @ get pc, cpsr
wdenkfe8c2802002-11-03 00:38:21 +0000405 add r0, sp, #S_FRAME_SIZE @ restore sp_SVC
406
407 add r5, sp, #S_SP
408 mov r1, lr
wdenkf4688a22003-05-28 08:06:31 +0000409 stmia r5, {r0 - r3} @ save sp_SVC, lr_SVC, pc, cpsr
wdenkfe8c2802002-11-03 00:38:21 +0000410 mov r0, sp
411 .endm
412
413 .macro irq_save_user_regs
414 sub sp, sp, #S_FRAME_SIZE
415 stmia sp, {r0 - r12} @ Calling r0-r12
416 add r8, sp, #S_PC
417 stmdb r8, {sp, lr}^ @ Calling SP, LR
418 str lr, [r8, #0] @ Save calling PC
419 mrs r6, spsr
420 str r6, [r8, #4] @ Save CPSR
421 str r0, [r8, #8] @ Save OLD_R0
422 mov r0, sp
423 .endm
424
425 .macro irq_restore_user_regs
426 ldmia sp, {r0 - lr}^ @ Calling r0 - lr
427 mov r0, r0
428 ldr lr, [sp, #S_PC] @ Get PC
429 add sp, sp, #S_FRAME_SIZE
430 subs pc, lr, #4 @ return & move spsr_svc into cpsr
431 .endm
432
433 .macro get_bad_stack
wdenk927034e2004-02-08 19:38:38 +0000434 ldr r13, _armboot_start @ setup our mode stack
435 sub r13, r13, #(CONFIG_STACKSIZE+CFG_MALLOC_LEN)
436 sub r13, r13, #(CFG_GBL_DATA_SIZE+8) @ reserved a couple spots in abort stack
wdenkfe8c2802002-11-03 00:38:21 +0000437
438 str lr, [r13] @ save caller lr / spsr
439 mrs lr, spsr
440 str lr, [r13, #4]
441
442 mov r13, #MODE_SVC @ prepare SVC-Mode
443 @ msr spsr_c, r13
444 msr spsr, r13
445 mov lr, pc
446 movs pc, lr
447 .endm
448
449 .macro get_irq_stack @ setup IRQ stack
450 ldr sp, IRQ_STACK_START
451 .endm
452
453 .macro get_fiq_stack @ setup FIQ stack
454 ldr sp, FIQ_STACK_START
455 .endm
456
457/*
458 * exception handlers
459 */
460 .align 5
461undefined_instruction:
462 get_bad_stack
463 bad_save_user_regs
464 bl do_undefined_instruction
465
466 .align 5
467software_interrupt:
468 get_bad_stack
469 bad_save_user_regs
470 bl do_software_interrupt
471
472 .align 5
473prefetch_abort:
474 get_bad_stack
475 bad_save_user_regs
476 bl do_prefetch_abort
477
478 .align 5
479data_abort:
480 get_bad_stack
481 bad_save_user_regs
482 bl do_data_abort
483
484 .align 5
485not_used:
486 get_bad_stack
487 bad_save_user_regs
488 bl do_not_used
489
490#ifdef CONFIG_USE_IRQ
491
492 .align 5
493irq:
494 get_irq_stack
495 irq_save_user_regs
496 bl do_irq
497 irq_restore_user_regs
498
499 .align 5
500fiq:
501 get_fiq_stack
502 /* someone ought to write a more effiction fiq_save_user_regs */
503 irq_save_user_regs
504 bl do_fiq
505 irq_restore_user_regs
506
507#else
508
509 .align 5
510irq:
511 get_bad_stack
512 bad_save_user_regs
513 bl do_irq
514
515 .align 5
516fiq:
517 get_bad_stack
518 bad_save_user_regs
519 bl do_fiq
520
521#endif