Merge branch 'master' of git://git.denx.de/u-boot-arm
[platform/kernel/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         ldr     r0,=0x00000000
224         bl      board_init_f
225
226 /*------------------------------------------------------------------------------*/
227
228 /*
229  * void relocate_code (addr_sp, gd, addr_moni)
230  *
231  * This "function" does not return, instead it continues in RAM
232  * after relocating the monitor code.
233  *
234  */
235         .globl  relocate_code
236 relocate_code:
237         mov     r4, r0  /* save addr_sp */
238         mov     r5, r1  /* save addr of gd */
239         mov     r6, r2  /* save addr of destination */
240         mov     r7, r2  /* save addr of destination */
241
242         /* Set up the stack                                                 */
243 stack_setup:
244         mov     sp, r4
245
246         adr     r0, _start
247         ldr     r2, _TEXT_BASE
248         ldr     r3, _bss_start_ofs
249         add     r2, r0, r3              /* r2 <- source end address         */
250         cmp     r0, r6
251         beq     clear_bss
252
253         stmfd sp!, {r0-r12}
254 copy_loop:
255         ldmia   r0!, {r3-r5, r7-r11}    /* copy from source address [r0]    */
256         stmia   r6!, {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, r7, 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     r8, r1, #0xff
278         cmp     r8, #23         /* relative fixup? */
279         beq     fixrel
280         cmp     r8, #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, 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         ldr     r3, _TEXT_BASE          /* Text base */
307         mov     r4, r7                  /* reloc addr */
308         add     r0, r0, r4
309         add     r1, r1, r4
310         mov     r2, #0x00000000         /* clear                            */
311
312 clbss_l:str     r2, [r0]                /* clear loop...                    */
313         add     r0, r0, #4
314         cmp     r0, r1
315         bne     clbss_l
316 #endif  /* #ifndef CONFIG_PRELOADER */
317
318 /*
319  * We are done. Do not return, instead branch to second part of board
320  * initialization, now running from RAM.
321  */
322 #ifdef CONFIG_ONENAND_IPL
323         ldr     r0, _start_oneboot_ofs
324         mov     pc, r0
325
326 _start_oneboot_ofs
327         : .word start_oneboot
328 #else
329         ldr     r0, _board_init_r_ofs
330         adr     r1, _start
331         add     lr, r0, r1
332         add     lr, lr, r9
333         /* setup parameters for board_init_r */
334         mov     r0, r5          /* gd_t */
335         mov     r1, r7          /* dest_addr */
336         /* jump to it ... */
337         mov     pc, lr
338
339 _board_init_r_ofs:
340         .word board_init_r - _start
341 #endif  /* CONFIG_ONENAND_IPL */
342
343 _rel_dyn_start_ofs:
344         .word __rel_dyn_start - _start
345 _rel_dyn_end_ofs:
346         .word __rel_dyn_end - _start
347 _dynsym_start_ofs:
348         .word __dynsym_start - _start
349
350 #else /* CONFIG_PRELOADER */
351
352 /****************************************************************************/
353 /*                                                                          */
354 /* the actual reset code for OneNAND IPL                                    */
355 /*                                                                          */
356 /****************************************************************************/
357
358 #ifndef CONFIG_PXA27X
359 #error OneNAND IPL is not supported on PXA25x and 26x due to lack of SRAM
360 #endif
361
362 reset:
363         /* Set CPU to SVC32 mode */
364         mrs     r0,cpsr
365         bic     r0,r0,#0x1f
366         orr     r0,r0,#0x13
367         msr     cpsr,r0
368
369         /* Point stack at the end of SRAM and leave 32 words for abort-stack */
370         ldr     sp, =0x5c03ff80
371
372         /* Start OneNAND IPL */
373         ldr     pc, =start_oneboot
374
375 #endif /* CONFIG_PRELOADER */
376
377 #ifndef CONFIG_PRELOADER
378 /****************************************************************************/
379 /*                                                                          */
380 /* Interrupt handling                                                       */
381 /*                                                                          */
382 /****************************************************************************/
383
384 /* IRQ stack frame                                                          */
385
386 #define S_FRAME_SIZE    72
387
388 #define S_OLD_R0        68
389 #define S_PSR           64
390 #define S_PC            60
391 #define S_LR            56
392 #define S_SP            52
393
394 #define S_IP            48
395 #define S_FP            44
396 #define S_R10           40
397 #define S_R9            36
398 #define S_R8            32
399 #define S_R7            28
400 #define S_R6            24
401 #define S_R5            20
402 #define S_R4            16
403 #define S_R3            12
404 #define S_R2            8
405 #define S_R1            4
406 #define S_R0            0
407
408 #define MODE_SVC 0x13
409
410         /* use bad_save_user_regs for abort/prefetch/undef/swi ...          */
411
412         .macro  bad_save_user_regs
413         sub     sp, sp, #S_FRAME_SIZE
414         stmia   sp, {r0 - r12}                  /* Calling r0-r12           */
415         add     r8, sp, #S_PC
416
417         ldr     r2, IRQ_STACK_START_IN
418         ldmia   r2, {r2 - r4}                   /* get pc, cpsr, old_r0     */
419         add     r0, sp, #S_FRAME_SIZE           /* restore sp_SVC           */
420
421         add     r5, sp, #S_SP
422         mov     r1, lr
423         stmia   r5, {r0 - r4}                   /* save sp_SVC, lr_SVC, pc, cpsr, old_r */
424         mov     r0, sp
425         .endm
426
427
428         /* use irq_save_user_regs / irq_restore_user_regs for                */
429         /* IRQ/FIQ handling                                                  */
430
431         .macro  irq_save_user_regs
432         sub     sp, sp, #S_FRAME_SIZE
433         stmia   sp, {r0 - r12}                  /* Calling r0-r12            */
434         add     r8, sp, #S_PC
435         stmdb   r8, {sp, lr}^                   /* Calling SP, LR            */
436         str     lr, [r8, #0]                    /* Save calling PC           */
437         mrs     r6, spsr
438         str     r6, [r8, #4]                    /* Save CPSR                 */
439         str     r0, [r8, #8]                    /* Save OLD_R0               */
440         mov     r0, sp
441         .endm
442
443         .macro  irq_restore_user_regs
444         ldmia   sp, {r0 - lr}^                  @ Calling r0 - lr
445         mov     r0, r0
446         ldr     lr, [sp, #S_PC]                 @ Get PC
447         add     sp, sp, #S_FRAME_SIZE
448         subs    pc, lr, #4                      @ return & move spsr_svc into cpsr
449         .endm
450
451         .macro get_bad_stack
452         ldr     r13, IRQ_STACK_START_IN         @ setup our mode stack
453
454         str     lr, [r13]                       @ save caller lr / spsr
455         mrs     lr, spsr
456         str     lr, [r13, #4]
457
458         mov     r13, #MODE_SVC                  @ prepare SVC-Mode
459         msr     spsr_c, r13
460         mov     lr, pc
461         movs    pc, lr
462         .endm
463
464         .macro get_irq_stack                    @ setup IRQ stack
465         ldr     sp, IRQ_STACK_START
466         .endm
467
468         .macro get_fiq_stack                    @ setup FIQ stack
469         ldr     sp, FIQ_STACK_START
470         .endm
471 #endif  /* CONFIG_PRELOADER
472
473
474 /****************************************************************************/
475 /*                                                                          */
476 /* exception handlers                                                       */
477 /*                                                                          */
478 /****************************************************************************/
479
480 #ifdef CONFIG_PRELOADER
481         .align  5
482 do_hang:
483         ldr     sp, _TEXT_BASE                  /* use 32 words abort stack */
484         bl      hang                            /* hang and never return */
485 #else
486         .align  5
487 undefined_instruction:
488         get_bad_stack
489         bad_save_user_regs
490         bl      do_undefined_instruction
491
492         .align  5
493 software_interrupt:
494         get_bad_stack
495         bad_save_user_regs
496         bl      do_software_interrupt
497
498         .align  5
499 prefetch_abort:
500         get_bad_stack
501         bad_save_user_regs
502         bl      do_prefetch_abort
503
504         .align  5
505 data_abort:
506         get_bad_stack
507         bad_save_user_regs
508         bl      do_data_abort
509
510         .align  5
511 not_used:
512         get_bad_stack
513         bad_save_user_regs
514         bl      do_not_used
515
516 #ifdef CONFIG_USE_IRQ
517
518         .align  5
519 irq:
520         get_irq_stack
521         irq_save_user_regs
522         bl      do_irq
523         irq_restore_user_regs
524
525         .align  5
526 fiq:
527         get_fiq_stack
528         irq_save_user_regs              /* someone ought to write a more    */
529         bl      do_fiq                  /* effiction fiq_save_user_regs     */
530         irq_restore_user_regs
531
532 #else /* !CONFIG_USE_IRQ */
533
534         .align  5
535 irq:
536         get_bad_stack
537         bad_save_user_regs
538         bl      do_irq
539
540         .align  5
541 fiq:
542         get_bad_stack
543         bad_save_user_regs
544         bl      do_fiq
545 #endif  /* CONFIG_PRELOADER */
546 #endif /* CONFIG_USE_IRQ */
547
548 /****************************************************************************/
549 /*                                                                          */
550 /* Reset function: the PXA250 doesn't have a reset function, so we have to  */
551 /* perform a watchdog timeout for a soft reset.                             */
552 /*                                                                          */
553 /****************************************************************************/
554 /* Operating System Timer */
555 .align  5
556 .globl reset_cpu
557
558         /* FIXME: this code is PXA250 specific. How is this handled on      */
559         /*        other XScale processors?                                  */
560
561 reset_cpu:
562
563         /* We set OWE:WME (watchdog enable) and wait until timeout happens  */
564
565         ldr     r0, =OWER
566         ldr     r1, [r0]
567         orr     r1, r1, #0x0001                 /* bit0: WME                */
568         str     r1, [r0]
569
570         /* OS timer does only wrap every 1165 seconds, so we have to set    */
571         /* the match register as well.                                      */
572
573         ldr     r0, =OSCR
574         ldr     r1, [r0]                        /* read OS timer            */
575         add     r1, r1, #0x800                  /* let OSMR3 match after    */
576         add     r1, r1, #0x800                  /* 4096*(1/3.6864MHz)=1ms   */
577         ldr     r0, =OSMR3
578         str     r1, [r0]
579
580 reset_endless:
581
582         b       reset_endless
583
584 #ifndef CONFIG_PRELOADER
585 .section .mmudata, "a"
586         .align  14
587         .globl  mmu_table
588 mmu_table:
589         /* 0x00000000 - 0xa0000000 : 1:1, uncached mapping */
590         .set    __base, 0
591         .rept   0xa00
592         .word   (__base << 20) | 0xc12
593         .set    __base, __base + 1
594         .endr
595
596         /* 0xa0000000 - 0xa0100000 : 1:1, cached mapping */
597         .word   (0xa00 << 20) | 0x1c1e
598
599         .set    __base, 0xa01
600         .rept   0x1000 - 0xa01
601         .word   (__base << 20) | 0xc12
602         .set    __base, __base + 1
603         .endr
604 #endif  /* CONFIG_PRELOADER */