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