pxa: Save lr register in relocate_code function
[oweals/u-boot.git] / arch / arm / cpu / pxa / start.S
1 /*
2  *  armboot - Startup Code for XScale CPU-core
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) 2001  Marius Groger <mag@sysgo.de>
9  *  Copyright (C) 2002  Alex Zupke <azu@sysgo.de>
10  *  Copyright (C) 2002  Gary Jennejohn <garyj@denx.de>
11  *  Copyright (C) 2002  Kyle Harris <kharris@nexus-tech.net>
12  *  Copyright (C) 2003  Kai-Uwe Bloem <kai-uwe.bloem@auerswald.de>
13  *  Copyright (C) 2003  Kshitij <kshitij@ti.com>
14  *  Copyright (C) 2003  Richard Woodruff <r-woodruff2@ti.com>
15  *  Copyright (C) 2003  Robert Schwebel <r.schwebel@pengutronix.de>
16  *  Copyright (C) 2004  Texas Instruments <r-woodruff2@ti.com>
17  *  Copyright (C) 2010  Marek Vasut <marek.vasut@gmail.com>
18  *
19  * See file CREDITS for list of people who contributed to this
20  * project.
21  *
22  * This program is free software; you can redistribute it and/or
23  * modify it under the terms of the GNU General Public License as
24  * published by the Free Software Foundation; either version 2 of
25  * the License, or (at your option) any later version.
26  *
27  * This program is distributed in the hope that it will be useful,
28  * but WITHOUT ANY WARRANTY; without even the implied warranty of
29  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
30  * GNU General Public License for more details.
31  *
32  * You should have received a copy of the GNU General Public License
33  * along with this program; if not, write to the Free Software
34  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
35  * MA 02111-1307 USA
36  */
37
38 #include <asm-offsets.h>
39 #include <config.h>
40 #include <version.h>
41
42 #ifdef CONFIG_CPU_PXA25X
43 #if ((CONFIG_SYS_INIT_SP_ADDR) != 0xfffff800)
44 #error "Init SP address must be set to 0xfffff800 for PXA250"
45 #endif
46 #endif
47
48 .globl _start
49 _start: b       reset
50 #ifdef CONFIG_SPL_BUILD
51         ldr     pc, _hang
52         ldr     pc, _hang
53         ldr     pc, _hang
54         ldr     pc, _hang
55         ldr     pc, _hang
56         ldr     pc, _hang
57         ldr     pc, _hang
58
59 _hang:
60         .word   do_hang
61         .word   0x12345678
62         .word   0x12345678
63         .word   0x12345678
64         .word   0x12345678
65         .word   0x12345678
66         .word   0x12345678
67         .word   0x12345678      /* now 16*4=64 */
68 #else
69         ldr     pc, _undefined_instruction
70         ldr     pc, _software_interrupt
71         ldr     pc, _prefetch_abort
72         ldr     pc, _data_abort
73         ldr     pc, _not_used
74         ldr     pc, _irq
75         ldr     pc, _fiq
76
77 _undefined_instruction: .word undefined_instruction
78 _software_interrupt:    .word software_interrupt
79 _prefetch_abort:        .word prefetch_abort
80 _data_abort:            .word data_abort
81 _not_used:              .word not_used
82 _irq:                   .word irq
83 _fiq:                   .word fiq
84 _pad:                   .word 0x12345678 /* now 16*4=64 */
85 #endif  /* CONFIG_SPL_BUILD */
86 .global _end_vect
87 _end_vect:
88
89         .balignl 16,0xdeadbeef
90 /*
91  *************************************************************************
92  *
93  * Startup Code (reset vector)
94  *
95  * do important init only if we don't start from memory!
96  * setup Memory and board specific bits prior to relocation.
97  * relocate armboot to ram
98  * setup stack
99  *
100  *************************************************************************
101  */
102
103 .globl _TEXT_BASE
104 _TEXT_BASE:
105 #ifdef  CONFIG_SPL_BUILD
106         .word   CONFIG_SPL_TEXT_BASE
107 #else
108         .word   CONFIG_SYS_TEXT_BASE
109 #endif
110
111 /*
112  * These are defined in the board-specific linker script.
113  * Subtracting _start from them lets the linker put their
114  * relative position in the executable instead of leaving
115  * them null.
116  */
117 .globl _bss_start_ofs
118 _bss_start_ofs:
119         .word __bss_start - _start
120
121 .globl _bss_end_ofs
122 _bss_end_ofs:
123         .word __bss_end__ - _start
124
125 .globl _end_ofs
126 _end_ofs:
127         .word _end - _start
128
129 #ifdef CONFIG_USE_IRQ
130 /* IRQ stack memory (calculated at run-time) */
131 .globl IRQ_STACK_START
132 IRQ_STACK_START:
133         .word   0x0badc0de
134
135 /* IRQ stack memory (calculated at run-time) */
136 .globl FIQ_STACK_START
137 FIQ_STACK_START:
138         .word 0x0badc0de
139 #endif
140
141 /* IRQ stack memory (calculated at run-time) + 8 bytes */
142 .globl IRQ_STACK_START_IN
143 IRQ_STACK_START_IN:
144         .word   0x0badc0de
145
146 /*
147  * the actual reset code
148  */
149
150 reset:
151         /*
152          * set the cpu to SVC32 mode
153          */
154         mrs     r0,cpsr
155         bic     r0,r0,#0x1f
156         orr     r0,r0,#0xd3
157         msr     cpsr,r0
158
159 #ifndef CONFIG_SKIP_LOWLEVEL_INIT
160         bl  cpu_init_crit
161 #endif
162
163 #ifdef  CONFIG_CPU_PXA25X
164         bl      lock_cache_for_stack
165 #endif
166
167         bl      _main
168
169 /*------------------------------------------------------------------------------*/
170 #ifndef CONFIG_SPL_BUILD
171 /*
172  * void relocate_code (addr_sp, gd, addr_moni)
173  *
174  * This "function" does not return, instead it continues in RAM
175  * after relocating the monitor code.
176  *
177  */
178         .globl  relocate_code
179 relocate_code:
180         mov     r4, r0  /* save addr_sp */
181         mov     r5, r1  /* save addr of gd */
182         mov     r6, r2  /* save addr of destination */
183
184 /* Disable the Dcache RAM lock for stack now */
185 #ifdef  CONFIG_CPU_PXA25X
186         mov     r12, lr
187         bl      cpu_init_crit
188         mov     lr, r12
189 #endif
190
191         adr     r0, _start
192         cmp     r0, r6
193         moveq   r9, #0          /* no relocation. relocation offset(r9) = 0 */
194         beq     relocate_done           /* skip relocation */
195         mov     r1, r6                  /* r1 <- scratch for copy_loop */
196         ldr     r3, _bss_start_ofs
197         add     r2, r0, r3              /* r2 <- source end address         */
198
199 copy_loop:
200         ldmia   r0!, {r9-r10}           /* copy from source address [r0]    */
201         stmia   r1!, {r9-r10}           /* copy to   target address [r1]    */
202         cmp     r0, r2                  /* until source end address [r2]    */
203         blo     copy_loop
204
205 #ifndef CONFIG_SPL_BUILD
206         /*
207          * fix .rel.dyn relocations
208          */
209         ldr     r0, _TEXT_BASE          /* r0 <- Text base */
210         sub     r9, r6, r0              /* r9 <- relocation offset */
211         ldr     r10, _dynsym_start_ofs  /* r10 <- sym table ofs */
212         add     r10, r10, r0            /* r10 <- sym table in FLASH */
213         ldr     r2, _rel_dyn_start_ofs  /* r2 <- rel dyn start ofs */
214         add     r2, r2, r0              /* r2 <- rel dyn start in FLASH */
215         ldr     r3, _rel_dyn_end_ofs    /* r3 <- rel dyn end ofs */
216         add     r3, r3, r0              /* r3 <- rel dyn end in FLASH */
217 fixloop:
218         ldr     r0, [r2]                /* r0 <- location to fix up, IN FLASH! */
219         add     r0, r0, r9              /* r0 <- location to fix up in RAM */
220         ldr     r1, [r2, #4]
221         and     r7, r1, #0xff
222         cmp     r7, #23                 /* relative fixup? */
223         beq     fixrel
224         cmp     r7, #2                  /* absolute fixup? */
225         beq     fixabs
226         /* ignore unknown type of fixup */
227         b       fixnext
228 fixabs:
229         /* absolute fix: set location to (offset) symbol value */
230         mov     r1, r1, LSR #4          /* r1 <- symbol index in .dynsym */
231         add     r1, r10, r1             /* r1 <- address of symbol in table */
232         ldr     r1, [r1, #4]            /* r1 <- symbol value */
233         add     r1, r1, r9              /* r1 <- relocated sym addr */
234         b       fixnext
235 fixrel:
236         /* relative fix: increase location by offset */
237         ldr     r1, [r0]
238         add     r1, r1, r9
239 fixnext:
240         str     r1, [r0]
241         add     r2, r2, #8              /* each rel.dyn entry is 8 bytes */
242         cmp     r2, r3
243         blo     fixloop
244 #endif
245
246 relocate_done:
247
248         bx      lr
249
250 _rel_dyn_start_ofs:
251         .word __rel_dyn_start - _start
252 _rel_dyn_end_ofs:
253         .word __rel_dyn_end - _start
254 _dynsym_start_ofs:
255         .word __dynsym_start - _start
256
257 #endif
258
259         .globl  c_runtime_cpu_setup
260 c_runtime_cpu_setup:
261
262         bx      lr
263
264 /*
265  *************************************************************************
266  *
267  * CPU_init_critical registers
268  *
269  * setup important registers
270  * setup memory timing
271  *
272  *************************************************************************
273  */
274 #if !defined(CONFIG_SKIP_LOWLEVEL_INIT) || defined(CONFIG_CPU_PXA25X)
275 cpu_init_crit:
276         /*
277          * flush v4 I/D caches
278          */
279         mov     r0, #0
280         mcr     p15, 0, r0, c7, c7, 0   /* Invalidate I+D+BTB caches */
281         mcr     p15, 0, r0, c8, c7, 0   /* Invalidate Unified TLB */
282
283         /*
284          * disable MMU stuff and caches
285          */
286         mrc     p15, 0, r0, c1, c0, 0
287         bic     r0, r0, #0x00002300     @ clear bits 13, 9:8 (--V- --RS)
288         bic     r0, r0, #0x00000087     @ clear bits 7, 2:0 (B--- -CAM)
289         orr     r0, r0, #0x00000002     @ set bit 2 (A) Align
290         orr     r0, r0, #0x00001000     @ set bit 12 (I) I-Cache
291         mcr     p15, 0, r0, c1, c0, 0
292
293         mov     pc, lr          /* back to my caller */
294 #endif /* !CONFIG_SKIP_LOWLEVEL_INIT || CONFIG_CPU_PXA25X */
295
296 #ifndef CONFIG_SPL_BUILD
297 /*
298  *************************************************************************
299  *
300  * Interrupt handling
301  *
302  *************************************************************************
303  */
304 @
305 @ IRQ stack frame.
306 @
307 #define S_FRAME_SIZE    72
308
309 #define S_OLD_R0        68
310 #define S_PSR           64
311 #define S_PC            60
312 #define S_LR            56
313 #define S_SP            52
314
315 #define S_IP            48
316 #define S_FP            44
317 #define S_R10           40
318 #define S_R9            36
319 #define S_R8            32
320 #define S_R7            28
321 #define S_R6            24
322 #define S_R5            20
323 #define S_R4            16
324 #define S_R3            12
325 #define S_R2            8
326 #define S_R1            4
327 #define S_R0            0
328
329 #define MODE_SVC 0x13
330 #define I_BIT    0x80
331
332 /*
333  * use bad_save_user_regs for abort/prefetch/undef/swi ...
334  * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling
335  */
336
337         .macro  bad_save_user_regs
338         sub     sp, sp, #S_FRAME_SIZE           @ carve out a frame on current user stack
339         stmia   sp, {r0 - r12}                  @ Save user registers (now in svc mode) r0-r12
340
341         ldr     r2, IRQ_STACK_START_IN          @ set base 2 words into abort stack
342         ldmia   r2, {r2 - r3}                   @ get values for "aborted" pc and cpsr (into parm regs)
343         add     r0, sp, #S_FRAME_SIZE           @ grab pointer to old stack
344
345         add     r5, sp, #S_SP
346         mov     r1, lr
347         stmia   r5, {r0 - r3}                   @ save sp_SVC, lr_SVC, pc, cpsr
348         mov     r0, sp                          @ save current stack into r0 (param register)
349         .endm
350
351         .macro  irq_save_user_regs
352         sub     sp, sp, #S_FRAME_SIZE
353         stmia   sp, {r0 - r12}                  @ Calling r0-r12
354         add     r8, sp, #S_PC                   @ !!!! R8 NEEDS to be saved !!!! a reserved stack spot would be good.
355         stmdb   r8, {sp, lr}^                   @ Calling SP, LR
356         str     lr, [r8, #0]                    @ Save calling PC
357         mrs     r6, spsr
358         str     r6, [r8, #4]                    @ Save CPSR
359         str     r0, [r8, #8]                    @ Save OLD_R0
360         mov     r0, sp
361         .endm
362
363         .macro  irq_restore_user_regs
364         ldmia   sp, {r0 - lr}^                  @ Calling r0 - lr
365         mov     r0, r0
366         ldr     lr, [sp, #S_PC]                 @ Get PC
367         add     sp, sp, #S_FRAME_SIZE
368         subs    pc, lr, #4                      @ return & move spsr_svc into cpsr
369         .endm
370
371         .macro get_bad_stack
372         ldr     r13, IRQ_STACK_START_IN         @ setup our mode stack (enter in banked mode)
373
374         str     lr, [r13]                       @ save caller lr in position 0 of saved stack
375         mrs     lr, spsr                        @ get the spsr
376         str     lr, [r13, #4]                   @ save spsr in position 1 of saved stack
377
378         mov     r13, #MODE_SVC                  @ prepare SVC-Mode
379         @ msr   spsr_c, r13
380         msr     spsr, r13                       @ switch modes, make sure moves will execute
381         mov     lr, pc                          @ capture return pc
382         movs    pc, lr                          @ jump to next instruction & switch modes.
383         .endm
384
385         .macro get_bad_stack_swi
386         sub     r13, r13, #4                    @ space on current stack for scratch reg.
387         str     r0, [r13]                       @ save R0's value.
388         ldr     r0, IRQ_STACK_START_IN          @ get data regions start
389         str     lr, [r0]                        @ save caller lr in position 0 of saved stack
390         mrs     r0, spsr                        @ get the spsr
391         str     lr, [r0, #4]                    @ save spsr in position 1 of saved stack
392         ldr     r0, [r13]                       @ restore r0
393         add     r13, r13, #4                    @ pop stack entry
394         .endm
395
396         .macro get_irq_stack                    @ setup IRQ stack
397         ldr     sp, IRQ_STACK_START
398         .endm
399
400         .macro get_fiq_stack                    @ setup FIQ stack
401         ldr     sp, FIQ_STACK_START
402         .endm
403 #endif  /* CONFIG_SPL_BUILD */
404
405 /*
406  * exception handlers
407  */
408 #ifdef CONFIG_SPL_BUILD
409         .align  5
410 do_hang:
411         ldr     sp, _TEXT_BASE                  /* use 32 words about stack */
412         bl      hang                            /* hang and never return */
413 #else   /* !CONFIG_SPL_BUILD */
414         .align  5
415 undefined_instruction:
416         get_bad_stack
417         bad_save_user_regs
418         bl      do_undefined_instruction
419
420         .align  5
421 software_interrupt:
422         get_bad_stack_swi
423         bad_save_user_regs
424         bl      do_software_interrupt
425
426         .align  5
427 prefetch_abort:
428         get_bad_stack
429         bad_save_user_regs
430         bl      do_prefetch_abort
431
432         .align  5
433 data_abort:
434         get_bad_stack
435         bad_save_user_regs
436         bl      do_data_abort
437
438         .align  5
439 not_used:
440         get_bad_stack
441         bad_save_user_regs
442         bl      do_not_used
443
444 #ifdef CONFIG_USE_IRQ
445
446         .align  5
447 irq:
448         get_irq_stack
449         irq_save_user_regs
450         bl      do_irq
451         irq_restore_user_regs
452
453         .align  5
454 fiq:
455         get_fiq_stack
456         /* someone ought to write a more effiction fiq_save_user_regs */
457         irq_save_user_regs
458         bl      do_fiq
459         irq_restore_user_regs
460
461 #else
462
463         .align  5
464 irq:
465         get_bad_stack
466         bad_save_user_regs
467         bl      do_irq
468
469         .align  5
470 fiq:
471         get_bad_stack
472         bad_save_user_regs
473         bl      do_fiq
474
475 #endif
476         .align 5
477 #endif  /* CONFIG_SPL_BUILD */
478
479
480 /*
481  * Enable MMU to use DCache as DRAM.
482  *
483  * This is useful on PXA25x and PXA26x in early bootstages, where there is no
484  * other possible memory available to hold stack.
485  */
486 #ifdef CONFIG_CPU_PXA25X
487 .macro CPWAIT reg
488         mrc     p15, 0, \reg, c2, c0, 0
489         mov     \reg, \reg
490         sub     pc, pc, #4
491 .endm
492 lock_cache_for_stack:
493         /* Domain access -- enable for all CPs */
494         ldr     r0, =0x0000ffff
495         mcr     p15, 0, r0, c3, c0, 0
496
497         /* Point TTBR to MMU table */
498         ldr     r0, =mmutable
499         mcr     p15, 0, r0, c2, c0, 0
500
501         /* Kick in MMU, ICache, DCache, BTB */
502         mrc     p15, 0, r0, c1, c0, 0
503         bic     r0, #0x1b00
504         bic     r0, #0x0087
505         orr     r0, #0x1800
506         orr     r0, #0x0005
507         mcr     p15, 0, r0, c1, c0, 0
508         CPWAIT  r0
509
510         /* Unlock Icache, Dcache */
511         mcr     p15, 0, r0, c9, c1, 1
512         mcr     p15, 0, r0, c9, c2, 1
513
514         /* Flush Icache, Dcache, BTB */
515         mcr     p15, 0, r0, c7, c7, 0
516
517         /* Unlock I-TLB, D-TLB */
518         mcr     p15, 0, r0, c10, c4, 1
519         mcr     p15, 0, r0, c10, c8, 1
520
521         /* Flush TLB */
522         mcr     p15, 0, r0, c8, c7, 0
523
524         /* Allocate 4096 bytes of Dcache as RAM */
525
526         /* Drain pending loads and stores */
527         mcr     p15, 0, r0, c7, c10, 4
528
529         mov     r4, #0x00
530         mov     r5, #0x00
531         mov     r2, #0x01
532         mcr     p15, 0, r0, c9, c2, 0
533         CPWAIT  r0
534
535         /* 128 lines reserved (128 x 32bytes = 4096 bytes total) */
536         mov     r0, #128
537         ldr     r1, =0xfffff000
538
539 alloc:
540         mcr     p15, 0, r1, c7, c2, 5
541         /* Drain pending loads and stores */
542         mcr     p15, 0, r0, c7, c10, 4
543         strd    r4, [r1], #8
544         strd    r4, [r1], #8
545         strd    r4, [r1], #8
546         strd    r4, [r1], #8
547         subs    r0, #0x01
548         bne     alloc
549         /* Drain pending loads and stores */
550         mcr     p15, 0, r0, c7, c10, 4
551         mov     r2, #0x00
552         mcr     p15, 0, r2, c9, c2, 0
553         CPWAIT  r0
554
555         mov     pc, lr
556
557 .section .mmutable, "a"
558 mmutable:
559         .align  14
560         /* 0x00000000 - 0xffe00000 : 1:1, uncached mapping */
561         .set    __base, 0
562         .rept   0xfff
563         .word   (__base << 20) | 0xc12
564         .set    __base, __base + 1
565         .endr
566
567         /* 0xfff00000 : 1:1, cached mapping */
568         .word   (0xfff << 20) | 0x1c1e
569 #endif  /* CONFIG_CPU_PXA25X */