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