Merge with git://www.denx.de/git/u-boot.git
[platform/kernel/u-boot.git] / cpu / arm920t / start.S
1 /*
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
28 #include <config.h>
29 #include <version.h>
30 #if     defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK) || defined(CONFIG_AT91RM9200DF)
31 #include        <led.h>
32 #endif
33
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
77 _TEXT_BASE:
78         .word   TEXT_BASE
79
80 .globl _armboot_start
81 _armboot_start:
82         .word _start
83
84 /*
85  * These are defined in the board-specific linker script.
86  */
87 .globl _bss_start
88 _bss_start:
89         .word __bss_start
90
91 .globl _bss_end
92 _bss_end:
93         .word _end
94
95 #ifdef CONFIG_USE_IRQ
96 /* IRQ stack memory (calculated at run-time) */
97 .globl IRQ_STACK_START
98 IRQ_STACK_START:
99         .word   0x0badc0de
100
101 /* IRQ stack memory (calculated at run-time) */
102 .globl FIQ_STACK_START
103 FIQ_STACK_START:
104         .word 0x0badc0de
105 #endif
106
107
108 /*
109  * the actual reset code
110  */
111
112 reset:
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
121 #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
140 LoopOsc:
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
177 copyex:
178         subs    r2, r2, #1
179         ldr     r3, [r0], #4
180         str     r3, [r1], #4
181         bne     copyex
182 #endif
183
184 /* turn off the watchdog */
185 #if defined(CONFIG_S3C2400)
186 # define pWTCON         0x15300000
187 # define INTMSK         0x14400008      /* Interupt-Controller base addresses */
188 # define CLKDIVN        0x14800014      /* clock divisor register */
189 #elif defined(CONFIG_S3C2410)
190 # define pWTCON         0x53000000
191 # define INTMSK         0x4A000008      /* Interupt-Controller base addresses */
192 # define INTSUBMSK      0x4A00001C
193 # define CLKDIVN        0x4C000014      /* clock divisor register */
194 #endif
195
196 #if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)
197         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]
207 # if defined(CONFIG_S3C2410)
208         ldr     r1, =0x3ff
209         ldr     r0, =INTSUBMSK
210         str     r1, [r0]
211 # endif
212
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]
218 #endif  /* CONFIG_S3C2400 || CONFIG_S3C2410 */
219
220         /*
221          * we do sys-critical inits only at reboot,
222          * not when booting from ram!
223          */
224 #ifndef CONFIG_SKIP_LOWLEVEL_INIT
225         bl      cpu_init_crit
226 #endif
227
228 #ifdef  CONFIG_AT91RM9200
229 #ifdef CONFIG_BOOTBINFUNC
230 relocate:                               /* 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
241 copy_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
248 #ifndef CONFIG_SKIP_RELOCATE_UBOOT
249 relocate:                               /* 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
255         ldr     r2, _armboot_start
256         ldr     r3, _bss_start
257         sub     r2, r3, r2              /* r2 <- size of armboot            */
258         add     r2, r0, r2              /* r2 <- source end address         */
259
260 copy_loop:
261         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]    */
264         ble     copy_loop
265 #endif  /* CONFIG_SKIP_RELOCATE_UBOOT */
266 #endif
267         /* Set up the stack                                                 */
268 stack_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
277 clear_bss:
278         ldr     r0, _bss_start          /* find start of bss segment        */
279         ldr     r1, _bss_end            /* stop here                        */
280         mov     r2, #0x00000000         /* clear                            */
281
282 clbss_l:str     r2, [r0]                /* clear loop...                    */
283         add     r0, r0, #4
284         cmp     r0, r1
285         ble     clbss_l
286
287 #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
308         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
325 #ifndef CONFIG_SKIP_LOWLEVEL_INIT
326 cpu_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
344         /*
345          * before relocating, we have to setup RAM timing
346          * because memory timing is board-dependend, you will
347          * find a lowlevel_init.S in your board directory.
348          */
349         mov     ip, lr
350 #if     defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK) || defined(CONFIG_AT91RM9200DF)
351
352 #else
353         bl      lowlevel_init
354 #endif
355         mov     lr, ip
356         mov     pc, lr
357 #endif /* CONFIG_SKIP_LOWLEVEL_INIT */
358
359 /*
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
403         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
406         ldmia   r2, {r2 - r3}                   @ get pc, cpsr
407         add     r0, sp, #S_FRAME_SIZE           @ restore sp_SVC
408
409         add     r5, sp, #S_SP
410         mov     r1, lr
411         stmia   r5, {r0 - r3}                   @ save sp_SVC, lr_SVC, pc, cpsr
412         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
436         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
439
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
463 undefined_instruction:
464         get_bad_stack
465         bad_save_user_regs
466         bl      do_undefined_instruction
467
468         .align  5
469 software_interrupt:
470         get_bad_stack
471         bad_save_user_regs
472         bl      do_software_interrupt
473
474         .align  5
475 prefetch_abort:
476         get_bad_stack
477         bad_save_user_regs
478         bl      do_prefetch_abort
479
480         .align  5
481 data_abort:
482         get_bad_stack
483         bad_save_user_regs
484         bl      do_data_abort
485
486         .align  5
487 not_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
495 irq:
496         get_irq_stack
497         irq_save_user_regs
498         bl      do_irq
499         irq_restore_user_regs
500
501         .align  5
502 fiq:
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
512 irq:
513         get_bad_stack
514         bad_save_user_regs
515         bl      do_irq
516
517         .align  5
518 fiq:
519         get_bad_stack
520         bad_save_user_regs
521         bl      do_fiq
522
523 #endif