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