ARM: */start.S: code cleanup
[oweals/u-boot.git] / arch / arm / cpu / pxa / start.S
1 /*
2  *  armboot - Startup Code for XScale
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 Zuepke <azu@sysgo.de>
8  *  Copyright (C) 2002  Kyle Harris <kharris@nexus-tech.net>
9  *  Copyright (C) 2003  Robert Schwebel <r.schwebel@pengutronix.de>
10  *  Copyright (C) 2003  Kai-Uwe Bloem <kai-uwe.bloem@auerswald.de>
11  *  Copyright (c) 2010  Marek Vasut <marek.vasut@gmail.com>
12  *
13  * See file CREDITS for list of people who contributed to this
14  * project.
15  *
16  * This program is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU General Public License as
18  * published by the Free Software Foundation; either version 2 of
19  * the License, or (at your option) any later version.
20  *
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  *
26  * You should have received a copy of the GNU General Public License
27  * along with this program; if not, write to the Free Software
28  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
29  * MA 02111-1307 USA
30  */
31
32 #include <asm-offsets.h>
33 #include <config.h>
34 #include <version.h>
35 #include <asm/arch/pxa-regs.h>
36
37 /* takes care the CP15 update has taken place */
38 .macro CPWAIT reg
39 mrc  p15,0,\reg,c2,c0,0
40 mov  \reg,\reg
41 sub  pc,pc,#4
42 .endm
43
44 .globl _start
45 _start: b       reset
46 #ifdef CONFIG_PRELOADER
47         ldr     pc, _hang
48         ldr     pc, _hang
49         ldr     pc, _hang
50         ldr     pc, _hang
51         ldr     pc, _hang
52         ldr     pc, _hang
53         ldr     pc, _hang
54
55 _hang:
56         .word   do_hang
57         .word   0x12345678
58         .word   0x12345678
59         .word   0x12345678
60         .word   0x12345678
61         .word   0x12345678
62         .word   0x12345678
63         .word   0x12345678      /* now 16*4=64 */
64 #else
65         ldr     pc, _undefined_instruction
66         ldr     pc, _software_interrupt
67         ldr     pc, _prefetch_abort
68         ldr     pc, _data_abort
69         ldr     pc, _not_used
70         ldr     pc, _irq
71         ldr     pc, _fiq
72
73 _undefined_instruction: .word undefined_instruction
74 _software_interrupt:    .word software_interrupt
75 _prefetch_abort:        .word prefetch_abort
76 _data_abort:            .word data_abort
77 _not_used:              .word not_used
78 _irq:                   .word irq
79 _fiq:                   .word fiq
80 #endif  /* CONFIG_PRELOADER */
81
82         .balignl 16,0xdeadbeef
83
84
85 /*
86  * Startup Code (reset vector)
87  *
88  * do important init only if we don't start from RAM!
89  * - relocate armboot to RAM
90  * - setup stack
91  * - jump to second stage
92  */
93
94 .globl _TEXT_BASE
95 _TEXT_BASE:
96         .word   CONFIG_SYS_TEXT_BASE
97
98 /*
99  * These are defined in the board-specific linker script.
100  */
101 .globl _bss_start_ofs
102 _bss_start_ofs:
103         .word __bss_start - _start
104
105 .globl _bss_end_ofs
106 _bss_end_ofs:
107         .word _end - _start
108
109 #ifdef CONFIG_USE_IRQ
110 /* IRQ stack memory (calculated at run-time) */
111 .globl IRQ_STACK_START
112 IRQ_STACK_START:
113         .word   0x0badc0de
114
115 /* IRQ stack memory (calculated at run-time) */
116 .globl FIQ_STACK_START
117 FIQ_STACK_START:
118         .word 0x0badc0de
119 #endif /* CONFIG_USE_IRQ */
120
121 #ifndef CONFIG_PRELOADER
122 /* IRQ stack memory (calculated at run-time) + 8 bytes */
123 .globl IRQ_STACK_START_IN
124 IRQ_STACK_START_IN:
125         .word   0x0badc0de
126
127 /*
128  * the actual reset code
129  */
130
131 reset:
132         /*
133          * set the cpu to SVC32 mode
134          */
135         mrs     r0,cpsr
136         bic     r0,r0,#0x1f
137         orr     r0,r0,#0xd3
138         msr     cpsr,r0
139
140         /*
141          * Enable MMU to use DCache as DRAM
142          */
143         /* Domain access -- enable for all CPs */
144         ldr     r0, =0x0000ffff
145         mcr     p15, 0, r0, c3, c0, 0
146
147         /* Point TTBR to MMU table */
148         ldr     r0, =mmu_table
149         adr     r2, _start
150         orr     r0, r2
151         mcr     p15, 0, r0, c2, c0, 0
152
153 /* !!! Hereby, check if the code is running from SRAM !!! */
154 /* If the code is running from SRAM, alias SRAM to 0x0 to simulate NOR. The code
155  * is linked to 0x0 too, so this makes things easier. */
156         cmp     r2, #0x5c000000
157
158         ldreq   r1, [r0]
159         orreq   r1, r2
160         streq   r1, [r0]
161
162         /* Kick in MMU, ICache, DCache, BTB */
163         mrc     p15, 0, r0, c1, c0, 0
164         bic     r0, #0x1b00
165         bic     r0, #0x0087
166         orr     r0, #0x1800
167         orr     r0, #0x0005
168         mcr     p15, 0, r0, c1, c0, 0
169         CPWAIT  r0
170
171         /* Unlock Icache, Dcache */
172         mcr     p15, 0, r0, c9, c1, 1
173         mcr     p15, 0, r0, c9, c2, 1
174
175         /* Flush Icache, Dcache, BTB */
176         mcr     p15, 0, r0, c7, c7, 0
177
178         /* Unlock I-TLB, D-TLB */
179         mcr     p15, 0, r0, c10, c4, 1
180         mcr     p15, 0, r0, c10, c8, 1
181
182         /* Flush TLB */
183         mcr     p15, 0, r0, c8, c7, 0
184         /* Allocate 4096 bytes of Dcache as RAM */
185
186         /* Drain pending loads and stores */
187         mcr     p15, 0, r0, c7, c10, 4
188
189         mov     r4, #0x00
190         mov     r5, #0x00
191         mov     r2, #0x01
192         mcr     p15, 0, r0, c9, c2, 0
193         CPWAIT  r0
194
195         /* 128 lines reserved (128 x 32bytes = 4096 bytes total) */
196         mov     r0, #128
197         mov     r1, #0xa0000000
198 alloc:
199         mcr     p15, 0, r1, c7, c2, 5
200         /* Drain pending loads and stores */
201         mcr     p15, 0, r0, c7, c10, 4
202         strd    r4, [r1], #8
203         strd    r4, [r1], #8
204         strd    r4, [r1], #8
205         strd    r4, [r1], #8
206         subs    r0, #0x01
207         bne     alloc
208         /* Drain pending loads and stores */
209         mcr     p15, 0, r0, c7, c10, 4
210         mov     r2, #0x00
211         mcr     p15, 0, r2, c9, c2, 0
212         CPWAIT  r0
213
214         /* Jump to 0x0 ( + offset) if running from SRAM */
215         adr     r0, zerojmp
216         bic     r0, #0x5c000000
217         mov     pc, r0
218 zerojmp:
219
220 /* Set stackpointer in internal RAM to call board_init_f */
221 call_board_init_f:
222         ldr     sp, =(CONFIG_SYS_INIT_SP_ADDR)
223         bic     sp, sp, #7 /* 8-byte alignment for ABI compliance */
224         ldr     r0,=0x00000000
225         bl      board_init_f
226
227 /*------------------------------------------------------------------------------*/
228
229 /*
230  * void relocate_code (addr_sp, gd, addr_moni)
231  *
232  * This "function" does not return, instead it continues in RAM
233  * after relocating the monitor code.
234  *
235  */
236         .globl  relocate_code
237 relocate_code:
238         mov     r4, r0  /* save addr_sp */
239         mov     r5, r1  /* save addr of gd */
240         mov     r6, r2  /* save addr of destination */
241
242         /* Set up the stack                                                 */
243 stack_setup:
244         mov     sp, r4
245
246         adr     r0, _start
247         cmp     r0, r6
248         beq     clear_bss               /* skip relocation */
249         mov     r1, r6                  /* r1 <- scratch for copy_loop */
250         ldr     r3, _bss_start_ofs
251         add     r2, r0, r3              /* r2 <- source end address         */
252
253         stmfd sp!, {r0-r12}
254 copy_loop:
255         ldmia   r0!, {r3-r5, r7-r11}    /* copy from source address [r0]    */
256         stmia   r1!, {r3-r5, r7-r11}    /* copy to   target address [r1]    */
257         cmp     r0, r2                  /* until source end address [r2]    */
258         blo     copy_loop
259         ldmfd sp!, {r0-r12}
260
261 #ifndef CONFIG_PRELOADER
262         /*
263          * fix .rel.dyn relocations
264          */
265         ldr     r0, _TEXT_BASE          /* r0 <- Text base */
266         sub     r9, r6, r0              /* r9 <- relocation offset */
267         ldr     r10, _dynsym_start_ofs  /* r10 <- sym table ofs */
268         add     r10, r10, r0            /* r10 <- sym table in FLASH */
269         ldr     r2, _rel_dyn_start_ofs  /* r2 <- rel dyn start ofs */
270         add     r2, r2, r0              /* r2 <- rel dyn start in FLASH */
271         ldr     r3, _rel_dyn_end_ofs    /* r3 <- rel dyn end ofs */
272         add     r3, r3, r0              /* r3 <- rel dyn end in FLASH */
273 fixloop:
274         ldr     r0, [r2]        /* r0 <- location to fix up, IN FLASH! */
275         add     r0, r9          /* r0 <- location to fix up in RAM */
276         ldr     r1, [r2, #4]
277         and     r7, r1, #0xff
278         cmp     r7, #23         /* relative fixup? */
279         beq     fixrel
280         cmp     r7, #2          /* absolute fixup? */
281         beq     fixabs
282         /* ignore unknown type of fixup */
283         b       fixnext
284 fixabs:
285         /* absolute fix: set location to (offset) symbol value */
286         mov     r1, r1, LSR #4          /* r1 <- symbol index in .dynsym */
287         add     r1, r10, r1             /* r1 <- address of symbol in table */
288         ldr     r1, [r1, #4]            /* r1 <- symbol value */
289         add     r1, r1, r9              /* r1 <- relocated sym addr */
290         b       fixnext
291 fixrel:
292         /* relative fix: increase location by offset */
293         ldr     r1, [r0]
294         add     r1, r1, r9
295 fixnext:
296         str     r1, [r0]
297         add     r2, r2, #8      /* each rel.dyn entry is 8 bytes */
298         cmp     r2, r3
299         blo     fixloop
300 #endif  /* #ifndef CONFIG_PRELOADER */
301
302 clear_bss:
303 #ifndef CONFIG_PRELOADER
304         ldr     r0, _bss_start_ofs
305         ldr     r1, _bss_end_ofs
306         mov     r4, r6                  /* reloc addr */
307         add     r0, r0, r4
308         add     r1, r1, r4
309         mov     r2, #0x00000000         /* clear                            */
310
311 clbss_l:str     r2, [r0]                /* clear loop...                    */
312         add     r0, r0, #4
313         cmp     r0, r1
314         bne     clbss_l
315 #endif  /* #ifndef CONFIG_PRELOADER */
316
317 /*
318  * We are done. Do not return, instead branch to second part of board
319  * initialization, now running from RAM.
320  */
321 #ifdef CONFIG_ONENAND_IPL
322         ldr     r0, _start_oneboot_ofs
323         mov     pc, r0
324
325 _start_oneboot_ofs
326         : .word start_oneboot
327 #else
328         ldr     r0, _board_init_r_ofs
329         adr     r1, _start
330         add     lr, r0, r1
331         add     lr, lr, r9
332         /* setup parameters for board_init_r */
333         mov     r0, r5          /* gd_t */
334         mov     r1, r6          /* dest_addr */
335         /* jump to it ... */
336         mov     pc, lr
337
338 _board_init_r_ofs:
339         .word board_init_r - _start
340 #endif  /* CONFIG_ONENAND_IPL */
341
342 _rel_dyn_start_ofs:
343         .word __rel_dyn_start - _start
344 _rel_dyn_end_ofs:
345         .word __rel_dyn_end - _start
346 _dynsym_start_ofs:
347         .word __dynsym_start - _start
348
349 #else /* CONFIG_PRELOADER */
350
351 /****************************************************************************/
352 /*                                                                          */
353 /* the actual reset code for OneNAND IPL                                    */
354 /*                                                                          */
355 /****************************************************************************/
356
357 #ifndef CONFIG_PXA27X
358 #error OneNAND IPL is not supported on PXA25x and 26x due to lack of SRAM
359 #endif
360
361 reset:
362         /* Set CPU to SVC32 mode */
363         mrs     r0,cpsr
364         bic     r0,r0,#0x1f
365         orr     r0,r0,#0x13
366         msr     cpsr,r0
367
368         /* Point stack at the end of SRAM and leave 32 words for abort-stack */
369         ldr     sp, =0x5c03ff80
370
371         /* Start OneNAND IPL */
372         ldr     pc, =start_oneboot
373
374 #endif /* CONFIG_PRELOADER */
375
376 #ifndef CONFIG_PRELOADER
377 /****************************************************************************/
378 /*                                                                          */
379 /* Interrupt handling                                                       */
380 /*                                                                          */
381 /****************************************************************************/
382
383 /* IRQ stack frame                                                          */
384
385 #define S_FRAME_SIZE    72
386
387 #define S_OLD_R0        68
388 #define S_PSR           64
389 #define S_PC            60
390 #define S_LR            56
391 #define S_SP            52
392
393 #define S_IP            48
394 #define S_FP            44
395 #define S_R10           40
396 #define S_R9            36
397 #define S_R8            32
398 #define S_R7            28
399 #define S_R6            24
400 #define S_R5            20
401 #define S_R4            16
402 #define S_R3            12
403 #define S_R2            8
404 #define S_R1            4
405 #define S_R0            0
406
407 #define MODE_SVC 0x13
408
409         /* use bad_save_user_regs for abort/prefetch/undef/swi ...          */
410
411         .macro  bad_save_user_regs
412         sub     sp, sp, #S_FRAME_SIZE
413         stmia   sp, {r0 - r12}                  /* Calling r0-r12           */
414         add     r8, sp, #S_PC
415
416         ldr     r2, IRQ_STACK_START_IN
417         ldmia   r2, {r2 - r4}                   /* get pc, cpsr, old_r0     */
418         add     r0, sp, #S_FRAME_SIZE           /* restore sp_SVC           */
419
420         add     r5, sp, #S_SP
421         mov     r1, lr
422         stmia   r5, {r0 - r4}                   /* save sp_SVC, lr_SVC, pc, cpsr, old_r */
423         mov     r0, sp
424         .endm
425
426
427         /* use irq_save_user_regs / irq_restore_user_regs for                */
428         /* IRQ/FIQ handling                                                  */
429
430         .macro  irq_save_user_regs
431         sub     sp, sp, #S_FRAME_SIZE
432         stmia   sp, {r0 - r12}                  /* Calling r0-r12            */
433         add     r8, sp, #S_PC
434         stmdb   r8, {sp, lr}^                   /* Calling SP, LR            */
435         str     lr, [r8, #0]                    /* Save calling PC           */
436         mrs     r6, spsr
437         str     r6, [r8, #4]                    /* Save CPSR                 */
438         str     r0, [r8, #8]                    /* Save OLD_R0               */
439         mov     r0, sp
440         .endm
441
442         .macro  irq_restore_user_regs
443         ldmia   sp, {r0 - lr}^                  @ Calling r0 - lr
444         mov     r0, r0
445         ldr     lr, [sp, #S_PC]                 @ Get PC
446         add     sp, sp, #S_FRAME_SIZE
447         subs    pc, lr, #4                      @ return & move spsr_svc into cpsr
448         .endm
449
450         .macro get_bad_stack
451         ldr     r13, IRQ_STACK_START_IN         @ setup our mode stack
452
453         str     lr, [r13]                       @ save caller lr / spsr
454         mrs     lr, spsr
455         str     lr, [r13, #4]
456
457         mov     r13, #MODE_SVC                  @ prepare SVC-Mode
458         msr     spsr_c, r13
459         mov     lr, pc
460         movs    pc, lr
461         .endm
462
463         .macro get_irq_stack                    @ setup IRQ stack
464         ldr     sp, IRQ_STACK_START
465         .endm
466
467         .macro get_fiq_stack                    @ setup FIQ stack
468         ldr     sp, FIQ_STACK_START
469         .endm
470 #endif  /* CONFIG_PRELOADER
471
472
473 /****************************************************************************/
474 /*                                                                          */
475 /* exception handlers                                                       */
476 /*                                                                          */
477 /****************************************************************************/
478
479 #ifdef CONFIG_PRELOADER
480         .align  5
481 do_hang:
482         ldr     sp, _TEXT_BASE                  /* use 32 words abort stack */
483         bl      hang                            /* hang and never return */
484 #else
485         .align  5
486 undefined_instruction:
487         get_bad_stack
488         bad_save_user_regs
489         bl      do_undefined_instruction
490
491         .align  5
492 software_interrupt:
493         get_bad_stack
494         bad_save_user_regs
495         bl      do_software_interrupt
496
497         .align  5
498 prefetch_abort:
499         get_bad_stack
500         bad_save_user_regs
501         bl      do_prefetch_abort
502
503         .align  5
504 data_abort:
505         get_bad_stack
506         bad_save_user_regs
507         bl      do_data_abort
508
509         .align  5
510 not_used:
511         get_bad_stack
512         bad_save_user_regs
513         bl      do_not_used
514
515 #ifdef CONFIG_USE_IRQ
516
517         .align  5
518 irq:
519         get_irq_stack
520         irq_save_user_regs
521         bl      do_irq
522         irq_restore_user_regs
523
524         .align  5
525 fiq:
526         get_fiq_stack
527         irq_save_user_regs              /* someone ought to write a more    */
528         bl      do_fiq                  /* effiction fiq_save_user_regs     */
529         irq_restore_user_regs
530
531 #else /* !CONFIG_USE_IRQ */
532
533         .align  5
534 irq:
535         get_bad_stack
536         bad_save_user_regs
537         bl      do_irq
538
539         .align  5
540 fiq:
541         get_bad_stack
542         bad_save_user_regs
543         bl      do_fiq
544 #endif  /* CONFIG_PRELOADER */
545 #endif /* CONFIG_USE_IRQ */
546
547 /****************************************************************************/
548 /*                                                                          */
549 /* Reset function: the PXA250 doesn't have a reset function, so we have to  */
550 /* perform a watchdog timeout for a soft reset.                             */
551 /*                                                                          */
552 /****************************************************************************/
553 /* Operating System Timer */
554 .align  5
555 .globl reset_cpu
556
557         /* FIXME: this code is PXA250 specific. How is this handled on      */
558         /*        other XScale processors?                                  */
559
560 reset_cpu:
561
562         /* We set OWE:WME (watchdog enable) and wait until timeout happens  */
563
564         ldr     r0, =OWER
565         ldr     r1, [r0]
566         orr     r1, r1, #0x0001                 /* bit0: WME                */
567         str     r1, [r0]
568
569         /* OS timer does only wrap every 1165 seconds, so we have to set    */
570         /* the match register as well.                                      */
571
572         ldr     r0, =OSCR
573         ldr     r1, [r0]                        /* read OS timer            */
574         add     r1, r1, #0x800                  /* let OSMR3 match after    */
575         add     r1, r1, #0x800                  /* 4096*(1/3.6864MHz)=1ms   */
576         ldr     r0, =OSMR3
577         str     r1, [r0]
578
579 reset_endless:
580
581         b       reset_endless
582
583 #ifndef CONFIG_PRELOADER
584 .section .mmudata, "a"
585         .align  14
586         .globl  mmu_table
587 mmu_table:
588         /* 0x00000000 - 0xa0000000 : 1:1, uncached mapping */
589         .set    __base, 0
590         .rept   0xa00
591         .word   (__base << 20) | 0xc12
592         .set    __base, __base + 1
593         .endr
594
595         /* 0xa0000000 - 0xa0100000 : 1:1, cached mapping */
596         .word   (0xa00 << 20) | 0x1c1e
597
598         .set    __base, 0xa01
599         .rept   0x1000 - 0xa01
600         .word   (__base << 20) | 0xc12
601         .set    __base, __base + 1
602         .endr
603 #endif  /* CONFIG_PRELOADER */