]> git.sur5r.net Git - u-boot/blob - arch/nds32/cpu/n1213/start.S
nds32: Support relocation.
[u-boot] / arch / nds32 / cpu / n1213 / start.S
1 /*
2  *      Andesboot - Startup Code for Whitiger core
3  *
4  *      Copyright (C) 2006      Andes Technology Corporation
5  *      Copyright (C) 2006      Shawn Lin <nobuhiro@andestech.com>
6  *      Copyright (C) 2011      Macpaul Lin <macpaul@andestech.com>
7  *                              Greentime Hu <greentime@andestech.com>
8  *
9  * SPDX-License-Identifier:     GPL-2.0+
10  */
11
12 .pic
13
14 #include <asm-offsets.h>
15 #include <config.h>
16 #include <common.h>
17 #include <asm/macro.h>
18
19 /*
20  * Jump vector table for EVIC mode
21  */
22 #define ENA_DCAC                2UL
23 #define DIS_DCAC                ~ENA_DCAC
24 #define ICAC_MEM_KBF_ISET       (0x07)          ! I Cache sets per way
25 #define ICAC_MEM_KBF_IWAY       (0x07<<3)       ! I cache ways
26 #define ICAC_MEM_KBF_ISZ        (0x07<<6)       ! I cache line size
27 #define DCAC_MEM_KBF_DSET       (0x07)          ! D Cache sets per way
28 #define DCAC_MEM_KBF_DWAY       (0x07<<3)       ! D cache ways
29 #define DCAC_MEM_KBF_DSZ        (0x07<<6)       ! D cache line size
30
31 #define PSW                     $ir0
32 #define EIT_INTR_PSW            $ir1            ! interruption $PSW
33 #define EIT_PREV_IPSW           $ir2            ! previous $IPSW
34 #define EIT_IVB                 $ir3            ! intr vector base address
35 #define EIT_EVA                 $ir4            ! MMU related Exception VA reg
36 #define EIT_PREV_EVA            $ir5            ! previous $eva
37 #define EIT_ITYPE               $ir6            ! interruption type
38 #define EIT_PREV_ITYPE          $ir7            ! prev intr type
39 #define EIT_MACH_ERR            $ir8            ! machine error log
40 #define EIT_INTR_PC             $ir9            ! Interruption PC
41 #define EIT_PREV_IPC            $ir10           ! previous $IPC
42 #define EIT_OVL_INTR_PC         $ir11           ! overflow interruption PC
43 #define EIT_PREV_P0             $ir12           ! prev $P0
44 #define EIT_PREV_P1             $ir13           ! prev $p1
45 #define CR_ICAC_MEM             $cr1            ! I-cache/memory config reg
46 #define CR_DCAC_MEM             $cr2            ! D-cache/memory config reg
47 #define MR_CAC_CTL              $mr8
48
49 .globl _start
50
51 _start: j       reset
52         j       tlb_fill
53         j       tlb_not_present
54         j       tlb_misc
55         j       tlb_vlpt_miss
56         j       machine_error
57         j       debug
58         j       general_exception
59         j       syscall
60         j       internal_interrupt              ! H0I
61         j       internal_interrupt              ! H1I
62         j       internal_interrupt              ! H2I
63         j       internal_interrupt              ! H3I
64         j       internal_interrupt              ! H4I
65         j       internal_interrupt              ! H5I
66         j       software_interrupt              ! S0I
67
68         .balign 16
69
70 /*
71  * Andesboot Startup Code (reset vector)
72  *
73  *      1.      bootstrap
74  *              1.1 reset - start of u-boot
75  *              1.2 to superuser mode - as is when reset
76  *              1.4 Do lowlevel_init
77  *                      - (this will jump out to lowlevel_init.S in SoC)
78  *                      - (lowlevel_init)
79  *              1.3 Turn off watchdog timer
80  *                      - (this will jump out to watchdog.S in SoC)
81  *                      - (turnoff_watchdog)
82  *      2.      Do critical init when reboot (not from mem)
83  *      3.      Relocate andesboot to ram
84  *      4.      Setup stack
85  *      5.      Jump to second stage (board_init_r)
86  */
87
88 /* Note: TEXT_BASE is defined by the (board-dependent) linker script */
89 .globl _TEXT_BASE
90 _TEXT_BASE:
91         .word   CONFIG_SYS_TEXT_BASE
92
93 /*
94  * These are defined in the board-specific linker script.
95  * Subtracting _start from them lets the linker put their
96  * relative position in the executable instead of leaving
97  * them null.
98  */
99 #ifdef CONFIG_USE_IRQ
100 /* IRQ stack memory (calculated at run-time) */
101 .globl IRQ_STACK_START
102 IRQ_STACK_START:
103         .word 0x0badc0de
104
105 /* IRQ stack memory (calculated at run-time) */
106 .globl FIQ_STACK_START
107 FIQ_STACK_START:
108         .word 0x0badc0de
109 #endif
110
111 /* IRQ stack memory (calculated at run-time) + 8 bytes */
112 .globl IRQ_STACK_START_IN
113 IRQ_STACK_START_IN:
114         .word 0x0badc0de
115
116 /*
117  * The bootstrap code of nds32 core
118  */
119
120 reset:
121
122 /*
123  *  gp = ~0            for burn mode
124  *     = ~load_address for load mode
125  */
126 reset_gp:
127         .relax_hint 0
128         sethi   $gp, hi20(_GLOBAL_OFFSET_TABLE_-8)
129         .relax_hint 0
130         ori     $gp, $gp, lo12(_GLOBAL_OFFSET_TABLE_-4)
131         add5.pc $gp
132
133 set_ivb:
134         li      $r0, 0x0
135
136         /* turn on BTB */
137         mtsr    $r0, $misc_ctl
138         /* set IVIC, vector size: 4 bytes, base: 0x0 */
139         mtsr    $r0, $ivb
140
141 #ifndef CONFIG_SKIP_LOWLEVEL_INIT
142         jal     lowlevel_init
143 /*
144  *  gp = ~VMA          for burn mode
145  *     = ~load_address for load mode
146  */
147 update_gp:
148         .relax_hint 0
149         sethi   $gp, hi20(_GLOBAL_OFFSET_TABLE_-8)
150         .relax_hint 0
151         ori     $gp, $gp, lo12(_GLOBAL_OFFSET_TABLE_-4)
152         add5.pc $gp
153 #endif
154
155 /*
156  *  do critical initializations first (shall be in short time)
157  *  do self_relocation ASAP.
158  */
159
160 /*
161  * Set the N1213 (Whitiger) core to superuser mode
162  * According to spec, it is already when reset
163  */
164 #ifndef CONFIG_SKIP_TRUNOFF_WATCHDOG
165         jal     turnoff_watchdog
166 #endif
167
168 /*
169  * Do CPU critical regs init only at reboot,
170  * not when booting from ram
171  */
172 #ifdef CONFIG_INIT_CRITICAL
173         jal     cpu_init_crit           ! Do CPU critical regs init
174 #endif
175
176 /*
177  * Set stackpointer in internal RAM to call board_init_f
178  * $sp must be 8-byte alignment for ABI compliance.
179  */
180 call_board_init_f:
181         li              $sp, CONFIG_SYS_INIT_SP_ADDR
182         li              $r10, GD_SIZE   /* get GD size */
183         sub             $sp, $sp, $r10  /* GD start addr */
184         move    $r10, $sp
185         li              $r0, 0x00000000
186
187 #ifdef __PIC__
188 #ifdef __NDS32_N1213_43U1H__
189 /* __NDS32_N1213_43U1H__ implies NDS32 V0 ISA */
190         la      $r15, board_init_f      ! store function address into $r15
191 #endif
192 #endif
193         j       board_init_f            ! jump to board_init_f() in lib/board.c
194
195 /*
196  * void relocate_code (addr_sp, gd, addr_moni)
197  *
198  * This "function" does not return, instead it continues in RAM
199  * after relocating the monitor code.
200  *
201  */
202
203 /*
204  *  gp = ~RAM_SIZE - TEXT_SIZE for burn/load mode
205  */
206
207 .globl  relocate_code
208 relocate_code:
209         move    $r4, $r0                /* save addr_sp */
210         move    $r5, $r1                /* save addr of gd */
211         move    $r6, $r2                /* save addr of destination */
212
213 /* Set up the stack */
214 stack_setup:
215         move    $sp, $r4
216
217         la      $r0, _start@GOTOFF
218         beq     $r0, $r6, clear_bss     /* skip relocation */
219
220         la       $r1, _end@GOTOFF
221         move $r2, $r6                   /* r2 <- scratch for copy_loop */
222
223 copy_loop:
224         lwi.p   $r7, [$r0], #4
225         swi.p   $r7, [$r2], #4
226         blt     $r0, $r1, copy_loop
227
228 /*
229  * fix relocations related issues
230  */
231 fix_relocations:
232         l.w     $r0, _TEXT_BASE@GOTOFF  /* r0 <- Text base */
233         sub     $r9, $r6, $r0                   /* r9 <- relocation offset */
234
235         la  $r7, __rel_dyn_start@GOTOFF
236         add     $r7, $r7, $r9           /* r2 <- rel __got_start in RAM */
237         la  $r8, __rel_dyn_end@GOTOFF
238         add     $r8, $r8, $r9           /* r2 <- rel __got_start in RAM */
239         li  $r3, #0x2a /* R_NDS32_RELATIVE */
240 1:
241         lmw.bim $r0, [$r7], $r2 /* r0,r1,r2 <- adr,type,addend */
242         bne $r1, $r3, 2f
243
244         add $r0, $r0, $r9
245         add $r2, $r2, $r9
246         sw  $r2, [$r0]
247 2:
248         blt $r7, $r8, 1b
249
250 clear_bss:
251         la      $r0, __bss_start@GOTOFF /* r0 <- rel __bss_start in FLASH */
252         add     $r0, $r0, $r9           /* r0 <- rel __bss_start in FLASH */
253         la      $r1, __bss_end@GOTOFF           /* r1 <- rel __bss_end in RAM */
254         add     $r1, $r1, $r9           /* r0 <- rel __bss_end in RAM */
255         li      $r2, 0x00000000         /* clear */
256
257 clbss_l:
258         sw      $r2, [$r0]              /* clear loop... */
259         addi    $r0, $r0, #4
260         bne     $r0, $r1, clbss_l
261
262 /*
263  * We are done. Do not return, instead branch to second part of board
264  * initialization, now running from RAM.
265  */
266 call_board_init_r:
267         la      $r0, board_init_r@GOTOFF
268         move    $lp, $r0                /* offset of board_init_r() */
269         add     $lp, $lp, $r9           /* real address of board_init_r() */
270         /* setup parameters for board_init_r */
271         move    $r0, $r5                /* gd_t */
272         move    $r1, $r6                /* dest_addr */
273
274 #ifdef __PIC__
275 #ifdef __NDS32_N1213_43U1H__            /* NDS32 V0 ISA */
276         move    $r15, $lp               /* store function address into $r15 */
277 #endif
278 #endif
279
280         /* jump to it ... */
281         jr      $lp                     /* jump to board_init_r() */
282
283 /*
284  * Initialize CPU critical registers
285  *
286  *      1.      Setup control registers
287  *              1.1 Mask all IRQs
288  *              1.2 Flush cache and TLB
289  *              1.3 Disable MMU and cache
290  *      2.      Setup memory timing
291  */
292
293 cpu_init_crit:
294
295         move    $r0, $lp                /* push ra */
296
297         /* Disable Interrupts by clear GIE in $PSW reg */
298         setgie.d
299
300         /* Flush caches and TLB */
301         /* Invalidate caches */
302         jal     invalidate_icac
303         jal     invalidate_dcac
304
305         /* Flush TLB */
306         mfsr    $p0, $MMU_CFG
307         andi    $p0, $p0, 0x3                   ! MMPS
308         li      $p1, 0x2                        ! TLB MMU
309         bne     $p0, $p1, 1f
310         tlbop   flushall                        ! Flush TLB
311
312 1:
313         ! Disable MMU, Dcache
314         ! Whitiger is MMU disabled when reset
315         ! Disable the D$
316         mfsr    $p0, MR_CAC_CTL                 ! Get the $CACHE_CTL reg
317         li      $p1, DIS_DCAC
318         and     $p0, $p0, $p1                   ! Set DC_EN bit
319         mtsr    $p0, MR_CAC_CTL                 ! write back the $CACHE_CTL reg
320         isb
321
322         move    $lp, $r0
323 2:
324         ret
325
326 /*
327  * Invalidate I$
328  */
329 invalidate_icac:
330         ! read $cr1(I CAC/MEM cfg. reg.) configuration
331         mfsr    $t0, CR_ICAC_MEM
332
333         ! Get the ISZ field
334         andi    $p0, $t0, ICAC_MEM_KBF_ISZ
335
336         ! if $p0=0, then no I CAC existed
337         beqz    $p0, end_flush_icache
338
339         ! get $p0 the index of I$ block
340         srli    $p0, $p0, 6
341
342         ! $t1= bit width of I cache line size(ISZ)
343         addi    $t1, $p0, 2
344
345         li      $t4, 1
346         sll     $t5, $t4, $t1                   ! get $t5 cache line size
347         andi    $p1, $t0, ICAC_MEM_KBF_ISET     ! get the ISET field
348         addi    $t2, $p1, 6                     ! $t2= bit width of ISET
349         andi    $p1, $t0, ICAC_MEM_KBF_IWAY     ! get bitfield of Iway
350         srli    $p1, $p1, 3
351         addi    $p1, $p1, 1                     ! then $p1 is I way number
352         add     $t3, $t2, $t1                   ! SHIFT
353         sll     $p1, $p1, $t3                   ! GET the total cache size
354 ICAC_LOOP:
355         sub     $p1, $p1, $t5
356         cctl    $p1, L1I_IX_INVAL
357         bnez    $p1, ICAC_LOOP
358 end_flush_icache:
359         ret
360
361 /*
362  * Invalidate D$
363  */
364 invalidate_dcac:
365         ! read $cr2(D CAC/MEM cfg. reg.) configuration
366         mfsr    $t0, CR_DCAC_MEM
367
368         ! Get the DSZ field
369         andi    $p0, $t0, DCAC_MEM_KBF_DSZ
370
371         ! if $p0=0, then no D CAC existed
372         beqz    $p0, end_flush_dcache
373
374         ! get $p0 the index of D$ block
375         srli    $p0, $p0, 6
376
377         ! $t1= bit width of D cache line size(DSZ)
378         addi    $t1, $p0, 2
379
380         li      $t4, 1
381         sll     $t5, $t4, $t1                   ! get $t5 cache line size
382         andi    $p1, $t0, DCAC_MEM_KBF_DSET     ! get the DSET field
383         addi    $t2, $p1, 6                     ! $t2= bit width of DSET
384         andi    $p1, $t0, DCAC_MEM_KBF_DWAY     ! get bitfield of D way
385         srli    $p1, $p1, 3
386         addi    $p1, $p1, 1                     ! then $p1 is D way number
387         add     $t3, $t2, $t1                   ! SHIFT
388         sll     $p1, $p1, $t3                   ! GET the total cache size
389 DCAC_LOOP:
390         sub     $p1, $p1, $t5
391         cctl    $p1, L1D_IX_INVAL
392         bnez    $p1, DCAC_LOOP
393 end_flush_dcache:
394         ret
395
396 /*
397  * Interrupt handling
398  */
399
400 /*
401  * exception handlers
402  */
403         .align  5
404
405 .macro  SAVE_ALL
406         ! FIXME: Other way to get PC?
407         ! FIXME: Update according to the newest spec!!
408 1:
409         li       $r28, 1
410         push $r28
411         mfsr $r28, PSW                  ! $PSW
412         push $r28
413         mfsr $r28, EIT_EVA              ! $ir1 $EVA
414         push $r28
415         mfsr $r28, EIT_ITYPE            ! $ir2 $ITYPE
416         push $r28
417         mfsr $r28, EIT_MACH_ERR         ! $ir3 Mach Error
418         push $r28
419         mfsr $r28, EIT_INTR_PSW         ! $ir5 $IPSW
420         push $r28
421         mfsr $r28, EIT_PREV_IPSW        ! $ir6 prev $IPSW
422         push $r28
423         mfsr $r28, EIT_PREV_EVA         ! $ir7 prev $EVA
424         push $r28
425         mfsr $r28, EIT_PREV_ITYPE       ! $ir8 prev $ITYPE
426         push $r28
427         mfsr $r28, EIT_INTR_PC          ! $ir9 Interruption PC
428         push $r28
429         mfsr $r28, EIT_PREV_IPC         ! $ir10 prev INTR_PC
430         push $r28
431         mfsr $r28, EIT_OVL_INTR_PC      ! $ir11 Overflowed INTR_PC
432         push $r28
433         mfusr $r28, $d1.lo
434         push $r28
435         mfusr $r28, $d1.hi
436         push $r28
437         mfusr $r28, $d0.lo
438         push $r28
439         mfusr $r28, $d0.hi
440         push $r28
441         pushm $r0, $r30         ! store $sp-$r31, ra-$r30, $gp-$r29, $r28-$fp
442         addi    $sp, $sp, -4    ! make room for implicit pt_regs parameters
443 .endm
444
445         .align  5
446 tlb_fill:
447         SAVE_ALL
448         move    $r0, $sp                        ! To get the kernel stack
449         li      $r1, 1                          ! Determine interruption type
450         bal     do_interruption
451
452         .align  5
453 tlb_not_present:
454         SAVE_ALL
455         move    $r0, $sp                        ! To get the kernel stack
456         li      $r1, 2                          ! Determine interruption type
457         bal     do_interruption
458
459         .align  5
460 tlb_misc:
461         SAVE_ALL
462         move    $r0, $sp                        ! To get the kernel stack
463         li      $r1, 3                          ! Determine interruption type
464         bal     do_interruption
465
466         .align  5
467 tlb_vlpt_miss:
468         SAVE_ALL
469         move    $r0, $sp                        ! To get the kernel stack
470         li      $r1, 4                          ! Determine interruption type
471         bal     do_interruption
472
473         .align  5
474 machine_error:
475         SAVE_ALL
476         move    $r0, $sp                        ! To get the kernel stack
477         li      $r1, 5                          ! Determine interruption type
478         bal     do_interruption
479
480         .align  5
481 debug:
482         SAVE_ALL
483         move    $r0, $sp                        ! To get the kernel stack
484         li      $r1, 6                          ! Determine interruption type
485         bal     do_interruption
486
487         .align  5
488 general_exception:
489         SAVE_ALL
490         move    $r0, $sp                        ! To get the kernel stack
491         li      $r1, 7                          ! Determine interruption type
492         bal     do_interruption
493
494         .align  5
495 syscall:
496         SAVE_ALL
497         move    $r0, $sp                        ! To get the kernel stack
498         li      $r1, 8                          ! Determine interruption type
499         bal     do_interruption
500
501         .align  5
502 internal_interrupt:
503         SAVE_ALL
504         move    $r0, $sp                        ! To get the kernel stack
505         li      $r1, 9                          ! Determine interruption type
506         bal     do_interruption
507
508         .align  5
509 software_interrupt:
510         SAVE_ALL
511         move    $r0, $sp                        ! To get the kernel stack
512         li      $r1, 10                         ! Determine interruption type
513         bal     do_interruption
514
515         .align  5
516
517 /*
518  * void reset_cpu(ulong addr);
519  * $r0: input address to jump to
520  */
521 .globl reset_cpu
522 reset_cpu:
523 /* No need to disable MMU because we never enable it */
524
525         bal     invalidate_icac
526         bal     invalidate_dcac
527         mfsr    $p0, $MMU_CFG
528         andi    $p0, $p0, 0x3                   ! MMPS
529         li      $p1, 0x2                        ! TLB MMU
530         bne     $p0, $p1, 1f
531         tlbop   flushall                        ! Flush TLB
532 1:
533         mfsr    $p0, MR_CAC_CTL                 ! Get the $CACHE_CTL reg
534         li      $p1, DIS_DCAC
535         and     $p0, $p0, $p1                   ! Clear the DC_EN bit
536         mtsr    $p0, MR_CAC_CTL                 ! Write back the $CACHE_CTL reg
537         br      $r0                             ! Jump to the input address