nds32: Support AG101P serial DM.
[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 .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 /* IRQ stack memory (calculated at run-time) + 8 bytes */
94 .globl IRQ_STACK_START_IN
95 IRQ_STACK_START_IN:
96         .word 0x0badc0de
97
98 /*
99  * The bootstrap code of nds32 core
100  */
101
102 reset:
103
104 /*
105  *  gp = ~0            for burn mode
106  *     = ~load_address for load mode
107  */
108 reset_gp:
109         .relax_hint 0
110         sethi   $gp, hi20(_GLOBAL_OFFSET_TABLE_-8)
111         .relax_hint 0
112         ori     $gp, $gp, lo12(_GLOBAL_OFFSET_TABLE_-4)
113         add5.pc $gp
114
115 set_ivb:
116         li      $r0, 0x0
117
118         /* turn on BTB */
119         mtsr    $r0, $misc_ctl
120         /* set IVIC, vector size: 4 bytes, base: 0x0 */
121         mtsr    $r0, $ivb
122
123 #ifndef CONFIG_SKIP_LOWLEVEL_INIT
124         jal     lowlevel_init
125 /*
126  *  gp = ~VMA          for burn mode
127  *     = ~load_address for load mode
128  */
129 update_gp:
130         .relax_hint 0
131         sethi   $gp, hi20(_GLOBAL_OFFSET_TABLE_-8)
132         .relax_hint 0
133         ori     $gp, $gp, lo12(_GLOBAL_OFFSET_TABLE_-4)
134         add5.pc $gp
135 #endif
136
137 /*
138  *  do critical initializations first (shall be in short time)
139  *  do self_relocation ASAP.
140  */
141
142 /*
143  * Set the N1213 (Whitiger) core to superuser mode
144  * According to spec, it is already when reset
145  */
146 #ifndef CONFIG_SKIP_TRUNOFF_WATCHDOG
147         jal     turnoff_watchdog
148 #endif
149
150 /*
151  * Do CPU critical regs init only at reboot,
152  * not when booting from ram
153  */
154 #ifdef CONFIG_INIT_CRITICAL
155         jal     cpu_init_crit           ! Do CPU critical regs init
156 #endif
157
158 /*
159  * Set stackpointer in internal RAM to call board_init_f
160  * $sp must be 8-byte alignment for ABI compliance.
161  */
162 call_board_init_f:
163         li              $sp, CONFIG_SYS_INIT_SP_ADDR
164         move    $r0, $sp
165         bal     board_init_f_alloc_reserve
166         move    $sp, $r0
167         bal     board_init_f_init_reserve
168 #ifdef CONFIG_DEBUG_UART
169         bal     debug_uart_init
170 #endif
171         li              $r0, 0x00000000
172
173 #ifdef __PIC__
174 #ifdef __NDS32_N1213_43U1H__
175 /* __NDS32_N1213_43U1H__ implies NDS32 V0 ISA */
176         la      $r15, board_init_f      ! store function address into $r15
177 #endif
178 #endif
179         j       board_init_f            ! jump to board_init_f() in lib/board.c
180
181 /*
182  * void relocate_code (addr_sp, gd, addr_moni)
183  *
184  * This "function" does not return, instead it continues in RAM
185  * after relocating the monitor code.
186  *
187  */
188
189 /*
190  *  gp = ~RAM_SIZE - TEXT_SIZE for burn/load mode
191  */
192
193 .globl  relocate_code
194 relocate_code:
195         move    $r4, $r0                /* save addr_sp */
196         move    $r5, $r1                /* save addr of gd */
197         move    $r6, $r2                /* save addr of destination */
198
199 /* Set up the stack */
200 stack_setup:
201         move    $sp, $r4
202
203         la      $r0, _start@GOTOFF
204         beq     $r0, $r6, clear_bss     /* skip relocation */
205
206         la       $r1, _end@GOTOFF
207         move $r2, $r6                   /* r2 <- scratch for copy_loop */
208
209 copy_loop:
210         lwi.p   $r7, [$r0], #4
211         swi.p   $r7, [$r2], #4
212         blt     $r0, $r1, copy_loop
213
214 /*
215  * fix relocations related issues
216  */
217 fix_relocations:
218         l.w     $r0, _TEXT_BASE@GOTOFF  /* r0 <- Text base */
219         sub     $r9, $r6, $r0                   /* r9 <- relocation offset */
220
221         la  $r7, __rel_dyn_start@GOTOFF
222         add     $r7, $r7, $r9           /* r2 <- rel __got_start in RAM */
223         la  $r8, __rel_dyn_end@GOTOFF
224         add     $r8, $r8, $r9           /* r2 <- rel __got_start in RAM */
225         li  $r3, #0x2a /* R_NDS32_RELATIVE */
226 1:
227         lmw.bim $r0, [$r7], $r2 /* r0,r1,r2 <- adr,type,addend */
228         bne $r1, $r3, 2f
229
230         add $r0, $r0, $r9
231         add $r2, $r2, $r9
232         sw  $r2, [$r0]
233 2:
234         blt $r7, $r8, 1b
235
236 clear_bss:
237         la      $r0, __bss_start@GOTOFF /* r0 <- rel __bss_start in FLASH */
238         add     $r0, $r0, $r9           /* r0 <- rel __bss_start in FLASH */
239         la      $r1, __bss_end@GOTOFF           /* r1 <- rel __bss_end in RAM */
240         add     $r1, $r1, $r9           /* r0 <- rel __bss_end in RAM */
241         li      $r2, 0x00000000         /* clear */
242
243 clbss_l:
244         sw      $r2, [$r0]              /* clear loop... */
245         addi    $r0, $r0, #4
246         bne     $r0, $r1, clbss_l
247
248 /*
249  * We are done. Do not return, instead branch to second part of board
250  * initialization, now running from RAM.
251  */
252 call_board_init_r:
253         la      $r0, board_init_r@GOTOFF
254         move    $lp, $r0                /* offset of board_init_r() */
255         add     $lp, $lp, $r9           /* real address of board_init_r() */
256         /* setup parameters for board_init_r */
257         move    $r0, $r5                /* gd_t */
258         move    $r1, $r6                /* dest_addr */
259
260 #ifdef __PIC__
261 #ifdef __NDS32_N1213_43U1H__            /* NDS32 V0 ISA */
262         move    $r15, $lp               /* store function address into $r15 */
263 #endif
264 #endif
265
266         /* jump to it ... */
267         jr      $lp                     /* jump to board_init_r() */
268
269 /*
270  * Initialize CPU critical registers
271  *
272  *      1.      Setup control registers
273  *              1.1 Mask all IRQs
274  *              1.2 Flush cache and TLB
275  *              1.3 Disable MMU and cache
276  *      2.      Setup memory timing
277  */
278
279 cpu_init_crit:
280
281         move    $r0, $lp                /* push ra */
282
283         /* Disable Interrupts by clear GIE in $PSW reg */
284         setgie.d
285
286         /* Flush caches and TLB */
287         /* Invalidate caches */
288         jal     invalidate_icac
289         jal     invalidate_dcac
290
291         /* Flush TLB */
292         mfsr    $p0, $MMU_CFG
293         andi    $p0, $p0, 0x3                   ! MMPS
294         li      $p1, 0x2                        ! TLB MMU
295         bne     $p0, $p1, 1f
296         tlbop   flushall                        ! Flush TLB
297
298 1:
299         ! Disable MMU, Dcache
300         ! Whitiger is MMU disabled when reset
301         ! Disable the D$
302         mfsr    $p0, MR_CAC_CTL                 ! Get the $CACHE_CTL reg
303         li      $p1, DIS_DCAC
304         and     $p0, $p0, $p1                   ! Set DC_EN bit
305         mtsr    $p0, MR_CAC_CTL                 ! write back the $CACHE_CTL reg
306         isb
307
308         move    $lp, $r0
309 2:
310         ret
311
312 /*
313  * Invalidate I$
314  */
315 invalidate_icac:
316         ! read $cr1(I CAC/MEM cfg. reg.) configuration
317         mfsr    $t0, CR_ICAC_MEM
318
319         ! Get the ISZ field
320         andi    $p0, $t0, ICAC_MEM_KBF_ISZ
321
322         ! if $p0=0, then no I CAC existed
323         beqz    $p0, end_flush_icache
324
325         ! get $p0 the index of I$ block
326         srli    $p0, $p0, 6
327
328         ! $t1= bit width of I cache line size(ISZ)
329         addi    $t1, $p0, 2
330
331         li      $t4, 1
332         sll     $t5, $t4, $t1                   ! get $t5 cache line size
333         andi    $p1, $t0, ICAC_MEM_KBF_ISET     ! get the ISET field
334         addi    $t2, $p1, 6                     ! $t2= bit width of ISET
335         andi    $p1, $t0, ICAC_MEM_KBF_IWAY     ! get bitfield of Iway
336         srli    $p1, $p1, 3
337         addi    $p1, $p1, 1                     ! then $p1 is I way number
338         add     $t3, $t2, $t1                   ! SHIFT
339         sll     $p1, $p1, $t3                   ! GET the total cache size
340 ICAC_LOOP:
341         sub     $p1, $p1, $t5
342         cctl    $p1, L1I_IX_INVAL
343         bnez    $p1, ICAC_LOOP
344 end_flush_icache:
345         ret
346
347 /*
348  * Invalidate D$
349  */
350 invalidate_dcac:
351         ! read $cr2(D CAC/MEM cfg. reg.) configuration
352         mfsr    $t0, CR_DCAC_MEM
353
354         ! Get the DSZ field
355         andi    $p0, $t0, DCAC_MEM_KBF_DSZ
356
357         ! if $p0=0, then no D CAC existed
358         beqz    $p0, end_flush_dcache
359
360         ! get $p0 the index of D$ block
361         srli    $p0, $p0, 6
362
363         ! $t1= bit width of D cache line size(DSZ)
364         addi    $t1, $p0, 2
365
366         li      $t4, 1
367         sll     $t5, $t4, $t1                   ! get $t5 cache line size
368         andi    $p1, $t0, DCAC_MEM_KBF_DSET     ! get the DSET field
369         addi    $t2, $p1, 6                     ! $t2= bit width of DSET
370         andi    $p1, $t0, DCAC_MEM_KBF_DWAY     ! get bitfield of D way
371         srli    $p1, $p1, 3
372         addi    $p1, $p1, 1                     ! then $p1 is D way number
373         add     $t3, $t2, $t1                   ! SHIFT
374         sll     $p1, $p1, $t3                   ! GET the total cache size
375 DCAC_LOOP:
376         sub     $p1, $p1, $t5
377         cctl    $p1, L1D_IX_INVAL
378         bnez    $p1, DCAC_LOOP
379 end_flush_dcache:
380         ret
381
382 /*
383  * Interrupt handling
384  */
385
386 /*
387  * exception handlers
388  */
389         .align  5
390
391 .macro  SAVE_ALL
392         ! FIXME: Other way to get PC?
393         ! FIXME: Update according to the newest spec!!
394 1:
395         li       $r28, 1
396         push $r28
397         mfsr $r28, PSW                  ! $PSW
398         push $r28
399         mfsr $r28, EIT_EVA              ! $ir1 $EVA
400         push $r28
401         mfsr $r28, EIT_ITYPE            ! $ir2 $ITYPE
402         push $r28
403         mfsr $r28, EIT_MACH_ERR         ! $ir3 Mach Error
404         push $r28
405         mfsr $r28, EIT_INTR_PSW         ! $ir5 $IPSW
406         push $r28
407         mfsr $r28, EIT_PREV_IPSW        ! $ir6 prev $IPSW
408         push $r28
409         mfsr $r28, EIT_PREV_EVA         ! $ir7 prev $EVA
410         push $r28
411         mfsr $r28, EIT_PREV_ITYPE       ! $ir8 prev $ITYPE
412         push $r28
413         mfsr $r28, EIT_INTR_PC          ! $ir9 Interruption PC
414         push $r28
415         mfsr $r28, EIT_PREV_IPC         ! $ir10 prev INTR_PC
416         push $r28
417         mfsr $r28, EIT_OVL_INTR_PC      ! $ir11 Overflowed INTR_PC
418         push $r28
419         mfusr $r28, $d1.lo
420         push $r28
421         mfusr $r28, $d1.hi
422         push $r28
423         mfusr $r28, $d0.lo
424         push $r28
425         mfusr $r28, $d0.hi
426         push $r28
427         pushm $r0, $r30         ! store $sp-$r31, ra-$r30, $gp-$r29, $r28-$fp
428         addi    $sp, $sp, -4    ! make room for implicit pt_regs parameters
429 .endm
430
431         .align  5
432 tlb_fill:
433         SAVE_ALL
434         move    $r0, $sp                        ! To get the kernel stack
435         li      $r1, 1                          ! Determine interruption type
436         bal     do_interruption
437
438         .align  5
439 tlb_not_present:
440         SAVE_ALL
441         move    $r0, $sp                        ! To get the kernel stack
442         li      $r1, 2                          ! Determine interruption type
443         bal     do_interruption
444
445         .align  5
446 tlb_misc:
447         SAVE_ALL
448         move    $r0, $sp                        ! To get the kernel stack
449         li      $r1, 3                          ! Determine interruption type
450         bal     do_interruption
451
452         .align  5
453 tlb_vlpt_miss:
454         SAVE_ALL
455         move    $r0, $sp                        ! To get the kernel stack
456         li      $r1, 4                          ! Determine interruption type
457         bal     do_interruption
458
459         .align  5
460 machine_error:
461         SAVE_ALL
462         move    $r0, $sp                        ! To get the kernel stack
463         li      $r1, 5                          ! Determine interruption type
464         bal     do_interruption
465
466         .align  5
467 debug:
468         SAVE_ALL
469         move    $r0, $sp                        ! To get the kernel stack
470         li      $r1, 6                          ! Determine interruption type
471         bal     do_interruption
472
473         .align  5
474 general_exception:
475         SAVE_ALL
476         move    $r0, $sp                        ! To get the kernel stack
477         li      $r1, 7                          ! Determine interruption type
478         bal     do_interruption
479
480         .align  5
481 syscall:
482         SAVE_ALL
483         move    $r0, $sp                        ! To get the kernel stack
484         li      $r1, 8                          ! Determine interruption type
485         bal     do_interruption
486
487         .align  5
488 internal_interrupt:
489         SAVE_ALL
490         move    $r0, $sp                        ! To get the kernel stack
491         li      $r1, 9                          ! Determine interruption type
492         bal     do_interruption
493
494         .align  5
495 software_interrupt:
496         SAVE_ALL
497         move    $r0, $sp                        ! To get the kernel stack
498         li      $r1, 10                         ! Determine interruption type
499         bal     do_interruption
500
501         .align  5
502
503 /*
504  * void reset_cpu(ulong addr);
505  * $r0: input address to jump to
506  */
507 .globl reset_cpu
508 reset_cpu:
509 /* No need to disable MMU because we never enable it */
510
511         bal     invalidate_icac
512         bal     invalidate_dcac
513         mfsr    $p0, $MMU_CFG
514         andi    $p0, $p0, 0x3                   ! MMPS
515         li      $p1, 0x2                        ! TLB MMU
516         bne     $p0, $p1, 1f
517         tlbop   flushall                        ! Flush TLB
518 1:
519         mfsr    $p0, MR_CAC_CTL                 ! Get the $CACHE_CTL reg
520         li      $p1, DIS_DCAC
521         and     $p0, $p0, $p1                   ! Clear the DC_EN bit
522         mtsr    $p0, MR_CAC_CTL                 ! Write back the $CACHE_CTL reg
523         br      $r0                             ! Jump to the input address