xref: /openbmc/u-boot/arch/nds32/cpu/n1213/start.S (revision 2482e3c8)
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
115IRQ_STACK_START:
116	.word 0x0badc0de
117
118/* IRQ stack memory (calculated at run-time) */
119.globl FIQ_STACK_START
120FIQ_STACK_START:
121	.word 0x0badc0de
122#endif
123
124/* IRQ stack memory (calculated at run-time) + 8 bytes */
125.globl IRQ_STACK_START_IN
126IRQ_STACK_START_IN:
127	.word 0x0badc0de
128
129/*
130 * The bootstrap code of nds32 core
131 */
132
133reset:
134set_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
142load_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 */
152turnoff_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 */
170call_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
190relocate_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 */
196stack_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
208copy_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 */
216fix_relocations:
217	l.w	$r0, _TEXT_BASE		/* r0 <- Text base */
218	sub	$r9, $r6, $r0		/* r9 <- relocation offset */
219
220fix_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 */
232fix_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
238clear_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
245clbss_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 */
254call_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
281cpu_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
3001:
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
3112:
312	ret
313
314#ifndef CONFIG_SKIP_LOWLEVEL_INIT
315load_lowlevel_init:
316	la  $r6, lowlevel_init
317	la  $r7, load_lli + 4
318	sub $p0, $r6, $r7
319	add $p0, $p0, $lp
320ret
321#endif
322
323#ifndef CONFIG_SKIP_TRUNOFF_WATCHDOG
324load_turnoff_watchdog:
325	la  $r6, turnoff_watchdog
326	la  $r7, turnoff_wtdog + 4
327	sub $p0, $r6, $r7
328	add $p0, $p0, $lp
329ret
330#endif
331
332/*
333 * Invalidate I$
334 */
335invalidate_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
360ICAC_LOOP:
361	sub	$p1, $p1, $t5
362	cctl	$p1, L1I_IX_INVAL
363	bnez	$p1, ICAC_LOOP
364end_flush_icache:
365	ret
366
367/*
368 * Invalidate D$
369 */
370invalidate_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
395DCAC_LOOP:
396	sub	$p1, $p1, $t5
397	cctl	$p1, L1D_IX_INVAL
398	bnez	$p1, DCAC_LOOP
399end_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!!
4141:
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
452tlb_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
459tlb_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
466tlb_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
473tlb_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
480cache_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
487debug:
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
494general_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
501internal_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
514reset_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
5241:
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
530