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