]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - arch/nds32/cpu/n1213/start.S
NDS32: Generic Board Support and Unsupport
[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
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              $r10, GD_SIZE   /* get GD size */
158         sub             $sp, $sp, $r10  /* GD start addr */
159         move    $r10, $sp
160         li              $r0, 0x00000000
161
162 #ifdef __PIC__
163 #ifdef __NDS32_N1213_43U1H__
164 /* __NDS32_N1213_43U1H__ implies NDS32 V0 ISA */
165         la      $r15, board_init_f      ! store function address into $r15
166 #endif
167 #endif
168         j       board_init_f            ! jump to board_init_f() in lib/board.c
169
170 /*
171  * void relocate_code (addr_sp, gd, addr_moni)
172  *
173  * This "function" does not return, instead it continues in RAM
174  * after relocating the monitor code.
175  *
176  */
177 .globl  relocate_code
178 relocate_code:
179         move    $r4, $r0                /* save addr_sp */
180         move    $r5, $r1                /* save addr of gd */
181         move    $r6, $r2                /* save addr of destination */
182
183 /* Set up the stack */
184 stack_setup:
185         move    $sp, $r4
186
187         la      $r0, _start
188
189         beq     $r0, $r6, clear_bss     /* skip relocation */
190
191         move    $r1, $r6                /* r1 <- scratch for copy_loop */
192         la      $r3, __bss_start
193         sub     $r3, $r3, $r0           /* r3 <- __bss_start_ofs */
194         add     $r2, $r0, $r3           /* r2 <- source end address */
195
196 copy_loop:
197         lwi.p   $r7, [$r0], #4
198         swi.p   $r7, [$r1], #4
199         blt     $r0, $r2, copy_loop
200
201 /*
202  * fix relocations related issues
203  */
204 fix_relocations:
205         l.w     $r0, _TEXT_BASE         /* r0 <- Text base */
206         sub     $r9, $r6, $r0           /* r9 <- relocation offset */
207
208 fix_got:
209 /*
210  * Now we want to update GOT.
211  *
212  * GOT[0] is reserved. GOT[1] is also reserved for the dynamic object
213  * generated by GNU ld. Skip these reserved entries from relocation.
214  */
215         la      $r2, __got_start        /* r2 <- rel __got_start in FLASH */
216         add     $r2, $r2, $r9           /* r2 <- rel __got_start in RAM */
217         la      $r3, __got_end          /* r3 <- rel __got_end in FLASH */
218         add     $r3, $r3, $r9           /* r3 <- rel __got_end in RAM */
219         addi    $r2, $r2, #8            /* skipping first two entries */
220 fix_got_loop:
221         lwi     $r0, [$r2]              /* r0 <- location in FLASH to fix up */
222         add     $r0, $r0, $r9           /* r0 <- location fix up to RAM */
223         swi.p   $r0, [$r2], #4          /* r0 <- store fix into .got in RAM */
224         blt     $r2, $r3, fix_got_loop
225
226 clear_bss:
227         la      $r0, __bss_start        /* r0 <- rel __bss_start in FLASH */
228         add     $r0, $r0, $r9           /* r0 <- rel __bss_start in FLASH */
229         la      $r1, __bss_end          /* r1 <- rel __bss_end in RAM */
230         add     $r1, $r1, $r9           /* r0 <- rel __bss_end in RAM */
231         li      $r2, 0x00000000         /* clear */
232
233 clbss_l:
234         sw      $r2, [$r0]              /* clear loop... */
235         addi    $r0, $r0, #4
236         bne     $r0, $r1, clbss_l
237
238 /*
239  * We are done. Do not return, instead branch to second part of board
240  * initialization, now running from RAM.
241  */
242 call_board_init_r:
243         la      $r0, board_init_r
244         move    $lp, $r0                /* offset of board_init_r() */
245         add     $lp, $lp, $r9           /* real address of board_init_r() */
246         /* setup parameters for board_init_r */
247         move    $r0, $r5                /* gd_t */
248         move    $r1, $r6                /* dest_addr */
249
250 #ifdef __PIC__
251 #ifdef __NDS32_N1213_43U1H__            /* NDS32 V0 ISA */
252         move    $r15, $lp               /* store function address into $r15 */
253 #endif
254 #endif
255
256         /* jump to it ... */
257         jr      $lp                     /* jump to board_init_r() */
258
259 /*
260  * Initialize CPU critical registers
261  *
262  *      1.      Setup control registers
263  *              1.1 Mask all IRQs
264  *              1.2 Flush cache and TLB
265  *              1.3 Disable MMU and cache
266  *      2.      Setup memory timing
267  */
268
269 cpu_init_crit:
270
271         move    $r0, $lp                /* push ra */
272
273         /* Disable Interrupts by clear GIE in $PSW reg */
274         setgie.d
275
276         /* Flush caches and TLB */
277         /* Invalidate caches */
278         bal     invalidate_icac
279         bal     invalidate_dcac
280
281         /* Flush TLB */
282         mfsr    $p0, $MMU_CFG
283         andi    $p0, $p0, 0x3                   ! MMPS
284         li      $p1, 0x2                        ! TLB MMU
285         bne     $p0, $p1, 1f
286         tlbop   flushall                        ! Flush TLB
287
288 1:
289         ! Disable MMU, Dcache
290         ! Whitiger is MMU disabled when reset
291         ! Disable the D$
292         mfsr    $p0, MR_CAC_CTL                 ! Get the $CACHE_CTL reg
293         li      $p1, DIS_DCAC
294         and     $p0, $p0, $p1                   ! Set DC_EN bit
295         mtsr    $p0, MR_CAC_CTL                 ! write back the $CACHE_CTL reg
296         isb
297
298         move    $lp, $r0
299 2:
300         ret
301
302 #ifndef CONFIG_SKIP_LOWLEVEL_INIT
303 load_lowlevel_init:
304         la  $r6, lowlevel_init
305         la  $r7, load_lli + 4
306         sub $p0, $r6, $r7
307         add $p0, $p0, $lp
308 ret
309 #endif
310
311 #ifndef CONFIG_SKIP_TRUNOFF_WATCHDOG
312 load_turnoff_watchdog:
313         la  $r6, turnoff_watchdog
314         la  $r7, turnoff_wtdog + 4
315         sub $p0, $r6, $r7
316         add $p0, $p0, $lp
317 ret
318 #endif
319
320 /*
321  * Invalidate I$
322  */
323 invalidate_icac:
324         ! read $cr1(I CAC/MEM cfg. reg.) configuration
325         mfsr    $t0, CR_ICAC_MEM
326
327         ! Get the ISZ field
328         andi    $p0, $t0, ICAC_MEM_KBF_ISZ
329
330         ! if $p0=0, then no I CAC existed
331         beqz    $p0, end_flush_icache
332
333         ! get $p0 the index of I$ block
334         srli    $p0, $p0, 6
335
336         ! $t1= bit width of I cache line size(ISZ)
337         addi    $t1, $p0, 2
338
339         li      $t4, 1
340         sll     $t5, $t4, $t1                   ! get $t5 cache line size
341         andi    $p1, $t0, ICAC_MEM_KBF_ISET     ! get the ISET field
342         addi    $t2, $p1, 6                     ! $t2= bit width of ISET
343         andi    $p1, $t0, ICAC_MEM_KBF_IWAY     ! get bitfield of Iway
344         srli    $p1, $p1, 3
345         addi    $p1, $p1, 1                     ! then $p1 is I way number
346         add     $t3, $t2, $t1                   ! SHIFT
347         sll     $p1, $p1, $t3                   ! GET the total cache size
348 ICAC_LOOP:
349         sub     $p1, $p1, $t5
350         cctl    $p1, L1I_IX_INVAL
351         bnez    $p1, ICAC_LOOP
352 end_flush_icache:
353         ret
354
355 /*
356  * Invalidate D$
357  */
358 invalidate_dcac:
359         ! read $cr2(D CAC/MEM cfg. reg.) configuration
360         mfsr    $t0, CR_DCAC_MEM
361
362         ! Get the DSZ field
363         andi    $p0, $t0, DCAC_MEM_KBF_DSZ
364
365         ! if $p0=0, then no D CAC existed
366         beqz    $p0, end_flush_dcache
367
368         ! get $p0 the index of D$ block
369         srli    $p0, $p0, 6
370
371         ! $t1= bit width of D cache line size(DSZ)
372         addi    $t1, $p0, 2
373
374         li      $t4, 1
375         sll     $t5, $t4, $t1                   ! get $t5 cache line size
376         andi    $p1, $t0, DCAC_MEM_KBF_DSET     ! get the DSET field
377         addi    $t2, $p1, 6                     ! $t2= bit width of DSET
378         andi    $p1, $t0, DCAC_MEM_KBF_DWAY     ! get bitfield of D way
379         srli    $p1, $p1, 3
380         addi    $p1, $p1, 1                     ! then $p1 is D way number
381         add     $t3, $t2, $t1                   ! SHIFT
382         sll     $p1, $p1, $t3                   ! GET the total cache size
383 DCAC_LOOP:
384         sub     $p1, $p1, $t5
385         cctl    $p1, L1D_IX_INVAL
386         bnez    $p1, DCAC_LOOP
387 end_flush_dcache:
388         ret
389
390 /*
391  * Interrupt handling
392  */
393
394 /*
395  * exception handlers
396  */
397         .align  5
398
399 .macro  SAVE_ALL
400         ! FIXME: Other way to get PC?
401         ! FIXME: Update according to the newest spec!!
402 1:
403         la       $r28, 1
404         push $r28
405         mfsr $r28, PSW                  ! $PSW
406         push $r28
407         mfsr $r28, EIT_EVA              ! $ir1 $EVA
408         push $r28
409         mfsr $r28, EIT_ITYPE            ! $ir2 $ITYPE
410         push $r28
411         mfsr $r28, EIT_MACH_ERR         ! $ir3 Mach Error
412         push $r28
413         mfsr $r28, EIT_INTR_PSW         ! $ir5 $IPSW
414         push $r28
415         mfsr $r28, EIT_PREV_IPSW        ! $ir6 prev $IPSW
416         push $r28
417         mfsr $r28, EIT_PREV_EVA         ! $ir7 prev $EVA
418         push $r28
419         mfsr $r28, EIT_PREV_ITYPE       ! $ir8 prev $ITYPE
420         push $r28
421         mfsr $r28, EIT_INTR_PC          ! $ir9 Interruption PC
422         push $r28
423         mfsr $r28, EIT_PREV_IPC         ! $ir10 prev INTR_PC
424         push $r28
425         mfsr $r28, EIT_OVL_INTR_PC      ! $ir11 Overflowed INTR_PC
426         push $r28
427         mfusr $r28, $d1.lo
428         push $r28
429         mfusr $r28, $d1.hi
430         push $r28
431         mfusr $r28, $d0.lo
432         push $r28
433         mfusr $r28, $d0.hi
434         push $r28
435         pushm $r0, $r30         ! store $sp-$r31, ra-$r30, $gp-$r29, $r28-$fp
436         addi    $sp, $sp, -4    ! make room for implicit pt_regs parameters
437 .endm
438
439         .align  5
440 tlb_fill:
441         SAVE_ALL
442         move    $r0, $sp                        ! To get the kernel stack
443         li      $r1, 1                          ! Determine interruption type
444         bal     do_interruption
445
446         .align  5
447 tlb_not_present:
448         SAVE_ALL
449         move    $r0, $sp                        ! To get the kernel stack
450         li      $r1, 2                          ! Determine interruption type
451         bal     do_interruption
452
453         .align  5
454 tlb_misc:
455         SAVE_ALL
456         move    $r0, $sp                        ! To get the kernel stack
457         li      $r1, 3                          ! Determine interruption type
458         bal     do_interruption
459
460         .align  5
461 tlb_vlpt_miss:
462         SAVE_ALL
463         move    $r0, $sp                        ! To get the kernel stack
464         li      $r1, 4                          ! Determine interruption type
465         bal     do_interruption
466
467         .align  5
468 machine_error:
469         SAVE_ALL
470         move    $r0, $sp                        ! To get the kernel stack
471         li      $r1, 5                          ! Determine interruption type
472         bal     do_interruption
473
474         .align  5
475 debug:
476         SAVE_ALL
477         move    $r0, $sp                        ! To get the kernel stack
478         li      $r1, 6                          ! Determine interruption type
479         bal     do_interruption
480
481         .align  5
482 general_exception:
483         SAVE_ALL
484         move    $r0, $sp                        ! To get the kernel stack
485         li      $r1, 7                          ! Determine interruption type
486         bal     do_interruption
487
488         .align  5
489 syscall:
490         SAVE_ALL
491         move    $r0, $sp                        ! To get the kernel stack
492         li      $r1, 8                          ! Determine interruption type
493         bal     do_interruption
494
495         .align  5
496 internal_interrupt:
497         SAVE_ALL
498         move    $r0, $sp                        ! To get the kernel stack
499         li      $r1, 9                          ! Determine interruption type
500         bal     do_interruption
501
502         .align  5
503 software_interrupt:
504         SAVE_ALL
505         move    $r0, $sp                        ! To get the kernel stack
506         li      $r1, 10                         ! Determine interruption type
507         bal     do_interruption
508
509         .align  5
510
511 /*
512  * void reset_cpu(ulong addr);
513  * $r0: input address to jump to
514  */
515 .globl reset_cpu
516 reset_cpu:
517 /* No need to disable MMU because we never enable it */
518
519         bal     invalidate_icac
520         bal     invalidate_dcac
521         mfsr    $p0, $MMU_CFG
522         andi    $p0, $p0, 0x3                   ! MMPS
523         li      $p1, 0x2                        ! TLB MMU
524         bne     $p0, $p1, 1f
525         tlbop   flushall                        ! Flush TLB
526 1:
527         mfsr    $p0, MR_CAC_CTL                 ! Get the $CACHE_CTL reg
528         li      $p1, DIS_DCAC
529         and     $p0, $p0, $p1                   ! Clear the DC_EN bit
530         mtsr    $p0, MR_CAC_CTL                 ! Write back the $CACHE_CTL reg
531         br      $r0                             ! Jump to the input address