Initial revision
[oweals/u-boot.git] / cpu / sa1100 / start.S
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
29
30 #include <config.h>
31 #include <version.h>
32
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 /*
78  * CFG_MEM_END is in the board dependent config-file (configs/config_BOARD.h)
79  */
80 _TEXT_BASE:
81         .word   TEXT_BASE
82
83 .globl _armboot_start
84 _armboot_start:
85         .word _start
86
87 /*
88  * Note: _armboot_end_data and _armboot_end are defined
89  * by the (board-dependent) linker script.
90  * _armboot_end_data is the first usable FLASH address after armboot
91  */
92 .globl _armboot_end_data
93 _armboot_end_data:
94         .word armboot_end_data
95 .globl _armboot_end
96 _armboot_end:
97         .word armboot_end
98
99 /*
100  * _armboot_real_end is the first usable RAM address behind armboot
101  * and the various stacks
102  */
103 .globl _armboot_real_end
104 _armboot_real_end:
105         .word 0x0badc0de
106
107 #ifdef CONFIG_USE_IRQ
108 /* IRQ stack memory (calculated at run-time) */
109 .globl IRQ_STACK_START
110 IRQ_STACK_START:
111         .word   0x0badc0de
112
113 /* IRQ stack memory (calculated at run-time) */
114 .globl FIQ_STACK_START
115 FIQ_STACK_START:
116         .word 0x0badc0de
117 #endif
118
119
120 /*
121  * the actual reset code
122  */
123
124 reset:
125         /*
126          * set the cpu to SVC32 mode
127          */
128         mrs     r0,cpsr
129         bic     r0,r0,#0x1f
130         orr     r0,r0,#0x13
131         msr     cpsr,r0
132
133         /*
134          * we do sys-critical inits only at reboot,
135          * not when booting from ram!
136          */
137 #ifdef CONFIG_INIT_CRITICAL
138         bl      cpu_init_crit
139 #endif
140
141 relocate:
142         /*
143          * relocate armboot to RAM
144          */
145         adr     r0, _start              /* r0 <- current position of code */
146         ldr     r2, _armboot_start
147         ldr     r3, _armboot_end
148         sub     r2, r3, r2              /* r2 <- size of armboot */
149         ldr     r1, _TEXT_BASE          /* r1 <- destination address */
150         add     r2, r0, r2              /* r2 <- source end address */
151
152         /*
153          * r0 = source address
154          * r1 = target address
155          * r2 = source end address
156          */
157 copy_loop:
158         ldmia   r0!, {r3-r10}
159         stmia   r1!, {r3-r10}
160         cmp     r0, r2
161         ble     copy_loop
162
163         /* set up the stack */
164         ldr     r0, _armboot_end
165         add     r0, r0, #CONFIG_STACKSIZE
166         sub     sp, r0, #12             /* leave 3 words for abort-stack */
167
168         ldr     pc, _start_armboot
169
170 _start_armboot: .word start_armboot
171
172
173 /*
174  *************************************************************************
175  *
176  * CPU_init_critical registers
177  *
178  * setup important registers
179  * setup memory timing
180  *
181  *************************************************************************
182  */
183
184
185 /* Interupt-Controller base address */
186 IC_BASE:        .word   0x90050000
187 #define ICMR    0x04
188
189
190 /* Reset-Controller */
191 RST_BASE:               .word   0x90030000
192 #define RSRR    0x00
193 #define RCSR    0x04
194
195
196 /* PWR */
197 PWR_BASE:               .word   0x90020000
198 #define PSPR    0x08
199 #define PPCR    0x14
200 cpuspeed:               .word   CFG_CPUSPEED
201
202
203 cpu_init_crit:
204         /*
205          * mask all IRQs
206          */
207         ldr     r0, IC_BASE
208         mov     r1, #0x00
209         str     r1, [r0, #ICMR]
210
211         /* set clock speed */
212         ldr     r0, PWR_BASE
213         ldr     r1, cpuspeed
214         str     r1, [r0, #PPCR]
215
216         /*
217          * before relocating, we have to setup RAM timing
218          * because memory timing is board-dependend, you will
219          * find a memsetup.S in your board directory.
220          */
221         mov     ip,     lr
222         bl      memsetup
223         mov     lr,     ip
224
225         /*
226          * disable MMU stuff and enable I-cache
227          */
228         mrc     p15,0,r0,c1,c0
229         bic     r0, r0, #0x00002000     @ clear bit 13 (X)
230         bic     r0, r0, #0x0000000f     @ clear bits 3-0 (WCAM)
231         orr     r0, r0, #0x00001000     @ set bit 12 (I) Icache
232         orr     r0, r0, #0x00000002     @ set bit 2 (A) Align
233         mcr     p15,0,r0,c1,c0
234
235         /*
236          * flush v4 I/D caches
237          */
238         mov     r0, #0
239         mcr     p15, 0, r0, c7, c7, 0   /* flush v3/v4 cache */
240         mcr     p15, 0, r0, c8, c7, 0   /* flush v4 TLB */
241
242         mov     pc, lr
243
244
245
246
247 /*
248  *************************************************************************
249  *
250  * Interrupt handling
251  *
252  *************************************************************************
253  */
254
255 @
256 @ IRQ stack frame.
257 @
258 #define S_FRAME_SIZE    72
259
260 #define S_OLD_R0        68
261 #define S_PSR           64
262 #define S_PC            60
263 #define S_LR            56
264 #define S_SP            52
265
266 #define S_IP            48
267 #define S_FP            44
268 #define S_R10           40
269 #define S_R9            36
270 #define S_R8            32
271 #define S_R7            28
272 #define S_R6            24
273 #define S_R5            20
274 #define S_R4            16
275 #define S_R3            12
276 #define S_R2            8
277 #define S_R1            4
278 #define S_R0            0
279
280 #define MODE_SVC 0x13
281 #define I_BIT    0x80
282
283 /*
284  * use bad_save_user_regs for abort/prefetch/undef/swi ...
285  * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling
286  */
287
288         .macro  bad_save_user_regs
289         sub     sp, sp, #S_FRAME_SIZE
290         stmia   sp, {r0 - r12}                  @ Calling r0-r12
291         add     r8, sp, #S_PC
292
293         ldr     r2, _armboot_end
294         add     r2, r2, #CONFIG_STACKSIZE
295         sub     r2, r2, #8
296         ldmia   r2, {r2 - r4}                   @ get pc, cpsr, old_r0
297         add     r0, sp, #S_FRAME_SIZE           @ restore sp_SVC
298
299         add     r5, sp, #S_SP
300         mov     r1, lr
301         stmia   r5, {r0 - r4}                   @ save sp_SVC, lr_SVC, pc, cpsr, old_r
302         mov     r0, sp
303         .endm
304
305         .macro  irq_save_user_regs
306         sub     sp, sp, #S_FRAME_SIZE
307         stmia   sp, {r0 - r12}                  @ Calling r0-r12
308         add     r8, sp, #S_PC
309         stmdb   r8, {sp, lr}^                   @ Calling SP, LR
310         str     lr, [r8, #0]                    @ Save calling PC
311         mrs     r6, spsr
312         str     r6, [r8, #4]                    @ Save CPSR
313         str     r0, [r8, #8]                    @ Save OLD_R0
314         mov     r0, sp
315         .endm
316
317         .macro  irq_restore_user_regs
318         ldmia   sp, {r0 - lr}^                  @ Calling r0 - lr
319         mov     r0, r0
320         ldr     lr, [sp, #S_PC]                 @ Get PC
321         add     sp, sp, #S_FRAME_SIZE
322         subs    pc, lr, #4                      @ return & move spsr_svc into cpsr
323         .endm
324
325         .macro get_bad_stack
326         ldr     r13, _armboot_end               @ setup our mode stack
327         add     r13, r13, #CONFIG_STACKSIZE     @ resides at top of normal stack
328         sub     r13, r13, #8
329
330         str     lr, [r13]                       @ save caller lr / spsr
331         mrs     lr, spsr
332         str     lr, [r13, #4]
333
334         mov     r13, #MODE_SVC                  @ prepare SVC-Mode
335         msr     spsr_c, r13
336         mov     lr, pc
337         movs    pc, lr
338         .endm
339
340         .macro get_irq_stack                    @ setup IRQ stack
341         ldr     sp, IRQ_STACK_START
342         .endm
343
344         .macro get_fiq_stack                    @ setup FIQ stack
345         ldr     sp, FIQ_STACK_START
346         .endm
347
348 /*
349  * exception handlers
350  */
351         .align  5
352 undefined_instruction:
353         get_bad_stack
354         bad_save_user_regs
355         bl      do_undefined_instruction
356
357         .align  5
358 software_interrupt:
359         get_bad_stack
360         bad_save_user_regs
361         bl      do_software_interrupt
362
363         .align  5
364 prefetch_abort:
365         get_bad_stack
366         bad_save_user_regs
367         bl      do_prefetch_abort
368
369         .align  5
370 data_abort:
371         get_bad_stack
372         bad_save_user_regs
373         bl      do_data_abort
374
375         .align  5
376 not_used:
377         get_bad_stack
378         bad_save_user_regs
379         bl      do_not_used
380
381 #ifdef CONFIG_USE_IRQ
382
383         .align  5
384 irq:
385         get_irq_stack
386         irq_save_user_regs
387         bl      do_irq
388         irq_restore_user_regs
389
390         .align  5
391 fiq:
392         get_fiq_stack
393         /* someone ought to write a more effiction fiq_save_user_regs */
394         irq_save_user_regs
395         bl      do_fiq
396         irq_restore_user_regs
397
398 #else
399
400         .align  5
401 irq:
402         get_bad_stack
403         bad_save_user_regs
404         bl      do_irq
405
406         .align  5
407 fiq:
408         get_bad_stack
409         bad_save_user_regs
410         bl      do_fiq
411
412 #endif
413
414         .align  5
415 .globl reset_cpu
416 reset_cpu:
417         ldr     r0, RST_BASE
418         mov     r1, #0x0                        @ set bit 3-0 ...
419         str     r1, [r0, #RCSR]                 @ ... to clear in RCSR
420         mov     r1, #0x1
421         str     r1, [r0, #RSRR]                 @ and perform reset
422         b       reset_cpu                       @ silly, but repeat endlessly