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