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